merge with master, including manual merge conflict resolution
[ardour.git] / gtk2_ardour / editor_routes.cc
index 65db793bb32bf5509e92c46d6b4410e8819abc7b..bf629ea27dd54a533194abc7f257ec388757bc53 100644 (file)
 #include <cmath>
 #include <cassert>
 
+#include "pbd/unknown_type.h"
+#include "pbd/unwind.h"
+
+#include "ardour/debug.h"
+#include "ardour/route.h"
+#include "ardour/midi_track.h"
 #include "ardour/session.h"
 
+#include "gtkmm2ext/cell_renderer_pixbuf_multi.h"
+#include "gtkmm2ext/cell_renderer_pixbuf_toggle.h"
+#include "gtkmm2ext/treeutils.h"
+
 #include "editor.h"
 #include "keyboard.h"
 #include "ardour_ui.h"
 #include "gui_thread.h"
 #include "actions.h"
 #include "utils.h"
+#include "route_sorter.h"
 #include "editor_group_tabs.h"
 #include "editor_routes.h"
 
-#include "pbd/unknown_type.h"
-
-#include "ardour/route.h"
-#include "ardour/midi_track.h"
-
-#include "gtkmm2ext/cell_renderer_pixbuf_multi.h"
-#include "gtkmm2ext/cell_renderer_pixbuf_toggle.h"
-#include "gtkmm2ext/treeutils.h"
-
 #include "i18n.h"
 
 using namespace std;
@@ -57,13 +59,18 @@ using namespace Gtkmm2ext;
 using namespace Glib;
 using Gtkmm2ext::Keyboard;
 
+struct ColumnInfo {
+    int         index;
+    const char* label;
+    const char* tooltip;
+};
+
 EditorRoutes::EditorRoutes (Editor* e)
        : EditorComponent (e)
         , _ignore_reorder (false)
         , _no_redisplay (false)
-        , _redisplay_does_not_sync_order_keys (false)
-        , _redisplay_does_not_reset_order_keys (false)
-        ,_menu (0)
+        , _adding_routes (false)
+        , _menu (0)
         , old_focus (0)
         , selection_countdown (0)
         , name_editable (0)
@@ -79,10 +86,10 @@ EditorRoutes::EditorRoutes (Editor* e)
        // Record enable toggle
        CellRendererPixbufMulti* rec_col_renderer = manage (new CellRendererPixbufMulti());
 
-       rec_col_renderer->set_pixbuf (0, ::get_icon("act-disabled"));
-       rec_col_renderer->set_pixbuf (1, ::get_icon("rec-in-progress"));
-       rec_col_renderer->set_pixbuf (2, ::get_icon("rec-enabled"));
-       rec_col_renderer->set_pixbuf (3, ::get_icon("step-editing"));
+       rec_col_renderer->set_pixbuf (0, ::get_icon("record-normal-disabled"));
+       rec_col_renderer->set_pixbuf (1, ::get_icon("record-normal-in-progress"));
+       rec_col_renderer->set_pixbuf (2, ::get_icon("record-normal-enabled"));
+       rec_col_renderer->set_pixbuf (3, ::get_icon("record-step"));
        rec_col_renderer->signal_changed().connect (sigc::mem_fun (*this, &EditorRoutes::on_tv_rec_enable_changed));
 
        TreeViewColumn* rec_state_column = manage (new TreeViewColumn("R", *rec_col_renderer));
@@ -98,7 +105,7 @@ EditorRoutes::EditorRoutes (Editor* e)
        // MIDI Input Active
 
        CellRendererPixbufMulti* input_active_col_renderer = manage (new CellRendererPixbufMulti());
-       input_active_col_renderer->set_pixbuf (0, ::get_icon("act-disabled"));
+       input_active_col_renderer->set_pixbuf (0, ::get_icon("midi-input-inactive"));
        input_active_col_renderer->set_pixbuf (1, ::get_icon("midi-input-active"));
        input_active_col_renderer->signal_changed().connect (sigc::mem_fun (*this, &EditorRoutes::on_input_active_changed));
 
@@ -115,9 +122,9 @@ EditorRoutes::EditorRoutes (Editor* e)
        // Mute enable toggle
        CellRendererPixbufMulti* mute_col_renderer = manage (new CellRendererPixbufMulti());
 
-       mute_col_renderer->set_pixbuf (0, ::get_icon("mute-disabled"));
-       mute_col_renderer->set_pixbuf (1, ::get_icon("muted-by-others"));
-       mute_col_renderer->set_pixbuf (2, ::get_icon("mute-enabled"));
+       mute_col_renderer->set_pixbuf (Gtkmm2ext::Off, ::get_icon("mute-disabled"));
+       mute_col_renderer->set_pixbuf (Gtkmm2ext::ImplicitActive, ::get_icon("muted-by-others"));
+       mute_col_renderer->set_pixbuf (Gtkmm2ext::ExplicitActive, ::get_icon("mute-enabled"));
        mute_col_renderer->signal_changed().connect (sigc::mem_fun (*this, &EditorRoutes::on_tv_mute_enable_toggled));
 
        TreeViewColumn* mute_state_column = manage (new TreeViewColumn("M", *mute_col_renderer));
