Paste to the source of a copy if there are no selected tracks (rather than using...
[ardour.git] / gtk2_ardour / editor_ops.cc
index 669a6096eba4d23ff72b99456e19efcc01e22b36..12ebeacdd8345dca9362100f02bfac56fc57f5a5 100644 (file)
@@ -80,6 +80,7 @@
 #include "editor_regions.h"
 #include "quantize_dialog.h"
 #include "interthread_progress_window.h"
+#include "insert_time_dialog.h"
 
 #include "i18n.h"
 
@@ -157,7 +158,6 @@ Editor::split_regions_at (nframes64_t where, RegionSelection& regions)
                boost::shared_ptr<Playlist> pl = (*a)->region()->playlist();
 
                 if (!pl) {
-                        cerr << "region " << (*a)->region()->name() << " has no playlist!\n";
                         a = tmp;
                         continue;
                 }
@@ -171,7 +171,7 @@ Editor::split_regions_at (nframes64_t where, RegionSelection& regions)
                }
 
                if (pl) {
-                        pl->clear_history ();
+                        pl->clear_changes ();
                        pl->split_region ((*a)->region(), where);
                        _session->add_command (new StatefulDiffCommand (pl));
                }
@@ -324,7 +324,7 @@ Editor::nudge_forward (bool next, bool force_playhead)
                                distance = next_distance;
                        }
 
-                        r->clear_history ();
+                        r->clear_changes ();
                        r->set_position (r->position() + distance, this);
                        _session->add_command (new StatefulDiffCommand (r));
                }
@@ -404,7 +404,7 @@ Editor::nudge_backward (bool next, bool force_playhead)
                                distance = next_distance;
                        }
                         
-                        r->clear_history ();
+                        r->clear_changes ();
 
                        if (r->position() > distance) {
                                r->set_position (r->position() - distance, this);
@@ -492,7 +492,7 @@ Editor::nudge_forward_capture_offset ()
                for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
                        boost::shared_ptr<Region> r ((*i)->region());
 
-                        r->clear_history ();
+                        r->clear_changes ();
                        r->set_position (r->position() + distance, this);
                        _session->add_command(new StatefulDiffCommand (r));
                }
@@ -521,7 +521,7 @@ Editor::nudge_backward_capture_offset ()
                for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
                        boost::shared_ptr<Region> r ((*i)->region());
 
