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