@@ -131,14 +138,15 @@ EditorRoutes::EditorRoutes (Editor* e)
        // Solo enable toggle
        CellRendererPixbufMulti* solo_col_renderer = manage (new CellRendererPixbufMulti());
 
-       solo_col_renderer->set_pixbuf (0, ::get_icon("solo-disabled"));
-       solo_col_renderer->set_pixbuf (1, ::get_icon("solo-enabled"));
-       solo_col_renderer->set_pixbuf (3, ::get_icon("soloed-by-others"));
+       solo_col_renderer->set_pixbuf (Gtkmm2ext::Off, ::get_icon("solo-disabled"));
+       solo_col_renderer->set_pixbuf (Gtkmm2ext::ExplicitActive, ::get_icon("solo-enabled"));
+       solo_col_renderer->set_pixbuf (Gtkmm2ext::ImplicitActive, ::get_icon("soloed-by-others"));
        solo_col_renderer->signal_changed().connect (sigc::mem_fun (*this, &EditorRoutes::on_tv_solo_enable_toggled));
 
        TreeViewColumn* solo_state_column = manage (new TreeViewColumn("S", *solo_col_renderer));
 
        solo_state_column->add_attribute(solo_col_renderer->property_state(), _columns.solo_state);
+       solo_state_column->add_attribute(solo_col_renderer->property_visible(), _columns.solo_visible);
        solo_state_column->set_sizing(TREE_VIEW_COLUMN_FIXED);
        solo_state_column->set_alignment(ALIGN_CENTER);
        solo_state_column->set_expand(false);
@@ -154,6 +162,7 @@ EditorRoutes::EditorRoutes (Editor* e)
        TreeViewColumn* solo_isolate_state_column = manage (new TreeViewColumn("SI", *solo_iso_renderer));
 
        solo_isolate_state_column->add_attribute(solo_iso_renderer->property_state(), _columns.solo_isolate_state);
+       solo_isolate_state_column->add_attribute(solo_iso_renderer->property_visible(), _columns.solo_visible);
        solo_isolate_state_column->set_sizing(TREE_VIEW_COLUMN_FIXED);
        solo_isolate_state_column->set_alignment(ALIGN_CENTER);
        solo_isolate_state_column->set_expand(false);
@@ -168,11 +177,16 @@ EditorRoutes::EditorRoutes (Editor* e)
 
        TreeViewColumn* solo_safe_state_column = manage (new TreeViewColumn(_("SS"), *solo_safe_renderer));
        solo_safe_state_column->add_attribute(solo_safe_renderer->property_state(), _columns.solo_safe_state);
+       solo_safe_state_column->add_attribute(solo_safe_renderer->property_visible(), _columns.solo_visible);
        solo_safe_state_column->set_sizing(TREE_VIEW_COLUMN_FIXED);
        solo_safe_state_column->set_alignment(ALIGN_CENTER);
        solo_safe_state_column->set_expand(false);
        solo_safe_state_column->set_fixed_width(column_width);
 
+        _name_column = _display.append_column ("", _columns.text) - 1;
+       _visible_column = _display.append_column ("", _columns.visible) - 1;
+       _active_column = _display.append_column ("", _columns.active) - 1;
+
        _display.append_column (*input_active_column);
        _display.append_column (*rec_state_column);
        _display.append_column (*mute_state_column);
@@ -180,14 +194,36 @@ EditorRoutes::EditorRoutes (Editor* e)
        _display.append_column (*solo_isolate_state_column);
        _display.append_column (*solo_safe_state_column);
 
-        _name_column = _display.append_column (_("Name"), _columns.text) - 1;
-       _visible_column = _display.append_column (_("V"), _columns.visible) - 1;
+
+       TreeViewColumn* col;
+       Gtk::Label* l;
+
+       ColumnInfo ci[] = {
+               { 0, _("Name"), _("Track/Bus Name") },
+               { 1, _("V"), _("Track/Bus visible ?") },
+               { 2, _("A"), _("Track/Bus active ?") },
+               { 3, _("I"), _("MIDI input enabled") },
+               { 4, _("R"), _("Record enabled") },
+               { 5, _("M"), _("Muted") },
+               { 6, _("S"), _("Soloed") },
+               { 7, _("SI"), _("Solo Isolated") },
+               { 8, _("SS"), _("Solo Safe (Locked)") },
+               { -1, 0, 0 }
+       };
+
+       for (int i = 0; ci[i].index >= 0; ++i) {
+               col = _display.get_column (ci[i].index);
+               l = manage (new Label (ci[i].label));
+               ARDOUR_UI::instance()->set_tip (*l, ci[i].tooltip);
+               col->set_widget (*l);
+               l->show ();
+       }
 
        _display.set_headers_visible (true);
-       _display.set_name ("TrackListDisplay");
        _display.get_selection()->set_mode (SELECTION_SINGLE);
        _display.get_selection()->set_select_function (sigc::mem_fun (*this, &EditorRoutes::selection_filter));
        _display.set_reorderable (true);