-                        r->clear_history ();
+                        r->clear_changes ();
 
                        if (r->position() > distance) {
                                r->set_position (r->position() - distance, this);
@@ -553,7 +553,7 @@ Editor::move_to_end ()
 void
 Editor::build_region_boundary_cache ()
 {
-       nframes64_t pos = 0;
+       framepos_t pos = 0;
        vector<RegionPoint> interesting_points;
        boost::shared_ptr<Region> r;
        TrackViewList tracks;
@@ -596,8 +596,8 @@ Editor::build_region_boundary_cache ()
 
        while (pos < _session->current_end_frame() && !at_end) {
 
-               nframes64_t rpos;
-               nframes64_t lpos = max_frames;
+               framepos_t rpos;
+               framepos_t lpos = max_frames;
 
                for (vector<RegionPoint>::iterator p = interesting_points.begin(); p != interesting_points.end(); ++p) {
 
@@ -620,7 +620,6 @@ Editor::build_region_boundary_cache ()
 
                        case SyncPoint:
                                rpos = r->sync_position ();
-                               //r->adjust_to_sync (r->first_frame());
                                break;
 
                        default:
@@ -646,7 +645,7 @@ Editor::build_region_boundary_cache ()
                           to sort later.
                        */
 
-                       vector<nframes64_t>::iterator ri;
+                       vector<framepos_t>::iterator ri;
 
                        for (ri = region_boundary_cache.begin(); ri != region_boundary_cache.end(); ++ri) {
                                if (*ri == rpos) {
@@ -665,23 +664,29 @@ Editor::build_region_boundary_cache ()
        /* finally sort to be sure that the order is correct */
 
        sort (region_boundary_cache.begin(), region_boundary_cache.end());
+
+        cerr << "RBC contains " << region_boundary_cache.size() << endl;
+
+        for (vector<framepos_t>::iterator x = region_boundary_cache.begin(); x != region_boundary_cache.end(); ++x) {
+                cerr << "Region boundary @ " << *x << endl;
+        }
 }
 
 boost::shared_ptr<Region>
-Editor::find_next_region (nframes64_t frame, RegionPoint point, int32_t dir, TrackViewList& tracks, TimeAxisView **ontrack)
+Editor::find_next_region (framepos_t frame, RegionPoint point, int32_t dir, TrackViewList& tracks, TimeAxisView **ontrack)
 {
        TrackViewList::iterator i;
        nframes64_t closest = max_frames;
        boost::shared_ptr<Region> ret;
-       nframes64_t rpos = 0;
+       framepos_t rpos = 0;
 
        float track_speed;
-       nframes64_t track_frame;
+       framepos_t track_frame;
        RouteTimeAxisView *rtav;
 
        for (i = tracks.begin(); i != tracks.end(); ++i) {
 
-               nframes64_t distance;
+               framecnt_t distance;
                boost::shared_ptr<Region> r;
 
                track_speed = 1.0f;
@@ -707,7 +712,6 @@ Editor::find_next_region (nframes64_t frame, RegionPoint point, int32_t dir, Tra
 
                case SyncPoint:
                        rpos = r->sync_position ();
-                       // r->adjust_to_sync (r->first_frame());
                        break;
                }
 
@@ -731,17 +735,16 @@ Editor::find_next_region (nframes64_t frame, RegionPoint point, int32_t dir, Tra
        return ret;
 }
 
-nframes64_t
-Editor::find_next_region_boundary (nframes64_t pos, int32_t dir, const TrackViewList& tracks)
+framepos_t
+Editor::find_next_region_boundary (framepos_t pos, int32_t dir, const TrackViewList& tracks)
 {
-       nframes64_t distance = max_frames;
-       nframes64_t current_nearest = -1;
-
+       framecnt_t distance = max_frames;
+       framepos_t current_nearest = -1;
 
        for (TrackViewList::const_iterator i = tracks.begin(); i != tracks.end(); ++i) {
-               nframes64_t contender;
-               nframes64_t d;
-
+               framepos_t contender;
+               framecnt_t d;
+                
                RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
 
                if (!rtv) {
@@ -763,10 +766,10 @@ Editor::find_next_region_boundary (nframes64_t pos, int32_t dir, const TrackView
        return current_nearest;
 }
 
-nframes64_t
-Editor::get_region_boundary (nframes64_t pos, int32_t dir, bool with_selection, bool only_onscreen)
+framepos_t
+Editor::get_region_boundary (framepos_t pos, int32_t dir, bool with_selection, bool only_onscreen)
 {
-       nframes64_t target;
+       framepos_t target;
        TrackViewList tvl;
 
        if (with_selection && Config->get_region_boundaries_from_selected_tracks()) {
@@ -879,7 +882,6 @@ Editor::cursor_to_region_point (EditorCursor* cursor, RegionPoint point, int32_t
 
        case SyncPoint:
                pos = r->sync_position ();
-               // r->adjust_to_sync (r->first_frame());
                break;
        }
 
@@ -1900,7 +1902,7 @@ Editor::add_location_from_selection ()
        nframes64_t end = selection->time[clicked_selection].end;
 
        _session->locations()->next_available_name(rangename,"selection");
-       Location *location = new Location (start, end, rangename, Location::IsRangeMarker);
+       Location *location = new Location (*_session, start, end, rangename, Location::IsRangeMarker);
 
        _session->begin_reversible_command (_("add marker"));
         XMLNode &before = _session->locations()->get_state();
@@ -1921,7 +1923,7 @@ Editor::add_location_mark (nframes64_t where)
        if (!choose_new_marker_name(markername)) {
                return;
        }
-       Location *location = new Location (where, where, markername, Location::IsMark);
+       Location *location = new Location (*_session, where, where, markername, Location::IsMark);
        _session->begin_reversible_command (_("add marker"));
         XMLNode &before = _session->locations()->get_state();
        _session->locations()->add (location, true);
@@ -1950,13 +1952,11 @@ Editor::add_locations_from_audio_region ()
        _session->begin_reversible_command (rs.size () > 1 ? _("add markers") : _("add marker"));
        XMLNode &before = _session->locations()->get_state();
 
-       cerr << "Add locations\n";
-
        for (RegionSelection::iterator i = rs.begin (); i != rs.end (); ++i) {
 
                boost::shared_ptr<Region> region = (*i)->region ();
 
-               Location *location = new Location (region->position(), region->last_frame(), region->name(), Location::IsRangeMarker);
+               Location *location = new Location (*_session, region->position(), region->last_frame(), region->name(), Location::IsRangeMarker);
 
                _session->locations()->add (location, true);
        }
@@ -1994,10 +1994,8 @@ Editor::add_location_from_audio_region ()
                return;
        }
 
-       cerr << "Add location\n";
-
        // single range spanning all selected
-       Location *location = new Location (rs.start(), rs.end_frame(), markername, Location::IsRangeMarker);
+       Location *location = new Location (*_session, rs.start(), rs.end_frame(), markername, Location::IsRangeMarker);
        _session->locations()->add (location, true);
 
        XMLNode &after = _session->locations()->get_state();
@@ -2114,7 +2112,7 @@ Editor::set_mark ()
        if (!choose_new_marker_name(markername)) {
                return;
        }
-       _session->locations()->add (new Location (pos, 0, markername, Location::IsMark), true);
+       _session->locations()->add (new Location (*_session, pos, 0, markername, Location::IsMark), true);
 }
 
 void
@@ -2226,7 +2224,7 @@ Editor::insert_region_list_drag (boost::shared_ptr<Region> region, int x, int y)
        snap_to (where);
 
        begin_reversible_command (_("insert dragged region"));
-        playlist->clear_history ();
+        playlist->clear_changes ();
        playlist->add_region (RegionFactory::create (region), where, 1.0);
        _session->add_command(new StatefulDiffCommand (playlist));
        commit_reversible_command ();
@@ -2305,7 +2303,7 @@ Editor::insert_region_list_selection (float times)
        }
 
        begin_reversible_command (_("insert region"));
-        playlist->clear_history ();
+        playlist->clear_changes ();
        playlist->add_region ((RegionFactory::create (region)), get_preferred_edit_position(), times);
        _session->add_command(new StatefulDiffCommand (playlist));
        commit_reversible_command ();
@@ -2787,7 +2785,7 @@ Editor::separate_regions_between (const TimeSelection& ts)
 
                                if ((playlist = rtv->playlist()) != 0) {
 
-                                       playlist->clear_history ();
+                                       playlist->clear_changes ();
 
                                        /* XXX need to consider musical time selections here at some point */
 
@@ -2798,10 +2796,11 @@ Editor::separate_regions_between (const TimeSelection& ts)
 
                                                sigc::connection c = rtv->view()->RegionViewAdded.connect (
                                                                sigc::mem_fun(*this, &Editor::collect_new_region_view));
+
                                                latest_regionviews.clear ();
 
                                                playlist->partition ((nframes64_t)((*t).start * speed),
-                                                               (nframes64_t)((*t).end * speed), true);
+                                                               (nframes64_t)((*t).end * speed), false);
 
                                                c.disconnect ();
 
@@ -2815,6 +2814,15 @@ Editor::separate_regions_between (const TimeSelection& ts)
                                                                begin_reversible_command (_("separate"));
                                                                in_command = true;
                                                        }
+                                                        
+                                                        /* pick up changes to existing regions */
+
+                                                        vector<Command*> cmds;
+                                                        playlist->rdiff (cmds);
+                                                       _session->add_commands (cmds);
+
+                                                        /* pick up changes to the playlist itself (adds/removes)
+                                                         */
 
                                                        _session->add_command(new StatefulDiffCommand (playlist));
                                                }
@@ -2832,6 +2840,11 @@ Editor::separate_regions_between (const TimeSelection& ts)
        }
 }
 
+struct PlaylistState {
+    boost::shared_ptr<Playlist> playlist;
+    XMLNode*  before;
+};
+
 /** Take tracks from get_tracks_for_range_action and cut any regions
  *  on those tracks so that the tracks are empty over the time
  *  selection.
@@ -2897,6 +2910,85 @@ Editor::separate_regions_using_location (Location& loc)
        separate_regions_between (ts);
 }
 
+/** Separate regions under the selected region */
+void
+Editor::separate_under_selected_regions ()
+{
+       RegionSelection rs;
+       get_regions_for_action (rs);
+       
+       vector<PlaylistState> playlists;
+
+       if (!_session) {
+               return;
+       }
+
+       if (rs.empty()) {
+               return;
+       }
+
+       begin_reversible_command (_("separate region under"));
+
+       list<boost::shared_ptr<Region> > regions_to_remove;
+
+       for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
+               // we can't just remove the region(s) in this loop because
+               // this removes them from the RegionSelection, and they thus
+               // disappear from underneath the iterator, and the ++i above
+               // SEGVs in a puzzling fashion.
+
+               // so, first iterate over the regions to be removed from rs and
+               // add them to the regions_to_remove list, and then
+               // iterate over the list to actually remove them.
+
+               regions_to_remove.push_back ((*i)->region());
+       }
+
+       for (list<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
+
+               boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
+
+               if (!playlist) {
+                       // is this check necessary?
+                       continue;
+               }
+
+               vector<PlaylistState>::iterator i;
+
+               //only take state if this is a new playlist.
+               for (i = playlists.begin(); i != playlists.end(); ++i) {
+                       if ((*i).playlist == playlist) {
+                               break;
+                       }
+               }
+
+               if (i == playlists.end()) {
+
+                       PlaylistState before;
+                       before.playlist = playlist;
+                       before.before = &playlist->get_state();
+
+                       playlist->freeze ();
+                       playlists.push_back(before);
+               }
+
+               //Partition on the region bounds
+               playlist->partition ((*rl)->first_frame() - 1, (*rl)->last_frame() + 1, true);
+               
+               //Re-add region that was just removed due to the partition operation
+               playlist->add_region( (*rl), (*rl)->first_frame() );
+       }
+
+       vector<PlaylistState>::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()));
+       }
+
+       commit_reversible_command ();
+}
+
 void
 Editor::crop_region_to_selection ()
 {
@@ -2980,7 +3072,7 @@ Editor::crop_region_to (nframes64_t start, nframes64_t end)
                the_end = min (end, the_end);
                cnt = the_end - the_start + 1;
 
-                region->clear_history ();
+                region->clear_changes ();
                region->trim_to (the_start, cnt, this);
                _session->add_command (new StatefulDiffCommand (region));
        }
@@ -3020,7 +3112,7 @@ Editor::region_fill_track ()
                        return;
                }
 
