midway snapshot of work done on managing Region & Source lifetimes correctly. may fix missing MIDI file bug ; save empty playlists because they may be referred to by the history file ; undo commands auto-delete when objects they refer to die (currently not commands built from XML deserialization); Sources now know how many regions are using them for something, meaning that we know if we can delete the files holding any data for the source
git-svn-id: svn://localhost/ardour2/branches/3.0@7291 d708f5d6-7413-0410-9779-e7cbd77b26cf
This commit is contained in:
parent
cac03dbeb6
commit
f4401c5928
@ -4419,10 +4419,12 @@ Editor::remove_last_capture ()
|
||||
|
||||
if (prompter.run () == 1) {
|
||||
_session->remove_last_capture ();
|
||||
_regions->redisplay ();
|
||||
}
|
||||
|
||||
} else {
|
||||
_session->remove_last_capture();
|
||||
_regions->redisplay ();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -365,7 +365,6 @@ EditorRegions::selection_changed ()
|
||||
|
||||
} else {
|
||||
_change_connection.block (true);
|
||||
cerr << "\tpush to region selection\n";
|
||||
_editor->set_selected_regionview_from_region_list (region, Selection::Add);
|
||||
|
||||
_change_connection.block (false);
|
||||
@ -392,13 +391,11 @@ EditorRegions::set_selected (RegionSelection& regions)
|
||||
boost::shared_ptr<Region> compared_region = (*i)[_columns.region];
|
||||
|
||||
if (r == compared_region) {
|
||||
cerr << "\tpush into region list\n";
|
||||
_display.get_selection()->select(*i);
|
||||
break;
|
||||
}
|
||||
|
||||
if (!(*i).children().empty()) {
|
||||
cerr << "\tlook for " << r->name() << " among children of " << (compared_region ? compared_region->name() : string ("NO REGION")) << endl;
|
||||
if (set_selected_in_subrow(r, (*i), 2)) {
|
||||
break;
|
||||
}
|
||||
@ -559,7 +556,6 @@ EditorRegions::update_all_rows ()
|
||||
boost::shared_ptr<Region> region = (*i)[_columns.region];
|
||||
|
||||
if (!region->automatic()) {
|
||||
cerr << "level 1 : Updating " << region->name() << "\n";
|
||||
populate_row(region, (*i));
|
||||
}
|
||||
|
||||
@ -580,7 +576,6 @@ EditorRegions::update_all_subrows (TreeModel::Row const &parent_row, int level)
|
||||
boost::shared_ptr<Region> region = (*i)[_columns.region];
|
||||
|
||||
if (!region->automatic()) {
|
||||
cerr << "level " << level << " : Updating " << region->name() << "\n";
|
||||
populate_row(region, (*i));
|
||||
}
|
||||
|
||||
|
@ -45,7 +45,7 @@ namespace ARDOUR {
|
||||
class IO;
|
||||
class Playlist;
|
||||
class Processor;
|
||||
class Region;
|
||||
class Source;
|
||||
class Session;
|
||||
class Track;
|
||||
class Location;
|
||||
@ -134,12 +134,10 @@ class Diskstream : public SessionObject, public PublicDiskstream
|
||||
|
||||
int set_loop (Location *loc);
|
||||
|
||||
std::list<boost::shared_ptr<Region> >& last_capture_regions () { return _last_capture_regions; }
|
||||
std::list<boost::shared_ptr<Source> >& last_capture_sources () { return _last_capture_sources; }
|
||||
|
||||
void handle_input_change (IOChange, void *src);
|
||||
|
||||
void remove_region_from_last_capture (boost::weak_ptr<Region> wregion);
|
||||
|
||||
void move_processor_automation (boost::weak_ptr<Processor>,
|
||||
std::list<Evoral::RangeMove<framepos_t> > const &);
|
||||
|
||||
@ -228,7 +226,7 @@ class Diskstream : public SessionObject, public PublicDiskstream
|
||||
|
||||
virtual bool realtime_set_speed (double, bool global_change);
|
||||
|
||||
std::list<boost::shared_ptr<Region> > _last_capture_regions;
|
||||
std::list<boost::shared_ptr<Source> > _last_capture_sources;
|
||||
|
||||
virtual int use_pending_capture_data (XMLNode& node) = 0;
|
||||
|
||||
|
@ -65,7 +65,8 @@ class RegionListProperty : public PBD::SequenceProperty<std::list<boost::shared_
|
||||
RegionListProperty (Playlist&);
|
||||
|
||||
boost::shared_ptr<Region> lookup_id (const PBD::ID& id);
|
||||
void diff (PBD::PropertyList& undo, PBD::PropertyList& redo) const;
|
||||
void diff (PBD::PropertyList& undo, PBD::PropertyList& redo, Command*) const;
|
||||
bool involves (boost::shared_ptr<Region>);
|
||||
|
||||
private:
|
||||
friend class Playlist;
|
||||
|
@ -23,7 +23,7 @@
|
||||
namespace ARDOUR {
|
||||
|
||||
class Playlist;
|
||||
class Region;
|
||||
class Source;
|
||||
class Location;
|
||||
|
||||
/** Public interface to a Diskstream */
|
||||
@ -34,7 +34,7 @@ public:
|
||||
virtual boost::shared_ptr<Playlist> playlist () = 0;
|
||||
virtual void monitor_input (bool) = 0;
|
||||
virtual bool destructive () const = 0;
|
||||
virtual std::list<boost::shared_ptr<Region> > & last_capture_regions () = 0;
|
||||
virtual std::list<boost::shared_ptr<Source> > & last_capture_sources () = 0;
|
||||
virtual void set_capture_offset () = 0;
|
||||
virtual void reset_write_sources (bool, bool force = false) = 0;
|
||||
virtual float playback_buffer_load () const = 0;
|
||||
|
@ -270,6 +270,8 @@ class Region
|
||||
return _pending_explicit_relayer;
|
||||
}
|
||||
|
||||
void drop_sources ();
|
||||
|
||||
protected:
|
||||
friend class RegionFactory;
|
||||
|
||||
|
@ -21,6 +21,7 @@
|
||||
#define __ardour_region_factory_h__
|
||||
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <glibmm/thread.h>
|
||||
|
||||
#include "pbd/id.h"
|
||||
@ -78,7 +79,10 @@ class RegionFactory {
|
||||
/** create a region with specified sources @param srcs and XML state */
|
||||
static boost::shared_ptr<Region> create (SourceList& srcs, const XMLNode&);
|
||||
|
||||
static void get_regions_using_source (boost::shared_ptr<Source>, std::set<boost::shared_ptr<Region> >& );
|
||||
|
||||
static void map_remove (boost::shared_ptr<Region>);
|
||||
static void map_remove_with_equivalents (boost::shared_ptr<Region>);
|
||||
static void delete_all_regions ();
|
||||
static const RegionMap& regions() { return region_map; }
|
||||
static uint32_t nregions ();
|
||||
|
@ -512,8 +512,7 @@ class Session : public PBD::StatefulDestructible, public PBD::ScopedConnectionLi
|
||||
int cleanup_sources (CleanupReport&);
|
||||
int cleanup_trash_sources (CleanupReport&);
|
||||
|
||||
int destroy_region (boost::shared_ptr<Region>);
|
||||
int destroy_regions (std::list<boost::shared_ptr<Region> >);
|
||||
int destroy_sources (std::list<boost::shared_ptr<Source> >);
|
||||
|
||||
int remove_last_capture ();
|
||||
|
||||
|
@ -53,6 +53,7 @@ public:
|
||||
template<class T> void foreach (T *obj, void (T::*func)(boost::shared_ptr<Playlist>));
|
||||
void get (std::vector<boost::shared_ptr<Playlist> >&);
|
||||
void unassigned (std::list<boost::shared_ptr<Playlist> > & list);
|
||||
void destroy_region (boost::shared_ptr<Region>);
|
||||
|
||||
private:
|
||||
friend class Session;
|
||||
@ -69,7 +70,7 @@ private:
|
||||
int load (Session &, const XMLNode&);
|
||||
int load_unused (Session &, const XMLNode&);
|
||||
boost::shared_ptr<Playlist> XMLPlaylistFactory (Session &, const XMLNode&);
|
||||
|
||||
|
||||
mutable Glib::Mutex lock;
|
||||
typedef std::set<boost::shared_ptr<Playlist> > List;
|
||||
List playlists;
|
||||
|
@ -23,6 +23,8 @@
|
||||
#include <string>
|
||||
#include <set>
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
#include <boost/utility.hpp>
|
||||
#include "pbd/statefuldestructible.h"
|
||||
|
||||
@ -102,6 +104,15 @@ class Source : public SessionObject
|
||||
Glib::Mutex& mutex() { return _lock; }
|
||||
Flag flags() const { return _flags; }
|
||||
|
||||
void inc_use_count () { g_atomic_int_inc (&_use_count); }
|
||||
void dec_use_count () {
|
||||
gint oldval = g_atomic_int_exchange_and_add (&_use_count, -1);
|
||||
assert (oldval > 0);
|
||||
}
|
||||
|
||||
int use_count() const { return g_atomic_int_get (&_use_count); }
|
||||
bool used() const { return use_count() > 0; }
|
||||
|
||||
protected:
|
||||
DataType _type;
|
||||
Flag _flags;
|
||||
@ -111,6 +122,7 @@ class Source : public SessionObject
|
||||
mutable Glib::Mutex _lock;
|
||||
mutable Glib::Mutex _analysis_lock;
|
||||
Glib::Mutex _playlist_lock;
|
||||
gint _use_count; /* atomic */
|
||||
|
||||
private:
|
||||
void fix_writable_flags ();
|
||||
|
@ -29,6 +29,7 @@ namespace ARDOUR {
|
||||
class Session;
|
||||
class Playlist;
|
||||
class RouteGroup;
|
||||
class Source;
|
||||
class Region;
|
||||
class Diskstream;
|
||||
|
||||
@ -100,7 +101,7 @@ class Track : public Route, public PublicDiskstream
|
||||
boost::shared_ptr<Playlist> playlist ();
|
||||
void monitor_input (bool);
|
||||
bool destructive () const;
|
||||
std::list<boost::shared_ptr<Region> > & last_capture_regions ();
|
||||
std::list<boost::shared_ptr<Source> > & last_capture_sources ();
|
||||
void set_capture_offset ();
|
||||
void reset_write_sources (bool, bool force = false);
|
||||
float playback_buffer_load () const;
|
||||
|
@ -480,8 +480,8 @@ AudioDiskstream::process (nframes_t transport_frame, nframes_t nframes, bool can
|
||||
was_recording = true;
|
||||
}
|
||||
|
||||
if (can_record && !_last_capture_regions.empty()) {
|
||||
_last_capture_regions.clear ();
|
||||
if (can_record && !_last_capture_sources.empty()) {
|
||||
_last_capture_sources.clear ();
|
||||
}
|
||||
|
||||
if (rec_nframes) {
|
||||
@ -1447,7 +1447,6 @@ AudioDiskstream::transport_stopped_wallclock (struct tm& when, time_t twhen, boo
|
||||
plist.add (Properties::start, c->front()->write_source->last_capture_start_frame());
|
||||
plist.add (Properties::length, total_capture);
|
||||
plist.add (Properties::name, whole_file_region_name);
|
||||
|
||||
boost::shared_ptr<Region> rx (RegionFactory::create (srcs, plist));
|
||||
rx->set_automatic (true);
|
||||
rx->set_whole_file (true);
|
||||
@ -1462,7 +1461,7 @@ AudioDiskstream::transport_stopped_wallclock (struct tm& when, time_t twhen, boo
|
||||
/* XXX what now? */
|
||||
}
|
||||
|
||||
_last_capture_regions.push_back (region);
|
||||
_last_capture_sources.insert (_last_capture_sources.end(), srcs.begin(), srcs.end());
|
||||
|
||||
// cerr << _name << ": there are " << capture_info.size() << " capture_info records\n";
|
||||
|
||||
@ -1494,10 +1493,6 @@ AudioDiskstream::transport_stopped_wallclock (struct tm& when, time_t twhen, boo
|
||||
continue; /* XXX is this OK? */
|
||||
}
|
||||
|
||||
region->DropReferences.connect_same_thread (*this, boost::bind (&Diskstream::remove_region_from_last_capture, this, boost::weak_ptr<Region>(region)));
|
||||
|
||||
_last_capture_regions.push_back (region);
|
||||
|
||||
i_am_the_modifier++;
|
||||
_playlist->add_region (region, (*ci)->start, 1, non_layered());
|
||||
i_am_the_modifier--;
|
||||
@ -1914,6 +1909,8 @@ AudioDiskstream::reset_write_sources (bool mark_write_complete, bool /*force*/)
|
||||
boost::shared_ptr<ChannelList> c = channels.reader();
|
||||
uint32_t n;
|
||||
|
||||
cerr << name() << " resetting write sources, recrodable " << recordable() << " chans = " << c->size() << endl;
|
||||
|
||||
if (!_session.writable() || !recordable()) {
|
||||
return;
|
||||
}
|
||||
@ -2356,6 +2353,7 @@ void
|
||||
AudioDiskstream::ChannelInfo::resize_capture (nframes_t capture_bufsize)
|
||||
{
|
||||
delete capture_buf;
|
||||
|
||||
capture_buf = new RingBufferNPT<Sample> (capture_bufsize);
|
||||
memset (capture_buf->buffer(), 0, sizeof (Sample) * capture_buf->bufsize());
|
||||
}
|
||||
|
@ -663,17 +663,15 @@ bool
|
||||
AudioPlaylist::destroy_region (boost::shared_ptr<Region> region)
|
||||
{
|
||||
boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
|
||||
|
||||
if (!r) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool changed = false;
|
||||
Crossfades::iterator c, ctmp;
|
||||
set<boost::shared_ptr<Crossfade> > unique_xfades;
|
||||
|
||||
if (r == 0) {
|
||||
fatal << _("programming error: non-audio Region passed to remove_overlap in audio playlist")
|
||||
<< endmsg;
|
||||
/*NOTREACHED*/
|
||||
return false;
|
||||
}
|
||||
|
||||
{
|
||||
RegionLock rlock (this);
|
||||
|
||||
|
@ -263,6 +263,9 @@ AudioRegion::connect_to_header_position_offset_changed ()
|
||||
|
||||
for (SourceList::const_iterator i = _sources.begin(); i != _sources.end(); ++i) {
|
||||
|
||||
/* connect only once to HeaderPositionOffsetChanged, even if sources are replicated
|
||||
*/
|
||||
|
||||
if (unique_srcs.find (*i) == unique_srcs.end ()) {
|
||||
unique_srcs.insert (*i);
|
||||
boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource> (*i);
|
||||
@ -520,24 +523,8 @@ AudioRegion::state (bool full)
|
||||
XMLNode& node (Region::state (full));
|
||||
XMLNode *child;
|
||||
char buf[64];
|
||||
char buf2[64];
|
||||
LocaleGuard lg (X_("POSIX"));
|
||||
|
||||
|
||||
// XXX these should move into Region
|
||||
|
||||
for (uint32_t n=0; n < _sources.size(); ++n) {
|
||||
snprintf (buf2, sizeof(buf2), "source-%d", n);
|
||||
_sources[n]->id().print (buf, sizeof (buf));
|
||||
node.add_property (buf2, buf);
|
||||
}
|
||||
|
||||
for (uint32_t n=0; n < _master_sources.size(); ++n) {
|
||||
snprintf (buf2, sizeof(buf2), "master-source-%d", n);
|
||||
_master_sources[n]->id().print (buf, sizeof (buf));
|
||||
node.add_property (buf2, buf);
|
||||
}
|
||||
|
||||
snprintf (buf, sizeof (buf), "%u", (uint32_t) _sources.size());
|
||||
node.add_property ("channels", buf);
|
||||
|
||||
@ -571,10 +558,6 @@ AudioRegion::state (bool full)
|
||||
child->add_property ("default", "yes");
|
||||
}
|
||||
|
||||
if (full && _extra_xml) {
|
||||
node.add_child_copy (*_extra_xml);
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
|
@ -435,18 +435,6 @@ Diskstream::set_name (const string& str)
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
Diskstream::remove_region_from_last_capture (boost::weak_ptr<Region> wregion)
|
||||
{
|
||||
boost::shared_ptr<Region> region (wregion.lock());
|
||||
|
||||
if (!region) {
|
||||
return;
|
||||
}
|
||||
|
||||
_last_capture_regions.remove (region);
|
||||
}
|
||||
|
||||
void
|
||||
Diskstream::playlist_ranges_moved (list< Evoral::RangeMove<framepos_t> > const & movements_frames)
|
||||
{
|
||||
|
@ -524,8 +524,8 @@ MidiDiskstream::process (nframes_t transport_frame, nframes_t nframes, bool can_
|
||||
}
|
||||
|
||||
|
||||
if (can_record && !_last_capture_regions.empty()) {
|
||||
_last_capture_regions.clear ();
|
||||
if (can_record && !_last_capture_sources.empty()) {
|
||||
_last_capture_sources.clear ();
|
||||
}
|
||||
|
||||
if (nominally_recording || rec_nframes) {
|
||||
@ -975,9 +975,7 @@ MidiDiskstream::transport_stopped_wallclock (struct tm& /*when*/, time_t /*twhen
|
||||
/* XXX what now? */
|
||||
}
|
||||
|
||||
_last_capture_regions.push_back (region);
|
||||
|
||||
// cerr << _name << ": there are " << capture_info.size() << " capture_info records\n";
|
||||
_last_capture_sources.insert (_last_capture_sources.end(), srcs.begin(), srcs.end());
|
||||
|
||||
_playlist->clear_history ();
|
||||
_playlist->freeze ();
|
||||
@ -1007,10 +1005,6 @@ MidiDiskstream::transport_stopped_wallclock (struct tm& /*when*/, time_t /*twhen
|
||||
continue; /* XXX is this OK? */
|
||||
}
|
||||
|
||||
region->DropReferences.connect_same_thread (*this, boost::bind (&Diskstream::remove_region_from_last_capture, this, boost::weak_ptr<Region>(region)));
|
||||
|
||||
_last_capture_regions.push_back (region);
|
||||
|
||||
// cerr << "add new region, buffer position = " << buffer_position << " @ " << (*ci)->start << endl;
|
||||
|
||||
i_am_the_modifier++;
|
||||
@ -1312,6 +1306,8 @@ MidiDiskstream::set_state (const XMLNode& node, int /*version*/)
|
||||
int
|
||||
MidiDiskstream::use_new_write_source (uint32_t n)
|
||||
{
|
||||
cerr << name() << " use new write source for n = " << n << " recordable ? " << recordable() << endl;
|
||||
|
||||
if (!recordable()) {
|
||||
return 1;
|
||||
}
|
||||
|
@ -359,15 +359,13 @@ bool
|
||||
MidiPlaylist::destroy_region (boost::shared_ptr<Region> region)
|
||||
{
|
||||
boost::shared_ptr<MidiRegion> r = boost::dynamic_pointer_cast<MidiRegion> (region);
|
||||
bool changed = false;
|
||||
|
||||
if (r == 0) {
|
||||
PBD::fatal << _("programming error: non-midi Region passed to remove_overlap in midi playlist")
|
||||
<< endmsg;
|
||||
/*NOTREACHED*/
|
||||
if (!r) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool changed = false;
|
||||
|
||||
{
|
||||
RegionLock rlock (this);
|
||||
RegionList::iterator i;
|
||||
|
@ -193,30 +193,7 @@ MidiRegion::_read_at (const SourceList& /*srcs*/, Evoral::EventSink<nframes_t>&
|
||||
XMLNode&
|
||||
MidiRegion::state (bool full)
|
||||
{
|
||||
XMLNode& node (Region::state (full));
|
||||
char buf[64];
|
||||
char buf2[64];
|
||||
LocaleGuard lg (X_("POSIX"));
|
||||
|
||||
// XXX these should move into Region
|
||||
|
||||
for (uint32_t n=0; n < _sources.size(); ++n) {
|
||||
snprintf (buf2, sizeof(buf2), "source-%d", n);
|
||||
_sources[n]->id().print (buf, sizeof(buf));
|
||||
node.add_property (buf2, buf);
|
||||
}
|
||||
|
||||
for (uint32_t n=0; n < _master_sources.size(); ++n) {
|
||||
snprintf (buf2, sizeof(buf2), "master-source-%d", n);
|
||||
_master_sources[n]->id().print (buf, sizeof (buf));
|
||||
node.add_property (buf2, buf);
|
||||
}
|
||||
|
||||
if (full && _extra_xml) {
|
||||
node.add_child_copy (*_extra_xml);
|
||||
}
|
||||
|
||||
return node;
|
||||
return Region::state (full);
|
||||
}
|
||||
|
||||
int
|
||||
|
@ -134,7 +134,7 @@ RegionListProperty::copy_for_history () const
|
||||
}
|
||||
|
||||
void
|
||||
RegionListProperty::diff (PropertyList& undo, PropertyList& redo) const
|
||||
RegionListProperty::diff (PropertyList& undo, PropertyList& redo, Command* cmd) const
|
||||
{
|
||||
if (changed()) {
|
||||
/* list of the removed/added regions since clear_history() was last called */
|
||||
@ -144,6 +144,18 @@ RegionListProperty::diff (PropertyList& undo, PropertyList& redo) const
|
||||
RegionListProperty* b = copy_for_history ();
|
||||
b->invert_changes ();
|
||||
|
||||
if (cmd) {
|
||||
/* whenever one of the regions emits DropReferences, make sure
|
||||
that the Destructible we've been told to notify hears about
|
||||
it. the Destructible is likely to be the Command being built
|
||||
with this diff().
|
||||
*/
|
||||
|
||||
for (set<boost::shared_ptr<Region> >::iterator i = a->change().added.begin(); i != a->change().added.end(); ++i) {
|
||||
(*i)->DropReferences.connect_same_thread (*cmd, boost::bind (&Destructible::drop_references, cmd));
|
||||
}
|
||||
}
|
||||
|
||||
undo.add (b);
|
||||
redo.add (a);
|
||||
}
|
||||
|
@ -415,6 +415,7 @@ Region::Region (boost::shared_ptr<const Region> other)
|
||||
Region::~Region ()
|
||||
{
|
||||
DEBUG_TRACE (DEBUG::Destruction, string_compose ("Region %1 destructor @ %2\n", _name, this));
|
||||
drop_sources ();
|
||||
}
|
||||
|
||||
void
|
||||
@ -1126,10 +1127,12 @@ Region::set_layer (layer_t l)
|
||||
}
|
||||
|
||||
XMLNode&
|
||||
Region::state (bool /*full_state*/)
|
||||
Region::state (bool full)
|
||||
{
|
||||
XMLNode *node = new XMLNode ("Region");
|
||||
char buf[64];
|
||||
char buf2[64];
|
||||
LocaleGuard lg (X_("POSIX"));
|
||||
const char* fe = NULL;
|
||||
|
||||
add_properties (*node);
|
||||
@ -1164,6 +1167,22 @@ Region::state (bool /*full_state*/)
|
||||
node->add_property ("bbt-position", str.str());
|
||||
}
|
||||
|
||||
for (uint32_t n=0; n < _sources.size(); ++n) {
|
||||
snprintf (buf2, sizeof(buf2), "source-%d", n);
|
||||
_sources[n]->id().print (buf, sizeof(buf));
|
||||
node->add_property (buf2, buf);
|
||||
}
|
||||
|
||||
for (uint32_t n=0; n < _master_sources.size(); ++n) {
|
||||
snprintf (buf2, sizeof(buf2), "master-source-%d", n);
|
||||
_master_sources[n]->id().print (buf, sizeof (buf));
|
||||
node->add_property (buf2, buf);
|
||||
}
|
||||
|
||||
if (full && _extra_xml) {
|
||||
node->add_child_copy (*_extra_xml);
|
||||
}
|
||||
|
||||
return *node;
|
||||
}
|
||||
|
||||
@ -1237,11 +1256,6 @@ Region::_set_state (const XMLNode& node, int version, PropertyChange& what_chang
|
||||
}
|
||||
|
||||
if (send) {
|
||||
cerr << _name << ": final change to be sent: ";
|
||||
for (PropertyChange::iterator i = what_changed.begin(); i != what_changed.end(); ++i) {
|
||||
cerr << g_quark_to_string ((GQuark) *i) << ' ';
|
||||
}
|
||||
cerr << endl;
|
||||
send_change (what_changed);
|
||||
}
|
||||
|
||||
@ -1335,7 +1349,7 @@ Region::region_list_equivalent (boost::shared_ptr<const Region> other) const
|
||||
void
|
||||
Region::source_deleted (boost::weak_ptr<Source>)
|
||||
{
|
||||
_sources.clear ();
|
||||
drop_sources ();
|
||||
|
||||
if (!_session.deletion_in_progress()) {
|
||||
/* this is a very special case: at least one of the region's
|
||||
@ -1366,8 +1380,16 @@ Region::master_source_names ()
|
||||
void
|
||||
Region::set_master_sources (const SourceList& srcs)
|
||||
{
|
||||
for (SourceList::const_iterator i = _master_sources.begin (); i != _master_sources.end(); ++i) {
|
||||
(*i)->dec_use_count ();
|
||||
}
|
||||
|
||||
_master_sources = srcs;
|
||||
assert (_sources.size() == _master_sources.size());
|
||||
|
||||
for (SourceList::const_iterator i = _master_sources.begin (); i != _master_sources.end(); ++i) {
|
||||
(*i)->inc_use_count ();
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
@ -1408,6 +1430,7 @@ Region::uses_source (boost::shared_ptr<const Source> source) const
|
||||
sframes_t
|
||||
Region::source_length(uint32_t n) const
|
||||
{
|
||||
assert (n < _sources.size());
|
||||
return _sources[n]->length(_position - _start);
|
||||
}
|
||||
|
||||
@ -1420,7 +1443,7 @@ Region::verify_length (framecnt_t len)
|
||||
|
||||
framecnt_t maxlen = 0;
|
||||
|
||||
for (uint32_t n=0; n < _sources.size(); ++n) {
|
||||
for (uint32_t n = 0; n < _sources.size(); ++n) {
|
||||
maxlen = max (maxlen, source_length(n) - _start);
|
||||
}
|
||||
|
||||
@ -1438,7 +1461,7 @@ Region::verify_start_and_length (framepos_t new_start, framecnt_t& new_length)
|
||||
|
||||
framecnt_t maxlen = 0;
|
||||
|
||||
for (uint32_t n=0; n < _sources.size(); ++n) {
|
||||
for (uint32_t n = 0; n < _sources.size(); ++n) {
|
||||
maxlen = max (maxlen, source_length(n) - new_start);
|
||||
}
|
||||
|
||||
@ -1454,7 +1477,7 @@ Region::verify_start (framepos_t pos)
|
||||
return true;
|
||||
}
|
||||
|
||||
for (uint32_t n=0; n < _sources.size(); ++n) {
|
||||
for (uint32_t n = 0; n < _sources.size(); ++n) {
|
||||
if (pos > source_length(n) - _length) {
|
||||
return false;
|
||||
}
|
||||
@ -1469,7 +1492,7 @@ Region::verify_start_mutable (framepos_t& new_start)
|
||||
return true;
|
||||
}
|
||||
|
||||
for (uint32_t n=0; n < _sources.size(); ++n) {
|
||||
for (uint32_t n = 0; n < _sources.size(); ++n) {
|
||||
if (new_start > source_length(n) - _length) {
|
||||
new_start = source_length(n) - _length;
|
||||
}
|
||||
@ -1508,6 +1531,21 @@ Region::invalidate_transients ()
|
||||
_transients.clear ();
|
||||
}
|
||||
|
||||
void
|
||||
Region::drop_sources ()
|
||||
{
|
||||
for (SourceList::const_iterator i = _sources.begin (); i != _sources.end(); ++i) {
|
||||
(*i)->dec_use_count ();
|
||||
}
|
||||
|
||||
_sources.clear ();
|
||||
|
||||
for (SourceList::const_iterator i = _master_sources.begin (); i != _master_sources.end(); ++i) {
|
||||
(*i)->dec_use_count ();
|
||||
}
|
||||
|
||||
_master_sources.clear ();
|
||||
}
|
||||
|
||||
void
|
||||
Region::use_sources (SourceList const & s)
|
||||
@ -1515,16 +1553,19 @@ Region::use_sources (SourceList const & s)
|
||||
set<boost::shared_ptr<Source> > unique_srcs;
|
||||
|
||||
for (SourceList::const_iterator i = s.begin (); i != s.end(); ++i) {
|
||||
_sources.push_back (*i);
|
||||
(*i)->DropReferences.connect_same_thread (*this, boost::bind (&Region::source_deleted, this, boost::weak_ptr<Source>(*i)));
|
||||
unique_srcs.insert (*i);
|
||||
}
|
||||
|
||||
for (SourceList::const_iterator i = s.begin (); i != s.end(); ++i) {
|
||||
_sources.push_back (*i);
|
||||
(*i)->inc_use_count ();
|
||||
_master_sources.push_back (*i);
|
||||
if (unique_srcs.find (*i) == unique_srcs.end()) {
|
||||
(*i)->DropReferences.connect_same_thread (*this, boost::bind (&Region::source_deleted, this, boost::weak_ptr<Source>(*i)));
|
||||
}
|
||||
(*i)->inc_use_count ();
|
||||
|
||||
/* connect only once to DropReferences, even if sources are replicated
|
||||
*/
|
||||
|
||||
if (unique_srcs.find (*i) == unique_srcs.end ()) {
|
||||
unique_srcs.insert (*i);
|
||||
(*i)->DropReferences.connect_same_thread (*this, boost::bind (&Region::source_deleted, this, boost::weak_ptr<Source>(*i)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -73,6 +73,7 @@ RegionFactory::create (boost::shared_ptr<const Region> region)
|
||||
}
|
||||
|
||||
if (ret) {
|
||||
cerr << "Pure copy constructor region " << ret << " named " << ret->name() << endl;
|
||||
map_add (ret);
|
||||
|
||||
/* pure copy constructor - no property list */
|
||||
@ -124,6 +125,7 @@ RegionFactory::create (boost::shared_ptr<Region> region, frameoffset_t offset, b
|
||||
|
||||
if (ret) {
|
||||
ret->set_properties (plist);
|
||||
cerr << "Partial copy constructor region\n";
|
||||
map_add (ret);
|
||||
|
||||
if (announce) {
|
||||
@ -163,6 +165,7 @@ RegionFactory::create (boost::shared_ptr<Region> region, const SourceList& srcs,
|
||||
if (ret) {
|
||||
|
||||
ret->set_properties (plist);
|
||||
cerr << "New sources copy constructor region\n";
|
||||
map_add (ret);
|
||||
|
||||
if (announce) {
|
||||
@ -208,6 +211,7 @@ RegionFactory::create (const SourceList& srcs, const PropertyList& plist, bool a
|
||||
if (ret) {
|
||||
|
||||
ret->set_properties (plist);
|
||||
cerr << "de-novo constructor region " << ret << " named " << ret->name() << endl;
|
||||
map_add (ret);
|
||||
|
||||
if (announce) {
|
||||
@ -281,6 +285,8 @@ RegionFactory::map_add (boost::shared_ptr<Region> r)
|
||||
boost::bind (&RegionFactory::region_changed, _1, boost::weak_ptr<Region> (r))
|
||||
);
|
||||
|
||||
cerr << "Added region with ID = " << r->id() << " named " << r->name() << endl;
|
||||
|
||||
update_region_name_map (r);
|
||||
}
|
||||
|
||||
@ -292,7 +298,32 @@ RegionFactory::map_remove (boost::shared_ptr<Region> r)
|
||||
|
||||
if (i != region_map.end()) {
|
||||
region_map.erase (i);
|
||||
cerr << "Removed region with ID = " << r->id() << " named " << r->name() << endl;;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
RegionFactory::map_remove_with_equivalents (boost::shared_ptr<Region> r)
|
||||
{
|
||||
Glib::Mutex::Lock lm (region_map_lock);
|
||||
|
||||
for (RegionMap::iterator i = region_map.begin(); i != region_map.end(); ) {
|
||||
RegionMap::iterator tmp = i;
|
||||
++tmp;
|
||||
|
||||
if (r->region_list_equivalent (i->second)) {
|
||||
cerr << "Removed equivalent region " << i->second->name() << '/' << i->first << endl;
|
||||
region_map.erase (i);
|
||||
} else if (r == i->second) {
|
||||
cerr << "Removed actual region " << i->second->name() << '/' << i->first << endl;
|
||||
region_map.erase (i);
|
||||
}
|
||||
|
||||
i = tmp;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
boost::shared_ptr<Region>
|
||||
@ -487,3 +518,15 @@ RegionFactory::new_region_name (string old)
|
||||
error << string_compose (_("cannot create new name for region \"%1\""), old) << endmsg;
|
||||
return old;
|
||||
}
|
||||
|
||||
void
|
||||
RegionFactory::get_regions_using_source (boost::shared_ptr<Source> s, std::set<boost::shared_ptr<Region> >& r)
|
||||
{
|
||||
Glib::Mutex::Lock lm (region_map_lock);
|
||||
|
||||
for (RegionMap::iterator i = region_map.begin(); i != region_map.end(); ++i) {
|
||||
if (i->second->uses_source (s)) {
|
||||
r.insert (i->second);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1484,6 +1484,7 @@ Session::new_midi_track (TrackMode mode, RouteGroup* route_group, uint32_t how_m
|
||||
auto_connect_route (track, existing_inputs, existing_outputs);
|
||||
|
||||
track->non_realtime_input_change();
|
||||
|
||||
if (route_group) {
|
||||
route_group->add (track);
|
||||
}
|
||||
@ -2483,46 +2484,58 @@ Session::find_whole_file_parent (boost::shared_ptr<Region const> child) const
|
||||
}
|
||||
|
||||
int
|
||||
Session::destroy_region (boost::shared_ptr<Region> region)
|
||||
Session::destroy_sources (list<boost::shared_ptr<Source> > srcs)
|
||||
{
|
||||
vector<boost::shared_ptr<Source> > srcs;
|
||||
set<boost::shared_ptr<Region> > relevant_regions;
|
||||
|
||||
{
|
||||
if (region->playlist()) {
|
||||
region->playlist()->destroy_region (region);
|
||||
}
|
||||
|
||||
for (uint32_t n = 0; n < region->n_channels(); ++n) {
|
||||
srcs.push_back (region->source (n));
|
||||
}
|
||||
for (list<boost::shared_ptr<Source> >::iterator s = srcs.begin(); s != srcs.end(); ++s) {
|
||||
RegionFactory::get_regions_using_source (*s, relevant_regions);
|
||||
}
|
||||
|
||||
region->drop_references ();
|
||||
cerr << "There are " << relevant_regions.size() << " using " << srcs.size() << " sources" << endl;
|
||||
|
||||
for (vector<boost::shared_ptr<Source> >::iterator i = srcs.begin(); i != srcs.end(); ++i) {
|
||||
for (set<boost::shared_ptr<Region> >::iterator r = relevant_regions.begin(); r != relevant_regions.end(); ) {
|
||||
set<boost::shared_ptr<Region> >::iterator tmp;
|
||||
|
||||
(*i)->mark_for_remove ();
|
||||
(*i)->drop_references ();
|
||||
tmp = r;
|
||||
++tmp;
|
||||
|
||||
cerr << "Cleanup " << (*r)->name() << " UC = " << (*r).use_count() << endl;
|
||||
|
||||
playlists->destroy_region (*r);
|
||||
RegionFactory::map_remove (*r);
|
||||
|
||||
(*r)->drop_sources ();
|
||||
(*r)->drop_references ();
|
||||
|
||||
cerr << "\tdone UC = " << (*r).use_count() << endl;
|
||||
|
||||
relevant_regions.erase (r);
|
||||
|
||||
r = tmp;
|
||||
}
|
||||
|
||||
for (list<boost::shared_ptr<Source> >::iterator s = srcs.begin(); s != srcs.end(); ) {
|
||||
|
||||
cerr << "source was not used by any playlist\n";
|
||||
}
|
||||
{
|
||||
Glib::Mutex::Lock ls (source_lock);
|
||||
/* remove from the main source list */
|
||||
sources.erase ((*s)->id());
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
(*s)->mark_for_remove ();
|
||||
(*s)->drop_references ();
|
||||
|
||||
s = srcs.erase (s);
|
||||
}
|
||||
|
||||
int
|
||||
Session::destroy_regions (list<boost::shared_ptr<Region> > regions)
|
||||
{
|
||||
for (list<boost::shared_ptr<Region> >::iterator i = regions.begin(); i != regions.end(); ++i) {
|
||||
destroy_region (*i);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
Session::remove_last_capture ()
|
||||
{
|
||||
list<boost::shared_ptr<Region> > r;
|
||||
list<boost::shared_ptr<Source> > srcs;
|
||||
|
||||
boost::shared_ptr<RouteList> rl = routes.reader ();
|
||||
for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
|
||||
@ -2531,15 +2544,15 @@ Session::remove_last_capture ()
|
||||
continue;
|
||||
}
|
||||
|
||||
list<boost::shared_ptr<Region> >& l = tr->last_capture_regions();
|
||||
list<boost::shared_ptr<Source> >& l = tr->last_capture_sources();
|
||||
|
||||
if (!l.empty()) {
|
||||
r.insert (r.end(), l.begin(), l.end());
|
||||
srcs.insert (srcs.end(), l.begin(), l.end());
|
||||
l.clear ();
|
||||
}
|
||||
}
|
||||
|
||||
destroy_regions (r);
|
||||
destroy_sources (srcs);
|
||||
|
||||
save_state (_current_snapshot_name);
|
||||
|
||||
@ -2563,16 +2576,19 @@ Session::add_source (boost::shared_ptr<Source> source)
|
||||
}
|
||||
|
||||
if (result.second) {
|
||||
|
||||
/* yay, new source */
|
||||
|
||||
set_dirty();
|
||||
}
|
||||
|
||||
boost::shared_ptr<AudioFileSource> afs;
|
||||
|
||||
if ((afs = boost::dynamic_pointer_cast<AudioFileSource>(source)) != 0) {
|
||||
if (Config->get_auto_analyse_audio()) {
|
||||
Analyser::queue_source_for_analysis (source, false);
|
||||
}
|
||||
}
|
||||
boost::shared_ptr<AudioFileSource> afs;
|
||||
|
||||
if ((afs = boost::dynamic_pointer_cast<AudioFileSource>(source)) != 0) {
|
||||
if (Config->get_auto_analyse_audio()) {
|
||||
Analyser::queue_source_for_analysis (source, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -219,6 +219,21 @@ SessionPlaylists::get (vector<boost::shared_ptr<Playlist> >& s)
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
SessionPlaylists::destroy_region (boost::shared_ptr<Region> r)
|
||||
{
|
||||
Glib::Mutex::Lock lm (lock);
|
||||
|
||||
for (List::iterator i = playlists.begin(); i != playlists.end(); ++i) {
|
||||
(*i)->destroy_region (r);
|
||||
}
|
||||
|
||||
for (List::iterator i = unused_playlists.begin(); i != unused_playlists.end(); ++i) {
|
||||
(*i)->destroy_region (r);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
SessionPlaylists::find_equivalent_playlist_regions (boost::shared_ptr<Region> region, vector<boost::shared_ptr<Region> >& result)
|
||||
{
|
||||
@ -262,14 +277,12 @@ SessionPlaylists::add_state (XMLNode* node, bool full_state)
|
||||
XMLNode* child = node->add_child ("Playlists");
|
||||
for (List::iterator i = playlists.begin(); i != playlists.end(); ++i) {
|
||||
if (!(*i)->hidden()) {
|
||||
if (!(*i)->empty()) {
|
||||
if (full_state) {
|
||||
child->add_child_nocopy ((*i)->get_state());
|
||||
} else {
|
||||
child->add_child_nocopy ((*i)->get_template());
|
||||
}
|
||||
}
|
||||
}
|
||||
if (full_state) {
|
||||
child->add_child_nocopy ((*i)->get_state());
|
||||
} else {
|
||||
child->add_child_nocopy ((*i)->get_template());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
child = node->add_child ("UnusedPlaylists");
|
||||
|
@ -1040,13 +1040,18 @@ Session::state(bool full_state)
|
||||
|
||||
for (SourceMap::iterator siter = sources.begin(); siter != sources.end(); ++siter) {
|
||||
|
||||
/* Don't save information about non-destructive file sources that are empty */
|
||||
/* FIXME: MIDI breaks if this is made FileSource like it should be... */
|
||||
/* Don't save information about non-destructive file sources that are empty
|
||||
and unused by any regions.
|
||||
*/
|
||||
|
||||
boost::shared_ptr<AudioFileSource> fs;
|
||||
if ((fs = boost::dynamic_pointer_cast<AudioFileSource> (siter->second)) != 0) {
|
||||
cerr << "Source " << siter->second->name() << " has UC = " << siter->second->used()
|
||||
<< " length = " << siter->second->length (0)
|
||||
<< endl;
|
||||
|
||||
boost::shared_ptr<FileSource> fs;
|
||||
if ((fs = boost::dynamic_pointer_cast<FileSource> (siter->second)) != 0) {
|
||||
if (!fs->destructive()) {
|
||||
if (fs->length(fs->timeline_position()) == 0) {
|
||||
if (fs->length(fs->timeline_position()) == 0 && !fs->used()) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
@ -52,6 +52,7 @@ Source::Source (Session& s, DataType type, const string& name, Flag flags)
|
||||
, _type(type)
|
||||
, _flags(flags)
|
||||
, _timeline_position(0)
|
||||
, _use_count (0)
|
||||
{
|
||||
_analysed = false;
|
||||
_timestamp = 0;
|
||||
@ -63,6 +64,7 @@ Source::Source (Session& s, const XMLNode& node)
|
||||
, _type(DataType::AUDIO)
|
||||
, _flags (Flag (Writable|CanRename))
|
||||
, _timeline_position(0)
|
||||
, _use_count (0)
|
||||
{
|
||||
_timestamp = 0;
|
||||
_analysed = false;
|
||||
|
@ -425,10 +425,10 @@ Track::destructive () const
|
||||
return _diskstream->destructive ();
|
||||
}
|
||||
|
||||
list<boost::shared_ptr<Region> > &
|
||||
Track::last_capture_regions ()
|
||||
list<boost::shared_ptr<Source> > &
|
||||
Track::last_capture_sources ()
|
||||
{
|
||||
return _diskstream->last_capture_regions ();
|
||||
return _diskstream->last_capture_sources ();
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -275,6 +275,16 @@ SMF::begin_write()
|
||||
void
|
||||
SMF::end_write() THROW_FILE_ERROR
|
||||
{
|
||||
#if 0
|
||||
/* don't create empty MIDI files
|
||||
*/
|
||||
|
||||
smf_rewind (_smf); // smf_save() would have done this anyway
|
||||
if (smf_peek_next_event (_smf) == 0) {
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
PBD::StdioFileDescriptor d (_file_path, "w+");
|
||||
FILE* f = d.allocate ();
|
||||
if (f == 0) {
|
||||
|
@ -22,10 +22,12 @@
|
||||
#ifndef __lib_pbd_command_h__
|
||||
#define __lib_pbd_command_h__
|
||||
|
||||
#include "pbd/statefuldestructible.h"
|
||||
#include <boost/utility.hpp>
|
||||
#include <string>
|
||||
|
||||
class Command : public PBD::StatefulDestructible, public boost::noncopyable
|
||||
#include "pbd/signals.h"
|
||||
#include "pbd/statefuldestructible.h"
|
||||
|
||||
class Command : public PBD::StatefulDestructible, public PBD::ScopedConnectionList
|
||||
{
|
||||
public:
|
||||
virtual ~Command() { /* NOTE: derived classes must call drop_references() */ }
|
||||
@ -34,7 +36,7 @@ public:
|
||||
|
||||
void set_name (const std::string& str) { _name = str; }
|
||||
const std::string& name() const { return _name; }
|
||||
|
||||
|
||||
virtual void undo() = 0;
|
||||
virtual void redo() { (*this)(); }
|
||||
|
||||
|
@ -165,7 +165,7 @@ public:
|
||||
: PropertyTemplate<T> (q, v)
|
||||
{}
|
||||
|
||||
void diff (PropertyList& undo, PropertyList& redo) const {
|
||||
void diff (PropertyList& undo, PropertyList& redo, Command* /*ignored*/) const {
|
||||
if (this->_have_old) {
|
||||
undo.add (new Property<T> (this->property_id(), this->_old));
|
||||
redo.add (new Property<T> (this->property_id(), this->_current));
|
||||
@ -227,7 +227,7 @@ public:
|
||||
: PropertyTemplate<std::string> (q, v)
|
||||
{}
|
||||
|
||||
void diff (PropertyList& before, PropertyList& after) const {
|
||||
void diff (PropertyList& before, PropertyList& after, Command* /*ignored*/) const {
|
||||
if (this->_have_old) {
|
||||
before.add (new Property<std::string> (PropertyDescriptor<std::string> (this->property_id()), this->_old));
|
||||
after.add (new Property<std::string> (PropertyDescriptor<std::string> (this->property_id()), this->_current));
|
||||
|
@ -25,6 +25,8 @@
|
||||
|
||||
#include "pbd/xml++.h"
|
||||
|
||||
class Command;
|
||||
|
||||
namespace PBD {
|
||||
|
||||
class PropertyList;
|
||||
@ -83,7 +85,7 @@ public:
|
||||
{}
|
||||
|
||||
virtual ~PropertyBase () {}
|
||||
|
||||
|
||||
/** Forget about any old value for this state */
|
||||
virtual void clear_history () = 0;
|
||||
|
||||
@ -97,7 +99,7 @@ public:
|
||||
* the last call to clear_history, and one that allows redo
|
||||
* of those changes.
|
||||
*/
|
||||
virtual void diff (PropertyList& undo, PropertyList& redo) const = 0;
|
||||
virtual void diff (PropertyList& undo, PropertyList& redo, Command*) const = 0;
|
||||
|
||||
virtual PropertyBase* maybe_clone_self_if_found_in_history_node (const XMLNode&) const { return 0; }
|
||||
|
||||
|
@ -67,7 +67,7 @@ class Stateful {
|
||||
/* history management */
|
||||
|
||||
void clear_history ();
|
||||
void diff (PropertyList&, PropertyList&) const;
|
||||
void diff (PropertyList&, PropertyList&, Command*) const;
|
||||
bool changed() const;
|
||||
|
||||
/* create a property list from an XMLNode
|
||||
|
@ -27,7 +27,7 @@
|
||||
namespace PBD
|
||||
{
|
||||
|
||||
class Stateful;
|
||||
class StatefulDestructible;
|
||||
class PropertyList;
|
||||
|
||||
/** A Command which stores its action as the differences between the before and after
|
||||
@ -36,13 +36,13 @@ class PropertyList;
|
||||
class StatefulDiffCommand : public Command
|
||||
{
|
||||
public:
|
||||
StatefulDiffCommand (boost::shared_ptr<Stateful>);
|
||||
StatefulDiffCommand (boost::shared_ptr<Stateful>, XMLNode const &);
|
||||
StatefulDiffCommand (boost::shared_ptr<StatefulDestructible>);
|
||||
StatefulDiffCommand (boost::shared_ptr<StatefulDestructible>, XMLNode const &);
|
||||
~StatefulDiffCommand ();
|
||||
|
||||
void operator() ();
|
||||
void undo ();
|
||||
|
||||
|
||||
XMLNode& get_state ();
|
||||
|
||||
private:
|
||||
|
@ -27,12 +27,11 @@
|
||||
#include <sigc++/bind.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#include "pbd/signals.h"
|
||||
#include "pbd/command.h"
|
||||
|
||||
typedef sigc::slot<void> UndoAction;
|
||||
|
||||
class UndoTransaction : public Command, public PBD::ScopedConnectionList
|
||||
class UndoTransaction : public Command
|
||||
{
|
||||
public:
|
||||
UndoTransaction ();
|
||||
|
@ -167,10 +167,10 @@ Stateful::clear_history ()
|
||||
}
|
||||
|
||||
void
|
||||
Stateful::diff (PropertyList& before, PropertyList& after) const
|
||||
Stateful::diff (PropertyList& before, PropertyList& after, Command* cmd) const
|
||||
{
|
||||
for (OwnedPropertyList::const_iterator i = _properties->begin(); i != _properties->end(); ++i) {
|
||||
i->second->diff (before, after);
|
||||
i->second->diff (before, after, cmd);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -32,15 +32,21 @@ using namespace PBD;
|
||||
* @param s Stateful object.
|
||||
*/
|
||||
|
||||
StatefulDiffCommand::StatefulDiffCommand (boost::shared_ptr<Stateful> s)
|
||||
: _object (s)
|
||||
StatefulDiffCommand::StatefulDiffCommand (boost::shared_ptr<StatefulDestructible> s)
|
||||
: _object (s)
|
||||
, _undo (new PropertyList)
|
||||
, _redo (new PropertyList)
|
||||
{
|
||||
s->diff (*_undo, *_redo);
|
||||
s->diff (*_undo, *_redo, this);
|
||||
|
||||
/* if the stateful object that this command refers to goes away,
|
||||
be sure to notify owners of this command.
|
||||
*/
|
||||
|
||||
s->DropReferences.connect_same_thread (*this, boost::bind (&Destructible::drop_references, this));
|
||||
}
|
||||
|
||||
StatefulDiffCommand::StatefulDiffCommand (boost::shared_ptr<Stateful> s, XMLNode const & n)
|
||||
StatefulDiffCommand::StatefulDiffCommand (boost::shared_ptr<StatefulDestructible> s, XMLNode const & n)
|
||||
: _object (s)
|
||||
, _undo (0)
|
||||
, _redo (0)
|
||||
@ -57,10 +63,18 @@ StatefulDiffCommand::StatefulDiffCommand (boost::shared_ptr<Stateful> s, XMLNode
|
||||
|
||||
assert (_undo != 0);
|
||||
assert (_redo != 0);
|
||||
|
||||
/* if the stateful object that this command refers to goes away,
|
||||
be sure to notify owners of this command.
|
||||
*/
|
||||
|
||||
s->DropReferences.connect_same_thread (*this, boost::bind (&Destructible::drop_references, this));
|
||||
}
|
||||
|
||||
StatefulDiffCommand::~StatefulDiffCommand ()
|
||||
{
|
||||
drop_references ();
|
||||
|
||||
delete _undo;
|
||||
delete _redo;
|
||||
}
|
||||
|
@ -39,7 +39,6 @@ UndoTransaction::UndoTransaction ()
|
||||
|
||||
UndoTransaction::UndoTransaction (const UndoTransaction& rhs)
|
||||
: Command(rhs._name)
|
||||
, PBD::ScopedConnectionList ()
|
||||
, _clearing(false)
|
||||
{
|
||||
clear ();
|
||||
@ -77,15 +76,15 @@ UndoTransaction::operator= (const UndoTransaction& rhs)
|
||||
}
|
||||
|
||||
void
|
||||
UndoTransaction::add_command (Command *const action)
|
||||
UndoTransaction::add_command (Command *const cmd)
|
||||
{
|
||||
/* catch death of command (e.g. caused by death of object to
|
||||
which it refers. command_death() is a normal static function
|
||||
so there is no need to manage this connection.
|
||||
*/
|
||||
|
||||
action->DropReferences.connect_same_thread (*this, boost::bind (&command_death, this, action));
|
||||
actions.push_back (action);
|
||||
cmd->DropReferences.connect_same_thread (*this, boost::bind (&command_death, this, cmd));
|
||||
actions.push_back (cmd);
|
||||
}
|
||||
|
||||
void
|
||||
@ -250,9 +249,6 @@ UndoHistory::undo (unsigned int n)
|
||||
return;
|
||||
}
|
||||
|
||||
struct timeval start, end, diff;
|
||||
gettimeofday (&start, 0);
|
||||
|
||||
{
|
||||
UndoRedoSignaller exception_safe_signaller (*this);
|
||||
|
||||
@ -265,16 +261,8 @@ UndoHistory::undo (unsigned int n)
|
||||
ut->undo ();
|
||||
RedoList.push_back (ut);
|
||||
}
|
||||
gettimeofday (&end, 0);
|
||||
timersub (&end, &start, &diff);
|
||||
cerr << "Undo-pre-signals took " << diff.tv_sec << '.' << diff.tv_usec << endl;
|
||||
|
||||
}
|
||||
|
||||
gettimeofday (&end, 0);
|
||||
timersub (&end, &start, &diff);
|
||||
cerr << "Undo took " << diff.tv_sec << '.' << diff.tv_usec << endl;
|
||||
|
||||
Changed (); /* EMIT SIGNAL */
|
||||
}
|
||||
|
||||
@ -285,9 +273,6 @@ UndoHistory::redo (unsigned int n)
|
||||
return;
|
||||
}
|
||||
|
||||
struct timeval start, end, diff;
|
||||
gettimeofday (&start, 0);
|
||||
|
||||
{
|
||||
UndoRedoSignaller exception_safe_signaller (*this);
|
||||
|
||||
@ -300,15 +285,8 @@ UndoHistory::redo (unsigned int n)
|
||||
ut->redo ();
|
||||
UndoList.push_back (ut);
|
||||
}
|
||||
gettimeofday (&end, 0);
|
||||
timersub (&end, &start, &diff);
|
||||
cerr << "Redo-pre-signals took " << diff.tv_sec << '.' << diff.tv_usec << endl;
|
||||
}
|
||||
|
||||
gettimeofday (&end, 0);
|
||||
timersub (&end, &start, &diff);
|
||||
cerr << "Redo took " << diff.tv_sec << '.' << diff.tv_usec << endl;
|
||||
|
||||
Changed (); /* EMIT SIGNAL */
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user