+       _display.set_name (X_("EditGroupList"));
        _display.set_rules_hint (true);
        _display.set_size_request (100, -1);
        _display.add_object_drag (_columns.route.index(), "routes");
@@ -222,6 +258,18 @@ EditorRoutes::EditorRoutes (Editor* e)
        visible_col->set_fixed_width(30);
        visible_col->set_alignment(ALIGN_CENTER);
 
+       CellRendererToggle* active_cell = dynamic_cast<CellRendererToggle*> (_display.get_column_cell_renderer (_active_column));
+
+       active_cell->property_activatable() = true;
+       active_cell->property_radio() = false;
+       active_cell->signal_toggled().connect (sigc::mem_fun (*this, &EditorRoutes::active_changed));
+
+       TreeViewColumn* active_col = dynamic_cast<TreeViewColumn*> (_display.get_column (_active_column));
+       active_col->set_expand (false);
+       active_col->set_sizing (TREE_VIEW_COLUMN_FIXED);
+       active_col->set_fixed_width (30);
+       active_col->set_alignment (ALIGN_CENTER);
+       
        _model->signal_row_deleted().connect (sigc::mem_fun (*this, &EditorRoutes::route_deleted));
        _model->signal_rows_reordered().connect (sigc::mem_fun (*this, &EditorRoutes::reordered));
 
@@ -236,7 +284,7 @@ EditorRoutes::EditorRoutes (Editor* e)
 
         _display.set_enable_search (false);
 
-       Route::SyncOrderKeys.connect (*this, MISSING_INVALIDATOR, ui_bind (&EditorRoutes::sync_order_keys, this, _1), gui_context());
+       Route::SyncOrderKeys.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::sync_treeview_from_order_keys, this, _1), gui_context());
 }
 
 bool
@@ -443,13 +491,17 @@ EditorRoutes::show_menu ()
 void
 EditorRoutes::redisplay ()
 {
-       if (_no_redisplay || !_session) {
+       if (_no_redisplay || !_session || _session->deletion_in_progress()) {
                return;
        }
 
        TreeModel::Children rows = _model->children();
        TreeModel::Children::iterator i;
        uint32_t position;
+
+       /* n will be the count of tracks plus children (updated by TimeAxisView::show_at),
+          so we will use that to know where to put things.
+       */
        int n;
 
        for (n = 0, position = 0, i = rows.begin(); i != rows.end(); ++i) {
@@ -461,28 +513,19 @@ EditorRoutes::redisplay ()
                        continue;
                }
 
-               if (!_redisplay_does_not_reset_order_keys) {
-                       /* this reorder is caused by user action, so reassign sort order keys
-                          to tracks.
-                       */
-                       route->set_order_key (N_ ("editor"), n);
-               }
-
-               bool visible = (*i)[_columns.visible];
+               bool visible = tv->marked_for_display ();
 
                /* show or hide the TimeAxisView */
                if (visible) {
-                       tv->set_marked_for_display (true);
                        position += tv->show_at (position, n, &_editor->edit_controls_vbox);
                        tv->clip_to_viewport ();
                } else {
-                       tv->set_visibility (false);
+                       tv->hide ();
                }
 
                n++;
        }
 
-
        /* whenever we go idle, update the track view list to reflect the new order.
           we can't do this here, because we could mess up something that is traversing
           the track order and has caused a redisplay of the list.
@@ -491,34 +534,33 @@ EditorRoutes::redisplay ()
 
         _editor->reset_controls_layout_height (position);
         _editor->reset_controls_layout_width ();
-       _editor->full_canvas_height = position + _editor->canvas_timebars_vsize;
-       _editor->vertical_adjustment.set_upper (_editor->full_canvas_height);
+       _editor->_full_canvas_height = position;
+       _editor->vertical_adjustment.set_upper (_editor->_full_canvas_height);
 
-       if ((_editor->vertical_adjustment.get_value() + _editor->_canvas_height) > _editor->vertical_adjustment.get_upper()) {
+       if ((_editor->vertical_adjustment.get_value() + _editor->_visible_canvas_height) > _editor->vertical_adjustment.get_upper()) {
                /*
                   We're increasing the size of the canvas while the bottom is visible.
                   We scroll down to keep in step with the controls layout.
                */
-               _editor->vertical_adjustment.set_value (_editor->full_canvas_height - _editor->_canvas_height);
-       }
-
-       if (!_redisplay_does_not_reset_order_keys && !_redisplay_does_not_sync_order_keys) {
-               _session->sync_order_keys (N_ ("editor"));
+               _editor->vertical_adjustment.set_value (_editor->_full_canvas_height - _editor->_visible_canvas_height);
        }
 }
 
 void
 EditorRoutes::route_deleted (Gtk::TreeModel::Path const &)
 {
-       if (!_session || _session->deletion_in_progress()) {
-               return;
-       }
+       /* this happens as the second step of a DnD within the treeview as well
+          as when a row/route is actually deleted.
+       */
+       DEBUG_TRACE (DEBUG::OrderKeys, "editor routes treeview row deleted\n");
+       sync_order_keys_from_treeview ();
+}
 