-                pl->clear_history ();
+                pl->clear_changes ();
                pl->add_region (RegionFactory::create (region), region->last_frame(), times);
                _session->add_command (new StatefulDiffCommand (pl));
        }
@@ -3064,7 +3156,7 @@ Editor::region_fill_selection ()
                        continue;
                }
 
-                playlist->clear_history ();
+                playlist->clear_changes ();
                playlist->add_region (RegionFactory::create (region), start, times);
                _session->add_command (new StatefulDiffCommand (playlist));
        }
@@ -3099,7 +3191,7 @@ Editor::set_sync_point (nframes64_t where, const RegionSelection& rs)
                        in_command = true;
                }
 
-                region->clear_history ();
+                region->clear_changes ();
                region->set_sync_position (where);
                _session->add_command(new StatefulDiffCommand (region));
        }
@@ -3124,7 +3216,7 @@ Editor::remove_region_sync ()
        begin_reversible_command (_("remove sync"));
        for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
 
-                (*i)->region()->clear_history ();
+                (*i)->region()->clear_changes ();
                (*i)->region()->clear_sync_position ();
                _session->add_command(new StatefulDiffCommand ((*i)->region()));
        }
@@ -3144,7 +3236,7 @@ Editor::naturalize ()
 
        begin_reversible_command (_("naturalize"));
        for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
-               (*i)->region()->clear_history ();
+               (*i)->region()->clear_changes ();
                (*i)->region()->move_to_natural_position (this);
                _session->add_command (new StatefulDiffCommand ((*i)->region()));
        }
@@ -3245,7 +3337,7 @@ Editor::align_selection_relative (RegionPoint point, nframes64_t position, const
 
        /* move first one specially */
 
-        r->clear_history ();
+        r->clear_changes ();
        r->set_position (pos, this);
        _session->add_command(new StatefulDiffCommand (r));
 
@@ -3257,7 +3349,7 @@ Editor::align_selection_relative (RegionPoint point, nframes64_t position, const
 
                boost::shared_ptr<Region> region ((*i)->region());
 
-                region->clear_history ();
+                region->clear_changes ();
 
                if (dir > 0) {
                        region->set_position (region->position() + distance, this);
@@ -3299,7 +3391,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)
 {
-       region->clear_history ();
+       region->clear_changes ();
 
        switch (point) {
        case SyncPoint:
@@ -3348,12 +3440,15 @@ 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()) {
-                        (*i)->region()->clear_history ();
+                        
+                       (*i)->region()->clear_changes ();
+                       
                        if (front) {
                                (*i)->region()->trim_front (where, this);
                        } else {
                                (*i)->region()->trim_end (where, this);
                        }
+                       
                        _session->add_command (new StatefulDiffCommand ((*i)->region()));
                }
        }
@@ -3417,7 +3512,7 @@ Editor::trim_region_to_location (const Location& loc, const char* str)
                start = session_frame_to_track_frame (loc.start(), speed);
                end = session_frame_to_track_frame (loc.end(), speed);
                 
-               rv->region()->clear_history ();
+               rv->region()->clear_changes ();
                rv->region()->trim_to (start, (end - start), this);
                _session->add_command(new StatefulDiffCommand (rv->region()));
        }
@@ -3455,7 +3550,7 @@ Editor::trim_region_to_edit_point ()
                        speed = tav->track()->speed();
                }
 
-                rv->region()->clear_history ();
+                rv->region()->clear_changes ();
                rv->region()->trim_end (session_frame_to_track_frame(where, speed), this);
                _session->add_command(new StatefulDiffCommand (rv->region()));
        }
@@ -3493,7 +3588,7 @@ Editor::trim_region_from_edit_point ()
                        speed = tav->track()->speed();
                }
 
-                rv->region()->clear_history ();
+                rv->region()->clear_changes ();
                rv->region()->trim_front (session_frame_to_track_frame(where, speed), this);
                _session->add_command(new StatefulDiffCommand (rv->region()));
        }
@@ -3548,7 +3643,7 @@ Editor::trim_to_region(bool forward)
                boost::shared_ptr<Region> region = arv->region();
                boost::shared_ptr<Playlist> playlist (region->playlist());
 
-                region->clear_history ();
+                region->clear_changes ();
 
                if(forward){
 
@@ -3558,7 +3653,7 @@ Editor::trim_to_region(bool forward)
                        continue;
                    }
 
