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