Move Diskstream ownership to Track, so that Session no longer holds lists of Diskstre...
[ardour.git] / gtk2_ardour / editor_ops.cc
index 278aaf9cd663389a9b30bbd753759d85cf9b3bff..7f3aa7f7a84347feef185d86eb0fb86b05e562c7 100644 (file)
@@ -32,6 +32,7 @@
 #include "pbd/pthread_utils.h"
 #include "pbd/memento_command.h"
 #include "pbd/whitespace.h"
+#include "pbd/stateful_diff_command.h"
 
 #include <gtkmm2ext/utils.h>
 #include <gtkmm2ext/choice.h>
@@ -78,6 +79,7 @@
 #include "editor_routes.h"
 #include "editor_regions.h"
 #include "quantize_dialog.h"
+#include "interthread_progress_window.h"
 
 #include "i18n.h"
 
@@ -154,7 +156,13 @@ Editor::split_regions_at (nframes64_t where, RegionSelection& regions)
 
                boost::shared_ptr<Playlist> pl = (*a)->region()->playlist();
 
-               if (! pl->frozen()) {
+                if (!pl) {
+                        cerr << "region " << (*a)->region()->name() << " has no playlist!\n";
+                        a = tmp;
+                        continue;
+                }
+
+               if (!pl->frozen()) {
                        /* we haven't seen this playlist before */
 
                        /* remember used playlists so we can thaw them later */
@@ -168,10 +176,9 @@ Editor::split_regions_at (nframes64_t where, RegionSelection& regions)
                }
 
                if (pl) {
-                       XMLNode &before = pl->get_state();
+                        pl->clear_history ();
                        pl->split_region ((*a)->region(), where);
-                       XMLNode &after = pl->get_state();
-                       _session->add_command(new MementoCommand<Playlist>(*pl, &before, &after));
+                       _session->add_command (new StatefulDiffCommand (pl));
                }
 
                a = tmp;
@@ -323,10 +330,9 @@ Editor::nudge_forward (bool next, bool force_playhead)
                                distance = next_distance;
                        }
 
-                        XMLNode &before = r->playlist()->get_state();
+                        r->clear_history ();
                        r->set_position (r->position() + distance, this);
-                        XMLNode &after = r->playlist()->get_state();
-                       _session->add_command (new MementoCommand<Playlist>(*(r->playlist()), &before, &after));
+                       _session->add_command (new StatefulDiffCommand (r));
                }
 
                commit_reversible_command ();
@@ -403,16 +409,15 @@ Editor::nudge_backward (bool next, bool force_playhead)
                        if (next) {
                                distance = next_distance;
                        }
-
-                        XMLNode &before = r->playlist()->get_state();
+                        
+                        r->clear_history ();
 
                        if (r->position() > distance) {
                                r->set_position (r->position() - distance, this);
                        } else {
                                r->set_position (0, this);
                        }
-                        XMLNode &after = r->playlist()->get_state();
-                       _session->add_command(new MementoCommand<Playlist>(*(r->playlist()), &before, &after));
+                       _session->add_command (new StatefulDiffCommand (r));
                }
 
                commit_reversible_command ();
@@ -493,10 +498,9 @@ Editor::nudge_forward_capture_offset ()
                for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
                        boost::shared_ptr<Region> r ((*i)->region());
 
-                       XMLNode &before = r->playlist()->get_state();
+                        r->clear_history ();
                        r->set_position (r->position() + distance, this);
-                       XMLNode &after = r->playlist()->get_state();
-                       _session->add_command(new MementoCommand<Playlist>(*(r->playlist()), &before, &after));
+                       _session->add_command(new StatefulDiffCommand (r));
                }
 
                commit_reversible_command ();
@@ -523,15 +527,14 @@ Editor::nudge_backward_capture_offset ()
                for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
                        boost::shared_ptr<Region> r ((*i)->region());
 
-                        XMLNode &before = r->playlist()->get_state();
+                        r->clear_history ();
 
                        if (r->position() > distance) {
                                r->set_position (r->position() - distance, this);
                        } else {
                                r->set_position (0, this);
                        }
-                        XMLNode &after = r->playlist()->get_state();
-                       _session->add_command(new MementoCommand<Playlist>(*(r->playlist()), &before, &after));
+                       _session->add_command(new StatefulDiffCommand (r));
                }
 
                commit_reversible_command ();
@@ -634,8 +637,8 @@ Editor::build_region_boundary_cache ()
                        RouteTimeAxisView *rtav;
 
                        if (ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0 ) {
-                               if (rtav->get_diskstream() != 0) {
-                                       speed = rtav->get_diskstream()->speed();
+                               if (rtav->track() != 0) {
+                                       speed = rtav->track()->speed();
                                }
                        }
 
@@ -689,8 +692,8 @@ Editor::find_next_region (nframes64_t frame, RegionPoint point, int32_t dir, Tra
 
                track_speed = 1.0f;
                if ( (rtav = dynamic_cast<RouteTimeAxisView*>(*i)) != 0 ) {
-                       if (rtav->get_diskstream()!=0)
-                               track_speed = rtav->get_diskstream()->speed();
+                       if (rtav->track()!=0)
+                               track_speed = rtav->track()->speed();
                }
 
                track_frame = session_frame_to_track_frame(frame, track_speed);
@@ -820,7 +823,6 @@ Editor::cursor_to_region_boundary (bool with_selection, int32_t dir)
                return;
        }
 
-
        _session->request_locate (target);
 }
 
