debug output
[ardour.git] / gtk2_ardour / editor_route_groups.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 <cstdlib>
21 #include <cmath>
22
23 #include <gtkmm2ext/stop_signal.h>
24 #include <gtkmm2ext/gtk_ui.h>
25 #include "ardour/route_group.h"
26
27 #include "editor.h"
28 #include "keyboard.h"
29 #include "marker.h"
30 #include "time_axis_view.h"
31 #include "prompter.h"
32 #include "gui_thread.h"
33 #include "editor_group_tabs.h"
34 #include "route_group_dialog.h"
35 #include "route_time_axis.h"
36 #include "editor_routes.h"
37 #include "editor_route_groups.h"
38
39 #include "ardour/route.h"
40 #include "ardour/session.h"
41
42 #include "i18n.h"
43
44 using namespace std;
45 using namespace sigc;
46 using namespace ARDOUR;
47 using namespace PBD;
48 using namespace Gtk;
49
50 EditorRouteGroups::EditorRouteGroups (Editor* e)
51         : EditorComponent (e),
52           _menu (0),
53           _in_row_change (false)
54
55 {
56         _model = ListStore::create (_columns);
57         _display.set_model (_model);
58
59         _display.append_column (_("Name"), _columns.text);
60
61         _display.append_column (_("G"), _columns.gain);
62         _display.append_column (_("R"), _columns.record);
63         _display.append_column (_("M"), _columns.mute);
64         _display.append_column (_("S"), _columns.solo);
65         _display.append_column (_("Sel"), _columns.select);
66         _display.append_column (_("E"), _columns.edits);
67
68         _display.append_column (_("Show"), _columns.is_visible);
69
70         _display.get_column (0)->set_data (X_("colnum"), GUINT_TO_POINTER(0));
71         _display.get_column (1)->set_data (X_("colnum"), GUINT_TO_POINTER(1));
72         _display.get_column (2)->set_data (X_("colnum"), GUINT_TO_POINTER(2));
73         _display.get_column (3)->set_data (X_("colnum"), GUINT_TO_POINTER(3));
74         _display.get_column (4)->set_data (X_("colnum"), GUINT_TO_POINTER(4));
75         _display.get_column (5)->set_data (X_("colnum"), GUINT_TO_POINTER(5));
76         _display.get_column (6)->set_data (X_("colnum"), GUINT_TO_POINTER(6));
77         _display.get_column (7)->set_data (X_("colnum"), GUINT_TO_POINTER(7));
78
79         _display.get_column (0)->set_expand (true);
80         _display.get_column (1)->set_expand (false);
81         _display.get_column (2)->set_expand (false);
82         _display.get_column (3)->set_expand (false);
83         _display.get_column (4)->set_expand (false);
84         _display.get_column (5)->set_expand (false);
85         _display.get_column (6)->set_expand (false);
86         _display.get_column (7)->set_expand (false);
87
88         _display.set_headers_visible (true);
89
90         /* name is directly editable */
91
92         CellRendererText* name_cell = dynamic_cast<CellRendererText*>(_display.get_column_cell_renderer (0));
93         name_cell->property_editable() = true;
94         name_cell->signal_edited().connect (mem_fun (*this, &EditorRouteGroups::name_edit));
95
96         /* use checkbox for the active + visible columns */
97
98         CellRendererToggle* active_cell = dynamic_cast<CellRendererToggle*>(_display.get_column_cell_renderer (1));
99         active_cell->property_activatable() = true;
100         active_cell->property_radio() = false;
101
102         active_cell = dynamic_cast<CellRendererToggle*>(_display.get_column_cell_renderer (2));
103         active_cell->property_activatable() = true;
104         active_cell->property_radio() = false;
105
106         active_cell = dynamic_cast<CellRendererToggle*>(_display.get_column_cell_renderer (3));
107         active_cell->property_activatable() = true;
108         active_cell->property_radio() = false;
109
110         active_cell = dynamic_cast<CellRendererToggle*>(_display.get_column_cell_renderer (4));
111         active_cell->property_activatable() = true;
112         active_cell->property_radio() = false;
113
114         active_cell = dynamic_cast<CellRendererToggle*>(_display.get_column_cell_renderer (5));
115         active_cell->property_activatable() = true;
116         active_cell->property_radio() = false;
117
118         active_cell = dynamic_cast<CellRendererToggle*>(_display.get_column_cell_renderer (6));
119         active_cell->property_activatable() = true;
120         active_cell->property_radio() = false;
121
122         active_cell = dynamic_cast<CellRendererToggle*>(_display.get_column_cell_renderer (7));
123         active_cell->property_activatable() = true;
124         active_cell->property_radio() = false;
125
126         _model->signal_row_changed().connect (mem_fun (*this, &EditorRouteGroups::row_change));
127
128         _display.set_name ("EditGroupList");
129         _display.get_selection()->set_mode (SELECTION_SINGLE);
130         _display.set_headers_visible (true);
131         _display.set_reorderable (false);
132         _display.set_rules_hint (true);
133         _display.set_size_request (75, -1);
134
135         _scroller.add (_display);
136         _scroller.set_policy (POLICY_AUTOMATIC, POLICY_AUTOMATIC);
137
138         _display.signal_button_press_event().connect (mem_fun(*this, &EditorRouteGroups::button_press_event), false);
139
140         _display_packer = new VBox;
141         HBox* button_box = manage (new HBox());
142         button_box->set_homogeneous (true);
143
144         Button* add_button = manage (new Button ());
145         Button* remove_button = manage (new Button ());
146
147         Widget* w;
148
149         w = manage (new Image (Stock::ADD, ICON_SIZE_BUTTON));
150         w->show();
151         add_button->add (*w);
152
153         w = manage (new Image (Stock::REMOVE, ICON_SIZE_BUTTON));
154         w->show();
155         remove_button->add (*w);
156
157         add_button->signal_clicked().connect (mem_fun (*this, &EditorRouteGroups::new_route_group));
158         remove_button->signal_clicked().connect (mem_fun (*this, &EditorRouteGroups::remove_selected));
159
160         button_box->pack_start (*add_button);
161         button_box->pack_start (*remove_button);
162
163         _display_packer->pack_start (_scroller, true, true);
164         _display_packer->pack_start (*button_box, false, false);
165 }
166
167
168 Gtk::Menu*
169 EditorRouteGroups::menu (RouteGroup* g)
170 {
171         using namespace Gtk::Menu_Helpers;
172
173         delete _menu;
174
175         Menu* new_from = new Menu;
176         MenuList& f = new_from->items ();
177         f.push_back (MenuElem (_("Selection..."), mem_fun (*this, &EditorRouteGroups::new_from_selection)));
178         f.push_back (MenuElem (_("Record Enabled..."), mem_fun (*this, &EditorRouteGroups::new_from_rec_enabled)));
179         f.push_back (MenuElem (_("Soloed..."), mem_fun (*this, &EditorRouteGroups::new_from_soloed)));
180
181         _menu = new Menu;
182         _menu->set_name ("ArdourContextMenu");
183         MenuList& items = _menu->items();
184
185         items.push_back (MenuElem (_("New..."), mem_fun(*this, &EditorRouteGroups::new_route_group)));
186         items.push_back (MenuElem (_("New From"), *new_from));
187         if (g) {
188                 items.push_back (MenuElem (_("Edit..."), bind (mem_fun (*this, &EditorRouteGroups::edit), g)));
189                 items.push_back (MenuElem (_("Fit to Window"), bind (mem_fun (*_editor, &Editor::fit_route_group), g)));
190                 items.push_back (MenuElem (_("Subgroup"), bind (mem_fun (*this, &EditorRouteGroups::subgroup), g)));
191                 items.push_back (MenuElem (_("Collect"), bind (mem_fun (*this, &EditorRouteGroups::collect), g)));
192         }
193         items.push_back (SeparatorElem());
194         items.push_back (MenuElem (_("Activate All"), mem_fun(*this, &EditorRouteGroups::activate_all)));
195         items.push_back (MenuElem (_("Disable All"), mem_fun(*this, &EditorRouteGroups::disable_all)));
196
197         return _menu;
198 }
199
200 void
201 EditorRouteGroups::subgroup (RouteGroup* g)
202 {
203         g->make_subgroup ();
204 }
205
206 void
207 EditorRouteGroups::unsubgroup (RouteGroup* g)
208 {
209         g->destroy_subgroup ();
210 }
211
212 void
213 EditorRouteGroups::activate_all ()
214 {
215         _session->foreach_route_group (
216                 bind (mem_fun (*this, &EditorRouteGroups::set_activation), true)
217                 );
218 }
219
220 void
221 EditorRouteGroups::disable_all ()
222 {
223         _session->foreach_route_group (
224                 bind (mem_fun (*this, &EditorRouteGroups::set_activation), false)
225                 );
226 }
227
228 void
229 EditorRouteGroups::set_activation (RouteGroup* g, bool a)
230 {
231         g->set_active (a, this);
232 }
233
234 void
235 EditorRouteGroups::new_route_group ()
236 {
237         RouteGroup* g = new RouteGroup (
238                 *_session,
239                 "",
240                 RouteGroup::Active,
241                 (RouteGroup::Property) (RouteGroup::Mute | RouteGroup::Solo | RouteGroup::Edit)
242                 );
243
244         RouteGroupDialog d (g, Gtk::Stock::NEW);
245         int const r = d.do_run ();
246
247         if (r == Gtk::RESPONSE_OK) {
248                 _session->add_route_group (g);
249         } else {
250                 delete g;
251         }
252 }
253
254 void
255 EditorRouteGroups::new_from_selection ()
256 {
257         RouteGroup* g = new RouteGroup (
258                 *_session,
259                 "",
260                 RouteGroup::Active,
261                 (RouteGroup::Property) (RouteGroup::Mute | RouteGroup::Solo | RouteGroup::Edit | RouteGroup::Select)
262                 );
263
264         RouteGroupDialog d (g, Gtk::Stock::NEW);
265         int const r = d.do_run ();
266
267         if (r == Gtk::RESPONSE_OK) {
268                 _session->add_route_group (g);
269
270                 for (TrackSelection::iterator i = _editor->get_selection().tracks.begin(); i != _editor->get_selection().tracks.end(); ++i) {
271                         RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
272                         if (rtv) {
273                                 rtv->route()->set_route_group (g, this);
274                         }
275                 }
276
277         } else {
278                 delete g;
279         }
280 }
281
282 void
283 EditorRouteGroups::new_from_rec_enabled ()
284 {
285         RouteGroup* g = new RouteGroup (
286                 *_session,
287                 "",
288                 RouteGroup::Active,
289                 (RouteGroup::Property) (RouteGroup::Mute | RouteGroup::Solo | RouteGroup::Edit | RouteGroup::RecEnable)
290                 );
291
292         RouteGroupDialog d (g, Gtk::Stock::NEW);
293         int const r = d.do_run ();
294
295         if (r == Gtk::RESPONSE_OK) {
296                 _session->add_route_group (g);
297
298                 for (Editor::TrackViewList::const_iterator i = _editor->get_track_views().begin(); i != _editor->get_track_views().end(); ++i) {
299                         RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
300                         if (rtv && rtv->route()->record_enabled()) {
301                                 rtv->route()->set_route_group (g, this);
302                         }
303                 }
304
305         } else {
306                 delete g;
307         }
308 }
309
310 void
311 EditorRouteGroups::new_from_soloed ()
312 {
313         RouteGroup* g = new RouteGroup (
314                 *_session,
315                 "",
316                 RouteGroup::Active,
317                 (RouteGroup::Property) (RouteGroup::Mute | RouteGroup::Solo | RouteGroup::Edit)
318                 );
319
320         RouteGroupDialog d (g, Gtk::Stock::NEW);
321         int const r = d.do_run ();
322
323         if (r == Gtk::RESPONSE_OK) {
324                 _session->add_route_group (g);
325
326                 for (Editor::TrackViewList::const_iterator i = _editor->get_track_views().begin(); i != _editor->get_track_views().end(); ++i) {
327                         RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
328                         if (rtv && !rtv->route()->is_master() && rtv->route()->soloed()) {
329                                 rtv->route()->set_route_group (g, this);
330                         }
331                 }
332
333         } else {
334                 delete g;
335         }
336 }
337
338 void
339 EditorRouteGroups::edit (RouteGroup* g)
340 {
341         RouteGroupDialog d (g, Gtk::Stock::APPLY);
342         d.do_run ();
343 }
344
345 void
346 EditorRouteGroups::remove_selected ()
347 {
348         Glib::RefPtr<TreeSelection> selection = _display.get_selection();
349         TreeView::Selection::ListHandle_Path rows = selection->get_selected_rows ();
350
351         if (rows.empty()) {
352                 return;
353         }
354
355         TreeView::Selection::ListHandle_Path::iterator i = rows.begin();
356         TreeIter iter;
357
358         /* selection mode is single, so rows.begin() is it */
359
360         if ((iter = _model->get_iter (*i))) {
361
362                 RouteGroup* rg = (*iter)[_columns.routegroup];
363
364                 if (rg) {
365                         _session->remove_route_group (*rg);
366                 }
367         }
368 }
369
370 void
371 EditorRouteGroups::button_clicked ()
372 {
373         new_route_group ();
374 }
375
376 gint
377 EditorRouteGroups::button_press_event (GdkEventButton* ev)
378 {
379         TreeModel::Path path;
380         TreeIter iter;
381         RouteGroup* group = 0;
382         TreeViewColumn* column;
383         int cellx;
384         int celly;
385
386         bool const p = _display.get_path_at_pos ((int)ev->x, (int)ev->y, path, column, cellx, celly);
387
388         if (p) {
389                 iter = _model->get_iter (path);
390         }
391
392         if (iter) {
393                 group = (*iter)[_columns.routegroup];
394         }
395
396         if (Keyboard::is_context_menu_event (ev)) {
397                 menu(group)->popup (1, ev->time);
398                 return true;
399         }
400
401         if (!p) {
402                 return 1;
403         }
404
405         switch (GPOINTER_TO_UINT (column->get_data (X_("colnum")))) {
406         case 0:
407                 if (Keyboard::is_edit_event (ev)) {
408                         if ((iter = _model->get_iter (path))) {
409                                 if ((group = (*iter)[_columns.routegroup]) != 0) {
410                                         // edit_route_group (group);
411 #ifdef GTKOSX
412                                         _display.queue_draw();
413 #endif
414                                         return true;
415                                 }
416                         }
417
418                 }
419                 break;
420
421         case 1:
422                 if ((iter = _model->get_iter (path))) {
423                         bool gain = (*iter)[_columns.gain];
424                         (*iter)[_columns.gain] = !gain;
425 #ifdef GTKOSX
426                         _display.queue_draw();
427 #endif
428                         return true;
429                 }
430                 break;
431
432         case 2:
433                 if ((iter = _model->get_iter (path))) {
434                         bool record = (*iter)[_columns.record];
435                         (*iter)[_columns.record] = !record;
436 #ifdef GTKOSX
437                         _display.queue_draw();
438 #endif
439                         return true;
440                 }
441                 break;
442
443         case 3:
444                 if ((iter = _model->get_iter (path))) {
445                         bool mute = (*iter)[_columns.mute];
446                         (*iter)[_columns.mute] = !mute;
447 #ifdef GTKOSX
448                         _display.queue_draw();
449 #endif
450                         return true;
451                 }
452                 break;
453
454         case 4:
455                 if ((iter = _model->get_iter (path))) {
456                         bool solo = (*iter)[_columns.solo];
457                         (*iter)[_columns.solo] = !solo;
458 #ifdef GTKOSX
459                         _display.queue_draw();
460 #endif
461                         return true;
462                 }
463                 break;
464
465         case 5:
466                 if ((iter = _model->get_iter (path))) {
467                         bool select = (*iter)[_columns.select];
468                         (*iter)[_columns.select] = !select;
469 #ifdef GTKOSX
470                         _display.queue_draw();
471 #endif
472                         return true;
473                 }
474                 break;
475
476         case 6:
477                 if ((iter = _model->get_iter (path))) {
478                         bool edits = (*iter)[_columns.edits];
479                         (*iter)[_columns.edits] = !edits;
480 #ifdef GTKOSX
481                         _display.queue_draw();
482 #endif
483                         return true;
484                 }
485                 break;
486
487         case 7:
488                 if ((iter = _model->get_iter (path))) {
489                         bool visible = (*iter)[_columns.is_visible];
490                         (*iter)[_columns.is_visible] = !visible;
491 #ifdef GTKOSX
492                         _display.queue_draw();
493 #endif
494                         return true;
495                 }
496                 break;
497
498         default:
499                 break;
500         }
501
502         return false;
503  }
504
505 void
506 EditorRouteGroups::row_change (const Gtk::TreeModel::Path&, const Gtk::TreeModel::iterator& iter)
507 {
508         RouteGroup* group;
509
510         if (_in_row_change) {
511                 return;
512         }
513
514         if ((group = (*iter)[_columns.routegroup]) == 0) {
515                 return;
516         }
517
518         if ((*iter)[_columns.is_visible]) {
519                 for (Editor::TrackViewList::const_iterator j = _editor->get_track_views().begin(); j != _editor->get_track_views().end(); ++j) {
520                         if ((*j)->route_group() == group) {
521                                 _editor->_routes->show_track_in_display (**j);
522                         }
523                 }
524         } else {
525                 for (Editor::TrackViewList::const_iterator j = _editor->get_track_views().begin(); j != _editor->get_track_views().end(); ++j) {
526                         if ((*j)->route_group() == group) {
527                                 _editor->hide_track_in_display (**j);
528                         }
529                 }
530         }
531
532         group->set_property (RouteGroup::Gain, (*iter)[_columns.gain]);
533         group->set_property (RouteGroup::RecEnable, (*iter)[_columns.record]);
534         group->set_property (RouteGroup::Mute, (*iter)[_columns.mute]);
535         group->set_property (RouteGroup::Solo, (*iter)[_columns.solo]);
536         group->set_property (RouteGroup::Select, (*iter)[_columns.select]);
537         group->set_property (RouteGroup::Edit, (*iter)[_columns.edits]);
538
539         string name = (*iter)[_columns.text];
540
541         if (name != group->name()) {
542                 group->set_name (name);
543         }
544 }
545
546 void
547 EditorRouteGroups::add (RouteGroup* group)
548 {
549         ENSURE_GUI_THREAD (bind (mem_fun(*this, &EditorRouteGroups::add), group));
550         bool focus = false;
551
552         TreeModel::Row row = *(_model->append());
553
554         row[_columns.is_visible] = !group->is_hidden();
555         row[_columns.gain] = group->property(RouteGroup::Gain);
556         row[_columns.record] = group->property(RouteGroup::RecEnable);
557         row[_columns.mute] = group->property(RouteGroup::Mute);
558         row[_columns.solo] = group->property(RouteGroup::Solo);
559         row[_columns.select] = group->property(RouteGroup::Select);
560         row[_columns.edits] = group->property(RouteGroup::Edit);
561
562         _in_row_change = true;
563
564         row[_columns.routegroup] = group;
565
566         if (!group->name().empty()) {
567                 row[_columns.text] = group->name();
568         } else {
569                 row[_columns.text] = _("unnamed");
570                 focus = true;
571         }
572
573         group->FlagsChanged.connect (bind (mem_fun (*this, &EditorRouteGroups::flags_changed), group));
574
575         if (focus) {
576                 TreeViewColumn* col = _display.get_column (0);
577                 CellRendererText* name_cell = dynamic_cast<CellRendererText*>(_display.get_column_cell_renderer (0));
578                 _display.set_cursor (_model->get_path (row), *col, *name_cell, true);
579         }
580
581         _in_row_change = false;
582
583         _editor->_group_tabs->set_dirty ();
584 }
585
586 void
587 EditorRouteGroups::groups_changed ()
588 {
589         ENSURE_GUI_THREAD (mem_fun (*this, &EditorRouteGroups::groups_changed));
590
591         /* just rebuild the while thing */
592
593         _model->clear ();
594
595         {
596                 TreeModel::Row row;
597                 row = *(_model->append());
598                 row[_columns.is_visible] = true;
599                 row[_columns.text] = (_("-all-"));
600                 row[_columns.routegroup] = 0;
601         }
602
603         _session->foreach_route_group (mem_fun (*this, &EditorRouteGroups::add));
604 }
605
606 void
607 EditorRouteGroups::flags_changed (void* src, RouteGroup* group)
608 {
609         ENSURE_GUI_THREAD (bind (mem_fun(*this, &EditorRouteGroups::flags_changed), src, group));
610
611         _in_row_change = true;
612
613         Gtk::TreeModel::Children children = _model->children();
614
615         for(Gtk::TreeModel::Children::iterator iter = children.begin(); iter != children.end(); ++iter) {
616                 if (group == (*iter)[_columns.routegroup]) {
617                         (*iter)[_columns.is_visible] = !group->is_hidden();
618                         (*iter)[_columns.text] = group->name();
619                         (*iter)[_columns.gain] = group->property(RouteGroup::Gain);
620                         (*iter)[_columns.record] = group->property(RouteGroup::RecEnable);
621                         (*iter)[_columns.mute] = group->property(RouteGroup::Mute);
622                         (*iter)[_columns.solo] = group->property(RouteGroup::Solo);
623                         (*iter)[_columns.select] = group->property(RouteGroup::Select);
624                         (*iter)[_columns.edits] = group->property(RouteGroup::Edit);
625                 }
626         }
627
628         _in_row_change = false;
629
630         _editor->_group_tabs->set_dirty ();
631 }
632
633 void
634 EditorRouteGroups::name_edit (const Glib::ustring& path, const Glib::ustring& new_text)
635 {
636         RouteGroup* group;
637         TreeIter iter;
638
639         if ((iter = _model->get_iter (path))) {
640
641                 if ((group = (*iter)[_columns.routegroup]) == 0) {
642                         return;
643                 }
644
645                 if (new_text != group->name()) {
646                         group->set_name (new_text);
647                 }
648         }
649 }
650
651 void
652 EditorRouteGroups::clear ()
653 {
654         _display.set_model (Glib::RefPtr<Gtk::TreeStore> (0));
655         _model->clear ();
656         _display.set_model (_model);
657 }
658
659 void
660 EditorRouteGroups::connect_to_session (Session* s)
661 {
662         EditorComponent::connect_to_session (s);
663
664         _session_connections.push_back (_session->route_group_added.connect (mem_fun (*this, &EditorRouteGroups::add)));
665         _session_connections.push_back (_session->route_group_removed.connect (mem_fun (*this, &EditorRouteGroups::groups_changed)));
666
667         groups_changed ();
668 }
669
670 struct CollectSorter {
671         bool operator () (Route* a, Route* b) {
672                 return a->order_key (N_ ("editor")) < b->order_key (N_ ("editor"));
673         }
674 };
675
676 /** Collect all members of a RouteGroup so that they are together in the Editor.
677  *  @param g Group to collect.
678  */
679 void
680 EditorRouteGroups::collect (RouteGroup* g)
681 {
682         list<Route*> routes = g->route_list ();
683         routes.sort (CollectSorter ());
684         int const N = routes.size ();
685
686         list<Route*>::iterator i = routes.begin ();
687         Editor::TrackViewList::const_iterator j = _editor->get_track_views().begin();
688
689         int diff = 0;
690         int coll = -1;
691         while (i != routes.end() && j != _editor->get_track_views().end()) {
692
693                 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*j);
694                 if (rtv) {
695
696                         boost::shared_ptr<Route> r = rtv->route ();
697                         int const k = r->order_key (N_ ("editor"));
698
699                         if (*i == r.get()) {
700
701                                 if (coll == -1) {
702                                         coll = k;
703                                         diff = N - 1;
704                                 } else {
705                                         --diff;
706                                 }
707
708                                 r->set_order_key (N_ ("editor"), coll);
709
710                                 ++coll;
711                                 ++i;
712
713                         } else {
714
715                                 r->set_order_key (N_ ("editor"), k + diff);
716
717                         }
718                 }
719
720                 ++j;
721         }
722
723         _editor->_routes->sync_order_keys ("");
724 }