Separate selection operations into their own temporary history mechanism.
[ardour.git] / gtk2_ardour / selection.cc
index 6465bb4d44592d1ecd2748c71bdf6d9ddddc7bd7..6d07564f2cb276c9b6920af188f8ca0f386ce493 100644 (file)
@@ -160,9 +160,6 @@ Selection::clear_regions ()
        if (!regions.empty()) {
                regions.clear_all ();
                RegionsChanged();
-               if (Config->get_link_region_and_track_selection()) {
-                       clear_tracks ();
-               }
        }
 }
 
@@ -176,6 +173,10 @@ Selection::clear_midi_notes ()
                midi_notes.clear ();
                MidiNotesChanged ();
        }
+
+       /* The note selection is actually stored in MidiRegionView, emit signal to
+          tell them to clear their selection. */
+       ClearMidiNoteSelection();  /* EMIT SIGNAL */
 }
 
 void
@@ -226,6 +227,7 @@ void
 Selection::toggle (boost::shared_ptr<Playlist> pl)
 {
        clear_time();  //enforce object/range exclusivity
+       clear_tracks();  //enforce object/track exclusivity
        
        PlaylistSelection::iterator i;
 
@@ -269,6 +271,7 @@ void
 Selection::toggle (const MidiNoteSelection& midi_note_list)
 {
        clear_time();  //enforce object/range exclusivity
+       clear_tracks();  //enforce object/track exclusivity
 
        for (MidiNoteSelection::const_iterator i = midi_note_list.begin(); i != midi_note_list.end(); ++i) {
                toggle ((*i));
@@ -296,6 +299,7 @@ void
 Selection::toggle (RegionView* r)
 {
        clear_time();  //enforce object/range exclusivity
+       clear_tracks();  //enforce object/track exclusivity
        
        RegionSelection::iterator i;
 
@@ -312,6 +316,7 @@ void
 Selection::toggle (MidiRegionView* mrv)
 {
        clear_time();   //enforce object/range exclusivity
+       clear_tracks();  //enforce object/track exclusivity
 
        MidiRegionSelection::iterator i;
 
@@ -328,6 +333,7 @@ void
 Selection::toggle (vector<RegionView*>& r)
 {
        clear_time();  //enforce object/range exclusivity
+       clear_tracks();  //enforce object/track exclusivity
 
        RegionSelection::iterator i;
 
@@ -364,6 +370,7 @@ void
 Selection::add (boost::shared_ptr<Playlist> pl)
 {
        clear_time();  //enforce object/range exclusivity
+       clear_tracks();  //enforce object/track exclusivity
        
        if (find (playlists.begin(), playlists.end(), pl) == playlists.end()) {
                pl->use ();
@@ -376,6 +383,7 @@ void
 Selection::add (const list<boost::shared_ptr<Playlist> >& pllist)
 {
        clear_time();  //enforce object/range exclusivity
+       clear_tracks();  //enforce object/track exclusivity
        
        bool changed = false;
 
@@ -395,6 +403,8 @@ Selection::add (const list<boost::shared_ptr<Playlist> >& pllist)
 void
 Selection::add (const TrackViewList& track_list)
 {
+       clear_objects();  //enforce object/range exclusivity
+
        TrackViewList added = tracks.add (track_list);
 
        if (!added.empty()) {
@@ -410,6 +420,8 @@ Selection::add (const TrackViewList& track_list)
 void
 Selection::add (TimeAxisView* track)
 {
+       clear_objects();  //enforce object/range exclusivity
+
        TrackViewList tr;
        track->set_selected (true);
        tr.push_back (track);
@@ -420,6 +432,7 @@ void
 Selection::add (const MidiNoteSelection& midi_list)
 {
        clear_time();  //enforce object/range exclusivity
+       clear_tracks();  //enforce object/track exclusivity
 
        const MidiNoteSelection::const_iterator b = midi_list.begin();
        const MidiNoteSelection::const_iterator e = midi_list.end();
@@ -445,6 +458,7 @@ void
 Selection::add (vector<RegionView*>& v)
 {
        clear_time();  //enforce object/range exclusivity
+       clear_tracks();  //enforce object/track exclusivity
 
        /* XXX This method or the add (const RegionSelection&) needs to go
         */
@@ -454,9 +468,6 @@ Selection::add (vector<RegionView*>& v)
        for (vector<RegionView*>::iterator i = v.begin(); i != v.end(); ++i) {
                if (find (regions.begin(), regions.end(), (*i)) == regions.end()) {
                        changed = regions.add ((*i));
-                       if (Config->get_link_region_and_track_selection() && changed) {
-                               add (&(*i)->get_time_axis_view());
-                       }
                }
        }
 
@@ -469,6 +480,7 @@ void
 Selection::add (const RegionSelection& rs)
 {
        clear_time();  //enforce object/range exclusivity
+       clear_tracks();  //enforce object/track exclusivity
 
        /* XXX This method or the add (const vector<RegionView*>&) needs to go
         */
@@ -478,9 +490,6 @@ Selection::add (const RegionSelection& rs)
        for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
                if (find (regions.begin(), regions.end(), (*i)) == regions.end()) {
                        changed = regions.add ((*i));
-                       if (Config->get_link_region_and_track_selection() && changed) {
-                               add (&(*i)->get_time_axis_view());
-                       }
                }
        }
 
@@ -493,15 +502,13 @@ void
 Selection::add (RegionView* r)
 {
        clear_time();  //enforce object/range exclusivity
+       clear_tracks();  //enforce object/track exclusivity
 
        if (find (regions.begin(), regions.end(), r) == regions.end()) {
                bool changed = regions.add (r);
-                if (Config->get_link_region_and_track_selection() && changed) {
-                        add (&r->get_time_axis_view());
-                }
-                if (changed) {
-                        RegionsChanged ();
-                }
+        if (changed) {
+            RegionsChanged ();
+        }
        }
 }
 
@@ -509,15 +516,11 @@ void
 Selection::add (MidiRegionView* mrv)
 {
        clear_time();  //enforce object/range exclusivity
+       clear_tracks();  //enforce object/track exclusivity
 
        if (find (midi_regions.begin(), midi_regions.end(), mrv) == midi_regions.end()) {
                midi_regions.push_back (mrv);
                /* XXX should we do this? */
-#if 0
-               if (Config->get_link_region_and_track_selection()) {
-                       add (&mrv->get_time_axis_view());
-               }
-#endif
                MidiRegionsChanged ();
        }
 }
@@ -581,6 +584,7 @@ void
 Selection::add (boost::shared_ptr<Evoral::ControlList> cl)
 {
        clear_time();  //enforce object/range exclusivity
+       clear_tracks();  //enforce object/track exclusivity
 
        boost::shared_ptr<ARDOUR::AutomationList> al
                = boost::dynamic_pointer_cast<ARDOUR::AutomationList>(cl);
@@ -707,10 +711,6 @@ Selection::remove (RegionView* r)
        if (regions.remove (r)) {
                RegionsChanged ();
        }
-
-       if (Config->get_link_region_and_track_selection() && !regions.involves (r->get_time_axis_view())) {
-               remove (&r->get_time_axis_view());
-       }
 }
 
 void
@@ -722,13 +722,6 @@ Selection::remove (MidiRegionView* mrv)
                midi_regions.erase (x);
                MidiRegionsChanged ();
        }
-
-#if 0
-       /* XXX fix this up ? */
-       if (Config->get_link_region_and_track_selection() && !regions.involves (r->get_time_axis_view())) {
-               remove (&r->get_time_axis_view());
-       }
-#endif
 }
 
 
@@ -767,6 +760,7 @@ Selection::remove (boost::shared_ptr<ARDOUR::AutomationList> ac)
 void
 Selection::set (TimeAxisView* track)
 {
+       clear_objects();  //enforce object/range exclusivity
        clear_tracks ();
        add (track);
 }
@@ -774,6 +768,7 @@ Selection::set (TimeAxisView* track)
 void
 Selection::set (const TrackViewList& track_list)
 {
+       clear_objects();  //enforce object/range exclusivity
        clear_tracks ();
        add (track_list);
 }
@@ -782,6 +777,7 @@ void
 Selection::set (const MidiNoteSelection& midi_list)
 {
        clear_time ();  //enforce region/object exclusivity
+       clear_tracks();  //enforce object/track exclusivity
        clear_objects ();
        add (midi_list);
 }
@@ -790,6 +786,7 @@ void
 Selection::set (boost::shared_ptr<Playlist> playlist)
 {
        clear_time ();  //enforce region/object exclusivity
+       clear_tracks();  //enforce object/track exclusivity
        clear_objects ();
        add (playlist);
 }
@@ -806,6 +803,7 @@ void
 Selection::set (const RegionSelection& rs)
 {
        clear_time();  //enforce region/object exclusivity
+       clear_tracks();  //enforce object/track exclusivity
        clear_objects();
        regions = rs;
        RegionsChanged(); /* EMIT SIGNAL */
@@ -815,44 +813,27 @@ void
 Selection::set (MidiRegionView* mrv)
 {
        clear_time();  //enforce region/object exclusivity
+       clear_tracks();  //enforce object/track exclusivity
        clear_objects ();
        add (mrv);
 }
 
 void
-Selection::set (RegionView* r, bool also_clear_tracks)
+Selection::set (RegionView* r, bool /*also_clear_tracks*/)
 {
        clear_time();  //enforce region/object exclusivity
+       clear_tracks();  //enforce object/track exclusivity
        clear_objects ();
-       if (also_clear_tracks && !Config->get_link_region_and_track_selection()) {
-               /* clear_regions() will have done this if the link preference
-                * is enabled
-                */
-               clear_tracks ();
-       }
        add (r);
 }
 
 void
 Selection::set (vector<RegionView*>& v)
 {
-       bool had_regions = !regions.empty();
-
        clear_time();  //enforce region/object exclusivity
+       clear_tracks();  //enforce object/track exclusivity
        clear_objects();
 
-       if (Config->get_link_region_and_track_selection()) {
-               if (had_regions) {
-                       /* there were regions before, so we're changing the
-                        * region selection (likely), thus link region/track
-                        * selection. relevant tracks will get selected
-                        * as we ::add() below.
-                        */
-                       clear_tracks ();
-                       // make sure to deselect any automation selections
-                       clear_points();
-               }
-       }
        add (v);
 }
 
@@ -922,6 +903,7 @@ void
 Selection::set (boost::shared_ptr<Evoral::ControlList> ac)
 {
        clear_time();  //enforce region/object exclusivity
+       clear_tracks();  //enforce object/track exclusivity
        clear_objects();
        
        add (ac);
@@ -973,13 +955,14 @@ Selection::empty (bool internal_selection)
           as a cut buffer.
        */
 
-       return object_level_empty && midi_notes.empty();
+       return object_level_empty && midi_notes.empty() && points.empty();
 }
 
 void
 Selection::toggle (ControlPoint* cp)
 {
        clear_time();  //enforce region/object exclusivity
+       clear_tracks();  //enforce object/track exclusivity
 
        cp->set_selected (!cp->get_selected ());
        PointSelection::iterator i = find (points.begin(), points.end(), cp);
@@ -996,6 +979,7 @@ void
 Selection::toggle (vector<ControlPoint*> const & cps)
 {
        clear_time();  //enforce region/object exclusivity
+       clear_tracks();  //enforce object/track exclusivity
 
        for (vector<ControlPoint*>::const_iterator i = cps.begin(); i != cps.end(); ++i) {
                toggle (*i);
@@ -1006,6 +990,7 @@ void
 Selection::toggle (list<Selectable*> const & selectables)
 {
        clear_time();  //enforce region/object exclusivity
+       clear_tracks();  //enforce object/track exclusivity
        
        RegionView* rv;
        ControlPoint* cp;
@@ -1021,7 +1006,7 @@ Selection::toggle (list<Selectable*> const & selectables)
                        fatal << _("programming error: ")
                              << X_("unknown selectable type passed to Selection::toggle()")
                              << endmsg;
-                       /*NOTREACHED*/
+                       abort(); /*NOTREACHED*/
                }
        }
 
@@ -1038,12 +1023,9 @@ void
 Selection::set (list<Selectable*> const & selectables)
 {
        clear_time ();  //enforce region/object exclusivity
+       clear_tracks();  //enforce object/track exclusivity
        clear_objects ();
 
-       if (Config->get_link_region_and_track_selection ()) {
-               clear_tracks ();
-       }
-
        add (selectables);
 }
 
@@ -1051,6 +1033,7 @@ void
 Selection::add (PointSelection const & s)
 {
        clear_time ();  //enforce region/object exclusivity
+       clear_tracks();  //enforce object/track exclusivity
 
        for (PointSelection::const_iterator i = s.begin(); i != s.end(); ++i) {
                points.push_back (*i);
@@ -1061,6 +1044,7 @@ void
 Selection::add (list<Selectable*> const & selectables)
 {
        clear_time ();  //enforce region/object exclusivity
+       clear_tracks();  //enforce object/track exclusivity
 
        RegionView* rv;
        ControlPoint* cp;
@@ -1076,7 +1060,7 @@ Selection::add (list<Selectable*> const & selectables)
                        fatal << _("programming error: ")
                              << X_("unknown selectable type passed to Selection::add()")
                              << endmsg;
-                       /*NOTREACHED*/
+                       abort(); /*NOTREACHED*/
                }
        }
 
@@ -1102,6 +1086,7 @@ void
 Selection::add (ControlPoint* cp)
 {
        clear_time ();  //enforce region/object exclusivity
+       clear_tracks();  //enforce object/track exclusivity
 
        cp->set_selected (true);
        points.push_back (cp);
@@ -1112,6 +1097,7 @@ void
 Selection::add (vector<ControlPoint*> const & cps)
 {
        clear_time ();  //enforce region/object exclusivity
+       clear_tracks();  //enforce object/track exclusivity
 
        for (vector<ControlPoint*>::const_iterator i = cps.begin(); i != cps.end(); ++i) {
                (*i)->set_selected (true);
@@ -1124,6 +1110,7 @@ void
 Selection::set (ControlPoint* cp)
 {
        clear_time ();  //enforce region/object exclusivity
+       clear_tracks();  //enforce object/track exclusivity
 
        if (cp->get_selected()) {
                return;
@@ -1141,6 +1128,7 @@ void
 Selection::set (Marker* m)
 {
        clear_time ();  //enforce region/object exclusivity
+       clear_tracks();  //enforce object/track exclusivity
        markers.clear ();
 
        add (m);
@@ -1173,6 +1161,7 @@ void
 Selection::add (Marker* m)
 {
        clear_time ();  //enforce region/object exclusivity
+       clear_tracks();  //enforce object/track exclusivity
 
        if (find (markers.begin(), markers.end(), m) == markers.end()) {
                markers.push_back (m);
@@ -1184,6 +1173,7 @@ void
 Selection::add (const list<Marker*>& m)
 {
        clear_time ();  //enforce region/object exclusivity
+       clear_tracks();  //enforce object/track exclusivity
 
        markers.insert (markers.end(), m.begin(), m.end());
        markers.sort ();
@@ -1220,6 +1210,7 @@ Selection::get_state () const
           so that re-opening plugin windows for editor mixer strips works
        */
 
+       char buf[32];
        XMLNode* node = new XMLNode (X_("Selection"));
 
        for (TrackSelection::const_iterator i = tracks.begin(); i != tracks.end(); ++i) {
@@ -1235,9 +1226,23 @@ Selection::get_state () const
                }
        }
 
+       for (RegionSelection::const_iterator i = regions.begin(); i != regions.end(); ++i) {
+               XMLNode* r = node->add_child (X_("Region"));
+               r->add_property (X_("id"), atoi ((*i)->region ()->id ().to_s ().c_str()));
+               
+       }
+
+       for (TimeSelection::const_iterator i = time.begin(); i != time.end(); ++i) {
+               XMLNode* t = node->add_child (X_("AudioRange"));
+               snprintf(buf, sizeof(buf), "%" PRId64, (*i).start);
+               t->add_property (X_("start"), string(buf));
+               snprintf(buf, sizeof(buf), "%" PRId64, (*i).end);
+               t->add_property (X_("end"), string(buf));
+       }
+       
        for (MarkerSelection::const_iterator i = markers.begin(); i != markers.end(); ++i) {
                XMLNode* t = node->add_child (X_("Marker"));
-
+               
                bool is_start;
                Location* loc = editor->find_location_from_marker (*i, is_start);
 
@@ -1255,6 +1260,12 @@ Selection::set_state (XMLNode const & node, int)
                return -1;
        }
 
+       clear_regions ();
+       clear_points ();
+       clear_time ();
+       clear_tracks ();
+       clear_markers ();
+
        XMLNodeList children = node.children ();
        for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
                if ((*i)->name() == X_("RouteView")) {
@@ -1267,6 +1278,36 @@ Selection::set_state (XMLNode const & node, int)
                                add (rtv);
                        }
 
+               } else if ((*i)->name() == X_("Region")) {
+                       XMLProperty* prop_id = (*i)->property (X_("id"));
+                       assert (prop_id);
+                       PBD::ID id (prop_id->value ());
+                       
+                       RegionSelection rs;
+                       editor->get_regionviews_by_id (id, rs);
+                       
+                       if (!rs.empty ()) {
+                               add (rs);
+                       } else {
+                               /*
+                                 regionviews are being constructed - stash the region IDs 
+                                 so we can identify them in Editor::region_view_added ()
+                               */
+                               regions.pending.push_back (id);
+                       }
+                       
+               } else if  ((*i)->name() == X_("AudioRange")) {
+                       XMLProperty* prop_start = (*i)->property (X_("start"));
+                       XMLProperty* prop_end = (*i)->property (X_("end"));
+
+                       assert (prop_start);
+                       assert (prop_end);
+
+                       framepos_t s (atol (prop_start->value ().c_str()));
+                       framepos_t e (atol (prop_end->value ().c_str()));
+
+                       set_preserving_all_ranges (s, e);
+
                } else if ((*i)->name() == X_("AutomationView")) {
 
                        XMLProperty* prop_id = (*i)->property (X_("id"));
@@ -1279,7 +1320,7 @@ Selection::set_state (XMLNode const & node, int)
                        RouteTimeAxisView* rtv = editor->get_route_view_by_route_id (id);
 
                        if (rtv) {
-                               boost::shared_ptr<AutomationTimeAxisView> atv = rtv->automation_child (EventTypeMap::instance().new_parameter (prop_parameter->value ()));
+                               boost::shared_ptr<AutomationTimeAxisView> atv = rtv->automation_child (EventTypeMap::instance().from_symbol (prop_parameter->value ()));
 
                                /* the automation could be for an entity that was never saved
                                   in the session file. Don't freak out if we can't find