Fix AutomationTrackItem rubberband click thinking it was unhandled.
[ardour.git] / gtk2_ardour / selection.cc
1 /*
2     Copyright (C) 2002 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 <algorithm>
21 #include <sigc++/bind.h>
22
23 #include "pbd/error.h"
24 #include "pbd/stacktrace.h"
25
26 #include "ardour/playlist.h"
27 #include "ardour/rc_configuration.h"
28
29 #include "gui_thread.h"
30 #include "midi_cut_buffer.h"
31 #include "region_view.h"
32 #include "selection.h"
33 #include "selection_templates.h"
34 #include "time_axis_view.h"
35 #include "automation_time_axis.h"
36 #include "public_editor.h"
37 #include "control_point.h"
38
39 #include "i18n.h"
40
41 using namespace std;
42 using namespace ARDOUR;
43 using namespace PBD;
44
45 struct AudioRangeComparator {
46     bool operator()(AudioRange a, AudioRange b) {
47             return a.start < b.start;
48     }
49 };
50
51 Selection::Selection (const PublicEditor* e)
52         : tracks (e)
53         , editor (e)
54         , next_time_id (0)
55         , _no_tracks_changed (false)
56 {
57         clear ();
58
59         /* we have disambiguate which remove() for the compiler */
60
61         void (Selection::*track_remove)(TimeAxisView*) = &Selection::remove;
62         TimeAxisView::CatchDeletion.connect (*this, MISSING_INVALIDATOR, boost::bind (track_remove, this, _1), gui_context());
63
64         void (Selection::*marker_remove)(Marker*) = &Selection::remove;
65         Marker::CatchDeletion.connect (*this, MISSING_INVALIDATOR, boost::bind (marker_remove, this, _1), gui_context());
66
67         void (Selection::*point_remove)(ControlPoint*) = &Selection::remove;
68         ControlPoint::CatchDeletion.connect (*this, MISSING_INVALIDATOR, boost::bind (point_remove, this, _1), gui_context());
69 }
70
71 #if 0
72 Selection&
73 Selection::operator= (const Selection& other)
74 {
75         if (&other != this) {
76                 regions = other.regions;
77                 tracks = other.tracks;
78                 time = other.time;
79                 lines = other.lines;
80                 midi_regions = other.midi_regions;
81                 midi_notes = other.midi_notes;
82         }
83         return *this;
84 }
85 #endif
86
87 bool
88 operator== (const Selection& a, const Selection& b)
89 {
90         return a.regions == b.regions &&
91                 a.tracks == b.tracks &&
92                 a.time == b.time &&
93                 a.lines == b.lines &&
94                 a.playlists == b.playlists &&
95                 a.midi_notes == b.midi_notes &&
96                 a.midi_regions == b.midi_regions;
97 }
98
99 /** Clear everything from the Selection */
100 void
101 Selection::clear ()
102 {
103         clear_tracks ();
104         clear_regions ();
105         clear_points ();
106         clear_lines();
107         clear_time ();
108         clear_playlists ();
109         clear_midi_notes ();
110         clear_midi_regions ();
111         clear_markers ();
112         pending_midi_note_selection.clear();
113 }
114
115 void
116 Selection::clear_objects ()
117 {
118         clear_regions ();
119         clear_points ();
120         clear_lines();
121         clear_playlists ();
122         clear_midi_notes ();
123         clear_midi_regions ();
124 }
125
126 void
127 Selection::clear_tracks ()
128 {
129         if (!tracks.empty()) {
130                 for (TrackViewList::iterator x = tracks.begin(); x != tracks.end(); ++x) {
131                         (*x)->set_selected (false);
132                 }
133                 tracks.clear ();
134                 if (!_no_tracks_changed) {
135                         TracksChanged();
136                 }
137         }
138 }
139
140 void
141 Selection::clear_time ()
142 {
143         time.clear();
144
145         TimeChanged ();
146 }
147
148 void
149 Selection::dump_region_layers()
150 {
151         cerr << "region selection layer dump" << endl;
152         for (RegionSelection::iterator i = regions.begin(); i != regions.end(); ++i) {
153                 cerr << "layer: " << (int)(*i)->region()->layer() << endl;
154         }
155 }
156
157
158 void
159 Selection::clear_regions ()
160 {
161         if (!regions.empty()) {
162                 regions.clear_all ();
163                 RegionsChanged();
164         }
165 }
166
167 void
168 Selection::clear_midi_notes ()
169 {
170         if (!midi_notes.empty()) {
171                 for (MidiNoteSelection::iterator x = midi_notes.begin(); x != midi_notes.end(); ++x) {
172                         delete *x;
173                 }
174                 midi_notes.clear ();
175                 MidiNotesChanged ();
176         }
177
178         /* The note selection is actually stored in MidiRegionView, emit signal to
179            tell them to clear their selection. */
180         ClearMidiNoteSelection();  /* EMIT SIGNAL */
181 }
182
183 void
184 Selection::clear_midi_regions ()
185 {
186         if (!midi_regions.empty()) {
187                 midi_regions.clear ();
188                 MidiRegionsChanged ();
189         }
190 }
191
192 void
193 Selection::clear_playlists ()
194 {
195         /* Selections own their playlists */
196
197         for (PlaylistSelection::iterator i = playlists.begin(); i != playlists.end(); ++i) {
198                 /* selections own their own regions, which are copies of the "originals". make them go away */
199                 (*i)->drop_regions ();
200                 (*i)->release ();
201         }
202
203         if (!playlists.empty()) {
204                 playlists.clear ();
205                 PlaylistsChanged();
206         }
207 }
208
209 void
210 Selection::clear_lines ()
211 {
212         if (!lines.empty()) {
213                 lines.clear ();
214                 LinesChanged();
215         }
216 }
217
218 void
219 Selection::clear_markers ()
220 {
221         if (!markers.empty()) {
222                 markers.clear ();
223                 MarkersChanged();
224         }
225 }
226
227 void
228 Selection::toggle (boost::shared_ptr<Playlist> pl)
229 {
230         clear_time();  //enforce object/range exclusivity
231         clear_tracks();  //enforce object/track exclusivity
232         
233         PlaylistSelection::iterator i;
234
235         if ((i = find (playlists.begin(), playlists.end(), pl)) == playlists.end()) {
236                 pl->use ();
237                 playlists.push_back(pl);
238         } else {
239                 playlists.erase (i);
240         }
241
242         PlaylistsChanged ();
243 }
244
245 void
246 Selection::toggle (const TrackViewList& track_list)
247 {
248         for (TrackViewList::const_iterator i = track_list.begin(); i != track_list.end(); ++i) {
249                 toggle ((*i));
250         }
251 }
252
253 void
254 Selection::toggle (TimeAxisView* track)
255 {
256         TrackSelection::iterator i;
257
258         if ((i = find (tracks.begin(), tracks.end(), track)) == tracks.end()) {
259                 track->set_selected (true);
260                 tracks.push_back (track);
261         } else {
262                 track->set_selected (false);
263                 tracks.erase (i);
264         }
265
266         if (!_no_tracks_changed) {
267                 TracksChanged();
268         }
269 }
270
271 void
272 Selection::toggle (const MidiNoteSelection& midi_note_list)
273 {
274         clear_time();  //enforce object/range exclusivity
275         clear_tracks();  //enforce object/track exclusivity
276
277         for (MidiNoteSelection::const_iterator i = midi_note_list.begin(); i != midi_note_list.end(); ++i) {
278                 toggle ((*i));
279         }
280 }
281
282 void
283 Selection::toggle (MidiCutBuffer* midi)
284 {
285         MidiNoteSelection::iterator i;
286
287         if ((i = find (midi_notes.begin(), midi_notes.end(), midi)) == midi_notes.end()) {
288                 midi_notes.push_back (midi);
289         } else {
290                 /* remember that we own the MCB */
291                 delete *i;
292                 midi_notes.erase (i);
293         }
294
295         MidiNotesChanged();
296 }
297
298
299 void
300 Selection::toggle (RegionView* r)
301 {
302         clear_time();  //enforce object/range exclusivity
303         clear_tracks();  //enforce object/track exclusivity
304         
305         RegionSelection::iterator i;
306
307         if ((i = find (regions.begin(), regions.end(), r)) == regions.end()) {
308                 add (r);
309         } else {
310                 remove (*i);
311         }
312
313         RegionsChanged ();
314 }
315
316 void
317 Selection::toggle (MidiRegionView* mrv)
318 {
319         clear_time();   //enforce object/range exclusivity
320         clear_tracks();  //enforce object/track exclusivity
321
322         MidiRegionSelection::iterator i;
323
324         if ((i = find (midi_regions.begin(), midi_regions.end(), mrv)) == midi_regions.end()) {
325                 add (mrv);
326         } else {
327                 midi_regions.erase (i);
328         }
329
330         MidiRegionsChanged ();
331 }
332
333 void
334 Selection::toggle (vector<RegionView*>& r)
335 {
336         clear_time();  //enforce object/range exclusivity
337         clear_tracks();  //enforce object/track exclusivity
338
339         RegionSelection::iterator i;
340
341         for (vector<RegionView*>::iterator x = r.begin(); x != r.end(); ++x) {
342                 if ((i = find (regions.begin(), regions.end(), (*x))) == regions.end()) {
343                         add ((*x));
344                 } else {
345                         remove (*x);
346                 }
347         }
348
349         RegionsChanged ();
350 }
351
352 long
353 Selection::toggle (framepos_t start, framepos_t end)
354 {
355         clear_objects();  //enforce object/range exclusivity
356
357         AudioRangeComparator cmp;
358
359         /* XXX this implementation is incorrect */
360
361         time.push_back (AudioRange (start, end, ++next_time_id));
362         time.consolidate ();
363         time.sort (cmp);
364
365         TimeChanged ();
366
367         return next_time_id;
368 }
369
370 void
371 Selection::add (boost::shared_ptr<Playlist> pl)
372 {
373         clear_time();  //enforce object/range exclusivity
374         clear_tracks();  //enforce object/track exclusivity
375         
376         if (find (playlists.begin(), playlists.end(), pl) == playlists.end()) {
377                 pl->use ();
378                 playlists.push_back(pl);
379                 PlaylistsChanged ();
380         }
381 }
382
383 void
384 Selection::add (const list<boost::shared_ptr<Playlist> >& pllist)
385 {
386         clear_time();  //enforce object/range exclusivity
387         clear_tracks();  //enforce object/track exclusivity
388         
389         bool changed = false;
390
391         for (list<boost::shared_ptr<Playlist> >::const_iterator i = pllist.begin(); i != pllist.end(); ++i) {
392                 if (find (playlists.begin(), playlists.end(), (*i)) == playlists.end()) {
393                         (*i)->use ();
394                         playlists.push_back (*i);
395                         changed = true;
396                 }
397         }
398
399         if (changed) {
400                 PlaylistsChanged ();
401         }
402 }
403
404 void
405 Selection::add (const TrackViewList& track_list)
406 {
407         clear_objects();  //enforce object/range exclusivity
408
409         TrackViewList added = tracks.add (track_list);
410
411         if (!added.empty()) {
412                 for (TrackViewList::iterator x = added.begin(); x != added.end(); ++x) {
413                         (*x)->set_selected (true);
414                 }
415                 if (!_no_tracks_changed) {
416                         TracksChanged ();
417                 }
418         }
419 }
420
421 void
422 Selection::add (TimeAxisView* track)
423 {
424         clear_objects();  //enforce object/range exclusivity
425
426         TrackViewList tr;
427         track->set_selected (true);
428         tr.push_back (track);
429         add (tr);
430 }
431
432 void
433 Selection::add (const MidiNoteSelection& midi_list)
434 {
435         clear_time();  //enforce object/range exclusivity
436         clear_tracks();  //enforce object/track exclusivity
437
438         const MidiNoteSelection::const_iterator b = midi_list.begin();
439         const MidiNoteSelection::const_iterator e = midi_list.end();
440
441         if (!midi_list.empty()) {
442                 midi_notes.insert (midi_notes.end(), b, e);
443                 MidiNotesChanged ();
444         }
445 }
446
447 void
448 Selection::add (MidiCutBuffer* midi)
449 {
450         /* we take ownership of the MCB */
451
452         if (find (midi_notes.begin(), midi_notes.end(), midi) == midi_notes.end()) {
453                 midi_notes.push_back (midi);
454                 MidiNotesChanged ();
455         }
456 }
457
458 void
459 Selection::add (vector<RegionView*>& v)
460 {
461         clear_time();  //enforce object/range exclusivity
462         clear_tracks();  //enforce object/track exclusivity
463
464         /* XXX This method or the add (const RegionSelection&) needs to go
465          */
466
467         bool changed = false;
468
469         for (vector<RegionView*>::iterator i = v.begin(); i != v.end(); ++i) {
470                 if (find (regions.begin(), regions.end(), (*i)) == regions.end()) {
471                         changed = regions.add ((*i));
472                 }
473         }
474
475         if (changed) {
476                 RegionsChanged ();
477         }
478 }
479
480 void
481 Selection::add (const RegionSelection& rs)
482 {
483         clear_time();  //enforce object/range exclusivity
484         clear_tracks();  //enforce object/track exclusivity
485
486         /* XXX This method or the add (const vector<RegionView*>&) needs to go
487          */
488
489         bool changed = false;
490
491         for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
492                 if (find (regions.begin(), regions.end(), (*i)) == regions.end()) {
493                         changed = regions.add ((*i));
494                 }
495         }
496
497         if (changed) {
498                 RegionsChanged ();
499         }
500 }
501
502 void
503 Selection::add (RegionView* r)
504 {
505         clear_time();  //enforce object/range exclusivity
506         clear_tracks();  //enforce object/track exclusivity
507
508         if (find (regions.begin(), regions.end(), r) == regions.end()) {
509                 bool changed = regions.add (r);
510                 if (changed) {
511                         RegionsChanged ();
512                 }
513         }
514 }
515
516 void
517 Selection::add (MidiRegionView* mrv)
518 {
519         clear_time();  //enforce object/range exclusivity
520         clear_tracks();  //enforce object/track exclusivity
521
522         if (find (midi_regions.begin(), midi_regions.end(), mrv) == midi_regions.end()) {
523                 midi_regions.push_back (mrv);
524                 /* XXX should we do this? */
525                 MidiRegionsChanged ();
526         }
527 }
528
529 long
530 Selection::add (framepos_t start, framepos_t end)
531 {
532         clear_objects();  //enforce object/range exclusivity
533
534         AudioRangeComparator cmp;
535
536         /* XXX this implementation is incorrect */
537
538         time.push_back (AudioRange (start, end, ++next_time_id));
539         time.consolidate ();
540         time.sort (cmp);
541
542         TimeChanged ();
543
544         return next_time_id;
545 }
546
547 void
548 Selection::move_time (framecnt_t distance)
549 {
550         if (distance == 0) {
551                 return;
552         }
553
554         for (list<AudioRange>::iterator i = time.begin(); i != time.end(); ++i) {
555                 (*i).start += distance;
556                 (*i).end += distance;
557         }
558
559         TimeChanged ();
560 }
561
562 void
563 Selection::replace (uint32_t sid, framepos_t start, framepos_t end)
564 {
565         clear_objects();  //enforce object/range exclusivity
566         
567         for (list<AudioRange>::iterator i = time.begin(); i != time.end(); ++i) {
568                 if ((*i).id == sid) {
569                         time.erase (i);
570                         time.push_back (AudioRange(start,end, sid));
571
572                         /* don't consolidate here */
573
574
575                         AudioRangeComparator cmp;
576                         time.sort (cmp);
577
578                         TimeChanged ();
579                         break;
580                 }
581         }
582 }
583
584 void
585 Selection::add (boost::shared_ptr<Evoral::ControlList> cl)
586 {
587         clear_time();  //enforce object/range exclusivity
588         clear_tracks();  //enforce object/track exclusivity
589
590         boost::shared_ptr<ARDOUR::AutomationList> al
591                 = boost::dynamic_pointer_cast<ARDOUR::AutomationList>(cl);
592         if (!al) {
593                 warning << "Programming error: Selected list is not an ARDOUR::AutomationList" << endmsg;
594                 return;
595         }
596         if (find (lines.begin(), lines.end(), al) == lines.end()) {
597                 lines.push_back (al);
598                 LinesChanged();
599         }
600 }
601
602 void
603 Selection::remove (TimeAxisView* track)
604 {
605         list<TimeAxisView*>::iterator i;
606         if ((i = find (tracks.begin(), tracks.end(), track)) != tracks.end()) {
607                 track->set_selected (false);
608                 tracks.erase (i);
609                 if (!_no_tracks_changed) {
610                         TracksChanged();
611                 }
612         }
613 }
614
615 void
616 Selection::remove (const TrackViewList& track_list)
617 {
618         bool changed = false;
619
620         for (TrackViewList::const_iterator i = track_list.begin(); i != track_list.end(); ++i) {
621
622                 TrackViewList::iterator x = find (tracks.begin(), tracks.end(), *i);
623                 if (x != tracks.end()) {
624                         (*i)->set_selected (false);
625                         tracks.erase (x);
626                         changed = true;
627                 }
628         }
629
630         if (changed) {
631                 if (!_no_tracks_changed) {
632                         TracksChanged();
633                 }
634         }
635 }
636
637 void
638 Selection::remove (ControlPoint* p)
639 {
640         PointSelection::iterator i = find (points.begin(), points.end(), p);
641         if (i != points.end ()) {
642                 points.erase (i);
643         }
644 }
645
646 void
647 Selection::remove (const MidiNoteSelection& midi_list)
648 {
649         bool changed = false;
650
651         for (MidiNoteSelection::const_iterator i = midi_list.begin(); i != midi_list.end(); ++i) {
652
653                 MidiNoteSelection::iterator x;
654
655                 if ((x = find (midi_notes.begin(), midi_notes.end(), (*i))) != midi_notes.end()) {
656                         midi_notes.erase (x);
657                         changed = true;
658                 }
659         }
660
661         if (changed) {
662                 MidiNotesChanged();
663         }
664 }
665
666 void
667 Selection::remove (MidiCutBuffer* midi)
668 {
669         MidiNoteSelection::iterator x;
670
671         if ((x = find (midi_notes.begin(), midi_notes.end(), midi)) != midi_notes.end()) {
672                 /* remember that we own the MCB */
673                 delete *x;
674                 midi_notes.erase (x);
675                 MidiNotesChanged ();
676         }
677 }
678
679 void
680 Selection::remove (boost::shared_ptr<Playlist> track)
681 {
682         list<boost::shared_ptr<Playlist> >::iterator i;
683         if ((i = find (playlists.begin(), playlists.end(), track)) != playlists.end()) {
684                 playlists.erase (i);
685                 PlaylistsChanged();
686         }
687 }
688
689 void
690 Selection::remove (const list<boost::shared_ptr<Playlist> >& pllist)
691 {
692         bool changed = false;
693
694         for (list<boost::shared_ptr<Playlist> >::const_iterator i = pllist.begin(); i != pllist.end(); ++i) {
695
696                 list<boost::shared_ptr<Playlist> >::iterator x;
697
698                 if ((x = find (playlists.begin(), playlists.end(), (*i))) != playlists.end()) {
699                         playlists.erase (x);
700                         changed = true;
701                 }
702         }
703
704         if (changed) {
705                 PlaylistsChanged();
706         }
707 }
708
709 void
710 Selection::remove (RegionView* r)
711 {
712         if (regions.remove (r)) {
713                 RegionsChanged ();
714         }
715 }
716
717 void
718 Selection::remove (MidiRegionView* mrv)
719 {
720         MidiRegionSelection::iterator x;
721
722         if ((x = find (midi_regions.begin(), midi_regions.end(), mrv)) != midi_regions.end()) {
723                 midi_regions.erase (x);
724                 MidiRegionsChanged ();
725         }
726 }
727
728
729 void
730 Selection::remove (uint32_t selection_id)
731 {
732         if (time.empty()) {
733                 return;
734         }
735
736         for (list<AudioRange>::iterator i = time.begin(); i != time.end(); ++i) {
737                 if ((*i).id == selection_id) {
738                         time.erase (i);
739
740                         TimeChanged ();
741                         break;
742                 }
743         }
744 }
745
746 void
747 Selection::remove (framepos_t /*start*/, framepos_t /*end*/)
748 {
749 }
750
751 void
752 Selection::remove (boost::shared_ptr<ARDOUR::AutomationList> ac)
753 {
754         AutomationSelection::iterator i;
755         if ((i = find (lines.begin(), lines.end(), ac)) != lines.end()) {
756                 lines.erase (i);
757                 LinesChanged();
758         }
759 }
760
761 void
762 Selection::set (TimeAxisView* track)
763 {
764         clear_objects();  //enforce object/range exclusivity
765         clear_tracks ();
766         add (track);
767 }
768
769 void
770 Selection::set (const TrackViewList& track_list)
771 {
772         clear_objects();  //enforce object/range exclusivity
773         clear_tracks ();
774         add (track_list);
775 }
776
777 void
778 Selection::set (const MidiNoteSelection& midi_list)
779 {
780         clear_time ();  //enforce region/object exclusivity
781         clear_tracks();  //enforce object/track exclusivity
782         clear_objects ();
783         add (midi_list);
784 }
785
786 void
787 Selection::set (boost::shared_ptr<Playlist> playlist)
788 {
789         clear_time ();  //enforce region/object exclusivity
790         clear_tracks();  //enforce object/track exclusivity
791         clear_objects ();
792         add (playlist);
793 }
794
795 void
796 Selection::set (const list<boost::shared_ptr<Playlist> >& pllist)
797 {
798         clear_time();  //enforce region/object exclusivity
799         clear_objects ();
800         add (pllist);
801 }
802
803 void
804 Selection::set (const RegionSelection& rs)
805 {
806         clear_time();  //enforce region/object exclusivity
807         clear_tracks();  //enforce object/track exclusivity
808         clear_objects();
809         regions = rs;
810         RegionsChanged(); /* EMIT SIGNAL */
811 }
812
813 void
814 Selection::set (MidiRegionView* mrv)
815 {
816         clear_time();  //enforce region/object exclusivity
817         clear_tracks();  //enforce object/track exclusivity
818         clear_objects ();
819         add (mrv);
820 }
821
822 void
823 Selection::set (RegionView* r, bool /*also_clear_tracks*/)
824 {
825         clear_time();  //enforce region/object exclusivity
826         clear_tracks();  //enforce object/track exclusivity
827         clear_objects ();
828         add (r);
829 }
830
831 void
832 Selection::set (vector<RegionView*>& v)
833 {
834         clear_time();  //enforce region/object exclusivity
835         clear_tracks();  //enforce object/track exclusivity
836         clear_objects();
837
838         add (v);
839 }
840
841 /** Set the start and end time of the time selection, without changing
842  *  the list of tracks it applies to.
843  */
844 long
845 Selection::set (framepos_t start, framepos_t end)
846 {
847         clear_objects();  //enforce region/object exclusivity
848         clear_time();
849
850         if ((start == 0 && end == 0) || end < start) {
851                 return 0;
852         }
853
854         if (time.empty()) {
855                 time.push_back (AudioRange (start, end, ++next_time_id));
856         } else {
857                 /* reuse the first entry, and remove all the rest */
858
859                 while (time.size() > 1) {
860                         time.pop_front();
861                 }
862                 time.front().start = start;
863                 time.front().end = end;
864         }
865
866         time.consolidate ();
867
868         TimeChanged ();
869
870         return time.front().id;
871 }
872
873 /** Set the start and end of the range selection.  If more than one range
874  *  is currently selected, the start of the earliest range and the end of the
875  *  latest range are set.  If no range is currently selected, this method
876  *  selects a single range from start to end.
877  *
878  *  @param start New start time.
879  *  @param end New end time.
880  */
881 void
882 Selection::set_preserving_all_ranges (framepos_t start, framepos_t end)
883 {
884         clear_objects();  //enforce region/object exclusivity
885
886         if ((start == 0 && end == 0) || (end < start)) {
887                 return;
888         }
889
890         if (time.empty ()) {
891                 time.push_back (AudioRange (start, end, ++next_time_id));
892         } else {
893                 time.sort (AudioRangeComparator ());
894                 time.front().start = start;
895                 time.back().end = end;
896         }
897
898         time.consolidate ();
899
900         TimeChanged ();
901 }
902
903 void
904 Selection::set (boost::shared_ptr<Evoral::ControlList> ac)
905 {
906         clear_time();  //enforce region/object exclusivity
907         clear_tracks();  //enforce object/track exclusivity
908         clear_objects();
909         
910         add (ac);
911 }
912
913 bool
914 Selection::selected (Marker* m)
915 {
916         return find (markers.begin(), markers.end(), m) != markers.end();
917 }
918
919 bool
920 Selection::selected (TimeAxisView* tv)
921 {
922         return tv->get_selected ();
923 }
924
925 bool
926 Selection::selected (RegionView* rv)
927 {
928         return find (regions.begin(), regions.end(), rv) != regions.end();
929 }
930
931 bool
932 Selection::selected (ControlPoint* cp)
933 {
934         return find (points.begin(), points.end(), cp) != points.end();
935 }
936
937 bool
938 Selection::empty (bool internal_selection)
939 {
940         bool object_level_empty =  regions.empty () &&
941                 tracks.empty () &&
942                 points.empty () &&
943                 playlists.empty () &&
944                 lines.empty () &&
945                 time.empty () &&
946                 playlists.empty () &&
947                 markers.empty() &&
948                 midi_regions.empty()
949                 ;
950
951         if (!internal_selection) {
952                 return object_level_empty;
953         }
954
955         /* this is intended to really only apply when using a Selection
956            as a cut buffer.
957         */
958
959         return object_level_empty && midi_notes.empty() && points.empty();
960 }
961
962 void
963 Selection::toggle (ControlPoint* cp)
964 {
965         clear_time();  //enforce region/object exclusivity
966         clear_tracks();  //enforce object/track exclusivity
967
968         cp->set_selected (!cp->get_selected ());
969         PointSelection::iterator i = find (points.begin(), points.end(), cp);
970         if (i == points.end()) {
971                 points.push_back (cp);
972         } else {
973                 points.erase (i);
974         }
975
976         PointsChanged (); /* EMIT SIGNAL */
977 }
978
979 void
980 Selection::toggle (vector<ControlPoint*> const & cps)
981 {
982         clear_time();  //enforce region/object exclusivity
983         clear_tracks();  //enforce object/track exclusivity
984
985         for (vector<ControlPoint*>::const_iterator i = cps.begin(); i != cps.end(); ++i) {
986                 toggle (*i);
987         }
988 }
989
990 void
991 Selection::toggle (list<Selectable*> const & selectables)
992 {
993         clear_time();  //enforce region/object exclusivity
994         clear_tracks();  //enforce object/track exclusivity
995         
996         RegionView* rv;
997         ControlPoint* cp;
998         vector<RegionView*> rvs;
999         vector<ControlPoint*> cps;
1000
1001         for (std::list<Selectable*>::const_iterator i = selectables.begin(); i != selectables.end(); ++i) {
1002                 if ((rv = dynamic_cast<RegionView*> (*i)) != 0) {
1003                         rvs.push_back (rv);
1004                 } else if ((cp = dynamic_cast<ControlPoint*> (*i)) != 0) {
1005                         cps.push_back (cp);
1006                 } else {
1007                         fatal << _("programming error: ")
1008                               << X_("unknown selectable type passed to Selection::toggle()")
1009                               << endmsg;
1010                         abort(); /*NOTREACHED*/
1011                 }
1012         }
1013
1014         if (!rvs.empty()) {
1015                 toggle (rvs);
1016         }
1017
1018         if (!cps.empty()) {
1019                 toggle (cps);
1020         }
1021 }
1022
1023 void
1024 Selection::set (list<Selectable*> const & selectables)
1025 {
1026         clear_time ();  //enforce region/object exclusivity
1027         clear_tracks();  //enforce object/track exclusivity
1028         clear_objects ();
1029
1030         add (selectables);
1031 }
1032
1033 void
1034 Selection::add (PointSelection const & s)
1035 {
1036         clear_time ();  //enforce region/object exclusivity
1037         clear_tracks();  //enforce object/track exclusivity
1038
1039         for (PointSelection::const_iterator i = s.begin(); i != s.end(); ++i) {
1040                 points.push_back (*i);
1041         }
1042 }
1043
1044 void
1045 Selection::add (list<Selectable*> const & selectables)
1046 {
1047         clear_time ();  //enforce region/object exclusivity
1048         clear_tracks();  //enforce object/track exclusivity
1049
1050         RegionView* rv;
1051         ControlPoint* cp;
1052         vector<RegionView*> rvs;
1053         vector<ControlPoint*> cps;
1054
1055         for (std::list<Selectable*>::const_iterator i = selectables.begin(); i != selectables.end(); ++i) {
1056                 if ((rv = dynamic_cast<RegionView*> (*i)) != 0) {
1057                         rvs.push_back (rv);
1058                 } else if ((cp = dynamic_cast<ControlPoint*> (*i)) != 0) {
1059                         cps.push_back (cp);
1060                 } else {
1061                         fatal << _("programming error: ")
1062                               << X_("unknown selectable type passed to Selection::add()")
1063                               << endmsg;
1064                         abort(); /*NOTREACHED*/
1065                 }
1066         }
1067
1068         if (!rvs.empty()) {
1069                 add (rvs);
1070         }
1071
1072         if (!cps.empty()) {
1073                 add (cps);
1074         }
1075 }
1076
1077 void
1078 Selection::clear_points ()
1079 {
1080         if (!points.empty()) {
1081                 points.clear ();
1082                 PointsChanged ();
1083         }
1084 }
1085
1086 void
1087 Selection::add (ControlPoint* cp)
1088 {
1089         clear_time ();  //enforce region/object exclusivity
1090         clear_tracks();  //enforce object/track exclusivity
1091
1092         cp->set_selected (true);
1093         points.push_back (cp);
1094         PointsChanged (); /* EMIT SIGNAL */
1095 }
1096
1097 void
1098 Selection::add (vector<ControlPoint*> const & cps)
1099 {
1100         clear_time ();  //enforce region/object exclusivity
1101         clear_tracks();  //enforce object/track exclusivity
1102
1103         for (vector<ControlPoint*>::const_iterator i = cps.begin(); i != cps.end(); ++i) {
1104                 (*i)->set_selected (true);
1105                 points.push_back (*i);
1106         }
1107         PointsChanged (); /* EMIT SIGNAL */
1108 }
1109
1110 void
1111 Selection::set (ControlPoint* cp)
1112 {
1113         clear_time ();  //enforce region/object exclusivity
1114         clear_tracks();  //enforce object/track exclusivity
1115
1116         if (cp->get_selected()) {
1117                 return;
1118         }
1119
1120         for (uint32_t i = 0; i < cp->line().npoints(); ++i) {
1121                 cp->line().nth (i)->set_selected (false);
1122         }
1123
1124         clear_objects ();
1125         add (cp);
1126 }
1127
1128 void
1129 Selection::set (Marker* m)
1130 {
1131         clear_time ();  //enforce region/object exclusivity
1132         clear_tracks();  //enforce object/track exclusivity
1133         markers.clear ();
1134
1135         add (m);
1136 }
1137
1138 void
1139 Selection::toggle (Marker* m)
1140 {
1141         MarkerSelection::iterator i;
1142
1143         if ((i = find (markers.begin(), markers.end(), m)) == markers.end()) {
1144                 add (m);
1145         } else {
1146                 remove (m);
1147         }
1148 }
1149
1150 void
1151 Selection::remove (Marker* m)
1152 {
1153         MarkerSelection::iterator i;
1154
1155         if ((i = find (markers.begin(), markers.end(), m)) != markers.end()) {
1156                 markers.erase (i);
1157                 MarkersChanged();
1158         }
1159 }
1160
1161 void
1162 Selection::add (Marker* m)
1163 {
1164         clear_time ();  //enforce region/object exclusivity
1165         clear_tracks();  //enforce object/track exclusivity
1166
1167         if (find (markers.begin(), markers.end(), m) == markers.end()) {
1168                 markers.push_back (m);
1169                 MarkersChanged();
1170         }
1171 }
1172
1173 void
1174 Selection::add (const list<Marker*>& m)
1175 {
1176         clear_time ();  //enforce region/object exclusivity
1177         clear_tracks();  //enforce object/track exclusivity
1178
1179         markers.insert (markers.end(), m.begin(), m.end());
1180         markers.sort ();
1181         markers.unique ();
1182         
1183         MarkersChanged ();
1184 }
1185
1186 void
1187 MarkerSelection::range (framepos_t& s, framepos_t& e)
1188 {
1189         s = max_framepos;
1190         e = 0;
1191
1192         for (MarkerSelection::iterator i = begin(); i != end(); ++i) {
1193
1194                 if ((*i)->position() < s) {
1195                         s = (*i)->position();
1196                 }
1197
1198                 if ((*i)->position() > e) {
1199                         e = (*i)->position();
1200                 }
1201         }
1202
1203         s = std::min (s, e);
1204         e = std::max (s, e);
1205 }
1206
1207 XMLNode&
1208 Selection::get_state () const
1209 {
1210         /* XXX: not complete; just sufficient to get track selection state
1211            so that re-opening plugin windows for editor mixer strips works
1212         */
1213
1214         char buf[32];
1215         XMLNode* node = new XMLNode (X_("Selection"));
1216
1217         for (TrackSelection::const_iterator i = tracks.begin(); i != tracks.end(); ++i) {
1218                 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
1219                 AutomationTimeAxisView* atv = dynamic_cast<AutomationTimeAxisView*> (*i);
1220                 if (rtv) {
1221                         XMLNode* t = node->add_child (X_("RouteView"));
1222                         t->add_property (X_("id"), atoi (rtv->route()->id().to_s().c_str()));
1223                 } else if (atv) {
1224                         XMLNode* t = node->add_child (X_("AutomationView"));
1225                         t->add_property (X_("id"), atoi (atv->parent_route()->id().to_s().c_str()));
1226                         t->add_property (X_("parameter"), EventTypeMap::instance().to_symbol (atv->parameter ()));
1227                 }
1228         }
1229
1230         for (RegionSelection::const_iterator i = regions.begin(); i != regions.end(); ++i) {
1231                 XMLNode* r = node->add_child (X_("Region"));
1232                 r->add_property (X_("id"), atoi ((*i)->region ()->id ().to_s ().c_str()));
1233         }
1234
1235         /* midi region views have thir own internal selection. */
1236         XMLNode* n;
1237         list<pair<PBD::ID, std::set<boost::shared_ptr<Evoral::Note<Evoral::Beats> > > > > rid_notes;
1238         editor->get_per_region_note_selection (rid_notes);
1239         if (!rid_notes.empty()) {
1240                 n = node->add_child (X_("MIDINote"));
1241         }
1242         list<pair<PBD::ID, std::set<boost::shared_ptr<Evoral::Note<Evoral::Beats> > > > >::iterator rn_it;
1243         for (rn_it = rid_notes.begin(); rn_it != rid_notes.end(); ++rn_it) {
1244                 n->add_property (X_("region_id"), atoi((*rn_it).first.to_s().c_str()));
1245                         
1246                 for (std::set<boost::shared_ptr<Evoral::Note<Evoral::Beats> > >::iterator i = (*rn_it).second.begin(); i != (*rn_it).second.end(); ++i) {
1247                         XMLNode* nc = n->add_child(X_("note"));
1248                         snprintf(buf, sizeof(buf), "%d", (*i)->channel());
1249                         nc->add_property(X_("channel"), string(buf));
1250
1251                         snprintf(buf, sizeof(buf), "%f", (*i)->time().to_double());
1252                         nc->add_property(X_("time"), string(buf));
1253
1254                         snprintf(buf, sizeof(buf), "%d", (*i)->note());
1255                         nc->add_property(X_("note"), string(buf));
1256
1257                         snprintf(buf, sizeof(buf), "%f", (*i)->length().to_double());
1258                         nc->add_property(X_("length"), string(buf));
1259
1260                         snprintf(buf, sizeof(buf), "%d", (*i)->velocity());
1261                         nc->add_property(X_("velocity"), string(buf));
1262
1263                         snprintf(buf, sizeof(buf), "%d", (*i)->off_velocity());
1264                         nc->add_property(X_("off-velocity"), string(buf));
1265                 }
1266         }
1267
1268         for (PointSelection::const_iterator i = points.begin(); i != points.end(); ++i) {
1269                 AutomationTimeAxisView* atv = dynamic_cast<AutomationTimeAxisView*> (&(*i)->line().trackview);
1270                 if (atv) {
1271
1272                         XMLNode* r = node->add_child (X_("ControlPoint"));
1273                         r->add_property (X_("type"), "track");
1274                         r->add_property (X_("route-id"), atoi (atv->parent_route()->id ().to_s ().c_str()));
1275                         r->add_property (X_("automation-list-id"), atoi ((*i)->line().the_list()->id ().to_s ().c_str()));
1276                         r->add_property (X_("parameter"), EventTypeMap::instance().to_symbol ((*i)->line().the_list()->parameter ()));
1277
1278                         snprintf(buf, sizeof(buf), "%d", (*i)->view_index());
1279                         r->add_property (X_("view-index"), string(buf));
1280
1281                 }
1282         }
1283
1284         for (TimeSelection::const_iterator i = time.begin(); i != time.end(); ++i) {
1285                 XMLNode* t = node->add_child (X_("AudioRange"));
1286                 snprintf(buf, sizeof(buf), "%" PRId64, (*i).start);
1287                 t->add_property (X_("start"), string(buf));
1288                 snprintf(buf, sizeof(buf), "%" PRId64, (*i).end);
1289                 t->add_property (X_("end"), string(buf));
1290         }
1291         
1292         for (MarkerSelection::const_iterator i = markers.begin(); i != markers.end(); ++i) {
1293                 XMLNode* t = node->add_child (X_("Marker"));
1294                 
1295                 bool is_start;
1296                 Location* loc = editor->find_location_from_marker (*i, is_start);
1297
1298                 t->add_property (X_("id"), atoi (loc->id().to_s().c_str()));
1299                 t->add_property (X_("start"), is_start ? X_("yes") : X_("no"));
1300         }
1301
1302         return *node;
1303 }
1304
1305 int
1306 Selection::set_state (XMLNode const & node, int)
1307 {
1308         if (node.name() != X_("Selection")) {
1309                 return -1;
1310         }
1311
1312         clear_regions ();
1313         clear_points ();
1314         clear_time ();
1315         clear_tracks ();
1316         clear_markers ();
1317
1318         XMLNodeList children = node.children ();
1319         for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
1320                 if ((*i)->name() == X_("RouteView")) {
1321
1322                         XMLProperty* prop_id = (*i)->property (X_("id"));
1323                         assert (prop_id);
1324                         PBD::ID id (prop_id->value ());
1325                         RouteTimeAxisView* rtv = editor->get_route_view_by_route_id (id);
1326                         if (rtv) {
1327                                 add (rtv);
1328                         }
1329
1330                 } else if ((*i)->name() == X_("Region")) {
1331                         XMLProperty* prop_id = (*i)->property (X_("id"));
1332                         assert (prop_id);
1333                         PBD::ID id (prop_id->value ());
1334                         
1335                         RegionSelection rs;
1336                         editor->get_regionviews_by_id (id, rs);
1337                         
1338                         if (!rs.empty ()) {
1339                                 add (rs);
1340                         } else {
1341                                 /*
1342                                   regionviews haven't been constructed - stash the region IDs 
1343                                   so we can identify them in Editor::region_view_added ()
1344                                 */
1345                                 regions.pending.push_back (id);
1346                         }
1347                         
1348                 } else if ((*i)->name() == X_("MIDINote")) {
1349                         XMLProperty* prop_region_id = (*i)->property (X_("region-id"));
1350
1351                         assert (prop_region_id);
1352
1353                         PBD::ID const id (prop_region_id->value ());
1354                         RegionSelection rs;
1355
1356                         editor->get_regionviews_by_id (id, rs); // there could be more than one
1357
1358                         std::list<boost::shared_ptr<Evoral::Note<Evoral::Beats> > > notes;
1359                         XMLNodeList children = (*i)->children ();
1360
1361                         for (XMLNodeList::const_iterator ci = children.begin(); ci != children.end(); ++ci) {
1362                                 XMLProperty* prop_channel = (*ci)->property (X_("channel"));
1363                                 XMLProperty* prop_time = (*ci)->property (X_("time"));
1364                                 XMLProperty* prop_note = (*ci)->property (X_("note"));
1365                                 XMLProperty* prop_length = (*ci)->property (X_("length"));
1366                                 XMLProperty* prop_velocity = (*ci)->property (X_("velocity"));
1367                                 XMLProperty* prop_off_velocity = (*ci)->property (X_("off-velocity"));
1368                                 
1369                                 assert (prop_channel);
1370                                 assert (prop_time);
1371                                 assert (prop_note);
1372                                 assert (prop_length);
1373                                 assert (prop_velocity);
1374                                 assert (prop_off_velocity);
1375                                 
1376                                 uint8_t channel = atoi(prop_channel->value());
1377                                 Evoral::Beats time (atof(prop_time->value()));
1378                                 Evoral::Beats length (atof(prop_length->value()));
1379                                 uint8_t note = atoi(prop_note->value());
1380                                 uint8_t velocity = atoi(prop_velocity->value());
1381                                 uint8_t off_velocity = atoi(prop_off_velocity->value());
1382                                 boost::shared_ptr<Evoral::Note<Evoral::Beats> > the_note 
1383                                         (new Evoral::Note<Evoral::Beats>  (channel, time, length, note, velocity));
1384                                 the_note->set_off_velocity (off_velocity);
1385                                 
1386                                 notes.push_back (the_note);
1387                         }
1388                         
1389                         for (RegionSelection::iterator rsi = rs.begin(); rsi != rs.end(); ++rsi) {
1390                                 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (*rsi);
1391                                 if (mrv) {
1392                                         mrv->select_notes(notes);
1393                                 }
1394                         }
1395
1396                         if (rs.empty()) {
1397                                 /* regionviews containing these notes don't yet exist on the canvas.*/
1398                                 pending_midi_note_selection.push_back (make_pair (id, notes));
1399                         }
1400
1401                 } else if  ((*i)->name() == X_("ControlPoint")) {
1402                         XMLProperty* prop_type = (*i)->property (X_("type"));
1403         
1404                         assert(prop_type);
1405
1406                         if (prop_type->value () == "track") {
1407
1408                                 XMLProperty* prop_route_id = (*i)->property (X_("route-id"));
1409                                 XMLProperty* prop_alist_id = (*i)->property (X_("automation-list-id"));
1410                                 XMLProperty* prop_parameter = (*i)->property (X_("parameter"));
1411                                 XMLProperty* prop_view_index = (*i)->property (X_("view-index"));
1412
1413                                 assert (prop_type);
1414                                 assert (prop_route_id);
1415                                 assert (prop_alist_id);
1416                                 assert (prop_parameter);
1417                                 assert (prop_view_index);
1418
1419                                 PBD::ID route_id (prop_route_id->value ());
1420                                 RouteTimeAxisView* rtv = editor->get_route_view_by_route_id (route_id);
1421                                 vector <ControlPoint *> cps;
1422
1423                                 if (rtv) {
1424                                         boost::shared_ptr<AutomationTimeAxisView> atv = rtv->automation_child (EventTypeMap::instance().from_symbol (prop_parameter->value ()));
1425                                         if (atv) {
1426                                                 list<boost::shared_ptr<AutomationLine> > lines = atv->lines();
1427                                                 for (list<boost::shared_ptr<AutomationLine> > ::iterator li = lines.begin(); li != lines.end(); ++li) {
1428                                                         if ((*li)->the_list()->id() == prop_alist_id->value()) {
1429                                                                 ControlPoint* cp = (*li)->nth(atol(prop_view_index->value().c_str()));
1430                                                                 if (cp) {
1431                                                                         cps.push_back (cp);
1432                                                                         cp->show();
1433                                                                 }
1434                                                         }
1435                                                 }
1436                                         }
1437                                 }
1438                                 if (!cps.empty()) {
1439                                         add (cps);
1440                                 }
1441                         }
1442
1443                 } else if  ((*i)->name() == X_("AudioRange")) {
1444                         XMLProperty* prop_start = (*i)->property (X_("start"));
1445                         XMLProperty* prop_end = (*i)->property (X_("end"));
1446
1447                         assert (prop_start);
1448                         assert (prop_end);
1449
1450                         framepos_t s (atol (prop_start->value ().c_str()));
1451                         framepos_t e (atol (prop_end->value ().c_str()));
1452
1453                         set_preserving_all_ranges (s, e);
1454
1455                 } else if ((*i)->name() == X_("AutomationView")) {
1456
1457                         XMLProperty* prop_id = (*i)->property (X_("id"));
1458                         XMLProperty* prop_parameter = (*i)->property (X_("parameter"));
1459
1460                         assert (prop_id);
1461                         assert (prop_parameter);
1462
1463                         PBD::ID id (prop_id->value ());
1464                         RouteTimeAxisView* rtv = editor->get_route_view_by_route_id (id);
1465
1466                         if (rtv) {
1467                                 boost::shared_ptr<AutomationTimeAxisView> atv = rtv->automation_child (EventTypeMap::instance().from_symbol (prop_parameter->value ()));
1468
1469                                 /* the automation could be for an entity that was never saved
1470                                    in the session file. Don't freak out if we can't find
1471                                    it.
1472                                 */
1473
1474                                 if (atv) {
1475                                         add (atv.get());
1476                                 }
1477                         }
1478
1479                 } else if ((*i)->name() == X_("Marker")) {
1480
1481                         XMLProperty* prop_id = (*i)->property (X_("id"));
1482                         XMLProperty* prop_start = (*i)->property (X_("start"));
1483                         assert (prop_id);
1484                         assert (prop_start);
1485
1486                         PBD::ID id (prop_id->value ());
1487                         Marker* m = editor->find_marker_from_location_id (id, string_is_affirmative (prop_start->value ()));
1488                         if (m) {
1489                                 add (m);
1490                         }
1491                         
1492                 }
1493                 
1494         }
1495
1496         return 0;
1497 }
1498
1499 void
1500 Selection::remove_regions (TimeAxisView* t)
1501 {
1502         RegionSelection::iterator i = regions.begin();
1503         while (i != regions.end ()) {
1504                 RegionSelection::iterator tmp = i;
1505                 ++tmp;
1506
1507                 if (&(*i)->get_time_axis_view() == t) {
1508                         remove (*i);
1509                 }
1510
1511                 i = tmp;
1512         }
1513 }
1514
1515 void
1516 Selection::block_tracks_changed (bool yn)
1517 {
1518         _no_tracks_changed = yn;
1519 }