-        /* this could require an order reset & sync */
-       _session->set_remote_control_ids();
-       _ignore_reorder = true;
-       redisplay ();
-       _ignore_reorder = false;
+void
+EditorRoutes::reordered (TreeModel::Path const &, TreeModel::iterator const &, int* /*what*/)
+{
+       DEBUG_TRACE (DEBUG::OrderKeys, "editor routes treeview reordered\n");
+       sync_order_keys_from_treeview ();
 }
 
 void
@@ -534,24 +576,37 @@ EditorRoutes::visible_changed (std::string const & path)
                TimeAxisView* tv = (*iter)[_columns.tv];
                if (tv) {
                        bool visible = (*iter)[_columns.visible];
-                       (*iter)[_columns.visible] = !visible;
+
+                       if (tv->set_marked_for_display (!visible)) {
+                               update_visibility ();
+                       }
                }
        }
+}
 
-       _redisplay_does_not_reset_order_keys = true;
-       _session->set_remote_control_ids();
-       redisplay ();
-       _redisplay_does_not_reset_order_keys = false;
+void
+EditorRoutes::active_changed (std::string const & path)
+{
+       if (_session && _session->deletion_in_progress ()) {
+               return;
+       }
+
+       Gtk::TreeModel::Row row = *_model->get_iter (path);
+       boost::shared_ptr<Route> route = row[_columns.route];
+       bool const active = row[_columns.active];
+       route->set_active (!active, this);
 }
 
 void
 EditorRoutes::routes_added (list<RouteTimeAxisView*> routes)
 {
        TreeModel::Row row;
+       PBD::Unwinder<bool> at (_adding_routes, true);
 
-       _redisplay_does_not_sync_order_keys = true;
        suspend_redisplay ();
 
+       _display.set_model (Glib::RefPtr<ListStore>());
+
        for (list<RouteTimeAxisView*>::iterator x = routes.begin(); x != routes.end(); ++x) {
 
                boost::shared_ptr<MidiTrack> midi_trk = boost::dynamic_pointer_cast<MidiTrack> ((*x)->route());
@@ -560,6 +615,7 @@ EditorRoutes::routes_added (list<RouteTimeAxisView*> routes)
 
                row[_columns.text] = (*x)->route()->name();
                row[_columns.visible] = (*x)->marked_for_display();
+               row[_columns.active] = (*x)->route()->active ();
                row[_columns.tv] = *x;
                row[_columns.route] = (*x)->route ();
                row[_columns.is_track] = (boost::dynamic_pointer_cast<Track> ((*x)->route()) != 0);
@@ -572,25 +628,17 @@ EditorRoutes::routes_added (list<RouteTimeAxisView*> routes)
                        row[_columns.is_midi] = false;
                }
 
-               row[_columns.mute_state] = (*x)->route()->muted();
-               row[_columns.solo_state] = RouteUI::solo_visual_state ((*x)->route());
+               row[_columns.mute_state] = (*x)->route()->muted() ? Gtkmm2ext::ExplicitActive : Gtkmm2ext::Off;
+               row[_columns.solo_state] = RouteUI::solo_active_state ((*x)->route());
+               row[_columns.solo_visible] = !(*x)->route()->is_master ();
                row[_columns.solo_isolate_state] = (*x)->route()->solo_isolated();
                row[_columns.solo_safe_state] = (*x)->route()->solo_safe();
                row[_columns.name_editable] = true;
 
-               _ignore_reorder = true;
-
-               /* added a new fresh one at the end */
-               if ((*x)->route()->order_key (N_ ("editor")) == -1) {
-                       (*x)->route()->set_order_key (N_ ("editor"), _model->children().size()-1);
-               }
-
-               _ignore_reorder = false;
-
                boost::weak_ptr<Route> wr ((*x)->route());
 
-               (*x)->route()->gui_changed.connect (*this, MISSING_INVALIDATOR, ui_bind (&EditorRoutes::handle_gui_changes, this, _1, _2), gui_context());
-               (*x)->route()->PropertyChanged.connect (*this, MISSING_INVALIDATOR, ui_bind (&EditorRoutes::route_property_changed, this, _1, wr), gui_context());
+               (*x)->route()->gui_changed.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::handle_gui_changes, this, _1, _2), gui_context());
+               (*x)->route()->PropertyChanged.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::route_property_changed, this, _1, wr), gui_context());
 
                if ((*x)->is_track()) {
                        boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track> ((*x)->route());
@@ -604,10 +652,12 @@ EditorRoutes::routes_added (list<RouteTimeAxisView*> routes)
                }
 
                (*x)->route()->mute_changed.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::update_mute_display, this), gui_context());
-               (*x)->route()->solo_changed.connect (*this, MISSING_INVALIDATOR, ui_bind (&EditorRoutes::update_solo_display, this, _1), gui_context());
-               (*x)->route()->listen_changed.connect (*this, MISSING_INVALIDATOR, ui_bind (&EditorRoutes::update_solo_display, this, _1), gui_context());
+               (*x)->route()->solo_changed.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::update_solo_display, this, _1), gui_context());
+               (*x)->route()->listen_changed.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::update_solo_display, this, _1), gui_context());
                (*x)->route()->solo_isolated_changed.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::update_solo_isolate_display, this), gui_context());
                (*x)->route()->solo_safe_changed.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::update_solo_safe_display, this), gui_context());
