diff options
27 files changed, 658 insertions, 250 deletions
diff --git a/src/common/interface/GraphObject.hpp b/src/common/interface/GraphObject.hpp index fa7be25a..c6fb5856 100644 --- a/src/common/interface/GraphObject.hpp +++ b/src/common/interface/GraphObject.hpp @@ -50,7 +50,9 @@ public: virtual const Raul::Path path() const = 0; virtual const Raul::Symbol symbol() const = 0; virtual const Variables& variables() const = 0; + virtual Variables& variables() = 0; virtual const Properties& properties() const = 0; + virtual Properties& properties() = 0; virtual bool polyphonic() const = 0; // FIXME: return WeakPtr, and stupid name diff --git a/src/libs/client/ClientStore.cpp b/src/libs/client/ClientStore.cpp index 969f3a8f..6c2c81ff 100644 --- a/src/libs/client/ClientStore.cpp +++ b/src/libs/client/ClientStore.cpp @@ -35,20 +35,27 @@ namespace Client { ClientStore::ClientStore(SharedPtr<EngineInterface> engine, SharedPtr<SigClientInterface> emitter) : _engine(engine) , _emitter(emitter) + , _plugins(new Plugins()) { - emitter->signal_object_destroyed.connect(sigc::mem_fun(this, &ClientStore::destruction_event)); - emitter->signal_object_renamed.connect(sigc::mem_fun(this, &ClientStore::rename_event)); - emitter->signal_new_plugin.connect(sigc::mem_fun(this, &ClientStore::new_plugin_event)); - emitter->signal_new_patch.connect(sigc::mem_fun(this, &ClientStore::new_patch_event)); - emitter->signal_new_node.connect(sigc::mem_fun(this, &ClientStore::new_node_event)); - emitter->signal_new_port.connect(sigc::mem_fun(this, &ClientStore::new_port_event)); - emitter->signal_patch_cleared.connect(sigc::mem_fun(this, &ClientStore::patch_cleared_event)); - emitter->signal_connection.connect(sigc::mem_fun(this, &ClientStore::connection_event)); - emitter->signal_disconnection.connect(sigc::mem_fun(this, &ClientStore::disconnection_event)); - emitter->signal_variable_change.connect(sigc::mem_fun(this, &ClientStore::variable_change_event)); - emitter->signal_property_change.connect(sigc::mem_fun(this, &ClientStore::property_change_event)); - emitter->signal_port_value.connect(sigc::mem_fun(this, &ClientStore::port_value_event)); - emitter->signal_port_activity.connect(sigc::mem_fun(this, &ClientStore::port_activity_event)); + _handle_orphans = (engine && emitter); + + if (!emitter) + return; + + emitter->signal_object_destroyed.connect(sigc::mem_fun(this, &ClientStore::destruction)); + emitter->signal_object_renamed.connect(sigc::mem_fun(this, &ClientStore::rename)); + emitter->signal_new_plugin.connect(sigc::mem_fun(this, &ClientStore::new_plugin)); + emitter->signal_new_patch.connect(sigc::mem_fun(this, &ClientStore::new_patch)); + emitter->signal_new_node.connect(sigc::mem_fun(this, &ClientStore::new_node)); + emitter->signal_new_port.connect(sigc::mem_fun(this, &ClientStore::new_port)); + emitter->signal_patch_cleared.connect(sigc::mem_fun(this, &ClientStore::patch_cleared)); + emitter->signal_connection.connect(sigc::mem_fun(this, &ClientStore::connect)); + emitter->signal_disconnection.connect(sigc::mem_fun(this, &ClientStore::disconnect)); + emitter->signal_variable_change.connect(sigc::mem_fun(this, &ClientStore::set_variable)); + emitter->signal_property_change.connect(sigc::mem_fun(this, &ClientStore::set_property)); + emitter->signal_port_value.connect(sigc::mem_fun(this, &ClientStore::set_port_value)); + emitter->signal_voice_value.connect(sigc::mem_fun(this, &ClientStore::set_voice_value)); + emitter->signal_port_activity.connect(sigc::mem_fun(this, &ClientStore::port_activity)); } @@ -56,13 +63,15 @@ void ClientStore::clear() { Store::clear(); - _plugins.clear(); + _plugins->clear(); } void ClientStore::add_plugin_orphan(SharedPtr<NodeModel> node) { + if (!_handle_orphans) + return; cerr << "WARNING: Node " << node->path() << " received, but plugin " << node->plugin_uri() << " unknown." << endl; @@ -84,6 +93,8 @@ ClientStore::add_plugin_orphan(SharedPtr<NodeModel> node) void ClientStore::resolve_plugin_orphans(SharedPtr<PluginModel> plugin) { + if (!_handle_orphans) + return; Raul::Table<string, list<SharedPtr<NodeModel> > >::iterator n = _plugin_orphans.find(plugin->uri()); @@ -106,6 +117,8 @@ ClientStore::resolve_plugin_orphans(SharedPtr<PluginModel> plugin) void ClientStore::add_connection_orphan(std::pair<Path, Path> orphan) { + if (!_handle_orphans) + return; cerr << "WARNING: Orphan connection " << orphan.first << " -> " << orphan.second << " received." << endl; @@ -116,6 +129,8 @@ ClientStore::add_connection_orphan(std::pair<Path, Path> orphan) void ClientStore::resolve_connection_orphans(SharedPtr<PortModel> port) { + if (!_handle_orphans) + return; assert(port->parent()); for (list< pair<Path, Path> >::iterator c = _connection_orphans.begin(); @@ -139,6 +154,8 @@ ClientStore::resolve_connection_orphans(SharedPtr<PortModel> port) void ClientStore::add_orphan(SharedPtr<ObjectModel> child) { + if (!_handle_orphans) + return; cerr << "WARNING: Orphan object " << child->path() << " received." << endl; Raul::PathTable<list<SharedPtr<ObjectModel> > >::iterator children @@ -159,6 +176,8 @@ ClientStore::add_orphan(SharedPtr<ObjectModel> child) void ClientStore::add_variable_orphan(const Path& subject_path, const string& predicate, const Atom& value) { + if (!_handle_orphans) + return; Raul::PathTable<list<std::pair<string, Atom> > >::iterator orphans = _variable_orphans.find(subject_path); @@ -177,6 +196,8 @@ ClientStore::add_variable_orphan(const Path& subject_path, const string& predica void ClientStore::resolve_variable_orphans(SharedPtr<ObjectModel> subject) { + if (!_handle_orphans) + return; Raul::PathTable<list<std::pair<string, Atom> > >::iterator v = _variable_orphans.find(subject->path()); @@ -198,6 +219,8 @@ ClientStore::resolve_variable_orphans(SharedPtr<ObjectModel> subject) void ClientStore::resolve_orphans(SharedPtr<ObjectModel> parent) { + if (!_handle_orphans) + return; Raul::PathTable<list<SharedPtr<ObjectModel> > >::iterator c = _orphans.find(parent->path()); @@ -222,6 +245,7 @@ ClientStore::add_object(SharedPtr<ObjectModel> object) // one (with precedence to the new values). iterator existing = find(object->path()); if (existing != end()) { + cout << "WARNING: Object " << object->path() << " already exists in store" << endl; PtrCast<ObjectModel>(existing->second)->set(object); } else { @@ -307,8 +331,8 @@ SharedPtr<PluginModel> ClientStore::plugin(const string& uri) { assert(uri.length() > 0); - Plugins::iterator i = _plugins.find(uri); - if (i == _plugins.end()) + Plugins::iterator i = _plugins->find(uri); + if (i == _plugins->end()) return SharedPtr<PluginModel>(); else return (*i).second; @@ -335,9 +359,9 @@ ClientStore::add_plugin(SharedPtr<PluginModel> pm) { // FIXME: dupes? merge, like with objects? - _plugins[pm->uri()] = pm; + (*_plugins)[pm->uri()] = pm; signal_new_plugin(pm); - //cerr << "Plugin: " << pm->uri() << ", # plugins: " << _plugins.size() << endl; + //cerr << "Plugin: " << pm->uri() << ", # plugins: " << _plugins->size() << endl; } @@ -345,7 +369,7 @@ ClientStore::add_plugin(SharedPtr<PluginModel> pm) void -ClientStore::destruction_event(const Path& path) +ClientStore::destruction(const Path& path) { SharedPtr<ObjectModel> removed = remove_object(path); @@ -356,7 +380,7 @@ ClientStore::destruction_event(const Path& path) } void -ClientStore::rename_event(const Path& old_path, const Path& new_path) +ClientStore::rename(const Path& old_path, const Path& new_path) { iterator parent = find(old_path); if (parent == end()) { @@ -398,7 +422,7 @@ ClientStore::rename_event(const Path& old_path, const Path& new_path) } void -ClientStore::new_plugin_event(const string& uri, const string& type_uri, const string& symbol, const string& name) +ClientStore::new_plugin(const string& uri, const string& type_uri, const string& symbol, const string& name) { SharedPtr<PluginModel> p(new PluginModel(uri, type_uri, symbol, name)); add_plugin(p); @@ -407,7 +431,7 @@ ClientStore::new_plugin_event(const string& uri, const string& type_uri, const s void -ClientStore::new_patch_event(const Path& path, uint32_t poly) +ClientStore::new_patch(const string& path, uint32_t poly) { SharedPtr<PatchModel> p(new PatchModel(path, poly)); add_object(p); @@ -415,7 +439,7 @@ ClientStore::new_patch_event(const Path& path, uint32_t poly) void -ClientStore::new_node_event(const Path& path, const string& plugin_uri) +ClientStore::new_node(const string& path, const string& plugin_uri) { SharedPtr<PluginModel> plug = plugin(plugin_uri); if (!plug) { @@ -429,7 +453,7 @@ ClientStore::new_node_event(const Path& path, const string& plugin_uri) void -ClientStore::new_port_event(const Path& path, uint32_t index, const string& type, bool is_output) +ClientStore::new_port(const string& path, uint32_t index, const string& type, bool is_output) { PortModel::Direction pdir = is_output ? PortModel::OUTPUT : PortModel::INPUT; @@ -441,7 +465,7 @@ ClientStore::new_port_event(const Path& path, uint32_t index, const string& type void -ClientStore::patch_cleared_event(const Path& path) +ClientStore::patch_cleared(const Path& path) { iterator i = find(path); if (i != end()) { @@ -469,7 +493,7 @@ ClientStore::patch_cleared_event(const Path& path) void -ClientStore::variable_change_event(const Path& subject_path, const string& predicate, const Atom& value) +ClientStore::set_variable(const string& subject_path, const string& predicate, const Atom& value) { SharedPtr<ObjectModel> subject = object(subject_path); @@ -485,7 +509,7 @@ ClientStore::variable_change_event(const Path& subject_path, const string& predi void -ClientStore::property_change_event(const Path& subject_path, const string& predicate, const Atom& value) +ClientStore::set_property(const string& subject_path, const string& predicate, const Atom& value) { SharedPtr<ObjectModel> subject = object(subject_path); @@ -501,7 +525,7 @@ ClientStore::property_change_event(const Path& subject_path, const string& predi void -ClientStore::port_value_event(const Path& port_path, const Raul::Atom& value) +ClientStore::set_port_value(const string& port_path, const Raul::Atom& value) { SharedPtr<PortModel> port = PtrCast<PortModel>(object(port_path)); if (port) @@ -510,9 +534,20 @@ ClientStore::port_value_event(const Path& port_path, const Raul::Atom& value) cerr << "ERROR: control change for nonexistant port " << port_path << endl; } + +void +ClientStore::set_voice_value(const string& port_path, uint32_t voice, const Raul::Atom& value) +{ + SharedPtr<PortModel> port = PtrCast<PortModel>(object(port_path)); + if (port) + port->value(voice, value); + else + cerr << "ERROR: poly control change for nonexistant port " << port_path << endl; +} + void -ClientStore::port_activity_event(const Path& port_path) +ClientStore::port_activity(const Path& port_path) { SharedPtr<PortModel> port = PtrCast<PortModel>(object(port_path)); if (port) @@ -581,14 +616,14 @@ ClientStore::attempt_connection(const Path& src_port_path, const Path& dst_port_ void -ClientStore::connection_event(const Path& src_port_path, const Path& dst_port_path) +ClientStore::connect(const string& src_port_path, const string& dst_port_path) { attempt_connection(src_port_path, dst_port_path, true); } void -ClientStore::disconnection_event(const Path& src_port_path, const Path& dst_port_path) +ClientStore::disconnect(const string& src_port_path, const string& dst_port_path) { // Find the ports and create a ConnectionModel just to get at the parent path // finding logic in ConnectionModel. So I'm lazy. diff --git a/src/libs/client/ClientStore.hpp b/src/libs/client/ClientStore.hpp index a750f875..4b4d9742 100644 --- a/src/libs/client/ClientStore.hpp +++ b/src/libs/client/ClientStore.hpp @@ -53,9 +53,10 @@ class ConnectionModel; * * \ingroup IngenClient */ -class ClientStore : public Shared::Store, public sigc::trackable { // FIXME: is trackable necessary? +class ClientStore : public Shared::Store, public Shared::CommonInterface, public sigc::trackable { public: - ClientStore(SharedPtr<EngineInterface> engine, SharedPtr<SigClientInterface> emitter); + ClientStore(SharedPtr<EngineInterface> engine=SharedPtr<EngineInterface>(), + SharedPtr<SigClientInterface> emitter=SharedPtr<SigClientInterface>()); SharedPtr<PluginModel> plugin(const string& uri); SharedPtr<ObjectModel> object(const Path& path); @@ -63,7 +64,21 @@ public: void clear(); typedef Raul::Table<string, SharedPtr<PluginModel> > Plugins; - const Plugins& plugins() const { return _plugins; } + SharedPtr<const Plugins> plugins() const { return _plugins; } + SharedPtr<Plugins> plugins() { return _plugins; } + void set_plugins(SharedPtr<Plugins> p) { _plugins = p; } + + // CommonInterface + void new_plugin(const string& uri, const string& type_uri, const string& symbol, const string& name); + void new_patch(const string& path, uint32_t poly); + void new_node(const string& path, const string& plugin_uri); + void new_port(const string& path, uint32_t index, const string& data_type, bool is_output); + void set_variable(const string& subject_path, const string& predicate, const Atom& value); + void set_property(const string& subject_path, const string& predicate, const Atom& value); + void set_port_value(const string& port_path, const Raul::Atom& value); + void set_voice_value(const string& port_path, uint32_t voice, const Raul::Atom& value); + void connect(const string& src_port_path, const string& dst_port_path); + void disconnect(const string& src_port_path, const string& dst_port_path); sigc::signal<void, SharedPtr<ObjectModel> > signal_new_object; sigc::signal<void, SharedPtr<PluginModel> > signal_new_plugin; @@ -92,28 +107,24 @@ private: void add_variable_orphan(const Path& subject, const string& predicate, const Atom& value); void resolve_variable_orphans(SharedPtr<ObjectModel> subject); + + void bundle_begin() {} + void bundle_end() {} // Slots for SigClientInterface signals - void destruction_event(const Path& path); - void rename_event(const Path& old_path, const Path& new_path); - void new_plugin_event(const string& uri, const string& type_uri, const string& symbol, const string& name); - void new_patch_event(const Path& path, uint32_t poly); - void new_node_event(const Path& path, const string& plugin_uri); - void new_port_event(const Path& path, uint32_t index, const string& data_type, bool is_output); - void patch_cleared_event(const Path& path); - void variable_change_event(const Path& subject_path, const string& predicate, const Atom& value); - void property_change_event(const Path& subject_path, const string& predicate, const Atom& value); - void port_value_event(const Path& port_path, const Raul::Atom& value); - void port_activity_event(const Path& port_path); - void connection_event(const Path& src_port_path, const Path& dst_port_path); - void disconnection_event(const Path& src_port_path, const Path& dst_port_path); + void destruction(const Path& path); + void rename(const Path& old_path, const Path& new_path); + void patch_cleared(const Path& path); + void port_activity(const Path& port_path); bool attempt_connection(const Path& src_port_path, const Path& dst_port_path, bool add_orphan=false); + bool _handle_orphans; + SharedPtr<EngineInterface> _engine; SharedPtr<SigClientInterface> _emitter; - Plugins _plugins; ///< Map, keyed by plugin URI + SharedPtr<Plugins> _plugins; ///< Map, keyed by plugin URI /** Objects we've received, but depend on the existance of another unknown object. * Keyed by the path of the depended-on object (for tolerance of orderless comms) */ diff --git a/src/libs/client/ObjectModel.cpp b/src/libs/client/ObjectModel.cpp index 0afb9ad8..e9a491a6 100644 --- a/src/libs/client/ObjectModel.cpp +++ b/src/libs/client/ObjectModel.cpp @@ -54,6 +54,23 @@ ObjectModel::get_variable(const string& key) const } +/** Get a variable for this object. + * + * @return Metadata value with key @a key, empty string otherwise. + */ +Atom& +ObjectModel::get_variable( string& key) +{ + static Atom null_atom; + + Variables::iterator i = _variables.find(key); + if (i != _variables.end()) + return i->second; + else + return null_atom; +} + + /** Get a property of this object. * * @return Metadata value with key @a key, empty string otherwise. @@ -71,6 +88,23 @@ ObjectModel::get_property(const string& key) const } +/** Get a property of this object. + * + * @return Metadata value with key @a key, empty string otherwise. + */ +Atom& +ObjectModel::get_property(const string& key) +{ + static Atom null_atom; + + Properties::iterator i = _properties.find(key); + if (i != _properties.end()) + return i->second; + else + return null_atom; +} + + bool ObjectModel::polyphonic() const { diff --git a/src/libs/client/ObjectModel.hpp b/src/libs/client/ObjectModel.hpp index 2b4642da..11cc87a4 100644 --- a/src/libs/client/ObjectModel.hpp +++ b/src/libs/client/ObjectModel.hpp @@ -60,7 +60,9 @@ public: virtual ~ObjectModel(); const Atom& get_variable(const string& key) const; + Atom& get_variable( string& key); const Atom& get_property(const string& key) const; + Atom& get_property(const string& key); virtual void set_variable(const string& key, const Atom& value) { _variables[key] = value; signal_variable.emit(key, value); } @@ -70,6 +72,8 @@ public: const Variables& variables() const { return _variables; } const Properties& properties() const { return _properties; } + Variables& variables() { return _variables; } + Properties& properties() { return _properties; } const Path path() const { return _path; } const Symbol symbol() const { return _path.name(); } SharedPtr<ObjectModel> parent() const { return _parent; } diff --git a/src/libs/client/PortModel.hpp b/src/libs/client/PortModel.hpp index 8fa18f1c..a86c9188 100644 --- a/src/libs/client/PortModel.hpp +++ b/src/libs/client/PortModel.hpp @@ -56,16 +56,21 @@ public: inline bool operator==(const PortModel& pm) const { return (_path == pm._path); } - inline void value(const Atom& val) - { + inline void value(const Atom& val) { if (val != _current_val) { _current_val = val; signal_value_changed.emit(val); } } + inline void value(uint32_t voice, const Atom& val) { + // FIXME: implement properly + signal_voice_changed.emit(voice, val); + } + // Signals sigc::signal<void, const Atom&> signal_value_changed; ///< Value ports + sigc::signal<void, uint32_t, const Atom&> signal_voice_changed; ///< Polyphonic value ports sigc::signal<void> signal_activity; ///< Message ports sigc::signal<void, SharedPtr<PortModel> > signal_connection; sigc::signal<void, SharedPtr<PortModel> > signal_disconnection; diff --git a/src/libs/engine/EngineStore.cpp b/src/libs/engine/EngineStore.cpp index 5f5e41e5..9fcd3806 100644 --- a/src/libs/engine/EngineStore.cpp +++ b/src/libs/engine/EngineStore.cpp @@ -82,19 +82,7 @@ EngineStore::add(GraphObject* obj) assert(ThreadManager::current_thread_id() == THREAD_PRE_PROCESS); - if (find(o->path()) != end()) { - cerr << "[EngineStore] ERROR: Attempt to add duplicate object " << o->path() << endl; - return; - } - - insert(make_pair(o->path(), o)); - - NodeImpl* node = dynamic_cast<NodeImpl*>(o); - if (node) { - for (uint32_t i=0; i < node->num_ports(); ++i) { - add(node->port_impl(i)); - } - } + Store::add(obj); } diff --git a/src/libs/engine/GraphObjectImpl.hpp b/src/libs/engine/GraphObjectImpl.hpp index d1896b1b..bee10c98 100644 --- a/src/libs/engine/GraphObjectImpl.hpp +++ b/src/libs/engine/GraphObjectImpl.hpp @@ -87,6 +87,8 @@ public: const Variables& variables() const { return _variables; } const Properties& properties() const { return _properties; } + Variables& variables() { return _variables; } + Properties& properties() { return _properties; } /** The Patch this object is a child of. */ virtual PatchImpl* parent_patch() const; diff --git a/src/libs/engine/LV2Plugin.cpp b/src/libs/engine/LV2Plugin.cpp index 871050e4..53d317b4 100644 --- a/src/libs/engine/LV2Plugin.cpp +++ b/src/libs/engine/LV2Plugin.cpp @@ -47,9 +47,8 @@ LV2Plugin::symbol() const const string LV2Plugin::name() const { - SLV2Value name = slv2_plugin_get_name(_slv2_plugin); - if (name) - return slv2_value_as_string(name); + if (_name) + return slv2_value_as_string(_name); else return "(no name)"; } @@ -70,9 +69,21 @@ LV2Plugin::instantiate(const string& name, delete n; n = NULL; } + + return n; } + + +void +LV2Plugin::slv2_plugin(SLV2Plugin p) +{ + _slv2_plugin = p; + if (_name) + slv2_value_free(_name); + _name = slv2_plugin_get_name(_slv2_plugin); +} } // namespace Ingen diff --git a/src/libs/engine/LV2Plugin.hpp b/src/libs/engine/LV2Plugin.hpp index effdefdc..827e7e89 100644 --- a/src/libs/engine/LV2Plugin.hpp +++ b/src/libs/engine/LV2Plugin.hpp @@ -53,6 +53,8 @@ class LV2Plugin : public PluginImpl public: LV2Plugin(SharedPtr<LV2Info> lv2_info, const string& uri) : PluginImpl(Plugin::LV2, uri) + , _name(NULL) + , _slv2_plugin(NULL) , _lv2_info(lv2_info) {} @@ -68,9 +70,10 @@ public: SharedPtr<LV2Info> lv2_info() const { return _lv2_info; } SLV2Plugin slv2_plugin() const { return _slv2_plugin; } - void slv2_plugin(SLV2Plugin p) { _slv2_plugin = p; } + void slv2_plugin(SLV2Plugin p); private: + SLV2Value _name; SLV2Plugin _slv2_plugin; SharedPtr<LV2Info> _lv2_info; }; diff --git a/src/libs/gui/LoadPluginWindow.cpp b/src/libs/gui/LoadPluginWindow.cpp index 92fcb221..436de188 100644 --- a/src/libs/gui/LoadPluginWindow.cpp +++ b/src/libs/gui/LoadPluginWindow.cpp @@ -211,11 +211,11 @@ LoadPluginWindow::plugin_compare(const Gtk::TreeModel::iterator& a_i, void -LoadPluginWindow::set_plugins(const Raul::Table<string, SharedPtr<PluginModel> >& m) +LoadPluginWindow::set_plugins(SharedPtr<const ClientStore::Plugins> m) { _plugins_liststore->clear(); - for (Raul::Table<string, SharedPtr<PluginModel> >::const_iterator i = m.begin(); i != m.end(); ++i) { + for (ClientStore::Plugins::const_iterator i = m->begin(); i != m->end(); ++i) { SharedPtr<PluginModel> plugin = (*i).second; Gtk::TreeModel::iterator iter = _plugins_liststore->append(); @@ -396,8 +396,8 @@ LoadPluginWindow::filter_changed() size_t num_visible = 0; - for (Raul::Table<string, SharedPtr<PluginModel> >::const_iterator i = App::instance().store()->plugins().begin(); - i != App::instance().store()->plugins().end(); ++i) { + for (ClientStore::Plugins::const_iterator i = App::instance().store()->plugins()->begin(); + i != App::instance().store()->plugins()->end(); ++i) { const SharedPtr<PluginModel> plugin = (*i).second; diff --git a/src/libs/gui/LoadPluginWindow.hpp b/src/libs/gui/LoadPluginWindow.hpp index ef1420a0..a5246c39 100644 --- a/src/libs/gui/LoadPluginWindow.hpp +++ b/src/libs/gui/LoadPluginWindow.hpp @@ -26,6 +26,7 @@ #include "interface/GraphObject.hpp" #include "client/PatchModel.hpp" #include "client/PluginModel.hpp" +#include "client/ClientStore.hpp" using Ingen::Client::PluginModel; using Ingen::Client::PatchModel; using namespace Ingen::Shared; @@ -93,7 +94,7 @@ public: LoadPluginWindow(BaseObjectType* cobject, const Glib::RefPtr<Gnome::Glade::Xml>& xml); void set_patch(SharedPtr<PatchModel> patch); - void set_plugins(const Raul::Table<string, SharedPtr<PluginModel> >& m); + void set_plugins(SharedPtr<const ClientStore::Plugins> plugins); void add_plugin(SharedPtr<PluginModel> plugin); diff --git a/src/libs/gui/NodeModule.cpp b/src/libs/gui/NodeModule.cpp index fe71dd2f..7ac86e40 100644 --- a/src/libs/gui/NodeModule.cpp +++ b/src/libs/gui/NodeModule.cpp @@ -104,13 +104,17 @@ NodeModule::create(boost::shared_ptr<PatchCanvas> canvas, SharedPtr<NodeModel> n void NodeModule::value_changed(uint32_t index, const Atom& value) { - float control = value.get_float(); - if (_plugin_ui) { - SLV2UIInstance inst = _plugin_ui->instance(); - const LV2UI_Descriptor* ui_descriptor = slv2_ui_instance_get_descriptor(inst); - LV2UI_Handle ui_handle = slv2_ui_instance_get_handle(inst); - if (ui_descriptor->port_event) - ui_descriptor->port_event(ui_handle, index, 4, 0, &control); + if (value.type() == Atom::FLOAT) { + float control = value.get_float(); + if (_plugin_ui) { + SLV2UIInstance inst = _plugin_ui->instance(); + const LV2UI_Descriptor* ui_descriptor = slv2_ui_instance_get_descriptor(inst); + LV2UI_Handle ui_handle = slv2_ui_instance_get_handle(inst); + if (ui_descriptor->port_event) + ui_descriptor->port_event(ui_handle, index, 4, 0, &control); + } + } else { + cerr << "WARNING: Unknown value type " << (int)value.type() << endl; } } diff --git a/src/libs/gui/PatchCanvas.cpp b/src/libs/gui/PatchCanvas.cpp index 019851f0..d625d2cd 100644 --- a/src/libs/gui/PatchCanvas.cpp +++ b/src/libs/gui/PatchCanvas.cpp @@ -23,6 +23,7 @@ #include <flowcanvas/Canvas.hpp> #include <flowcanvas/Ellipse.hpp> #include "interface/EngineInterface.hpp" +#include "shared/Builder.hpp" #include "serialisation/Serialiser.hpp" #include "client/PluginModel.hpp" #include "client/PatchModel.hpp" @@ -41,6 +42,7 @@ #include "SubpatchModule.hpp" #include "GladeFactory.hpp" #include "WindowFactory.hpp" +#include "ThreadedLoader.hpp" using Ingen::Client::ClientStore; using Ingen::Serialisation::Serialiser; using Ingen::Client::PluginModel; @@ -159,10 +161,10 @@ PatchCanvas::build_internal_menu() _menu->reorder_child(*internal_menu_item, 2); } - const ClientStore::Plugins& plugins = App::instance().store()->plugins(); + SharedPtr<const ClientStore::Plugins> plugins = App::instance().store()->plugins(); // Add Internal plugins - for (ClientStore::Plugins::const_iterator i = plugins.begin(); i != plugins.end(); ++i) { + for (ClientStore::Plugins::const_iterator i = plugins->begin(); i != plugins->end(); ++i) { SharedPtr<PluginModel> p = i->second; if (p->type() == Plugin::Internal) { _internal_menu->items().push_back(Gtk::Menu_Helpers::MenuElem(p->name(), @@ -200,10 +202,10 @@ PatchCanvas::build_plugin_class_menu(Gtk::Menu* menu, } } - const ClientStore::Plugins& plugins = App::instance().store()->plugins(); + SharedPtr<const ClientStore::Plugins> plugins = App::instance().store()->plugins(); // Add LV2 plugins - for (ClientStore::Plugins::const_iterator i = plugins.begin(); i != plugins.end(); ++i) { + for (ClientStore::Plugins::const_iterator i = plugins->begin(); i != plugins->end(); ++i) { SLV2Plugin p = i->second->slv2_plugin(); if (p && slv2_plugin_get_class(p) == plugin_class) { @@ -565,6 +567,36 @@ PatchCanvas::copy_selection() Glib::RefPtr<Gtk::Clipboard> clipboard = Gtk::Clipboard::get(); clipboard->set_text(result); } + + +void +PatchCanvas::paste() +{ + Glib::ustring str = Gtk::Clipboard::get()->wait_for_text(); + SharedPtr<Parser> parser = App::instance().loader()->parser(); + if (!parser) { + cerr << "Unable to load parser, paste unavailable" << endl; + return; + } + + Builder builder(*App::instance().engine()); + ClientStore clipboard; + clipboard.new_patch("/", _patch->poly()); + clipboard.set_plugins(App::instance().store()->plugins()); + parser->parse_string(App::instance().world(), &clipboard, str, "/"); + for (Store::iterator i = clipboard.begin(); i != clipboard.end(); ++i) { + /*GraphObject::Properties::iterator s = i->second->properties().find("ingen:symbol"); + const string sym = string(s->second.get_string()) + "_copy"; + s->second = sym;*/ + GraphObject::Variables::iterator x = i->second->variables().find("ingenuity:canvas-x"); + if (x != i->second->variables().end()) + x->second = x->second.get_float() + 20.0f; + GraphObject::Variables::iterator y = i->second->variables().find("ingenuity:canvas-y"); + if (y != i->second->variables().end()) + y->second = y->second.get_float() + 20.0f; + builder.build(i->second); + } +} string diff --git a/src/libs/gui/PatchCanvas.hpp b/src/libs/gui/PatchCanvas.hpp index 3998532d..f596c97b 100644 --- a/src/libs/gui/PatchCanvas.hpp +++ b/src/libs/gui/PatchCanvas.hpp @@ -79,6 +79,7 @@ public: void destroy_selection(); void copy_selection(); + void paste(); void show_menu(GdkEvent* event); diff --git a/src/libs/gui/PatchWindow.cpp b/src/libs/gui/PatchWindow.cpp index ad558903..125adeea 100644 --- a/src/libs/gui/PatchWindow.cpp +++ b/src/libs/gui/PatchWindow.cpp @@ -98,6 +98,8 @@ PatchWindow::PatchWindow(BaseObjectType* cobject, const Glib::RefPtr<Gnome::Glad sigc::mem_fun(this, &PatchWindow::event_upload)); _menu_copy->signal_activate().connect( sigc::mem_fun(this, &PatchWindow::event_copy)); + _menu_paste->signal_activate().connect( + sigc::mem_fun(this, &PatchWindow::event_paste)); _menu_delete->signal_activate().connect( sigc::mem_fun(this, &PatchWindow::event_delete)); _menu_quit->signal_activate().connect( @@ -130,6 +132,9 @@ PatchWindow::PatchWindow(BaseObjectType* cobject, const Glib::RefPtr<Gnome::Glad #ifndef HAVE_CURL _menu_upload->hide(); #endif + + Glib::RefPtr<Gtk::Clipboard> clipboard = Gtk::Clipboard::get(); + clipboard->signal_owner_change().connect(sigc::mem_fun(this, &PatchWindow::event_clipboard_changed)); } @@ -274,6 +279,14 @@ PatchWindow::event_show_engine() void +PatchWindow::event_clipboard_changed(GdkEventOwnerChange* ev) +{ + Glib::RefPtr<Gtk::Clipboard> clipboard = Gtk::Clipboard::get(); + _menu_paste->set_sensitive(clipboard->wait_is_text_available()); +} + + +void PatchWindow::event_show_controls() { App::instance().window_factory()->present_controls(_patch); @@ -386,6 +399,14 @@ PatchWindow::event_copy() void +PatchWindow::event_paste() +{ + if (_view) + _view->canvas()->paste(); +} + + +void PatchWindow::event_delete() { if (_view) diff --git a/src/libs/gui/PatchWindow.hpp b/src/libs/gui/PatchWindow.hpp index a3851dc1..2b5a90be 100644 --- a/src/libs/gui/PatchWindow.hpp +++ b/src/libs/gui/PatchWindow.hpp @@ -89,6 +89,7 @@ private: void event_save_as(); void event_upload(); void event_copy(); + void event_paste(); void event_delete(); void event_quit(); void event_destroy(); @@ -98,6 +99,7 @@ private: void event_show_properties(); void event_show_controls(); void event_show_engine(); + void event_clipboard_changed(GdkEventOwnerChange* ev); SharedPtr<PatchModel> _patch; SharedPtr<PatchView> _view; diff --git a/src/libs/gui/ThreadedLoader.cpp b/src/libs/gui/ThreadedLoader.cpp index d85d54a3..88dd4b1a 100644 --- a/src/libs/gui/ThreadedLoader.cpp +++ b/src/libs/gui/ThreadedLoader.cpp @@ -36,8 +36,18 @@ ThreadedLoader::ThreadedLoader(SharedPtr<EngineInterface> engine) { set_name("Loader"); - // FIXME: rework this so the thread is only present when it's doing something (save mem) - // and module isn't loaded until required + if (parser()) + start(); + else + cerr << "WARNING: Failed to load ingen_serialisation module, load disabled." << endl; +} + + +SharedPtr<Parser> +ThreadedLoader::parser() +{ + if (_parser) + return _parser; World* world = App::instance().world(); if (!world->serialisation_module) @@ -53,15 +63,7 @@ ThreadedLoader::ThreadedLoader(SharedPtr<EngineInterface> engine) _parser = SharedPtr<Parser>(new_parser()); } - if (_parser) - start(); - else - cerr << "WARNING: Failed to load ingen_serialisation module, load disabled." << endl; -} - - -ThreadedLoader::~ThreadedLoader() -{ + return _parser; } diff --git a/src/libs/gui/ThreadedLoader.hpp b/src/libs/gui/ThreadedLoader.hpp index dd5909fe..3cf88cf9 100644 --- a/src/libs/gui/ThreadedLoader.hpp +++ b/src/libs/gui/ThreadedLoader.hpp @@ -56,11 +56,7 @@ class ThreadedLoader : public Raul::Slave { public: ThreadedLoader(SharedPtr<EngineInterface> engine); - ~ThreadedLoader(); - // FIXME: there's a pattern here.... - // (same core interface as Loader/Serialiser) - void load_patch(bool merge, const Glib::ustring& data_base_uri, const Path& data_path, @@ -70,6 +66,8 @@ public: void save_patch(SharedPtr<PatchModel> model, const string& filename); + SharedPtr<Parser> parser(); + private: void save_patch_event(SharedPtr<PatchModel> model, const string& filename); diff --git a/src/libs/serialisation/Parser.cpp b/src/libs/serialisation/Parser.cpp index b34a3e47..c1d8c4e5 100644 --- a/src/libs/serialisation/Parser.cpp +++ b/src/libs/serialisation/Parser.cpp @@ -38,6 +38,18 @@ namespace Serialisation { #define NS_INGEN "http://drobilla.net/ns/ingen#" +Glib::ustring +Parser::uri_relative_to_base(const Glib::ustring base, const Glib::ustring uri) +{ + Glib::ustring ret; + if (uri.length() > base.length() && uri.substr(0, base.length()) == base) + ret = uri.substr(base.length()); + else + ret = uri; + return ret; +} + + /** Parse a patch from RDF into a CommonInterface (engine or client). * * @param document_uri URI of file to load objects from. @@ -56,13 +68,10 @@ Parser::parse_document( { Redland::Model model(*world->rdf_world, document_uri, document_uri); - if (object_uri == "") { - object_uri = string("<") + document_uri + ">"; + if (object_uri == document_uri || object_uri == "") cout << "[Parser] Parsing document " << object_uri << endl; - } else { - object_uri = string("<") + object_uri + ">"; + else cout << "[Parser] Parsing " << object_uri << " from " << document_uri << endl; - } return parse(world, target, model, document_uri, object_uri, parent, symbol, data);; } @@ -74,21 +83,18 @@ Parser::parse_string( Ingen::Shared::CommonInterface* target, const Glib::ustring& str, const Glib::ustring& base_uri, - Glib::ustring object_uri, + boost::optional<Glib::ustring> object_uri, boost::optional<Raul::Path> parent, boost::optional<Raul::Symbol> symbol, boost::optional<GraphObject::Variables> data) { Redland::Model model(*world->rdf_world, str.c_str(), str.length(), base_uri); - - if (object_uri == "") { - object_uri = string("<") + base_uri + ">"; - cout << "[Parser] Parsing document " << object_uri << endl; - } else { - object_uri = string("<") + object_uri + ">"; - cout << "[Parser] Parsing " << object_uri << " from string" << endl; - } - + + if (object_uri) + cout << "[Parser] Parsing " << object_uri.get() << " (base " << base_uri << ")" << endl; + else + cout << "[Parser] Parsing all objects found in string (base " << base_uri << ")" << endl; + return parse(world, target, model, base_uri, object_uri, parent, symbol, data);; } @@ -98,40 +104,59 @@ Parser::parse( Ingen::Shared::World* world, Ingen::Shared::CommonInterface* target, Redland::Model& model, - const Glib::ustring& base_uri, - Glib::ustring object_uri, + Glib::ustring base_uri, + boost::optional<Glib::ustring> object_uri, boost::optional<Raul::Path> parent, boost::optional<Raul::Symbol> symbol, boost::optional<GraphObject::Variables> data) { - Redland::Query query(*world->rdf_world, Glib::ustring( - "SELECT DISTINCT ?class WHERE { ") + object_uri + " a ?class . }"); - - Redland::Query::Results results = query.run(*world->rdf_world, model); + //if (object_uri) + // object_uri = uri_relative_to_base(base_uri, object_uri.get()); + + Glib::ustring query_str; + if (object_uri) + query_str = Glib::ustring("SELECT DISTINCT ?class WHERE { <") + object_uri.get() + "> a ?class . }"; + else + query_str = Glib::ustring("SELECT DISTINCT ?subject ?class WHERE { ?subject a ?class . }"); + + Redland::Query query(*world->rdf_world, query_str); + Redland::Query::Results results = query.run(*world->rdf_world, model, base_uri); const Redland::Node patch_class(*world->rdf_world, Redland::Node::RESOURCE, NS_INGEN "Patch"); const Redland::Node node_class(*world->rdf_world, Redland::Node::RESOURCE, NS_INGEN "Node"); const Redland::Node port_class(*world->rdf_world, Redland::Node::RESOURCE, NS_INGEN "Port"); + + const Redland::Node subject_uri(*world->rdf_world, Redland::Node::RESOURCE, + (object_uri ? object_uri.get() : "http://example.org")); + + bool ret = false; for (Redland::Query::Results::iterator i = results.begin(); i != results.end(); ++i) { + const Redland::Node subject = (object_uri ? subject_uri : (*i)["subject"]); + cout << "SUBJECT FROM RDF: " << subject.to_string() << endl; const Redland::Node rdf_class = (*i)["class"]; + cout << subject.to_c_string() << " :: " << rdf_class.to_c_string() << endl; if (rdf_class == patch_class || rdf_class == node_class || rdf_class == port_class) { - Path path = parse_path(world, model, base_uri, object_uri, parent, symbol); - bool ret = false; + Path path = parse_path(world, model, base_uri, subject.to_c_string(), parent, symbol); if (rdf_class == patch_class) { - ret = parse_patch(world, target, model, object_uri, path, data); + ret = parse_patch(world, target, model, base_uri, subject.to_c_string(), path, data); if (ret) target->set_variable(path, "ingen:document", Atom(base_uri.c_str())); } else if (rdf_class == node_class) { - cout << "NODE" << endl; + ret = parse_node(world, target, model, + base_uri, Glib::ustring("<") + subject.to_c_string() + ">", path, data); } else if (rdf_class == port_class) { cout << "PORT" << endl; } - return ret; + if (ret == false) { + cerr << "Failed to parse object " << object_uri << endl; + return ret; + } } + } - return false; + return ret; } @@ -143,19 +168,25 @@ Parser::parse_path(Ingen::Shared::World* world, boost::optional<Raul::Path>& parent, boost::optional<Raul::Symbol>& symbol) { + string subject = string("</") + uri_relative_to_base(base_uri, object_uri) + ">"; + Redland::Query query(*world->rdf_world, Glib::ustring( - "SELECT DISTINCT ?sym WHERE { ") + object_uri + " ingen:symbol ?sym }"); + "SELECT DISTINCT ?sym WHERE { ") + subject + " ingen:symbol ?sym }"); - Redland::Query::Results results = query.run(*world->rdf_world, model); + Redland::Query::Results results = query.run(*world->rdf_world, model, base_uri); if (results.size() > 0) { symbol = (*results.begin())["sym"].to_string(); } else { - const string sym = base_uri.substr(base_uri.find_last_of("/")+1); - symbol = sym.substr(0, sym.find(".")); + const string sym = object_uri.substr(base_uri.find_last_of("/")+1); + symbol = Symbol::symbolify(sym.substr(0, sym.find("."))); } - - Path ret = (parent ? (parent.get().base() + symbol.get()) : Path("/")); - cout << "Parsing " << object_uri << " from " << base_uri << " as " << ret << endl; + + Path ret; + if (base_uri == object_uri) + ret = (parent ? parent.get().base() : Path("/")); + else + ret = (parent ? parent.get().base() : Path("/")) + symbol.get(); + cout << "Parsing " << object_uri << " (base " << base_uri << ") to " << ret << endl; return ret; } @@ -165,6 +196,7 @@ Parser::parse_patch( Ingen::Shared::World* world, Ingen::Shared::CommonInterface* target, Redland::Model& model, + const Glib::ustring& base_uri, const Glib::ustring& object_uri, Raul::Path patch_path, boost::optional<GraphObject::Variables> data=boost::optional<GraphObject::Variables>()) @@ -178,14 +210,16 @@ Parser::parse_patch( if (poly_param != data.get().end() && poly_param->second.type() == Atom::INT) patch_poly = poly_param->second.get_int32(); } + + const Glib::ustring subject = ((object_uri[0] == '<') + ? object_uri : Glib::ustring("<") + object_uri + ">"); /* Get polyphony from file (mandatory if not specified in parameters) */ if (patch_poly == 0) { Redland::Query query(*world->rdf_world, Glib::ustring( - "SELECT DISTINCT ?poly WHERE {\n") + - object_uri + " ingen:polyphony ?poly\n }"); + "SELECT DISTINCT ?poly WHERE { ") + subject + " ingen:polyphony ?poly\n }"); - Redland::Query::Results results = query.run(*world->rdf_world, model); + Redland::Query::Results results = query.run(*world->rdf_world, model, base_uri); if (results.size() == 0) { cerr << "[Parser] ERROR: No polyphony found!" << endl; @@ -200,27 +234,20 @@ Parser::parse_patch( if (patch_path != "/") target->new_patch(patch_path, patch_poly); - /* Set document metadata (so File->Save doesn't prompt) - * FIXME: This needs some thinking for multiple clients... */ - - /* Load (plugin) nodes */ - Redland::Query query(*world->rdf_world, Glib::ustring( "SELECT DISTINCT ?name ?plugin ?varkey ?varval ?poly WHERE {\n") + - object_uri + " ingen:node ?node .\n" - "?node ingen:symbol ?name ;\n" - " ingen:plugin ?plugin ;\n" - " ingen:polyphonic ?poly .\n" + subject + " ingen:node ?node .\n" + "?node ingen:symbol ?name ;\n" + " ingen:plugin ?plugin ;\n" + " ingen:polyphonic ?poly .\n" "OPTIONAL { ?node ingen:variable ?variable .\n" " ?variable ingen:key ?varkey ;\n" " ingen:value ?varval .\n" " }" "}"); - Redland::Query::Results results = query.run(*world->rdf_world, model); - - map<const string, const Atom> variable; + Redland::Query::Results results = query.run(*world->rdf_world, model, base_uri); world->rdf_world->mutex().lock(); @@ -253,16 +280,14 @@ Parser::parse_patch( /* Load subpatches */ - query = Redland::Query(*world->rdf_world, Glib::ustring( "SELECT DISTINCT ?patch ?symbol WHERE {\n") + - object_uri + " ingen:node ?patch .\n" - "?patch a ingen:Patch ;\n" - " ingen:symbol ?symbol .\n" + subject + " ingen:node ?patch .\n" + "?patch a ingen:Patch ;\n" + " ingen:symbol ?symbol .\n" "}"); - results = query.run(*world->rdf_world, model); - + results = query.run(*world->rdf_world, model, base_uri); for (Redland::Query::Results::iterator i = results.begin(); i != results.end(); ++i) { const string symbol = (*i)["symbol"].to_string(); @@ -272,7 +297,7 @@ Parser::parse_patch( if (created.find(subpatch_path) == created.end()) { created.insert(subpatch_path); - parse_patch(world, target, model, Glib::ustring(object_uri + subpatch_path), subpatch_path); + parse_patch(world, target, model, base_uri, Glib::ustring(object_uri + subpatch_path), subpatch_path); } } @@ -280,19 +305,17 @@ Parser::parse_patch( /* Set node port control values */ - query = Redland::Query(*world->rdf_world, Glib::ustring( "SELECT DISTINCT ?nodename ?portname ?portval WHERE {\n") + - object_uri + " ingen:node ?node .\n" - "?node ingen:symbol ?nodename ;\n" - " ingen:port ?port .\n" - "?port ingen:symbol ?portname ;\n" - " ingen:value ?portval .\n" + subject + " ingen:node ?node .\n" + "?node ingen:symbol ?nodename ;\n" + " ingen:port ?port .\n" + "?port ingen:symbol ?portname ;\n" + " ingen:value ?portval .\n" "FILTER ( datatype(?portval) = xsd:decimal )\n" - "}\n"); - - results = query.run(*world->rdf_world, model); + "}"); + results = query.run(*world->rdf_world, model, base_uri); for (Redland::Query::Results::iterator i = results.begin(); i != results.end(); ++i) { const string node_name = (*i)["nodename"].to_string(); @@ -307,13 +330,12 @@ Parser::parse_patch( /* Load this patch's ports */ - query = Redland::Query(*world->rdf_world, Glib::ustring( "SELECT DISTINCT ?port ?type ?name ?datatype ?varkey ?varval ?portval WHERE {\n") + - object_uri + " ingen:port ?port .\n" - "?port a ?type ;\n" - " a ?datatype ;\n" - " ingen:symbol ?name .\n" + subject + " ingen:port ?port .\n" + "?port a ?type ;\n" + " a ?datatype ;\n" + " ingen:symbol ?name .\n" " FILTER (?type != ?datatype && ((?type = ingen:InputPort) || (?type = ingen:OutputPort)))\n" "OPTIONAL { ?port ingen:value ?portval . \n" " FILTER ( datatype(?portval) = xsd:decimal ) }\n" @@ -323,8 +345,7 @@ Parser::parse_patch( " }" "}"); - results = query.run(*world->rdf_world, model); - + results = query.run(*world->rdf_world, model, base_uri); for (Redland::Query::Results::iterator i = results.begin(); i != results.end(); ++i) { const string name = (*i)["name"].to_string(); const string type = world->rdf_world->qualify((*i)["type"].to_string()); @@ -354,22 +375,20 @@ Parser::parse_patch( /* Node -> Node connections */ - query = Redland::Query(*world->rdf_world, Glib::ustring( "SELECT DISTINCT ?srcnodename ?srcname ?dstnodename ?dstname WHERE {\n") + - object_uri + "ingen:node ?srcnode ;\n" - " ingen:node ?dstnode .\n" - "?srcnode ingen:port ?src ;\n" - " ingen:symbol ?srcnodename .\n" - "?dstnode ingen:port ?dst ;\n" - " ingen:symbol ?dstnodename .\n" - "?src ingen:symbol ?srcname .\n" - "?dst ingen:connectedTo ?src ;\n" - " ingen:symbol ?dstname .\n" - "}\n"); - - results = query.run(*world->rdf_world, model); + subject + "ingen:node ?srcnode ;\n" + " ingen:node ?dstnode .\n" + "?srcnode ingen:port ?src ;\n" + " ingen:symbol ?srcnodename .\n" + "?dstnode ingen:port ?dst ;\n" + " ingen:symbol ?dstnodename .\n" + "?src ingen:symbol ?srcname .\n" + "?dst ingen:connectedTo ?src ;\n" + " ingen:symbol ?dstname .\n" + "}"); + results = query.run(*world->rdf_world, model, base_uri); for (Redland::Query::Results::iterator i = results.begin(); i != results.end(); ++i) { Path src_node = patch_path.base() + Path::nameify((*i)["srcnodename"].to_string()); Path src_port = src_node.base() + Path::nameify((*i)["srcname"].to_string()); @@ -383,20 +402,18 @@ Parser::parse_patch( /* This Patch -> Node connections */ - query = Redland::Query(*world->rdf_world, Glib::ustring( "SELECT DISTINCT ?srcname ?dstnodename ?dstname WHERE {\n") + - object_uri + " ingen:port ?src ;\n" - " ingen:node ?dstnode .\n" - "?dstnode ingen:port ?dst ;\n" - " ingen:symbol ?dstnodename .\n" - "?dst ingen:connectedTo ?src ;\n" - " ingen:symbol ?dstname .\n" - "?src ingen:symbol ?srcname .\n" - "}\n"); - - results = query.run(*world->rdf_world, model); + subject + " ingen:port ?src ;\n" + " ingen:node ?dstnode .\n" + "?dstnode ingen:port ?dst ;\n" + " ingen:symbol ?dstnodename .\n" + "?dst ingen:connectedTo ?src ;\n" + " ingen:symbol ?dstname .\n" + "?src ingen:symbol ?srcname .\n" + "}"); + results = query.run(*world->rdf_world, model, base_uri); for (Redland::Query::Results::iterator i = results.begin(); i != results.end(); ++i) { Path src_port = patch_path.base() + Path::nameify((*i)["srcname"].to_string()); Path dst_node = patch_path.base() + Path::nameify((*i)["dstnodename"].to_string()); @@ -409,20 +426,18 @@ Parser::parse_patch( /* Node -> This Patch connections */ - query = Redland::Query(*world->rdf_world, Glib::ustring( "SELECT DISTINCT ?srcnodename ?srcname ?dstname WHERE {\n") + - object_uri + " ingen:port ?dst ;\n" - " ingen:node ?srcnode .\n" - "?srcnode ingen:port ?src ;\n" - " ingen:symbol ?srcnodename .\n" - "?dst ingen:connectedTo ?src ;\n" - " ingen:symbol ?dstname .\n" - "?src ingen:symbol ?srcname .\n" - "}\n"); - - results = query.run(*world->rdf_world, model); + subject + " ingen:port ?dst ;\n" + " ingen:node ?srcnode .\n" + "?srcnode ingen:port ?src ;\n" + " ingen:symbol ?srcnodename .\n" + "?dst ingen:connectedTo ?src ;\n" + " ingen:symbol ?dstname .\n" + "?src ingen:symbol ?srcname .\n" + "}"); + results = query.run(*world->rdf_world, model, base_uri); for (Redland::Query::Results::iterator i = results.begin(); i != results.end(); ++i) { Path dst_port = patch_path.base() + Path::nameify((*i)["dstname"].to_string()); Path src_node = patch_path.base() + Path::nameify((*i)["srcnodename"].to_string()); @@ -435,18 +450,16 @@ Parser::parse_patch( /* This Patch -> This Patch connections */ - query = Redland::Query(*world->rdf_world, Glib::ustring( "SELECT DISTINCT ?srcname ?dstname WHERE {\n") + - object_uri + " ingen:port ?src ;\n" - " ingen:port ?dst .\n" - "?dst ingen:connectedTo ?src ;\n" - " ingen:symbol ?dstname .\n" - "?src ingen:symbol ?srcname .\n" - "}\n"); - - results = query.run(*world->rdf_world, model); + subject + " ingen:port ?src ;\n" + " ingen:port ?dst .\n" + "?dst ingen:connectedTo ?src ;\n" + " ingen:symbol ?dstname .\n" + "?src ingen:symbol ?srcname .\n" + "}"); + results = query.run(*world->rdf_world, model, base_uri); for (Redland::Query::Results::iterator i = results.begin(); i != results.end(); ++i) { Path src_port = patch_path.base() + Path::nameify((*i)["srcname"].to_string()); Path dst_port = patch_path.base() + Path::nameify((*i)["dstname"].to_string()); @@ -456,58 +469,104 @@ Parser::parse_patch( target->connect(src_port, dst_port); } + parse_variables(world, target, model, base_uri, subject, patch_path, data); - /* Load variables */ - + /* Enable */ query = Redland::Query(*world->rdf_world, Glib::ustring( - "SELECT DISTINCT ?varkey ?varval WHERE {\n") + - object_uri + " ingen:variable ?variable .\n" - "?variable ingen:key ?varkey ;\n" - " ingen:value ?varval .\n" - "}"); - - results = query.run(*world->rdf_world, model); + "SELECT DISTINCT ?enabled WHERE { ") + subject + " ingen:enabled ?enabled }"); + results = query.run(*world->rdf_world, model, base_uri); for (Redland::Query::Results::iterator i = results.begin(); i != results.end(); ++i) { + Redland::Node enabled_node = (*i)["enabled"]; - const string key = world->rdf_world->prefixes().qualify(string((*i)["varkey"])); - Redland::Node val_node = (*i)["varval"]; - - if (key != "") - target->set_variable(patch_path, key, AtomRDF::node_to_atom(val_node)); + if (enabled_node.is_bool() && enabled_node) { + target->set_property(patch_path, "ingen:enabled", (bool)true); + break; + } else { + cerr << "WARNING: Unknown type for property ingen:enabled" << endl; + } } + return true; +} - // Set passed variables last to override any loaded values - if (data) - for (GraphObject::Variables::const_iterator i = data.get().begin(); i != data.get().end(); ++i) - target->set_variable(patch_path, i->first, i->second); +bool +Parser::parse_node( + Ingen::Shared::World* world, + Ingen::Shared::CommonInterface* target, + Redland::Model& model, + const Glib::ustring& base_uri, + Glib::ustring subject, + Raul::Path path, + boost::optional<GraphObject::Variables> data=boost::optional<GraphObject::Variables>()) +{ + /* Get plugin */ + Redland::Query query(*world->rdf_world, Glib::ustring( + "SELECT DISTINCT ?plug WHERE { ") + subject + " ingen:plugin ?plug }"); - /* Enable */ + Redland::Query::Results results = query.run(*world->rdf_world, model, base_uri); - query = Redland::Query(*world->rdf_world, Glib::ustring( - "SELECT DISTINCT ?enabled WHERE {\n") + - object_uri + " ingen:enabled ?enabled .\n" - "}"); + if (results.size() == 0) { + cerr << "[Parser] ERROR: Node missing mandatory ingen:plugin property" << endl; + return false; + } + + for (Redland::Query::Results::iterator i = results.begin(); i != results.end(); ++i) { + Redland::Node s_node = (*i)["s"]; + Redland::Node plug_node = (*i)["plug"]; + cout << s_node.to_c_string() << " :: " << plug_node.to_c_string() << endl; + } - results = query.run(*world->rdf_world, model); + const Redland::Node& plugin_node = (*results.begin())["plug"]; + if (plugin_node.type() != Redland::Node::RESOURCE) { + cerr << "[Parser] ERROR: node's ingen:plugin property is not a resource" << endl; + return false; + } - for (Redland::Query::Results::iterator i = results.begin(); i != results.end(); ++i) { + target->new_node(path, plugin_node.to_c_string()); + parse_variables(world, target, model, base_uri, subject, path, data); - Redland::Node enabled_node = (*i)["enabled"]; + return true; +} - if (enabled_node.is_bool() && enabled_node) { - target->set_property(patch_path, "ingen:enabled", (bool)true); - break; - } else { - cerr << "WARNING: Unknown type for property ingen:enabled" << endl; - } + + +bool +Parser::parse_variables( + Ingen::Shared::World* world, + Ingen::Shared::CommonInterface* target, + Redland::Model& model, + const Glib::ustring& base_uri, + const Glib::ustring& subject, + Raul::Path path, + boost::optional<GraphObject::Variables> data=boost::optional<GraphObject::Variables>()) +{ + /* Parse variables */ + Redland::Query query = Redland::Query(*world->rdf_world, Glib::ustring( + "SELECT DISTINCT ?varkey ?varval WHERE {\n") + + subject + " ingen:variable ?variable .\n" + "?variable ingen:key ?varkey ;\n" + " ingen:value ?varval .\n" + "}"); + + Redland::Query::Results results = query.run(*world->rdf_world, model, base_uri); + for (Redland::Query::Results::iterator i = results.begin(); i != results.end(); ++i) { + const string key = world->rdf_world->prefixes().qualify(string((*i)["varkey"])); + Redland::Node val_node = (*i)["varval"]; + if (key != "") + target->set_variable(path, key, AtomRDF::node_to_atom(val_node)); } + // Set passed variables last to override any loaded values + if (data) + for (GraphObject::Variables::const_iterator i = data.get().begin(); i != data.get().end(); ++i) + target->set_variable(path, i->first, i->second); + return true; } + } // namespace Serialisation } // namespace Ingen diff --git a/src/libs/serialisation/Parser.hpp b/src/libs/serialisation/Parser.hpp index 2aaf3bfb..4ee94d46 100644 --- a/src/libs/serialisation/Parser.hpp +++ b/src/libs/serialisation/Parser.hpp @@ -54,18 +54,21 @@ public: Shared::CommonInterface* target, const Glib::ustring& str, const Glib::ustring& base_uri, - Glib::ustring object_uri, + boost::optional<Glib::ustring> object_uri=boost::optional<Glib::ustring>(), boost::optional<Raul::Path> parent=boost::optional<Raul::Path>(), boost::optional<Raul::Symbol> symbol=boost::optional<Raul::Symbol>(), boost::optional<GraphObject::Variables> data=boost::optional<GraphObject::Variables>()); private: + + Glib::ustring uri_relative_to_base(const Glib::ustring base, const Glib::ustring uri); + bool parse( Ingen::Shared::World* world, Shared::CommonInterface* target, Redland::Model& model, - const Glib::ustring& base_uri, - Glib::ustring object_uri, + Glib::ustring base_uri, + boost::optional<Glib::ustring> object_uri=boost::optional<Glib::ustring>(), boost::optional<Raul::Path> parent=boost::optional<Raul::Path>(), boost::optional<Raul::Symbol> symbol=boost::optional<Raul::Symbol>(), boost::optional<GraphObject::Variables> data=boost::optional<GraphObject::Variables>()); @@ -82,9 +85,28 @@ private: Ingen::Shared::World* world, Ingen::Shared::CommonInterface* target, Redland::Model& model, + const Glib::ustring& base_uri, const Glib::ustring& object_uri, Raul::Path path, boost::optional<GraphObject::Variables> data); + + bool parse_node( + Ingen::Shared::World* world, + Ingen::Shared::CommonInterface* target, + Redland::Model& model, + const Glib::ustring& base_uri, + Glib::ustring subject, + Raul::Path path, + boost::optional<GraphObject::Variables> data); + + bool parse_variables( + Ingen::Shared::World* world, + Ingen::Shared::CommonInterface* target, + Redland::Model& model, + const Glib::ustring& base_uri, + const Glib::ustring& subject, + Raul::Path path, + boost::optional<GraphObject::Variables> data); }; diff --git a/src/libs/serialisation/Serialiser.cpp b/src/libs/serialisation/Serialiser.cpp index a56d6add..8f0241e0 100644 --- a/src/libs/serialisation/Serialiser.cpp +++ b/src/libs/serialisation/Serialiser.cpp @@ -380,6 +380,11 @@ Serialiser::serialise_node(SharedPtr<Shared::Node> node, const Redland::Node& no Redland::Node(_model->world(), Redland::Node::LITERAL, node->path().name())); _model->add_statement( + plugin_id, + "rdf:type", + Redland::Node(_model->world(), Redland::Node::RESOURCE, "ingen:Plugin")); + + _model->add_statement( node_id, "ingen:plugin", plugin_id); diff --git a/src/libs/shared/Builder.cpp b/src/libs/shared/Builder.cpp new file mode 100644 index 00000000..062afc63 --- /dev/null +++ b/src/libs/shared/Builder.cpp @@ -0,0 +1,88 @@ +/* This file is part of Ingen. + * Copyright (C) 2008 Dave Robillard <http://drobilla.net> + * + * Ingen 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. + * + * Ingen 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 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., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "Builder.hpp" +#include "common/interface/CommonInterface.hpp" +#include "common/interface/Patch.hpp" +#include "common/interface/Node.hpp" +#include "common/interface/Port.hpp" +#include "common/interface/Connection.hpp" +#include "common/interface/Plugin.hpp" +#include <iostream> +using namespace std; + +namespace Ingen { +namespace Shared { + + +Builder::Builder(CommonInterface& interface) + : _interface(interface) +{ +} + + +void +Builder::build(SharedPtr<const GraphObject> object) +{ + cout << "BUILDING: " << object->path() << endl; + + SharedPtr<const Patch> patch = PtrCast<const Patch>(object); + if (patch) { + if (patch->path() != "/") + _interface.new_patch(patch->path() + "_copy", patch->internal_polyphony()); + build_object(object); + for (Patch::Connections::const_iterator i = patch->connections().begin(); + i != patch->connections().end(); ++i) + _interface.connect((*i)->src_port_path(), (*i)->dst_port_path()); + return; + } + + SharedPtr<const Node> node = PtrCast<const Node>(object); + if (node) { + _interface.new_node(node->path() + "_copy", node->plugin()->uri()); + build_object(object); + return; + } + + SharedPtr<const Port> port = PtrCast<const Port>(object); + if (port) { + _interface.new_port(port->path() + "_copy", port->index(), port->type().uri(), !port->is_input()); + build_object(object); + return; + } +} + + +void +Builder::build_object(SharedPtr<const GraphObject> object) +{ + for (GraphObject::Variables::const_iterator i = object->variables().begin(); + i != object->variables().end(); ++i) { + cout << "SETTING " << object->path() << " . " << i->first << endl; + _interface.set_variable(object->path() + "_copy", i->first, i->second); + } + + for (GraphObject::Properties::const_iterator i = object->properties().begin(); + i != object->properties().end(); ++i) { + cout << "SETTING " << object->path() << " . " << i->first << endl; + _interface.set_property(object->path() + "_copy", i->first, i->second); + } +} + + +} // namespace Shared +} // namespace Ingen diff --git a/src/libs/shared/Builder.hpp b/src/libs/shared/Builder.hpp new file mode 100644 index 00000000..01d3b7e5 --- /dev/null +++ b/src/libs/shared/Builder.hpp @@ -0,0 +1,53 @@ +/* This file is part of Ingen. + * Copyright (C) 2008 Dave Robillard <http://drobilla.net> + * + * Ingen 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. + * + * Ingen 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 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., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef BUILDER_H +#define BUILDER_H + +#include <raul/SharedPtr.hpp> + +namespace Ingen { +namespace Shared { + +class GraphObject; +class CommonInterface; + + +/** Wrapper for CommonInterface to create existing objects/models. + * + * \ingroup interface + */ +class Builder +{ +public: + Builder(CommonInterface& interface); + virtual ~Builder() {} + + void build(SharedPtr<const GraphObject> object); + +private: + void build_object(SharedPtr<const GraphObject> object); + + CommonInterface& _interface; +}; + + +} // namespace Shared +} // namespace Ingen + +#endif // BUILDER_H + diff --git a/src/libs/shared/Makefile.am b/src/libs/shared/Makefile.am index 9e52923a..fcb261c8 100644 --- a/src/libs/shared/Makefile.am +++ b/src/libs/shared/Makefile.am @@ -8,6 +8,8 @@ libingen_shared_la_CXXFLAGS = \ @SLV2_CFLAGS@ libingen_shared_la_SOURCES = \ + Builder.cpp \ + Builder.hpp \ LV2Features.cpp \ LV2Features.hpp \ LV2URIMap.cpp \ diff --git a/src/libs/shared/Store.cpp b/src/libs/shared/Store.cpp index 88fb9cb8..f77be312 100644 --- a/src/libs/shared/Store.cpp +++ b/src/libs/shared/Store.cpp @@ -17,6 +17,8 @@ #include <raul/PathTable.hpp> #include <raul/TableImpl.hpp> +#include "common/interface/Node.hpp" +#include "common/interface/Port.hpp" #include "Store.hpp" using namespace std; @@ -26,6 +28,25 @@ namespace Ingen { namespace Shared { +void +Store::add(GraphObject* o) +{ + if (find(o->path()) != end()) { + cerr << "[Store] ERROR: Attempt to add duplicate object " << o->path() << endl; + return; + } + + insert(make_pair(o->path(), o)); + + Node* node = dynamic_cast<Node*>(o); + if (node) { + for (uint32_t i=0; i < node->num_ports(); ++i) { + add(node->port(i)); + } + } +} + + Store::const_iterator Store::children_begin(SharedPtr<Shared::GraphObject> o) const { diff --git a/src/libs/shared/Store.hpp b/src/libs/shared/Store.hpp index f0a89024..573c4837 100644 --- a/src/libs/shared/Store.hpp +++ b/src/libs/shared/Store.hpp @@ -31,8 +31,10 @@ namespace Shared { class Store : public Raul::PathTable< SharedPtr<Shared::GraphObject> > { public: - virtual void add(GraphObject* o) = 0; + virtual ~Store() {} + virtual void add(Shared::GraphObject* o); + typedef Raul::Table< Raul::Path, SharedPtr<Shared::GraphObject> > Objects; const_iterator children_begin(SharedPtr<Shared::GraphObject> o) const; |