@@ -891,8 +893,8 @@ Editor::cursor_to_region_point (EditorCursor* cursor, RegionPoint point, int32_t
        RouteTimeAxisView *rtav;
 
        if ( ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0 ) {
-               if (rtav->get_diskstream() != 0) {
-                       speed = rtav->get_diskstream()->speed();
+               if (rtav->track() != 0) {
+                       speed = rtav->track()->speed();
                }
        }
 
@@ -1088,8 +1090,8 @@ Editor::selected_marker_to_region_point (RegionPoint point, int32_t dir)
        RouteTimeAxisView *rtav;
 
        if (ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0) {
-               if (rtav->get_diskstream() != 0) {
-                       speed = rtav->get_diskstream()->speed();
+               if (rtav->track() != 0) {
+                       speed = rtav->track()->speed();
                }
        }
 
@@ -1554,7 +1556,7 @@ Editor::temporal_zoom (gdouble fpu)
 
        /* XXX this limit is also in ::set_frames_per_unit() */
 
-       if (frames_per_unit <= 2.0 && fpu <= frames_per_unit) {
+       if (frames_per_unit <= 1.0 && fpu <= frames_per_unit) {
                return;
        }
 
@@ -1587,11 +1589,8 @@ Editor::temporal_zoom (gdouble fpu)
                break;
 
        case ZoomFocusPlayhead:
-               /* try to keep the playhead in the same place */
-
-               where = playhead_cursor->current_frame;
-
-               l = - ((new_page_size * ((where - current_leftmost)/(double)current_page)) - where);
+               /* centre playhead */
+               l = playhead_cursor->current_frame - (new_page_size * 0.5);
 
                if (l < 0) {
                        leftmost_after_zoom = 0;
@@ -2229,9 +2228,9 @@ Editor::insert_region_list_drag (boost::shared_ptr<Region> region, int x, int y)
        snap_to (where);
 
        begin_reversible_command (_("insert dragged region"));
-        XMLNode &before = playlist->get_state();
+        playlist->clear_history ();
        playlist->add_region (RegionFactory::create (region), where, 1.0);
-       _session->add_command(new MementoCommand<Playlist>(*playlist, &before, &playlist->get_state()));
+       _session->add_command(new StatefulDiffCommand (playlist));
        commit_reversible_command ();
 }
 
@@ -2307,9 +2306,9 @@ Editor::insert_region_list_selection (float times)
        }
 
        begin_reversible_command (_("insert region"));
-       XMLNode &before = playlist->get_state();
+        playlist->clear_history ();
        playlist->add_region ((RegionFactory::create (region)), get_preferred_edit_position(), times);
-       _session->add_command(new MementoCommand<Playlist>(*playlist, &before, &playlist->get_state()));
+       _session->add_command(new StatefulDiffCommand (playlist));
        commit_reversible_command ();
 }
 
@@ -2514,8 +2513,8 @@ Editor::rename_region()
        d.get_vbox()->set_border_width (12);
        d.get_vbox()->pack_start (hbox, false, false);
 
-       d.add_button(Gtk::Stock::OK, Gtk::RESPONSE_OK);
        d.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
+       d.add_button(Gtk::Stock::OK, Gtk::RESPONSE_OK);
 
        d.set_size_request (300, -1);
        d.set_position (Gtk::WIN_POS_MOUSE);
@@ -2604,39 +2603,6 @@ Editor::audition_playlist_region_standalone (boost::shared_ptr<Region> region)
        _session->audition_region (region);
 }
 
-void
-Editor::build_interthread_progress_window ()
-{
-       interthread_progress_window = new ArdourDialog (X_("interthread progress"), true);
-
-       interthread_progress_bar.set_orientation (Gtk::PROGRESS_LEFT_TO_RIGHT);
-
-       interthread_progress_window->set_border_width (12);
-       interthread_progress_window->get_vbox()->set_spacing (6);
-
-       interthread_progress_label.set_alignment (0.5, 0.5);
-
-       interthread_progress_window->get_vbox()->pack_start (interthread_progress_label, false, false);
-       interthread_progress_window->get_vbox()->pack_start (interthread_progress_bar,false, false);
-
-       // GTK2FIX: this button needs a modifiable label
-
-       Button* b = interthread_progress_window->add_button (Stock::CANCEL, RESPONSE_CANCEL);
-       b->signal_clicked().connect (sigc::mem_fun(*this, &Editor::interthread_cancel_clicked));
-
-       interthread_cancel_button.add (interthread_cancel_label);
-
-       interthread_progress_window->set_default_size (200, 100);
-}
-
-void
-Editor::interthread_cancel_clicked ()
-{
-       if (current_interthread_info) {
-               current_interthread_info->cancel = true;
-       }
-}
-
 void
 Editor::region_from_selection ()
 {
@@ -2670,9 +2636,16 @@ Editor::region_from_selection ()
                }
 
                internal_start = start - current->position();
-               _session->region_name (new_name, current->name(), true);
-               boost::shared_ptr<Region> region (RegionFactory::create (current,
-                               internal_start, selection_cnt, new_name));
+               RegionFactory::region_name (new_name, current->name(), true);
+
+               PropertyList plist; 
+               
+               plist.add (ARDOUR::Properties::start, current->start() + internal_start);
+               plist.add (ARDOUR::Properties::length, selection_cnt);
+               plist.add (ARDOUR::Properties::name, new_name);
+               plist.add (ARDOUR::Properties::layer, 0);
+
+               boost::shared_ptr<Region> region (RegionFactory::create (current, plist));
        }
 }
 
@@ -2703,10 +2676,15 @@ Editor::create_region_from_selection (vector<boost::shared_ptr<Region> >& new_re
                }
 
                internal_start = start - current->position();
-               _session->region_name (new_name, current->name(), true);
+               RegionFactory::region_name (new_name, current->name(), true);
 
-               new_regions.push_back (RegionFactory::create (current,
-                                       internal_start, end - start + 1, new_name));
+               PropertyList plist; 
+               
+               plist.add (ARDOUR::Properties::start, current->start() + internal_start);
+               plist.add (ARDOUR::Properties::length, end - start + 1);
+               plist.add (ARDOUR::Properties::name, new_name);
+
+               new_regions.push_back (RegionFactory::create (current, plist));
        }
 }
 
@@ -2804,21 +2782,17 @@ Editor::separate_regions_between (const TimeSelection& ts)
 
                                /* no edits to destructive tracks */
 
