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