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