-                               if (rtv->track()->diskstream()->destructive()) {
+                               if (rtv->track()->destructive()) {
                                        continue;
                                }
 
                                if ((playlist = rtv->playlist()) != 0) {
 
-                                       XMLNode *before;
-                                       bool got_some;
-
-                                       before = &(playlist->get_state());
-                                       got_some = false;
+                                       playlist->clear_history ();
 
                                        /* XXX need to consider musical time selections here at some point */
 
-                                       double speed = rtv->get_diskstream()->speed();
+                                       double speed = rtv->track()->speed();
 
 
                                        for (list<AudioRange>::const_iterator t = ts.begin(); t != ts.end(); ++t) {
@@ -2834,25 +2808,18 @@ Editor::separate_regions_between (const TimeSelection& ts)
 
                                                if (!latest_regionviews.empty()) {
 
-                                                       got_some = true;
-
                                                        rtv->view()->foreach_regionview (sigc::bind (
                                                                                sigc::ptr_fun (add_if_covered),
                                                                                &(*t), &new_selection));
-
+                                                        
                                                        if (!in_command) {
                                                                begin_reversible_command (_("separate"));
                                                                in_command = true;
                                                        }
 
-                                                       _session->add_command(new MementoCommand<Playlist>(
-                                                                       *playlist, before, &playlist->get_state()));
+                                                       _session->add_command(new StatefulDiffCommand (playlist));
                                                }
                                        }
-
-                                       if (!got_some) {
-                                               delete before;
-                                       }
                                }
                        }
                }
@@ -2972,7 +2939,7 @@ Editor::crop_region_to (nframes64_t start, nframes64_t end)
 
                        boost::shared_ptr<Track> t = rtv->track();
 
-                       if (t != 0 && ! t->diskstream()->destructive()) {
+                       if (t != 0 && ! t->destructive()) {
 
                                if ((playlist = rtv->playlist()) != 0) {
                                        playlists.push_back (playlist);
@@ -3014,10 +2981,9 @@ Editor::crop_region_to (nframes64_t start, nframes64_t end)
                the_end = min (end, the_end);
                cnt = the_end - the_start + 1;
 
-               XMLNode &before = (*i)->get_state();
+                region->clear_history ();
                region->trim_to (the_start, cnt, this);
-               XMLNode &after = (*i)->get_state();
-               _session->add_command (new MementoCommand<Playlist>(*(*i), &before, &after));
+               _session->add_command (new StatefulDiffCommand (region));
        }
 
        commit_reversible_command ();
@@ -3055,9 +3021,9 @@ Editor::region_fill_track ()
                        return;
                }
 
-               XMLNode &before = pl->get_state();
+                pl->clear_history ();
                pl->add_region (RegionFactory::create (region), region->last_frame(), times);
-               _session->add_command (new MementoCommand<Playlist>(*pl, &before, &pl->get_state()));
+               _session->add_command (new StatefulDiffCommand (pl));
        }
 
        commit_reversible_command ();
@@ -3099,9 +3065,9 @@ Editor::region_fill_selection ()
                        continue;
                }
 
-                XMLNode &before = playlist->get_state();
+                playlist->clear_history ();
                playlist->add_region (RegionFactory::create (region), start, times);
-               _session->add_command (new MementoCommand<Playlist>(*playlist, &before, &playlist->get_state()));
+               _session->add_command (new StatefulDiffCommand (playlist));
        }
 
        commit_reversible_command ();
@@ -3134,10 +3100,9 @@ Editor::set_sync_point (nframes64_t where, const RegionSelection& rs)
                        in_command = true;
                }
 
-               XMLNode &before = region->playlist()->get_state();
+                region->clear_history ();
                region->set_sync_position (where);
-               XMLNode &after = region->playlist()->get_state();
-               _session->add_command(new MementoCommand<Playlist>(*(region->playlist()), &before, &after));
+               _session->add_command(new StatefulDiffCommand (region));
        }
 
        if (in_command) {
@@ -3160,10 +3125,9 @@ Editor::remove_region_sync ()
        begin_reversible_command (_("remove sync"));
        for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
 
-                XMLNode &before = (*i)->region()->playlist()->get_state();
+                (*i)->region()->clear_history ();
                (*i)->region()->clear_sync_position ();
-                XMLNode &after = (*i)->region()->playlist()->get_state();
-               _session->add_command(new MementoCommand<Playlist>(*((*i)->region()->playlist()), &before, &after));
+               _session->add_command(new StatefulDiffCommand ((*i)->region()));
        }
        commit_reversible_command ();
 }
@@ -3181,10 +3145,9 @@ Editor::naturalize ()
 
        begin_reversible_command (_("naturalize"));
        for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
-                XMLNode &before = (*i)->region()->get_state();
+               (*i)->region()->clear_history ();
                (*i)->region()->move_to_natural_position (this);
-                XMLNode &after = (*i)->region()->get_state();
-               _session->add_command (new MementoCommand<Region>(*((*i)->region().get()), &before, &after));
+               _session->add_command (new StatefulDiffCommand ((*i)->region()));
        }
        commit_reversible_command ();
 }
