the mega-properties/SequenceProperty patch. split is broken at present (right hand starts has start-in-source of zero)

git-svn-id: svn://localhost/ardour2/branches/3.0@6718 d708f5d6-7413-0410-9779-e7cbd77b26cf
This commit is contained in:
Paul Davis 2010-03-02 00:00:00 +00:00
parent 3540594dc5
commit db8b575c30
48 changed files with 1552 additions and 484 deletions

View File

@ -3995,7 +3995,7 @@ Editor::new_playlists (TimeAxisView* v)
begin_reversible_command (_("new playlists"));
vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
_session->playlists->get (playlists);
mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_new_playlist), playlists), v, ARDOUR::Properties::edit.id);
mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_new_playlist), playlists), v, ARDOUR::Properties::edit.property_id);
commit_reversible_command ();
}
@ -4011,7 +4011,7 @@ Editor::copy_playlists (TimeAxisView* v)
begin_reversible_command (_("copy playlists"));
vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
_session->playlists->get (playlists);
mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_copy_playlist), playlists), v, ARDOUR::Properties::edit.id);
mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_copy_playlist), playlists), v, ARDOUR::Properties::edit.property_id);
commit_reversible_command ();
}
@ -4026,7 +4026,7 @@ Editor::clear_playlists (TimeAxisView* v)
begin_reversible_command (_("clear playlists"));
vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
_session->playlists->get (playlists);
mapover_tracks (sigc::mem_fun (*this, &Editor::mapped_clear_playlist), v, ARDOUR::Properties::edit.id);
mapover_tracks (sigc::mem_fun (*this, &Editor::mapped_clear_playlist), v, ARDOUR::Properties::edit.property_id);
commit_reversible_command ();
}

View File

@ -838,7 +838,7 @@ Editor::finish_bringing_in_material (boost::shared_ptr<Region> region, uint32_t
}
boost::shared_ptr<Playlist> playlist = existing_track->diskstream()->playlist();
boost::shared_ptr<Region> copy (RegionFactory::create (region));
boost::shared_ptr<Region> copy (RegionFactory::create (region, region->properties()));
begin_reversible_command (_("insert file"));
XMLNode &before = playlist->get_state();
playlist->add_region (copy, pos);

View File

