From 72a21b5dbe82ac726f4d7a4308601d802001d9c0 Mon Sep 17 00:00:00 2001 From: David Robillard Date: Wed, 11 Apr 2007 03:46:40 +0000 Subject: Serialization (both saving and restoring) of nested patches. Serialization of patch (float) metadata. Removed useless cruft from Save dialog. Remember filename on save to avoid save as next time. git-svn-id: http://svn.drobilla.net/lad/ingen@437 a436a847-0d15-0410-975c-d299462d15a1 --- src/libs/client/Loader.cpp | 150 ++++++++++++++++++++++++----- src/libs/client/PatchModel.h | 2 + src/libs/client/Serializer.cpp | 83 +++++++++------- src/libs/client/Serializer.h | 14 ++- src/libs/engine/events/ConnectionEvent.cpp | 14 ++- src/libs/engine/events/ConnectionEvent.h | 1 + src/progs/ingenuity/PatchWindow.cpp | 13 ++- 7 files changed, 198 insertions(+), 79 deletions(-) diff --git a/src/libs/client/Loader.cpp b/src/libs/client/Loader.cpp index 70ef0820..09724d6c 100644 --- a/src/libs/client/Loader.cpp +++ b/src/libs/client/Loader.cpp @@ -16,6 +16,7 @@ */ #include +#include #include #include "raul/RDFQuery.h" #include "Loader.h" @@ -63,11 +64,10 @@ Loader::load(const Glib::ustring& filename, Glib::ustring document_uri = (const char*)document_uri_str; //Glib::ustring document_uri = "file:///home/dave/code/drobillanet/ingen/src/progs/ingenuity/test2.ingen.ttl"; - if (patch_uri == "") - patch_uri = "<>"; // FIXME: Will load every patch in the file? + patch_uri = string("<") + patch_uri + ">"; cerr << "[Loader] Loading " << patch_uri << " from " << document_uri - << " under " << parent << endl; + << " under " << (string)(parent ? (string)parent.get() : "no parent") << endl; /* Get polyphony (mandatory) */ @@ -106,11 +106,12 @@ Loader::load(const Glib::ustring& filename, } Path patch_path = ( parent ? (parent.get().base() + patch_name) : Path("/") ); - cerr << "************ PATCH: " << patch_path << ", poly = " << patch_poly << endl; + cerr << "************ PATCH: name=" << patch_name << ", path=" << patch_path + << ", poly = " << patch_poly << endl; _engine->create_patch(patch_path, patch_poly); - /* Load nodes */ + /* Load (plugin) nodes */ query = RDFQuery(*_namespaces, Glib::ustring( "SELECT DISTINCT ?name ?plugin ?floatkey ?floatval FROM <") + document_uri + "> WHERE {\n" + @@ -135,8 +136,8 @@ Loader::load(const Glib::ustring& filename, created[node_path] = true; } - Glib::ustring floatkey = _namespaces->qualify((*i)["floatkey"]); - Glib::ustring floatval = (*i)["floatval"]; + const Glib::ustring& floatkey = _namespaces->qualify((*i)["floatkey"]); + const Glib::ustring& floatval = (*i)["floatval"]; if (floatkey != "" && floatval != "") { const float val = atof(floatval.c_str()); @@ -144,6 +145,31 @@ Loader::load(const Glib::ustring& filename, } } + + /* Load subpatches */ + + query = RDFQuery(*_namespaces, Glib::ustring( + "SELECT DISTINCT ?patch ?name FROM <") + document_uri + "> WHERE {\n" + + patch_uri + " ingen:node ?patch .\n" + "?patch a ingen:Patch ;\n" + " ingen:name ?name .\n" + "}"); + + results = query.run(document_uri); + + for (RDFQuery::Results::iterator i = results.begin(); i != results.end(); ++i) { + + const Glib::ustring& name = (*i)["name"]; + const Glib::ustring& patch = (*i)["patch"]; + + const Path subpatch_path = patch_path.base() + (string)name; + + if (created.find(subpatch_path) == created.end()) { + load(filename, patch_path, name, patch); + created[subpatch_path] = true; + } + } + created.clear(); @@ -225,39 +251,111 @@ Loader::load(const Glib::ustring& filename, created.clear(); - /* Load connections */ + /* Node -> Node connections */ + + query = RDFQuery(*_namespaces, Glib::ustring( + "SELECT DISTINCT ?srcnodename ?srcname ?dstnodename ?dstname FROM <") + document_uri + "> WHERE {\n" + + patch_uri + " ingen:node ?srcnode ;\n" + " ingen:node ?dstnode .\n" + "?srcnode ingen:port ?src ;\n" + " ingen:name ?srcnodename .\n" + + "?dstnode ingen:port ?dst ;\n" + " ingen:name ?dstnodename .\n" + "?src ingen:name ?srcname .\n" + "?dst ingen:connectedTo ?src ;\n" + " ingen:name ?dstname .\n" + "}\n"); + + results = query.run(document_uri); + + for (RDFQuery::Results::iterator i = results.begin(); i != results.end(); ++i) { + Path src_node = patch_path.base() + string((*i)["srcnodename"]); + Path src_port = src_node.base() + string((*i)["srcname"]); + Path dst_node = patch_path.base() + string((*i)["dstnodename"]); + Path dst_port = dst_node.base() + string((*i)["dstname"]); + + cerr << patch_path << " 1 CONNECTION: " << src_port << " -> " << dst_port << endl; + + _engine->connect(src_port, dst_port); + } + + + /* This Patch -> Node connections */ + + query = RDFQuery(*_namespaces, Glib::ustring( + "SELECT DISTINCT ?srcname ?dstnodename ?dstname FROM <") + document_uri + "> WHERE {\n" + + patch_uri + " ingen:port ?src ;\n" + + " ingen:node ?dstnode .\n" + "?dstnode ingen:port ?dst ;\n" + " ingen:name ?dstnodename .\n" + "?dst ingen:connectedTo ?src ;\n" + " ingen:name ?dstname .\n" + "?src ingen:name ?srcname .\n" + "}\n"); + + results = query.run(document_uri); + + for (RDFQuery::Results::iterator i = results.begin(); i != results.end(); ++i) { + Path src_port = patch_path.base() + string((*i)["srcname"]); + + Path dst_node = patch_path.base() + string((*i)["dstnodename"]); + Path dst_port = dst_node.base() + string((*i)["dstname"]); + + cerr << patch_path << " 2 CONNECTION: " << src_port << " -> " << dst_port << endl; + + _engine->connect(src_port, dst_port); + } + + + /* Node -> This Patch connections */ - // FIXME: path? query = RDFQuery(*_namespaces, Glib::ustring( - "SELECT DISTINCT ?srcnode ?src ?dstnode ?dst FROM <") + document_uri + "> WHERE {\n" + - "?srcnoderef ingen:port ?srcref .\n" - "?dstnoderef ingen:port ?dstref .\n" - "?dstref ingen:connectedTo ?srcref .\n" - "?srcref ingen:name ?src .\n" - "?dstref ingen:name ?dst .\n" - "OPTIONAL { ?srcnoderef ingen:name ?srcnode } .\n" - "OPTIONAL { ?dstnoderef ingen:name ?dstnode }\n" + "SELECT DISTINCT ?srcnodename ?srcname ?dstname FROM <") + document_uri + "> WHERE {\n" + + patch_uri + " ingen:port ?dst ;\n" + + " ingen:node ?srcnode .\n" + "?srcnode ingen:port ?src ;\n" + " ingen:name ?srcnodename .\n" + "?dst ingen:connectedTo ?src ;\n" + " ingen:name ?dstname .\n" + "?src ingen:name ?srcname .\n" "}\n"); results = query.run(document_uri); for (RDFQuery::Results::iterator i = results.begin(); i != results.end(); ++i) { - Path src_node = patch_path; - if ((*i).find("srcnode") != (*i).end()) - src_node = patch_path.base() + string((*i)["srcnode"]); - Path src_port = src_node.base() + string((*i)["src"]); + Path dst_port = patch_path.base() + string((*i)["dstname"]); - Path dst_node = patch_path; - if ((*i).find("dstnode") != (*i).end()) - dst_node = patch_path.base() + string((*i)["dstnode"]); - Path dst_port = dst_node.base() + string((*i)["dst"]); + Path src_node = patch_path.base() + string((*i)["srcnodename"]); + Path src_port = src_node.base() + string((*i)["srcname"]); - //cerr << "CONNECTION: " << src_port << " -> " << dst_port << endl; + cerr << patch_path << " 3 CONNECTION: " << src_port << " -> " << dst_port << endl; _engine->connect(src_port, dst_port); } + /* Load metadata */ + + query = RDFQuery(*_namespaces, Glib::ustring( + "SELECT DISTINCT ?floatkey ?floatval FROM <") + document_uri + "> WHERE {\n" + + patch_uri + " ?floatkey ?floatval . \n" + " FILTER ( datatype(?floatval) = xsd:decimal ) \n" + "}"); + + results = query.run(document_uri); + + for (RDFQuery::Results::iterator i = results.begin(); i != results.end(); ++i) { + + const Glib::ustring& floatkey = _namespaces->qualify((*i)["floatkey"]); + const Glib::ustring& floatval = (*i)["floatval"]; + + if (floatkey != "" && floatval != "") { + const float val = atof(floatval.c_str()); + _engine->set_metadata(patch_path, floatkey, Atom(val)); + } + } + + // Set passed metadata last to override any loaded values for (MetadataMap::const_iterator i = data.begin(); i != data.end(); ++i) _engine->set_metadata(patch_path, i->first, i->second); diff --git a/src/libs/client/PatchModel.h b/src/libs/client/PatchModel.h index c38d83a5..c55bce89 100644 --- a/src/libs/client/PatchModel.h +++ b/src/libs/client/PatchModel.h @@ -48,6 +48,8 @@ public: SharedPtr get_connection(const string& src_port_path, const string& dst_port_path) const; SharedPtr get_node(const string& node_name) const; + void set_filename(const string& filename) { _filename = filename; } + size_t poly() const { return _poly; } const string& filename() const { return _filename; } bool enabled() const { return _enabled; } diff --git a/src/libs/client/Serializer.cpp b/src/libs/client/Serializer.cpp index 767d86d9..1374ab12 100644 --- a/src/libs/client/Serializer.cpp +++ b/src/libs/client/Serializer.cpp @@ -64,6 +64,7 @@ Serializer::Serializer() void Serializer::start_to_filename(const string& filename) throw (std::logic_error) { + _base_uri = "file://" + filename; _writer.start_to_filename(filename); } @@ -78,6 +79,7 @@ Serializer::start_to_filename(const string& filename) throw (std::logic_error) void Serializer::start_to_string() throw (std::logic_error) { + _base_uri = ""; _writer.start_to_string(); } @@ -91,6 +93,7 @@ string Serializer::finish() throw(std::logic_error) { return _writer.finish(); + _id_map.clear(); } @@ -99,7 +102,7 @@ Serializer::finish() throw(std::logic_error) RdfId Serializer::path_to_node_id(const Path& path) { - string ret = path.substr(1); + /*string ret = path.substr(1); for (size_t i=0; i < ret.length(); ++i) { if (ret[i] == '/') @@ -107,8 +110,19 @@ Serializer::path_to_node_id(const Path& path) } return RdfId(RdfId::ANONYMOUS, ret); + */ + + IDMap::iterator i = _id_map.find(path); + if (i != _id_map.end()) { + return i->second; + } else { + const RdfId id = _writer.blank_id(); + _id_map[path] = id; + return id; + } } + #if 0 /** Searches for the filename passed in the path, returning the full * path of the file, or the empty string if not found. @@ -166,23 +180,21 @@ Serializer::serialize(SharedPtr object) throw (std::logic_error) if (!_writer.serialization_in_progress()) throw std::logic_error("serialize called without serialization in progress"); - // FIXME: depth - SharedPtr patch = PtrCast(object); if (patch) { - serialize_patch(patch, 0); + serialize_patch(patch, RdfId(RdfId::RESOURCE, _base_uri)); return; } SharedPtr node = PtrCast(object); if (node) { - serialize_node(node, 0); + serialize_node(node, path_to_node_id(node->path())); return; } SharedPtr port = PtrCast(object); if (port) { - serialize_port(port, 0); + serialize_port(port, path_to_node_id(port->path())); return; } @@ -192,15 +204,8 @@ Serializer::serialize(SharedPtr object) throw (std::logic_error) void -Serializer::serialize_patch(SharedPtr patch, unsigned depth) +Serializer::serialize_patch(SharedPtr patch, const RdfId& patch_id) { - RdfId patch_id = path_to_node_id(patch->path()); // anonymous - - if (patch->path().length() < 2) - patch_id = RdfId(RdfId::RESOURCE, string("")); - else if (depth == 0) - patch_id = RdfId(RdfId::RESOURCE, string("#") + patch->path().substr(1)); - _writer.write( patch_id, NS_RDF("type"), @@ -218,23 +223,37 @@ Serializer::serialize_patch(SharedPtr patch, unsigned depth) Atom((int)patch->poly())); for (NodeModelMap::const_iterator n = patch->nodes().begin(); n != patch->nodes().end(); ++n) { - _writer.write(patch_id, NS_INGEN("node"), path_to_node_id(n->second->path())); SharedPtr patch = PtrCast(n->second); - if (patch) - serialize_patch(patch, depth+1); - else - serialize_node(n->second, depth+1); + if (patch) { + const RdfId subpatch_id = RdfId(RdfId::RESOURCE, + patch_id.to_string() + "#" + patch->path().substr(1)); + _writer.write(patch_id, NS_INGEN("node"), subpatch_id); + serialize_patch(patch, subpatch_id); + } else { + const RdfId node_id = path_to_node_id(n->second->path()); + _writer.write(patch_id, NS_INGEN("node"), node_id); + serialize_node(n->second, node_id); + } } for (PortModelList::const_iterator p = patch->ports().begin(); p != patch->ports().end(); ++p) { - _writer.write(patch_id, NS_INGEN("port"), path_to_node_id((*p)->path())); - serialize_port(*p, depth+1); - + const RdfId port_id = path_to_node_id((*p)->path()); + _writer.write(patch_id, NS_INGEN("port"), port_id); + serialize_port(*p, port_id); } for (ConnectionList::const_iterator c = patch->connections().begin(); c != patch->connections().end(); ++c) { serialize_connection(*c); } + + for (MetadataMap::const_iterator m = patch->metadata().begin(); m != patch->metadata().end(); ++m) { + if (_writer.expand_uri(m->first) != "") { + _writer.write( + patch_id, + RdfId(RdfId::RESOURCE, _writer.expand_uri(m->first.c_str()).c_str()), + m->second); + } + } } @@ -251,12 +270,8 @@ Serializer::serialize_plugin(SharedPtr plugin) void -Serializer::serialize_node(SharedPtr node, unsigned depth) +Serializer::serialize_node(SharedPtr node, const RdfId& node_id) { - const RdfId node_id = (depth == 0) - ? RdfId(RdfId::RESOURCE, string("#") + node->path().substr(1)) - : path_to_node_id(node->path()); // anonymous - const RdfId plugin_id = RdfId(RdfId::RESOURCE, node->plugin()->uri()); _writer.write( @@ -282,8 +297,9 @@ Serializer::serialize_node(SharedPtr node, unsigned depth) Atom(node->path().name()));*/ for (PortModelList::const_iterator p = node->ports().begin(); p != node->ports().end(); ++p) { - serialize_port(*p, depth+1); - _writer.write(node_id, NS_INGEN("port"), path_to_node_id((*p)->path())); + const RdfId port_id = path_to_node_id((*p)->path()); + serialize_port(*p, port_id); + _writer.write(node_id, NS_INGEN("port"), port_id); } for (MetadataMap::const_iterator m = node->metadata().begin(); m != node->metadata().end(); ++m) { @@ -301,12 +317,8 @@ Serializer::serialize_node(SharedPtr node, unsigned depth) * Audio output ports with no metadata will not be written, for example. */ void -Serializer::serialize_port(SharedPtr port, unsigned depth) +Serializer::serialize_port(SharedPtr port, const RdfId& port_id) { - const RdfId port_id = (depth == 0) - ? RdfId(RdfId::RESOURCE, string("#") + port->path().substr(1)) - : path_to_node_id(port->path()); // anonymous - if (port->is_input()) _writer.write(port_id, NS_RDF("type"), NS_INGEN("InputPort")); else @@ -355,7 +367,7 @@ Serializer::serialize_connection(SharedPtr connection) throw (s */ } - +#if 0 /** Load a patch into the engine (e.g. from a patch file). * * @param base_uri Base URI (e.g. URI of the file to load from). @@ -522,6 +534,7 @@ Serializer::load_patch(bool merge, #endif return "/FIXME"; } +#endif } // namespace Client } // namespace Ingen diff --git a/src/libs/client/Serializer.h b/src/libs/client/Serializer.h index 8d81b149..45407e52 100644 --- a/src/libs/client/Serializer.h +++ b/src/libs/client/Serializer.h @@ -33,6 +33,7 @@ using std::string; using boost::optional; +using Raul::RdfId; namespace Ingen { namespace Client { @@ -65,14 +66,14 @@ public: //string find_file(const string& filename, const string& additional_path = ""); - bool load_patch(bool merge, + /*bool load_patch(bool merge, const string& data_base_uri, const Path& data_path, MetadataMap engine_data, optional engine_parent = optional(), optional engine_name = optional(), optional engine_poly = optional()); - + */ void start_to_filename(const string& filename) throw (std::logic_error); void start_to_string() throw (std::logic_error); @@ -84,12 +85,15 @@ private: void serialize_plugin(SharedPtr p); - void serialize_patch(SharedPtr p, unsigned depth); - void serialize_node(SharedPtr n, unsigned depth); - void serialize_port(SharedPtr p, unsigned depth); + void serialize_patch(SharedPtr p, const Raul::RdfId& id); + void serialize_node(SharedPtr n, const Raul::RdfId& id); + void serialize_port(SharedPtr p, const Raul::RdfId& id); Raul::RdfId path_to_node_id(const Path& path); + typedef std::map IDMap; + IDMap _id_map; + string _base_uri; Raul::RDFWriter _writer; }; diff --git a/src/libs/engine/events/ConnectionEvent.cpp b/src/libs/engine/events/ConnectionEvent.cpp index af35265b..7c4b4422 100644 --- a/src/libs/engine/events/ConnectionEvent.cpp +++ b/src/libs/engine/events/ConnectionEvent.cpp @@ -84,16 +84,14 @@ ConnectionEvent::pre_process() return; } - /*if ( !( _src_port->is_output() && _dst_port->is_input() ) ) { - _error = TYPE_MISMATCH; - QueuedEvent::pre_process(); - return; - }*/ - _dst_input_port = dynamic_cast(_dst_port); _src_output_port = dynamic_cast(_src_port); - assert(_src_output_port); - assert(_dst_input_port); + + if (!_dst_input_port || !_src_output_port) { + _error = DIRECTION_MISMATCH; + QueuedEvent::pre_process(); + return; + } if (_dst_input_port->is_connected_to(_src_output_port)) { _error = ALREADY_CONNECTED; diff --git a/src/libs/engine/events/ConnectionEvent.h b/src/libs/engine/events/ConnectionEvent.h index 8f5e1cc2..bebb6cfd 100644 --- a/src/libs/engine/events/ConnectionEvent.h +++ b/src/libs/engine/events/ConnectionEvent.h @@ -61,6 +61,7 @@ private: PARENT_PATCH_DIFFERENT, PORT_NOT_FOUND, TYPE_MISMATCH, + DIRECTION_MISMATCH, ALREADY_CONNECTED, PARENTS_NOT_FOUND }; diff --git a/src/progs/ingenuity/PatchWindow.cpp b/src/progs/ingenuity/PatchWindow.cpp index 22305247..ddcccf10 100644 --- a/src/progs/ingenuity/PatchWindow.cpp +++ b/src/progs/ingenuity/PatchWindow.cpp @@ -267,16 +267,18 @@ PatchWindow::event_save_as() { Gtk::FileChooserDialog dialog(*this, "Save Patch", Gtk::FILE_CHOOSER_ACTION_SAVE); - Gtk::VBox* box = dialog.get_vbox(); + /*Gtk::VBox* box = dialog.get_vbox(); Gtk::Label warning("Warning: Recursively saving will overwrite any subpatch files \ without confirmation."); box->pack_start(warning, false, false, 2); Gtk::CheckButton recursive_checkbutton("Recursively save all subpatches"); box->pack_start(recursive_checkbutton, false, false, 0); recursive_checkbutton.show(); + */ dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL); - dialog.add_button(Gtk::Stock::SAVE, Gtk::RESPONSE_OK); + Gtk::Button* save_button = dialog.add_button(Gtk::Stock::SAVE, Gtk::RESPONSE_OK); + save_button->property_has_default() = true; // Set current folder to most sensible default const string& current_filename = _patch->filename(); @@ -286,7 +288,7 @@ PatchWindow::event_save_as() dialog.set_current_folder(App::instance().configuration()->patch_folder()); int result = dialog.run(); - bool recursive = recursive_checkbutton.get_active(); + //bool recursive = recursive_checkbutton.get_active(); assert(result == Gtk::RESPONSE_OK || result == Gtk::RESPONSE_CANCEL || result == Gtk::RESPONSE_NONE); @@ -313,8 +315,9 @@ PatchWindow::event_save_as() fin.close(); if (confirm) { - App::instance().loader()->save_patch(_patch, filename, recursive); - //m_patch->set_metadata("filename", Atom(filename.c_str())); + App::instance().loader()->save_patch(_patch, filename, true); + _patch->set_filename(filename); + //_patch->set_metadata("filename", Atom(filename.c_str())); } } App::instance().configuration()->set_patch_folder(dialog.get_current_folder()); -- cgit v1.2.1