@@ -3283,10 +3246,9 @@ Editor::align_selection_relative (RegionPoint point, nframes64_t position, const
 
        /* move first one specially */
 
-       XMLNode &before = r->playlist()->get_state();
+        r->clear_history ();
        r->set_position (pos, this);
-       XMLNode &after = r->playlist()->get_state();
-       _session->add_command(new MementoCommand<Playlist>(*(r->playlist()), &before, &after));
+       _session->add_command(new StatefulDiffCommand (r));
 
        /* move rest by the same amount */
 
@@ -3296,16 +3258,15 @@ Editor::align_selection_relative (RegionPoint point, nframes64_t position, const
 
                boost::shared_ptr<Region> region ((*i)->region());
 
-                XMLNode &before = region->playlist()->get_state();
+                region->clear_history ();
 
                if (dir > 0) {
                        region->set_position (region->position() + distance, this);
                } else {
                        region->set_position (region->position() - distance, this);
                }
-
-                XMLNode &after = region->playlist()->get_state();
-               _session->add_command(new MementoCommand<Playlist>(*(region->playlist()), &before, &after));
+                
+               _session->add_command(new StatefulDiffCommand (region));
 
        }
 
@@ -3339,7 +3300,7 @@ Editor::align_region (boost::shared_ptr<Region> region, RegionPoint point, nfram
 void
 Editor::align_region_internal (boost::shared_ptr<Region> region, RegionPoint point, nframes64_t position)
 {
-       XMLNode &before = region->playlist()->get_state();
+       region->clear_history ();
 
        switch (point) {
        case SyncPoint:
@@ -3357,8 +3318,7 @@ Editor::align_region_internal (boost::shared_ptr<Region> region, RegionPoint poi
                break;
        }
 
-       XMLNode &after = region->playlist()->get_state();
-       _session->add_command(new MementoCommand<Playlist>(*(region->playlist()), &before, &after));
+       _session->add_command(new StatefulDiffCommand (region));
 }
 
 void
@@ -3389,15 +3349,13 @@ Editor::trim_region (bool front)
 
        for (list<RegionView*>::const_iterator i = rs.by_layer().begin(); i != rs.by_layer().end(); ++i) {
                if (!(*i)->region()->locked()) {
-                       boost::shared_ptr<Playlist> pl = (*i)->region()->playlist();
-                       XMLNode &before = pl->get_state();
+                        (*i)->region()->clear_history ();
                        if (front) {
                                (*i)->region()->trim_front (where, this);
                        } else {
                                (*i)->region()->trim_end (where, this);
                        }
-                       XMLNode &after = pl->get_state();
-                       _session->add_command(new MementoCommand<Playlist>(*pl.get(), &before, &after));
+                       _session->add_command (new StatefulDiffCommand ((*i)->region()));
                }
        }
 
@@ -3453,18 +3411,16 @@ Editor::trim_region_to_location (const Location& loc, const char* str)
                nframes64_t start;
                nframes64_t end;
 
-               if (tav->get_diskstream() != 0) {
-                       speed = tav->get_diskstream()->speed();
+               if (tav->track() != 0) {
+                       speed = tav->track()->speed();
                }
 
                start = session_frame_to_track_frame (loc.start(), speed);
                end = session_frame_to_track_frame (loc.end(), speed);
-
-               XMLNode &before = rv->region()->playlist()->get_state();
+                
+               rv->region()->clear_history ();
                rv->region()->trim_to (start, (end - start), this);
-               XMLNode &after = rv->region()->playlist()->get_state();
-               _session->add_command(new MementoCommand<Playlist>(
-                               *(rv->region()->playlist()), &before, &after));
+               _session->add_command(new StatefulDiffCommand (rv->region()));
        }
 
        commit_reversible_command ();
@@ -3496,15 +3452,13 @@ Editor::trim_region_to_edit_point ()
 
                float speed = 1.0;
 
-               if (tav->get_diskstream() != 0) {
-                       speed = tav->get_diskstream()->speed();
+               if (tav->track() != 0) {
+                       speed = tav->track()->speed();
                }
 
-               XMLNode &before = rv->region()->playlist()->get_state();
+                rv->region()->clear_history ();
                rv->region()->trim_end (session_frame_to_track_frame(where, speed), this);
-               XMLNode &after = rv->region()->playlist()->get_state();
-               _session->add_command(new MementoCommand<Playlist>(
-                               *(rv->region()->playlist()), &before, &after));
+               _session->add_command(new StatefulDiffCommand (rv->region()));
        }
 
        commit_reversible_command ();
@@ -3536,15 +3490,13 @@ Editor::trim_region_from_edit_point ()
 
                float speed = 1.0;
 
-               if (tav->get_diskstream() != 0) {
-                       speed = tav->get_diskstream()->speed();
+               if (tav->track() != 0) {
+                       speed = tav->track()->speed();
                }
 
-               XMLNode &before = rv->region()->playlist()->get_state();
+                rv->region()->clear_history ();
                rv->region()->trim_front (session_frame_to_track_frame(where, speed), this);
-               XMLNode &after = rv->region()->playlist()->get_state();
-               _session->add_command(new MementoCommand<Playlist>(
-                               *(rv->region()->playlist()), &before, &after));
+               _session->add_command(new StatefulDiffCommand (rv->region()));
        }
 
        commit_reversible_command ();
@@ -3589,15 +3541,15 @@ Editor::trim_to_region(bool forward)
 
                float speed = 1.0;
 
-               if (atav->get_diskstream() != 0) {
-                       speed = atav->get_diskstream()->speed();
+               if (atav->track() != 0) {
+                       speed = atav->track()->speed();
                }
 
 
                boost::shared_ptr<Region> region = arv->region();
                boost::shared_ptr<Playlist> playlist (region->playlist());
 
-               XMLNode &before = playlist->get_state();
+                region->clear_history ();
 
                if(forward){
 
@@ -3608,7 +3560,7 @@ Editor::trim_to_region(bool forward)
                    }
 
                    region->trim_end((nframes64_t) (next_region->first_frame() * speed), this);
-                   arv->region_changed (Change (LengthChanged));
+                   arv->region_changed (PropertyChange (ARDOUR::Properties::length));
                }
                else {
 
@@ -3619,11 +3571,11 @@ Editor::trim_to_region(bool forward)
                    }
 
                    region->trim_front((nframes64_t) ((next_region->last_frame() + 1) * speed), this);
-                   arv->region_changed (Change (LengthChanged|PositionChanged|StartChanged));
+
+                   arv->region_changed (ARDOUR::bounds_change);
                }
 
-               XMLNode &after = playlist->get_state();
-               _session->add_command(new MementoCommand<Playlist>(*playlist, &before, &after));
+               _session->add_command(new StatefulDiffCommand (region));
        }
 
        commit_reversible_command ();
@@ -3650,18 +3602,11 @@ Editor::_freeze_thread (void* arg)
 void*
 Editor::freeze_thread ()
 {
-       clicked_routeview->audio_track()->freeze (*current_interthread_info);
+       clicked_routeview->audio_track()->freeze_me (*current_interthread_info);
        current_interthread_info->done = true;
        return 0;
 }
 
-gint
-Editor::freeze_progress_timeout (void */*arg*/)
-{
-       interthread_progress_bar.set_fraction (current_interthread_info->progress);
-       return !(current_interthread_info->done || current_interthread_info->cancel);
-}
-
 void
 Editor::freeze_route ()
 {
@@ -3670,21 +3615,9 @@ Editor::freeze_route ()
        }
 
        InterThreadInfo itt;
-
-       if (interthread_progress_window == 0) {
-               build_interthread_progress_window ();
-       }
-
-       interthread_progress_window->set_title (_("Freeze"));
-       interthread_progress_window->set_position (Gtk::WIN_POS_MOUSE);
-       interthread_progress_window->show_all ();
-       interthread_progress_bar.set_fraction (0.0f);
-       interthread_progress_label.set_text ("");
-       interthread_cancel_label.set_text (_("Cancel Freeze"));
        current_interthread_info = &itt;
 
-       interthread_progress_connection =
-         Glib::signal_timeout().connect (sigc::bind (sigc::mem_fun(*this, &Editor::freeze_progress_timeout), (gpointer) 0), 100);
+       InterthreadProgressWindow ipw (current_interthread_info, _("Freeze"), _("Cancel Freeze"));
 
        itt.done = false;
        itt.cancel = false;
@@ -3698,8 +3631,6 @@ Editor::freeze_route ()
                gtk_main_iteration ();
        }
 
