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