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