-       interthread_progress_connection.disconnect ();
-       interthread_progress_window->hide_all ();
        current_interthread_info = 0;
        track_canvas->get_window()->set_cursor (*current_canvas_cursor);
 }
@@ -3739,7 +3670,7 @@ Editor::bounce_range_selection (bool replace, bool enable_processing)
                itt.cancel = false;
                itt.progress = false;
 
-                XMLNode &before = playlist->get_state();
+                playlist->clear_history ();
                boost::shared_ptr<Region> r = rtv->track()->bounce_range (start, start+cnt, itt, enable_processing);
 
                if (replace) {
@@ -3749,8 +3680,7 @@ Editor::bounce_range_selection (bool replace, bool enable_processing)
                        playlist->add_region (r, start);
                }
 
-                XMLNode &after = playlist->get_state();
-               _session->add_command (new MementoCommand<Playlist> (*playlist, &before, &after));
+               _session->add_command (new StatefulDiffCommand (playlist));
        }
 
        commit_reversible_command ();
@@ -3957,17 +3887,6 @@ Editor::cut_copy_midi (CutCopyOp op)
        }
 }
 
-struct PlaylistState {
-    boost::shared_ptr<Playlist> playlist;
-    XMLNode*  before;
-};
-
-struct lt_playlist {
-    bool operator () (const PlaylistState& a, const PlaylistState& b) {
-           return a.playlist < b.playlist;
-    }
-};
-
 struct PlaylistMapping {
     TimeAxisView* tv;
     boost::shared_ptr<Playlist> pl;
@@ -3986,10 +3905,9 @@ Editor::remove_clicked_region ()
        boost::shared_ptr<Playlist> playlist = clicked_routeview->playlist();
 
        begin_reversible_command (_("remove region"));
-        XMLNode &before = playlist->get_state();
+        playlist->clear_history ();
        playlist->remove_region (clicked_regionview->region());
-        XMLNode &after = playlist->get_state();
-       _session->add_command(new MementoCommand<Playlist>(*playlist, &before, &after));
+       _session->add_command(new StatefulDiffCommand (playlist));
        commit_reversible_command ();
 }
 
@@ -4026,7 +3944,7 @@ Editor::remove_selected_regions ()
                regions_to_remove.push_back ((*i)->region());
        }
 
-       vector<PlaylistState> playlists;
+        vector<boost::shared_ptr<Playlist> > playlists;
 
        for (list<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
 
@@ -4037,33 +3955,31 @@ Editor::remove_selected_regions ()
                        continue;
                }
 
-               vector<PlaylistState>::iterator i;
+               vector<boost::shared_ptr<Playlist> >::iterator i;
 
-               //only take state if this is a new playlist.
+               //only prep history if this is a new playlist.
                for (i = playlists.begin(); i != playlists.end(); ++i) {
-                       if ((*i).playlist == playlist) {
+                       if ((*i) == playlist) {
                                break;
                        }
                }
 
                if (i == playlists.end()) {
 
-                       PlaylistState before;
-                       before.playlist = playlist;
-                       before.before = &playlist->get_state();
-
+                        playlist->clear_history ();
                        playlist->freeze ();
-                       playlists.push_back(before);
+
+                       playlists.push_back (playlist);
                }
 
                playlist->remove_region (*rl);
        }
 
-       vector<PlaylistState>::iterator pl;
+       vector<boost::shared_ptr<Playlist> >::iterator pl;
 
        for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
-               (*pl).playlist->thaw ();
-               _session->add_command(new MementoCommand<Playlist>(*(*pl).playlist, (*pl).before, &(*pl).playlist->get_state()));
+               (*pl)->thaw ();
+               _session->add_command(new StatefulDiffCommand (*pl));
        }
 
        commit_reversible_command ();
@@ -4083,8 +3999,8 @@ Editor::cut_copy_regions (CutCopyOp op, RegionSelection& rs)
 
        nframes64_t first_position = max_frames;
 
-       set<PlaylistState, lt_playlist> freezelist;
-       pair<set<PlaylistState, lt_playlist>::iterator,bool> insert_result;
+       typedef set<boost::shared_ptr<Playlist> > FreezeList;
+        FreezeList freezelist;
 
        /* get ordering correct before we cut/copy */
 
@@ -4098,21 +4014,19 @@ Editor::cut_copy_regions (CutCopyOp op, RegionSelection& rs)
                        boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
 
                        if (pl) {
-                               set<PlaylistState, lt_playlist>::iterator fl;
+                               FreezeList::iterator fl;
 
                                //only take state if this is a new playlist.
                                for (fl = freezelist.begin(); fl != freezelist.end(); ++fl) {
-                                       if ((*fl).playlist == pl) {
+                                       if ((*fl) == pl) {
                                                break;
                                        }
                                }
 
                                if (fl == freezelist.end()) {
-                                       PlaylistState before;
-                                       before.playlist = pl;
-                                       before.before = &pl->get_state();
+                                        pl->clear_history();
                                        pl->freeze ();
-                                       insert_result = freezelist.insert (before);
+                                       freezelist.insert (pl);
                                }
                        }
                }
