Fix session range location by hooking into the undo system. Fixes #3654.

git-svn-id: svn://localhost/ardour2/branches/3.0@8539 d708f5d6-7413-0410-9779-e7cbd77b26cf
This commit is contained in:
Carl Hetherington 2011-01-19 17:38:56 +00:00
parent 074d58fc6f
commit 1e8586742e
12 changed files with 117 additions and 71 deletions

View file

@ -3069,6 +3069,14 @@ Editor::begin_reversible_command (string name)
} }
} }
void
Editor::begin_reversible_command (GQuark q)
{
if (_session) {
_session->begin_reversible_command (q);
}
}
void void
Editor::commit_reversible_command () Editor::commit_reversible_command ()
{ {

View file

@ -429,6 +429,7 @@ class Editor : public PublicEditor, public PBD::ScopedConnectionList, public ARD
void snap_to (framepos_t& first, framepos_t& last, int32_t direction = 0, bool for_mark = false); void snap_to (framepos_t& first, framepos_t& last, int32_t direction = 0, bool for_mark = false);
void begin_reversible_command (std::string cmd_name); void begin_reversible_command (std::string cmd_name);
void begin_reversible_command (GQuark);
void commit_reversible_command (); void commit_reversible_command ();
DragManager* drags () const { DragManager* drags () const {

View file

@ -48,6 +48,7 @@
#include "ardour/source_factory.h" #include "ardour/source_factory.h"
#include "ardour/session.h" #include "ardour/session.h"
#include "ardour/smf_source.h" #include "ardour/smf_source.h"
#include "ardour/operations.h"
#include "pbd/memento_command.h" #include "pbd/memento_command.h"
#include "ardour_ui.h" #include "ardour_ui.h"
@ -874,7 +875,7 @@ Editor::finish_bringing_in_material (boost::shared_ptr<Region> region, uint32_t
boost::shared_ptr<Playlist> playlist = existing_track->playlist(); boost::shared_ptr<Playlist> playlist = existing_track->playlist();
boost::shared_ptr<Region> copy (RegionFactory::create (region, region->properties())); boost::shared_ptr<Region> copy (RegionFactory::create (region, region->properties()));
begin_reversible_command (_("insert file")); begin_reversible_command (Operations::insert_file);
playlist->clear_changes (); playlist->clear_changes ();
playlist->add_region (copy, pos); playlist->add_region (copy, pos);
_session->add_command (new StatefulDiffCommand (playlist)); _session->add_command (new StatefulDiffCommand (playlist));

View file

@ -32,6 +32,8 @@
#include "ardour/session.h" #include "ardour/session.h"
#include "ardour/dB.h" #include "ardour/dB.h"
#include "ardour/region_factory.h" #include "ardour/region_factory.h"
#include "ardour/operations.h"
#include "editor.h" #include "editor.h"
#include "i18n.h" #include "i18n.h"
#include "keyboard.h" #include "keyboard.h"
@ -905,7 +907,7 @@ RegionMoveDrag::finished_no_copy (
if (_x_constrained) { if (_x_constrained) {
_editor->begin_reversible_command (_("fixed time region drag")); _editor->begin_reversible_command (_("fixed time region drag"));
} else { } else {
_editor->begin_reversible_command (_("region drag")); _editor->begin_reversible_command (Operations::region_drag);
} }
for (list<DraggingView>::const_iterator i = _views.begin(); i != _views.end(); ) { for (list<DraggingView>::const_iterator i = _views.begin(); i != _views.end(); ) {
@ -1227,7 +1229,7 @@ RegionInsertDrag::finished (GdkEvent *, bool)
boost::shared_ptr<Playlist> playlist = dest_rtv->playlist(); boost::shared_ptr<Playlist> playlist = dest_rtv->playlist();
_editor->begin_reversible_command (_("insert region")); _editor->begin_reversible_command (Operations::insert_region);
playlist->clear_changes (); playlist->clear_changes ();
playlist->add_region (_primary->region (), _last_frame_position); playlist->add_region (_primary->region (), _last_frame_position);
_editor->session()->add_command (new StatefulDiffCommand (playlist)); _editor->session()->add_command (new StatefulDiffCommand (playlist));

View file

@ -74,6 +74,7 @@
#include "ardour/region_factory.h" #include "ardour/region_factory.h"
#include "ardour/source_factory.h" #include "ardour/source_factory.h"
#include "ardour/session.h" #include "ardour/session.h"
#include "ardour/operations.h"
#include <bitset> #include <bitset>
@ -2540,7 +2541,7 @@ Editor::add_region_brush_drag (ArdourCanvas::Item* item, GdkEvent* event, Region
RegionSelection s = get_equivalent_regions (selection->regions, ARDOUR::Properties::edit.property_id); RegionSelection s = get_equivalent_regions (selection->regions, ARDOUR::Properties::edit.property_id);
_drags->add (new RegionMoveDrag (this, item, region_view, s.by_layer(), true, false)); _drags->add (new RegionMoveDrag (this, item, region_view, s.by_layer(), true, false));
begin_reversible_command (_("Drag region brush")); begin_reversible_command (Operations::drag_region_brush);
} }
/** Start a grab where a time range is selected, track(s) are selected, and the /** Start a grab where a time range is selected, track(s) are selected, and the
@ -2581,7 +2582,7 @@ Editor::start_selection_grab (ArdourCanvas::Item* /*item*/, GdkEvent* event)
creating the new region and another for moving it. creating the new region and another for moving it.
*/ */
begin_reversible_command (_("selection grab")); begin_reversible_command (Operations::selection_grab);
boost::shared_ptr<Playlist> playlist = clicked_axisview->playlist(); boost::shared_ptr<Playlist> playlist = clicked_axisview->playlist();

View file

@ -55,6 +55,7 @@
#include "ardour/quantize.h" #include "ardour/quantize.h"
#include "ardour/strip_silence.h" #include "ardour/strip_silence.h"
#include "ardour/route_group.h" #include "ardour/route_group.h"
#include "ardour/operations.h"
#include "ardour_ui.h" #include "ardour_ui.h"
#include "editor.h" #include "editor.h"
@ -3032,7 +3033,7 @@ Editor::region_fill_track ()
framepos_t const end = _session->current_end_frame (); framepos_t const end = _session->current_end_frame ();
begin_reversible_command (_("region fill")); begin_reversible_command (Operations::region_fill);
for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) { for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
@ -3086,7 +3087,7 @@ Editor::region_fill_selection ()
framepos_t selection_length = end - start; framepos_t selection_length = end - start;
float times = (float)selection_length / region->length(); float times = (float)selection_length / region->length();
begin_reversible_command (_("fill selection")); begin_reversible_command (Operations::fill_selection);
for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) { for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
@ -4155,7 +4156,7 @@ Editor::paste_internal (framepos_t position, float times)
position = get_preferred_edit_position(); position = get_preferred_edit_position();
} }
begin_reversible_command (_("paste")); begin_reversible_command (Operations::paste);
TrackViewList ts; TrackViewList ts;
TrackViewList::iterator i; TrackViewList::iterator i;
@ -4218,7 +4219,7 @@ Editor::duplicate_some_regions (RegionSelection& regions, float times)
framepos_t const start_frame = regions.start (); framepos_t const start_frame = regions.start ();
framepos_t const end_frame = regions.end_frame (); framepos_t const end_frame = regions.end_frame ();
begin_reversible_command (_("duplicate region")); begin_reversible_command (Operations::duplicate_region);
selection->clear_regions (); selection->clear_regions ();

View file

@ -52,6 +52,7 @@
#include "ardour/session_playlist.h" #include "ardour/session_playlist.h"
#include "ardour/tempo.h" #include "ardour/tempo.h"
#include "ardour/utils.h" #include "ardour/utils.h"
#include "ardour/operations.h"
#include "midi++/names.h" #include "midi++/names.h"
@ -1028,7 +1029,7 @@ MidiTimeAxisView::add_region (framepos_t pos, framecnt_t length, bool commit)
{ {
Editor* real_editor = dynamic_cast<Editor*> (&_editor); Editor* real_editor = dynamic_cast<Editor*> (&_editor);
real_editor->begin_reversible_command (_("create region")); real_editor->begin_reversible_command (Operations::create_region);
playlist()->clear_changes (); playlist()->clear_changes ();
real_editor->snap_to (pos, 0); real_editor->snap_to (pos, 0);

View file

@ -23,7 +23,6 @@
#include <list> #include <list>
#include <map> #include <map>
#include <set> #include <set>
#include <stack>
#include <string> #include <string>
#include <vector> #include <vector>
#include <stdint.h> #include <stdint.h>
@ -315,7 +314,6 @@ class Session : public PBD::StatefulDestructible, public PBD::ScopedConnectionLi
int wipe (); int wipe ();
std::pair<framepos_t, framepos_t> get_extent () const;
framepos_t current_end_frame () const; framepos_t current_end_frame () const;
framepos_t current_start_frame () const; framepos_t current_start_frame () const;
/** "actual" sample rate of session, set by current audioengine rate, pullup/down etc. */ /** "actual" sample rate of session, set by current audioengine rate, pullup/down etc. */
@ -666,6 +664,7 @@ class Session : public PBD::StatefulDestructible, public PBD::ScopedConnectionLi
std::string next_redo() const { return _history.next_redo(); } std::string next_redo() const { return _history.next_redo(); }
void begin_reversible_command (const std::string& cmd_name); void begin_reversible_command (const std::string& cmd_name);
void begin_reversible_command (GQuark);
void commit_reversible_command (Command* cmd = 0); void commit_reversible_command (Command* cmd = 0);
void add_command (Command *const cmd) { void add_command (Command *const cmd) {
@ -673,6 +672,11 @@ class Session : public PBD::StatefulDestructible, public PBD::ScopedConnectionLi
_current_trans->add_command (cmd); _current_trans->add_command (cmd);
} }
/** @return The list of operations that are currently in progress */
std::list<GQuark> const & current_operations () {
return _current_trans_quarks;
}
void add_commands (std::vector<Command*> const & cmds); void add_commands (std::vector<Command*> const & cmds);
std::map<PBD::ID,PBD::StatefulDestructible*> registry; std::map<PBD::ID,PBD::StatefulDestructible*> registry;
@ -842,6 +846,8 @@ class Session : public PBD::StatefulDestructible, public PBD::ScopedConnectionLi
Slave* _slave; Slave* _slave;
bool _silent; bool _silent;
void maybe_update_session_range (framepos_t, framepos_t);
// varispeed playback // varispeed playback
double _transport_speed; double _transport_speed;
double _last_transport_speed; double _last_transport_speed;
@ -1059,7 +1065,6 @@ class Session : public PBD::StatefulDestructible, public PBD::ScopedConnectionLi
void first_stage_init (std::string path, std::string snapshot_name); void first_stage_init (std::string path, std::string snapshot_name);
int second_stage_init (); int second_stage_init ();
void update_session_range_location_marker ();
void remove_empty_sounds (); void remove_empty_sounds ();
void setup_midi_control (); void setup_midi_control ();
@ -1258,6 +1263,8 @@ class Session : public PBD::StatefulDestructible, public PBD::ScopedConnectionLi
void remove_playlist (boost::weak_ptr<Playlist>); void remove_playlist (boost::weak_ptr<Playlist>);
void track_playlist_changed (boost::weak_ptr<Track>); void track_playlist_changed (boost::weak_ptr<Track>);
void playlist_region_added (boost::weak_ptr<Region>);
void playlist_ranges_moved (std::list<Evoral::RangeMove<framepos_t> > const &);
/* NAMED SELECTIONS */ /* NAMED SELECTIONS */
@ -1339,8 +1346,11 @@ class Session : public PBD::StatefulDestructible, public PBD::ScopedConnectionLi
UndoHistory _history; UndoHistory _history;
/** current undo transaction, or 0 */ /** current undo transaction, or 0 */
UndoTransaction* _current_trans; UndoTransaction* _current_trans;
/** number of times that begin_reversible_command has been called without commit_reversible_command */ /** GQuarks to describe the reversible commands that are currently in progress.
int _current_trans_depth; * These may be nested, in which case more recently-started commands are toward
* the front of the list.
*/
std::list<GQuark> _current_trans_quarks;
void jack_timebase_callback (jack_transport_state_t, pframes_t, jack_position_t*, int); void jack_timebase_callback (jack_transport_state_t, pframes_t, jack_position_t*, int);
int jack_sync_callback (jack_transport_state_t, jack_position_t*); int jack_sync_callback (jack_transport_state_t, jack_position_t*);

View file

@ -100,6 +100,7 @@
#include "ardour/utils.h" #include "ardour/utils.h"
#include "ardour/graph.h" #include "ardour/graph.h"
#include "ardour/vbap_speakers.h" #include "ardour/vbap_speakers.h"
#include "ardour/operations.h"
#include "midi++/port.h" #include "midi++/port.h"
#include "midi++/mmc.h" #include "midi++/mmc.h"
@ -152,7 +153,6 @@ Session::Session (AudioEngine &eng,
, _bundles (new BundleList) , _bundles (new BundleList)
, _bundle_xml_node (0) , _bundle_xml_node (0)
, _current_trans (0) , _current_trans (0)
, _current_trans_depth (0)
, _click_io ((IO*) 0) , _click_io ((IO*) 0)
, click_data (0) , click_data (0)
, click_emphasis_data (0) , click_emphasis_data (0)
@ -766,11 +766,9 @@ Session::track_playlist_changed (boost::weak_ptr<Track> wp)
boost::shared_ptr<Playlist> playlist; boost::shared_ptr<Playlist> playlist;
if ((playlist = track->playlist()) != 0) { if ((playlist = track->playlist()) != 0) {
playlist->LengthChanged.connect_same_thread (*this, boost::bind (&Session::update_session_range_location_marker, this)); playlist->RegionAdded.connect_same_thread (*this, boost::bind (&Session::playlist_region_added, this, _1));
playlist->RangesMoved.connect_same_thread (*this, boost::bind (&Session::update_session_range_location_marker, this)); playlist->RangesMoved.connect_same_thread (*this, boost::bind (&Session::playlist_ranges_moved, this, _1));
} }
update_session_range_location_marker ();
} }
bool bool
@ -2168,7 +2166,6 @@ Session::remove_route (boost::shared_ptr<Route> route)
} }
update_route_solo_state (); update_route_solo_state ();
update_session_range_location_marker ();
// We need to disconnect the route's inputs and outputs // We need to disconnect the route's inputs and outputs
@ -2496,64 +2493,77 @@ Session::route_by_remote_id (uint32_t id)
return boost::shared_ptr<Route> ((Route*) 0); return boost::shared_ptr<Route> ((Route*) 0);
} }
/** If either end of the session range location marker lies inside the current void
* session extent, move it to the corresponding session extent. Session::playlist_region_added (boost::weak_ptr<Region> w)
{
boost::shared_ptr<Region> r = w.lock ();
if (!r) {
return;
}
/* These are the operations that are currently in progress... */
list<GQuark> curr = _current_trans_quarks;
curr.sort ();
/* ...and these are the operations during which we want to update
the session range location markers.
*/
list<GQuark> ops;
ops.push_back (Operations::capture);
ops.push_back (Operations::paste);
ops.push_back (Operations::duplicate_region);
ops.push_back (Operations::insert_file);
ops.push_back (Operations::insert_region);
ops.push_back (Operations::drag_region_brush);
ops.push_back (Operations::region_drag);
ops.push_back (Operations::selection_grab);
ops.push_back (Operations::region_fill);
ops.push_back (Operations::fill_selection);
ops.push_back (Operations::create_region);
ops.sort ();
/* See if any of the current operations match the ones that we want */
list<GQuark> in;
set_intersection (_current_trans_quarks.begin(), _current_trans_quarks.end(), ops.begin(), ops.end(), back_inserter (in));
/* If so, update the session range markers */
if (!in.empty ()) {
maybe_update_session_range (r->position (), r->last_frame ());
}
}
/** Update the session range markers if a is before the current start or
* b is after the current end.
*/ */
void void
Session::update_session_range_location_marker () Session::maybe_update_session_range (framepos_t a, framepos_t b)
{ {
if (_state_of_the_state & Loading) { if (_state_of_the_state & Loading) {
return; return;
} }
pair<framepos_t, framepos_t> const ext = get_extent ();
if (_session_range_location == 0) { if (_session_range_location == 0) {
/* we don't have a session range yet; use this one (provided it is valid) */
if (ext.first != max_framepos) { add_session_range_location (a, b);
add_session_range_location (ext.first, ext.second);
}
} else { } else {
/* update the existing session range */
if (ext.first < _session_range_location->start()) { if (a < _session_range_location->start()) {
_session_range_location->set_start (ext.first); _session_range_location->set_start (a);
set_dirty ();
} }
if (ext.second > _session_range_location->end()) { if (b > _session_range_location->end()) {
_session_range_location->set_end (ext.second); _session_range_location->set_end (b);
set_dirty ();
} }
} }
} }
/** @return Extent of the session's contents; if the session is empty, the first value of void
* the pair will equal max_framepos. Session::playlist_ranges_moved (list<Evoral::RangeMove<framepos_t> > const & ranges)
*/
pair<framepos_t, framepos_t>
Session::get_extent () const
{ {
pair<framepos_t, framepos_t> ext (max_framepos, 0); for (list<Evoral::RangeMove<framepos_t> >::const_iterator i = ranges.begin(); i != ranges.end(); ++i) {
maybe_update_session_range (i->to, i->to + i->length);
boost::shared_ptr<RouteList> rl = routes.reader ();
for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
if (!tr || tr->destructive()) {
// ignore tape tracks when getting extents
continue;
} }
pair<framepos_t, framepos_t> e = tr->playlist()->get_extent ();
if (e.first < ext.first) {
ext.first = e.first;
}
if (e.second > ext.second) {
ext.second = e.second;
}
}
return ext;
} }
/* Region management */ /* Region management */