@ -818,6 +818,7 @@ RegionMoveDrag::finished (GdkEvent* /*event*/, bool movement_occurred)
vector<RegionView*> copies;
boost::shared_ptr<Diskstream> ds;
boost::shared_ptr<Playlist> from_playlist;
boost::shared_ptr<Playlist> to_playlist;
RegionSelection new_views;
typedef set<boost::shared_ptr<Playlist> > PlaylistSet;
PlaylistSet modified_playlists;
@ -828,6 +829,7 @@ RegionMoveDrag::finished (GdkEvent* /*event*/, bool movement_occurred)
bool changed_tracks, changed_position;
map<RegionView*, pair<RouteTimeAxisView*, int> > final;
RouteTimeAxisView* source_tv;
vector<StatefulDiffCommand*> sdc;
if (!movement_occurred) {
/* just a click */
@ -878,6 +880,8 @@ RegionMoveDrag::finished (GdkEvent* /*event*/, bool movement_occurred)
/* make a list of where each region ended up */
final = find_time_axis_views_and_layers ();
cerr << "Iterate over " << _views.size() << " views\n";
for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ) {
RegionView* rv = (*i);
@ -886,6 +890,9 @@ RegionMoveDrag::finished (GdkEvent* /*event*/, bool movement_occurred)
nframes64_t where;
from_playlist.reset ();
to_playlist.reset ();
if (rv->region()->locked()) {
++i;
continue;
@ -915,7 +922,7 @@ RegionMoveDrag::finished (GdkEvent* /*event*/, bool movement_occurred)
if (changed_tracks || _copy) {
boost::shared_ptr<Playlist> to_playlist = dest_rtv->playlist();
to_playlist = dest_rtv->playlist();
if (!to_playlist) {
++i;
@ -929,10 +936,18 @@ RegionMoveDrag::finished (GdkEvent* /*event*/, bool movement_occurred)
insert_result = modified_playlists.insert (to_playlist);
if (insert_result.second) {
_editor->session()->add_command (new MementoCommand<Playlist>(*to_playlist, &to_playlist->get_state(), 0));
to_playlist->clear_history ();
}
cerr << "To playlist " << to_playlist->name() << " region history contains "
<< to_playlist->region_list().change().added.size() << " adds and "
<< to_playlist->region_list().change().removed.size() << " removes\n";
cerr << "Adding new region " << new_region->id() << " based on "
<< rv->region()->id() << endl;
to_playlist->add_region (new_region, where);
if (dest_rtv->view()->layer_display() == Stacked) {
new_region->set_layer (dest_layer);
new_region->set_pending_explicit_relayer (true);
@ -977,9 +992,11 @@ RegionMoveDrag::finished (GdkEvent* /*event*/, bool movement_occurred)
playlist->freeze();
}
cerr << "Moving region " << rv->region()->id() << endl;
rv->region()->set_position (where, (void*) this);
_editor->session()->add_command (new StatefulDiffCommand (rv->region()));
sdc.push_back (new StatefulDiffCommand (rv->region()));
}
if (changed_tracks && !_copy) {
@ -1012,9 +1029,15 @@ RegionMoveDrag::finished (GdkEvent* /*event*/, bool movement_occurred)
insert_result = modified_playlists.insert (from_playlist);
if (insert_result.second) {
_editor->session()->add_command (new MementoCommand<Playlist>(*from_playlist, &from_playlist->get_state(), 0));
from_playlist->clear_history ();
}
cerr << "From playlist " << from_playlist->name() << " region history contains "
<< from_playlist->region_list().change().added.size() << " adds and "
<< from_playlist->region_list().change().removed.size() << " removes\n";
cerr << "removing region " << rv->region() << endl;
from_playlist->remove_region (rv->region());
/* OK, this is where it gets tricky. If the playlist was being used by >1 tracks, and the region
@ -1035,7 +1058,16 @@ RegionMoveDrag::finished (GdkEvent* /*event*/, bool movement_occurred)
*/
if (_views.empty()) {
break;
if (to_playlist) {
sdc.push_back (new StatefulDiffCommand (to_playlist));
cerr << "Saved diff for to:" << to_playlist->name() << endl;
}
if (from_playlist && (from_playlist != to_playlist)) {
sdc.push_back (new StatefulDiffCommand (from_playlist));
cerr << "Saved diff for from:" << from_playlist->name() << endl;
}
break;
} else {
i = _views.begin();
}
@ -1047,11 +1079,25 @@ RegionMoveDrag::finished (GdkEvent* /*event*/, bool movement_occurred)
if (_copy) {
copies.push_back (rv);
}
cerr << "Done with TV, top = " << to_playlist << " from = " << from_playlist << endl;
if (to_playlist) {
sdc.push_back (new StatefulDiffCommand (to_playlist));
cerr << "Saved diff for to:" << to_playlist->name() << endl;
}
if (from_playlist && (from_playlist != to_playlist)) {
sdc.push_back (new StatefulDiffCommand (from_playlist));
cerr << "Saved diff for from:" << from_playlist->name() << endl;
}
}
/*
if we've created new regions either by copying or moving
to a new track, we want to replace the old selection with the new ones
*/
if (new_views.size() > 0) {
_editor->selection->set (new_views);
}
@ -1061,9 +1107,9 @@ RegionMoveDrag::finished (GdkEvent* /*event*/, bool movement_occurred)
}
out:
for (set<boost::shared_ptr<Playlist> >::iterator p = modified_playlists.begin(); p != modified_playlists.end(); ++p) {
_editor->session()->add_command (new MementoCommand<Playlist>(*(*p), 0, &(*p)->get_state()));
}
for (vector<StatefulDiffCommand*>::iterator i = sdc.begin(); i != sdc.end(); ++i) {
_editor->session()->add_command (*i);
}
_editor->commit_reversible_command ();

View File

@ -687,14 +687,14 @@ Editor::button_press_handler_1 (ArdourCanvas::Item* item, GdkEvent* event, ItemT
switch (item_type) {
case FadeInHandleItem:
{
RegionSelection s = get_equivalent_regions (selection->regions, Properties::edit.id);
RegionSelection s = get_equivalent_regions (selection->regions, Properties::edit.property_id);
_drags->set (new FadeInDrag (this, item, reinterpret_cast<RegionView*> (item->get_data("regionview")), s), event);
return true;
}
case FadeOutHandleItem:
{
RegionSelection s = get_equivalent_regions (selection->regions, Properties::edit.id);
RegionSelection s = get_equivalent_regions (selection->regions, Properties::edit.property_id);
_drags->set (new FadeOutDrag (this, item, reinterpret_cast<RegionView*> (item->get_data("regionview")), s), event);
return true;
}
@ -717,7 +717,7 @@ Editor::button_press_handler_1 (ArdourCanvas::Item* item, GdkEvent* event, ItemT
case RegionViewNameHighlight:
{
RegionSelection s = get_equivalent_regions (selection->regions, Properties::edit.id);
RegionSelection s = get_equivalent_regions (selection->regions, Properties::edit.property_id);
_drags->set (new TrimDrag (this, item, clicked_regionview, s.by_layer()), event);
return true;
break;
@ -726,7 +726,7 @@ Editor::button_press_handler_1 (ArdourCanvas::Item* item, GdkEvent* event, ItemT
case RegionViewName:
{
/* rename happens on edit clicks */
RegionSelection s = get_equivalent_regions (selection->regions, Properties::edit.id);
RegionSelection s = get_equivalent_regions (selection->regions, Properties::edit.property_id);
_drags->set (new TrimDrag (this, clicked_regionview->get_name_highlight(), clicked_regionview, s.by_layer()), event);
return true;
break;
@ -2484,7 +2484,7 @@ Editor::add_region_drag (ArdourCanvas::Item* item, GdkEvent* event, RegionView*
if (Config->get_edit_mode() == Splice) {
_drags->add (new RegionSpliceDrag (this, item, region_view, selection->regions.by_layer()));
} else {
RegionSelection s = get_equivalent_regions (selection->regions, ARDOUR::Properties::edit.id);
RegionSelection s = get_equivalent_regions (selection->regions, ARDOUR::Properties::edit.property_id);
_drags->add (new RegionMoveDrag (this, item, region_view, s.by_layer(), false, false));
}
@ -2499,7 +2499,7 @@ Editor::add_region_copy_drag (ArdourCanvas::Item* item, GdkEvent* event, RegionV
_region_motion_group->raise_to_top ();
RegionSelection s = get_equivalent_regions (selection->regions, ARDOUR::Properties::edit.id);
RegionSelection s = get_equivalent_regions (selection->regions, ARDOUR::Properties::edit.property_id);
_drags->add (new RegionMoveDrag (this, item, region_view, s.by_layer(), false, true));
}
@ -2512,7 +2512,7 @@ Editor::add_region_brush_drag (ArdourCanvas::Item* item, GdkEvent* event, Region
return;
}
RegionSelection s = get_equivalent_regions (selection->regions, ARDOUR::Properties::edit.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));
begin_reversible_command (_("Drag region brush"));

View File

@ -169,10 +169,9 @@ Editor::split_regions_at (nframes64_t where, RegionSelection& regions)
}
if (pl) {
XMLNode &before = pl->get_state();
pl->clear_history ();
pl->split_region ((*a)->region(), where);
XMLNode &after = pl->get_state();
_session->add_command(new MementoCommand<Playlist>(*pl, &before, &after));
_session->add_command (new StatefulDiffCommand (pl));
}
a = tmp;
@ -4883,7 +4882,7 @@ Editor::brush (nframes64_t pos)
void
Editor::reset_region_gain_envelopes ()
{
RegionSelection rs = get_equivalent_regions (selection->regions, ARDOUR::Properties::edit.id);
RegionSelection rs = get_equivalent_regions (selection->regions, ARDOUR::Properties::edit.property_id);
if (!_session || rs.empty()) {
return;
@ -4908,7 +4907,7 @@ Editor::reset_region_gain_envelopes ()
void
Editor::toggle_gain_envelope_visibility ()
{
RegionSelection rs = get_equivalent_regions (selection->regions, ARDOUR::Properties::edit.id);
RegionSelection rs = get_equivalent_regions (selection->regions, ARDOUR::Properties::edit.property_id);
if (!_session || rs.empty()) {
return;
@ -4932,7 +4931,7 @@ Editor::toggle_gain_envelope_visibility ()
void
Editor::toggle_gain_envelope_active ()
{
RegionSelection rs = get_equivalent_regions (selection->regions, ARDOUR::Properties::edit.id);
RegionSelection rs = get_equivalent_regions (selection->regions, ARDOUR::Properties::edit.property_id);
if (!_session || rs.empty()) {
return;
@ -4955,7 +4954,7 @@ Editor::toggle_gain_envelope_active ()
void
Editor::toggle_region_lock ()
{
RegionSelection rs = get_equivalent_regions (selection->regions, ARDOUR::Properties::edit.id);
RegionSelection rs = get_equivalent_regions (selection->regions, ARDOUR::Properties::edit.property_id);
if (!_session || rs.empty()) {
return;
@ -4975,7 +4974,7 @@ Editor::toggle_region_lock ()
void
Editor::set_region_lock_style (Region::PositionLockStyle ps)
{
RegionSelection rs = get_equivalent_regions (selection->regions, ARDOUR::Properties::edit.id);
RegionSelection rs = get_equivalent_regions (selection->regions, ARDOUR::Properties::edit.property_id);
if (!_session || rs.empty()) {
return;
@ -4997,7 +4996,7 @@ Editor::set_region_lock_style (Region::PositionLockStyle ps)
void
Editor::toggle_region_mute ()
{
RegionSelection rs = get_equivalent_regions (selection->regions, ARDOUR::Properties::edit.id);
RegionSelection rs = get_equivalent_regions (selection->regions, ARDOUR::Properties::edit.property_id);
if (!_session || rs.empty()) {
return;
@ -5017,7 +5016,7 @@ Editor::toggle_region_mute ()
void
Editor::toggle_region_opaque ()
{
RegionSelection rs = get_equivalent_regions (selection->regions, ARDOUR::Properties::edit.id);
RegionSelection rs = get_equivalent_regions (selection->regions, ARDOUR::Properties::edit.property_id);
if (!_session || rs.empty()) {
return;

View File

@ -476,7 +476,7 @@ Editor::set_selected_regionview_from_click (bool press, Selection::Operation op,
if (press) {
if (selection->selected (clicked_routeview)) {
get_equivalent_regions (clicked_regionview, all_equivalent_regions, ARDOUR::Properties::select.id);
get_equivalent_regions (clicked_regionview, all_equivalent_regions, ARDOUR::Properties::select.property_id);
} else {
all_equivalent_regions.push_back (clicked_regionview);
}
@ -494,7 +494,7 @@ Editor::set_selected_regionview_from_click (bool press, Selection::Operation op,
case Selection::Set:
if (!selection->selected (clicked_regionview)) {
get_equivalent_regions (clicked_regionview, all_equivalent_regions, ARDOUR::Properties::select.id);
get_equivalent_regions (clicked_regionview, all_equivalent_regions, ARDOUR::Properties::select.property_id);
selection->set (all_equivalent_regions);
commit = true;
} else {

View File

@ -139,7 +139,7 @@ ARDOUR_COMMAND_LINE::parse_opts (int argc, char *argv[])
break;
case 'D':
if (ARDOUR::parse_debug_options (optarg)) {
if (PBD::parse_debug_options (optarg)) {
exit (0);
}
break;

View File

@ -24,51 +24,28 @@
#include <sstream>
namespace ARDOUR {
extern uint64_t debug_bits;
void debug_print (const char* prefix, std::string str);
void set_debug_bits (uint64_t bits);
int parse_debug_options (const char* str);
void list_debug_options ();
#include "pbd/debug.h"
namespace PBD {
namespace DEBUG {
/* this namespace is so that we can write DEBUG::bit_name */
enum DebugBits {
MidiSourceIO = 0x1,
MidiPlaylistIO = 0x2,
MidiDiskstreamIO = 0x4,
SnapBBT = 0x8,
Configuration = 0x10,
Latency = 0x20,
Processors = 0x40,
Graph = 0x80,
Destruction = 0x100,
MTC = 0x200,
Transport = 0x400,
Slave = 0x800,
SessionEvents = 0x800,
MidiIO = 0x1000,
MackieControl = 0x2000,
MidiClock = 0x4000,
Properties = 0x8000
};
extern uint64_t MidiSourceIO;
extern uint64_t MidiPlaylistIO;
extern uint64_t MidiDiskstreamIO;
extern uint64_t SnapBBT;
extern uint64_t Configuration;
extern uint64_t Latency;
extern uint64_t Processors;
extern uint64_t Graph;
extern uint64_t Destruction;
extern uint64_t MTC;
extern uint64_t Transport;
extern uint64_t Slave;
extern uint64_t SessionEvents;
extern uint64_t MidiIO;
extern uint64_t MackieControl;
extern uint64_t MidiClock;
}
}
#ifndef NDEBUG
#define DEBUG_TRACE(bits,str) if ((bits) & ARDOUR::debug_bits) { ARDOUR::debug_print (# bits, str); }
#define DEBUG_STR_DECL(id) std::stringstream __debug_str ## id;
#define DEBUG_STR(id) __debug_str ## id
#define DEBUG_STR_APPEND(id,s) __debug_str ## id << s;
#else
#define DEBUG_TRACE(bits,fmt,...) /*empty*/
#define DEBUG_STR(a) /* empty */
#define DEBUG_STR_APPEND(a,b) /* empty */
#endif
#endif /* __ardour_debug_h__ */

View File

@ -36,6 +36,7 @@
#include "pbd/undo.h"
#include "pbd/stateful.h"
#include "pbd/statefuldestructible.h"
#include "pbd/sequence_property.h"
#include "evoral/types.hpp"
@ -49,11 +50,43 @@ namespace ARDOUR {
class Session;
class Region;
class Playlist;
namespace Properties {
/* fake the type, since regions are handled by SequenceProperty which doesn't
care about such things.
*/
extern PBD::PropertyDescriptor<bool> regions;
}
class RegionListProperty : public PBD::SequenceProperty<std::list<boost::shared_ptr<Region > > >
{
public:
RegionListProperty (Playlist&);
boost::shared_ptr<Region> lookup_id (const PBD::ID& id);
void diff (PBD::PropertyList& before, PBD::PropertyList& after) const;
private:
friend class Playlist;
std::list<boost::shared_ptr<Region> > rlist() { return _val; }
/* we live and die with our playlist, no lifetime management needed */
Playlist& _playlist;
/* create a copy of this RegionListProperty that only
has what is needed for use in a history list command. This
means that it won't contain the actual region list but
will have the added/removed list.
*/
RegionListProperty* copy_for_history () const;
};
class Playlist : public SessionObject
, public boost::enable_shared_from_this<Playlist> {
public:
typedef std::list<boost::shared_ptr<Region> > RegionList;
static void make_property_quarks ();
Playlist (Session&, const XMLNode&, DataType type, bool hidden = false);
Playlist (Session&, std::string name, DataType type, bool hidden = false);
@ -62,6 +95,13 @@ class Playlist : public SessionObject
virtual ~Playlist ();
bool set_property (const PBD::PropertyBase&);
void update (const RegionListProperty::ChangeRecord&);
PBD::PropertyList* property_factory (const XMLNode&) const;
boost::shared_ptr<Region> region_by_id (const PBD::ID&);
void set_region_ownership ();
virtual void clear (bool with_signals=true);
@ -107,7 +147,7 @@ class Playlist : public SessionObject
boost::shared_ptr<Playlist> copy (std::list<AudioRange>&, bool result_is_hidden = true);
int paste (boost::shared_ptr<Playlist>, framepos_t position, float times);
const RegionList& region_list () const { return regions; }
const RegionListProperty& region_list () const { return regions; }
RegionList* regions_at (framepos_t frame);
RegionList* regions_touched (framepos_t start, framepos_t end);
@ -192,7 +232,7 @@ class Playlist : public SessionObject
friend class RegionLock;
RegionList regions; /* the current list of regions in the playlist */
RegionListProperty regions; /* the current list of regions in the playlist */
std::set<boost::shared_ptr<Region> > all_regions; /* all regions ever added to this playlist */
PBD::ScopedConnectionList region_state_changed_connections;
DataType _type;
@ -277,8 +317,6 @@ class Playlist : public SessionObject
virtual XMLNode& state (bool);
boost::shared_ptr<Region> region_by_id (PBD::ID);
bool add_region_internal (boost::shared_ptr<Region>, framepos_t position);
int remove_region_internal (boost::shared_ptr<Region>);

View File

@ -91,6 +91,8 @@ class Region
static PBD::Signal2<void,boost::shared_ptr<ARDOUR::Region>, const PBD::PropertyChange&> RegionPropertyChanged;
PBD::PropertyList* property_factory (const XMLNode&) const;
void unlock_property_changes () { _no_property_changes = false; }
void block_property_changes () { _no_property_changes = true; }

View File

@ -21,6 +21,7 @@
#define __ardour_region_factory_h__
#include <map>
#include <glibmm/thread.h>
#include "pbd/id.h"
@ -37,8 +38,10 @@ class AudioRegion;
class RegionFactory {
public:
typedef std::map<PBD::ID,boost::shared_ptr<Region> > RegionMap;
static boost::shared_ptr<Region> region_by_id (const PBD::ID&);
static const RegionMap all_regions() { return region_map; }
static void clear_map ();
/** This is emitted only when a new id is assigned. Therefore,
@ -75,8 +78,10 @@ class RegionFactory {
static boost::shared_ptr<Region> create (SourceList& srcs, const XMLNode&);
private:
static std::map<PBD::ID,boost::weak_ptr<Region> > region_map;
static Glib::StaticMutex region_map_lock;
static RegionMap region_map;
static void map_add (boost::shared_ptr<Region>);
static void map_remove (boost::shared_ptr<Region>);
};
}

View File

@ -501,6 +501,9 @@ class Session : public PBD::StatefulDestructible, public PBD::ScopedConnectionLi
/* region info */
boost::shared_ptr<Region> region_by_id (const PBD::ID&) const;
boost::shared_ptr<Region> find_whole_file_parent (boost::shared_ptr<Region const>) const;
void add_regions (std::vector<boost::shared_ptr<Region> >&);
PBD::Signal1<void,boost::weak_ptr<Region> > RegionAdded;
@ -511,8 +514,6 @@ class Session : public PBD::StatefulDestructible, public PBD::ScopedConnectionLi
std::string new_region_name (std::string);
std::string path_from_region_name (DataType type, std::string name, std::string identifier);
boost::shared_ptr<Region> find_whole_file_parent (boost::shared_ptr<Region const>);
boost::shared_ptr<Region> XMLRegionFactory (const XMLNode&, bool full);
boost::shared_ptr<AudioRegion> XMLAudioRegionFactory (const XMLNode&, bool full);
boost::shared_ptr<MidiRegion> XMLMidiRegionFactory (const XMLNode&, bool full);

View File

@ -23,6 +23,7 @@
#include <string>
#include "pbd/statefuldestructible.h"
#include "pbd/signals.h"
#include "pbd/properties.h"
#include "ardour/ardour.h"
#include "ardour/session_handle.h"

View File

@ -31,6 +31,10 @@
class XMLNode;
namespace PBD {
class ID;
}
namespace ARDOUR {
class Playlist;
@ -44,6 +48,7 @@ public:
~SessionPlaylists ();
boost::shared_ptr<Playlist> by_name (std::string name);
boost::shared_ptr<Playlist> by_id (const PBD::ID&);
uint32_t source_use_count (boost::shared_ptr<const Source> src) const;
template<class T> void foreach (T *obj, void (T::*func)(boost::shared_ptr<Playlist>));
void get (std::vector<boost::shared_ptr<Playlist> >&);

View File

@ -67,12 +67,18 @@ namespace ARDOUR {
void
AudioRegion::make_property_quarks ()
{
Properties::envelope_active.id = g_quark_from_static_string (X_("envelope-active"));
Properties::default_fade_in.id = g_quark_from_static_string (X_("default-fade-in"));
Properties::default_fade_out.id = g_quark_from_static_string (X_("default-fade-out"));
Properties::fade_in_active.id = g_quark_from_static_string (X_("fade-in-active"));
Properties::fade_out_active.id = g_quark_from_static_string (X_("fade-out-active"));
Properties::scale_amplitude.id = g_quark_from_static_string (X_("scale-amplitude"));
Properties::envelope_active.property_id = g_quark_from_static_string (X_("envelope-active"));
DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for envelope-active = %1\n", Properties::envelope_active.property_id));
Properties::default_fade_in.property_id = g_quark_from_static_string (X_("default-fade-in"));
DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for default-fade-in = %1\n", Properties::default_fade_in.property_id));
Properties::default_fade_out.property_id = g_quark_from_static_string (X_("default-fade-out"));
DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for default-fade-out = %1\n", Properties::default_fade_out.property_id));
Properties::fade_in_active.property_id = g_quark_from_static_string (X_("fade-in-active"));
DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for fade-in-active = %1\n", Properties::fade_in_active.property_id));
Properties::fade_out_active.property_id = g_quark_from_static_string (X_("fade-out-active"));
DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for fade-out-active = %1\n", Properties::fade_out_active.property_id));
Properties::scale_amplitude.property_id = g_quark_from_static_string (X_("scale-amplitude"));
DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for scale-amplitude = %1\n", Properties::scale_amplitude.property_id));
}
void
@ -690,37 +696,37 @@ AudioRegion::set_property (const PropertyBase& prop)
{
DEBUG_TRACE (DEBUG::Properties, string_compose ("audio region %1 set property %2\n", _name.val(), prop.property_name()));
if (prop == Properties::envelope_active.id) {
if (prop == Properties::envelope_active.property_id) {
bool val = dynamic_cast<const PropertyTemplate<bool>*>(&prop)->val();
if (val != _envelope_active) {
_envelope_active = val;
return true;
}
} else if (prop == Properties::default_fade_in.id) {
} else if (prop == Properties::default_fade_in.property_id) {
bool val = dynamic_cast<const PropertyTemplate<bool>*>(&prop)->val();
if (val != _default_fade_in) {
_default_fade_in = val;
return true;
}
} else if (prop == Properties::default_fade_out.id) {
} else if (prop == Properties::default_fade_out.property_id) {
bool val = dynamic_cast<const PropertyTemplate<bool>*>(&prop)->val();
if (val != _default_fade_out) {
_default_fade_out = val;
return true;
}
} else if (prop == Properties::fade_in_active.id) {
} else if (prop == Properties::fade_in_active.property_id) {
bool val = dynamic_cast<const PropertyTemplate<bool>*>(&prop)->val();
if (val != _fade_in_active) {
_fade_in_active = val;
return true;
}
} else if (prop == Properties::fade_out_active.id) {
} else if (prop == Properties::fade_out_active.property_id) {
bool val = dynamic_cast<const PropertyTemplate<bool>*>(&prop)->val();
if (val != _fade_out_active) {
_fade_out_active = val;
return true;
}
} else if (prop == Properties::scale_amplitude.id) {
} else if (prop == Properties::scale_amplitude.property_id) {
gain_t val = dynamic_cast<const PropertyTemplate<gain_t>*>(&prop)->val();
if (val != _scale_amplitude) {
_scale_amplitude = val;

View File

@ -20,6 +20,7 @@
#include "pbd/stacktrace.h"
#include "ardour/debug.h"
#include "ardour/types.h"
#include "ardour/crossfade.h"
#include "ardour/crossfade_compare.h"
@ -60,7 +61,8 @@ namespace ARDOUR {
void
Crossfade::make_property_quarks ()
{
Properties::follow_overlap.id = g_quark_from_static_string (X_("follow-overlap"));
Properties::follow_overlap.property_id = g_quark_from_static_string (X_("follow-overlap"));
DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for follow-overlap = %1\n", Properties::follow_overlap.property_id));
}
void

View File

@ -23,106 +23,22 @@
#include "ardour/debug.h"
#include "i18n.h"
using namespace std;
void
ARDOUR::debug_print (const char* prefix, string str)
{
cerr << prefix << ": " << str;
}
uint64_t PBD::DEBUG::MidiSourceIO = PBD::new_debug_bit ("midisourceio");
uint64_t PBD::DEBUG::MidiPlaylistIO = PBD::new_debug_bit ("midiplaylistio");
uint64_t PBD::DEBUG::MidiDiskstreamIO = PBD::new_debug_bit ("mididiskstreamio");
uint64_t PBD::DEBUG::SnapBBT = PBD::new_debug_bit ("snapbbt");
uint64_t PBD::DEBUG::Configuration = PBD::new_debug_bit ("configuration");
uint64_t PBD::DEBUG::Latency = PBD::new_debug_bit ("latency");
uint64_t PBD::DEBUG::Processors = PBD::new_debug_bit ("processors");
uint64_t PBD::DEBUG::Graph = PBD::new_debug_bit ("graph");
uint64_t PBD::DEBUG::Destruction = PBD::new_debug_bit ("destruction");
uint64_t PBD::DEBUG::MTC = PBD::new_debug_bit ("mtc");
uint64_t PBD::DEBUG::Transport = PBD::new_debug_bit ("transport");
uint64_t PBD::DEBUG::Slave = PBD::new_debug_bit ("slave");
uint64_t PBD::DEBUG::SessionEvents = PBD::new_debug_bit ("sessionevents");
uint64_t PBD::DEBUG::MidiIO = PBD::new_debug_bit ("midiio");
uint64_t PBD::DEBUG::MackieControl = PBD::new_debug_bit ("mackiecontrol");
uint64_t PBD::DEBUG::MidiClock = PBD::new_debug_bit ("midiclock");
void
ARDOUR::set_debug_bits (uint64_t bits)
{
debug_bits = bits;
}
int
ARDOUR::parse_debug_options (const char* str)
{
char* p;
char* sp;
uint64_t bits = 0;
char* copy = strdup (str);
p = strtok_r (copy, ",", &sp);
while (p) {
if (strcasecmp (p, "list") == 0) {
list_debug_options ();
free (copy);
return 1;
}
if (strcasecmp (p, "all") == 0) {
ARDOUR::set_debug_bits (~0ULL);
free (copy);
return 0;
}
if (strncasecmp (p, "midisourceio", strlen (p)) == 0) {
bits |= ARDOUR::DEBUG::MidiSourceIO;
} else if (strncasecmp (p, "midiplaylistio", strlen (p)) == 0) {
bits |= ARDOUR::DEBUG::MidiPlaylistIO;
} else if (strncasecmp (p, "mididiskstreamio", strlen (p)) == 0) {
bits |= ARDOUR::DEBUG::MidiDiskstreamIO;
} else if (strncasecmp (p, "snapbbt", strlen (p)) == 0) {
bits |= ARDOUR::DEBUG::SnapBBT;
} else if (strncasecmp (p, "configuration", strlen (p)) == 0) {
bits |= ARDOUR::DEBUG::Configuration;
} else if (strncasecmp (p, "latency", strlen (p)) == 0) {
bits |= ARDOUR::DEBUG::Latency;
} else if (strncasecmp (p, "processors", strlen (p)) == 0) {
bits |= ARDOUR::DEBUG::Processors;
} else if (strncasecmp (p, "graph", strlen (p)) == 0) {
bits |= ARDOUR::DEBUG::Graph;
} else if (strncasecmp (p, "destruction", strlen (p)) == 0) {
bits |= ARDOUR::DEBUG::Destruction;
} else if (strncasecmp (p, "mtc", strlen (p)) == 0) {
bits |= ARDOUR::DEBUG::MTC;
} else if (strncasecmp (p, "transport", strlen (p)) == 0) {
bits |= ARDOUR::DEBUG::Transport;
} else if (strncasecmp (p, "slave", strlen (p)) == 0) {
bits |= ARDOUR::DEBUG::Slave;
} else if (strncasecmp (p, "sessionevents", strlen (p)) == 0) {
bits |= ARDOUR::DEBUG::SessionEvents;
} else if (strncasecmp (p, "midiio", strlen (p)) == 0) {
bits |= ARDOUR::DEBUG::MidiIO;
} else if (strncasecmp (p, "midiclock", strlen (p)) == 0) {
bits |= ARDOUR::DEBUG::MidiClock;
} else if (strncasecmp (p, "properties", strlen (p)) == 0) {
bits |= ARDOUR::DEBUG::Properties;
}
p = strtok_r (0, ",", &sp);
}
free (copy);
ARDOUR::set_debug_bits (bits);
return 0;
}
void
ARDOUR::list_debug_options ()
{
cerr << _("The following debug options are available. Separate multipe options with commas.\nNames are case-insensitive and can be abbreviated.") << endl << endl;
cerr << "\tAll" << endl;
cerr << "\tMidiSourceIO" << endl;
cerr << "\tMidiPlaylistIO" << endl;
cerr << "\tMidiDiskstreamIO" << endl;
cerr << "\tSnapBBT" << endl;
cerr << "\tConfiguration" << endl;
cerr << "\tLatency" << endl;
cerr << "\tGraph" << endl;
cerr << "\tDestruction" << endl;
cerr << "\tMTC" << endl;
cerr << "\tTransport" << endl;
cerr << "\tSlave" << endl;
cerr << "\tSessionEvents" << endl;
cerr << "\tMidiIO" << endl;
cerr << "\tLatencyCompensation" << endl;
cerr << "\tMidiClock" << endl;
cerr << "\tProperties" << endl;
}

View File

@ -68,6 +68,7 @@
#include "ardour/debug.h"
#include "ardour/filesystem_paths.h"
#include "ardour/mix.h"
#include "ardour/playlist.h"
#include "ardour/plugin_manager.h"
#include "ardour/profile.h"
#include "ardour/region.h"
@ -95,8 +96,6 @@ using namespace ARDOUR;
using namespace std;
using namespace PBD;
uint64_t ARDOUR::debug_bits = 0x0;
MIDI::Port *ARDOUR::default_mmc_port = 0;
MIDI::Port *ARDOUR::default_mtc_port = 0;
MIDI::Port *ARDOUR::default_midi_port = 0;
@ -137,9 +136,12 @@ namespace ARDOUR {
void
ARDOUR::make_property_quarks ()
{
Properties::fade_in.id = g_quark_from_static_string (X_("fade_in_FAKE"));
Properties::fade_out.id = g_quark_from_static_string (X_("fade_out_FAKE"));
Properties::envelope.id = g_quark_from_static_string (X_("envelope_FAKE"));
Properties::fade_in.property_id = g_quark_from_static_string (X_("fade_in_FAKE"));
DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for fade_in_FAKE = %1\n", Properties::fade_in.property_id));
Properties::fade_out.property_id = g_quark_from_static_string (X_("fade_out_FAKE"));
DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for fade_out_FAKE = %1\n", Properties::fade_out.property_id));
Properties::envelope.property_id = g_quark_from_static_string (X_("envelope_FAKE"));
DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for envelope_FAKE = %1\n", Properties::envelope.property_id));
}
int
@ -332,6 +334,7 @@ ARDOUR::init (bool use_vst, bool try_optimization)
Region::make_property_quarks ();
AudioRegion::make_property_quarks ();
RouteGroup::make_property_quarks ();
Playlist::make_property_quarks ();
/* this is a useful ready to use PropertyChange that many
things need to check. This avoids having to compose

View File

@ -39,6 +39,7 @@
#include "i18n.h"
using namespace ARDOUR;
using namespace PBD;
using namespace std;
MidiPlaylist::MidiPlaylist (Session& session, const XMLNode& node, bool hidden)

View File

@ -25,6 +25,7 @@
using namespace std;
using namespace ARDOUR;
using namespace PBD;
/** Read a block of MIDI events from buffer into a MidiBuffer.
*

View File

@ -34,6 +34,7 @@
using namespace std;
using namespace ARDOUR;
using namespace PBD;
using namespace Glib;
#include "i18n.h"

View File

@ -46,6 +46,12 @@ using namespace std;
using namespace ARDOUR;
using namespace PBD;
namespace ARDOUR {
namespace Properties {
PBD::PropertyDescriptor<bool> regions;
}
}
struct ShowMeTheList {
ShowMeTheList (boost::shared_ptr<Playlist> pl, const string& n) : playlist (pl), name (n) {}
~ShowMeTheList () {
@ -90,9 +96,66 @@ struct RegionSortByLastLayerOp {
}
};
void
Playlist::make_property_quarks ()
{
Properties::regions.property_id = g_quark_from_static_string (X_("regions"));
DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for regions = %1\n", Properties::regions.property_id));
}
RegionListProperty::RegionListProperty (Playlist& pl)
: SequenceProperty<std::list<boost::shared_ptr<Region> > > (Properties::regions.property_id, boost::bind (&Playlist::update, &pl, _1))
, _playlist (pl)
{
}
boost::shared_ptr<Region>
RegionListProperty::lookup_id (const ID& id)
{
boost::shared_ptr<Region> ret = _playlist.region_by_id (id);
if (!ret) {
ret = _playlist.session().region_by_id (id);
}
if (!ret) {
ret = RegionFactory::region_by_id (id);
}
return ret;
}
RegionListProperty*
RegionListProperty::copy_for_history () const
{
RegionListProperty* copy = new RegionListProperty (_playlist);
/* this is all we need */
copy->_change = _change;
return copy;
}
void
RegionListProperty::diff (PropertyList& before, PropertyList& after) const
{
if (_have_old) {
RegionListProperty* a = copy_for_history ();
RegionListProperty* b = copy_for_history ();
b->invert_changes ();
before.add (b);
after.add (a);
cerr << "pdiff on " << _playlist.name() << " before contains "
<< b->change().added.size() << " adds and " << b->change().removed.size() << " removes\n";
cerr << "pdiff on " << _playlist.name() << " after contains "
<< a->change().added.size() << " adds and " << a->change().removed.size() << " removes\n";
}
}
Playlist::Playlist (Session& sess, string nom, DataType type, bool hide)
: SessionObject(sess, nom)
, regions (*this)
, _type(type)
{
init (hide);
@ -103,7 +166,9 @@ Playlist::Playlist (Session& sess, string nom, DataType type, bool hide)
Playlist::Playlist (Session& sess, const XMLNode& node, DataType type, bool hide)
: SessionObject(sess, "unnamed playlist")
, _type(type)
, regions (*this)
, _type(type)
{
const XMLProperty* prop = node.property("type");
assert(!prop || DataType(prop->value()) == _type);
@ -116,6 +181,7 @@ Playlist::Playlist (Session& sess, const XMLNode& node, DataType type, bool hide
Playlist::Playlist (boost::shared_ptr<const Playlist> other, string namestr, bool hide)
: SessionObject(other->_session, namestr)
, regions (*this)
, _type(other->_type)
, _orig_diskstream_id(other->_orig_diskstream_id)
{
@ -150,6 +216,7 @@ Playlist::Playlist (boost::shared_ptr<const Playlist> other, string namestr, boo
Playlist::Playlist (boost::shared_ptr<const Playlist> other, framepos_t start, framecnt_t cnt, string str, bool hide)
: SessionObject(other->_session, str)
, regions (*this)
, _type(other->_type)
, _orig_diskstream_id(other->_orig_diskstream_id)
{
@ -256,6 +323,9 @@ Playlist::copy_regions (RegionList& newlist) const
void
Playlist::init (bool hide)
{
add_property (regions);
_xml_node_name = X_("Playlist");
g_atomic_int_set (&block_notifications, 0);
g_atomic_int_set (&ignore_state_changes, 0);
pending_contents_change = false;
@ -362,7 +432,7 @@ Playlist::release_notifications ()
{
if (g_atomic_int_dec_and_test (&block_notifications)) {
flush_notifications ();
}
}
}
void
@ -811,7 +881,7 @@ Playlist::partition_internal (framepos_t start, framepos_t end, bool cutting, Re
get operated on as well.
*/
RegionList copy = regions;
RegionList copy = regions.rlist();
for (RegionList::iterator i = copy.begin(); i != copy.end(); i = tmp) {
@ -1189,7 +1259,7 @@ void
Playlist::shift (framepos_t at, frameoffset_t distance, bool move_intersected, bool ignore_music_glue)
{
RegionLock rlock (this);
RegionList copy (regions);
RegionList copy (regions.rlist());
RegionList fixup;
for (RegionList::iterator r = copy.begin(); r != copy.end(); ++r) {
@ -1227,7 +1297,7 @@ void
Playlist::split (framepos_t at)
{
RegionLock rlock (this);
RegionList copy (regions);
RegionList copy (regions.rlist());
/* use a copy since this operation can modify the region list
*/
@ -1406,9 +1476,10 @@ Playlist::region_bounds_changed (const PropertyChange& what_changed, boost::shar
RegionList::iterator i = find (regions.begin(), regions.end(), region);
if (i == regions.end()) {
warning << string_compose (_("%1: bounds changed received for region (%2)not in playlist"),
_name, region->name())
<< endmsg;
/* the region bounds are being modified but its not currently
in the region list. we will use its bounds correctly when/if
it is added
*/
return;
}
@ -1939,6 +2010,63 @@ Playlist::mark_session_dirty ()
}
}
bool
Playlist::set_property (const PropertyBase& prop)
{
if (prop == Properties::regions.property_id) {
const RegionListProperty::ChangeRecord& change (dynamic_cast<const RegionListProperty*>(&prop)->change());
regions.update (change);
return (!change.added.empty() && !change.removed.empty());
}
return false;
}
void
Playlist::update (const RegionListProperty::ChangeRecord& change)
{
DEBUG_TRACE (DEBUG::Properties, string_compose ("Playlist %1 updates from a change record with %2 adds %3 removes\n",
name(), change.added.size(), change.removed.size()));
freeze ();
/* add the added regions */
for (RegionListProperty::ChangeContainer::iterator i = change.added.begin(); i != change.added.end(); ++i) {
add_region ((*i), (*i)->position());
}
/* remove the removed regions */
for (RegionListProperty::ChangeContainer::iterator i = change.removed.begin(); i != change.removed.end(); ++i) {
remove_region (*i);
}
thaw ();
}
PropertyList*
Playlist::property_factory (const XMLNode& history_node) const
{
const XMLNodeList& children (history_node.children());
PropertyList* prop_list = 0;
for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
/* XXX property name needs capitalizing */
if ((*i)->name() == regions.property_name()) {
RegionListProperty* rlp = new RegionListProperty (*const_cast<Playlist*> (this));
if (rlp->load_history_state (**i)) {
if (!prop_list) {
prop_list = new PropertyList();
}
prop_list->add (rlp);
} else {
delete rlp;
}
}
}
return prop_list;
}
int
Playlist::set_state (const XMLNode& node, int version)
{
@ -1968,6 +2096,8 @@ Playlist::set_state (const XMLNode& node, int version)
if (prop->name() == X_("name")) {
_name = prop->value();
} else if (prop->name() == X_("id")) {
_id = prop->value();
} else if (prop->name() == X_("orig_diskstream_id")) {
_orig_diskstream_id = prop->value ();
} else if (prop->name() == X_("frozen")) {
@ -2053,6 +2183,7 @@ Playlist::state (bool full_state)
XMLNode *node = new XMLNode (X_("Playlist"));
char buf[64];
node->add_property (X_("id"), id().to_s());
node->add_property (X_("name"), _name);
node->add_property (X_("type"), _type.to_string());
@ -2177,7 +2308,7 @@ Playlist::relayer ()
which depends on the layer model
*/
RegionList copy = regions;
RegionList copy = regions.rlist();
/* sort according to the model and the layering mode that we're in */
@ -2191,6 +2322,7 @@ Playlist::relayer ()
}
for (RegionList::iterator i = copy.begin(); i != copy.end(); ++i) {
/* reset the pending explicit relayer flag for every region, now that we're relayering */
@ -2447,7 +2579,7 @@ Playlist::find_region (const ID& id) const
}
boost::shared_ptr<Region>
Playlist::region_by_id (ID id)
Playlist::region_by_id (const ID& id)
{
/* searches all regions ever added to this playlist */
@ -2627,7 +2759,7 @@ void
Playlist::update_after_tempo_map_change ()
{
RegionLock rlock (const_cast<Playlist*> (this));
RegionList copy (regions);
RegionList copy (regions.rlist());
freeze ();

View File

@ -77,27 +77,48 @@ PBD::Signal2<void,boost::shared_ptr<ARDOUR::Region>,const PropertyChange&> Regio
void
Region::make_property_quarks ()
{
Properties::muted.id = g_quark_from_static_string (X_("muted"));
Properties::opaque.id = g_quark_from_static_string (X_("opaque"));
Properties::locked.id = g_quark_from_static_string (X_("locked"));
Properties::automatic.id = g_quark_from_static_string (X_("automatic"));
Properties::whole_file.id = g_quark_from_static_string (X_("whole-file"));
Properties::import.id = g_quark_from_static_string (X_("import"));
Properties::external.id = g_quark_from_static_string (X_("external"));
Properties::sync_marked.id = g_quark_from_static_string (X_("sync-marked"));
Properties::left_of_split.id = g_quark_from_static_string (X_("left-of-split"));
Properties::right_of_split.id = g_quark_from_static_string (X_("right-of-split"));
Properties::hidden.id = g_quark_from_static_string (X_("hidden"));
Properties::position_locked.id = g_quark_from_static_string (X_("position-locked"));
Properties::start.id = g_quark_from_static_string (X_("start"));
Properties::length.id = g_quark_from_static_string (X_("length"));
Properties::position.id = g_quark_from_static_string (X_("position"));
Properties::sync_position.id = g_quark_from_static_string (X_("sync-position"));
Properties::layer.id = g_quark_from_static_string (X_("layer"));
Properties::ancestral_start.id = g_quark_from_static_string (X_("ancestral-start"));
Properties::ancestral_length.id = g_quark_from_static_string (X_("ancestral-length"));
Properties::stretch.id = g_quark_from_static_string (X_("stretch"));
Properties::shift.id = g_quark_from_static_string (X_("shift"));
Properties::muted.property_id = g_quark_from_static_string (X_("muted"));
DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for muted = %1\n", Properties::muted.property_id));
Properties::opaque.property_id = g_quark_from_static_string (X_("opaque"));
DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for opaque = %1\n", Properties::opaque.property_id));
Properties::locked.property_id = g_quark_from_static_string (X_("locked"));
DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for locked = %1\n", Properties::locked.property_id));
Properties::automatic.property_id = g_quark_from_static_string (X_("automatic"));
DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for automatic = %1\n", Properties::automatic.property_id));
Properties::whole_file.property_id = g_quark_from_static_string (X_("whole-file"));
DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for whole-file = %1\n", Properties::whole_file.property_id));
Properties::import.property_id = g_quark_from_static_string (X_("import"));
DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for import = %1\n", Properties::import.property_id));
Properties::external.property_id = g_quark_from_static_string (X_("external"));
DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for external = %1\n", Properties::external.property_id));
Properties::sync_marked.property_id = g_quark_from_static_string (X_("sync-marked"));
DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for sync-marked = %1\n", Properties::sync_marked.property_id));
Properties::left_of_split.property_id = g_quark_from_static_string (X_("left-of-split"));
DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for left-of-split = %1\n", Properties::left_of_split.property_id));
Properties::right_of_split.property_id = g_quark_from_static_string (X_("right-of-split"));
DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for right-of-split = %1\n", Properties::right_of_split.property_id));
Properties::hidden.property_id = g_quark_from_static_string (X_("hidden"));
DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for hidden = %1\n", Properties::hidden.property_id));
Properties::position_locked.property_id = g_quark_from_static_string (X_("position-locked"));
DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for position-locked = %1\n", Properties::position_locked.property_id));
Properties::start.property_id = g_quark_from_static_string (X_("start"));
DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for start = %1\n", Properties::start.property_id));
Properties::length.property_id = g_quark_from_static_string (X_("length"));
DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for length = %1\n", Properties::length.property_id));
Properties::position.property_id = g_quark_from_static_string (X_("position"));
DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for position = %1\n", Properties::position.property_id));
Properties::sync_position.property_id = g_quark_from_static_string (X_("sync-position"));
DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for sync-position = %1\n", Properties::sync_position.property_id));
Properties::layer.property_id = g_quark_from_static_string (X_("layer"));
DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for layer = %1\n", Properties::layer.property_id));
Properties::ancestral_start.property_id = g_quark_from_static_string (X_("ancestral-start"));
DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for ancestral-start = %1\n", Properties::ancestral_start.property_id));
Properties::ancestral_length.property_id = g_quark_from_static_string (X_("ancestral-length"));
DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for ancestral-length = %1\n", Properties::ancestral_length.property_id));
Properties::stretch.property_id = g_quark_from_static_string (X_("stretch"));
DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for stretch = %1\n", Properties::stretch.property_id));
Properties::shift.property_id = g_quark_from_static_string (X_("shift"));
DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for shift = %1\n", Properties::shift.property_id));
}
void
@ -1516,7 +1537,7 @@ Region::set_property (const PropertyBase& prop)
{
DEBUG_TRACE (DEBUG::Properties, string_compose ("region %1 set property %2\n", _name.val(), prop.property_name()));
if (prop == Properties::muted.id) {
if (prop == Properties::muted.property_id) {
bool val = dynamic_cast<const PropertyTemplate<bool>*>(&prop)->val();
if (val != _muted) {
DEBUG_TRACE (DEBUG::Properties, string_compose ("region %1 muted changed from %2 to %3",
@ -1524,7 +1545,7 @@ Region::set_property (const PropertyBase& prop)
_muted = val;
return true;
}
} else if (prop == Properties::opaque.id) {
} else if (prop == Properties::opaque.property_id) {
bool val = dynamic_cast<const PropertyTemplate<bool>*>(&prop)->val();
if (val != _opaque) {
DEBUG_TRACE (DEBUG::Properties, string_compose ("region %1 opaque changed from %2 to %3",
@ -1532,7 +1553,7 @@ Region::set_property (const PropertyBase& prop)
_opaque = val;
return true;
}
} else if (prop == Properties::locked.id) {
} else if (prop == Properties::locked.property_id) {
bool val = dynamic_cast<const PropertyTemplate<bool>*>(&prop)->val();
if (val != _locked) {
DEBUG_TRACE (DEBUG::Properties, string_compose ("region %1 locked changed from %2 to %3",
@ -1540,61 +1561,61 @@ Region::set_property (const PropertyBase& prop)
_locked = val;
return true;
}
} else if (prop == Properties::automatic.id) {
} else if (prop == Properties::automatic.property_id) {
_automatic = dynamic_cast<const PropertyTemplate<bool>*>(&prop)->val();
} else if (prop == Properties::whole_file.id) {
} else if (prop == Properties::whole_file.property_id) {
_whole_file = dynamic_cast<const PropertyTemplate<bool>*>(&prop)->val();
} else if (prop == Properties::import.id) {
} else if (prop == Properties::import.property_id) {
_import = dynamic_cast<const PropertyTemplate<bool>*>(&prop)->val();
} else if (prop == Properties::external.id) {
} else if (prop == Properties::external.property_id) {
_external = dynamic_cast<const PropertyTemplate<bool>*>(&prop)->val();
} else if (prop == Properties::sync_marked.id) {
} else if (prop == Properties::sync_marked.property_id) {
_sync_marked = dynamic_cast<const PropertyTemplate<bool>*>(&prop)->val();
} else if (prop == Properties::left_of_split.id) {
} else if (prop == Properties::left_of_split.property_id) {
_left_of_split = dynamic_cast<const PropertyTemplate<bool>*>(&prop)->val();
} else if (prop == Properties::right_of_split.id) {
} else if (prop == Properties::right_of_split.property_id) {
_right_of_split = dynamic_cast<const PropertyTemplate<bool>*>(&prop)->val();
} else if (prop == Properties::hidden.id) {
} else if (prop == Properties::hidden.property_id) {
bool val = dynamic_cast<const PropertyTemplate<bool>*>(&prop)->val();
if (val != _hidden) {
_hidden = val;
return true;
}
} else if (prop == Properties::position_locked.id) {
} else if (prop == Properties::position_locked.property_id) {
_position_locked = dynamic_cast<const PropertyTemplate<bool>*>(&prop)->val();
} else if (prop == Properties::start.id) {
} else if (prop == Properties::start.property_id) {
_start = dynamic_cast<const PropertyTemplate<framepos_t>*>(&prop)->val();
} else if (prop == Properties::length.id) {
} else if (prop == Properties::length.property_id) {
framecnt_t val = dynamic_cast<const PropertyTemplate<framecnt_t>* > (&prop)->val();
if (val != _length) {
_length = val;
return true;
}
} else if (prop == Properties::position.id) {
} else if (prop == Properties::position.property_id) {
framepos_t val = dynamic_cast<const PropertyTemplate<framepos_t>*>(&prop)->val();
if (val != _position) {
_position = val;
return true;
}
} else if (prop == Properties::sync_position.id) {
} else if (prop == Properties::sync_position.property_id) {
framepos_t val = dynamic_cast<const PropertyTemplate<framepos_t>*>(&prop)->val();
if (val != _sync_position) {
_sync_position = val;
return true;
}
} else if (prop == Properties::layer.id) {
} else if (prop == Properties::layer.property_id) {
layer_t val = dynamic_cast<const PropertyTemplate<layer_t>*>(&prop)->val();
if (val != _layer) {
_layer = val;
return true;
}
} else if (prop == Properties::ancestral_start.id) {
} else if (prop == Properties::ancestral_start.property_id) {
_ancestral_start = dynamic_cast<const PropertyTemplate<framepos_t>*>(&prop)->val();
} else if (prop == Properties::ancestral_length.id) {
} else if (prop == Properties::ancestral_length.property_id) {
_ancestral_length = dynamic_cast<const PropertyTemplate<framecnt_t>*>(&prop)->val();
} else if (prop == Properties::stretch.id) {
} else if (prop == Properties::stretch.property_id) {
_stretch = dynamic_cast<const PropertyTemplate<float>*>(&prop)->val();
} else if (prop == Properties::shift.id) {
} else if (prop == Properties::shift.property_id) {
_shift = dynamic_cast<const PropertyTemplate<float>*>(&prop)->val();
} else {
return SessionObject::set_property (prop);
@ -1602,3 +1623,19 @@ Region::set_property (const PropertyBase& prop)
return false;
}
PropertyList*
Region::property_factory (const XMLNode& history_node) const
{
PropertyList* prop_list = new PropertyList;
for (OwnedPropertyList::const_iterator i = _properties->begin(); i != _properties->end(); ++i) {
PropertyBase* prop = i->second->maybe_clone_self_if_found_in_history_node (history_node);
if (prop) {
prop_list->add (prop);
}
}
return prop_list;
}

View File

@ -36,7 +36,8 @@ using namespace ARDOUR;
using namespace PBD;
PBD::Signal1<void,boost::shared_ptr<Region> > RegionFactory::CheckNewRegion;
map<PBD::ID,boost::weak_ptr<Region> > RegionFactory::region_map;
Glib::StaticMutex RegionFactory::region_map_lock;
RegionFactory::RegionMap RegionFactory::region_map;
boost::shared_ptr<Region>
RegionFactory::create (boost::shared_ptr<const Region> region)
@ -302,23 +303,40 @@ RegionFactory::create (SourceList& srcs, const XMLNode& node)
void
RegionFactory::map_add (boost::shared_ptr<Region> r)
{
pair<ID,boost::weak_ptr<Region> > p;
pair<ID,boost::shared_ptr<Region> > p;
p.first = r->id();
p.second = r;
region_map.insert (p);
{
Glib::Mutex::Lock lm (region_map_lock);
region_map.insert (p);
/* we pay no attention to attempts to delete regions */
}
}
void
RegionFactory::map_remove (boost::shared_ptr<Region> r)
{
{
Glib::Mutex::Lock lm (region_map_lock);
RegionMap::iterator i = region_map.find (r->id());
if (i != region_map.end()) {
region_map.erase (i);
}
}
}
boost::shared_ptr<Region>
RegionFactory::region_by_id (const PBD::ID& id)
{
map<ID,boost::weak_ptr<Region> >::iterator i = region_map.find (id);
RegionMap::iterator i = region_map.find (id);
if (i == region_map.end()) {
cerr << "ID " << id << " not found in region map\n";
return boost::shared_ptr<Region>();
}
return i->second.lock();
return i->second;
}
void

View File

@ -28,6 +28,7 @@
#include "pbd/strsplit.h"
#include "ardour/amp.h"
#include "ardour/debug.h"
#include "ardour/route_group.h"
#include "ardour/audio_track.h"
#include "ardour/audio_diskstream.h"
@ -56,15 +57,24 @@ namespace ARDOUR {
void
RouteGroup::make_property_quarks ()
{
Properties::relative.id = g_quark_from_static_string (X_("relative"));
Properties::active.id = g_quark_from_static_string (X_("active"));
Properties::hidden.id = g_quark_from_static_string (X_("hidden"));
Properties::gain.id = g_quark_from_static_string (X_("gain"));
Properties::mute.id = g_quark_from_static_string (X_("mute"));
Properties::solo.id = g_quark_from_static_string (X_("solo"));
Properties::recenable.id = g_quark_from_static_string (X_("recenable"));
Properties::select.id = g_quark_from_static_string (X_("select"));
Properties::edit.id = g_quark_from_static_string (X_("edit"));
Properties::relative.property_id = g_quark_from_static_string (X_("relative"));
DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for relative = %1\n", Properties::relative.property_id));
Properties::active.property_id = g_quark_from_static_string (X_("active"));
DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for active = %1\n", Properties::active.property_id));
Properties::hidden.property_id = g_quark_from_static_string (X_("hidden"));
DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for hidden = %1\n", Properties::hidden.property_id));
Properties::gain.property_id = g_quark_from_static_string (X_("gain"));
DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for gain = %1\n", Properties::gain.property_id));
Properties::mute.property_id = g_quark_from_static_string (X_("mute"));
DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for mute = %1\n", Properties::mute.property_id));
Properties::solo.property_id = g_quark_from_static_string (X_("solo"));
DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for solo = %1\n", Properties::solo.property_id));
Properties::recenable.property_id = g_quark_from_static_string (X_("recenable"));
DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for recenable = %1\n", Properties::recenable.property_id));
Properties::select.property_id = g_quark_from_static_string (X_("select"));
DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for select = %1\n", Properties::select.property_id));
Properties::edit.property_id = g_quark_from_static_string (X_("edit"));
DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for edit = %1\n", Properties::edit.property_id));
}
#define ROUTE_GROUP_DEFAULT_PROPERTIES _relative (Properties::relative, false) \
@ -432,23 +442,23 @@ RouteGroup::destroy_subgroup ()
bool
RouteGroup::enabled_property (PBD::PropertyID prop)
{
if (Properties::relative.id == prop) {
if (Properties::relative.property_id == prop) {
return is_relative();
} else if (Properties::active.id == prop) {
} else if (Properties::active.property_id == prop) {
return is_active();
} else if (Properties::hidden.id == prop) {
} else if (Properties::hidden.property_id == prop) {
return is_hidden();
} else if (Properties::gain.id == prop) {
} else if (Properties::gain.property_id == prop) {
return is_gain();
} else if (Properties::mute.id == prop) {
} else if (Properties::mute.property_id == prop) {
return is_mute();
} else if (Properties::solo.id == prop) {
} else if (Properties::solo.property_id == prop) {
return is_solo();
} else if (Properties::recenable.id == prop) {
} else if (Properties::recenable.property_id == prop) {
return is_recenable();
} else if (Properties::select.id == prop) {
} else if (Properties::select.property_id == prop) {
return is_select();
} else if (Properties::edit.id == prop) {
} else if (Properties::edit.property_id == prop) {
return is_edit();
}

View File

@ -2803,9 +2803,9 @@ Session::remove_region (boost::weak_ptr<Region> weak_region)
}
boost::shared_ptr<Region>
Session::find_whole_file_parent (boost::shared_ptr<Region const> child)
Session::find_whole_file_parent (boost::shared_ptr<Region const> child) const
{
RegionList::iterator i;
RegionList::const_iterator i;
boost::shared_ptr<Region> region;
Glib::Mutex::Lock lm (region_lock);
@ -2825,6 +2825,20 @@ Session::find_whole_file_parent (boost::shared_ptr<Region const> child)
return boost::shared_ptr<Region> ();
}
boost::shared_ptr<Region>
Session::region_by_id (const PBD::ID& id) const
{
Glib::Mutex::Lock lm (region_lock);
RegionList::const_iterator i = regions.find (id);
if (i != regions.end()) {
return i->second;
}
return boost::shared_ptr<Region> ();
}
int
Session::destroy_region (boost::shared_ptr<Region> region)
{

View File

@ -146,7 +146,15 @@ Session::stateful_diff_command_factory (XMLNode* n)
if (r) {
return new StatefulDiffCommand (r, *n);
}
}
} else if (obj_T == typeid (AudioPlaylist).name() || obj_T == typeid (MidiPlaylist).name()) {
boost::shared_ptr<Playlist> p = playlists->by_id (id);
if (p) {
return new StatefulDiffCommand (p, *n);
} else {
cerr << "Playlist with ID = " << id << " not found\n";
}
}
/* we failed */

View File

@ -34,13 +34,14 @@ namespace ARDOUR {
void
SessionObject::make_property_quarks ()
{
Properties::name.id = g_quark_from_static_string (X_("name"));
Properties::name.property_id = g_quark_from_static_string (X_("name"));
DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for name = %1\n", Properties::name.property_id));
}
bool
SessionObject::set_property (const PropertyBase& prop)
{
if (prop == Properties::name.id) {
if (prop == Properties::name.property_id) {
std::string str = dynamic_cast<const PropertyTemplate<std::string>*>(&prop)->val();
if (_name != str) {
DEBUG_TRACE (DEBUG::Properties, string_compose ("session object named %1 renamed %2\n",

View File

@ -167,6 +167,26 @@ SessionPlaylists::by_name (string name)
return boost::shared_ptr<Playlist>();
}
boost::shared_ptr<Playlist>
SessionPlaylists::by_id (const PBD::ID& id)
{
Glib::Mutex::Lock lm (lock);
for (List::iterator i = playlists.begin(); i != playlists.end(); ++i) {
if ((*i)->id() == id) {
return* i;
}
}
for (List::iterator i = unused_playlists.begin(); i != unused_playlists.end(); ++i) {
if ((*i)->id() == id) {
return* i;
}
}
return boost::shared_ptr<Playlist>();
}
void
SessionPlaylists::unassigned (std::list<boost::shared_ptr<Playlist> > & list)
{

View File

@ -991,7 +991,7 @@ Session::state(bool full_state)
if (full_state) {
Glib::Mutex::Lock rl (region_lock);
#if 0
for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
/* only store regions not attached to playlists */
@ -1000,6 +1000,17 @@ Session::state(bool full_state)
child->add_child_nocopy (i->second->state (true));
}
}
#else
const RegionFactory::RegionMap& region_map (RegionFactory::all_regions());
for (RegionFactory::RegionMap::const_iterator i = region_map.begin(); i != region_map.end(); ++i) {
boost::shared_ptr<Region> r = i->second;
/* only store regions not attached to playlists */
if (r->playlist() == 0) {
child->add_child_nocopy (r->state (true));
}
}
#endif
}
child = node->add_child ("DiskStreams");

View File

@ -45,6 +45,7 @@
using namespace std;
using namespace ARDOUR;
using namespace PBD;
Source::Source (Session& s, DataType type, const string& name, Flag flags)
: SessionObject(s, name)

108
libs/pbd/debug.cc Normal file
View File

@ -0,0 +1,108 @@
/*
Copyright (C) 2009 Paul Davis
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <map>
#include "pbd/debug.h"
#include "i18n.h"
using namespace std;
static uint64_t _debug_bit = 1;
static std::map<const char*,uint64_t> _debug_bit_map;
uint64_t PBD::DEBUG::Stateful = PBD::new_debug_bit ("stateful");
uint64_t PBD::DEBUG::Properties = PBD::new_debug_bit ("properties");
uint64_t PBD::debug_bits = 0x0;
uint64_t
PBD::new_debug_bit (const char* name)
{
uint64_t ret;
_debug_bit_map.insert (make_pair (name, _debug_bit));
cerr << "debug name " << name << " = " << _debug_bit << endl;
ret = _debug_bit;
_debug_bit <<= 1;
return ret;
}
void
PBD::debug_print (const char* prefix, string str)
{
cerr << prefix << ": " << str;
}
void
PBD::set_debug_bits (uint64_t bits)
{
debug_bits = bits;
}
int
PBD::parse_debug_options (const char* str)
{
char* p;
char* sp;
uint64_t bits = 0;
char* copy = strdup (str);
p = strtok_r (copy, ",", &sp);
while (p) {
if (strcasecmp (p, "list") == 0) {
list_debug_options ();
free (copy);
return 1;
}
if (strcasecmp (p, "all") == 0) {
PBD::set_debug_bits (~0ULL);
free (copy);
return 0;
}
for (map<const char*,uint64_t>::iterator i = _debug_bit_map.begin(); i != _debug_bit_map.end(); ++i) {
if (strncasecmp (p, i->first, strlen (p)) == 0) {
cerr << "debug args matched for " << p << " set bit " << i->second << endl;
bits |= i->second;
}
}
p = strtok_r (0, ",", &sp);
}
free (copy);
PBD::set_debug_bits (bits);
return 0;
}
void
PBD::list_debug_options ()
{
cerr << _("The following debug options are available. Separate multipe options with commas.\nNames are case-insensitive and can be abbreviated.") << endl << endl;
cerr << "\tAll" << endl;
for (map<const char*,uint64_t>::iterator i = _debug_bit_map.begin(); i != _debug_bit_map.end(); ++i) {
cerr << "\t" << i->first << endl;
}
}

57
libs/pbd/pbd/debug.h Normal file
View File

@ -0,0 +1,57 @@
/*
Copyright (C) 2009 Paul Davis
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef __libpbd_debug_h__
#define __libpbd_debug_h__
#include <stdint.h>
#include <sstream>
namespace PBD {
extern uint64_t debug_bits;
uint64_t new_debug_bit (const char* name);
void debug_print (const char* prefix, std::string str);
void set_debug_bits (uint64_t bits);
int parse_debug_options (const char* str);
void list_debug_options ();
namespace DEBUG {
/* this namespace is so that we can write DEBUG::bit_name */
extern uint64_t Stateful;
extern uint64_t Properties;
}
}
#ifndef NDEBUG
#define DEBUG_TRACE(bits,str) if ((bits) & PBD::debug_bits) { PBD::debug_print (# bits, str); }
#define DEBUG_STR_DECL(id) std::stringstream __debug_str ## id;
#define DEBUG_STR(id) __debug_str ## id
#define DEBUG_STR_APPEND(id,s) __debug_str ## id << s;
#else
#define DEBUG_TRACE(bits,fmt,...) /*empty*/
#define DEBUG_STR(a) /* empty */
#define DEBUG_STR_APPEND(a,b) /* empty */
#endif
#endif /* __libpbd_debug_h__ */

View File

@ -27,96 +27,19 @@
#include <glib.h>
#include "pbd/xml++.h"
#include "pbd/property_basics.h"
#include "pbd/property_list.h"
namespace PBD {
typedef GQuark PropertyID;
template<typename T>
struct PropertyDescriptor {
PropertyID id;
typedef T value_type;
};
class PropertyChange : public std::set<PropertyID>
{
public:
PropertyChange() {}
template<typename T>
PropertyChange(PropertyDescriptor<T> p) { insert (p.id); }
PropertyChange(const PropertyChange& other) : std::set<PropertyID> (other) {}
PropertyChange operator=(const PropertyChange& other) {
clear ();
insert (other.begin (), other.end ());
return *this;
}
template<typename T>
PropertyChange operator=(PropertyDescriptor<T> p) {
clear ();
insert (p.id);
return *this;
}
template<typename T>
bool contains (PropertyDescriptor<T> p) const { return find (p.id) != end (); }
bool contains (const PropertyChange& other) const {
for (const_iterator x = other.begin (); x != other.end (); ++x) {
if (find (*x) != end ()) {
return true;
}
}
return false;
}
void add (PropertyID id) { (void) insert (id); }
void add (const PropertyChange& other) { (void) insert (other.begin (), other.end ()); }
template<typename T>
void add (PropertyDescriptor<T> p) { (void)insert (p.id); }
};
/** Base (non template) part of Property */
class PropertyBase
{
public:
PropertyBase (PropertyID pid)
: _property_id (pid)
, _have_old (false)
{}
/** Forget about any old value for this state */
void clear_history () {
_have_old = false;
}
virtual void diff (XMLNode*, XMLNode*) const = 0;
virtual void diff (PropertyChange&) const = 0;
virtual bool set_state (XMLNode const&) = 0;
virtual void add_state (XMLNode&) const = 0;
const gchar*property_name () const { return g_quark_to_string (_property_id); }
PropertyID id () const { return _property_id; }
bool operator==(PropertyID pid) const {
return _property_id == pid;
}
protected:
PropertyID _property_id;
bool _have_old;
};
/** Parent class for classes which represent a single property in a Stateful object */
/** Parent class for classes which represent a single scalar property in a Stateful object
*/
template<class T>
class PropertyTemplate : public PropertyBase
{
public:
PropertyTemplate (PropertyDescriptor<T> p, T const& v)
: PropertyBase (p.id)
: PropertyBase (p.property_id)
, _current (v)
{}
@ -156,25 +79,22 @@ public:
return _current;
}
void diff (XMLNode* old, XMLNode* current) const {
if (_have_old) {
old->add_property (property_name (), to_string (_old));
current->add_property (property_name (), to_string (_current));
}
}
void diff (PropertyChange& c) const {
if (_have_old) {
c.add (_property_id);
}
/** If this property has been changed since the last clear_history() call
(or its construction), add an (XML) property describing the old value
to the XMLNode @param old and another describing the current value to
the XMLNode @param current.
*/
void add_history_state (XMLNode* history_node) const {
history_node->add_property (property_name(), to_string (_current));
}
/** Try to set state from the property of an XML node.
* @param node XML node.
* @return true if the value of the property is changed
*/
bool set_state (XMLNode const& node) {
XMLProperty const* p = node.property (property_name ());
bool set_state_from_owner_state (XMLNode const& owner_state) {
XMLProperty const* p = owner_state.property (property_name());
if (p) {
T const v = from_string (p->value ());
@ -188,11 +108,19 @@ public:
return false;
}
void add_state (XMLNode& node) const {
node.add_property (property_name (), to_string (_current));
void add_state_to_owner_state (XMLNode& owner_state) const {
owner_state.add_property (property_name(), to_string (_current));
}
protected:
/** Constructs a PropertyTemplate with a default
value for _old and _current.
*/
PropertyTemplate (PropertyDescriptor<T> p)
: PropertyBase (p.property_id)
{}
void set (T const& v) {
_old = _current;
_have_old = true;
@ -212,7 +140,7 @@ std::ostream & operator<<(std::ostream& os, PropertyTemplate<T> const& s)
return os << s.val ();
}
/** Representation of a single piece of state in a Stateful; for use
/** Representation of a single piece of scalar state in a Stateful; for use
* with types that can be written to / read from stringstreams.
*/
template<class T>
@ -222,6 +150,21 @@ public:
Property (PropertyDescriptor<T> q, T const& v)
: PropertyTemplate<T> (q, v)
{}
void diff (PropertyList& before, PropertyList& after) const {
if (this->_have_old) {
before.add (new Property<T> (this->property_id(), this->_old));
after.add (new Property<T> (this->property_id(), this->_current));
}
}
Property<T>* maybe_clone_self_if_found_in_history_node (const XMLNode& node) const {
const XMLProperty* prop = node.property (this->property_name());
if (!prop) {
return 0;
}
return new Property<T> (this->property_id(), from_string (prop->value()));
}
T & operator=(T const& v) {
this->set (v);
@ -229,6 +172,12 @@ public:
}
private:
friend class PropertyFactory;
Property (PropertyDescriptor<T> q)
: PropertyTemplate<T> (q)
{}
/* Note that we do not set a locale for the streams used
* in to_string() or from_string(), because we want the
* format to be portable across locales (i.e. C or
@ -254,7 +203,7 @@ private:
/** Specialization, for std::string which is common and special (see to_string() and from_string()
* Using stringstream to read from a std::string is easy to get wrong because of whitespace
* delineation, etc.
* separators, etc.
*/
template<>
class Property<std::string> : public PropertyTemplate<std::string>
@ -264,6 +213,13 @@ public:
: PropertyTemplate<std::string> (q, v)
{}
void diff (PropertyList& before, PropertyList& after) 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));
}
}
std::string & operator=(std::string const& v) {
this->set (v);
return this->_current;
@ -280,48 +236,9 @@ private:
};
class PropertyList : public std::map<PropertyID, PropertyBase*>
{
public:
PropertyList() : _property_owner (true) {}
virtual ~PropertyList() {
if (_property_owner) {
for (std::map<PropertyID, PropertyBase*>::iterator i = begin (); i != end (); ++i) {
delete i->second;
}
}
}
/* Classes that own property lists use this to add their
* property members to their plists.
*/
bool add (PropertyBase& p) {
return insert (value_type (p.id (), &p)).second;
}
/* Code that is constructing a property list for use
* in setting the state of an object uses this.
*/
template<typename T, typename V>
bool add (PropertyDescriptor<T> pid, const V& v) {
return insert (value_type (pid.id, new Property<T> (pid, (T)v))).second;
}
protected:
bool _property_owner;
};
/** A variant of PropertyList that does not delete its
* property list in its destructor. Objects with their
* own Properties store them in an OwnedPropertyList
* to avoid having them deleted at the wrong time.
*/
class OwnedPropertyList : public PropertyList
{
public:
OwnedPropertyList() { _property_owner = false; }
};
} /* namespace PBD */
#include "pbd/property_list_impl.h"
#include "pbd/property_basics_impl.h"
#endif /* __pbd_properties_h__ */

View File

@ -0,0 +1,116 @@
/*
Copyright (C) 2010 Paul Davis
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef __libpbd_property_basics_h__
#define __libpbd_property_basics_h__
#include <glib.h>
#include <set>
#include "pbd/xml++.h"
namespace PBD {
class PropertyList;
typedef GQuark PropertyID;
template<typename T>
struct PropertyDescriptor {
PropertyDescriptor () : property_id (0) {}
PropertyDescriptor (PropertyID pid) : property_id (pid) {}
PropertyID property_id;
typedef T value_type;
};
class PropertyChange : public std::set<PropertyID>
{
public:
PropertyChange() {}
template<typename T> PropertyChange(PropertyDescriptor<T> p);
PropertyChange(const PropertyChange& other) : std::set<PropertyID> (other) {}
PropertyChange operator=(const PropertyChange& other) {
clear ();
insert (other.begin (), other.end ());
return *this;
}
template<typename T> PropertyChange operator=(PropertyDescriptor<T> p);
template<typename T> bool contains (PropertyDescriptor<T> p) const;
bool contains (const PropertyChange& other) const {
for (const_iterator x = other.begin (); x != other.end (); ++x) {
if (find (*x) != end ()) {
return true;
}
}
return false;
}
void add (PropertyID id) { insert (id); }
void add (const PropertyChange& other) { insert (other.begin (), other.end ()); }
template<typename T> void add (PropertyDescriptor<T> p);
};
/** Base (non template) part of Property */
class PropertyBase
{
public:
PropertyBase (PropertyID pid)
: _property_id (pid)
, _have_old (false)
{}
/** Forget about any old value for this state */
virtual void clear_history () {
_have_old = false;
}
virtual void add_history_state (XMLNode*) const = 0;
virtual void diff (PropertyList&, PropertyList&) const = 0;
virtual PropertyBase* maybe_clone_self_if_found_in_history_node (const XMLNode&) const { return 0; }
virtual bool set_state_from_owner_state (XMLNode const&) = 0;
virtual void add_state_to_owner_state (XMLNode&) const = 0;
const gchar*property_name () const { return g_quark_to_string (_property_id); }
PropertyID property_id () const { return _property_id; }
bool operator==(PropertyID pid) const {
return _property_id == pid;
}
protected:
PropertyID _property_id;
bool _have_old;
};
class PropertyFactory
{
public:
static PropertyBase* create (const XMLNode&);
};
}
#endif /* __libpbd_property_basics_h__ */

View File

@ -0,0 +1,53 @@
/*
Copyright (C) 2010 Paul Davis
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef __libpbd_property_basics_impl_h__
#define __libpbd_property_basics_impl_h__
namespace PBD {
template<typename T>
PropertyChange::PropertyChange(PropertyDescriptor<T> p)
{
insert (p.property_id);
}
template<typename T> PropertyChange
PropertyChange::operator=(PropertyDescriptor<T> p)
{
clear ();
insert (p.property_id);
return *this;
}
template<typename T> bool
PropertyChange::contains (PropertyDescriptor<T> p) const
{
return find (p.property_id) != end ();
}
template<typename T> void
PropertyChange::add (PropertyDescriptor<T> p)
{
insert (p.property_id);
}
}
#endif /* __libpbd_property_basics_impl_h__ */

View File

@ -0,0 +1,75 @@
/*
Copyright (C) 2010 Paul Davis
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef __pbd_property_list_h__
#define __pbd_property_list_h__
#include <map>
#include "pbd/property_basics.h"
class XMLNode;
namespace PBD {
class PropertyList : public std::map<PropertyID, PropertyBase*>
{
public:
PropertyList();
virtual ~PropertyList();
void add_history_state (XMLNode* before);
/** Add a property (of some kind) to the list. Used when
constructing PropertyList's that describe a change/operation.
*/
bool add (PropertyBase* prop);
/* Code that is constructing a property list for use
* in setting the state of an object uses this.
*
* Defined below, once we have Property<T>
*/
template<typename T, typename V> bool add (PropertyDescriptor<T> pid, const V& v);
protected:
bool _property_owner;
};
/** A variant of PropertyList that does not delete its
* property list in its destructor. Objects with their
* own Properties store them in an OwnedPropertyList
* to avoid having them deleted at the wrong time.
*/
class OwnedPropertyList : public PropertyList
{
public:
OwnedPropertyList();
/* Classes that own property lists use this to add their
* property members to their plists. Note that it takes
* a reference argument rather than a pointer like
* one of the add() methods in PropertyList.
*/
bool add (PropertyBase& p);
};
}
#endif /* __pbd_property_list_h__ */

View File

@ -0,0 +1,37 @@
/*
Copyright (C) 2010 Paul Davis
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef __libpbd_property_list_impl_h__
#define __libpbd_property_list_impl_h__
#include "pbd/property_list.h"
#include "pbd/properties.h"
/* now we can define this ... */
namespace PBD {
template<typename T, typename V> bool
PropertyList::add (PropertyDescriptor<T> pid, const V& v) {
return insert (value_type (pid.property_id, new Property<T> (pid, (T)v))).second;
}
}
#endif /* __libpbd_property_list_impl_h__ */

View File

@ -0,0 +1,291 @@
#ifndef __libpbd_sequence_property_h__
#define __libpbd_sequence_property_h__
#include <iostream>
#include <set>
#include <list>
#include <boost/function.hpp>
#include "pbd/id.h"
#include "pbd/property_basics.h"
#include "i18n.h"
namespace PBD {
template<typename Container>
class SequenceProperty : public PropertyBase
{
public:
typedef std::set<typename Container::value_type> ChangeContainer;
struct ChangeRecord {
ChangeContainer added;
ChangeContainer removed;
};
SequenceProperty (PropertyID id, const boost::function<void(const ChangeRecord&)>& update)
: PropertyBase (id), _update_callback (update) {}
virtual typename Container::value_type lookup_id (const PBD::ID&) = 0;
void invert_changes () {
/* reverse the adds/removes so that this property's change member
correctly describes how to undo the changes it currently
reflects. A derived instance of this type of property will
create a pdiff() pair by copying the property twice, and
calling this method on the "before" item of the pair.
*/
_change.removed.swap (_change.added);
}
void add_history_state (XMLNode* history_node) const {
/* XXX need to capitalize property name */
XMLNode* child = new XMLNode (property_name());
history_node->add_child_nocopy (*child);
/* record the change described in our change member */
if (!_change.added.empty()) {
for (typename ChangeContainer::iterator i = _change.added.begin(); i != _change.added.end(); ++i) {
XMLNode* add_node = new XMLNode (X_("Add"));
child->add_child_nocopy (*add_node);
add_node->add_property (X_("id"), (*i)->id().to_s());
}
}
if (!_change.removed.empty()) {
for (typename ChangeContainer::iterator i = _change.removed.begin(); i != _change.removed.end(); ++i) {
XMLNode* remove_node = new XMLNode (X_("Remove"));
child->add_child_nocopy (*remove_node);
remove_node->add_property (X_("id"), (*i)->id().to_s());
}
}
}
bool set_state_from_owner_state (XMLNode const& owner_state) {
XMLProperty const* n = owner_state.property (X_("name"));
if (!n) {
return false;
}
assert (g_quark_from_string (n->value().c_str()) == property_id());
const XMLNodeList& children = owner_state.children();
for (XMLNodeList::const_iterator c = children.begin(); c != children.end(); ++c) {
if ((*c)->name() == X_("Added")) {
const XMLNodeList& grandchildren = (*c)->children();
for (XMLNodeList::const_iterator gc = grandchildren.begin(); gc != grandchildren.end(); ++gc) {
const XMLProperty* prop = (*gc)->property (X_("id"));
if (prop) {
typename Container::value_type v = lookup_id (PBD::ID (prop->value()));
if (v) {
_change.added.insert (v);
}
}
}
} else if ((*c)->name() == X_("Removed")) {
const XMLNodeList& grandchildren = (*c)->children();
for (XMLNodeList::const_iterator gc = grandchildren.begin(); gc != grandchildren.end(); ++gc) {
const XMLProperty* prop = (*gc)->property (X_("id"));
if (prop) {
typename Container::value_type v = lookup_id (PBD::ID (prop->value()));
if (v) {
_change.removed.insert (v);
}
}
}
}
}
return true;
}
void add_state_to_owner_state (XMLNode& owner_state_node) const {
for (typename Container::const_iterator i = _val.begin(); i != _val.end(); ++i) {
owner_state_node.add_child_nocopy ((*i)->get_state ());
}
}
void clear_history () {
PropertyBase::clear_history();
_change.added.clear ();
_change.removed.clear ();
}
/** Given a record of changes to this property, pass it to a callback that will
* update the property in some appropriate way.
*
* This exists because simply using std::sequence methods to add/remove items
* from the property is far too simplistic - the semantics of add/remove may
* be much more complex than that.
*/
void update (const ChangeRecord& cr) {
_update_callback (cr);
}
/* Wrap salient methods of Sequence
*/
typename Container::iterator begin() { return _val.begin(); }
typename Container::iterator end() { return _val.end(); }
typename Container::const_iterator begin() const { return _val.begin(); }
typename Container::const_iterator end() const { return _val.end(); }
typename Container::reverse_iterator rbegin() { return _val.rbegin(); }
typename Container::reverse_iterator rend() { return _val.rend(); }
typename Container::const_reverse_iterator rbegin() const { return _val.rbegin(); }
typename Container::const_reverse_iterator rend() const { return _val.rend(); }
typename Container::iterator insert (typename Container::iterator i, const typename Container::value_type& v) {
_have_old = true;
_change.added.insert (v);
return _val.insert (i, v);
}
typename Container::iterator erase (typename Container::iterator i) {
if (i != _val.end()) {
_have_old = true;
_change.removed.insert (*i);
}
return _val.erase (i);
}
typename Container::iterator erase (typename Container::iterator f, typename Container::iterator l) {
_have_old = true;
for (typename Container::const_iterator i = f; i != l; ++i) {
_change.removed.insert(*i);
}
return _val.erase (f, l);
}
void push_back (const typename Container::value_type& v) {
_have_old = true;
_change.added.insert (v);
_val.push_back (v);
}
void push_front (const typename Container::value_type& v) {
_have_old = true;
_change.added.insert (v);
_val.push_front (v);
}
void pop_front () {
if (!_val.empty()) {
_have_old = true;
_change.removed.insert (front());
}
_val.pop_front ();
}
void pop_back () {
if (!_val.empty()) {
_have_old = true;
_change.removed.insert (front());
}
_val.pop_back ();
}
void clear () {
_have_old = true;
_change.removed.insert (_val.begin(), _val.end());
_val.clear ();
}
typename Container::size_type size() const {
return _val.size();
}
bool empty() const {
return _val.empty();
}
Container& operator= (const Container& other) {
_have_old = true;
_change.removed.insert (_val.begin(), _val.end());
_change.added.insert (other.begin(), other.end());
return _val = other;
}
typename Container::reference front() {
return _val.front ();
}
typename Container::const_reference front() const {
return _val.front ();
}
typename Container::reference back() {
return _val.back ();
}
typename Container::const_reference back() const {
return _val.back ();
}
void sort() {
_val.sort ();
}
template<class BinaryPredicate> void sort(BinaryPredicate comp) {
_val.sort (comp);
}
const ChangeRecord& change() const { return _change; }
/* for use in building up a SequenceProperty from a serialized
version on disk.
*/
void record_addition (typename Container::value_type v) {
_change.added.insert (v);
}
void record_removal (typename Container::value_type v) {
_change.added.erase (v);
}
protected:
Container _val;
ChangeRecord _change;
boost::function<void(const ChangeRecord&)> _update_callback;
/** Load serialized change history.
* @return true if loading succeeded, false otherwise
*/
bool load_history_state (const XMLNode& history_node) {
const XMLNodeList& children (history_node.children());
for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
const XMLProperty* prop = (*i)->property ("id");
if (prop) {
PBD::ID id (prop->value());
typename Container::value_type v = lookup_id (id);
if (!v) {
std::cerr << "No such item, ID = " << id.to_s() << " (from " << prop->value() << ")\n";
return false;
}
if ((*i)->name() == "Add") {
_change.added.insert (v);
} else if ((*i)->name() == "Remove") {
_change.removed.insert (v);
}
}
}
return true;
}
};
}
#endif /* __libpbd_sequence_property_h__ */

View File

@ -26,7 +26,7 @@
#include "pbd/id.h"
#include "pbd/xml++.h"
#include "pbd/properties.h"
#include "pbd/property_basics.h"
#include "pbd/signals.h"
class XMLNode;
@ -37,6 +37,9 @@ namespace sys {
class path;
}
class PropertyList;
class OwnedPropertyList;
/** Base class for objects with saveable and undoable state */
class Stateful {
public:
@ -51,10 +54,9 @@ class Stateful {
virtual bool set_property (const PropertyBase&) { return false; }
PropertyChange set_properties (const PropertyList&);
const OwnedPropertyList& properties() const { return *_properties; }
void add_property (PropertyBase& s) {
_properties.add (s);
}
void add_property (PropertyBase& s);
/* Extra XML node: so that 3rd parties can attach state to the XMLNode
representing the state of this object.
@ -65,9 +67,13 @@ class Stateful {
const PBD::ID& id() const { return _id; }
/* history management */
void clear_history ();
std::pair<XMLNode *, XMLNode*> diff () const;
void changed (PropertyChange&) const;
void diff (PropertyList&, PropertyList&) const;
/* create a property list from an XMLNode
*/
virtual PropertyList* property_factory(const XMLNode&) const { return 0; }
/* How stateful's notify of changes to their properties
*/
@ -85,7 +91,6 @@ class Stateful {
to get basic property setting done.
*/
PropertyChange set_properties (XMLNode const &);
/* derived classes can implement this to do cross-checking
of property values after either a PropertyList or XML
@ -98,7 +103,7 @@ class Stateful {
PBD::ID _id;
std::string _xml_node_name; ///< name of node to use for this object in XML
OwnedPropertyList _properties;
OwnedPropertyList* _properties;
};
} // namespace PBD

View File

@ -28,6 +28,7 @@ namespace PBD
{
class Stateful;
class PropertyList;
/** A Command which stores its action as the differences between the before and after
* state of a Stateful object.
@ -46,8 +47,8 @@ public:
private:
boost::weak_ptr<Stateful> _object; ///< the object in question
XMLNode* _before; ///< XML node containing the previous values of XML properties which changed
XMLNode* _after; ///< XML node containing the new values of XML properties which changed
PBD::PropertyList* _before; ///< its (partial) state before the command
PBD::PropertyList* _after; ///< its (partial) state after the operation
};
};

View File

@ -0,0 +1,53 @@
/*
Copyright (C) 2010 Paul Davis
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <stdint.h>
#include <cstdio>
#include "pbd/properties.h"
#include "pbd/xml++.h"
#include "i18n.h"
using namespace PBD;
PropertyBase*
PropertyFactory::create (const XMLNode& node)
{
const XMLProperty* prop_type = node.property (X_("property-type"));
const XMLProperty* prop_id = node.property (X_("id"));
const XMLProperty* prop_val = node.property (X_("val"));
if (!prop_type || !prop_id || !prop_val) {
return 0;
}
PropertyID id;
sscanf (prop_id->value().c_str(), "%u", &id);
if (prop_type->value() == typeid (Property<bool>).name()) {
PropertyDescriptor<bool> pd (id);
Property<bool>* p = new Property<bool> (pd);
p->set (p->from_string (prop_val->value()));
return p;
}
return 0;
}

69
libs/pbd/property_list.cc Normal file
View File

@ -0,0 +1,69 @@
/*
Copyright (C) 2010 Paul Davis
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "pbd/debug.h"
#include "pbd/compose.h"
#include "pbd/property_list.h"
#include "pbd/xml++.h"
using namespace PBD;
PropertyList::PropertyList()
: _property_owner (true)
{
}
PropertyList::~PropertyList ()
{
if (_property_owner) {
for (iterator i = begin (); i != end (); ++i) {
delete i->second;
}
}
}
void
PropertyList::add_history_state (XMLNode* history_node)
{
for (const_iterator i = begin(); i != end(); ++i) {
DEBUG_TRACE (DEBUG::Properties, string_compose ("Add before/after to %1 for %2\n",
history_node->name(),
i->second->property_name()));
i->second->add_history_state (history_node);
}
}
bool
PropertyList::add (PropertyBase* prop)
{
return insert (value_type (prop->property_id(), prop)).second;
}
OwnedPropertyList::OwnedPropertyList ()
{
_property_owner = false;
}
bool
OwnedPropertyList::add (PropertyBase& p)
{
return insert (value_type (p.property_id (), &p)).second;
}

View File

@ -20,7 +20,10 @@
#include <unistd.h>
#include "pbd/debug.h"
#include "pbd/stateful.h"
#include "pbd/property_list.h"
#include "pbd/properties.h"
#include "pbd/destructible.h"
#include "pbd/filesystem.h"
#include "pbd/xml++.h"
@ -36,6 +39,7 @@ int Stateful::current_state_version = 0;
int Stateful::loading_state_version = 0;
Stateful::Stateful ()
: _properties (new OwnedPropertyList)
{
_extra_xml = 0;
_instant_xml = 0;
@ -43,6 +47,8 @@ Stateful::Stateful ()
Stateful::~Stateful ()
{
delete _properties;
// Do not delete _extra_xml. The use of add_child_nocopy()
// means it needs to live on indefinately.
@ -153,53 +159,30 @@ Stateful::instant_xml (const string& str, const sys::path& directory_path)
void
Stateful::clear_history ()
{
for (OwnedPropertyList::iterator i = _properties.begin(); i != _properties.end(); ++i) {
for (OwnedPropertyList::iterator i = _properties->begin(); i != _properties->end(); ++i) {
i->second->clear_history ();
}
}
/** @return A pair of XMLNodes representing state that has changed since the last time clear_history
* was called on this object; the first is the state before, the second the state after.
*
* It is the caller's responsibility to delete the returned XMLNodes.
*/
pair<XMLNode *, XMLNode *>
Stateful::diff () const
void
Stateful::diff (PropertyList& before, PropertyList& after) const
{
XMLNode* old = new XMLNode (_xml_node_name);
XMLNode* current = new XMLNode (_xml_node_name);
for (OwnedPropertyList::const_iterator i = _properties.begin(); i != _properties.end(); ++i) {
i->second->diff (old, current);
for (OwnedPropertyList::const_iterator i = _properties->begin(); i != _properties->end(); ++i) {
i->second->diff (before, after);
}
return make_pair (old, current);
}
/** Modifies PropertyChange @param c to indicate what properties have changed since the last
time clear_history was called on this object. Note that not all properties have change
values - if this object has any such Property members, they will never show up in
the value of @param c. Note also that @param c is not cleared by this function.
*/
void
Stateful::changed (PropertyChange& c) const
{
for (OwnedPropertyList::const_iterator i = _properties.begin(); i != _properties.end(); ++i) {
i->second->diff (c);
}
}
/** Set state of some/all _properties from an XML node.
* @param node Node.
* @return PropertyChanges made.
*/
PropertyChange
Stateful::set_properties (XMLNode const & node)
Stateful::set_properties (XMLNode const & owner_state)
{
PropertyChange c;
for (OwnedPropertyList::iterator i = _properties.begin(); i != _properties.end(); ++i) {
if (i->second->set_state (node)) {
for (OwnedPropertyList::iterator i = _properties->begin(); i != _properties->end(); ++i) {
if (i->second->set_state_from_owner_state (owner_state)) {
c.add (i->first);
}
}
@ -215,12 +198,22 @@ Stateful::set_properties (const PropertyList& property_list)
PropertyChange c;
PropertyList::const_iterator p;
for (OwnedPropertyList::iterator i = _properties.begin(); i != _properties.end(); ++i) {
if ((p = property_list.find (i->first)) != property_list.end()) {
if (set_property (*p->second)) {
DEBUG_TRACE (DEBUG::Stateful, string_compose ("Stateful %1 setting properties from list of %2\n", this, property_list.size()));
for (PropertyList::const_iterator pp = property_list.begin(); pp != property_list.end(); ++pp) {
DEBUG_TRACE (DEBUG::Stateful, string_compose ("in plist: %1\n", pp->second->property_name()));
}
for (PropertyList::const_iterator i = property_list.begin(); i != property_list.end(); ++i) {
if ((p = _properties->find (i->first)) != _properties->end()) {
DEBUG_TRACE (DEBUG::Stateful, string_compose ("actually setting property %1\n", p->second->property_name()));
if (set_property (*i->second)) {
c.add (i->first);
}
}
} else {
DEBUG_TRACE (DEBUG::Stateful, string_compose ("passed in property %1 not found in own property list\n",
i->second->property_name()));
}
}
post_set ();
@ -228,16 +221,21 @@ Stateful::set_properties (const PropertyList& property_list)
return c;
}
/** Add property states to an XML node.
* @param node Node.
*/
void
Stateful::add_properties (XMLNode & node)
Stateful::add_properties (XMLNode& owner_state)
{
for (OwnedPropertyList::iterator i = _properties.begin(); i != _properties.end(); ++i) {
i->second->add_state (node);
for (OwnedPropertyList::iterator i = _properties->begin(); i != _properties->end(); ++i) {
i->second->add_state_to_owner_state (owner_state);
}
}
void
Stateful::add_property (PropertyBase& s)
{
_properties->add (s);
}
} // namespace PBD

View File

@ -17,7 +17,10 @@
*/
#include <iostream>
#include "pbd/stateful_diff_command.h"
#include "pbd/property_list.h"
#include "i18n.h"
using namespace std;
@ -30,24 +33,35 @@ using namespace PBD;
StatefulDiffCommand::StatefulDiffCommand (boost::shared_ptr<Stateful> s)
: _object (s)
, _before (new PropertyList)
, _after (new PropertyList)
{
pair<XMLNode *, XMLNode*> const p = s->diff ();
_before = p.first;
_after = p.second;
s->diff (*_before, *_after);
}
StatefulDiffCommand::StatefulDiffCommand (boost::shared_ptr<Stateful> s, XMLNode const & n)
: _object (s)
, _before (0)
, _after (0)
{
_before = new XMLNode (*n.children().front());
_after = new XMLNode (*n.children().back());
}
const XMLNodeList& children (n.children());
for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
if ((*i)->name() == X_("Undo")) {
_before = s->property_factory (**i);
} else if ((*i)->name() == X_("Do")) {
_after = s->property_factory (**i);
}
}
assert (_before != 0);
assert (_after != 0);
}
StatefulDiffCommand::~StatefulDiffCommand ()
{
delete _before;
delete _after;
delete _before;
delete _after;
}
void
@ -56,7 +70,10 @@ StatefulDiffCommand::operator() ()
boost::shared_ptr<Stateful> s (_object.lock());
if (s) {
s->set_state (*_after, Stateful::current_state_version);
PropertyChange changed = s->set_properties (*_after);
if (!changed.empty()) {
s->PropertyChanged (changed);
}
}
}
@ -66,7 +83,12 @@ StatefulDiffCommand::undo ()
boost::shared_ptr<Stateful> s (_object.lock());
if (s) {
s->set_state (*_before, Stateful::current_state_version);
std::cerr << "Undoing a stateful diff command\n";
PropertyChange changed = s->set_properties (*_before);
if (!changed.empty()) {
std::cerr << "Sending changed\n";
s->PropertyChanged (changed);
}
}
}
@ -84,8 +106,15 @@ StatefulDiffCommand::get_state ()
node->add_property ("obj-id", s->id().to_s());
node->add_property ("type-name", typeid(*s.get()).name());
node->add_child_copy (*_before);
node->add_child_copy (*_after);
XMLNode* before = new XMLNode (X_("Undo"));
XMLNode* after = new XMLNode (X_("Do"));
_before->add_history_state (before);
_after->add_history_state (after);
node->add_child_nocopy (*before);
node->add_child_nocopy (*after);
return *node;
}

View File

@ -309,7 +309,6 @@ UndoHistory::redo (unsigned int n)
timersub (&end, &start, &diff);
cerr << "Redo took " << diff.tv_sec << '.' << diff.tv_usec << endl;
EndUndoRedo (); /* EMIT SIGNAL */
Changed (); /* EMIT SIGNAL */
}

View File

@ -59,6 +59,7 @@ def build(bld):
controllable.cc
controllable_descriptor.cc
crossthread.cc
debug.cc
enumwriter.cc
event_loop.cc
dmalloc.cc
@ -74,6 +75,8 @@ def build(bld):
mountpoint.cc
pathscanner.cc
pool.cc
property_factory.cc
property_list.cc
pthread_utils.cc
receiver.cc
search_path.cc

View File

@ -40,6 +40,7 @@
using namespace std;
using namespace Mackie;
using namespace ARDOUR;
using namespace PBD;
// The MCU sysex header
MidiByteArray mackie_sysex_hdr ( 5, MIDI::sysex, 0x0, 0x0, 0x66, 0x10 );