-                   region->trim_end((nframes64_t) (next_region->first_frame() * speed), this);
+                   region->trim_end((nframes64_t) ( (next_region->first_frame() - 1) * speed), this);
                    arv->region_changed (PropertyChange (ARDOUR::Properties::length));
                }
                else {
@@ -3661,7 +3756,9 @@ Editor::bounce_range_selection (bool replace, bool enable_processing)
 
                InterThreadInfo itt;
 
-                playlist->clear_history ();
+                playlist->clear_changes ();
+               playlist->clear_owned_changes ();
+               
                boost::shared_ptr<Region> r = rtv->track()->bounce_range (start, start+cnt, itt, enable_processing);
 
                if (replace) {
@@ -3671,7 +3768,11 @@ Editor::bounce_range_selection (bool replace, bool enable_processing)
                        playlist->add_region (r, start);
                }
 
-               _session->add_command (new StatefulDiffCommand (playlist));
+               vector<Command*> cmds;
+               playlist->rdiff (cmds);
+               _session->add_commands (cmds);
+
+                _session->add_command (new StatefulDiffCommand (playlist));
        }
 
        commit_reversible_command ();
@@ -3878,6 +3979,14 @@ Editor::cut_copy_midi (CutCopyOp op)
        }
 }
 
+
+
+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;
@@ -3896,7 +4005,7 @@ Editor::remove_clicked_region ()
        boost::shared_ptr<Playlist> playlist = clicked_routeview->playlist();
 
        begin_reversible_command (_("remove region"));
-        playlist->clear_history ();
+        playlist->clear_changes ();
        playlist->remove_region (clicked_regionview->region());
        _session->add_command(new StatefulDiffCommand (playlist));
        commit_reversible_command ();
@@ -3957,7 +4066,7 @@ Editor::remove_selected_regions ()
 
                if (i == playlists.end()) {
 
-                        playlist->clear_history ();
+                        playlist->clear_changes ();
                        playlist->freeze ();
 
                        playlists.push_back (playlist);
@@ -4015,7 +4124,7 @@ Editor::cut_copy_regions (CutCopyOp op, RegionSelection& rs)
                                }
 
                                if (fl == freezelist.end()) {
-                                        pl->clear_history();
+                                        pl->clear_changes();
                                        pl->freeze ();
                                        freezelist.insert (pl);
                                }
@@ -4104,10 +4213,15 @@ Editor::cut_copy_regions (CutCopyOp op, RegionSelection& rs)
                foo.push_back ((*i).pl);
        }
 
-
        if (!foo.empty()) {
                cut_buffer->set (foo);
        }
+
+       if (pmap.empty()) {
+               _last_cut_copy_source_track = 0;
+       } else {
+               _last_cut_copy_source_track = pmap.front().tv;
+       }
         
        for (FreezeList::iterator pl = freezelist.begin(); pl != freezelist.end(); ++pl) {
                (*pl)->thaw ();
@@ -4184,10 +4298,14 @@ Editor::paste_internal (nframes64_t position, float times)
        /* get everything in the correct order */
 
        if (!selection->tracks.empty()) {
+               /* there are some selected tracks, so paste to them */
                sort_track_selection ();
                ts = selection->tracks;
-       } else if (entered_track) {
-               ts.push_back (entered_track);
+       } else if (_last_cut_copy_source_track) {
+               /* otherwise paste to the track that the cut/copy came from;
+                  see discussion in mants #3333.
+               */
+               ts.push_back (_last_cut_copy_source_track);
        }
 
        for (nth = 0, i = ts.begin(); i != ts.end(); ++i, ++nth) {
@@ -4248,8 +4366,8 @@ 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();
-                playlist->clear_history ();
-               playlist->duplicate (r, end_frame + (r->first_frame() - start_frame) + 1, times);
+                playlist->clear_changes ();
+               playlist->duplicate (r, end_frame + (r->first_frame() - start_frame), times);
                _session->add_command(new StatefulDiffCommand (playlist));
 
                c.disconnect ();
@@ -4289,7 +4407,7 @@ Editor::duplicate_selection (float times)
                if ((playlist = (*i)->playlist()) == 0) {
                        continue;
                }
-                playlist->clear_history ();
+                playlist->clear_changes ();
                playlist->duplicate (*ri, selection->time[clicked_selection].end, times);
                _session->add_command (new StatefulDiffCommand (playlist));
 
@@ -4335,7 +4453,7 @@ void
 Editor::clear_playlist (boost::shared_ptr<Playlist> playlist)
 {
        begin_reversible_command (_("clear playlist"));
-        playlist->clear_history ();
+        playlist->clear_changes ();
        playlist->clear ();
        _session->add_command (new StatefulDiffCommand (playlist));
        commit_reversible_command ();
@@ -4371,18 +4489,15 @@ Editor::nudge_track (bool use_edit, bool forwards)
                        continue;
                }
 
-                playlist->clear_history ();
-                playlist->clear_owned_history ();
+                playlist->clear_changes ();
+                playlist->clear_owned_changes ();
 
                playlist->nudge_after (start, distance, forwards);
                 
-                vector<StatefulDiffCommand*> cmds;
+                vector<Command*> cmds;
 
                 playlist->rdiff (cmds);
-
-                for (vector<StatefulDiffCommand*>::iterator c = cmds.begin(); c != cmds.end(); ++c) {
-                        _session->add_command (*c);
-                }
+               _session->add_commands (cmds);
 
                 _session->add_command (new StatefulDiffCommand (playlist));
        }
@@ -4411,10 +4526,12 @@ Editor::remove_last_capture ()
 
                if (prompter.run () == 1) {
                        _session->remove_last_capture ();
+                        _regions->redisplay ();
                }
 
        } else {
                _session->remove_last_capture();
+                _regions->redisplay ();
        }
 }
 
@@ -4433,6 +4550,11 @@ Editor::normalize_region ()
        }
 
        Dialog dialog (rs.size() > 1 ? _("Normalize regions") : _("Normalize region"));
+
+       VBox vbox;
+       vbox.set_spacing (6);
+       vbox.set_border_width (6);
+       
        HBox hbox;
        hbox.set_spacing (6);
        hbox.set_border_width (6);
@@ -4444,9 +4566,18 @@ Editor::normalize_region ()
        hbox.pack_start (spin);
        spin.set_value (_last_normalization_value);
        hbox.pack_start (*manage (new Label (_("dbFS"))));