@@ -4203,10 +4117,10 @@ Editor::cut_copy_regions (CutCopyOp op, RegionSelection& rs)
        if (!foo.empty()) {
                cut_buffer->set (foo);
        }
-
-       for (set<PlaylistState, lt_playlist>::iterator pl = freezelist.begin(); pl != freezelist.end(); ++pl) {
-               (*pl).playlist->thaw ();
-               _session->add_command (new MementoCommand<Playlist>(*(*pl).playlist, (*pl).before, &(*pl).playlist->get_state()));
+        
+       for (FreezeList::iterator pl = freezelist.begin(); pl != freezelist.end(); ++pl) {
+               (*pl)->thaw ();
+               _session->add_command (new StatefulDiffCommand (*pl));
        }
 }
 
@@ -4343,9 +4257,9 @@ Editor::duplicate_some_regions (RegionSelection& regions, float times)
                sigc::connection c = rtv->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view));
 
                playlist = (*i)->region()->playlist();
-                XMLNode &before = playlist->get_state();
+                playlist->clear_history ();
                playlist->duplicate (r, end_frame + (r->first_frame() - start_frame) + 1, times);
-               _session->add_command(new MementoCommand<Playlist>(*playlist, &before, &playlist->get_state()));
+               _session->add_command(new StatefulDiffCommand (playlist));
 
                c.disconnect ();
 
@@ -4384,10 +4298,9 @@ Editor::duplicate_selection (float times)
                if ((playlist = (*i)->playlist()) == 0) {
                        continue;
                }
-               XMLNode &before = playlist->get_state();
+                playlist->clear_history ();
                playlist->duplicate (*ri, selection->time[clicked_selection].end, times);
-               XMLNode &after = playlist->get_state();
-               _session->add_command (new MementoCommand<Playlist>(*playlist, &before, &after));
+               _session->add_command (new StatefulDiffCommand (playlist));
 
                ++ri;
                if (ri == new_regions.end()) {
@@ -4431,10 +4344,9 @@ void
 Editor::clear_playlist (boost::shared_ptr<Playlist> playlist)
 {
        begin_reversible_command (_("clear playlist"));
-        XMLNode &before = playlist->get_state();
+        playlist->clear_history ();
        playlist->clear ();
-        XMLNode &after = playlist->get_state();
-       _session->add_command (new MementoCommand<Playlist>(*playlist.get(), &before, &after));
+       _session->add_command (new StatefulDiffCommand (playlist));
        commit_reversible_command ();
 }
 
@@ -4468,10 +4380,20 @@ Editor::nudge_track (bool use_edit, bool forwards)
                        continue;
                }
 
-                XMLNode &before = playlist->get_state();
+                playlist->clear_history ();
+                playlist->clear_owned_history ();
+
                playlist->nudge_after (start, distance, forwards);
-                XMLNode &after = playlist->get_state();
-               _session->add_command (new MementoCommand<Playlist>(*playlist, &before, &after));
+                
+                vector<StatefulDiffCommand*> cmds;
+
+                playlist->rdiff (cmds);
+
+                for (vector<StatefulDiffCommand*>::iterator c = cmds.begin(); c != cmds.end(); ++c) {
+                        _session->add_command (*c);
+                }
+
+                _session->add_command (new StatefulDiffCommand (playlist));
        }
 
        commit_reversible_command ();
@@ -4547,9 +4469,10 @@ Editor::normalize_region ()
                AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
                if (!arv)
                        continue;
-               XMLNode &before = arv->region()->get_state();
+                arv->region()->clear_history ();
                arv->audio_region()->normalize_to (spin.get_value());
-               _session->add_command (new MementoCommand<Region>(*(arv->region().get()), &before, &arv->region()->get_state()));
+               _session->add_command (new StatefulDiffCommand (arv->region()));
+                                       
        }
 
        commit_reversible_command ();
@@ -4580,9 +4503,9 @@ Editor::reset_region_scale_amplitude ()
                AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
                if (!arv)
                        continue;
-               XMLNode &before = arv->region()->get_state();
+                arv->region()->clear_history ();
                arv->audio_region()->set_scale_amplitude (1.0f);
-               _session->add_command (new MementoCommand<Region>(*(arv->region().get()), &before, &arv->region()->get_state()));
+               _session->add_command (new StatefulDiffCommand (arv->region()));
        }
 
        commit_reversible_command ();
@@ -4607,10 +4530,12 @@ Editor::adjust_region_scale_amplitude (bool up)
 
        for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
                AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
-               if (!arv)
+               if (!arv) {
                        continue;
-               XMLNode &before = arv->region()->get_state();
+                }
 
+                arv->region()->clear_history ();
+                
                double fraction = gain_to_slider_position (arv->audio_region()->scale_amplitude ());
 
                if (up) {
@@ -4632,7 +4557,7 @@ Editor::adjust_region_scale_amplitude (bool up)
                }
 
                arv->audio_region()->set_scale_amplitude (fraction);
-               _session->add_command (new MementoCommand<Region>(*(arv->region().get()), &before, &arv->region()->get_state()));
+               _session->add_command (new StatefulDiffCommand (arv->region()));
        }
 
        commit_reversible_command ();
@@ -4673,7 +4598,7 @@ Editor::strip_region_silence ()
                }
        }
 
