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