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