Fix up route group state signal handling. Make the PropertyList version
[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 ARDOUR;
46 using namespace PBD;
47 using namespace Gtk;
48 using Gtkmm2ext::Keyboard;
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 (sigc::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 (sigc::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 (sigc::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 (hide_return (sigc::mem_fun (*this, &EditorRouteGroups::new_route_group)));
158         remove_button->signal_clicked().connect (sigc::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..."), sigc::mem_fun (*this, &EditorRouteGroups::new_from_selection)));
178         f.push_back (MenuElem (_("Record Enabled..."), sigc::mem_fun (*this, &EditorRouteGroups::new_from_rec_enabled)));
179         f.push_back (MenuElem (_("Soloed..."), sigc::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..."), hide_return (sigc::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..."), sigc::bind (sigc::mem_fun (*this, &EditorRouteGroups::edit), g)));
189                 items.push_back (MenuElem (_("Fit to Window"), sigc::bind (sigc::mem_fun (*_editor, &Editor::fit_route_group), g)));
190                 items.push_back (MenuElem (_("Subgroup"), sigc::bind (sigc::mem_fun (*this, &EditorRouteGroups::subgroup), g)));
191                 items.push_back (MenuElem (_("Collect"), sigc::bind (sigc::mem_fun (*this, &EditorRouteGroups::collect), g)));
192         }
193         items.push_back (SeparatorElem());
194         items.push_back (MenuElem (_("Activate All"), sigc::mem_fun(*this, &EditorRouteGroups::activate_all)));
195         items.push_back (MenuElem (_("Disable All"), sigc::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                 sigc::bind (sigc::mem_fun (*this, &EditorRouteGroups::set_activation), true)
217                 );
218 }
219
220 void
221 EditorRouteGroups::disable_all ()
222 {
223         _session->foreach_route_group (
224                 sigc::bind (sigc::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 ARDOUR::RouteGroup *
235 EditorRouteGroups::new_route_group () const
236 {
237         PropertyList plist;
238
239         plist.add (Properties::active, true);
240         plist.add (Properties::mute, true);
241         plist.add (Properties::solo, true);
242         plist.add (Properties::edit, true);
243
244         RouteGroup* g = new RouteGroup (*_session, "");
245
246         g->set_properties (plist);
247
248         RouteGroupDialog d (g, Gtk::Stock::NEW);
249         int const r = d.do_run ();
250
251         if (r != Gtk::RESPONSE_OK) {
252                 delete g;
253                 return 0;
254         }
255         
256         _session->add_route_group (g);
257         return g;
258 }
259 void
260 EditorRouteGroups::run_new_group_dialog (const RouteList& rl)
261 {
262         PropertyList plist;
263
264         plist.add (Properties::active, true);
265         plist.add (Properties::mute, true);
266         plist.add (Properties::solo, true);
267         plist.add (Properties::recenable, true);
268         plist.add (Properties::edit, true);
269
270         RouteGroup* g = new RouteGroup (*_session, "");
271         g->set_properties (plist);
272
273         RouteGroupDialog d (g, Gtk::Stock::NEW);
274         int const r = d.do_run ();
275
276         switch (r) {
277         case Gtk::RESPONSE_OK:
278         case Gtk::RESPONSE_ACCEPT:
279                 _session->add_route_group (g);
280                 for (RouteList::const_iterator i = rl.begin(); i != rl.end(); ++i) {
281                         g->add (*i);
282                 }
283                 break;
284         default:
285                 delete g;
286         }
287 }
288
289 void
290 EditorRouteGroups::new_from_selection ()
291 {
292         if (_editor->get_selection().tracks.empty()) {
293                 return;
294         }
295
296         RouteList rl;
297
298         for (TrackSelection::iterator i = _editor->get_selection().tracks.begin(); i != _editor->get_selection().tracks.end(); ++i) {
299                 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
300                 if (rtv) {
301                         rl.push_back (rtv->route());
302                 }
303         }
304
305         if (rl.empty()) {
306                 return;
307         }
308
309         run_new_group_dialog (rl);
310 }
311
312 void
313 EditorRouteGroups::new_from_rec_enabled ()
314 {
315         RouteList rl;
316
317         for (TrackViewList::const_iterator i = _editor->get_track_views().begin(); i != _editor->get_track_views().end(); ++i) {
318                 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
319                 if (rtv && rtv->route()->record_enabled()) {
320                         rl.push_back (rtv->route());
321                 }
322         }
323
324         if (rl.empty()) {
325                 return;
326         }
327
328         run_new_group_dialog (rl);
329 }
330
331 void
332 EditorRouteGroups::new_from_soloed ()
333 {
334         RouteList rl;
335
336         for (TrackViewList::const_iterator i = _editor->get_track_views().begin(); i != _editor->get_track_views().end(); ++i) {
337                 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
338                 if (rtv && !rtv->route()->is_master() && rtv->route()->soloed()) {
339                         rl.push_back (rtv->route());
340                 }
341         }
342
343         if (rl.empty()) {
344                 return;
345         }
346
347         run_new_group_dialog (rl);
348 }
349
350 void
351 EditorRouteGroups::edit (RouteGroup* g)
352 {
353         RouteGroupDialog d (g, Gtk::Stock::APPLY);
354         d.do_run ();
355 }
356
357 void
358 EditorRouteGroups::remove_selected ()
359 {
360         Glib::RefPtr<TreeSelection> selection = _display.get_selection();
361         TreeView::Selection::ListHandle_Path rows = selection->get_selected_rows ();
362
363         if (rows.empty()) {
364                 return;
365         }
366
367         TreeView::Selection::ListHandle_Path::iterator i = rows.begin();
368         TreeIter iter;
369
370         /* selection mode is single, so rows.begin() is it */
371
372         if ((iter = _model->get_iter (*i))) {
373
374                 RouteGroup* rg = (*iter)[_columns.routegroup];
375
376                 if (rg) {
377                         _session->remove_route_group (*rg);
378                 }
379         }
380 }
381
382 void
383 EditorRouteGroups::button_clicked ()
384 {
385         new_route_group ();
386 }
387
388 gint
389 EditorRouteGroups::button_press_event (GdkEventButton* ev)
390 {
391         TreeModel::Path path;
392         TreeIter iter;
393         RouteGroup* group = 0;
394         TreeViewColumn* column;
395         int cellx;
396         int celly;
397
398         bool const p = _display.get_path_at_pos ((int)ev->x, (int)ev->y, path, column, cellx, celly);
399
400         if (p) {
401                 iter = _model->get_iter (path);
402         }
403
404         if (iter) {
405                 group = (*iter)[_columns.routegroup];
406         }
407
408         if (Keyboard::is_context_menu_event (ev)) {
409                 menu(group)->popup (1, ev->time);
410                 return true;
411         }
412
413         if (!p) {
414                 return 1;
415         }
416
417         switch (GPOINTER_TO_UINT (column->get_data (X_("colnum")))) {
418         case 0:
419                 if (Keyboard::is_edit_event (ev)) {
420                         if ((iter = _model->get_iter (path))) {
421                                 if ((group = (*iter)[_columns.routegroup]) != 0) {
422                                         // edit_route_group (group);
423 #ifdef GTKOSX
424                                         _display.queue_draw();
425 #endif
426                                         return true;
427                                 }
428                         }
429
430                 }
431                 break;
432
433         case 1:
434                 if ((iter = _model->get_iter (path))) {
435                         bool gain = (*iter)[_columns.gain];
436                         (*iter)[_columns.gain] = !gain;
437 #ifdef GTKOSX
438                         _display.queue_draw();
439 #endif
440                         return true;
441                 }
442                 break;
443
444         case 2:
445                 if ((iter = _model->get_iter (path))) {
446                         bool record = (*iter)[_columns.record];
447                         (*iter)[_columns.record] = !record;
448 #ifdef GTKOSX
449                         _display.queue_draw();
450 #endif
451                         return true;
452                 }
453                 break;
454
455         case 3:
456                 if ((iter = _model->get_iter (path))) {
457                         bool mute = (*iter)[_columns.mute];
458                         (*iter)[_columns.mute] = !mute;
459 #ifdef GTKOSX
460                         _display.queue_draw();
461 #endif
462                         return true;
463                 }
464                 break;
465
466         case 4:
467                 if ((iter = _model->get_iter (path))) {
468                         bool solo = (*iter)[_columns.solo];
469                         (*iter)[_columns.solo] = !solo;
470 #ifdef GTKOSX
471                         _display.queue_draw();
472 #endif
473                         return true;
474                 }
475                 break;
476
477         case 5:
478                 if ((iter = _model->get_iter (path))) {
479                         bool select = (*iter)[_columns.select];
480                         (*iter)[_columns.select] = !select;
481 #ifdef GTKOSX
482                         _display.queue_draw();
483 #endif
484                         return true;
485                 }
486                 break;
487
488         case 6:
489                 if ((iter = _model->get_iter (path))) {
490                         bool edits = (*iter)[_columns.edits];
491                         (*iter)[_columns.edits] = !edits;
492 #ifdef GTKOSX
493                         _display.queue_draw();
494 #endif
495                         return true;
496                 }
497                 break;
498
499         case 7:
500                 if ((iter = _model->get_iter (path))) {
501                         bool visible = (*iter)[_columns.is_visible];
502                         (*iter)[_columns.is_visible] = !visible;
503 #ifdef GTKOSX
504                         _display.queue_draw();
505 #endif
506                         return true;
507                 }
508                 break;
509
510         default:
511                 break;
512         }
513
514         return false;
515  }
516
517 void
518 EditorRouteGroups::row_change (const Gtk::TreeModel::Path&, const Gtk::TreeModel::iterator& iter)
519 {
520         RouteGroup* group;
521
522         if (_in_row_change) {
523                 return;
524         }
525
526         if ((group = (*iter)[_columns.routegroup]) == 0) {
527                 return;
528         }
529
530         if ((*iter)[_columns.is_visible]) {
531                 for (TrackViewList::const_iterator j = _editor->get_track_views().begin(); j != _editor->get_track_views().end(); ++j) {
532                         if ((*j)->route_group() == group) {
533                                 _editor->_routes->show_track_in_display (**j);
534                         }
535                 }
536         } else {
537                 for (TrackViewList::const_iterator j = _editor->get_track_views().begin(); j != _editor->get_track_views().end(); ++j) {
538                         if ((*j)->route_group() == group) {
539                                 _editor->hide_track_in_display (**j);
540                         }
541                 }
542         }
543
544         PropertyList plist;
545         bool val = (*iter)[_columns.gain];
546         plist.add (Properties::gain, val);
547         val = (*iter)[_columns.record];
548         plist.add (Properties::recenable, val);
549         val = (*iter)[_columns.mute];
550         plist.add (Properties::mute, val);
551         val = (*iter)[_columns.solo];
552         plist.add (Properties::solo, val);
553         val = (*iter)[_columns.select];
554         plist.add (Properties::select, val);
555         val = (*iter)[_columns.edits];
556         plist.add (Properties::edit, val);
557         plist.add (Properties::name, string ((*iter)[_columns.text]));
558         
559         group->set_properties (plist);
560 }
561
562 void
563 EditorRouteGroups::add (RouteGroup* group)
564 {
565         ENSURE_GUI_THREAD (*this, &EditorRouteGroups::add, group)
566         bool focus = false;
567
568         TreeModel::Row row = *(_model->append());
569
570         row[_columns.is_visible] = !group->is_hidden();
571         row[_columns.gain] = group->is_gain ();
572         row[_columns.record] = group->is_recenable();
573         row[_columns.mute] = group->is_mute ();
574         row[_columns.solo] = group->is_solo ();
575         row[_columns.select] = group->is_select ();
576         row[_columns.edits] = group->is_edit ();
577
578         _in_row_change = true;
579
580         row[_columns.routegroup] = group;
581
582         if (!group->name().empty()) {
583                 row[_columns.text] = group->name();
584         } else {
585                 row[_columns.text] = _("unnamed");
586                 focus = true;
587         }
588
589         group->PropertyChanged.connect (property_changed_connection, MISSING_INVALIDATOR, ui_bind (&EditorRouteGroups::property_changed, this, group, _1), gui_context());
590
591         if (focus) {
592                 TreeViewColumn* col = _display.get_column (0);
593                 CellRendererText* name_cell = dynamic_cast<CellRendererText*>(_display.get_column_cell_renderer (0));
594                 _display.set_cursor (_model->get_path (row), *col, *name_cell, true);
595         }
596
597         _in_row_change = false;
598
599         _editor->_group_tabs->set_dirty ();
600 }
601
602 void
603 EditorRouteGroups::groups_changed ()
604 {
605         ENSURE_GUI_THREAD (*this, &EditorRouteGroups::groups_changed)
606
607         /* just rebuild the while thing */
608
609         _model->clear ();
610
611         {
612                 TreeModel::Row row;
613                 row = *(_model->append());
614                 row[_columns.is_visible] = true;
615                 row[_columns.text] = (_("-all-"));
616                 row[_columns.routegroup] = 0;
617         }
618
619         if (_session) {
620                 _session->foreach_route_group (sigc::mem_fun (*this, &EditorRouteGroups::add));
621         }
622 }
623
624 void
625 EditorRouteGroups::property_changed (RouteGroup* group, const PropertyChange& change)
626 {
627         _in_row_change = true;
628
629         Gtk::TreeModel::Children children = _model->children();
630
631         for(Gtk::TreeModel::Children::iterator iter = children.begin(); iter != children.end(); ++iter) {
632                 if (group == (*iter)[_columns.routegroup]) {
633                         (*iter)[_columns.is_visible] = !group->is_hidden();
634                         (*iter)[_columns.text] = group->name();
635                         (*iter)[_columns.gain] = group->is_gain ();
636                         (*iter)[_columns.record] = group->is_recenable ();
637                         (*iter)[_columns.mute] = group->is_mute ();
638                         (*iter)[_columns.solo] = group->is_solo ();
639                         (*iter)[_columns.select] = group->is_select ();
640                         (*iter)[_columns.edits] = group->is_edit ();
641                 }
642         }
643
644         _in_row_change = false;
645
646         if (change.contains (Properties::name) || change.contains (Properties::active)) {
647                 _editor->_group_tabs->set_dirty ();
648         }
649 }
650
651 void
652 EditorRouteGroups::name_edit (const Glib::ustring& path, const Glib::ustring& new_text)
653 {
654         RouteGroup* group;
655         TreeIter iter;
656
657         if ((iter = _model->get_iter (path))) {
658
659                 if ((group = (*iter)[_columns.routegroup]) == 0) {
660                         return;
661                 }
662
663                 if (new_text != group->name()) {
664                         group->set_name (new_text);
665                 }
666         }
667 }
668
669 void
670 EditorRouteGroups::clear ()
671 {
672         _display.set_model (Glib::RefPtr<Gtk::TreeStore> (0));
673         _model->clear ();
674         _display.set_model (_model);
675 }
676
677 void
678 EditorRouteGroups::set_session (Session* s)
679 {
680         EditorComponent::set_session (s);
681
682         if (_session) {
683                 _session->route_group_added.connect (_session_connections, MISSING_INVALIDATOR, ui_bind (&EditorRouteGroups::add, this, _1), gui_context());
684                 _session->route_group_removed.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&EditorRouteGroups::groups_changed, this), gui_context());
685         }
686
687         groups_changed ();
688 }
689
690 struct CollectSorter {
691     bool operator () (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
692                 return a->order_key (N_ ("editor")) < b->order_key (N_ ("editor"));
693         }
694 };
695
696 /** Collect all members of a RouteGroup so that they are together in the Editor.
697  *  @param g Group to collect.
698  */
699 void
700 EditorRouteGroups::collect (RouteGroup* g)
701 {
702         boost::shared_ptr<RouteList> routes = g->route_list ();
703         routes->sort (CollectSorter ());
704         int const N = routes->size ();
705
706         RouteList::iterator i = routes->begin ();
707         TrackViewList::const_iterator j = _editor->get_track_views().begin();
708
709         int diff = 0;
710         int coll = -1;
711         while (i != routes->end() && j != _editor->get_track_views().end()) {
712
713                 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*j);
714                 if (rtv) {
715
716                         boost::shared_ptr<Route> r = rtv->route ();
717                         int const k = r->order_key (N_ ("editor"));
718
719                         if (*i == r) {
720
721                                 if (coll == -1) {
722                                         coll = k;
723                                         diff = N - 1;
724                                 } else {
725                                         --diff;
726                                 }
727
728                                 r->set_order_key (N_ ("editor"), coll);
729
730                                 ++coll;
731                                 ++i;
732
733                         } else {
734
735                                 r->set_order_key (N_ ("editor"), k + diff);
736
737                         }
738                 }
739
740                 ++j;
741         }
742
743         _editor->_routes->sync_order_keys ("");
744 }