+               (*x)->route()->active_changed.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::update_active_display, this), gui_context ());
+
        }
 
        update_rec_display ();
@@ -616,14 +666,22 @@ EditorRoutes::routes_added (list<RouteTimeAxisView*> routes)
        update_solo_isolate_display ();
        update_solo_safe_display ();
        update_input_active_display ();
+       update_active_display ();
+
        resume_redisplay ();
-       _redisplay_does_not_sync_order_keys = false;
+       _display.set_model (_model);
+
+       /* now update route order keys from the treeview/track display order */
+
+       sync_order_keys_from_treeview ();
 }
 
 void
 EditorRoutes::handle_gui_changes (string const & what, void*)
 {
-       ENSURE_GUI_THREAD (*this, &EditorRoutes::handle_gui_changes, what, src)
+       if (_adding_routes) {
+               return;
+       }
 
        if (what == "track_height") {
                /* Optional :make tracks change height while it happens, instead
@@ -646,12 +704,6 @@ EditorRoutes::route_removed (TimeAxisView *tv)
        TreeModel::Children rows = _model->children();
        TreeModel::Children::iterator ri;
 
-       /* the core model has changed, there is no need to sync
-          view orders.
-       */
-
-       _redisplay_does_not_sync_order_keys = true;
-
        for (ri = rows.begin(); ri != rows.end(); ++ri) {
                if ((*ri)[_columns.tv] == tv) {
                        _model->erase (ri);
@@ -659,7 +711,9 @@ EditorRoutes::route_removed (TimeAxisView *tv)
                }
        }
 
-       _redisplay_does_not_sync_order_keys = false;
+       /* the deleted signal for the treeview/model will take 
+          care of any updates.
+       */
 }
 
 void
@@ -689,6 +743,18 @@ EditorRoutes::route_property_changed (const PropertyChange& what_changed, boost:
        }
 }
 
+void
+EditorRoutes::update_active_display ()
+{
+       TreeModel::Children rows = _model->children();
+       TreeModel::Children::iterator i;
+
+       for (i = rows.begin(); i != rows.end(); ++i) {
+               boost::shared_ptr<Route> route = (*i)[_columns.route];
+               (*i)[_columns.active] = route->active ();
+       }
+}
+
 void
 EditorRoutes::update_visibility ()
 {
@@ -700,9 +766,13 @@ EditorRoutes::update_visibility ()
        for (i = rows.begin(); i != rows.end(); ++i) {
                TimeAxisView *tv = (*i)[_columns.tv];
                (*i)[_columns.visible] = tv->marked_for_display ();
-               cerr << "marked " << tv->name() << " for display = " << tv->marked_for_display() << endl;
        }
 
+       /* force route order keys catch up with visibility changes
+        */
+
+       sync_order_keys_from_treeview ();
+
        resume_redisplay ();
 }
 
@@ -714,12 +784,12 @@ EditorRoutes::hide_track_in_display (TimeAxisView& tv)
 
        for (i = rows.begin(); i != rows.end(); ++i) {
                if ((*i)[_columns.tv] == &tv) {
+                       tv.set_marked_for_display (false);
                        (*i)[_columns.visible] = false;
+                       redisplay ();
                        break;
                }
        }
-
-       redisplay ();
 }
 
 void
@@ -728,66 +798,212 @@ EditorRoutes::show_track_in_display (TimeAxisView& tv)
        TreeModel::Children rows = _model->children();
        TreeModel::Children::iterator i;
 
+
        for (i = rows.begin(); i != rows.end(); ++i) {
                if ((*i)[_columns.tv] == &tv) {
+                       tv.set_marked_for_display (true);
                        (*i)[_columns.visible] = true;
+                       redisplay ();
                        break;
                }
        }
-
-       redisplay ();
 }
 
 void
-EditorRoutes::reordered (TreeModel::Path const &, TreeModel::iterator const &, int* /*what*/)
+EditorRoutes::reset_remote_control_ids ()
 {
-       redisplay ();
+       if (Config->get_remote_model() != EditorOrdered || !_session || _session->deletion_in_progress()) {
+               return;
+       }
+
+       TreeModel::Children rows = _model->children();
+       
+       if (rows.empty()) {
+               return;
+       }
+
+       
+       DEBUG_TRACE (DEBUG::OrderKeys, "editor reset remote control ids\n");
+
+       TreeModel::Children::iterator ri;
+       bool rid_change = false;
+       uint32_t rid = 1;
+       uint32_t invisible_key = UINT32_MAX;
+
+       for (ri = rows.begin(); ri != rows.end(); ++ri) {
+
+               boost::shared_ptr<Route> route = (*ri)[_columns.route];
+               bool visible = (*ri)[_columns.visible];
+
+
+               if (!route->is_master() && !route->is_monitor()) {
+
+                       uint32_t new_rid = (visible ? rid : invisible_key--);
+
+                       if (new_rid != route->remote_control_id()) {
+                               route->set_remote_control_id_from_order_key (EditorSort, new_rid);      
+                               rid_change = true;
+                       }
+                       
+                       if (visible) {
+                               rid++;
+                       }
+
+               }
+       }
+
+       if (rid_change) {
+               /* tell the world that we changed the remote control IDs */
+               _session->notify_remote_id_change ();
+       }
 }
 
