f58ea47868fd54f52fbfcf80c51ce97cce38d257
[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("record-normal-disabled"));
83         rec_col_renderer->set_pixbuf (1, ::get_icon("record-normal-in-progress"));
84         rec_col_renderer->set_pixbuf (2, ::get_icon("record-normal-enabled"));
85         rec_col_renderer->set_pixbuf (3, ::get_icon("record-step"));
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("midi-input-inactive"));
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 = tv->marked_for_display ();
472
473                 /* show or hide the TimeAxisView */
474                 if (visible) {
475                         position += tv->show_at (position, n, &_editor->edit_controls_vbox);
476                         tv->clip_to_viewport ();
477                         n++;
478                 } else {
479                         tv->hide ();
480                 }
481         }
482
483         /* whenever we go idle, update the track view list to reflect the new order.
484            we can't do this here, because we could mess up something that is traversing
485            the track order and has caused a redisplay of the list.
486         */
487         Glib::signal_idle().connect (sigc::mem_fun (*_editor, &Editor::sync_track_view_list_and_routes));
488
489         _editor->reset_controls_layout_height (position);
490         _editor->reset_controls_layout_width ();
491         _editor->full_canvas_height = position + _editor->canvas_timebars_vsize;
492         _editor->vertical_adjustment.set_upper (_editor->full_canvas_height);
493
494         if ((_editor->vertical_adjustment.get_value() + _editor->_canvas_height) > _editor->vertical_adjustment.get_upper()) {
495                 /*
496                    We're increasing the size of the canvas while the bottom is visible.
497                    We scroll down to keep in step with the controls layout.
498                 */
499                 _editor->vertical_adjustment.set_value (_editor->full_canvas_height - _editor->_canvas_height);
500         }
501
502         if (!_redisplay_does_not_reset_order_keys && !_redisplay_does_not_sync_order_keys) {
503                 _session->sync_order_keys (N_ ("editor"));
504         }
505 }
506
507 void
508 EditorRoutes::route_deleted (Gtk::TreeModel::Path const &)
509 {
510         if (!_session || _session->deletion_in_progress()) {
511                 return;
512         }
513
514         /* this could require an order reset & sync */
515         _session->set_remote_control_ids();
516         _ignore_reorder = true;
517         redisplay ();
518         _ignore_reorder = false;
519 }
520
521 void
522 EditorRoutes::visible_changed (std::string const & path)
523 {
524         if (_session && _session->deletion_in_progress()) {
525                 return;
526         }
527
528         TreeIter iter;
529
530         if ((iter = _model->get_iter (path))) {
531                 TimeAxisView* tv = (*iter)[_columns.tv];
532                 if (tv) {
533                         bool visible = (*iter)[_columns.visible];
534
535                         if (tv->set_marked_for_display (!visible)) {
536                                 _redisplay_does_not_reset_order_keys = true;
537                                 _session->set_remote_control_ids();
538                                 update_visibility ();
539                                 redisplay ();
540                                 _redisplay_does_not_reset_order_keys = false;
541                         }
542                 }
543         }
544 }
545
546 void
547 EditorRoutes::routes_added (list<RouteTimeAxisView*> routes)
548 {
549         TreeModel::Row row;
550
551         _redisplay_does_not_sync_order_keys = true;
552         suspend_redisplay ();
553
554         for (list<RouteTimeAxisView*>::iterator x = routes.begin(); x != routes.end(); ++x) {
555
556                 boost::shared_ptr<MidiTrack> midi_trk = boost::dynamic_pointer_cast<MidiTrack> ((*x)->route());
557
558                 row = *(_model->append ());
559
560                 row[_columns.text] = (*x)->route()->name();
561                 row[_columns.visible] = (*x)->marked_for_display();
562                 row[_columns.tv] = *x;
563                 row[_columns.route] = (*x)->route ();
564                 row[_columns.is_track] = (boost::dynamic_pointer_cast<Track> ((*x)->route()) != 0);
565
566                 if (midi_trk) {
567                         row[_columns.is_input_active] = midi_trk->input_active ();
568                         row[_columns.is_midi] = true;
569                 } else {
570                         row[_columns.is_input_active] = false;
571                         row[_columns.is_midi] = false;
572                 }
573
574                 row[_columns.mute_state] = (*x)->route()->muted();
575                 row[_columns.solo_state] = RouteUI::solo_visual_state ((*x)->route());
576                 row[_columns.solo_isolate_state] = (*x)->route()->solo_isolated();
577                 row[_columns.solo_safe_state] = (*x)->route()->solo_safe();
578                 row[_columns.name_editable] = true;
579
580                 _ignore_reorder = true;
581
582                 /* added a new fresh one at the end */
583                 if ((*x)->route()->order_key (N_ ("editor")) == -1) {
584                         (*x)->route()->set_order_key (N_ ("editor"), _model->children().size()-1);
585                 }
586
587                 _ignore_reorder = false;
588
589                 boost::weak_ptr<Route> wr ((*x)->route());
590
591                 (*x)->route()->gui_changed.connect (*this, MISSING_INVALIDATOR, ui_bind (&EditorRoutes::handle_gui_changes, this, _1, _2), gui_context());
592                 (*x)->route()->PropertyChanged.connect (*this, MISSING_INVALIDATOR, ui_bind (&EditorRoutes::route_property_changed, this, _1, wr), gui_context());
593
594                 if ((*x)->is_track()) {
595                         boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track> ((*x)->route());
596                         t->RecordEnableChanged.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::update_rec_display, this), gui_context());
597                 }
598
599                 if ((*x)->is_midi_track()) {
600                         boost::shared_ptr<MidiTrack> t = boost::dynamic_pointer_cast<MidiTrack> ((*x)->route());
601                         t->StepEditStatusChange.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::update_rec_display, this), gui_context());
602                         t->InputActiveChanged.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::update_input_active_display, this), gui_context());
603                 }
604
605                 (*x)->route()->mute_changed.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::update_mute_display, this), gui_context());
606                 (*x)->route()->solo_changed.connect (*this, MISSING_INVALIDATOR, ui_bind (&EditorRoutes::update_solo_display, this, _1), gui_context());
607                 (*x)->route()->listen_changed.connect (*this, MISSING_INVALIDATOR, ui_bind (&EditorRoutes::update_solo_display, this, _1), gui_context());
608                 (*x)->route()->solo_isolated_changed.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::update_solo_isolate_display, this), gui_context());
609                 (*x)->route()->solo_safe_changed.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::update_solo_safe_display, this), gui_context());
610         }
611
612         update_rec_display ();
613         update_mute_display ();
614         update_solo_display (true);
615         update_solo_isolate_display ();
616         update_solo_safe_display ();
617         update_input_active_display ();
618         resume_redisplay ();
619         _redisplay_does_not_sync_order_keys = false;
620 }
621
622 void
623 EditorRoutes::handle_gui_changes (string const & what, void*)
624 {
625         ENSURE_GUI_THREAD (*this, &EditorRoutes::handle_gui_changes, what, src)
626
627         if (what == "track_height") {
628                 /* Optional :make tracks change height while it happens, instead
629                    of on first-idle
630                 */
631                 //update_canvas_now ();
632                 redisplay ();
633         }
634
635         if (what == "visible_tracks") {
636                 redisplay ();
637         }
638 }
639
640 void
641 EditorRoutes::route_removed (TimeAxisView *tv)
642 {
643         ENSURE_GUI_THREAD (*this, &EditorRoutes::route_removed, tv)
644
645         TreeModel::Children rows = _model->children();
646         TreeModel::Children::iterator ri;
647
648         /* the core model has changed, there is no need to sync
649            view orders.
650         */
651
652         _redisplay_does_not_sync_order_keys = true;
653
654         for (ri = rows.begin(); ri != rows.end(); ++ri) {
655                 if ((*ri)[_columns.tv] == tv) {
656                         _model->erase (ri);
657                         break;
658                 }
659         }
660
661         _redisplay_does_not_sync_order_keys = false;
662 }
663
664 void
665 EditorRoutes::route_property_changed (const PropertyChange& what_changed, boost::weak_ptr<Route> r)
666 {
667         if (!what_changed.contains (ARDOUR::Properties::name)) {
668                 return;
669         }
670
671         ENSURE_GUI_THREAD (*this, &EditorRoutes::route_name_changed, r)
672
673         boost::shared_ptr<Route> route = r.lock ();
674
675         if (!route) {
676                 return;
677         }
678
679         TreeModel::Children rows = _model->children();
680         TreeModel::Children::iterator i;
681
682         for (i = rows.begin(); i != rows.end(); ++i) {
683                 boost::shared_ptr<Route> t = (*i)[_columns.route];
684                 if (t == route) {
685                         (*i)[_columns.text] = route->name();
686                         break;
687                 }
688         }
689 }
690
691 void
692 EditorRoutes::update_visibility ()
693 {
694         TreeModel::Children rows = _model->children();
695         TreeModel::Children::iterator i;
696
697         suspend_redisplay ();
698
699         for (i = rows.begin(); i != rows.end(); ++i) {
700                 TimeAxisView *tv = (*i)[_columns.tv];
701                 (*i)[_columns.visible] = tv->marked_for_display ();
702         }
703
704         resume_redisplay ();
705 }
706
707 void
708 EditorRoutes::hide_track_in_display (TimeAxisView& tv)
709 {
710         TreeModel::Children rows = _model->children();
711         TreeModel::Children::iterator i;
712
713         for (i = rows.begin(); i != rows.end(); ++i) {
714                 if ((*i)[_columns.tv] == &tv) {
715                         tv.set_marked_for_display (false);
716                         (*i)[_columns.visible] = false;
717                         redisplay ();
718                         break;
719                 }
720         }
721 }
722
723 void
724 EditorRoutes::show_track_in_display (TimeAxisView& tv)
725 {
726         TreeModel::Children rows = _model->children();
727         TreeModel::Children::iterator i;
728
729
730         for (i = rows.begin(); i != rows.end(); ++i) {
731                 if ((*i)[_columns.tv] == &tv) {
732                         tv.set_marked_for_display (true);
733                         (*i)[_columns.visible] = true;
734                         redisplay ();
735                         break;
736                 }
737         }
738 }
739
740 void
741 EditorRoutes::reordered (TreeModel::Path const &, TreeModel::iterator const &, int* /*what*/)
742 {
743         redisplay ();
744 }
745
746 /** If src != "editor", take editor order keys from each route and use them to rearrange the
747  *  route list so that the visual arrangement of routes matches the order keys from the routes.
748  */
749 void
750 EditorRoutes::sync_order_keys (string const & src)
751 {
752         map<int, int> new_order;
753         TreeModel::Children rows = _model->children();
754         TreeModel::Children::iterator ri;
755
756         if (src == N_ ("editor") || !_session || (_session->state_of_the_state() & (Session::Loading|Session::Deletion)) || rows.empty()) {
757                 return;
758         }
759
760         bool changed = false;
761         int order;
762
763         for (order = 0, ri = rows.begin(); ri != rows.end(); ++ri, ++order) {
764                 boost::shared_ptr<Route> route = (*ri)[_columns.route];
765
766                 int const old_key = order;
767                 int const new_key = route->order_key (N_ ("editor"));
768
769                 new_order[new_key] = old_key;
770
771                 if (new_key != old_key) {
772                         changed = true;
773                 }
774         }
775
776         if (changed) {
777                 _redisplay_does_not_reset_order_keys = true;
778
779                 /* `compact' new_order into a vector */
780                 vector<int> co;
781                 for (map<int, int>::const_iterator i = new_order.begin(); i != new_order.end(); ++i) {
782                         co.push_back (i->second);
783                 }
784
785                 _model->reorder (co);
786                 _redisplay_does_not_reset_order_keys = false;
787         }
788 }
789
790
791 void
792 EditorRoutes::hide_all_tracks (bool /*with_select*/)
793 {
794         TreeModel::Children rows = _model->children();
795         TreeModel::Children::iterator i;
796
797         suspend_redisplay ();
798
799         for (i = rows.begin(); i != rows.end(); ++i) {
800
801                 TreeModel::Row row = (*i);
802                 TimeAxisView *tv = row[_columns.tv];
803
804                 if (tv == 0) {
805                         continue;
806                 }
807
808                 row[_columns.visible] = false;
809         }
810
811         resume_redisplay ();
812
813         /* XXX this seems like a hack and half, but its not clear where to put this
814            otherwise.
815         */
816
817         //reset_scrolling_region ();
818 }
819
820 void
821 EditorRoutes::set_all_tracks_visibility (bool yn)
822 {
823         TreeModel::Children rows = _model->children();
824         TreeModel::Children::iterator i;
825
826         suspend_redisplay ();
827
828         for (i = rows.begin(); i != rows.end(); ++i) {
829
830                 TreeModel::Row row = (*i);
831                 TimeAxisView* tv = row[_columns.tv];
832
833                 if (tv == 0) {
834                         continue;
835                 }
836
837                 (*i)[_columns.visible] = yn;
838         }
839
840         resume_redisplay ();
841 }
842
843 void
844 EditorRoutes::set_all_audio_midi_visibility (int tracks, bool yn)
845 {
846         TreeModel::Children rows = _model->children();
847         TreeModel::Children::iterator i;
848
849         suspend_redisplay ();
850
851         for (i = rows.begin(); i != rows.end(); ++i) {
852
853                 TreeModel::Row row = (*i);
854                 TimeAxisView* tv = row[_columns.tv];
855
856                 AudioTimeAxisView* atv;
857                 MidiTimeAxisView* mtv;
858
859                 if (tv == 0) {
860                         continue;
861                 }
862
863                 if ((atv = dynamic_cast<AudioTimeAxisView*>(tv)) != 0) {
864                         switch (tracks) {
865                         case 0:
866                                 (*i)[_columns.visible] = yn;
867                                 break;
868
869                         case 1:
870                                 if (atv->is_audio_track()) {
871                                         (*i)[_columns.visible] = yn;
872                                 }
873                                 break;
874
875                         case 2:
876                                 if (!atv->is_audio_track()) {
877                                         (*i)[_columns.visible] = yn;
878                                 }
879                                 break;
880                         }
881                 }
882                 else if ((mtv = dynamic_cast<MidiTimeAxisView*>(tv)) != 0) {
883                         switch (tracks) {
884                         case 0:
885                                 (*i)[_columns.visible] = yn;
886                                 break;
887
888                         case 3:
889                                 if (mtv->is_midi_track()) {
890                                         (*i)[_columns.visible] = yn;
891                                 }
892                                 break;
893                         }
894                 }
895         }
896
897         resume_redisplay ();
898 }
899
900 void
901 EditorRoutes::hide_all_routes ()
902 {
903         set_all_tracks_visibility (false);
904 }
905
906 void
907 EditorRoutes::show_all_routes ()
908 {
909         set_all_tracks_visibility (true);
910 }
911
912 void
913 EditorRoutes::show_all_audiotracks()
914 {
915         set_all_audio_midi_visibility (1, true);
916 }
917 void
918 EditorRoutes::hide_all_audiotracks ()
919 {
920         set_all_audio_midi_visibility (1, false);
921 }
922
923 void
924 EditorRoutes::show_all_audiobus ()
925 {
926         set_all_audio_midi_visibility (2, true);
927 }
928 void
929 EditorRoutes::hide_all_audiobus ()
930 {
931         set_all_audio_midi_visibility (2, false);
932 }
933
934 void
935 EditorRoutes::show_all_miditracks()
936 {
937         set_all_audio_midi_visibility (3, true);
938 }
939 void
940 EditorRoutes::hide_all_miditracks ()
941 {
942         set_all_audio_midi_visibility (3, false);
943 }
944
945 bool
946 EditorRoutes::key_press (GdkEventKey* ev)
947 {
948         TreeViewColumn *col;
949         boost::shared_ptr<RouteList> rl (new RouteList);
950         TreePath path;
951
952         switch (ev->keyval) {
953         case GDK_Tab:
954         case GDK_ISO_Left_Tab:
955
956                 /* If we appear to be editing something, leave that cleanly and appropriately.
957                 */
958                 if (name_editable) {
959                         name_editable->editing_done ();
960                         name_editable = 0;
961                 }
962
963                 col = _display.get_column (_name_column); // select&focus on name column
964
965                 if (Keyboard::modifier_state_equals (ev->state, Keyboard::TertiaryModifier)) {
966                         treeview_select_previous (_display, _model, col);
967                 } else {
968                         treeview_select_next (_display, _model, col);
969                 }
970
971                 return true;
972                 break;
973
974         case 'm':
975                 if (get_relevant_routes (rl)) {
976                         _session->set_mute (rl, !rl->front()->muted(), Session::rt_cleanup);
977                 }
978                 return true;
979                 break;
980
981         case 's':
982                 if (Config->get_solo_control_is_listen_control()) {
983                         _session->set_listen (rl, !rl->front()->listening_via_monitor(), Session::rt_cleanup);
984                 } else {
985                         _session->set_solo (rl, !rl->front()->self_soloed(), Session::rt_cleanup);
986                 }
987                 return true;
988                 break;
989
990         case 'r':
991                 if (get_relevant_routes (rl)) {
992                         _session->set_record_enabled (rl, !rl->front()->record_enabled(), Session::rt_cleanup);
993                 }
994                 break;
995
996         default:
997                 break;
998         }
999
1000         return false;
1001 }
1002
1003 bool
1004 EditorRoutes::get_relevant_routes (boost::shared_ptr<RouteList> rl)
1005 {
1006         TimeAxisView* tv;
1007         RouteTimeAxisView* rtv;
1008         RefPtr<TreeSelection> selection = _display.get_selection();
1009         TreePath path;
1010         TreeIter iter;
1011
1012         if (selection->count_selected_rows() != 0) {
1013
1014                 /* use selection */
1015
1016                 RefPtr<TreeModel> tm = RefPtr<TreeModel>::cast_dynamic (_model);
1017                 iter = selection->get_selected (tm);
1018
1019         } else {
1020                 /* use mouse pointer */
1021
1022                 int x, y;
1023                 int bx, by;
1024
1025                 _display.get_pointer (x, y);
1026                 _display.convert_widget_to_bin_window_coords (x, y, bx, by);
1027
1028                 if (_display.get_path_at_pos (bx, by, path)) {
1029                         iter = _model->get_iter (path);
1030                 }
1031         }
1032
1033         if (iter) {
1034                 tv = (*iter)[_columns.tv];
1035                 if (tv) {
1036                         rtv = dynamic_cast<RouteTimeAxisView*>(tv);
1037                         if (rtv) {
1038                                 rl->push_back (rtv->route());
1039                         }
1040                 }
1041         }
1042
1043         return !rl->empty();
1044 }
1045
1046 bool
1047 EditorRoutes::button_press (GdkEventButton* ev)
1048 {
1049         if (Keyboard::is_context_menu_event (ev)) {
1050                 show_menu ();
1051                 return true;
1052         }
1053
1054         //Scroll editor canvas to selected track
1055         if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
1056
1057                 TreeModel::Path path;
1058                 TreeViewColumn *tvc;
1059                 int cell_x;
1060                 int cell_y;
1061
1062                 _display.get_path_at_pos ((int) ev->x, (int) ev->y, path, tvc, cell_x, cell_y);
1063
1064                 // Get the model row.
1065                 Gtk::TreeModel::Row row = *_model->get_iter (path);
1066
1067                 TimeAxisView *tv = row[_columns.tv];
1068
1069                 int y_pos = tv->y_position();
1070
1071                 //Clamp the y pos so that we do not extend beyond the canvas full height.
1072                 if (_editor->full_canvas_height - y_pos < _editor->_canvas_height){
1073                     y_pos = _editor->full_canvas_height - _editor->_canvas_height;
1074                 }
1075
1076                 //Only scroll to if the track is visible
1077                 if(y_pos != -1){
1078                     _editor->reset_y_origin (y_pos);
1079                 }
1080         }
1081
1082         return false;
1083 }
1084
1085 bool
1086 EditorRoutes::selection_filter (Glib::RefPtr<TreeModel> const &, TreeModel::Path const&, bool /*selected*/)
1087 {
1088         if (selection_countdown) {
1089                 if (--selection_countdown == 0) {
1090                         return true;
1091                 } else {
1092                         /* no selection yet ... */
1093                         return false;
1094                 }
1095         }
1096         return true;
1097 }
1098
1099 struct EditorOrderRouteSorter {
1100     bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
1101             /* use of ">" forces the correct sort order */
1102             return a->order_key (N_ ("editor")) < b->order_key (N_ ("editor"));
1103     }
1104 };
1105
1106 void
1107 EditorRoutes::initial_display ()
1108 {
1109         suspend_redisplay ();
1110         _model->clear ();
1111
1112         if (!_session) {
1113                 resume_redisplay ();
1114                 return;
1115         }
1116
1117         boost::shared_ptr<RouteList> routes = _session->get_routes();
1118         RouteList r (*routes);
1119         EditorOrderRouteSorter sorter;
1120
1121         r.sort (sorter);
1122         _editor->handle_new_route (r);
1123
1124         /* don't show master bus in a new session */
1125
1126         if (ARDOUR_UI::instance()->session_is_new ()) {
1127
1128                 TreeModel::Children rows = _model->children();
1129                 TreeModel::Children::iterator i;
1130
1131                 _no_redisplay = true;
1132
1133                 for (i = rows.begin(); i != rows.end(); ++i) {
1134
1135                         TimeAxisView *tv =  (*i)[_columns.tv];
1136                         RouteTimeAxisView *rtv;
1137
1138                         if ((rtv = dynamic_cast<RouteTimeAxisView*>(tv)) != 0) {
1139                                 if (rtv->route()->is_master()) {
1140                                         _display.get_selection()->unselect (i);
1141                                 }
1142                         }
1143                 }
1144
1145                 _no_redisplay = false;
1146                 redisplay ();
1147         }
1148
1149         resume_redisplay ();
1150 }
1151
1152 void
1153 EditorRoutes::track_list_reorder (Gtk::TreeModel::Path const &, Gtk::TreeModel::iterator const &, int* /*new_order*/)
1154 {
1155         _redisplay_does_not_sync_order_keys = true;
1156         _session->set_remote_control_ids();
1157         redisplay ();
1158         _redisplay_does_not_sync_order_keys = false;
1159 }
1160
1161 void
1162 EditorRoutes::display_drag_data_received (const RefPtr<Gdk::DragContext>& context,
1163                                              int x, int y,
1164                                              const SelectionData& data,
1165                                              guint info, guint time)
1166 {
1167         if (data.get_target() == "GTK_TREE_MODEL_ROW") {
1168                 _display.on_drag_data_received (context, x, y, data, info, time);
1169                 return;
1170         }
1171
1172         context->drag_finish (true, false, time);
1173 }
1174
1175 void
1176 EditorRoutes::move_selected_tracks (bool up)
1177 {
1178         if (_editor->selection->tracks.empty()) {
1179                 return;
1180         }
1181
1182         typedef std::pair<TimeAxisView*,boost::shared_ptr<Route> > ViewRoute;
1183         std::list<ViewRoute> view_routes;
1184         std::vector<int> neworder;
1185         TreeModel::Children rows = _model->children();
1186         TreeModel::Children::iterator ri;
1187
1188         for (ri = rows.begin(); ri != rows.end(); ++ri) {
1189                 TimeAxisView* tv = (*ri)[_columns.tv];
1190                 boost::shared_ptr<Route> route = (*ri)[_columns.route];
1191
1192                 view_routes.push_back (ViewRoute (tv, route));
1193         }
1194
1195         list<ViewRoute>::iterator trailing;
1196         list<ViewRoute>::iterator leading;
1197
1198         if (up) {
1199
1200                 trailing = view_routes.begin();
1201                 leading = view_routes.begin();
1202
1203                 ++leading;
1204
1205                 while (leading != view_routes.end()) {
1206                         if (_editor->selection->selected (leading->first)) {
1207                                 view_routes.insert (trailing, ViewRoute (leading->first, leading->second));
1208                                 leading = view_routes.erase (leading);
1209                         } else {
1210                                 ++leading;
1211                                 ++trailing;
1212                         }
1213                 }
1214
1215         } else {
1216
1217                 /* if we could use reverse_iterator in list::insert, this code
1218                    would be a beautiful reflection of the code above. but we can't
1219                    and so it looks like a bit of a mess.
1220                 */
1221
1222                 trailing = view_routes.end();
1223                 leading = view_routes.end();
1224
1225                 --leading; if (leading == view_routes.begin()) { return; }
1226                 --leading;
1227                 --trailing;
1228
1229                 while (1) {
1230
1231                         if (_editor->selection->selected (leading->first)) {
1232                                 list<ViewRoute>::iterator tmp;
1233
1234                                 /* need to insert *after* trailing, not *before* it,
1235                                    which is what insert (iter, val) normally does.
1236                                 */
1237
1238                                 tmp = trailing;
1239                                 tmp++;
1240
1241                                 view_routes.insert (tmp, ViewRoute (leading->first, leading->second));
1242
1243                                 /* can't use iter = cont.erase (iter); form here, because
1244                                    we need iter to move backwards.
1245                                 */
1246
1247                                 tmp = leading;
1248                                 --tmp;
1249
1250                                 bool done = false;
1251
1252                                 if (leading == view_routes.begin()) {
1253                                         /* the one we've just inserted somewhere else
1254                                            was the first in the list. erase this copy,
1255                                            and then break, because we're done.
1256                                         */
1257                                         done = true;
1258                                 }
1259
1260                                 view_routes.erase (leading);
1261
1262                                 if (done) {
1263                                         break;
1264                                 }
1265
1266                                 leading = tmp;
1267
1268                         } else {
1269                                 if (leading == view_routes.begin()) {
1270                                         break;
1271                                 }
1272                                 --leading;
1273                                 --trailing;
1274                         }
1275                 };
1276         }
1277
1278         for (leading = view_routes.begin(); leading != view_routes.end(); ++leading) {
1279                 neworder.push_back (leading->second->order_key (N_ ("editor")));
1280         }
1281
1282         _model->reorder (neworder);
1283
1284        _session->sync_order_keys (N_ ("editor"));
1285 }
1286
1287 void
1288 EditorRoutes::update_input_active_display ()
1289 {
1290         TreeModel::Children rows = _model->children();
1291         TreeModel::Children::iterator i;
1292
1293         for (i = rows.begin(); i != rows.end(); ++i) {
1294                 boost::shared_ptr<Route> route = (*i)[_columns.route];
1295
1296                 if (boost::dynamic_pointer_cast<Track> (route)) {
1297                         boost::shared_ptr<MidiTrack> mt = boost::dynamic_pointer_cast<MidiTrack> (route);
1298                         
1299                         if (mt) {
1300                                 (*i)[_columns.is_input_active] = mt->input_active();
1301                         }
1302                 }
1303         }
1304 }
1305
1306 void
1307 EditorRoutes::update_rec_display ()
1308 {
1309         TreeModel::Children rows = _model->children();
1310         TreeModel::Children::iterator i;
1311
1312         for (i = rows.begin(); i != rows.end(); ++i) {
1313                 boost::shared_ptr<Route> route = (*i)[_columns.route];
1314
1315                 if (boost::dynamic_pointer_cast<Track> (route)) {
1316                         boost::shared_ptr<MidiTrack> mt = boost::dynamic_pointer_cast<MidiTrack> (route);
1317
1318                         if (route->record_enabled()) {
1319                                 if (_session->record_status() == Session::Recording) {
1320                                         (*i)[_columns.rec_state] = 1;
1321                                 } else {
1322                                         (*i)[_columns.rec_state] = 2;
1323                                 }
1324                         } else if (mt && mt->step_editing()) {
1325                                 (*i)[_columns.rec_state] = 3;
1326                         } else {
1327                                 (*i)[_columns.rec_state] = 0;
1328                         }
1329
1330                         (*i)[_columns.name_editable] = !route->record_enabled ();
1331                 }
1332         }
1333 }
1334
1335 void
1336 EditorRoutes::update_mute_display ()
1337 {
1338         TreeModel::Children rows = _model->children();
1339         TreeModel::Children::iterator i;
1340
1341         for (i = rows.begin(); i != rows.end(); ++i) {
1342                 boost::shared_ptr<Route> route = (*i)[_columns.route];
1343                 (*i)[_columns.mute_state] = RouteUI::mute_visual_state (_session, route);
1344         }
1345 }
1346
1347 void
1348 EditorRoutes::update_solo_display (bool /* selfsoloed */)
1349 {
1350         TreeModel::Children rows = _model->children();
1351         TreeModel::Children::iterator i;
1352
1353         for (i = rows.begin(); i != rows.end(); ++i) {
1354                 boost::shared_ptr<Route> route = (*i)[_columns.route];
1355                 (*i)[_columns.solo_state] = RouteUI::solo_visual_state (route);
1356         }
1357 }
1358
1359 void
1360 EditorRoutes::update_solo_isolate_display ()
1361 {
1362         TreeModel::Children rows = _model->children();
1363         TreeModel::Children::iterator i;
1364
1365         for (i = rows.begin(); i != rows.end(); ++i) {
1366                 boost::shared_ptr<Route> route = (*i)[_columns.route];
1367                 (*i)[_columns.solo_isolate_state] = RouteUI::solo_isolate_visual_state (route) > 0 ? 1 : 0;
1368         }
1369 }
1370
1371 void
1372 EditorRoutes::update_solo_safe_display ()
1373 {
1374         TreeModel::Children rows = _model->children();
1375         TreeModel::Children::iterator i;
1376
1377         for (i = rows.begin(); i != rows.end(); ++i) {
1378                 boost::shared_ptr<Route> route = (*i)[_columns.route];
1379                 (*i)[_columns.solo_safe_state] = RouteUI::solo_safe_visual_state (route) > 0 ? 1 : 0;
1380         }
1381 }
1382
1383 list<TimeAxisView*>
1384 EditorRoutes::views () const
1385 {
1386         list<TimeAxisView*> v;
1387         for (TreeModel::Children::iterator i = _model->children().begin(); i != _model->children().end(); ++i) {
1388                 v.push_back ((*i)[_columns.tv]);
1389         }
1390
1391         return v;
1392 }
1393
1394 void
1395 EditorRoutes::clear ()
1396 {
1397         _display.set_model (Glib::RefPtr<Gtk::TreeStore> (0));
1398         _model->clear ();
1399         _display.set_model (_model);
1400 }
1401
1402 void
1403 EditorRoutes::name_edit_started (CellEditable* ce, const Glib::ustring&)
1404 {
1405         name_editable = ce;
1406
1407         /* give it a special name */
1408
1409         Gtk::Entry *e = dynamic_cast<Gtk::Entry*> (ce);
1410
1411         if (e) {
1412                 e->set_name (X_("RouteNameEditorEntry"));
1413         }
1414 }
1415
1416 void
1417 EditorRoutes::name_edit (std::string const & path, std::string const & new_text)
1418 {
1419         name_editable = 0;
1420
1421         TreeIter iter = _model->get_iter (path);
1422
1423         if (!iter) {
1424                 return;
1425         }
1426
1427         boost::shared_ptr<Route> route = (*iter)[_columns.route];
1428
1429         if (route && route->name() != new_text) {
1430                 route->set_name (new_text);
1431         }
1432 }
1433
1434 void
1435 EditorRoutes::solo_changed_so_update_mute ()
1436 {
1437         update_mute_display ();
1438 }
1439
1440 void
1441 EditorRoutes::show_tracks_with_regions_at_playhead ()
1442 {
1443         boost::shared_ptr<RouteList> const r = _session->get_routes_with_regions_at (_session->transport_frame ());
1444
1445         set<TimeAxisView*> show;
1446         for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
1447                 TimeAxisView* tav = _editor->axis_view_from_route (*i);
1448                 if (tav) {
1449                         show.insert (tav);
1450                 }
1451         }
1452
1453         suspend_redisplay ();
1454
1455         TreeModel::Children rows = _model->children ();
1456         for (TreeModel::Children::iterator i = rows.begin(); i != rows.end(); ++i) {
1457                 TimeAxisView* tv = (*i)[_columns.tv];
1458                 (*i)[_columns.visible] = (show.find (tv) != show.end());
1459         }
1460
1461         resume_redisplay ();
1462 }