Fix up undo/redo of MIDI note paste (#3815).
[ardour.git] / gtk2_ardour / midi_region_view.cc
index e76433bcae2c3070119bf08fee5194675d9b665e..24ad86f7d6f18c7a4571bf3af3828252ca6bd87a 100644 (file)
@@ -921,7 +921,7 @@ MidiRegionView::note_diff_add_change (ArdourCanvas::CanvasNoteEvent* ev,
 }
 
 void
-MidiRegionView::apply_diff ()
+MidiRegionView::apply_diff (bool as_subcommand)
 {
         bool add_or_remove;
 
@@ -936,7 +936,12 @@ MidiRegionView::apply_diff ()
                 }
         }
 
-       _model->apply_command(*trackview.session(), _note_diff_command);
+       if (as_subcommand) {
+               _model->apply_command_as_subcommand (*trackview.session(), _note_diff_command);
+       } else {
+               _model->apply_command (*trackview.session(), _note_diff_command);
+       }
+       
        _note_diff_command = 0;
        midi_view()->midi_track()->playlist_modified();
         
@@ -947,33 +952,6 @@ MidiRegionView::apply_diff ()
        _marked_for_velocity.clear();
 }
 
-void
-MidiRegionView::apply_diff_as_subcommand ()
-{
-        bool add_or_remove;
-
-       if (!_note_diff_command) {
-               return;
-       }
-
-        if ((add_or_remove = _note_diff_command->adds_or_removes())) {
-                // Mark all selected notes for selection when model reloads
-                for (Selection::iterator i = _selection.begin(); i != _selection.end(); ++i) {
-                        _marked_for_selection.insert((*i)->note());
-                }
-        }
-
-       _model->apply_command_as_subcommand(*trackview.session(), _note_diff_command);
-       _note_diff_command = 0;
-       midi_view()->midi_track()->playlist_modified();
-
-        if (add_or_remove) {
-                _marked_for_selection.clear();
-        }
-       _marked_for_velocity.clear();
-}
-
-
 void
 MidiRegionView::abort_command()
 {
@@ -1457,8 +1435,12 @@ MidiRegionView::note_in_region_range(const boost::shared_ptr<NoteType> note, boo
        return !outside;
 }
 
+/** Update a canvas note's size from its model note.
+ *  @param ev Canvas note to update.
+ *  @param update_ghost_regions true to update the note in any ghost regions that we have, otherwise false.
+ */
 void
-MidiRegionView::update_note (CanvasNote* ev)
+MidiRegionView::update_note (CanvasNote* ev, bool update_ghost_regions)
 {
        boost::shared_ptr<NoteType> note = ev->note();
 
@@ -1501,6 +1483,15 @@ MidiRegionView::update_note (CanvasNote* ev)
                /* outline all edges */
                ev->property_outline_what() = (guint32) 0xF;
        }
+
+       if (update_ghost_regions) {
+               for (std::vector<GhostRegion*>::iterator i = ghosts.begin(); i != ghosts.end(); ++i) {
+                       MidiGhostRegion* gr = dynamic_cast<MidiGhostRegion*> (*i);
+                       if (gr) {
+                               gr->update_note (ev);
+                       }
+               }
+       }
 }
 
 double
@@ -2963,6 +2954,7 @@ MidiRegionView::selection_as_cut_buffer () const
        return cb;
 }
 
+/** This method handles undo */
 void
 MidiRegionView::paste (framepos_t pos, float times, const MidiCutBuffer& mcb)
 {
@@ -2972,6 +2964,8 @@ MidiRegionView::paste (framepos_t pos, float times, const MidiCutBuffer& mcb)
 
         DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("MIDI paste @ %1 times %2\n", pos, times));
 
+       trackview.session()->begin_reversible_command (_("paste"));
+
        start_note_diff_command (_("paste"));
 
        Evoral::MusicalTime beat_delta;
@@ -3017,14 +3011,14 @@ MidiRegionView::paste (framepos_t pos, float times, const MidiCutBuffer& mcb)
 
                 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("Paste extended region from %1 to %2\n", region_end, end_frame));
 
-               trackview.session()->begin_reversible_command (_("paste"));
-
                 _region->clear_changes ();
                _region->set_length (end_frame, this);
                trackview.session()->add_command (new StatefulDiffCommand (_region));
        }
 
-       apply_diff ();
+       apply_diff (true);
+       
+       trackview.session()->commit_reversible_command ();
 }
 
 struct EventNoteTimeEarlyFirstComparator {
@@ -3148,7 +3142,8 @@ MidiRegionView::update_ghost_note (double x, double y)
        _ghost_note->note()->set_length (length);
        _ghost_note->note()->set_note (midi_stream_view()->y_to_note (y));
 
-       update_note (_ghost_note);
+       /* the ghost note does not appear in ghost regions, so pass false in here */
+       update_note (_ghost_note, false);
 
        show_verbose_canvas_cursor (_ghost_note->note ());
 }