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