first pass (ok, third really) at internal send+return - audio routing inside ardour...
[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        _summary->set_dirty ();
425
426        return false; // do not call again (until needed)
427 }
428
429 void
430 Editor::hide_all_tracks (bool with_select)
431 {
432         TreeModel::Children rows = route_display_model->children();
433         TreeModel::Children::iterator i;
434
435         no_route_list_redisplay = true;
436
437         for (i = rows.begin(); i != rows.end(); ++i) {
438                 
439                 TreeModel::Row row = (*i);
440                 TimeAxisView *tv = row[route_display_columns.tv];
441
442                 if (tv == 0) {
443                         continue;
444                 }
445                 
446                 row[route_display_columns.visible] = false;
447         }
448
449         no_route_list_redisplay = false;
450         redisplay_route_list ();
451
452         /* XXX this seems like a hack and half, but its not clear where to put this
453            otherwise.
454         */
455
456         //reset_scrolling_region ();
457 }
458
459 void
460 Editor::build_route_list_menu ()
461 {
462         using namespace Menu_Helpers;
463         using namespace Gtk;
464
465         route_list_menu = new Menu;
466         
467         MenuList& items = route_list_menu->items();
468         route_list_menu->set_name ("ArdourContextMenu");
469
470         items.push_back (MenuElem (_("Show All"), mem_fun(*this, &Editor::show_all_routes)));
471         items.push_back (MenuElem (_("Hide All"), mem_fun(*this, &Editor::hide_all_routes)));
472         items.push_back (MenuElem (_("Show All Audio Tracks"), mem_fun(*this, &Editor::show_all_audiotracks)));
473         items.push_back (MenuElem (_("Hide All Audio Tracks"), mem_fun(*this, &Editor::hide_all_audiotracks)));
474         items.push_back (MenuElem (_("Show All Audio Busses"), mem_fun(*this, &Editor::show_all_audiobus)));
475         items.push_back (MenuElem (_("Hide All Audio Busses"), mem_fun(*this, &Editor::hide_all_audiobus)));
476
477 }
478
479 void
480 Editor::set_all_tracks_visibility (bool yn)
481 {
482         TreeModel::Children rows = route_display_model->children();
483         TreeModel::Children::iterator i;
484
485         no_route_list_redisplay = true;
486
487         for (i = rows.begin(); i != rows.end(); ++i) {
488
489                 TreeModel::Row row = (*i);
490                 TimeAxisView* tv = row[route_display_columns.tv];
491
492                 if (tv == 0) {
493                         continue;
494                 }
495                 
496                 (*i)[route_display_columns.visible] = yn;
497         }
498
499         no_route_list_redisplay = false;
500         redisplay_route_list ();
501 }
502
503 void
504 Editor::set_all_audio_visibility (int tracks, bool yn) 
505 {
506         TreeModel::Children rows = route_display_model->children();
507         TreeModel::Children::iterator i;
508
509         no_route_list_redisplay = true;
510
511         for (i = rows.begin(); i != rows.end(); ++i) {
512                 TreeModel::Row row = (*i);
513                 TimeAxisView* tv = row[route_display_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)[route_display_columns.visible] = yn;
524                                 break;
525
526                         case 1:
527                                 if (atv->is_audio_track()) {
528                                         (*i)[route_display_columns.visible] = yn;
529                                 }
530                                 break;
531                                 
532                         case 2:
533                                 if (!atv->is_audio_track()) {
534                                         (*i)[route_display_columns.visible] = yn;
535                                 }
536                                 break;
537                         }
538                 }
539         }
540
541         no_route_list_redisplay = false;
542         redisplay_route_list ();
543 }
544
545 void
546 Editor::hide_all_routes ()
547 {
548         set_all_tracks_visibility (false);
549 }
550
551 void
552 Editor::show_all_routes ()
553 {
554         set_all_tracks_visibility (true);
555 }
556
557 void
558 Editor::show_all_audiobus ()
559 {
560         set_all_audio_visibility (2, true);
561 }
562 void
563 Editor::hide_all_audiobus ()
564 {
565         set_all_audio_visibility (2, false);
566 }
567
568 void
569 Editor::show_all_audiotracks()
570 {
571         set_all_audio_visibility (1, true);
572 }
573 void
574 Editor::hide_all_audiotracks ()
575 {
576         set_all_audio_visibility (1, false);
577 }
578
579 bool
580 Editor::route_list_display_button_press (GdkEventButton* ev)
581 {
582         if (Keyboard::is_context_menu_event (ev)) {
583                 show_route_list_menu ();
584                 return true;
585         }
586
587         TreeIter iter;
588         TreeModel::Path path;
589         TreeViewColumn* column;
590         int cellx;
591         int celly;
592         
593         if (!route_list_display.get_path_at_pos ((int)ev->x, (int)ev->y, path, column, cellx, celly)) {
594                 return false;
595         }
596
597         switch (GPOINTER_TO_UINT (column->get_data (X_("colnum")))) {
598         case 0:
599                 if ((iter = route_display_model->get_iter (path))) {
600                         TimeAxisView* tv = (*iter)[route_display_columns.tv];
601                         if (tv) {
602                                 bool visible = (*iter)[route_display_columns.visible];
603                                 (*iter)[route_display_columns.visible] = !visible;
604                         }
605                 }
606                 return true;
607
608         case 1:
609                 /* allow normal processing to occur */
610                 return false;
611
612         default:
613                 break;
614         }
615
616         return false;
617 }
618
619 void
620 Editor::show_route_list_menu()
621 {
622         if (route_list_menu == 0) {
623                 build_route_list_menu ();
624         }
625
626         route_list_menu->popup (1, gtk_get_current_event_time());
627 }
628
629 bool
630 Editor::route_list_selection_filter (const Glib::RefPtr<TreeModel>& model, const TreeModel::Path& path, bool yn)
631 {
632         return true;
633 }
634
635 struct EditorOrderRouteSorter {
636     bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
637             /* use of ">" forces the correct sort order */
638             return a->order_key (_order_key) < b->order_key (_order_key);
639     }
640 };
641
642 void
643 Editor::initial_route_list_display ()
644 {
645         boost::shared_ptr<RouteList> routes = session->get_routes();
646         RouteList r (*routes);
647         EditorOrderRouteSorter sorter;
648
649         r.sort (sorter);
650         
651         no_route_list_redisplay = true;
652
653         route_display_model->clear ();
654
655         handle_new_route (r);
656
657         no_route_list_redisplay = false;
658
659         redisplay_route_list ();
660 }
661
662 void
663 Editor::track_list_reorder (const Gtk::TreeModel::Path& path,const Gtk::TreeModel::iterator& iter, int* new_order)
664 {
665         route_redisplay_does_not_sync_order_keys = true;
666         session->set_remote_control_ids();
667         redisplay_route_list ();
668         route_redisplay_does_not_sync_order_keys = false;
669 }
670
671 void
672 Editor::route_list_change (const Gtk::TreeModel::Path& path,const Gtk::TreeModel::iterator& iter)
673 {
674         /* never reset order keys because of a property change */
675         route_redisplay_does_not_reset_order_keys = true;
676         session->set_remote_control_ids();
677         redisplay_route_list ();
678         route_redisplay_does_not_reset_order_keys = false;
679 }
680
681 void
682 Editor::route_list_delete (const Gtk::TreeModel::Path& path)
683 {
684         /* this could require an order reset & sync */
685         session->set_remote_control_ids();
686         ignore_route_list_reorder = true;
687         redisplay_route_list ();
688         ignore_route_list_reorder = false;
689 }
690
691 void  
692 Editor::route_list_display_drag_data_received (const RefPtr<Gdk::DragContext>& context,
693                                                 int x, int y, 
694                                                 const SelectionData& data,
695                                                 guint info, guint time)
696 {
697         if (data.get_target() == "GTK_TREE_MODEL_ROW") {
698                 route_list_display.on_drag_data_received (context, x, y, data, info, time);
699                 return;
700         }
701         context->drag_finish (true, false, time);
702 }
703
704 RouteTimeAxisView*
705 Editor::get_route_view_by_id (PBD::ID& id)
706 {
707         RouteTimeAxisView* v;
708
709         for(TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
710                 if((v = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
711                         if(v->route()->id() == id) {
712                                 return v;
713                         }
714                 }
715         }
716
717         return 0;
718 }
719
720 void
721 Editor::foreach_time_axis_view (sigc::slot<void,TimeAxisView&> theslot)
722 {
723         for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
724                 theslot (**i);
725         }
726 }
727
728 void
729 Editor::move_selected_tracks (bool up)
730 {
731         if (selection->tracks.empty()) {
732                 return;
733         }
734
735         typedef std::pair<TimeAxisView*,boost::shared_ptr<Route> > ViewRoute;
736         std::list<ViewRoute> view_routes;
737         std::vector<int> neworder;
738         TreeModel::Children rows = route_display_model->children();
739         TreeModel::Children::iterator ri;
740
741         for (ri = rows.begin(); ri != rows.end(); ++ri) {
742                 TimeAxisView* tv = (*ri)[route_display_columns.tv];
743                 boost::shared_ptr<Route> route = (*ri)[route_display_columns.route];
744
745                 view_routes.push_back (ViewRoute (tv, route));
746         }
747
748         list<ViewRoute>::iterator trailing;
749         list<ViewRoute>::iterator leading;
750         
751         if (up) {
752                 
753                 trailing = view_routes.begin();
754                 leading = view_routes.begin();
755                 
756                 ++leading;
757                 
758                 while (leading != view_routes.end()) {
759                         if (selection->selected (leading->first)) {
760                                 view_routes.insert (trailing, ViewRoute (leading->first, leading->second));
761                                 leading = view_routes.erase (leading);
762                         } else {
763                                 ++leading;
764                                 ++trailing;
765                         }
766                 }
767
768         } else {
769
770                 /* if we could use reverse_iterator in list::insert, this code
771                    would be a beautiful reflection of the code above. but we can't
772                    and so it looks like a bit of a mess.
773                 */
774
775                 trailing = view_routes.end();
776                 leading = view_routes.end();
777
778                 --leading; if (leading == view_routes.begin()) { return; }
779                 --leading;
780                 --trailing;
781
782                 while (1) {
783
784                         if (selection->selected (leading->first)) {
785                                 list<ViewRoute>::iterator tmp;
786
787                                 /* need to insert *after* trailing, not *before* it,
788                                    which is what insert (iter, val) normally does.
789                                 */
790
791                                 tmp = trailing;
792                                 tmp++;
793
794                                 view_routes.insert (tmp, ViewRoute (leading->first, leading->second));
795                                         
796                                 /* can't use iter = cont.erase (iter); form here, because
797                                    we need iter to move backwards.
798                                 */
799
800                                 tmp = leading;
801                                 --tmp;
802
803                                 bool done = false;
804
805                                 if (leading == view_routes.begin()) {
806                                         /* the one we've just inserted somewhere else
807                                            was the first in the list. erase this copy,
808                                            and then break, because we're done.
809                                         */
810                                         done = true;
811                                 }
812
813                                 view_routes.erase (leading);
814                                 
815                                 if (done) {
816                                         break;
817                                 }
818
819                                 leading = tmp;
820
821                         } else {
822                                 if (leading == view_routes.begin()) {
823                                         break;
824                                 }
825                                 --leading;
826                                 --trailing;
827                         }
828                 };
829         }
830
831         for (leading = view_routes.begin(); leading != view_routes.end(); ++leading) {
832                 neworder.push_back (leading->second->order_key (_order_key));
833         }
834
835         route_display_model->reorder (neworder);
836
837         session->sync_order_keys (_order_key);
838 }