-/** If src != "editor", take editor order keys from each route and use them to rearrange the
- *  route list so that the visual arrangement of routes matches the order keys from the routes.
- */
+
 void
-EditorRoutes::sync_order_keys (string const & src)
+EditorRoutes::sync_order_keys_from_treeview ()
 {
-       map<int, int> new_order;
-       TreeModel::Children rows = _model->children();
-       TreeModel::Children::iterator ri;
+       if (_ignore_reorder || !_session || _session->deletion_in_progress()) {
+               return;
+       }
 
-       if (src == N_ ("editor") || !_session || (_session->state_of_the_state() & (Session::Loading|Session::Deletion)) || rows.empty()) {
+       TreeModel::Children rows = _model->children();
+       
+       if (rows.empty()) {
                return;
        }
 
+       
+       DEBUG_TRACE (DEBUG::OrderKeys, "editor sync order keys from treeview\n");
+
+       TreeModel::Children::iterator ri;
        bool changed = false;
-       int order;
+       bool rid_change = false;
+       uint32_t order = 0;
+       uint32_t rid = 1;
+       uint32_t invisible_key = UINT32_MAX;
+
+       for (ri = rows.begin(); ri != rows.end(); ++ri) {
 
-       for (order = 0, ri = rows.begin(); ri != rows.end(); ++ri, ++order) {
                boost::shared_ptr<Route> route = (*ri)[_columns.route];
+               bool visible = (*ri)[_columns.visible];
 
-               int const old_key = order;
-               int const new_key = route->order_key (N_ ("editor"));
+               uint32_t old_key = route->order_key (EditorSort);
 
-               new_order[new_key] = old_key;
+               if (order != old_key) {
+                       route->set_order_key (EditorSort, order);
 
-               if (new_key != old_key) {
                        changed = true;
                }
-       }
 
-       if (changed) {
-               _redisplay_does_not_reset_order_keys = true;
+               if ((Config->get_remote_model() == EditorOrdered) && !route->is_master() && !route->is_monitor()) {
+
+                       uint32_t new_rid = (visible ? rid : invisible_key--);
+
+                       if (new_rid != route->remote_control_id()) {
+                               route->set_remote_control_id_from_order_key (EditorSort, new_rid);      
+                               rid_change = true;
+                       }
+                       
+                       if (visible) {
+                               rid++;
+                       }
 
-               /* `compact' new_order into a vector */
-               vector<int> co;
-               for (map<int, int>::const_iterator i = new_order.begin(); i != new_order.end(); ++i) {
-                       co.push_back (i->second);
                }
 
-               _model->reorder (co);
-               _redisplay_does_not_reset_order_keys = false;
+               ++order;
+       }
+       
+       if (changed) {
+               /* tell the world that we changed the editor sort keys */
+               _session->sync_order_keys (EditorSort);
+       }
+
+       if (rid_change) {
+               /* tell the world that we changed the remote control IDs */
+               _session->notify_remote_id_change ();
        }
 }
 
+void
+EditorRoutes::sync_treeview_from_order_keys (RouteSortOrderKey src)
+{
+       /* Some route order key(s) for `src' has been changed, make sure that 
+          we update out tree/list model and GUI to reflect the change.
+       */
+
+       if (!_session || _session->deletion_in_progress()) {
+               return;
+       }
+
+       DEBUG_TRACE (DEBUG::OrderKeys, string_compose ("editor sync model from order keys, src = %1\n", enum_2_string (src)));
+
+       if (src == MixerSort) {
+
+               if (!Config->get_sync_all_route_ordering()) {
+                       /* mixer sort keys changed - we don't care */
+                       return;
+               }
+
+               DEBUG_TRACE (DEBUG::OrderKeys, "reset editor order key to match mixer\n");
+
+               /* mixer sort keys were changed, update the editor sort
+                * keys since "sync mixer+editor order" is enabled.
+                */
+
+               boost::shared_ptr<RouteList> r = _session->get_routes ();
+               
+               for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
+                       (*i)->sync_order_keys (src);
+               }
+       }
+
+       /* we could get here after either a change in the Mixer or Editor sort
+        * order, but either way, the mixer order keys reflect the intended
+        * order for the GUI, so reorder the treeview model to match it.
+        */
+
+       vector<int> neworder;
+       TreeModel::Children rows = _model->children();
+       uint32_t old_order = 0;
+       bool changed = false;
+
+       if (rows.empty()) {
+               return;
+       }
+
+       OrderKeySortedRoutes sorted_routes;
+
+       for (TreeModel::Children::iterator ri = rows.begin(); ri != rows.end(); ++ri, ++old_order) {
+               boost::shared_ptr<Route> route = (*ri)[_columns.route];
+               sorted_routes.push_back (RoutePlusOrderKey (route, old_order, route->order_key (EditorSort)));
+       }
+
+       SortByNewDisplayOrder cmp;
+
+       sort (sorted_routes.begin(), sorted_routes.end(), cmp);
+       neworder.assign (sorted_routes.size(), 0);
+
+       uint32_t n = 0;
+       
+       for (OrderKeySortedRoutes::iterator sr = sorted_routes.begin(); sr != sorted_routes.end(); ++sr, ++n) {
+
+               neworder[n] = sr->old_display_order;
+
+               if (sr->old_display_order != n) {
+                       changed = true;
+               }
+
+               DEBUG_TRACE (DEBUG::OrderKeys, string_compose ("EDITOR change order for %1 from %2 to %3\n",
+                                                              sr->route->name(), sr->old_display_order, n));
+       }
+
+       if (changed) {
+               Unwinder<bool> uw (_ignore_reorder, true);
+               _model->reorder (neworder);
+       }
+
+       redisplay ();
+}
 
 void
 EditorRoutes::hide_all_tracks (bool /*with_select*/)
@@ -835,9 +1051,15 @@ EditorRoutes::set_all_tracks_visibility (bool yn)
                        continue;
                }
 
+               tv->set_marked_for_display (yn);
                (*i)[_columns.visible] = yn;
        }
 
+       /* force route order keys catch up with visibility changes
+        */
+
+       sync_order_keys_from_treeview ();
+
        resume_redisplay ();
 }
 