-       hbox.show_all ();
+       vbox.pack_start (hbox);
+
+       CheckButton* normalize_across_all = manage (new CheckButton (_("Normalize across all selected regions")));
+       vbox.pack_start (*normalize_across_all);
+       if (rs.size() <= 1) {
+               normalize_across_all->set_sensitive (false);
+       }
+
+       vbox.show_all ();
+       
        dialog.get_vbox()->set_spacing (12);
-       dialog.get_vbox()->pack_start (hbox);
+       dialog.get_vbox()->pack_start (vbox);
        dialog.add_button (Stock::CANCEL, RESPONSE_CANCEL);
        dialog.add_button (_("Normalize"), RESPONSE_ACCEPT);
 
@@ -4459,14 +4590,28 @@ Editor::normalize_region ()
        track_canvas->get_window()->set_cursor (*wait_cursor);
        gdk_flush ();
 
+       double maxamp = 0;
+       if (normalize_across_all->get_active ()) {
+               for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
+                       AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*r);
+                       if (!arv) {
+                               continue;
+                       }
+                       maxamp = max (maxamp, arv->audio_region()->maximum_amplitude ());
+               }
+       }
+       
        for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
-               AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
-               if (!arv)
+               AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*r);
+               if (!arv) {
                        continue;
-                arv->region()->clear_history ();
-               arv->audio_region()->normalize_to (spin.get_value());
+               }
+               arv->region()->clear_changes ();
+
+               double const amp = normalize_across_all->get_active() ? maxamp : arv->audio_region()->maximum_amplitude ();
+               
+               arv->audio_region()->normalize (amp, spin.get_value ());
                _session->add_command (new StatefulDiffCommand (arv->region()));
-                                       
        }
 
        commit_reversible_command ();
@@ -4497,7 +4642,7 @@ Editor::reset_region_scale_amplitude ()
                AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
                if (!arv)
                        continue;
-                arv->region()->clear_history ();
+                arv->region()->clear_changes ();
                arv->audio_region()->set_scale_amplitude (1.0f);
                _session->add_command (new StatefulDiffCommand (arv->region()));
        }
@@ -4528,7 +4673,7 @@ Editor::adjust_region_scale_amplitude (bool up)
                        continue;
                 }
 
-                arv->region()->clear_history ();
+                arv->region()->clear_changes ();
                 
                double fraction = gain_to_slider_position (arv->audio_region()->scale_amplitude ());
 
@@ -4605,7 +4750,7 @@ Command*
 Editor::apply_midi_note_edit_op_to_region (MidiOperator& op, MidiRegionView& mrv)
 {
        Evoral::Sequence<Evoral::MusicalTime>::Notes selected;
-       mrv.selection_as_notelist (selected);
+       mrv.selection_as_notelist (selected, true);
 
        vector<Evoral::Sequence<Evoral::MusicalTime>::Notes> v;
        v.push_back (selected);
@@ -4648,6 +4793,46 @@ Editor::apply_midi_note_edit_op (MidiOperator& op)
        rs.clear ();
 }
 
+void
+Editor::fork_region ()
+{
+       RegionSelection rs;
+
+       get_regions_for_action (rs);
+
+       if (rs.empty()) {
+               return;
+       }
+
+       begin_reversible_command (_("Fork Region(s)"));
+
+       track_canvas->get_window()->set_cursor (*wait_cursor);
+       gdk_flush ();
+
+       for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
+               RegionSelection::iterator tmp = r;
+               ++tmp;
+
+               MidiRegionView* const mrv = dynamic_cast<MidiRegionView*>(*r);
+
+               if (mrv) {
+                       boost::shared_ptr<Playlist> playlist = mrv->region()->playlist();
+                        boost::shared_ptr<MidiRegion> newregion = mrv->midi_region()->clone ();
+                        
+                        playlist->clear_changes ();
+                        playlist->replace_region (mrv->region(), newregion, mrv->region()->position());
+                        _session->add_command(new StatefulDiffCommand (playlist));
+               }
+
+               r = tmp;
+       }
+
+       commit_reversible_command ();
+       rs.clear ();
+
+       track_canvas->get_window()->set_cursor (*current_canvas_cursor);
+}
+
 void
 Editor::quantize_region ()
 {
@@ -4697,7 +4882,7 @@ Editor::apply_filter (Filter& filter, string command)
 
                        if (arv->audio_region()->apply (filter) == 0) {
 
-                               playlist->clear_history ();
+                               playlist->clear_changes ();
                                 
                                if (filter.results.empty ()) {
 
@@ -4828,7 +5013,7 @@ Editor::toggle_gain_envelope_visibility ()
        for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
                AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
                if (arv) {
-                        arv->region()->clear_history ();
+                        arv->region()->clear_changes ();
                        arv->set_envelope_visible (!arv->envelope_visible());
                        _session->add_command (new StatefulDiffCommand (arv->region()));
                }
@@ -4851,7 +5036,7 @@ Editor::toggle_gain_envelope_active ()
        for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
                AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
                if (arv) {
-                       arv->region()->clear_history ();
+                       arv->region()->clear_changes ();
                        arv->audio_region()->set_envelope_active (!arv->audio_region()->envelope_active());
                        _session->add_command (new StatefulDiffCommand (arv->region()));
                }
@@ -4872,7 +5057,7 @@ Editor::toggle_region_lock ()
        _session->begin_reversible_command (_("region lock"));
 
        for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
-               (*i)->region()->clear_history ();
+               (*i)->region()->clear_changes ();
                (*i)->region()->set_locked (!(*i)->region()->locked());
                _session->add_command (new StatefulDiffCommand ((*i)->region()));
        }
@@ -4892,8 +5077,8 @@ Editor::toggle_region_lock_style ()
        _session->begin_reversible_command (_("region lock style"));
 
        for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
-                (*i)->region()->clear_history ();
-               Region::PositionLockStyle const ns = (*i)->region()->positional_lock_style() == Region::AudioTime ? Region::MusicTime : Region::AudioTime;
+                (*i)->region()->clear_changes ();
+               PositionLockStyle const ns = (*i)->region()->position_lock_style() == AudioTime ? MusicTime : AudioTime;
                (*i)->region()->set_position_lock_style (ns);
                _session->add_command (new StatefulDiffCommand ((*i)->region()));
        }
@@ -4914,7 +5099,7 @@ Editor::toggle_region_mute ()
        _session->begin_reversible_command (_("region mute"));
 
        for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
-               (*i)->region()->clear_history ();
+               (*i)->region()->clear_changes ();
                (*i)->region()->set_muted (!(*i)->region()->muted());
                _session->add_command (new StatefulDiffCommand ((*i)->region()));
        }
