don't resort routelists during session destruction
[ardour.git] / gtk2_ardour / editor_routes.cc
1 /*
2     Copyright (C) 2000-2009 Paul Davis
3
4     This program is free software; you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation; either version 2 of the License, or
7     (at your option) any later version.
8
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13
14     You should have received a copy of the GNU General Public License
15     along with this program; if not, write to the Free Software
16     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17
18 */
19
20 #include <list>
21 #include <vector>
22 #include <algorithm>
23 #include <cstdlib>
24 #include <cmath>
25 #include <cassert>
26
27 #include "ardour/diskstream.h"
28 #include "ardour/session.h"
29
30 #include "editor.h"
31 #include "keyboard.h"
32 #include "ardour_ui.h"
33 #include "audio_time_axis.h"
34 #include "midi_time_axis.h"
35 #include "mixer_strip.h"
36 #include "gui_thread.h"
37 #include "actions.h"
38 #include "utils.h"
39 #include "editor_group_tabs.h"
40 #include "editor_routes.h"
41
42 #include "pbd/unknown_type.h"
43
44 #include "ardour/route.h"
45
46 #include "gtkmm2ext/cell_renderer_pixbuf_multi.h"
47 #include "gtkmm2ext/cell_renderer_pixbuf_toggle.h"
48
49 #include "i18n.h"
50
51 using namespace std;
52 using namespace sigc;
53 using namespace ARDOUR;
54 using namespace PBD;
55 using namespace Gtk;
56 using namespace Gtkmm2ext;
57 using namespace Glib;
58
59 EditorRoutes::EditorRoutes (Editor* e)
60         : EditorComponent (e),
61           _ignore_reorder (false),
62           _no_redisplay (false),
63           _redisplay_does_not_sync_order_keys (false),
64           _redisplay_does_not_reset_order_keys (false),
65           _menu (0)
66 {
67         _scroller.add (_display);
68         _scroller.set_policy (POLICY_NEVER, POLICY_AUTOMATIC);
69
70         _model = ListStore::create (_columns);
71         _display.set_model (_model);
72
73         // Record enable toggle
74         CellRendererPixbufToggle* rec_col_renderer = manage (new CellRendererPixbufToggle());
75
76         rec_col_renderer->set_active_pixbuf (::get_icon("rec-enabled"));
77         rec_col_renderer->set_inactive_pixbuf (::get_icon("act-disabled"));
78         rec_col_renderer->signal_toggled().connect (mem_fun (*this, &EditorRoutes::on_tv_rec_enable_toggled));
79
80         Gtk::TreeViewColumn* rec_state_column = manage (new TreeViewColumn("R", *rec_col_renderer));
81
82         rec_state_column->add_attribute(rec_col_renderer->property_active(), _columns.rec_enabled);
83         rec_state_column->add_attribute(rec_col_renderer->property_visible(), _columns.is_track);
84
85         // Mute enable toggle
86         CellRendererPixbufMulti* mute_col_renderer = manage (new CellRendererPixbufMulti());
87
88         mute_col_renderer->set_pixbuf (0, ::get_icon("act-disabled"));
89         mute_col_renderer->set_pixbuf (1, ::get_icon("mute-enabled"));
90         mute_col_renderer->signal_changed().connect (mem_fun (*this, &EditorRoutes::on_tv_mute_enable_toggled));
91
92         Gtk::TreeViewColumn* mute_state_column = manage (new TreeViewColumn("M", *mute_col_renderer));
93
94         mute_state_column->add_attribute(mute_col_renderer->property_state(), _columns.mute_state);
95         mute_state_column->add_attribute(mute_col_renderer->property_visible(), _columns.is_track);
96
97         // Solo enable toggle
98         CellRendererPixbufMulti* solo_col_renderer = manage (new CellRendererPixbufMulti());
99
100         solo_col_renderer->set_pixbuf (0, ::get_icon("act-disabled"));
101         solo_col_renderer->set_pixbuf (1, ::get_icon("solo-enabled"));
102         solo_col_renderer->signal_changed().connect (mem_fun (*this, &EditorRoutes::on_tv_solo_enable_toggled));
103
104         Gtk::TreeViewColumn* solo_state_column = manage (new TreeViewColumn("S", *solo_col_renderer));
105
106         solo_state_column->add_attribute(solo_col_renderer->property_state(), _columns.solo_state);
107         solo_state_column->add_attribute(solo_col_renderer->property_visible(), _columns.is_track);
108
109         
110         _display.append_column (*rec_state_column);
111         _display.append_column (*mute_state_column);
112         _display.append_column (*solo_state_column);
113         _display.append_column (_("Show"), _columns.visible);
114         _display.append_column (_("Name"), _columns.text);
115
116         _display.get_column (0)->set_data (X_("colnum"), GUINT_TO_POINTER(0));
117         _display.get_column (1)->set_data (X_("colnum"), GUINT_TO_POINTER(1));
118         _display.get_column (2)->set_data (X_("colnum"), GUINT_TO_POINTER(2));
119         _display.get_column (3)->set_data (X_("colnum"), GUINT_TO_POINTER(3));
120         _display.get_column (4)->set_data (X_("colnum"), GUINT_TO_POINTER(4));
121
122         _display.set_headers_visible (true);
123         _display.set_name ("TrackListDisplay");
124         _display.get_selection()->set_mode (SELECTION_SINGLE);
125         _display.set_reorderable (true);
126         _display.set_rules_hint (true);
127         _display.set_size_request (100, -1);
128         _display.add_object_drag (_columns.route.index(), "routes");
129
130         CellRendererText* name_cell = dynamic_cast<CellRendererText*> (_display.get_column_cell_renderer (4));
131         assert (name_cell);
132
133         Gtk::TreeViewColumn* name_column = _display.get_column (4);
134         assert (name_column);
135
136         name_column->add_attribute (name_cell->property_editable(), _columns.name_editable);
137         
138         name_cell->property_editable() = true;
139         name_cell->signal_edited().connect (mem_fun (*this, &EditorRoutes::name_edit));
140
141         CellRendererToggle* visible_cell = dynamic_cast<CellRendererToggle*>(_display.get_column_cell_renderer (3));
142
143         visible_cell->property_activatable() = true;
144         visible_cell->property_radio() = false;
145
146         _model->signal_row_deleted().connect (mem_fun (*this, &EditorRoutes::route_deleted));
147         _model->signal_row_changed().connect (mem_fun (*this, &EditorRoutes::changed));
148         _model->signal_rows_reordered().connect (mem_fun (*this, &EditorRoutes::reordered));
149         _display.signal_button_press_event().connect (mem_fun (*this, &EditorRoutes::button_press), false);
150
151         Route::SyncOrderKeys.connect (mem_fun (*this, &EditorRoutes::sync_order_keys));
152 }
153
154 void
155 EditorRoutes::connect_to_session (Session* s)
156 {
157         EditorComponent::connect_to_session (s);
158
159         initial_display ();
160 }
161
162 void
163 EditorRoutes::on_tv_rec_enable_toggled (Glib::ustring const & path_string)
164 {
165         // Get the model row that has been toggled.
166         Gtk::TreeModel::Row row = *_model->get_iter (Gtk::TreeModel::Path (path_string));
167
168         row[_columns.name_editable] = !row[_columns.rec_enabled];
169         
170         TimeAxisView *tv = row[_columns.tv];
171         AudioTimeAxisView *atv = dynamic_cast<AudioTimeAxisView*> (tv);
172
173         if (atv != 0 && atv->is_audio_track()){
174                 atv->reversibly_apply_track_boolean ("rec-enable change", &Track::set_record_enable, !atv->track()->record_enabled(), this);
175         }
176 }
177
178 void
179 EditorRoutes::on_tv_mute_enable_toggled (Glib::ustring const & path_string)
180 {
181         // Get the model row that has been toggled.
182         Gtk::TreeModel::Row row = *_model->get_iter (Gtk::TreeModel::Path (path_string));
183
184         TimeAxisView *tv = row[_columns.tv];
185         AudioTimeAxisView *atv = dynamic_cast<AudioTimeAxisView*> (tv);
186
187         if (atv != 0 && atv->is_audio_track()){
188                 atv->reversibly_apply_track_boolean ("mute-enable change", &Track::set_mute, !atv->track()->muted(), this);
189         }
190 }
191
192 void
193 EditorRoutes::on_tv_solo_enable_toggled (Glib::ustring const & path_string)
194 {
195         // Get the model row that has been toggled.
196         Gtk::TreeModel::Row row = *_model->get_iter (Gtk::TreeModel::Path (path_string));
197
198         TimeAxisView *tv = row[_columns.tv];
199         AudioTimeAxisView *atv = dynamic_cast<AudioTimeAxisView*> (tv);
200
201         if (atv != 0 && atv->is_audio_track()){
202                 atv->reversibly_apply_track_boolean ("solo-enable change", &Track::set_solo, !atv->track()->soloed(), this);
203         }
204 }
205
206 void
207 EditorRoutes::build_menu ()
208 {
209         using namespace Menu_Helpers;
210         using namespace Gtk;
211
212         _menu = new Menu;
213
214         MenuList& items = _menu->items();
215         _menu->set_name ("ArdourContextMenu");
216
217         items.push_back (MenuElem (_("Show All"), mem_fun (*this, &EditorRoutes::show_all_routes)));
218         items.push_back (MenuElem (_("Hide All"), mem_fun (*this, &EditorRoutes::hide_all_routes)));
219         items.push_back (MenuElem (_("Show All Audio Tracks"), mem_fun (*this, &EditorRoutes::show_all_audiotracks)));
220         items.push_back (MenuElem (_("Hide All Audio Tracks"), mem_fun (*this, &EditorRoutes::hide_all_audiotracks)));
221         items.push_back (MenuElem (_("Show All Audio Busses"), mem_fun (*this, &EditorRoutes::show_all_audiobus)));
222         items.push_back (MenuElem (_("Hide All Audio Busses"), mem_fun (*this, &EditorRoutes::hide_all_audiobus)));
223
224 }
225
226 void
227 EditorRoutes::show_menu ()
228 {
229         if (_menu == 0) {
230                 build_menu ();
231         }
232
233         _menu->popup (1, gtk_get_current_event_time());
234 }
235
236 void
237 EditorRoutes::redisplay ()
238 {
239         TreeModel::Children rows = _model->children();
240         TreeModel::Children::iterator i;
241         uint32_t position;
242         int n;
243
244         if (_no_redisplay) {
245                 return;
246         }
247
248         for (n = 0, position = 0, i = rows.begin(); i != rows.end(); ++i) {
249                 TimeAxisView *tv = (*i)[_columns.tv];
250                 boost::shared_ptr<Route> route = (*i)[_columns.route];
251
252                 if (tv == 0) {
253                         // just a "title" row
254                         continue;
255                 }
256
257                 if (!_redisplay_does_not_reset_order_keys) {
258                         /* this reorder is caused by user action, so reassign sort order keys
259                            to tracks.
260                         */
261                         route->set_order_key (N_ ("editor"), n);
262                 }
263
264                 bool visible = (*i)[_columns.visible];
265
266                 /* show or hide the TimeAxisView */
267                 if (visible) {
268                         tv->set_marked_for_display (true);
269                         position += tv->show_at (position, n, &_editor->edit_controls_vbox);
270                         tv->clip_to_viewport ();
271                 } else {
272                         tv->set_marked_for_display (false);
273                         tv->hide ();
274                 }
275
276                 n++;
277         }
278
279         /* whenever we go idle, update the track view list to reflect the new order.
280            we can't do this here, because we could mess up something that is traversing
281            the track order and has caused a redisplay of the list.
282         */
283         Glib::signal_idle().connect (mem_fun (*_editor, &Editor::sync_track_view_list_and_routes));
284
285         _editor->full_canvas_height = position + _editor->canvas_timebars_vsize;
286         _editor->vertical_adjustment.set_upper (_editor->full_canvas_height);
287
288         if ((_editor->vertical_adjustment.get_value() + _editor->_canvas_height) > _editor->vertical_adjustment.get_upper()) {
289                 /*
290                    We're increasing the size of the canvas while the bottom is visible.
291                    We scroll down to keep in step with the controls layout.
292                 */
293                 _editor->vertical_adjustment.set_value (_editor->full_canvas_height - _editor->_canvas_height);
294         }
295
296         if (!_redisplay_does_not_reset_order_keys && !_redisplay_does_not_sync_order_keys) {
297                 _session->sync_order_keys (N_ ("editor"));
298         }
299 }
300
301 void
302 EditorRoutes::route_deleted (Gtk::TreeModel::Path const &)
303 {
304         /* this could require an order reset & sync */
305         _session->set_remote_control_ids();
306         _ignore_reorder = true;
307         redisplay ();
308         _ignore_reorder = false;
309 }
310
311
312 void
313 EditorRoutes::changed (Gtk::TreeModel::Path const &, Gtk::TreeModel::iterator const &)
314 {
315         /* never reset order keys because of a property change */
316         _redisplay_does_not_reset_order_keys = true;
317         _session->set_remote_control_ids();
318         redisplay ();
319         _redisplay_does_not_reset_order_keys = false;
320 }
321
322 void
323 EditorRoutes::routes_added (list<RouteTimeAxisView*> routes)
324 {
325         TreeModel::Row row;
326
327         _redisplay_does_not_sync_order_keys = true;
328         suspend_redisplay ();
329
330         for (list<RouteTimeAxisView*>::iterator x = routes.begin(); x != routes.end(); ++x) {
331
332                 row = *(_model->append ());
333
334                 row[_columns.text] = (*x)->route()->name();
335                 row[_columns.visible] = (*x)->marked_for_display();
336                 row[_columns.tv] = *x;
337                 row[_columns.route] = (*x)->route ();
338                 row[_columns.is_track] = (boost::dynamic_pointer_cast<Track> ((*x)->route()) != 0);
339
340                 _ignore_reorder = true;
341
342                 /* added a new fresh one at the end */
343                 if ((*x)->route()->order_key (N_ ("editor")) == -1) {
344                         (*x)->route()->set_order_key (N_ ("editor"), _model->children().size()-1);
345                 }
346
347                 _ignore_reorder = false;
348
349                 boost::weak_ptr<Route> wr ((*x)->route());
350                 (*x)->route()->gui_changed.connect (mem_fun (*this, &EditorRoutes::handle_gui_changes));
351                 (*x)->route()->NameChanged.connect (bind (mem_fun (*this, &EditorRoutes::route_name_changed), wr));
352                 (*x)->GoingAway.connect (bind (mem_fun (*this, &EditorRoutes::route_removed), *x));
353
354                 if ((*x)->is_track()) {
355                         boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track> ((*x)->route());
356                         t->diskstream()->RecordEnableChanged.connect (mem_fun (*this, &EditorRoutes::update_rec_display));
357                         t->mute_changed.connect (mem_fun (*this, &EditorRoutes::update_mute_display));
358                         t->solo_changed.connect (mem_fun (*this, &EditorRoutes::update_solo_display));
359                 }
360         }
361
362         update_rec_display ();
363         resume_redisplay ();
364         _redisplay_does_not_sync_order_keys = false;
365 }
366
367 void
368 EditorRoutes::handle_gui_changes (string const & what, void *src)
369 {
370         ENSURE_GUI_THREAD (bind (mem_fun(*this, &EditorRoutes::handle_gui_changes), what, src));
371
372         if (what == "track_height") {
373                 /* Optional :make tracks change height while it happens, instead
374                    of on first-idle
375                 */
376                 //update_canvas_now ();
377                 redisplay ();
378         }
379
380         if (what == "visible_tracks") {
381                 redisplay ();
382         }
383 }
384
385 void
386 EditorRoutes::route_removed (TimeAxisView *tv)
387 {
388         ENSURE_GUI_THREAD (bind (mem_fun(*this, &EditorRoutes::route_removed), tv));
389
390         TreeModel::Children rows = _model->children();
391         TreeModel::Children::iterator ri;
392
393         /* the core model has changed, there is no need to sync
394            view orders.
395         */
396
397         _redisplay_does_not_sync_order_keys = true;
398
399         for (ri = rows.begin(); ri != rows.end(); ++ri) {
400                 if ((*ri)[_columns.tv] == tv) {
401                         _model->erase (ri);
402                         break;
403                 }
404         }
405
406         _redisplay_does_not_sync_order_keys = false;
407 }
408
409 void
410 EditorRoutes::route_name_changed (boost::weak_ptr<Route> r)
411 {
412         ENSURE_GUI_THREAD (bind (mem_fun (*this, &EditorRoutes::route_name_changed), r));
413
414         boost::shared_ptr<Route> route = r.lock ();
415         if (!route) {
416                 return;
417         }
418
419         TreeModel::Children rows = _model->children();
420         TreeModel::Children::iterator i;
421
422         for (i = rows.begin(); i != rows.end(); ++i) {
423                 boost::shared_ptr<Route> t = (*i)[_columns.route];
424                 if (t == route) {
425                         (*i)[_columns.text] = route->name();
426                         break;
427                 }
428         }
429 }
430
431 void
432 EditorRoutes::update_visibility ()
433 {
434         TreeModel::Children rows = _model->children();
435         TreeModel::Children::iterator i;
436
437         suspend_redisplay ();
438
439         for (i = rows.begin(); i != rows.end(); ++i) {
440                 TimeAxisView *tv = (*i)[_columns.tv];
441                 (*i)[_columns.visible] = tv->marked_for_display ();
442                 cerr << "marked " << tv->name() << " for display = " << tv->marked_for_display() << endl;
443         }
444
445         resume_redisplay ();
446 }
447
448 void
449 EditorRoutes::hide_track_in_display (TimeAxisView& tv)
450 {
451         TreeModel::Children rows = _model->children();
452         TreeModel::Children::iterator i;
453
454         for (i = rows.begin(); i != rows.end(); ++i) {
455                 if ((*i)[_columns.tv] == &tv) {
456                         (*i)[_columns.visible] = false;
457                         break;
458                 }
459         }
460 }
461
462 void
463 EditorRoutes::show_track_in_display (TimeAxisView& tv)
464 {
465         TreeModel::Children rows = _model->children();
466         TreeModel::Children::iterator i;
467
468         for (i = rows.begin(); i != rows.end(); ++i) {
469                 if ((*i)[_columns.tv] == &tv) {
470                         (*i)[_columns.visible] = true;
471                         break;
472                 }
473         }
474 }
475
476 void
477 EditorRoutes::reordered (TreeModel::Path const &, TreeModel::iterator const &, int* /*what*/)
478 {
479         redisplay ();
480 }
481
482 /** If src != "editor", take editor order keys from each route and use them to rearrange the
483  *  route list so that the visual arrangement of routes matches the order keys from the routes.
484  */
485 void
486 EditorRoutes::sync_order_keys (string const & src)
487 {
488         vector<int> neworder;
489         TreeModel::Children rows = _model->children();
490         TreeModel::Children::iterator ri;
491
492         if (src == N_ ("editor") || !_session || (_session->state_of_the_state() & (Session::Loading|Session::Deletion)) || rows.empty()) {
493                 return;
494         }
495
496         for (ri = rows.begin(); ri != rows.end(); ++ri) {
497                 neworder.push_back (0);
498         }
499
500         bool changed = false;
501         int order;
502
503         for (order = 0, ri = rows.begin(); ri != rows.end(); ++ri, ++order) {
504                 boost::shared_ptr<Route> route = (*ri)[_columns.route];
505
506                 int old_key = order;
507                 int new_key = route->order_key (N_ ("editor"));
508
509                 neworder[new_key] = old_key;
510
511                 if (new_key != old_key) {
512                         changed = true;
513                 }
514         }
515
516         if (changed) {
517                 _redisplay_does_not_reset_order_keys = true;
518                 _model->reorder (neworder);
519                 _redisplay_does_not_reset_order_keys = false;
520         }
521 }
522
523
524 void
525 EditorRoutes::hide_all_tracks (bool /*with_select*/)
526 {
527         TreeModel::Children rows = _model->children();
528         TreeModel::Children::iterator i;
529
530         suspend_redisplay ();
531
532         for (i = rows.begin(); i != rows.end(); ++i) {
533
534                 TreeModel::Row row = (*i);
535                 TimeAxisView *tv = row[_columns.tv];
536
537                 if (tv == 0) {
538                         continue;
539                 }
540
541                 row[_columns.visible] = false;
542         }
543
544         resume_redisplay ();
545
546         /* XXX this seems like a hack and half, but its not clear where to put this
547            otherwise.
548         */
549
550         //reset_scrolling_region ();
551 }
552
553 void
554 EditorRoutes::set_all_tracks_visibility (bool yn)
555 {
556         TreeModel::Children rows = _model->children();
557         TreeModel::Children::iterator i;
558
559         suspend_redisplay ();
560
561         for (i = rows.begin(); i != rows.end(); ++i) {
562
563                 TreeModel::Row row = (*i);
564                 TimeAxisView* tv = row[_columns.tv];
565
566                 if (tv == 0) {
567                         continue;
568                 }
569
570                 (*i)[_columns.visible] = yn;
571         }
572
573         resume_redisplay ();
574 }
575
576 void
577 EditorRoutes::set_all_audio_visibility (int tracks, bool yn)
578 {
579         TreeModel::Children rows = _model->children();
580         TreeModel::Children::iterator i;
581
582         suspend_redisplay ();
583
584         for (i = rows.begin(); i != rows.end(); ++i) {
585                 TreeModel::Row row = (*i);
586                 TimeAxisView* tv = row[_columns.tv];
587                 AudioTimeAxisView* atv;
588
589                 if (tv == 0) {
590                         continue;
591                 }
592
593                 if ((atv = dynamic_cast<AudioTimeAxisView*>(tv)) != 0) {
594                         switch (tracks) {
595                         case 0:
596                                 (*i)[_columns.visible] = yn;
597                                 break;
598
599                         case 1:
600                                 if (atv->is_audio_track()) {
601                                         (*i)[_columns.visible] = yn;
602                                 }
603                                 break;
604
605                         case 2:
606                                 if (!atv->is_audio_track()) {
607                                         (*i)[_columns.visible] = yn;
608                                 }
609                                 break;
610                         }
611                 }
612         }
613
614         resume_redisplay ();
615 }
616
617 void
618 EditorRoutes::hide_all_routes ()
619 {
620         set_all_tracks_visibility (false);
621 }
622
623 void
624 EditorRoutes::show_all_routes ()
625 {
626         set_all_tracks_visibility (true);
627 }
628
629 void
630 EditorRoutes::show_all_audiobus ()
631 {
632         set_all_audio_visibility (2, true);
633 }
634 void
635 EditorRoutes::hide_all_audiobus ()
636 {
637         set_all_audio_visibility (2, false);
638 }
639
640 void
641 EditorRoutes::show_all_audiotracks()
642 {
643         set_all_audio_visibility (1, true);
644 }
645 void
646 EditorRoutes::hide_all_audiotracks ()
647 {
648         set_all_audio_visibility (1, false);
649 }
650
651 bool
652 EditorRoutes::button_press (GdkEventButton* ev)
653 {
654         if (Keyboard::is_context_menu_event (ev)) {
655                 show_menu ();
656                 return true;
657         }
658
659         TreeIter iter;
660         TreeModel::Path path;
661         TreeViewColumn* column;
662         int cellx;
663         int celly;
664
665         if (!_display.get_path_at_pos ((int)ev->x, (int)ev->y, path, column, cellx, celly)) {
666                 return false;
667         }
668
669         switch (GPOINTER_TO_UINT (column->get_data (X_("colnum")))) {
670
671         case 0:
672                 /* allow normal processing to occur */
673                 return false;
674         case 1:
675                 /* allow normal processing to occur */
676                 return false;
677         case 2:
678                 /* allow normal processing to occur */
679                 return false;           
680         case 3:
681                 if ((iter = _model->get_iter (path))) {
682                         TimeAxisView* tv = (*iter)[_columns.tv];
683                         if (tv) {
684                                 bool visible = (*iter)[_columns.visible];
685                                 (*iter)[_columns.visible] = !visible;
686                         }
687                 }
688                 return true;
689
690         case 4:
691                 /* allow normal processing to occur */
692                 return false;
693
694         default:
695                 break;
696         }
697
698         return false;
699 }
700
701 bool
702 EditorRoutes::selection_filter (Glib::RefPtr<TreeModel> const &, TreeModel::Path const &, bool)
703 {
704         return true;
705 }
706
707 struct EditorOrderRouteSorter {
708     bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
709             /* use of ">" forces the correct sort order */
710             return a->order_key (N_ ("editor")) < b->order_key (N_ ("editor"));
711     }
712 };
713
714 void
715 EditorRoutes::initial_display ()
716 {
717         boost::shared_ptr<RouteList> routes = _session->get_routes();
718         RouteList r (*routes);
719         EditorOrderRouteSorter sorter;
720
721         r.sort (sorter);
722
723         suspend_redisplay ();
724
725         _model->clear ();
726         _editor->handle_new_route (r);
727
728         /* don't show master bus in a new session */
729
730         if (ARDOUR_UI::instance()->session_is_new ()) {
731
732                 TreeModel::Children rows = _model->children();
733                 TreeModel::Children::iterator i;
734
735                 _no_redisplay = true;
736
737                 for (i = rows.begin(); i != rows.end(); ++i) {
738                         TimeAxisView *tv =  (*i)[_columns.tv];
739                         RouteTimeAxisView *rtv;
740
741                         if ((rtv = dynamic_cast<RouteTimeAxisView*>(tv)) != 0) {
742                                 if (rtv->route()->is_master()) {
743                                         _display.get_selection()->unselect (i);
744                                 }
745                         }
746                 }
747
748                 _no_redisplay = false;
749                 redisplay ();
750         }
751
752         resume_redisplay ();
753 }
754
755 void
756 EditorRoutes::track_list_reorder (Gtk::TreeModel::Path const &, Gtk::TreeModel::iterator const &, int* /*new_order*/)
757 {
758         _redisplay_does_not_sync_order_keys = true;
759         _session->set_remote_control_ids();
760         redisplay ();
761         _redisplay_does_not_sync_order_keys = false;
762 }
763
764 void
765 EditorRoutes::display_drag_data_received (const RefPtr<Gdk::DragContext>& context,
766                                              int x, int y,
767                                              const SelectionData& data,
768                                              guint info, guint time)
769 {
770         if (data.get_target() == "GTK_TREE_MODEL_ROW") {
771                 _display.on_drag_data_received (context, x, y, data, info, time);
772                 return;
773         }
774
775         context->drag_finish (true, false, time);
776 }
777
778 void
779 EditorRoutes::move_selected_tracks (bool up)
780 {
781         if (_editor->selection->tracks.empty()) {
782                 return;
783         }
784
785         typedef std::pair<TimeAxisView*,boost::shared_ptr<Route> > ViewRoute;
786         std::list<ViewRoute> view_routes;
787         std::vector<int> neworder;
788         TreeModel::Children rows = _model->children();
789         TreeModel::Children::iterator ri;
790
791         for (ri = rows.begin(); ri != rows.end(); ++ri) {
792                 TimeAxisView* tv = (*ri)[_columns.tv];
793                 boost::shared_ptr<Route> route = (*ri)[_columns.route];
794
795                 view_routes.push_back (ViewRoute (tv, route));
796         }
797
798         list<ViewRoute>::iterator trailing;
799         list<ViewRoute>::iterator leading;
800
801         if (up) {
802
803                 trailing = view_routes.begin();
804                 leading = view_routes.begin();
805
806                 ++leading;
807
808                 while (leading != view_routes.end()) {
809                         if (_editor->selection->selected (leading->first)) {
810                                 view_routes.insert (trailing, ViewRoute (leading->first, leading->second));
811                                 leading = view_routes.erase (leading);
812                         } else {
813                                 ++leading;
814                                 ++trailing;
815                         }
816                 }
817
818         } else {
819
820                 /* if we could use reverse_iterator in list::insert, this code
821                    would be a beautiful reflection of the code above. but we can't
822                    and so it looks like a bit of a mess.
823                 */
824
825                 trailing = view_routes.end();
826                 leading = view_routes.end();
827
828                 --leading; if (leading == view_routes.begin()) { return; }
829                 --leading;
830                 --trailing;
831
832                 while (1) {
833
834                         if (_editor->selection->selected (leading->first)) {
835                                 list<ViewRoute>::iterator tmp;
836
837                                 /* need to insert *after* trailing, not *before* it,
838                                    which is what insert (iter, val) normally does.
839                                 */
840
841                                 tmp = trailing;
842                                 tmp++;
843
844                                 view_routes.insert (tmp, ViewRoute (leading->first, leading->second));
845
846                                 /* can't use iter = cont.erase (iter); form here, because
847                                    we need iter to move backwards.
848                                 */
849
850                                 tmp = leading;
851                                 --tmp;
852
853                                 bool done = false;
854
855                                 if (leading == view_routes.begin()) {
856                                         /* the one we've just inserted somewhere else
857                                            was the first in the list. erase this copy,
858                                            and then break, because we're done.
859                                         */
860                                         done = true;
861                                 }
862
863                                 view_routes.erase (leading);
864
865                                 if (done) {
866                                         break;
867                                 }
868
869                                 leading = tmp;
870
871                         } else {
872                                 if (leading == view_routes.begin()) {
873                                         break;
874                                 }
875                                 --leading;
876                                 --trailing;
877                         }
878                 };
879         }
880
881         for (leading = view_routes.begin(); leading != view_routes.end(); ++leading) {
882                 neworder.push_back (leading->second->order_key (N_ ("editor")));
883         }
884
885         _model->reorder (neworder);
886
887         _session->sync_order_keys (N_ ("editor"));
888 }
889
890 void
891 EditorRoutes::update_rec_display ()
892 {
893         TreeModel::Children rows = _model->children();
894         TreeModel::Children::iterator i;
895
896         for (i = rows.begin(); i != rows.end(); ++i) {
897                 boost::shared_ptr<Route> route = (*i)[_columns.route];
898
899                 if (boost::dynamic_pointer_cast<Track>(route)) {
900                         (*i)[_columns.rec_enabled] = route->record_enabled ();
901                         (*i)[_columns.name_editable] = !route->record_enabled ();
902                 }
903         }
904 }
905
906 void
907 EditorRoutes::update_mute_display (void* /*src*/)
908 {
909         TreeModel::Children rows = _model->children();
910         TreeModel::Children::iterator i;
911
912         for (i = rows.begin(); i != rows.end(); ++i) {
913                 boost::shared_ptr<Route> route = (*i)[_columns.route];
914
915                 if (boost::dynamic_pointer_cast<Track>(route)) {
916
917                         if (route->muted()){
918                                 (*i)[_columns.mute_state] = 1;
919                         } else {
920                                 (*i)[_columns.mute_state] = 0;
921                         }
922                 }
923         }
924 }
925
926 void
927 EditorRoutes::update_solo_display (void* /*src*/)
928 {
929         TreeModel::Children rows = _model->children();
930         TreeModel::Children::iterator i;
931
932         for (i = rows.begin(); i != rows.end(); ++i) {
933                 boost::shared_ptr<Route> route = (*i)[_columns.route];
934
935                 if (boost::dynamic_pointer_cast<Track>(route)) {
936
937                         if (route->soloed()){
938                                 (*i)[_columns.solo_state] = 1;
939                         } else {
940                                 (*i)[_columns.solo_state] = 0;
941                         }
942                 }
943         }
944 }
945
946 list<TimeAxisView*>
947 EditorRoutes::views () const
948 {
949         list<TimeAxisView*> v;
950         for (TreeModel::Children::iterator i = _model->children().begin(); i != _model->children().end(); ++i) {
951                 v.push_back ((*i)[_columns.tv]);
952         }
953
954         return v;
955 }
956
957 void
958 EditorRoutes::clear ()
959 {
960         _display.set_model (Glib::RefPtr<Gtk::TreeStore> (0));
961         _model->clear ();
962         _display.set_model (_model);
963 }
964
965 void
966 EditorRoutes::name_edit (Glib::ustring const & path, Glib::ustring const & new_text)
967 {
968         TreeIter iter = _model->get_iter (path);
969         if (!iter) {
970                 return;
971         }
972
973         boost::shared_ptr<Route> route = (*iter)[_columns.route];
974
975         if (route && route->name() != new_text) {
976                 route->set_name (new_text);
977         }
978 }