-       StripSilenceDialog d (ar);
+       StripSilenceDialog d (_session, ar);
        int const r = d.run ();
 
        if (r == Gtk::RESPONSE_OK) {
@@ -4778,8 +4703,8 @@ Editor::apply_filter (Filter& filter, string command)
 
                        if (arv->audio_region()->apply (filter) == 0) {
 
-                               XMLNode &before = playlist->get_state();
-
+                               playlist->clear_history ();
+                                
                                if (filter.results.empty ()) {
 
                                        /* no regions returned; remove the old one */
@@ -4801,8 +4726,7 @@ Editor::apply_filter (Filter& filter, string command)
 
                                }
 
-                               XMLNode &after = playlist->get_state();
-                               _session->add_command(new MementoCommand<Playlist>(*playlist, &before, &after));
+                               _session->add_command(new StatefulDiffCommand (playlist));
                        } else {
                                goto out;
                        }
@@ -4874,7 +4798,7 @@ Editor::brush (nframes64_t pos)
 void
 Editor::reset_region_gain_envelopes ()
 {
-       RegionSelection rs = get_equivalent_regions (selection->regions, RouteGroup::Edit);
+       RegionSelection rs = get_equivalent_regions (selection->regions, ARDOUR::Properties::edit.property_id);
 
        if (!_session || rs.empty()) {
                return;
@@ -4899,7 +4823,7 @@ Editor::reset_region_gain_envelopes ()
 void
 Editor::toggle_gain_envelope_visibility ()
 {
-       RegionSelection rs = get_equivalent_regions (selection->regions, RouteGroup::Edit);
+       RegionSelection rs = get_equivalent_regions (selection->regions, ARDOUR::Properties::edit.property_id);
 
        if (!_session || rs.empty()) {
                return;
@@ -4910,10 +4834,9 @@ Editor::toggle_gain_envelope_visibility ()
        for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
                AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
                if (arv) {
-                       XMLNode &before = arv->region()->get_state ();
+                        arv->region()->clear_history ();
                        arv->set_envelope_visible (!arv->envelope_visible());
-                       XMLNode &after = arv->region()->get_state ();
-                       _session->add_command (new MementoCommand<Region> (*(arv->region().get()), &before, &after));
+                       _session->add_command (new StatefulDiffCommand (arv->region()));
                }
        }
 
@@ -4923,7 +4846,7 @@ Editor::toggle_gain_envelope_visibility ()
 void
 Editor::toggle_gain_envelope_active ()
 {
-       RegionSelection rs = get_equivalent_regions (selection->regions, RouteGroup::Edit);
+       RegionSelection rs = get_equivalent_regions (selection->regions, ARDOUR::Properties::edit.property_id);
 
        if (!_session || rs.empty()) {
                return;
@@ -4934,10 +4857,9 @@ Editor::toggle_gain_envelope_active ()
        for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
                AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
                if (arv) {
-                       XMLNode &before = arv->region()->get_state ();
+                       arv->region()->clear_history ();
                        arv->audio_region()->set_envelope_active (!arv->audio_region()->envelope_active());
-                       XMLNode &after = arv->region()->get_state ();
-                       _session->add_command (new MementoCommand<Region> (*(arv->region().get()), &before, &after));
+                       _session->add_command (new StatefulDiffCommand (arv->region()));
                }
        }
 
@@ -4947,7 +4869,7 @@ Editor::toggle_gain_envelope_active ()
 void
 Editor::toggle_region_lock ()
 {
-       RegionSelection rs = get_equivalent_regions (selection->regions, RouteGroup::Edit);
+       RegionSelection rs = get_equivalent_regions (selection->regions, ARDOUR::Properties::edit.property_id);
 
        if (!_session || rs.empty()) {
                return;
@@ -4956,10 +4878,9 @@ Editor::toggle_region_lock ()
        _session->begin_reversible_command (_("region lock"));
 
        for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
-               XMLNode &before = (*i)->region()->get_state ();
+               (*i)->region()->clear_history ();
                (*i)->region()->set_locked (!(*i)->region()->locked());
-               XMLNode &after = (*i)->region()->get_state ();
-               _session->add_command (new MementoCommand<Region> (*((*i)->region().get()), &before, &after));
+               _session->add_command (new StatefulDiffCommand ((*i)->region()));
        }
 
        _session->commit_reversible_command ();
@@ -4968,7 +4889,7 @@ Editor::toggle_region_lock ()
 void
 Editor::set_region_lock_style (Region::PositionLockStyle ps)
 {
-       RegionSelection rs = get_equivalent_regions (selection->regions, RouteGroup::Edit);
+       RegionSelection rs = get_equivalent_regions (selection->regions, ARDOUR::Properties::edit.property_id);
 
        if (!_session || rs.empty()) {
                return;
@@ -4977,10 +4898,9 @@ Editor::set_region_lock_style (Region::PositionLockStyle ps)
        _session->begin_reversible_command (_("region lock style"));
 
        for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
-               XMLNode &before = (*i)->region()->get_state ();
+                (*i)->region()->clear_history ();
                (*i)->region()->set_position_lock_style (ps);
-               XMLNode &after = (*i)->region()->get_state ();
-               _session->add_command (new MementoCommand<Region> (*((*i)->region().get()), &before, &after));
+               _session->add_command (new StatefulDiffCommand ((*i)->region()));
        }
 
        _session->commit_reversible_command ();
@@ -4990,7 +4910,7 @@ Editor::set_region_lock_style (Region::PositionLockStyle ps)
 void
 Editor::toggle_region_mute ()
 {
-       RegionSelection rs = get_equivalent_regions (selection->regions, RouteGroup::Edit);
+       RegionSelection rs = get_equivalent_regions (selection->regions, ARDOUR::Properties::edit.property_id);
 
        if (!_session || rs.empty()) {
                return;
@@ -4999,10 +4919,9 @@ Editor::toggle_region_mute ()
        _session->begin_reversible_command (_("region mute"));
 
        for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
-               XMLNode &before = (*i)->region()->get_state ();
+               (*i)->region()->clear_history ();
                (*i)->region()->set_muted (!(*i)->region()->muted());
-               XMLNode &after = (*i)->region()->get_state ();
-               _session->add_command (new MementoCommand<Region> (*((*i)->region().get()), &before, &after));
+               _session->add_command (new StatefulDiffCommand ((*i)->region()));
        }
 
        _session->commit_reversible_command ();
@@ -5011,7 +4930,7 @@ Editor::toggle_region_mute ()
 void
 Editor::toggle_region_opaque ()
 {
-       RegionSelection rs = get_equivalent_regions (selection->regions, RouteGroup::Edit);
+       RegionSelection rs = get_equivalent_regions (selection->regions, ARDOUR::Properties::edit.property_id);
 
        if (!_session || rs.empty()) {
                return;
@@ -5020,10 +4939,9 @@ Editor::toggle_region_opaque ()
        _session->begin_reversible_command (_("region opacity"));
 
        for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
-               XMLNode &before = (*i)->region()->get_state ();
+               (*i)->region()->clear_history ();
                (*i)->region()->set_opaque (!(*i)->region()->opaque());
-               XMLNode &after = (*i)->region()->get_state ();
-               _session->add_command (new MementoCommand<Region> (*((*i)->region().get()), &before, &after));
+               _session->add_command (new StatefulDiffCommand ((*i)->region()));
        }
 
        _session->commit_reversible_command ();
@@ -5161,14 +5079,15 @@ Editor::toggle_fade_active (bool in)
                        have_switch = true;
                }
 
-               XMLNode &before = region->get_state();
+               region->clear_history ();
+
                if (in) {
                        region->set_fade_in_active (!yn);
                } else {
                        region->set_fade_out_active (!yn);
                }
-               XMLNode &after = region->get_state();
-               _session->add_command(new MementoCommand<AudioRegion>(*region.get(), &before, &after));
+               
+               _session->add_command(new StatefulDiffCommand (region));
        }
 
        commit_reversible_command ();
@@ -5261,13 +5180,10 @@ Editor::set_fade_in_active (bool yn)
 
 
                boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
-
-               XMLNode &before = ar->get_state();
-
+               
+                ar->clear_history ();
                ar->set_fade_in_active (yn);
-
-               XMLNode &after = ar->get_state();
-               _session->add_command(new MementoCommand<AudioRegion>(*ar, &before, &after));
+               _session->add_command (new StatefulDiffCommand (ar));
        }
 
        commit_reversible_command ();
@@ -5295,12 +5211,9 @@ Editor::set_fade_out_active (bool yn)
 
                boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
 
-               XMLNode &before = ar->get_state();
-
+                ar->clear_history ();
                ar->set_fade_out_active (yn);
-
-               XMLNode &after = ar->get_state();
-               _session->add_command(new MementoCommand<AudioRegion>(*ar, &before, &after));
+               _session->add_command(new StatefulDiffCommand (ar));
        }
 
        commit_reversible_command ();
@@ -5921,7 +5834,7 @@ Editor::split_region_at_points (boost::shared_ptr<Region> r, AnalysisFeatureList
 
        nframes64_t pos = r->position();
 
-       XMLNode& before (pl->get_state());
+        pl->clear_history ();
 
        x = positions.begin();
 
@@ -5961,13 +5874,20 @@ Editor::split_region_at_points (boost::shared_ptr<Region> r, AnalysisFeatureList
 
                string new_name;
 
-               if (_session->region_name (new_name, r->name())) {
+               if (RegionFactory::region_name (new_name, r->name())) {
                        break;
                }
 
                /* do NOT announce new regions 1 by one, just wait till they are all done */
 
-               boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), file_start, len, new_name, 0, Region::DefaultFlags, false);
+               PropertyList plist; 
+               
+               plist.add (ARDOUR::Properties::start, file_start);
+               plist.add (ARDOUR::Properties::length, len);
+               plist.add (ARDOUR::Properties::name, new_name);
+               plist.add (ARDOUR::Properties::layer, 0);
+
+               boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
                pl->add_region (nr, pos);
 
                pos += len;
@@ -5980,7 +5900,14 @@ Editor::split_region_at_points (boost::shared_ptr<Region> r, AnalysisFeatureList
                        file_start = r->start() + (pos - r->position());
                        len = r->last_frame() - pos;
 
-                       nr = RegionFactory::create (r->sources(), file_start, len, new_name, 0, Region::DefaultFlags);
+                       PropertyList plist2; 
+                       
+                       plist2.add (ARDOUR::Properties::start, file_start);
+                       plist2.add (ARDOUR::Properties::length, len);
+                       plist2.add (ARDOUR::Properties::name, new_name);
+                       plist2.add (ARDOUR::Properties::layer, 0);
+
+                       nr = RegionFactory::create (r->sources(), plist2); 
                        pl->add_region (nr, pos);
 
                        break;
@@ -5989,9 +5916,7 @@ Editor::split_region_at_points (boost::shared_ptr<Region> r, AnalysisFeatureList
 
        pl->thaw ();
 
-       XMLNode& after (pl->get_state());
-
-       _session->add_command (new MementoCommand<Playlist>(*pl, &before, &after));
+       _session->add_command (new StatefulDiffCommand (pl));
 }
 
 void
@@ -6012,9 +5937,9 @@ Editor::tab_to_transient (bool forward)
                        RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*t);
 
                        if (rtv) {
-                               boost::shared_ptr<Diskstream> ds = rtv->get_diskstream();
-                               if (ds) {
-                                       boost::shared_ptr<Playlist> pl = rtv->get_diskstream()->playlist ();
+                               boost::shared_ptr<Track> tr = rtv->track();
+                               if (tr) {
+                                       boost::shared_ptr<Playlist> pl = tr->playlist ();
                                        if (pl) {
                                                nframes64_t result = pl->find_next_transient (pos, forward ? 1 : -1);
 
@@ -6312,7 +6237,8 @@ Editor::insert_time (nframes64_t pos, nframes64_t frames, InsertTimeOption opt,
 
                if (pl) {
 
-                       XMLNode &before = pl->get_state();
+                       pl->clear_history ();
+                        pl->clear_owned_history ();
 
                        if (opt == SplitIntersected) {
                                pl->split (pos);
@@ -6320,9 +6246,17 @@ Editor::insert_time (nframes64_t pos, nframes64_t frames, InsertTimeOption opt,
 
                        pl->shift (pos, frames, (opt == MoveIntersected), ignore_music_glue);
 
-                       XMLNode &after = pl->get_state();
-
-                       _session->add_command (new MementoCommand<Playlist> (*pl, &before, &after));
+                        vector<StatefulDiffCommand*> cmds;
+                        
+                        pl->rdiff (cmds);
+                        
+                        cerr << "Shift generated " << cmds.size() << " sdc's\n";
+
+                        for (vector<StatefulDiffCommand*>::iterator c = cmds.begin(); c != cmds.end(); ++c) {
+                                _session->add_command (*c);
+                        }
+                        
+                       _session->add_command (new StatefulDiffCommand (pl));
                        commit = true;
                }