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