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:
parent
3540594dc5
commit
db8b575c30
|
@ -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 ();
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 ();
|
||||
|
||||
|
|
|
@ -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"));
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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__ */
|
||||
|
||||
|
|
|
@ -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>);
|
||||
|
|
|
@ -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; }
|
||||
|
||||
|
|
|
@ -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>);
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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> >&);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
|
||||
using namespace std;
|
||||
using namespace ARDOUR;
|
||||
using namespace PBD;
|
||||
|
||||
/** Read a block of MIDI events from buffer into a MidiBuffer.
|
||||
*
|
||||
|
|
|
@ -34,6 +34,7 @@
|
|||
|
||||
using namespace std;
|
||||
using namespace ARDOUR;
|
||||
using namespace PBD;
|
||||
using namespace Glib;
|
||||
|
||||
#include "i18n.h"
|
||||
|
|
|
@ -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 ();
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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 */
|
||||
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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__ */
|
||||
|
|
@ -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__ */
|
||||
|
|
|
@ -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__ */
|
|
@ -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__ */
|
|
@ -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__ */
|
|
@ -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__ */
|
|
@ -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__ */
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
};
|
||||
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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 */
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 );
|
||||
|
|
Loading…
Reference in New Issue