From 8211b45bffe20e8a271396b7568609a84b7cf0ec Mon Sep 17 00:00:00 2001 From: David Robillard Date: Sat, 12 May 2012 03:31:57 +0000 Subject: Get copy and paste working again. Client side and text based is probably not the idea way to go about implementing this, but it more or less works and is certainly better than nothing for now. Copy paste of patch ports, and pasting into any path other than the root still isn't working currently. git-svn-id: http://svn.drobilla.net/lad/trunk/ingen@4367 a436a847-0d15-0410-975c-d299462d15a1 --- src/client/ClientStore.cpp | 6 +- src/gui/PatchCanvas.cpp | 69 +++++++++++++-------- src/serialisation/Parser.cpp | 129 +++++++++++++++++++++------------------ src/serialisation/Serialiser.cpp | 12 +++- src/shared/URIs.cpp | 1 - 5 files changed, 125 insertions(+), 92 deletions(-) (limited to 'src') diff --git a/src/client/ClientStore.cpp b/src/client/ClientStore.cpp index a78653e5..75acef63 100644 --- a/src/client/ClientStore.cpp +++ b/src/client/ClientStore.cpp @@ -459,9 +459,11 @@ ClientStore::attempt_connection(const Raul::Path& tail_path, patch->add_edge(cm); return true; + } else { + LOG(Raul::warn) << "Failed to connect " << tail_path + << " => " << head_path << std::endl; + return false; } - - return false; } void diff --git a/src/gui/PatchCanvas.cpp b/src/gui/PatchCanvas.cpp index 3562a007..640051cb 100644 --- a/src/gui/PatchCanvas.cpp +++ b/src/gui/PatchCanvas.cpp @@ -637,42 +637,56 @@ PatchCanvas::destroy_selection() for_each_selected_edge(destroy_edge, &_app); } -void -PatchCanvas::copy_selection() +static void +serialise_node(GanvNode* node, void* data) { - std::cerr << "FIXME: copy" << std::endl; - #if 0 - static const char* base_uri = ""; - Serialiser serialiser(*_app.world(), _app.store()); - serialiser.start_to_string(_patch->path(), base_uri); + Serialisation::Serialiser* serialiser = (Serialisation::Serialiser*)data; + if (!GANV_IS_MODULE(node)) { + return; + } - FOREACH_ITEM(m, selected_items()) { - NodeModule* module = dynamic_cast(*m); - if (module) { - serialiser.serialise(module->node()); - } else { - PatchPortModule* port_module = dynamic_cast(*m); - if (port_module) - serialiser.serialise(port_module->port()); + Ganv::Module* module = Glib::wrap(GANV_MODULE(node)); + NodeModule* node_module = dynamic_cast(module); + + if (node_module) { + serialiser->serialise(node_module->node()); + } else { + PatchPortModule* port_module = dynamic_cast(module); + if (port_module) { + serialiser->serialise(port_module->port()); } } +} - for (SelectedEdges::const_iterator c = selected_edges().begin(); - c != selected_edges().end(); ++c) { - Edge* const edge = dynamic_cast(*c); - if (edge) { - const Sord::URI subject(*_app.world()->rdf_world(), - base_uri); - serialiser.serialise_edge(subject, edge->model()); - } +static void +serialise_edge(GanvEdge* edge, void* data) +{ + Serialisation::Serialiser* serialiser = (Serialisation::Serialiser*)data; + if (!GANV_IS_EDGE(edge)) { + return; + } + + GUI::Edge* gedge = dynamic_cast(Glib::wrap(GANV_EDGE(edge))); + if (gedge) { + serialiser->serialise_edge(Sord::Node(), gedge->model()); } +} + +void +PatchCanvas::copy_selection() +{ + static const char* base_uri = "http://drobilla.net/ns/ingen/selection/"; + Serialisation::Serialiser serialiser(*_app.world()); + serialiser.start_to_string(_patch->path(), base_uri); + + for_each_selected_node(serialise_node, &serialiser); + for_each_selected_edge(serialise_edge, &serialiser); - string result = serialiser.finish(); + const std::string result = serialiser.finish(); _paste_count = 0; Glib::RefPtr clipboard = Gtk::Clipboard::get(); clipboard->set_text(result); - #endif } void @@ -702,7 +716,7 @@ PatchCanvas::paste() uris.ingen_Patch)); props.insert(make_pair(uris.ingen_polyphony, _app.forge().make(int32_t(_patch->internal_poly())))); - clipboard.put(Path(), props); + clipboard.put(Path("/"), props); size_t first_slash; while (to_create != "/" && !to_create.empty() && (first_slash = to_create.find("/")) != string::npos) { @@ -723,7 +737,8 @@ PatchCanvas::paste() } ClashAvoider avoider(*_app.store().get(), clipboard, &clipboard); - parser->parse_string(_app.world(), &avoider, str, "", + static const char* base_uri = "http://drobilla.net/ns/ingen/selection/"; + parser->parse_string(_app.world(), &avoider, str, base_uri, parent, symbol); for (Store::iterator i = clipboard.begin(); i != clipboard.end(); ++i) { diff --git a/src/serialisation/Parser.cpp b/src/serialisation/Parser.cpp index df17d7ff..2c56dc1e 100644 --- a/src/serialisation/Parser.cpp +++ b/src/serialisation/Parser.cpp @@ -177,6 +177,7 @@ parse( Interface* target, Sord::Model& model, Glib::ustring document_uri, + Sord::Node& subject, boost::optional parent = boost::optional(), boost::optional symbol = boost::optional(), boost::optional data = boost::optional()); @@ -397,49 +398,57 @@ parse_patch(Ingen::Shared::World* world, } static bool -parse_edges(Ingen::Shared::World* world, - Ingen::Interface* target, - Sord::Model& model, - const Sord::Node& subject, - const Raul::Path& parent) +parse_edge(Ingen::Shared::World* world, + Ingen::Interface* target, + Sord::Model& model, + const Sord::Node& subject, + const Raul::Path& parent) { - Sord::URI ingen_edge(*world->rdf_world(), NS_INGEN "edge"); Sord::URI ingen_tail(*world->rdf_world(), NS_INGEN "tail"); Sord::URI ingen_head(*world->rdf_world(), NS_INGEN "head"); + Sord::Iter t = model.find(subject, ingen_tail, nil); + Sord::Iter h = model.find(subject, ingen_head, nil); + const Glib::ustring& base_uri = model.base_uri().to_string(); - RDFNodes connections; - for (Sord::Iter i = model.find(subject, ingen_edge, nil); !i.end(); ++i) { - connections.insert(i.get_object()); + if (t.end()) { + LOG(error) << "Edge has no tail" << endl; + return false; + } else if (h.end()) { + LOG(error) << "Edge has no head" << endl; + return false; } - for (RDFNodes::const_iterator i = connections.begin(); i != connections.end(); ++i) { - Sord::Iter t = model.find(*i, ingen_tail, nil); - Sord::Iter h = model.find(*i, ingen_head, nil); + const Path tail_path( + parent.child(relative_uri(base_uri, t.get_object().to_string(), false))); + const Path head_path( + parent.child(relative_uri(base_uri, h.get_object().to_string(), false))); - if (t.end()) { - LOG(error) << "Edge has no tail" << endl; - return false; - } else if (h.end()) { - LOG(error) << "Edge has no head" << endl; - return false; - } + if (!(++t).end()) { + LOG(error) << "Edge has multiple tails" << endl; + return false; + } else if (!(++h).end()) { + LOG(error) << "Edge has multiple heads" << endl; + return false; + } - const Path tail_path( - parent.child(relative_uri(base_uri, t.get_object().to_string(), false))); - const Path head_path( - parent.child(relative_uri(base_uri, h.get_object().to_string(), false))); - - if (!(++t).end()) { - LOG(error) << "Edge has multiple tails" << endl; - return false; - } else if (!(++h).end()) { - LOG(error) << "Edge has multiple heads" << endl; - return false; - } + target->connect(tail_path, head_path); - target->connect(tail_path, head_path); + return true; +} + +static bool +parse_edges(Ingen::Shared::World* world, + Ingen::Interface* target, + Sord::Model& model, + const Sord::Node& subject, + const Raul::Path& parent) +{ + Sord::URI ingen_edge(*world->rdf_world(), NS_INGEN "edge"); + + for (Sord::Iter i = model.find(subject, ingen_edge, nil); !i.end(); ++i) { + parse_edge(world, target, model, i.get_object(), parent); } return true; @@ -469,24 +478,23 @@ parse(Ingen::Shared::World* world, Ingen::Interface* target, Sord::Model& model, Glib::ustring document_uri, + Sord::Node& subject, boost::optional parent, boost::optional symbol, boost::optional data) { const Sord::URI patch_class (*world->rdf_world(), NS_INGEN "Patch"); const Sord::URI node_class (*world->rdf_world(), NS_INGEN "Node"); - const Sord::URI port_class (*world->rdf_world(), NS_INGEN "Port"); + const Sord::URI edge_class (*world->rdf_world(), NS_INGEN "Edge"); const Sord::URI internal_class(*world->rdf_world(), NS_INGEN "Internal"); const Sord::URI in_port_class (*world->rdf_world(), LV2_CORE__InputPort); const Sord::URI out_port_class(*world->rdf_world(), LV2_CORE__OutputPort); const Sord::URI lv2_class (*world->rdf_world(), LV2_CORE__Plugin); - const Sord::URI rdf_type (*world->rdf_world(), NS_RDF "type"); - - Sord::Node subject = model.base_uri(); + const Sord::URI rdf_type (*world->rdf_world(), NS_RDF "type"); - Raul::Path path("/"); - if (parent && symbol) { - path = parent->child(*symbol); + // Parse explicit subject patch + if (subject.is_valid()) { + return parse_patch(world, target, model, subject, parent, symbol, data); } // Get all subjects and their types (?subject a ?type) @@ -508,19 +516,23 @@ parse(Ingen::Shared::World* world, } // Parse and create each subject - boost::optional ret; for (Subjects::const_iterator i = subjects.begin(); i != subjects.end(); ++i) { - const Sord::Node& subject = i->first; - const std::set& types = i->second; + const Sord::Node& s = i->first; + const std::set& types = i->second; + boost::optional ret; + const Raul::Path path( + relative_uri( model.base_uri().to_string(), s.to_string(), true)); if (types.find(patch_class) != types.end()) { - ret = parse_patch(world, target, model, subject, parent, symbol, data); + ret = parse_patch(world, target, model, s, parent, symbol, data); } else if (types.find(node_class) != types.end()) { - ret = parse_node(world, target, model, - subject, path.child(subject.to_string()), - data); - } else if (types.find(port_class) != types.end()) { - parse_properties(world, target, model, subject, path, data); + ret = parse_node(world, target, model, s, path, data); + } else if (types.find(in_port_class) != types.end() || + types.find(out_port_class) != types.end()) { + parse_properties(world, target, model, s, path, data); ret = path; + } else if (types.find(edge_class) != types.end()) { + Path parent_path(parent ? parent.get() : Path("/")); + parse_edge(world, target, model, s, parent_path); } else { LOG(error) << "Subject has no known types" << endl; } @@ -533,11 +545,10 @@ parse(Ingen::Shared::World* world, LOG(error) << " :: " << *t << endl; assert((*t).is_uri()); } - return boost::optional(); } } - return path; + return boost::optional(); } Parser::Parser(Ingen::Shared::World& world) @@ -578,7 +589,7 @@ Parser::parse_file(Ingen::Shared::World* world, SerdEnv* env = serd_env_new(&base_node); // Load patch file into model - Sord::Model model(*world->rdf_world(), uri); + Sord::Model model(*world->rdf_world(), uri, SORD_SPO|SORD_PSO, false); model.load_file(env, SERD_TURTLE, uri); serd_env_free(env); @@ -589,8 +600,9 @@ Parser::parse_file(Ingen::Shared::World* world, if (symbol) LOG(Raul::info)(Raul::fmt("Symbol: %1%\n") % symbol->c_str()); + Sord::Node subject(*world->rdf_world(), Sord::Node::URI, uri); boost::optional parsed_path - = parse(world, target, model, path, parent, symbol, data); + = parse(world, target, model, path, subject, parent, symbol, data); if (parsed_path) { target->set_property(*parsed_path, "http://drobilla.net/ns/ingen#document", @@ -612,8 +624,10 @@ Parser::parse_string(Ingen::Shared::World* world, boost::optional data) { // Load string into model - Sord::Model model(*world->rdf_world(), base_uri); - SerdEnv* env = serd_env_new(NULL); + Sord::Model model(*world->rdf_world(), base_uri, SORD_SPO|SORD_PSO, false); + const SerdNode base = serd_node_from_string( + SERD_URI, (const uint8_t*)base_uri.c_str()); + SerdEnv* env = serd_env_new(&base); model.load_string(env, SERD_TURTLE, str.c_str(), str.length(), base_uri); serd_env_free(env); @@ -622,11 +636,8 @@ Parser::parse_string(Ingen::Shared::World* world, info << " (base " << base_uri << ")"; info << endl; - bool ret = parse(world, target, model, base_uri, parent, symbol, data); - Sord::URI subject(*world->rdf_world(), base_uri); - parse_edges(world, target, model, subject, parent ? *parent : "/"); - - return ret; + Sord::Node subject; + return parse(world, target, model, base_uri, subject, parent, symbol, data); } } // namespace Serialisation diff --git a/src/serialisation/Serialiser.cpp b/src/serialisation/Serialiser.cpp index 6e126c42..6a674eb5 100644 --- a/src/serialisation/Serialiser.cpp +++ b/src/serialisation/Serialiser.cpp @@ -526,9 +526,15 @@ Serialiser::Impl::serialise_edge(const Sord::Node& parent, Sord::Curie(world, "ingen:head"), dst); - _model->add_statement(parent, - Sord::Curie(world, "ingen:edge"), - edge_id); + if (parent.is_valid()) { + _model->add_statement(parent, + Sord::Curie(world, "ingen:edge"), + edge_id); + } else { + _model->add_statement(edge_id, + Sord::Curie(world, "rdf:type"), + Sord::Curie(world, "ingen:Edge")); + } } static bool diff --git a/src/shared/URIs.cpp b/src/shared/URIs.cpp index 6cc32c0b..abb0a011 100644 --- a/src/shared/URIs.cpp +++ b/src/shared/URIs.cpp @@ -68,7 +68,6 @@ URIs::URIs(Shared::Forge& f, URIMap* map) , ingen_Internal (forge, map, NS_INGEN "Internal") , ingen_Node (forge, map, NS_INGEN "Node") , ingen_Patch (forge, map, NS_INGEN "Patch") - , ingen_Port (forge, map, NS_INGEN "Port") , ingen_activity (forge, map, NS_INGEN "activity") , ingen_broadcast (forge, map, NS_INGEN "broadcast") , ingen_canvasX (forge, map, NS_INGEN "canvasX") -- cgit v1.2.1