@@ -4934,7 +5119,7 @@ Editor::toggle_region_opaque ()
        _session->begin_reversible_command (_("region opacity"));
 
        for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
-               (*i)->region()->clear_history ();
+               (*i)->region()->clear_changes ();
                (*i)->region()->set_opaque (!(*i)->region()->opaque());
                _session->add_command (new StatefulDiffCommand ((*i)->region()));
        }
@@ -4959,7 +5144,7 @@ Editor::toggle_record_enable ()
                        first = false;
                }
 
-               rtav->track()->set_record_enable(new_state, this);
+               rtav->track()->set_record_enable(new_state, this);
        }
 }
 
@@ -5074,7 +5259,7 @@ Editor::toggle_fade_active (bool in)
                        have_switch = true;
                }
 
-               region->clear_history ();
+               region->clear_changes ();
 
                if (in) {
                        region->set_fade_in_active (!yn);
@@ -5176,7 +5361,7 @@ Editor::set_fade_in_active (bool yn)
 
                boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
                
-                ar->clear_history ();
+                ar->clear_changes ();
                ar->set_fade_in_active (yn);
                _session->add_command (new StatefulDiffCommand (ar));
        }
@@ -5206,7 +5391,7 @@ Editor::set_fade_out_active (bool yn)
 
                boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
 
-                ar->clear_history ();
+                ar->clear_changes ();
                ar->set_fade_out_active (yn);
                _session->add_command(new StatefulDiffCommand (ar));
        }
@@ -5347,6 +5532,13 @@ Editor::set_playhead_cursor ()
 void
 Editor::split ()
 {
+        if (((mouse_mode == MouseRange) || 
+             (mouse_mode != MouseObject && _join_object_range_state == JOIN_OBJECT_RANGE_RANGE)) && 
+            !selection->time.empty()) {
+                separate_regions_between (selection->time);
+                return;
+        } 
+
        RegionSelection rs;
 
        get_regions_for_action (rs, true);
@@ -5809,6 +6001,7 @@ Editor::split_region_at_points (boost::shared_ptr<Region> r, AnalysisFeatureList
 
                int response = msg.run();
                msg.hide ();
+               
                switch (response) {
                case RESPONSE_OK:
                        break;
@@ -5827,19 +6020,10 @@ Editor::split_region_at_points (boost::shared_ptr<Region> r, AnalysisFeatureList
 
        AnalysisFeatureList::const_iterator x;
 
-       nframes64_t pos = r->position();
-
-        pl->clear_history ();
+        pl->clear_changes ();
 
        x = positions.begin();
 
-       while (x != positions.end()) {
-               if ((*x) > pos) {
-                       break;
-               }
-               ++x;
-       }
-
        if (x == positions.end()) {
                return;
        }
@@ -5847,18 +6031,26 @@ Editor::split_region_at_points (boost::shared_ptr<Region> r, AnalysisFeatureList
        pl->freeze ();
        pl->remove_region (r);
 
+       nframes64_t pos = 0;
+
        while (x != positions.end()) {
+         
+               /* deal with positons that are out of scope of present region bounds */
+               if (*x <= 0 || *x > r->length()){
+                       ++x;
+                       continue;
+               }
 
                /* file start = original start + how far we from the initial position ?
                 */
 
-               nframes64_t file_start = r->start() + (pos - r->position());
+               nframes64_t file_start = r->start() + pos;
 
                /* length = next position - current position
                 */
 
                nframes64_t len = (*x) - pos;
-
+               
                /* XXX we do we really want to allow even single-sample regions?
                   shouldn't we have some kind of lower limit on region size?
                */
@@ -5883,35 +6075,190 @@ Editor::split_region_at_points (boost::shared_ptr<Region> r, AnalysisFeatureList
                plist.add (ARDOUR::Properties::layer, 0);
 
                boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
-               pl->add_region (nr, pos);
+               pl->add_region (nr, r->position() + pos);
 
                pos += len;
                ++x;
+       }
 
-               if (*x > r->last_frame()) {
+       string new_name;
 
-                       /* add final fragment */
+       RegionFactory::region_name (new_name, r->name());
+       
+       /* Add the final region */
+       PropertyList plist; 
+               
+       plist.add (ARDOUR::Properties::start, r->start() + pos);
+       plist.add (ARDOUR::Properties::length, r->last_frame() - (r->position() + pos) + 1);
+       plist.add (ARDOUR::Properties::name, new_name);
+       plist.add (ARDOUR::Properties::layer, 0);
 
-                       file_start = r->start() + (pos - r->position());
-                       len = r->last_frame() - pos;
+       boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
+       pl->add_region (nr, r->position() + pos);
 
-                       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);
+       
+       pl->thaw ();
 
-                       nr = RegionFactory::create (r->sources(), plist2); 
-                       pl->add_region (nr, pos);
+       _session->add_command (new StatefulDiffCommand (pl));
+}
 
-                       break;
-               }
+void
+Editor::place_transient()
+{
+       if (!_session) {
+               return;
        }
 
-       pl->thaw ();
+       RegionSelection rs;
 
-       _session->add_command (new StatefulDiffCommand (pl));
+       get_regions_for_action (rs);
+
+       if (rs.empty()) {
+               return;
+       }
+       
+       nframes64_t where = get_preferred_edit_position();
+
+       _session->begin_reversible_command (_("place transient"));
+       
+       for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
+               framepos_t position = (*r)->region()->position();
+               (*r)->region()->add_transient(where - position);
+       }
+       
+       _session->commit_reversible_command ();
+}
+
+void
+Editor::remove_transient(ArdourCanvas::Item* item)
+{
+       if (!_session) {
+               return;
+       }
+
+       ArdourCanvas::SimpleLine* _line = reinterpret_cast<ArdourCanvas::SimpleLine*> (item);
+       assert (_line);
+
+       AudioRegionView* _arv = reinterpret_cast<AudioRegionView*> (item->get_data ("regionview"));
+       _arv->remove_transient(_line->property_x1());
+}
+
+void
+Editor::snap_regions_to_grid()
+{
+       if (!_session) {
+               return;
+       }
+
+       RegionSelection rs;
+
+       get_regions_for_action (rs);
+
+       if (rs.empty()) {
+               return;
+       }
+       
+       _session->begin_reversible_command (_("snap regions to grid"));
+       
+       for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
+               framepos_t start_frame = (*r)->region()->first_frame ();
+               snap_to (start_frame);
+               (*r)->region()->set_position (start_frame, this);
+       }
+       
+       _session->commit_reversible_command ();
+}
+
+void
+Editor::close_region_gaps()
+{      
+       if (!_session) {
+               return;
+       }
+
+       RegionSelection rs;
+
+       get_regions_for_action (rs);
+       
+       if (rs.empty()) {
+               return;
+       }
+       
+       Dialog dialog (rs.size() > 1 ? _("Conform regions") : _("Conform region"));
+       
+       HBox hbox_crossfade;
+       hbox_crossfade.set_spacing (10);
+       //hbox_crossfade.set_border_width (3);
+       hbox_crossfade.pack_start (*manage (new Label (_("Crossfade length:"))));
+       
+       SpinButton spin_crossfade (1, 0);
+       spin_crossfade.set_range (0, 15);
+       spin_crossfade.set_increments (1, 1);
+       spin_crossfade.set_value (3);
+       
+       hbox_crossfade.pack_start (spin_crossfade);
+       hbox_crossfade.pack_start (*manage (new Label (_("ms"))));
+       hbox_crossfade.show_all ();
+
+       HBox hbox_pullback;
+       
+       hbox_pullback.set_spacing (10);
+       //hbox_pullback.set_border_width (3);
+       hbox_pullback.pack_start (*manage (new Label (_("Pull-back length:"))));
+       
+       SpinButton spin_pullback (1, 0);
+       spin_pullback.set_range (0, 15);
+       spin_pullback.set_increments (1, 1);
+       spin_pullback.set_value (5);
+       
+       hbox_pullback.pack_start (spin_pullback);
+       hbox_pullback.pack_start (*manage (new Label (_("ms"))));
+       hbox_pullback.show_all ();
+       
+       dialog.get_vbox()->set_spacing (6);
+       dialog.get_vbox()->pack_start (hbox_crossfade);
+       dialog.get_vbox()->pack_start (hbox_pullback);
+       dialog.add_button (Stock::CANCEL, RESPONSE_CANCEL);
+       dialog.add_button (_("Ok"), RESPONSE_ACCEPT);
+
+       if (dialog.run () == RESPONSE_CANCEL) {
+               return;
+       }
+
+       nframes64_t crossfade_len  = spin_crossfade.get_value(); 
+       nframes64_t pull_back_frames = spin_pullback.get_value();
+
+       crossfade_len = lrintf (crossfade_len * _session->frame_rate()/1000);
+       pull_back_frames = lrintf (pull_back_frames * _session->frame_rate()/1000);
+
+       /* Iterate over the region list and make adjacent regions overlap by crossfade_len_ms */
+       
+       _session->begin_reversible_command (_("close region gaps"));
+               
+       int idx = 0;
+       boost::shared_ptr<Region> last_region;
+       
+       rs.sort_by_position_and_track();
+       
+       for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
+
+               nframes64_t position = (*r)->region()->position();
+         
+               if (idx == 0 || position < last_region->position()){
+                       last_region = (*r)->region();
+                       idx++;
+                       continue;
+               }
+               
+               (*r)->region()->trim_front( (position - pull_back_frames), this );
+               last_region->trim_end( (position - pull_back_frames + crossfade_len), this );
+               
+               last_region = (*r)->region();
+               
+               idx++;
+       }
+       
+       _session->commit_reversible_command ();
 }
 
 void
@@ -5990,6 +6337,7 @@ Editor::tab_to_transient (bool forward)
                }
        }
 }