@@ -895,6 +1117,11 @@ EditorRoutes::set_all_audio_midi_visibility (int tracks, bool yn)
                }
        }
 
+       /* force route order keys catch up with visibility changes
+        */
+
+       sync_order_keys_from_treeview ();
+
        resume_redisplay ();
 }
 
@@ -980,10 +1207,12 @@ EditorRoutes::key_press (GdkEventKey* ev)
                 break;
 
         case 's':
-               if (Config->get_solo_control_is_listen_control()) {
-                       _session->set_listen (rl, !rl->front()->listening_via_monitor(), Session::rt_cleanup);
-               } else {
-                       _session->set_solo (rl, !rl->front()->self_soloed(), Session::rt_cleanup);
+                if (get_relevant_routes (rl)) {
+                       if (Config->get_solo_control_is_listen_control()) {
+                               _session->set_listen (rl, !rl->front()->listening_via_monitor(), Session::rt_cleanup);
+                       } else {
+                               _session->set_solo (rl, !rl->front()->self_soloed(), Session::rt_cleanup);
+                       }
                }
                 return true;
                 break;
@@ -1052,15 +1281,21 @@ EditorRoutes::button_press (GdkEventButton* ev)
                return true;
        }
 
-       //Scroll editor canvas to selected track
-       if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
+       TreeModel::Path path;
+       TreeViewColumn *tvc;
+       int cell_x;
+       int cell_y;
 
-               TreeModel::Path path;
-               TreeViewColumn *tvc;
-               int cell_x;
-               int cell_y;
+       if (!_display.get_path_at_pos ((int) ev->x, (int) ev->y, path, tvc, cell_x, cell_y)) {
+               /* cancel selection */
+               _display.get_selection()->unselect_all ();
+               /* end any editing by grabbing focus */
+               _display.grab_focus ();
+               return true;
+       }
 
-               _display.get_path_at_pos ((int) ev->x, (int) ev->y, path, tvc, cell_x, cell_y);
+       //Scroll editor canvas to selected track
+       if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
 
                // Get the model row.
                Gtk::TreeModel::Row row = *_model->get_iter (path);
@@ -1070,8 +1305,8 @@ EditorRoutes::button_press (GdkEventButton* ev)
                int y_pos = tv->y_position();
 
                //Clamp the y pos so that we do not extend beyond the canvas full height.
-               if (_editor->full_canvas_height - y_pos < _editor->_canvas_height){
-                   y_pos = _editor->full_canvas_height - _editor->_canvas_height;
+               if (_editor->_full_canvas_height - y_pos < _editor->_visible_canvas_height){
+                   y_pos = _editor->_full_canvas_height - _editor->_visible_canvas_height;
                }
 
                //Only scroll to if the track is visible
@@ -1099,8 +1334,14 @@ EditorRoutes::selection_filter (Glib::RefPtr<TreeModel> const &, TreeModel::Path
 
 struct EditorOrderRouteSorter {
     bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
-           /* use of ">" forces the correct sort order */
-           return a->order_key (N_ ("editor")) < b->order_key (N_ ("editor"));
+           if (a->is_master()) {
+                   /* master before everything else */
+                   return true;
+           } else if (b->is_master()) {
+                   /* everything else before master */
+                   return false;
+           }
+           return a->order_key (EditorSort) < b->order_key (EditorSort);
     }
 };
 
@@ -1116,49 +1357,32 @@ EditorRoutes::initial_display ()
        }
 
        boost::shared_ptr<RouteList> routes = _session->get_routes();
