fixed width columns for LHS of editor route list
[ardour.git] / gtk2_ardour / editor_routes.cc
1 /*
2     Copyright (C) 2000-2009 Paul Davis
3
4     This program is free software; you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation; either version 2 of the License, or
7     (at your option) any later version.
8
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13
14     You should have received a copy of the GNU General Public License
15     along with this program; if not, write to the Free Software
16     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17
18 */
19
20 #include <list>
21 #include <vector>
22 #include <algorithm>
23 #include <cstdlib>
24 #include <cmath>
25 #include <cassert>
26
27 #include "ardour/session.h"
28
29 #include "editor.h"
30 #include "keyboard.h"
31 #include "ardour_ui.h"
32 #include "audio_time_axis.h"
33 #include "midi_time_axis.h"
34 #include "mixer_strip.h"
35 #include "gui_thread.h"
36 #include "actions.h"
37 #include "utils.h"
38 #include "editor_group_tabs.h"
39 #include "editor_routes.h"
40
41 #include "pbd/unknown_type.h"
42
43 #include "ardour/route.h"
44 #include "ardour/midi_track.h"
45
46 #include "gtkmm2ext/cell_renderer_pixbuf_multi.h"
47 #include "gtkmm2ext/cell_renderer_pixbuf_toggle.h"
48 #include "gtkmm2ext/treeutils.h"
49
50 #include "i18n.h"
51
52 using namespace std;
53 using namespace ARDOUR;
54 using namespace PBD;
55 using namespace Gtk;
56 using namespace Gtkmm2ext;
57 using namespace Glib;
58 using Gtkmm2ext::Keyboard;
59
60 EditorRoutes::EditorRoutes (Editor* e)
61         : EditorComponent (e)
62         , _ignore_reorder (false)
63         , _no_redisplay (false)
64         , _redisplay_does_not_sync_order_keys (false)
65         , _redisplay_does_not_reset_order_keys (false)
66         ,_menu (0)
67         , old_focus (0)
68         , selection_countdown (0)
69         , name_editable (0)
70 {
71         static const int column_width = 22;
72
73         _scroller.add (_display);
74         _scroller.set_policy (POLICY_NEVER, POLICY_AUTOMATIC);
75
76         _model = ListStore::create (_columns);
77         _display.set_model (_model);
78
79         // Record enable toggle
80         CellRendererPixbufMulti* rec_col_renderer = manage (new CellRendererPixbufMulti());
81
82         rec_col_renderer->set_pixbuf (0, ::get_icon("act-disabled"));
83         rec_col_renderer->set_pixbuf (1, ::get_icon("rec-in-progress"));
84         rec_col_renderer->set_pixbuf (2, ::get_icon("rec-enabled"));
85         rec_col_renderer->set_pixbuf (3, ::get_icon("step-editing"));
86         rec_col_renderer->signal_changed().connect (sigc::mem_fun (*this, &EditorRoutes::on_tv_rec_enable_changed));
87
88         TreeViewColumn* rec_state_column = manage (new TreeViewColumn("R", *rec_col_renderer));
89
90         rec_state_column->add_attribute(rec_col_renderer->property_state(), _columns.rec_state);
91         rec_state_column->add_attribute(rec_col_renderer->property_visible(), _columns.is_track);
92
93         rec_state_column->set_sizing(TREE_VIEW_COLUMN_FIXED);
94         rec_state_column->set_alignment(ALIGN_CENTER);
95         rec_state_column->set_expand(false);
96         rec_state_column->set_fixed_width(column_width);
97
98         // MIDI Input Active
99
100         CellRendererPixbufMulti* input_active_col_renderer = manage (new CellRendererPixbufMulti());
101         input_active_col_renderer->set_pixbuf (0, ::get_icon("act-disabled"));
102         input_active_col_renderer->set_pixbuf (1, ::get_icon("midi-input-active"));
103         input_active_col_renderer->signal_changed().connect (sigc::mem_fun (*this, &EditorRoutes::on_input_active_changed));
104
105         TreeViewColumn* input_active_column = manage (new TreeViewColumn ("I", *input_active_col_renderer));
106
107         input_active_column->add_attribute(input_active_col_renderer->property_state(), _columns.is_input_active);
108         input_active_column->add_attribute (input_active_col_renderer->property_visible(), _columns.is_midi);
109
110         input_active_column->set_sizing(TREE_VIEW_COLUMN_FIXED);
111         input_active_column->set_alignment(ALIGN_CENTER);
112         input_active_column->set_expand(false);
113         input_active_column->set_fixed_width(column_width);
114
115         // Mute enable toggle
116         CellRendererPixbufMulti* mute_col_renderer = manage (new CellRendererPixbufMulti());
117
118         mute_col_renderer->set_pixbuf (0, ::get_icon("mute-disabled"));
119         mute_col_renderer->set_pixbuf (1, ::get_icon("muted-by-others"));
120         mute_col_renderer->set_pixbuf (2, ::get_icon("mute-enabled"));
121         mute_col_renderer->signal_changed().connect (sigc::mem_fun (*this, &EditorRoutes::on_tv_mute_enable_toggled));
122
123         TreeViewColumn* mute_state_column = manage (new TreeViewColumn("M", *mute_col_renderer));
124
125         mute_state_column->add_attribute(mute_col_renderer->property_state(), _columns.mute_state);
126         mute_state_column->set_sizing(TREE_VIEW_COLUMN_FIXED);
127         mute_state_column->set_alignment(ALIGN_CENTER);
128         mute_state_column->set_expand(false);
129         mute_state_column->set_fixed_width(15);
130
131         // Solo enable toggle
132         CellRendererPixbufMulti* solo_col_renderer = manage (new CellRendererPixbufMulti());
133
134         solo_col_renderer->set_pixbuf (0, ::get_icon("solo-disabled"));
135         solo_col_renderer->set_pixbuf (1, ::get_icon("solo-enabled"));
136         solo_col_renderer->set_pixbuf (3, ::get_icon("soloed-by-others"));
137         solo_col_renderer->signal_changed().connect (sigc::mem_fun (*this, &EditorRoutes::on_tv_solo_enable_toggled));
138
139         TreeViewColumn* solo_state_column = manage (new TreeViewColumn("S", *solo_col_renderer));
140
141         solo_state_column->add_attribute(solo_col_renderer->property_state(), _columns.solo_state);
142         solo_state_column->set_sizing(TREE_VIEW_COLUMN_FIXED);
143         solo_state_column->set_alignment(ALIGN_CENTER);
144         solo_state_column->set_expand(false);
145         solo_state_column->set_fixed_width(column_width);
146
147         // Solo isolate toggle
148         CellRendererPixbufMulti* solo_iso_renderer = manage (new CellRendererPixbufMulti());
149
150         solo_iso_renderer->set_pixbuf (0, ::get_icon("solo-isolate-disabled"));
151         solo_iso_renderer->set_pixbuf (1, ::get_icon("solo-isolate-enabled"));
152         solo_iso_renderer->signal_changed().connect (sigc::mem_fun (*this, &EditorRoutes::on_tv_solo_isolate_toggled));
153
154         TreeViewColumn* solo_isolate_state_column = manage (new TreeViewColumn("SI", *solo_iso_renderer));
155
156         solo_isolate_state_column->add_attribute(solo_iso_renderer->property_state(), _columns.solo_isolate_state);
157         solo_isolate_state_column->set_sizing(TREE_VIEW_COLUMN_FIXED);
158         solo_isolate_state_column->set_alignment(ALIGN_CENTER);
159         solo_isolate_state_column->set_expand(false);
160         solo_isolate_state_column->set_fixed_width(column_width);
161
162         // Solo safe toggle
163         CellRendererPixbufMulti* solo_safe_renderer = manage (new CellRendererPixbufMulti ());
164
165         solo_safe_renderer->set_pixbuf (0, ::get_icon("solo-safe-disabled"));
166         solo_safe_renderer->set_pixbuf (1, ::get_icon("solo-safe-enabled"));
167         solo_safe_renderer->signal_changed().connect (sigc::mem_fun (*this, &EditorRoutes::on_tv_solo_safe_toggled));
168
169         TreeViewColumn* solo_safe_state_column = manage (new TreeViewColumn(_("SS"), *solo_safe_renderer));
170         solo_safe_state_column->add_attribute(solo_safe_renderer->property_state(), _columns.solo_safe_state);
171         solo_safe_state_column->set_sizing(TREE_VIEW_COLUMN_FIXED);
172         solo_safe_state_column->set_alignment(ALIGN_CENTER);
173         solo_safe_state_column->set_expand(false);
174         solo_safe_state_column->set_fixed_width(column_width);
175
176         _display.append_column (*input_active_column);
177         _display.append_column (*rec_state_column);
178         _display.append_column (*mute_state_column);
179         _display.append_column (*solo_state_column);
180         _display.append_column (*solo_isolate_state_column);
181         _display.append_column (*solo_safe_state_column);
182
183         _name_column = _display.append_column (_("Name"), _columns.text) - 1;
184         _visible_column = _display.append_column (_("V"), _columns.visible) - 1;
185
186         _display.set_headers_visible (true);
187         _display.set_name ("TrackListDisplay");
188         _display.get_selection()->set_mode (SELECTION_SINGLE);
189         _display.get_selection()->set_select_function (sigc::mem_fun (*this, &EditorRoutes::selection_filter));
190         _display.set_reorderable (true);
191         _display.set_rules_hint (true);
192         _display.set_size_request (100, -1);
193         _display.add_object_drag (_columns.route.index(), "routes");
194
195         CellRendererText* name_cell = dynamic_cast<CellRendererText*> (_display.get_column_cell_renderer (_name_column));
196
197         assert (name_cell);
198         name_cell->signal_editing_started().connect (sigc::mem_fun (*this, &EditorRoutes::name_edit_started));
199
200         TreeViewColumn* name_column = _display.get_column (_name_column);
201
202         assert (name_column);
203
204         name_column->add_attribute (name_cell->property_editable(), _columns.name_editable);
205         name_column->set_sizing(TREE_VIEW_COLUMN_FIXED);
206         name_column->set_expand(true);
207         name_column->set_min_width(50);
208
209         name_cell->property_editable() = true;
210         name_cell->signal_edited().connect (sigc::mem_fun (*this, &EditorRoutes::name_edit));
211
212         // Set the visible column cell renderer to radio toggle
213         CellRendererToggle* visible_cell = dynamic_cast<CellRendererToggle*> (_display.get_column_cell_renderer (_visible_column));
214
215         visible_cell->property_activatable() = true;
216         visible_cell->property_radio() = false;
217         visible_cell->signal_toggled().connect (sigc::mem_fun (*this, &EditorRoutes::visible_changed));
218
219         TreeViewColumn* visible_col = dynamic_cast<TreeViewColumn*> (_display.get_column (_visible_column));
220         visible_col->set_expand(false);
221         visible_col->set_sizing(TREE_VIEW_COLUMN_FIXED);
222         visible_col->set_fixed_width(30);
223         visible_col->set_alignment(ALIGN_CENTER);
224
225         _model->signal_row_deleted().connect (sigc::mem_fun (*this, &EditorRoutes::route_deleted));
226         _model->signal_rows_reordered().connect (sigc::mem_fun (*this, &EditorRoutes::reordered));
227
228         _display.signal_button_press_event().connect (sigc::mem_fun (*this, &EditorRoutes::button_press), false);
229         _scroller.signal_key_press_event().connect (sigc::mem_fun(*this, &EditorRoutes::key_press), false);
230
231         _scroller.signal_focus_in_event().connect (sigc::mem_fun (*this, &EditorRoutes::focus_in), false);
232         _scroller.signal_focus_out_event().connect (sigc::mem_fun (*this, &EditorRoutes::focus_out));
233
234         _display.signal_enter_notify_event().connect (sigc::mem_fun (*this, &EditorRoutes::enter_notify), false);
235         _display.signal_leave_notify_event().connect (sigc::mem_fun (*this, &EditorRoutes::leave_notify), false);
236
237         _display.set_enable_search (false);
238
239         Route::SyncOrderKeys.connect (*this, MISSING_INVALIDATOR, ui_bind (&EditorRoutes::sync_order_keys, this, _1), gui_context());
240 }
241
242 bool
243 EditorRoutes::focus_in (GdkEventFocus*)
244 {
245         Window* win = dynamic_cast<Window*> (_scroller.get_toplevel ());
246
247         if (win) {
248                 old_focus = win->get_focus ();
249         } else {
250                 old_focus = 0;
251         }
252
253         name_editable = 0;
254
255         /* try to do nothing on focus in (doesn't work, hence selection_count nonsense) */
256         return true;
257 }
258
259 bool
260 EditorRoutes::focus_out (GdkEventFocus*)
261 {
262         if (old_focus) {
263                 old_focus->grab_focus ();
264                 old_focus = 0;
265         }
266
267         return false;
268 }
269
270 bool
271 EditorRoutes::enter_notify (GdkEventCrossing*)
272 {
273         if (name_editable) {
274                 return true;
275         }
276
277         /* arm counter so that ::selection_filter() will deny selecting anything for the
278            next two attempts to change selection status.
279         */
280         selection_countdown = 2;
281         _scroller.grab_focus ();
282         Keyboard::magic_widget_grab_focus ();
283         return false;
284 }
285
286 bool
287 EditorRoutes::leave_notify (GdkEventCrossing*)
288 {
289         selection_countdown = 0;
290
291         if (old_focus) {
292                 old_focus->grab_focus ();
293                 old_focus = 0;
294         }
295
296         Keyboard::magic_widget_drop_focus ();
297         return false;
298 }
299
300 void
301 EditorRoutes::set_session (Session* s)
302 {
303         SessionHandlePtr::set_session (s);
304
305         initial_display ();
306
307         if (_session) {
308                 _session->SoloChanged.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::solo_changed_so_update_mute, this), gui_context());
309                 _session->RecordStateChanged.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::update_rec_display, this), gui_context());
310         }
311 }
312
313 void
314 EditorRoutes::on_input_active_changed (std::string const & path_string)
315 {
316         // Get the model row that has been toggled.
317         Gtk::TreeModel::Row row = *_model->get_iter (Gtk::TreeModel::Path (path_string));
318
319         TimeAxisView* tv = row[_columns.tv];
320         RouteTimeAxisView *rtv = dynamic_cast<RouteTimeAxisView*> (tv);
321
322         if (rtv) {
323                 boost::shared_ptr<MidiTrack> mt;
324                 mt = rtv->midi_track();
325                 if (mt) {
326                         mt->set_input_active (!mt->input_active());
327                 }
328         }
329 }
330
331 void
332 EditorRoutes::on_tv_rec_enable_changed (std::string const & path_string)
333 {
334         // Get the model row that has been toggled.
335         Gtk::TreeModel::Row row = *_model->get_iter (Gtk::TreeModel::Path (path_string));
336
337         TimeAxisView* tv = row[_columns.tv];
338         RouteTimeAxisView *rtv = dynamic_cast<RouteTimeAxisView*> (tv);
339
340         if (rtv && rtv->track()) {
341                 boost::shared_ptr<RouteList> rl (new RouteList);
342                 rl->push_back (rtv->route());
343                 _session->set_record_enabled (rl, !rtv->track()->record_enabled(), Session::rt_cleanup);
344         }
345 }
346
347 void
348 EditorRoutes::on_tv_mute_enable_toggled (std::string const & path_string)
349 {
350         // Get the model row that has been toggled.
351         Gtk::TreeModel::Row row = *_model->get_iter (Gtk::TreeModel::Path (path_string));
352
353         TimeAxisView *tv = row[_columns.tv];
354         RouteTimeAxisView *rtv = dynamic_cast<RouteTimeAxisView*> (tv);
355
356         if (rtv != 0) {
357                 boost::shared_ptr<RouteList> rl (new RouteList);
358                 rl->push_back (rtv->route());
359                 _session->set_mute (rl, !rtv->route()->muted(), Session::rt_cleanup);
360         }
361 }
362
363 void
364 EditorRoutes::on_tv_solo_enable_toggled (std::string const & path_string)
365 {
366         // Get the model row that has been toggled.
367         Gtk::TreeModel::Row row = *_model->get_iter (Gtk::TreeModel::Path (path_string));
368
369         TimeAxisView *tv = row[_columns.tv];
370         RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
371
372         if (rtv != 0) {
373                 boost::shared_ptr<RouteList> rl (new RouteList);
374                 rl->push_back (rtv->route());
375                 if (Config->get_solo_control_is_listen_control()) {
376                         _session->set_listen (rl, !rtv->route()->listening_via_monitor(), Session::rt_cleanup);
377                 } else {
378                         _session->set_solo (rl, !rtv->route()->self_soloed(), Session::rt_cleanup);
379                 }
380         }
381 }
382
383 void
384 EditorRoutes::on_tv_solo_isolate_toggled (std::string const & path_string)
385 {
386         // Get the model row that has been toggled.
387         Gtk::TreeModel::Row row = *_model->get_iter (Gtk::TreeModel::Path (path_string));
388
389         TimeAxisView *tv = row[_columns.tv];
390         RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
391
392         if (rtv) {
393                 rtv->route()->set_solo_isolated (!rtv->route()->solo_isolated(), this);
394         }
395 }
396
397 void
398 EditorRoutes::on_tv_solo_safe_toggled (std::string const & path_string)
399 {
400         // Get the model row that has been toggled.
401         Gtk::TreeModel::Row row = *_model->get_iter (Gtk::TreeModel::Path (path_string));
402
403         TimeAxisView *tv = row[_columns.tv];
404         RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
405
406         if (rtv) {
407                 rtv->route()->set_solo_safe (!rtv->route()->solo_safe(), this);
408         }
409 }
410
411 void
412 EditorRoutes::build_menu ()
413 {
414         using namespace Menu_Helpers;
415         using namespace Gtk;
416
417         _menu = new Menu;
418
419         MenuList& items = _menu->items();
420         _menu->set_name ("ArdourContextMenu");
421
422         items.push_back (MenuElem (_("Show All"), sigc::mem_fun (*this, &EditorRoutes::show_all_routes)));
423         items.push_back (MenuElem (_("Hide All"), sigc::mem_fun (*this, &EditorRoutes::hide_all_routes)));
424         items.push_back (MenuElem (_("Show All Audio Tracks"), sigc::mem_fun (*this, &EditorRoutes::show_all_audiotracks)));
425         items.push_back (MenuElem (_("Hide All Audio Tracks"), sigc::mem_fun (*this, &EditorRoutes::hide_all_audiotracks)));
426         items.push_back (MenuElem (_("Show All Audio Busses"), sigc::mem_fun (*this, &EditorRoutes::show_all_audiobus)));
427         items.push_back (MenuElem (_("Hide All Audio Busses"), sigc::mem_fun (*this, &EditorRoutes::hide_all_audiobus)));
428         items.push_back (MenuElem (_("Show All Midi Tracks"), sigc::mem_fun (*this, &EditorRoutes::show_all_miditracks)));
429         items.push_back (MenuElem (_("Hide All Midi Tracks"), sigc::mem_fun (*this, &EditorRoutes::hide_all_miditracks)));
430         items.push_back (MenuElem (_("Show Tracks With Regions Under Playhead"), sigc::mem_fun (*this, &EditorRoutes::show_tracks_with_regions_at_playhead)));
431 }
432
433 void
434 EditorRoutes::show_menu ()
435 {
436         if (_menu == 0) {
437                 build_menu ();
438         }
439
440         _menu->popup (1, gtk_get_current_event_time());
441 }
442
443 void
444 EditorRoutes::redisplay ()
445 {
446         if (_no_redisplay || !_session) {
447                 return;
448         }
449
450         TreeModel::Children rows = _model->children();
451         TreeModel::Children::iterator i;
452         uint32_t position;
453         int n;
454
455         for (n = 0, position = 0, i = rows.begin(); i != rows.end(); ++i) {
456                 TimeAxisView *tv = (*i)[_columns.tv];
457                 boost::shared_ptr<Route> route = (*i)[_columns.route];
458
459                 if (tv == 0) {
460                         // just a "title" row
461                         continue;
462                 }
463
464                 if (!_redisplay_does_not_reset_order_keys) {
465                         /* this reorder is caused by user action, so reassign sort order keys
466                            to tracks.
467                         */
468                         route->set_order_key (N_ ("editor"), n);
469                 }
470
471                 bool visible = (*i)[_columns.visible];
472
473                 /* show or hide the TimeAxisView */
474                 if (visible) {
475                         tv->set_marked_for_display (true);
476                         position += tv->show_at (position, n, &_editor->edit_controls_vbox);
477                         tv->clip_to_viewport ();
478                 } else {
479                         tv->set_visibility (false);
480                 }
481
482                 n++;
483         }
484
485
486         /* whenever we go idle, update the track view list to reflect the new order.
487            we can't do this here, because we could mess up something that is traversing
488            the track order and has caused a redisplay of the list.
489         */
490         Glib::signal_idle().connect (sigc::mem_fun (*_editor, &Editor::sync_track_view_list_and_routes));
491
492         _editor->reset_controls_layout_height (position);
493         _editor->reset_controls_layout_width ();
494         _editor->full_canvas_height = position + _editor->canvas_timebars_vsize;
495         _editor->vertical_adjustment.set_upper (_editor->full_canvas_height);
496
497         if ((_editor->vertical_adjustment.get_value() + _editor->_canvas_height) > _editor->vertical_adjustment.get_upper()) {
498                 /*
499                    We're increasing the size of the canvas while the bottom is visible.
500                    We scroll down to keep in step with the controls layout.
501                 */
502                 _editor->vertical_adjustment.set_value (_editor->full_canvas_height - _editor->_canvas_height);
503         }
504
505         if (!_redisplay_does_not_reset_order_keys && !_redisplay_does_not_sync_order_keys) {
506                 _session->sync_order_keys (N_ ("editor"));
507         }
508 }
509
510 void
511 EditorRoutes::route_deleted (Gtk::TreeModel::Path const &)
512 {
513         if (!_session || _session->deletion_in_progress()) {
514                 return;
515         }
516
517         /* this could require an order reset & sync */
518         _session->set_remote_control_ids();
519         _ignore_reorder = true;
520         redisplay ();
521         _ignore_reorder = false;
522 }
523
524 void
525 EditorRoutes::visible_changed (std::string const & path)
526 {
527         if (_session && _session->deletion_in_progress()) {
528                 return;
529         }
530
531         TreeIter iter;
532
533         if ((iter = _model->get_iter (path))) {
534                 TimeAxisView* tv = (*iter)[_columns.tv];
535                 if (tv) {
536                         bool visible = (*iter)[_columns.visible];
537                         (*iter)[_columns.visible] = !visible;
538                 }
539         }
540
541         _redisplay_does_not_reset_order_keys = true;
542         _session->set_remote_control_ids();
543         redisplay ();
544         _redisplay_does_not_reset_order_keys = false;
545 }
546
547 void
548 EditorRoutes::routes_added (list<RouteTimeAxisView*> routes)
549 {
550         TreeModel::Row row;
551
552         _redisplay_does_not_sync_order_keys = true;
553         suspend_redisplay ();
554
555         for (list<RouteTimeAxisView*>::iterator x = routes.begin(); x != routes.end(); ++x) {
556
557                 boost::shared_ptr<MidiTrack> midi_trk = boost::dynamic_pointer_cast<MidiTrack> ((*x)->route());
558
559                 row = *(_model->append ());
560
561                 row[_columns.text] = (*x)->route()->name();
562                 row[_columns.visible] = (*x)->marked_for_display();
563                 row[_columns.tv] = *x;
564                 row[_columns.route] = (*x)->route ();
565                 row[_columns.is_track] = (boost::dynamic_pointer_cast<Track> ((*x)->route()) != 0);
566
567                 if (midi_trk) {
568                         row[_columns.is_input_active] = midi_trk->input_active ();
569                         row[_columns.is_midi] = true;
570                 } else {
571                         row[_columns.is_input_active] = false;
572                         row[_columns.is_midi] = false;
573                 }
574
575                 row[_columns.mute_state] = (*x)->route()->muted();
576                 row[_columns.solo_state] = RouteUI::solo_visual_state ((*x)->route());
577                 row[_columns.solo_isolate_state] = (*x)->route()->solo_isolated();
578                 row[_columns.solo_safe_state] = (*x)->route()->solo_safe();
579                 row[_columns.name_editable] = true;
580
581                 _ignore_reorder = true;
582
583                 /* added a new fresh one at the end */
584                 if ((*x)->route()->order_key (N_ ("editor")) == -1) {
585                         (*x)->route()->set_order_key (N_ ("editor"), _model->children().size()-1);
586                 }
587
588                 _ignore_reorder = false;
589
590                 boost::weak_ptr<Route> wr ((*x)->route());
591
592                 (*x)->route()->gui_changed.connect (*this, MISSING_INVALIDATOR, ui_bind (&EditorRoutes::handle_gui_changes, this, _1, _2), gui_context());
593                 (*x)->route()->PropertyChanged.connect (*this, MISSING_INVALIDATOR, ui_bind (&EditorRoutes::route_property_changed, this, _1, wr), gui_context());
594
595                 if ((*x)->is_track()) {
596                         boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track> ((*x)->route());
597                         t->RecordEnableChanged.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::update_rec_display, this), gui_context());
598                 }
599
600                 if ((*x)->is_midi_track()) {
601                         boost::shared_ptr<MidiTrack> t = boost::dynamic_pointer_cast<MidiTrack> ((*x)->route());
602                         t->StepEditStatusChange.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::update_rec_display, this), gui_context());
603                         t->InputActiveChanged.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::update_input_active_display, this), gui_context());
604                 }
605
606                 (*x)->route()->mute_changed.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::update_mute_display, this), gui_context());
607                 (*x)->route()->solo_changed.connect (*this, MISSING_INVALIDATOR, ui_bind (&EditorRoutes::update_solo_display, this, _1), gui_context());
608                 (*x)->route()->listen_changed.connect (*this, MISSING_INVALIDATOR, ui_bind (&EditorRoutes::update_solo_display, this, _1), gui_context());
609                 (*x)->route()->solo_isolated_changed.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::update_solo_isolate_display, this), gui_context());
610                 (*x)->route()->solo_safe_changed.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::update_solo_safe_display, this), gui_context());
611         }
612
613         update_rec_display ();
614         update_mute_display ();
615         update_solo_display (true);
616         update_solo_isolate_display ();
617         update_solo_safe_display ();
618         update_input_active_display ();
619         resume_redisplay ();
620         _redisplay_does_not_sync_order_keys = false;
621 }
622
623 void
624 EditorRoutes::handle_gui_changes (string const & what, void*)
625 {
626         ENSURE_GUI_THREAD (*this, &EditorRoutes::handle_gui_changes, what, src)
627
628         if (what == "track_height") {
629                 /* Optional :make tracks change height while it happens, instead
630                    of on first-idle
631                 */
632                 //update_canvas_now ();
633                 redisplay ();
634         }
635
636         if (what == "visible_tracks") {
637                 redisplay ();
638         }
639 }
640
641 void
642 EditorRoutes::route_removed (TimeAxisView *tv)
643 {
644         ENSURE_GUI_THREAD (*this, &EditorRoutes::route_removed, tv)
645
646         TreeModel::Children rows = _model->children();
647         TreeModel::Children::iterator ri;
648
649         /* the core model has changed, there is no need to sync
650            view orders.
651         */
652
653         _redisplay_does_not_sync_order_keys = true;
654
655         for (ri = rows.begin(); ri != rows.end(); ++ri) {
656                 if ((*ri)[_columns.tv] == tv) {
657                         _model->erase (ri);
658                         break;
659                 }
660         }
661
662         _redisplay_does_not_sync_order_keys = false;
663 }
664
665 void
666 EditorRoutes::route_property_changed (const PropertyChange& what_changed, boost::weak_ptr<Route> r)
667 {
668         if (!what_changed.contains (ARDOUR::Properties::name)) {
669                 return;
670         }
671
672         ENSURE_GUI_THREAD (*this, &EditorRoutes::route_name_changed, r)
673
674         boost::shared_ptr<Route> route = r.lock ();
675
676         if (!route) {
677                 return;
678         }
679
680         TreeModel::Children rows = _model->children();
681         TreeModel::Children::iterator i;
682
683         for (i = rows.begin(); i != rows.end(); ++i) {
684                 boost::shared_ptr<Route> t = (*i)[_columns.route];
685                 if (t == route) {
686                         (*i)[_columns.text] = route->name();
687                         break;
688                 }
689         }
690 }
691
692 void
693 EditorRoutes::update_visibility ()
694 {
695         TreeModel::Children rows = _model->children();
696         TreeModel::Children::iterator i;
697
698         suspend_redisplay ();
699
700         for (i = rows.begin(); i != rows.end(); ++i) {
701                 TimeAxisView *tv = (*i)[_columns.tv];
702                 (*i)[_columns.visible] = tv->marked_for_display ();
703                 cerr << "marked " << tv->name() << " for display = " << tv->marked_for_display() << endl;
704         }
705
706         resume_redisplay ();
707 }
708
709 void
710 EditorRoutes::hide_track_in_display (TimeAxisView& tv)
711 {
712         TreeModel::Children rows = _model->children();
713         TreeModel::Children::iterator i;
714
715         for (i = rows.begin(); i != rows.end(); ++i) {
716                 if ((*i)[_columns.tv] == &tv) {
717                         (*i)[_columns.visible] = false;
718                         break;
719                 }
720         }
721
722         redisplay ();
723 }
724
725 void
726 EditorRoutes::show_track_in_display (TimeAxisView& tv)
727 {
728         TreeModel::Children rows = _model->children();
729         TreeModel::Children::iterator i;
730
731         for (i = rows.begin(); i != rows.end(); ++i) {
732                 if ((*i)[_columns.tv] == &tv) {
733                         (*i)[_columns.visible] = true;
734                         break;
735                 }
736         }
737
738         redisplay ();
739 }
740
741 void
742 EditorRoutes::reordered (TreeModel::Path const &, TreeModel::iterator const &, int* /*what*/)
743 {
744         redisplay ();
745 }
746
747 /** If src != "editor", take editor order keys from each route and use them to rearrange the
748  *  route list so that the visual arrangement of routes matches the order keys from the routes.
749  */
750 void
751 EditorRoutes::sync_order_keys (string const & src)
752 {
753         map<int, int> new_order;
754         TreeModel::Children rows = _model->children();
755         TreeModel::Children::iterator ri;
756
757         if (src == N_ ("editor") || !_session || (_session->state_of_the_state() & (Session::Loading|Session::Deletion)) || rows.empty()) {
758                 return;
759         }
760
761         bool changed = false;
762         int order;
763
764         for (order = 0, ri = rows.begin(); ri != rows.end(); ++ri, ++order) {
765                 boost::shared_ptr<Route> route = (*ri)[_columns.route];
766
767                 int const old_key = order;
768                 int const new_key = route->order_key (N_ ("editor"));
769
770                 new_order[new_key] = old_key;
771
772                 if (new_key != old_key) {
773                         changed = true;
774                 }
775         }
776
777         if (changed) {
778                 _redisplay_does_not_reset_order_keys = true;
779
780                 /* `compact' new_order into a vector */
781                 vector<int> co;
782                 for (map<int, int>::const_iterator i = new_order.begin(); i != new_order.end(); ++i) {
783                         co.push_back (i->second);
784                 }
785
786                 _model->reorder (co);
787                 _redisplay_does_not_reset_order_keys = false;
788         }
789 }
790
791
792 void
793 EditorRoutes::hide_all_tracks (bool /*with_select*/)
794 {
795         TreeModel::Children rows = _model->children();
796         TreeModel::Children::iterator i;
797
798         suspend_redisplay ();
799
800         for (i = rows.begin(); i != rows.end(); ++i) {
801
802                 TreeModel::Row row = (*i);
803                 TimeAxisView *tv = row[_columns.tv];
804
805                 if (tv == 0) {
806                         continue;
807                 }
808
809                 row[_columns.visible] = false;
810         }
811
812         resume_redisplay ();
813
814         /* XXX this seems like a hack and half, but its not clear where to put this
815            otherwise.
816         */
817
818         //reset_scrolling_region ();
819 }
820
821 void
822 EditorRoutes::set_all_tracks_visibility (bool yn)
823 {
824         TreeModel::Children rows = _model->children();
825         TreeModel::Children::iterator i;
826
827         suspend_redisplay ();
828
829         for (i = rows.begin(); i != rows.end(); ++i) {
830
831                 TreeModel::Row row = (*i);
832                 TimeAxisView* tv = row[_columns.tv];
833
834                 if (tv == 0) {
835                         continue;
836                 }
837
838                 (*i)[_columns.visible] = yn;
839         }
840
841         resume_redisplay ();
842 }
843
844 void
845 EditorRoutes::set_all_audio_midi_visibility (int tracks, bool yn)
846 {
847         TreeModel::Children rows = _model->children();
848         TreeModel::Children::iterator i;
849
850         suspend_redisplay ();
851
852         for (i = rows.begin(); i != rows.end(); ++i) {
853
854                 TreeModel::Row row = (*i);
855                 TimeAxisView* tv = row[_columns.tv];
856
857                 AudioTimeAxisView* atv;
858                 MidiTimeAxisView* mtv;
859
860                 if (tv == 0) {
861                         continue;
862                 }
863
864                 if ((atv = dynamic_cast<AudioTimeAxisView*>(tv)) != 0) {
865                         switch (tracks) {
866                         case 0:
867                                 (*i)[_columns.visible] = yn;
868                                 break;
869
870                         case 1:
871                                 if (atv->is_audio_track()) {
872                                         (*i)[_columns.visible] = yn;
873                                 }
874                                 break;
875
876                         case 2:
877                                 if (!atv->is_audio_track()) {
878                                         (*i)[_columns.visible] = yn;
879                                 }
880                                 break;
881                         }
882                 }
883                 else if ((mtv = dynamic_cast<MidiTimeAxisView*>(tv)) != 0) {
884                         switch (tracks) {
885                         case 0:
886                                 (*i)[_columns.visible] = yn;
887                                 break;
888
889                         case 3:
890                                 if (mtv->is_midi_track()) {
891                                         (*i)[_columns.visible] = yn;
892                                 }
893                                 break;
894                         }
895                 }
896         }
897
898         resume_redisplay ();
899 }
900
901 void
902 EditorRoutes::hide_all_routes ()
903 {
904         set_all_tracks_visibility (false);
905 }
906
907 void
908 EditorRoutes::show_all_routes ()
909 {
910         set_all_tracks_visibility (true);
911 }
912
913 void
914 EditorRoutes::show_all_audiotracks()
915 {
916         set_all_audio_midi_visibility (1, true);
917 }
918 void
919 EditorRoutes::hide_all_audiotracks ()
920 {
921         set_all_audio_midi_visibility (1, false);
922 }
923
924 void
925 EditorRoutes::show_all_audiobus ()
926 {
927         set_all_audio_midi_visibility (2, true);
928 }
929 void
930 EditorRoutes::hide_all_audiobus ()
931 {
932         set_all_audio_midi_visibility (2, false);
933 }
934
935 void
936 EditorRoutes::show_all_miditracks()
937 {
938         set_all_audio_midi_visibility (3, true);
939 }
940 void
941 EditorRoutes::hide_all_miditracks ()
942 {
943         set_all_audio_midi_visibility (3, false);
944 }
945
946 bool
947 EditorRoutes::key_press (GdkEventKey* ev)
948 {
949         TreeViewColumn *col;
950         boost::shared_ptr<RouteList> rl (new RouteList);
951         TreePath path;
952
953         switch (ev->keyval) {
954         case GDK_Tab:
955         case GDK_ISO_Left_Tab:
956
957                 /* If we appear to be editing something, leave that cleanly and appropriately.
958                 */
959                 if (name_editable) {
960                         name_editable->editing_done ();
961                         name_editable = 0;
962                 }
963
964                 col = _display.get_column (_name_column); // select&focus on name column
965
966                 if (Keyboard::modifier_state_equals (ev->state, Keyboard::TertiaryModifier)) {
967                         treeview_select_previous (_display, _model, col);
968                 } else {
969                         treeview_select_next (_display, _model, col);
970                 }
971
972                 return true;
973                 break;
974
975         case 'm':
976                 if (get_relevant_routes (rl)) {
977                         _session->set_mute (rl, !rl->front()->muted(), Session::rt_cleanup);
978                 }
979                 return true;
980                 break;
981
982         case 's':
983                 if (Config->get_solo_control_is_listen_control()) {
984                         _session->set_listen (rl, !rl->front()->listening_via_monitor(), Session::rt_cleanup);
985                 } else {
986                         _session->set_solo (rl, !rl->front()->self_soloed(), Session::rt_cleanup);
987                 }
988                 return true;
989                 break;
990
991         case 'r':
992                 if (get_relevant_routes (rl)) {
993                         _session->set_record_enabled (rl, !rl->front()->record_enabled(), Session::rt_cleanup);
994                 }
995                 break;
996
997         default:
998                 break;
999         }
1000
1001         return false;
1002 }
1003
1004 bool
1005 EditorRoutes::get_relevant_routes (boost::shared_ptr<RouteList> rl)
1006 {
1007         TimeAxisView* tv;
1008         RouteTimeAxisView* rtv;
1009         RefPtr<TreeSelection> selection = _display.get_selection();
1010         TreePath path;
1011         TreeIter iter;
1012
1013         if (selection->count_selected_rows() != 0) {
1014
1015                 /* use selection */
1016
1017                 RefPtr<TreeModel> tm = RefPtr<TreeModel>::cast_dynamic (_model);
1018                 iter = selection->get_selected (tm);
1019
1020         } else {
1021                 /* use mouse pointer */
1022
1023                 int x, y;
1024                 int bx, by;
1025
1026                 _display.get_pointer (x, y);
1027                 _display.convert_widget_to_bin_window_coords (x, y, bx, by);
1028
1029                 if (_display.get_path_at_pos (bx, by, path)) {
1030                         iter = _model->get_iter (path);
1031                 }
1032         }
1033
1034         if (iter) {
1035                 tv = (*iter)[_columns.tv];
1036                 if (tv) {
1037                         rtv = dynamic_cast<RouteTimeAxisView*>(tv);
1038                         if (rtv) {
1039                                 rl->push_back (rtv->route());
1040                         }
1041                 }
1042         }
1043
1044         return !rl->empty();
1045 }
1046
1047 bool
1048 EditorRoutes::button_press (GdkEventButton* ev)
1049 {
1050         if (Keyboard::is_context_menu_event (ev)) {
1051                 show_menu ();
1052                 return true;
1053         }
1054
1055         //Scroll editor canvas to selected track
1056         if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
1057
1058                 TreeModel::Path path;
1059                 TreeViewColumn *tvc;
1060                 int cell_x;
1061                 int cell_y;
1062
1063                 _display.get_path_at_pos ((int) ev->x, (int) ev->y, path, tvc, cell_x, cell_y);
1064
1065                 // Get the model row.
1066                 Gtk::TreeModel::Row row = *_model->get_iter (path);
1067
1068                 TimeAxisView *tv = row[_columns.tv];
1069
1070                 int y_pos = tv->y_position();
1071
1072                 //Clamp the y pos so that we do not extend beyond the canvas full height.
1073                 if (_editor->full_canvas_height - y_pos < _editor->_canvas_height){
1074                     y_pos = _editor->full_canvas_height - _editor->_canvas_height;
1075                 }
1076
1077                 //Only scroll to if the track is visible
1078                 if(y_pos != -1){
1079                     _editor->reset_y_origin (y_pos);
1080                 }
1081         }
1082
1083         return false;
1084 }
1085
1086 bool
1087 EditorRoutes::selection_filter (Glib::RefPtr<TreeModel> const &, TreeModel::Path const&, bool /*selected*/)
1088 {
1089         if (selection_countdown) {
1090                 if (--selection_countdown == 0) {
1091                         return true;
1092                 } else {
1093                         /* no selection yet ... */
1094                         return false;
1095                 }
1096         }
1097         return true;
1098 }
1099
1100 struct EditorOrderRouteSorter {
1101     bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
1102             /* use of ">" forces the correct sort order */
1103             return a->order_key (N_ ("editor")) < b->order_key (N_ ("editor"));
1104     }
1105 };
1106
1107 void
1108 EditorRoutes::initial_display ()
1109 {
1110         suspend_redisplay ();
1111         _model->clear ();
1112
1113         if (!_session) {
1114                 resume_redisplay ();
1115                 return;
1116         }
1117
1118         boost::shared_ptr<RouteList> routes = _session->get_routes();
1119         RouteList r (*routes);
1120         EditorOrderRouteSorter sorter;
1121
1122         r.sort (sorter);
1123         _editor->handle_new_route (r);
1124
1125         /* don't show master bus in a new session */
1126
1127         if (ARDOUR_UI::instance()->session_is_new ()) {
1128
1129                 TreeModel::Children rows = _model->children();
1130                 TreeModel::Children::iterator i;
1131
1132                 _no_redisplay = true;
1133
1134                 for (i = rows.begin(); i != rows.end(); ++i) {
1135
1136                         TimeAxisView *tv =  (*i)[_columns.tv];
1137                         RouteTimeAxisView *rtv;
1138
1139                         if ((rtv = dynamic_cast<RouteTimeAxisView*>(tv)) != 0) {
1140                                 if (rtv->route()->is_master()) {
1141                                         _display.get_selection()->unselect (i);
1142                                 }
1143                         }
1144                 }
1145
1146                 _no_redisplay = false;
1147                 redisplay ();
1148         }
1149
1150         resume_redisplay ();
1151 }
1152
1153 void
1154 EditorRoutes::track_list_reorder (Gtk::TreeModel::Path const &, Gtk::TreeModel::iterator const &, int* /*new_order*/)
1155 {
1156         _redisplay_does_not_sync_order_keys = true;
1157         _session->set_remote_control_ids();
1158         redisplay ();
1159         _redisplay_does_not_sync_order_keys = false;
1160 }
1161
1162 void
1163 EditorRoutes::display_drag_data_received (const RefPtr<Gdk::DragContext>& context,
1164                                              int x, int y,
1165                                              const SelectionData& data,
1166                                              guint info, guint time)
1167 {
1168         if (data.get_target() == "GTK_TREE_MODEL_ROW") {
1169                 _display.on_drag_data_received (context, x, y, data, info, time);
1170                 return;
1171         }
1172
1173         context->drag_finish (true, false, time);
1174 }
1175
1176 void
1177 EditorRoutes::move_selected_tracks (bool up)
1178 {
1179         if (_editor->selection->tracks.empty()) {
1180                 return;
1181         }
1182
1183         typedef std::pair<TimeAxisView*,boost::shared_ptr<Route> > ViewRoute;
1184         std::list<ViewRoute> view_routes;
1185         std::vector<int> neworder;
1186         TreeModel::Children rows = _model->children();
1187         TreeModel::Children::iterator ri;
1188
1189         for (ri = rows.begin(); ri != rows.end(); ++ri) {
1190                 TimeAxisView* tv = (*ri)[_columns.tv];
1191                 boost::shared_ptr<Route> route = (*ri)[_columns.route];
1192
1193                 view_routes.push_back (ViewRoute (tv, route));
1194         }
1195
1196         list<ViewRoute>::iterator trailing;
1197         list<ViewRoute>::iterator leading;
1198
1199         if (up) {
1200
1201                 trailing = view_routes.begin();
1202                 leading = view_routes.begin();
1203
1204                 ++leading;
1205
1206                 while (leading != view_routes.end()) {
1207                         if (_editor->selection->selected (leading->first)) {
1208                                 view_routes.insert (trailing, ViewRoute (leading->first, leading->second));
1209                                 leading = view_routes.erase (leading);
1210                         } else {
1211                                 ++leading;
1212                                 ++trailing;
1213                         }
1214                 }
1215
1216         } else {
1217
1218                 /* if we could use reverse_iterator in list::insert, this code
1219                    would be a beautiful reflection of the code above. but we can't
1220                    and so it looks like a bit of a mess.
1221                 */
1222
1223                 trailing = view_routes.end();
1224                 leading = view_routes.end();
1225
1226                 --leading; if (leading == view_routes.begin()) { return; }
1227                 --leading;
1228                 --trailing;
1229
1230                 while (1) {
1231
1232                         if (_editor->selection->selected (leading->first)) {
1233                                 list<ViewRoute>::iterator tmp;
1234
1235                                 /* need to insert *after* trailing, not *before* it,
1236                                    which is what insert (iter, val) normally does.
1237                                 */
1238
1239                                 tmp = trailing;
1240                                 tmp++;
1241
1242                                 view_routes.insert (tmp, ViewRoute (leading->first, leading->second));
1243
1244                                 /* can't use iter = cont.erase (iter); form here, because
1245                                    we need iter to move backwards.
1246                                 */
1247
1248                                 tmp = leading;
1249                                 --tmp;
1250
1251                                 bool done = false;
1252
1253                                 if (leading == view_routes.begin()) {
1254                                         /* the one we've just inserted somewhere else
1255                                            was the first in the list. erase this copy,
1256                                            and then break, because we're done.
1257                                         */
1258                                         done = true;
1259                                 }
1260
1261                                 view_routes.erase (leading);
1262
1263                                 if (done) {
1264                                         break;
1265                                 }
1266
1267                                 leading = tmp;
1268
1269                         } else {
1270                                 if (leading == view_routes.begin()) {
1271                                         break;
1272                                 }
1273                                 --leading;
1274                                 --trailing;
1275                         }
1276                 };
1277         }
1278
1279         for (leading = view_routes.begin(); leading != view_routes.end(); ++leading) {
1280                 neworder.push_back (leading->second->order_key (N_ ("editor")));
1281         }
1282
1283         _model->reorder (neworder);
1284
1285        _session->sync_order_keys (N_ ("editor"));
1286 }
1287
1288 void
1289 EditorRoutes::update_input_active_display ()
1290 {
1291         TreeModel::Children rows = _model->children();
1292         TreeModel::Children::iterator i;
1293
1294         for (i = rows.begin(); i != rows.end(); ++i) {
1295                 boost::shared_ptr<Route> route = (*i)[_columns.route];
1296
1297                 if (boost::dynamic_pointer_cast<Track> (route)) {
1298                         boost::shared_ptr<MidiTrack> mt = boost::dynamic_pointer_cast<MidiTrack> (route);
1299                         
1300                         if (mt) {
1301                                 (*i)[_columns.is_input_active] = mt->input_active();
1302                         }
1303                 }
1304         }
1305 }
1306
1307 void
1308 EditorRoutes::update_rec_display ()
1309 {
1310         TreeModel::Children rows = _model->children();
1311         TreeModel::Children::iterator i;
1312
1313         for (i = rows.begin(); i != rows.end(); ++i) {
1314                 boost::shared_ptr<Route> route = (*i)[_columns.route];
1315
1316                 if (boost::dynamic_pointer_cast<Track> (route)) {
1317                         boost::shared_ptr<MidiTrack> mt = boost::dynamic_pointer_cast<MidiTrack> (route);
1318
1319                         if (route->record_enabled()) {
1320                                 if (_session->record_status() == Session::Recording) {
1321                                         (*i)[_columns.rec_state] = 1;
1322                                 } else {
1323                                         (*i)[_columns.rec_state] = 2;
1324                                 }
1325                         } else if (mt && mt->step_editing()) {
1326                                 (*i)[_columns.rec_state] = 3;
1327                         } else {
1328                                 (*i)[_columns.rec_state] = 0;
1329                         }
1330
1331                         (*i)[_columns.name_editable] = !route->record_enabled ();
1332                 }
1333         }
1334 }
1335
1336 void
1337 EditorRoutes::update_mute_display ()
1338 {
1339         TreeModel::Children rows = _model->children();
1340         TreeModel::Children::iterator i;
1341
1342         for (i = rows.begin(); i != rows.end(); ++i) {
1343                 boost::shared_ptr<Route> route = (*i)[_columns.route];
1344                 (*i)[_columns.mute_state] = RouteUI::mute_visual_state (_session, route);
1345         }
1346 }
1347
1348 void
1349 EditorRoutes::update_solo_display (bool /* selfsoloed */)
1350 {
1351         TreeModel::Children rows = _model->children();
1352         TreeModel::Children::iterator i;
1353
1354         for (i = rows.begin(); i != rows.end(); ++i) {
1355                 boost::shared_ptr<Route> route = (*i)[_columns.route];
1356                 (*i)[_columns.solo_state] = RouteUI::solo_visual_state (route);
1357         }
1358 }
1359
1360 void
1361 EditorRoutes::update_solo_isolate_display ()
1362 {
1363         TreeModel::Children rows = _model->children();
1364         TreeModel::Children::iterator i;
1365
1366         for (i = rows.begin(); i != rows.end(); ++i) {
1367                 boost::shared_ptr<Route> route = (*i)[_columns.route];
1368                 (*i)[_columns.solo_isolate_state] = RouteUI::solo_isolate_visual_state (route) > 0 ? 1 : 0;
1369         }
1370 }
1371
1372 void
1373 EditorRoutes::update_solo_safe_display ()
1374 {
1375         TreeModel::Children rows = _model->children();
1376         TreeModel::Children::iterator i;
1377
1378         for (i = rows.begin(); i != rows.end(); ++i) {
1379                 boost::shared_ptr<Route> route = (*i)[_columns.route];
1380                 (*i)[_columns.solo_safe_state] = RouteUI::solo_safe_visual_state (route) > 0 ? 1 : 0;
1381         }
1382 }
1383
1384 list<TimeAxisView*>
1385 EditorRoutes::views () const
1386 {
1387         list<TimeAxisView*> v;
1388         for (TreeModel::Children::iterator i = _model->children().begin(); i != _model->children().end(); ++i) {
1389                 v.push_back ((*i)[_columns.tv]);
1390         }
1391
1392         return v;
1393 }
1394
1395 void
1396 EditorRoutes::clear ()
1397 {
1398         _display.set_model (Glib::RefPtr<Gtk::TreeStore> (0));
1399         _model->clear ();
1400         _display.set_model (_model);
1401 }
1402
1403 void
1404 EditorRoutes::name_edit_started (CellEditable* ce, const Glib::ustring&)
1405 {
1406         name_editable = ce;
1407
1408         /* give it a special name */
1409
1410         Gtk::Entry *e = dynamic_cast<Gtk::Entry*> (ce);
1411
1412         if (e) {
1413                 e->set_name (X_("RouteNameEditorEntry"));
1414         }
1415 }
1416
1417 void
1418 EditorRoutes::name_edit (std::string const & path, std::string const & new_text)
1419 {
1420         name_editable = 0;
1421
1422         TreeIter iter = _model->get_iter (path);
1423
1424         if (!iter) {
1425                 return;
1426         }
1427
1428         boost::shared_ptr<Route> route = (*iter)[_columns.route];
1429
1430         if (route && route->name() != new_text) {
1431                 route->set_name (new_text);
1432         }
1433 }
1434
1435 void
1436 EditorRoutes::solo_changed_so_update_mute ()
1437 {
1438         update_mute_display ();
1439 }
1440
1441 void
1442 EditorRoutes::show_tracks_with_regions_at_playhead ()
1443 {
1444         boost::shared_ptr<RouteList> const r = _session->get_routes_with_regions_at (_session->transport_frame ());
1445
1446         set<TimeAxisView*> show;
1447         for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
1448                 TimeAxisView* tav = _editor->axis_view_from_route (*i);
1449                 if (tav) {
1450                         show.insert (tav);
1451                 }
1452         }
1453
1454         suspend_redisplay ();
1455
1456         TreeModel::Children rows = _model->children ();
1457         for (TreeModel::Children::iterator i = rows.begin(); i != rows.end(); ++i) {
1458                 TimeAxisView* tv = (*i)[_columns.tv];
1459                 (*i)[_columns.visible] = (show.find (tv) != show.end());
1460         }
1461
1462         resume_redisplay ();
1463 }