+
 void
 Editor::playhead_forward_to_grid ()
 {
@@ -6016,7 +6364,7 @@ Editor::playhead_backward_to_grid ()
 }
 
 void
-Editor::set_track_height (uint32_t h)
+Editor::set_track_height (Height h)
 {
        TrackSelection& ts (selection->tracks);
 
@@ -6065,6 +6413,7 @@ Editor::remove_tracks ()
        const char* trackstr;
        const char* busstr;
        vector<boost::shared_ptr<Route> > routes;
+        bool special_bus = false;
 
        for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
                RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*x);
@@ -6076,8 +6425,30 @@ Editor::remove_tracks ()
                        }
                }
                routes.push_back (rtv->_route);
-       }
 
+                if (rtv->route()->is_master() || rtv->route()->is_monitor()) {
+                        special_bus = true;
+                }
+        }
+
+        if (special_bus && !Config->get_allow_special_bus_removal()) {
+                MessageDialog msg (_("That would be bad news ...."),
+                                   false,
+                                   Gtk::MESSAGE_INFO,
+                                   Gtk::BUTTONS_OK);
+                msg.set_secondary_text (string_compose (_(
+"Removing the master or monitor bus is such a bad idea\n\
+that %1 is not going to allow it.\n\
+\n\
+If you really want to do this sort of thing\n\
+edit your ardour.rc file to set the\n\
+\"allow-special-bus-removal\" option to be \"yes\""), PROGRAM_NAME));
+
+                msg.present ();
+                msg.run ();
+                return;
+        }
+                
        if (ntracks + nbusses == 0) {
                return;
        }
@@ -6098,16 +6469,17 @@ Editor::remove_tracks ()
                if (nbusses) {
                        prompt  = string_compose (_("Do you really want to remove %1 %2 and %3 %4?\n"
                                                    "(You may also lose the playlists associated with the %2)\n\n"
-                                                   "This action cannot be undone!"),
+                                                   "This action cannot be undone, and the session file will be overwritten!"),
                                                  ntracks, trackstr, nbusses, busstr);
                } else {
                        prompt  = string_compose (_("Do you really want to remove %1 %2?\n"
                                                    "(You may also lose the playlists associated with the %2)\n\n"
-                                                   "This action cannot be undone!"),
+                                                   "This action cannot be undone, and the session file will be overwritten!"),
                                                  ntracks, trackstr);
                }
        } else if (nbusses) {
-               prompt  = string_compose (_("Do you really want to remove %1 %2?"),
+               prompt  = string_compose (_("Do you really want to remove %1 %2?\n\n"
+                                            "This action cannot be undon, and the session file will be overwritten"),
                                          nbusses, busstr);
        }
 
@@ -6143,81 +6515,34 @@ Editor::do_insert_time ()
                return;
        }
 
