From af759288a2517f9acf4c28f79d9c43be0086a221 Mon Sep 17 00:00:00 2001 From: David Robillard Date: Mon, 18 Aug 2008 03:49:35 +0000 Subject: More copy/paste and serialisation work. Don't die on invalid path for set_property and set_variable (return error to client). Working paste to subpatches, paste of connected patch ports and modules. git-svn-id: http://svn.drobilla.net/lad/ingen@1428 a436a847-0d15-0410-975c-d299462d15a1 --- src/libs/engine/OSCEngineReceiver.cpp | 2 +- src/libs/engine/events/SetMetadataEvent.cpp | 12 +++- src/libs/engine/events/SetMetadataEvent.hpp | 2 + src/libs/gui/App.cpp | 2 + src/libs/gui/App.hpp | 11 ++-- src/libs/gui/NodeModule.cpp | 3 +- src/libs/gui/PatchCanvas.cpp | 30 ++++++---- src/libs/gui/PatchPortModule.cpp | 3 +- src/libs/serialisation/Parser.cpp | 85 +++++++++++++++-------------- src/libs/serialisation/Parser.hpp | 8 --- src/libs/shared/Builder.cpp | 39 ++++++++----- src/libs/shared/Builder.hpp | 8 ++- src/libs/shared/ClashAvoider.cpp | 45 +++++++++++---- src/libs/shared/ClashAvoider.hpp | 12 ++-- src/libs/shared/Store.cpp | 5 +- src/libs/shared/Store.hpp | 3 +- 16 files changed, 166 insertions(+), 104 deletions(-) (limited to 'src') diff --git a/src/libs/engine/OSCEngineReceiver.cpp b/src/libs/engine/OSCEngineReceiver.cpp index b9e2a70d..1078a86a 100644 --- a/src/libs/engine/OSCEngineReceiver.cpp +++ b/src/libs/engine/OSCEngineReceiver.cpp @@ -70,7 +70,7 @@ OSCEngineReceiver::OSCEngineReceiver(Engine& engine, size_t queue_size, uint16_t } // For debugging, print all incoming OSC messages - //lo_server_add_method(_server, NULL, NULL, generic_cb, NULL); + lo_server_add_method(_server, NULL, NULL, generic_cb, NULL); // Set response address for this message. // It's important this is first and returns nonzero. diff --git a/src/libs/engine/events/SetMetadataEvent.cpp b/src/libs/engine/events/SetMetadataEvent.cpp index b4ee00ff..341fa06c 100644 --- a/src/libs/engine/events/SetMetadataEvent.cpp +++ b/src/libs/engine/events/SetMetadataEvent.cpp @@ -17,6 +17,7 @@ #include "SetMetadataEvent.hpp" #include +#include #include "Responder.hpp" #include "Engine.hpp" #include "ClientBroadcaster.hpp" @@ -37,6 +38,7 @@ SetMetadataEvent::SetMetadataEvent( const string& key, const Atom& value) : QueuedEvent(engine, responder, timestamp) + , _error(NO_ERROR) , _property(property) , _path(path) , _key(key) @@ -49,6 +51,12 @@ SetMetadataEvent::SetMetadataEvent( void SetMetadataEvent::pre_process() { + if (!Path::is_valid(_path)) { + _error = INVALID_PATH; + QueuedEvent::pre_process(); + return; + } + _object = _engine.engine_store()->find_object(_path); if (_object == NULL) { QueuedEvent::pre_process(); @@ -75,7 +83,9 @@ SetMetadataEvent::execute(ProcessContext& context) void SetMetadataEvent::post_process() { - if (_object == NULL) { + if (_error == INVALID_PATH) { + _responder->respond_error((boost::format("Invalid path %1% setting %2%") % _path % _key).str()); + } else if (_object == NULL) { string msg = "Unable to find object "; msg += _path; _responder->respond_error(msg); diff --git a/src/libs/engine/events/SetMetadataEvent.hpp b/src/libs/engine/events/SetMetadataEvent.hpp index 9707ce56..f6f8d3c3 100644 --- a/src/libs/engine/events/SetMetadataEvent.hpp +++ b/src/libs/engine/events/SetMetadataEvent.hpp @@ -49,6 +49,8 @@ public: void post_process(); private: + enum { NO_ERROR, INVALID_PATH } _error; + bool _property; string _path; string _key; diff --git a/src/libs/gui/App.cpp b/src/libs/gui/App.cpp index 34f04f35..408b7503 100644 --- a/src/libs/gui/App.cpp +++ b/src/libs/gui/App.cpp @@ -339,7 +339,9 @@ App::gtk_main_iteration() if (_world->local_engine) { _world->local_engine->main_iteration(); } else { + _enable_signal = false; _client->emit_signals(); + _enable_signal = true; } animate(); diff --git a/src/libs/gui/App.hpp b/src/libs/gui/App.hpp index a13259ad..04666285 100644 --- a/src/libs/gui/App.hpp +++ b/src/libs/gui/App.hpp @@ -91,9 +91,13 @@ public: bool gtk_main_iteration(); void show_about(); void quit(); - + void port_activity(Port* port); + bool signal() const { return _enable_signal; } + void enable_signals() { _enable_signal = true; } + void disable_signals() { _enable_signal = false; } + ConnectWindow* connect_window() const { return _connect_window; } MessagesWindow* messages_dialog() const { return _messages_window; } PatchTreeWindow* patch_tree() const { return _patch_tree_window; } @@ -157,11 +161,6 @@ protected: typedef std::map ActivityPorts; ActivityPorts _activity_ports; - /** Used to avoid feedback loops with (eg) process checkbutton - * FIXME: This should probably be implemented globally: - * disable all command sending while handling events to avoid feedback - * issues with widget event callbacks? This same pattern is duplicated - * too much... */ bool _enable_signal; }; diff --git a/src/libs/gui/NodeModule.cpp b/src/libs/gui/NodeModule.cpp index c38a898b..207bdd18 100644 --- a/src/libs/gui/NodeModule.cpp +++ b/src/libs/gui/NodeModule.cpp @@ -333,7 +333,8 @@ NodeModule::set_selected(bool b) { if (b != selected()) { Module::set_selected(b); - App::instance().engine()->set_property(_node->path(), "ingen:selected", b); + if (App::instance().signal()) + App::instance().engine()->set_property(_node->path(), "ingen:selected", b); } } diff --git a/src/libs/gui/PatchCanvas.cpp b/src/libs/gui/PatchCanvas.cpp index 46cde832..135a28c8 100644 --- a/src/libs/gui/PatchCanvas.cpp +++ b/src/libs/gui/PatchCanvas.cpp @@ -584,26 +584,36 @@ PatchCanvas::paste() Builder builder(*App::instance().engine()); ClientStore clipboard; - ClashAvoider avoider(*App::instance().store().get(), clipboard); - clipboard.new_patch("/", _patch->poly()); clipboard.set_plugins(App::instance().store()->plugins()); - parser->parse_string(App::instance().world(), &avoider, str, "/"); + clipboard.new_patch("/", _patch->poly()); + + ClashAvoider avoider(*App::instance().store().get(), _patch->path(), clipboard); + //parser->parse_string(App::instance().world(), &avoider, str, _patch->path().base()); + parser->parse_string(App::instance().world(), &avoider, str, "/", + boost::optional(), _patch->path()); for (Store::iterator i = clipboard.begin(); i != clipboard.end(); ++i) { - if (i->first == "/") + if (_patch->path() == "/" && i->first == "/") { + //cout << "SKIPPING ROOT " << _patch->path() << " :: " << i->first << endl; + continue; + } else if (i->first.parent() != "/") { + //cout << "SKIPPING NON ROOTED OBJECT " << i->first << endl; continue; + } 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; - GraphObject::Properties::iterator s = i->second->properties().find("ingen:selected"); - if (s != i->second->properties().end()) - s->second = true; - else - i->second->properties().insert(make_pair("ingen:selected", true)); - builder.build(i->second); + if (i->first.parent() == "/") { + GraphObject::Properties::iterator s = i->second->properties().find("ingen:selected"); + if (s != i->second->properties().end()) + s->second = true; + else + i->second->properties().insert(make_pair("ingen:selected", true)); + } + builder.build(_patch->path(), i->second); } for (ClientStore::ConnectionRecords::const_iterator i = clipboard.connection_records().begin(); diff --git a/src/libs/gui/PatchPortModule.cpp b/src/libs/gui/PatchPortModule.cpp index b23ac5c7..76bc8812 100644 --- a/src/libs/gui/PatchPortModule.cpp +++ b/src/libs/gui/PatchPortModule.cpp @@ -147,7 +147,8 @@ PatchPortModule::set_selected(bool b) { if (b != selected()) { Module::set_selected(b); - App::instance().engine()->set_property(_port->path(), "ingen:selected", b); + if (App::instance().signal()) + App::instance().engine()->set_property(_port->path(), "ingen:selected", b); } } diff --git a/src/libs/serialisation/Parser.cpp b/src/libs/serialisation/Parser.cpp index 9ddfb601..6d90499a 100644 --- a/src/libs/serialisation/Parser.cpp +++ b/src/libs/serialisation/Parser.cpp @@ -70,9 +70,9 @@ Parser::parse_document( Redland::Model model(*world->rdf_world, document_uri, document_uri); if (object_uri == document_uri || object_uri == "") - cout << "[Parser] Parsing document " << object_uri << endl; + cout << "Parsing document " << object_uri << " (base " << document_uri << ")" << endl; else - cout << "[Parser] Parsing " << object_uri << " from " << document_uri << endl; + cout << "Parsing " << object_uri << " from " << document_uri << endl; return parse(world, target, model, document_uri, object_uri, parent, symbol, data);; } @@ -92,11 +92,11 @@ Parser::parse_string( Redland::Model model(*world->rdf_world, str.c_str(), str.length(), base_uri); if (object_uri) - cout << "[Parser] Parsing " << object_uri.get() << " (base " << base_uri << ")" << endl; + cout << "Parsing " << object_uri.get() << " (base " << base_uri << ")" << endl; else - cout << "[Parser] Parsing all objects found in string (base " << base_uri << ")" << endl; - - bool ret = parse(world, target, model, base_uri, object_uri, parent, symbol, data);; + cout << "Parsing all objects found in string (base " << base_uri << ")" << endl; + + bool ret = parse(world, target, model, base_uri, object_uri, parent, symbol, data); if (ret) { const Glib::ustring subject = Glib::ustring("<") + base_uri + Glib::ustring(">"); parse_connections(world, target, model, base_uri, subject, parent ? parent.get() : "/"); @@ -117,9 +117,6 @@ Parser::parse( boost::optional symbol, boost::optional data) { - //if (object_uri) - // object_uri = uri_relative_to_base(base_uri, object_uri.get()); - const Redland::Node::Type res = Redland::Node::RESOURCE; Glib::ustring query_str; if (object_uri) @@ -143,9 +140,29 @@ Parser::parse( for (Redland::Query::Results::iterator i = results.begin(); i != results.end(); ++i) { const Redland::Node subject = (object_uri ? subject_uri : (*i)["subject"]); const Redland::Node rdf_class = (*i)["class"]; + if (!object_uri) { + std::string path_str = "/" + uri_relative_to_base(base_uri, subject.to_c_string()); + if (Path(path_str).parent() != "/") + continue; + } + if (rdf_class == patch_class || rdf_class == node_class || rdf_class == in_port_class || rdf_class == out_port_class) { - Path path = parse_path(world, model, base_uri, subject.to_c_string(), parent, symbol); + Raul::Path path("/"); + if (base_uri != subject.to_c_string()) { + string path_str = string("/") + (string)uri_relative_to_base( + base_uri, subject.to_c_string()); + if (Path::is_valid(path_str)) { + path = path_str; + } else { + cerr << "[Parser] ERROR: Invalid path " << path << endl; + continue; + } + } + + if (path.parent() != "/") + continue; + if (rdf_class == patch_class) { ret = parse_patch(world, target, model, base_uri, subject.to_c_string(), path, data); if (ret) @@ -169,37 +186,6 @@ Parser::parse( } -Path -Parser::parse_path(Ingen::Shared::World* world, - Redland::Model& model, - const Glib::ustring& base_uri, - const Glib::ustring& object_uri, - boost::optional& parent, - boost::optional& symbol) -{ - string subject = string(""; - - Redland::Query query(*world->rdf_world, Glib::ustring( - "SELECT DISTINCT ?sym WHERE { ") + subject + " ingen:symbol ?sym }"); - - 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 = object_uri.substr(base_uri.find_last_of("/")+1); - symbol = Symbol::symbolify(sym.substr(0, sym.find("."))); - } - - 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; -} - - bool Parser::parse_patch( Ingen::Shared::World* world, @@ -518,7 +504,7 @@ Parser::parse_variables( Raul::Path path, boost::optional data=boost::optional()) { - Redland::Query query = Redland::Query(*world->rdf_world, Glib::ustring( + Redland::Query query(*world->rdf_world, Glib::ustring( "SELECT DISTINCT ?varkey ?varval WHERE {\n") + subject + " ingen:variable ?variable .\n" "?variable ingen:key ?varkey ;\n" @@ -532,6 +518,21 @@ Parser::parse_variables( if (key != "") target->set_variable(path, key, AtomRDF::node_to_atom(val_node)); } + + query = Redland::Query(*world->rdf_world, Glib::ustring( + "SELECT DISTINCT ?key ?val WHERE {\n") + + subject + " ingen:property ?property .\n" + "?property ingen:key ?key ;\n" + " ingen:value ?val .\n" + "}"); + + 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)["key"])); + const Redland::Node& val_node = (*i)["val"]; + if (key != "") + target->set_property(path, key, AtomRDF::node_to_atom(val_node)); + } // Set passed variables last to override any loaded values if (data) diff --git a/src/libs/serialisation/Parser.hpp b/src/libs/serialisation/Parser.hpp index 3a99b7da..fd5fdece 100644 --- a/src/libs/serialisation/Parser.hpp +++ b/src/libs/serialisation/Parser.hpp @@ -73,14 +73,6 @@ private: boost::optional symbol=boost::optional(), boost::optional data=boost::optional()); - Raul::Path parse_path( - Ingen::Shared::World* world, - Redland::Model& model, - const Glib::ustring& base_uri, - const Glib::ustring& object_uri, - boost::optional& parent, - boost::optional& symbol); - bool parse_patch( Ingen::Shared::World* world, Ingen::Shared::CommonInterface* target, diff --git a/src/libs/shared/Builder.cpp b/src/libs/shared/Builder.cpp index bc8fb21c..7065e0b4 100644 --- a/src/libs/shared/Builder.cpp +++ b/src/libs/shared/Builder.cpp @@ -36,46 +36,59 @@ Builder::Builder(CommonInterface& interface) void -Builder::build(SharedPtr object) +Builder::build(const Raul::Path& prefix, SharedPtr object) { SharedPtr patch = PtrCast(object); if (patch) { - if (patch->path() != "/") - _interface.new_patch(patch->path(), patch->internal_polyphony()); - build_object(object); + if (object->path() != "/") { + const std::string path_str = prefix + object->path(); + //cout << "BUILDING PATCH " << path_str << endl; + _interface.new_patch(path_str, patch->internal_polyphony()); + } + + build_object(prefix, 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()); + _interface.connect(prefix.base() + (*i)->src_port_path().substr(1), + prefix.base() + (*i)->dst_port_path().substr(1)); } return; } SharedPtr node = PtrCast(object); if (node) { - _interface.new_node(node->path(), node->plugin()->uri()); - build_object(object); + Raul::Path path = prefix.base() + node->path().substr(1); + //cout << "BUILDING NODE " << path << endl; + _interface.new_node(path, node->plugin()->uri()); + build_object(prefix, object); return; } SharedPtr port = PtrCast(object); if (port) { - _interface.new_port(port->path(), port->index(), port->type().uri(), !port->is_input()); - build_object(object); + Raul::Path path = prefix.base() + port->path().substr(1); + //cout << "BUILDING PORT " << path << endl; + _interface.new_port(path, port->index(), port->type().uri(), !port->is_input()); + build_object(prefix, object); return; } } void -Builder::build_object(SharedPtr object) +Builder::build_object(const Raul::Path& prefix, SharedPtr object) { for (GraphObject::Variables::const_iterator i = object->variables().begin(); i != object->variables().end(); ++i) - _interface.set_variable(object->path(), i->first, i->second); + _interface.set_variable(prefix.base() + object->path().substr(1), i->first, i->second); for (GraphObject::Properties::const_iterator i = object->properties().begin(); - i != object->properties().end(); ++i) - _interface.set_property(object->path(), i->first, i->second); + i != object->properties().end(); ++i) { + if (object->path() == "/") + continue; + string path_str = prefix.base() + object->path().substr(1); + _interface.set_property(prefix.base() + object->path().substr(1), i->first, i->second); + } } diff --git a/src/libs/shared/Builder.hpp b/src/libs/shared/Builder.hpp index 01d3b7e5..a980bad2 100644 --- a/src/libs/shared/Builder.hpp +++ b/src/libs/shared/Builder.hpp @@ -20,6 +20,8 @@ #include +namespace Raul { class Path; } + namespace Ingen { namespace Shared { @@ -37,10 +39,12 @@ public: Builder(CommonInterface& interface); virtual ~Builder() {} - void build(SharedPtr object); + void build(const Raul::Path& prefix, + SharedPtr object); private: - void build_object(SharedPtr object); + void build_object(const Raul::Path& prefix, + SharedPtr object); CommonInterface& _interface; }; diff --git a/src/libs/shared/ClashAvoider.cpp b/src/libs/shared/ClashAvoider.cpp index bd169d4b..75f46bf6 100644 --- a/src/libs/shared/ClashAvoider.cpp +++ b/src/libs/shared/ClashAvoider.cpp @@ -28,12 +28,20 @@ namespace Shared { const Raul::Path& ClashAvoider::map_path(const Raul::Path& in) { + unsigned offset = 0; + bool has_offset = false; + size_t pos = in.find_last_of("_"); + if (pos != string::npos && pos != (in.length()-1)) { + const std::string trailing = in.substr(in.find_last_of("_")+1); + has_offset = (sscanf(trailing.c_str(), "%u", &offset) > 0); + } + SymbolMap::iterator m = _symbol_map.find(in); if (m != _symbol_map.end()) { return m->second; } else { typedef std::pair InsertRecord; - Store::iterator s = _store.find(in); + Store::iterator s = _store.find(_prefix.base() + in.substr(1)); // No clash, use symbol unmodified if (s == _store.end()) { @@ -54,18 +62,31 @@ ClashAvoider::map_path(const Raul::Path& in) // Append _2 _3 etc until an unused symbol is found string base_name = in.name(); - unsigned offset = 0; - if (sscanf(base_name.c_str(), "%*s_%u", &offset) == 1) + if (has_offset) base_name = base_name.substr(0, base_name.find_last_of("_")); - else - offset = _store.child_name_offset(in.parent(), in.name()); - - assert(offset != 0); // shouldn't have been a clash, then... - std::stringstream ss; - ss << in << "_" << offset; - InsertRecord i = _symbol_map.insert(make_pair(in, ss.str())); - assert(_store.find(i.first->second) == _store.end()); - return i.first->second; + + while (true) { + Offsets::iterator o = _offsets.find(base_name); + if (o != _offsets.end()) { + offset = ++o->second; + } else { + offset = _store.child_name_offset( + _prefix.base() + in.parent().base().substr(1), + base_name, + false); + _offsets.insert(make_pair(base_name, offset)); + } + + assert(offset != 0); // shouldn't have been a clash, then... + std::stringstream ss; + ss << in.parent().base() << base_name << "_" << offset; + if (_store.find(ss.str()) == _store.end()) { + InsertRecord i = _symbol_map.insert(make_pair(in, ss.str())); + return i.first->second; + } else { + cout << "MISSED OFFSET: " << in << " => " << ss.str() << endl; + } + } } } } diff --git a/src/libs/shared/ClashAvoider.hpp b/src/libs/shared/ClashAvoider.hpp index 05b2cd6c..f70e839a 100644 --- a/src/libs/shared/ClashAvoider.hpp +++ b/src/libs/shared/ClashAvoider.hpp @@ -37,8 +37,8 @@ class Store; class ClashAvoider : public CommonInterface { public: - ClashAvoider(Store& store, CommonInterface& target) - : _store(store), _target(target) {} + ClashAvoider(Store& store, const Raul::Path& prefix, CommonInterface& target) + : _prefix(prefix), _store(store), _target(target) {} // Bundles void bundle_begin() { _target.bundle_begin(); } @@ -81,8 +81,12 @@ public: private: const Raul::Path& map_path(const Raul::Path& in); - Store& _store; - CommonInterface& _target; + const Raul::Path& _prefix; + Store& _store; + CommonInterface& _target; + + typedef std::map Offsets; + Offsets _offsets; typedef std::map SymbolMap; SymbolMap _symbol_map; diff --git a/src/libs/shared/Store.cpp b/src/libs/shared/Store.cpp index fea18b6d..9f0f3624 100644 --- a/src/libs/shared/Store.cpp +++ b/src/libs/shared/Store.cpp @@ -82,7 +82,8 @@ Store::find_child(SharedPtr parent, const string& child_nam unsigned Store::child_name_offset(const Raul::Path& parent, - const Raul::Symbol& symbol) + const Raul::Symbol& symbol, + bool allow_zero) { unsigned offset = 0; @@ -91,7 +92,7 @@ Store::child_name_offset(const Raul::Path& parent, ss << symbol; if (offset > 0) ss << "_" << offset; - if (find(parent.base() + ss.str()) == end()) + if (find(parent.base() + ss.str()) == end() && (allow_zero || offset > 0)) break; else if (offset == 0) offset = 2; diff --git a/src/libs/shared/Store.hpp b/src/libs/shared/Store.hpp index bbefdc5c..27754345 100644 --- a/src/libs/shared/Store.hpp +++ b/src/libs/shared/Store.hpp @@ -44,7 +44,8 @@ public: const std::string& child_name) const; unsigned child_name_offset(const Raul::Path& parent, - const Raul::Symbol& symbol); + const Raul::Symbol& symbol, + bool allow_zero=true); Glib::RWLock& lock() { return _lock; } -- cgit v1.2.1