-       RouteList r (*routes);
-       EditorOrderRouteSorter sorter;
-
-       r.sort (sorter);
-       _editor->handle_new_route (r);
-
-       /* don't show master bus in a new session */
 
        if (ARDOUR_UI::instance()->session_is_new ()) {
 
-               TreeModel::Children rows = _model->children();
-               TreeModel::Children::iterator i;
+               /* new session: stamp all routes with the right editor order
+                * key
+                */
 
-               _no_redisplay = true;
-
-               for (i = rows.begin(); i != rows.end(); ++i) {
-
-                       TimeAxisView *tv =  (*i)[_columns.tv];
-                       RouteTimeAxisView *rtv;
+               _editor->add_routes (*(routes.get()));
+               
+       } else {
 
-                       if ((rtv = dynamic_cast<RouteTimeAxisView*>(tv)) != 0) {
-                               if (rtv->route()->is_master()) {
-                                       _display.get_selection()->unselect (i);
-                               }
-                       }
-               }
+               /* existing session: sort a copy of the route list by
+                * editor-order and add its contents to the display.
+                */
 
-               _no_redisplay = false;
-               redisplay ();
+               RouteList r (*routes);
+               EditorOrderRouteSorter sorter;
+               
+               r.sort (sorter);
+               _editor->add_routes (r);
+               
        }
 
        resume_redisplay ();
 }
 
-void
-EditorRoutes::track_list_reorder (Gtk::TreeModel::Path const &, Gtk::TreeModel::iterator const &, int* /*new_order*/)
-{
-       _redisplay_does_not_sync_order_keys = true;
-       _session->set_remote_control_ids();
-       redisplay ();
-       _redisplay_does_not_sync_order_keys = false;
-}
-
 void
 EditorRoutes::display_drag_data_received (const RefPtr<Gdk::DragContext>& context,
                                             int x, int y,
@@ -1277,12 +1501,26 @@ EditorRoutes::move_selected_tracks (bool up)
        }
 
        for (leading = view_routes.begin(); leading != view_routes.end(); ++leading) {
-               neworder.push_back (leading->second->order_key (N_ ("editor")));
+               uint32_t order = leading->second->order_key (EditorSort);
+               neworder.push_back (order);
        }
 
-       _model->reorder (neworder);
+#ifndef NDEBUG
+       DEBUG_TRACE (DEBUG::OrderKeys, "New order after moving tracks:\n");
+       for (vector<int>::iterator i = neworder.begin(); i != neworder.end(); ++i) {
+               DEBUG_TRACE (DEBUG::OrderKeys, string_compose ("\t%1\n", *i));
+       }
+       DEBUG_TRACE (DEBUG::OrderKeys, "-------\n");
+
+       for (vector<int>::iterator i = neworder.begin(); i != neworder.end(); ++i) {
+               if (*i >= (int) neworder.size()) {
+                       cerr << "Trying to move something to " << *i << " of " << neworder.size() << endl;
+               }
+               assert (*i < (int) neworder.size ());
+       }
+#endif 
 
-       _session->sync_order_keys (N_ ("editor"));
+       _model->reorder (neworder);
 }
 
 void
@@ -1341,7 +1579,7 @@ EditorRoutes::update_mute_display ()
 
        for (i = rows.begin(); i != rows.end(); ++i) {
                boost::shared_ptr<Route> route = (*i)[_columns.route];
-               (*i)[_columns.mute_state] = RouteUI::mute_visual_state (_session, route);
+               (*i)[_columns.mute_state] = RouteUI::mute_active_state (_session, route);
        }
 }
 
@@ -1353,7 +1591,7 @@ EditorRoutes::update_solo_display (bool /* selfsoloed */)
 
        for (i = rows.begin(); i != rows.end(); ++i) {
                boost::shared_ptr<Route> route = (*i)[_columns.route];
-               (*i)[_columns.solo_state] = RouteUI::solo_visual_state (route);
+               (*i)[_columns.solo_state] = RouteUI::solo_active_state (route);
        }
 }
 
@@ -1365,7 +1603,7 @@ EditorRoutes::update_solo_isolate_display ()
 
        for (i = rows.begin(); i != rows.end(); ++i) {
                boost::shared_ptr<Route> route = (*i)[_columns.route];
-               (*i)[_columns.solo_isolate_state] = RouteUI::solo_isolate_visual_state (route) > 0 ? 1 : 0;
+               (*i)[_columns.solo_isolate_state] = RouteUI::solo_isolate_active_state (route) ? 1 : 0;
        }
 }
 
@@ -1377,7 +1615,7 @@ EditorRoutes::update_solo_safe_display ()
 
        for (i = rows.begin(); i != rows.end(); ++i) {
                boost::shared_ptr<Route> route = (*i)[_columns.route];
-               (*i)[_columns.solo_safe_state] = RouteUI::solo_safe_visual_state (route) > 0 ? 1 : 0;
+               (*i)[_columns.solo_safe_state] = RouteUI::solo_safe_active_state (route) ? 1 : 0;
        }
 }
 
@@ -1461,3 +1699,4 @@ EditorRoutes::show_tracks_with_regions_at_playhead ()
 
        resume_redisplay ();
 }
+