-       ArdourDialog d (*this, _("Insert Time"));
-
-       nframes64_t const pos = get_preferred_edit_position ();
-
-       d.get_vbox()->set_border_width (12);
-       d.get_vbox()->set_spacing (4);
-
-       Table table (2, 2);
-       table.set_spacings (4);
-
-       Label time_label (_("Time to insert:"));
-       time_label.set_alignment (1, 0.5);
-       table.attach (time_label, 0, 1, 0, 1, FILL | EXPAND);
-       AudioClock clock ("insertTimeClock", true, X_("InsertTimeClock"), true, false, true, true);
-       clock.set (0);
-       clock.set_session (_session);
-       clock.set_bbt_reference (pos);
-       table.attach (clock, 1, 2, 0, 1);
-
-       Label intersected_label (_("Intersected regions should:"));
-       intersected_label.set_alignment (1, 0.5);
-       table.attach (intersected_label, 0, 1, 1, 2, FILL | EXPAND);
-       ComboBoxText intersected_combo;
-       intersected_combo.append_text (_("stay in position"));
-       intersected_combo.append_text (_("move"));
-       intersected_combo.append_text (_("be split"));
-       intersected_combo.set_active (0);
-       table.attach (intersected_combo, 1, 2, 1, 2);
-
-       d.get_vbox()->pack_start (table);
-
-       CheckButton move_glued (_("Move glued regions"));
-       d.get_vbox()->pack_start (move_glued);
-       CheckButton move_markers (_("Move markers"));
-       d.get_vbox()->pack_start (move_markers);
-       CheckButton move_tempos (_("Move tempo and meter changes"));
-       d.get_vbox()->pack_start (move_tempos);
-
-       d.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
-       d.add_button (_("Insert time"), Gtk::RESPONSE_OK);
-       d.show_all ();
-
+       InsertTimeDialog d (*this);
        int response = d.run ();
 
        if (response != RESPONSE_OK) {
                return;
        }
 
-       nframes64_t distance = clock.current_duration (pos);
-
-       if (distance == 0) {
+       if (d.distance() == 0) {
                return;
        }
 
-       /* only setting this to keep GCC quiet */
-       InsertTimeOption opt = LeaveIntersected;
+       InsertTimeOption opt = d.intersected_region_action ();
 
-       switch (intersected_combo.get_active_row_number ()) {
-       case 0:
-               opt = LeaveIntersected;
-               break;
-       case 1:
-               opt = MoveIntersected;
-               break;
-       case 2:
-               opt = SplitIntersected;
-               break;
-       }
-
-       insert_time (pos, distance, opt, move_glued.get_active(), move_markers.get_active(), move_tempos.get_active());
+       insert_time (
+               get_preferred_edit_position(),
+               d.distance(),
+               opt,
+               d.move_glued(),
+               d.move_markers(),
+               d.move_glued_markers(),
+               d.move_locked_markers(),
+               d.move_tempos()
+               );
 }
 
 void
 Editor::insert_time (nframes64_t pos, nframes64_t frames, InsertTimeOption opt,
-                    bool ignore_music_glue, bool markers_too, bool tempo_too)
+                    bool ignore_music_glue, bool markers_too, bool glued_markers_too, bool locked_markers_too, bool tempo_too)
 {
        bool commit = false;
 
@@ -6233,8 +6558,8 @@ Editor::insert_time (nframes64_t pos, nframes64_t frames, InsertTimeOption opt,
 
                if (pl) {
 
-                       pl->clear_history ();
-                        pl->clear_owned_history ();
+                       pl->clear_changes ();
+                        pl->clear_owned_changes ();
 
                        if (opt == SplitIntersected) {
                                pl->split (pos);
@@ -6242,16 +6567,10 @@ Editor::insert_time (nframes64_t pos, nframes64_t frames, InsertTimeOption opt,
 
                        pl->shift (pos, frames, (opt == MoveIntersected), ignore_music_glue);
 
-                        vector<StatefulDiffCommand*> cmds;
-                        
+                        vector<Command*> 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_commands (cmds);
+                       
                        _session->add_command (new StatefulDiffCommand (pl));
                        commit = true;
                }
@@ -6274,12 +6593,25 @@ Editor::insert_time (nframes64_t pos, nframes64_t frames, InsertTimeOption opt,
 
                        Locations::LocationList::const_iterator tmp;
 
-                       if ((*i)->start() >= pos) {
-                               (*i)->set_start ((*i)->start() + frames);
-                               if (!(*i)->is_mark()) {
-                                       (*i)->set_end ((*i)->end() + frames);
+                       bool const was_locked = (*i)->locked ();
+                       if (locked_markers_too) {
+                               (*i)->unlock ();
+                       }
+
+                       if ((*i)->position_lock_style() == AudioTime || glued_markers_too) {
+
+                               if ((*i)->start() >= pos) {
+                                       (*i)->set_start ((*i)->start() + frames);
+                                       if (!(*i)->is_mark()) {
+                                               (*i)->set_end ((*i)->end() + frames);
+                                       }
+                                       moved = true;
                                }
-                               moved = true;
+                               
+                       }
+
+                       if (was_locked) {
+                               (*i)->lock ();
                        }
                }
 
@@ -6325,7 +6657,7 @@ Editor::fit_tracks (TrackViewList & tracks)
        uint32_t h = (uint32_t) floor ((_canvas_height - child_heights - canvas_timebars_vsize) / tracks.size());
        double first_y_pos = DBL_MAX;
 
-       if (h < TimeAxisView::hSmall) {
+       if (h < TimeAxisView::preset_height (HeightSmall)) {
                MessageDialog msg (*this, _("There are too many tracks to fit in the current window"));
                /* too small to be displayed */
                return;
@@ -6333,20 +6665,31 @@ Editor::fit_tracks (TrackViewList & tracks)
 
        undo_visual_stack.push_back (current_visual_state());
 
+       /* build a list of all tracks, including children */
+
+       TrackViewList all;
+       for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
+               all.push_back (*i);
+               TimeAxisView::Children c = (*i)->get_child_list ();
+               for (TimeAxisView::Children::iterator j = c.begin(); j != c.end(); ++j) {
+                       all.push_back (j->get());
+               }
+       }
+
        /* operate on all tracks, hide unselected ones that are in the middle of selected ones */
 
        bool prev_was_selected = false;
-       bool is_selected = tracks.contains (track_views.front());
+       bool is_selected = tracks.contains (all.front());
        bool next_is_selected;
 
-       for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
+       for (TrackViewList::iterator t = all.begin(); t != all.end(); ++t) {
 
                TrackViewList::iterator next;
 
                next = t;
                ++next;
 
-               if (next != track_views.end()) {
+               if (next != all.end()) {
                        next_is_selected = tracks.contains (*next);
                } else {
                        next_is_selected = false;