View file

@ -2363,6 +2363,16 @@ Session::add_commands (vector<Command*> const & cmds)
void void
Session::begin_reversible_command (const string& name) Session::begin_reversible_command (const string& name)
{
begin_reversible_command (g_quark_from_string (name.c_str ()));
}
/** Begin a reversible command using a GQuark to identify it.
* begin_reversible_command() and commit_reversible_command() calls may be nested,
* but there must be as many begin...()s as there are commit...()s.
*/
void
Session::begin_reversible_command (GQuark q)
{ {
/* If nested begin/commit pairs are used, we create just one UndoTransaction /* If nested begin/commit pairs are used, we create just one UndoTransaction
to hold all the commands that are committed. This keeps the order of to hold all the commands that are committed. This keeps the order of
@ -2371,20 +2381,19 @@ Session::begin_reversible_command (const string& name)
if (_current_trans == 0) { if (_current_trans == 0) {
/* start a new transaction */ /* start a new transaction */
assert (_current_trans_depth == 0); assert (_current_trans_quarks.empty ());
_current_trans = new UndoTransaction(); _current_trans = new UndoTransaction();
_current_trans->set_name (name); _current_trans->set_name (g_quark_to_string (q));
} else {
/* use the existing transaction */
++_current_trans_depth;
} }
_current_trans_quarks.push_front (q);
} }
void void
Session::commit_reversible_command (Command *cmd) Session::commit_reversible_command (Command *cmd)
{ {
assert (_current_trans); assert (_current_trans);
assert (_current_trans_depth > 0); assert (!_current_trans_quarks.empty ());
struct timeval now; struct timeval now;
@ -2392,9 +2401,9 @@ Session::commit_reversible_command (Command *cmd)
_current_trans->add_command (cmd); _current_trans->add_command (cmd);
} }
--_current_trans_depth; _current_trans_quarks.pop_front ();
if (_current_trans_depth > 0) { if (!_current_trans_quarks.empty ()) {
/* the transaction we're committing is not the top-level one */ /* the transaction we're committing is not the top-level one */
return; return;
} }

View file

@ -40,6 +40,7 @@
#include "ardour/location.h" #include "ardour/location.h"
#include "ardour/session.h" #include "ardour/session.h"
#include "ardour/slave.h" #include "ardour/slave.h"
#include "ardour/operations.h"
#include "i18n.h" #include "i18n.h"
@ -435,7 +436,7 @@ Session::non_realtime_stop (bool abort, int on_entry, bool& finished)
reset_rf_scale (0); reset_rf_scale (0);
if (did_record) { if (did_record) {
begin_reversible_command ("capture"); begin_reversible_command (Operations::capture);
_have_captured = true; _have_captured = true;
} }

View file

@ -136,6 +136,7 @@ libardour_sources = [
'mute_master.cc', 'mute_master.cc',
'named_selection.cc', 'named_selection.cc',
'onset_detector.cc', 'onset_detector.cc',
'operations.cc',
'panner.cc', 'panner.cc',
'pcm_utils.cc', 'pcm_utils.cc',
'pi_controller.cc', 'pi_controller.cc',