From ac408e8d4ce77389e65d69e9a1ff30fd54a25ada Mon Sep 17 00:00:00 2001 From: David Robillard Date: Tue, 8 Jan 2013 04:05:01 +0000 Subject: Add support for URID ports. Fix glib errors when resetting properties dialog. Move RDFS domain/range/classes/etc code to reusable location. Add preliminary "mesp" (message processing) plugin package. git-svn-id: http://svn.drobilla.net/lad/trunk/ingen@4903 a436a847-0d15-0410-975c-d299462d15a1 --- ingen/Forge.hpp | 3 + ingen/URIs.hpp | 1 + ingen/client/PortModel.hpp | 1 + src/Forge.cpp | 3 + src/URIs.cpp | 1 + src/client/PortModel.cpp | 14 +++ src/gui/Port.cpp | 64 ++++++++++++ src/gui/Port.hpp | 2 + src/gui/PropertiesWindow.cpp | 199 +++++++------------------------------ src/gui/RDFS.cpp | 177 +++++++++++++++++++++++++++++++++ src/gui/RDFS.hpp | 67 +++++++++++++ src/gui/wscript | 1 + src/server/Buffer.hpp | 2 + src/server/BufferFactory.cpp | 6 +- src/server/BufferFactory.hpp | 3 + src/server/LV2Block.cpp | 25 ++++- src/server/LV2Info.cpp | 2 + src/server/LV2Info.hpp | 1 + src/server/events/SetPortValue.cpp | 2 + 19 files changed, 407 insertions(+), 167 deletions(-) create mode 100644 src/gui/RDFS.cpp create mode 100644 src/gui/RDFS.hpp diff --git a/ingen/Forge.hpp b/ingen/Forge.hpp index 8e7df926..e92a9501 100644 --- a/ingen/Forge.hpp +++ b/ingen/Forge.hpp @@ -33,6 +33,9 @@ public: explicit Forge(URIMap& map); std::string str(const Raul::Atom& atom); + +private: + URIMap& _map; }; } // namespace Ingen diff --git a/ingen/URIs.hpp b/ingen/URIs.hpp index 3e6427e6..77dc00d3 100644 --- a/ingen/URIs.hpp +++ b/ingen/URIs.hpp @@ -110,6 +110,7 @@ public: const Quark lv2_binary; const Quark lv2_connectionOptional; const Quark lv2_default; + const Quark lv2_designation; const Quark lv2_extensionData; const Quark lv2_index; const Quark lv2_integer; diff --git a/ingen/client/PortModel.hpp b/ingen/client/PortModel.hpp index 6a8583de..41b871ab 100644 --- a/ingen/client/PortModel.hpp +++ b/ingen/client/PortModel.hpp @@ -61,6 +61,7 @@ public: return ObjectModel::is_a(Raul::URI(LV2_CORE__ControlPort)) || ObjectModel::is_a(Raul::URI(LV2_CORE__CVPort)); } + bool is_uri() const; inline bool operator==(const PortModel& pm) const { return (path() == pm.path()); } diff --git a/src/Forge.cpp b/src/Forge.cpp index 077bec73..d74f42ee 100644 --- a/src/Forge.cpp +++ b/src/Forge.cpp @@ -23,6 +23,7 @@ namespace Ingen { Forge::Forge(URIMap& map) + : _map(map) { Int = map.map_uri(LV2_ATOM__Int); Float = map.map_uri(LV2_ATOM__Float); @@ -44,6 +45,8 @@ Forge::str(const Raul::Atom& atom) ss << (atom.get_bool() ? "true" : "false"); } else if (atom.type() == URI) { ss << "<" << atom.get_uri() << ">"; + } else if (atom.type() == URID) { + ss << "<" << _map.unmap_uri(atom.get_int32()) << ">"; } else if (atom.type() == String) { ss << "\"" << atom.get_string() << "\""; } diff --git a/src/URIs.cpp b/src/URIs.cpp index 8dbf87a6..a3ee8874 100644 --- a/src/URIs.cpp +++ b/src/URIs.cpp @@ -98,6 +98,7 @@ URIs::URIs(Forge& f, URIMap* map) , lv2_binary (forge, map, LV2_CORE__binary) , lv2_connectionOptional(forge, map, LV2_CORE__connectionOptional) , lv2_default (forge, map, LV2_CORE__default) + , lv2_designation (forge, map, LV2_CORE__designation) , lv2_extensionData (forge, map, LV2_CORE__extensionData) , lv2_index (forge, map, LV2_CORE__index) , lv2_integer (forge, map, LV2_CORE__integer) diff --git a/src/client/PortModel.cpp b/src/client/PortModel.cpp index fdef852d..e936a1e2 100644 --- a/src/client/PortModel.cpp +++ b/src/client/PortModel.cpp @@ -50,6 +50,20 @@ PortModel::port_property(const Raul::URI& uri) const _uris.forge.alloc_uri(uri)); } +bool +PortModel::is_uri() const +{ + // FIXME: Resource::has_property doesn't work, URI != URID + for (Resource::Properties::const_iterator i = properties().begin(); + i != properties().end(); ++i) { + if (i->second.type() == _uris.atom_URID && + static_cast(i->second.get_int32()) == _uris.atom_URID) { + return true; + } + } + return false; +} + void PortModel::set(SharedPtr model) { diff --git a/src/gui/Port.cpp b/src/gui/Port.cpp index 0027e480..f6e1e46b 100644 --- a/src/gui/Port.cpp +++ b/src/gui/Port.cpp @@ -28,6 +28,7 @@ #include "GraphWindow.hpp" #include "Port.hpp" #include "PortMenu.hpp" +#include "RDFS.hpp" #include "Style.hpp" #include "WidgetFactory.hpp" #include "WindowFactory.hpp" @@ -206,6 +207,63 @@ Port::build_enum_menu() return menu; } +void +Port::on_uri_activated(const Raul::URI& uri) +{ + _app.interface()->set_property( + model()->uri(), + _app.world()->uris().ingen_value, + _app.world()->forge().make_urid( + _app.world()->uri_map().map_uri(uri.c_str()))); +} + +Gtk::Menu* +Port::build_uri_menu() +{ + World* world = _app.world(); + SharedPtr block = PtrCast(model()->parent()); + Gtk::Menu* menu = Gtk::manage(new Gtk::Menu()); + + // Get the port designation, which should be a rdf:Property + const Raul::Atom& designation_atom = model()->get_property( + _app.uris().lv2_designation); + if (!designation_atom.is_valid()) { + return NULL; + } + + LilvNode* designation = lilv_new_uri( + world->lilv_world(), designation_atom.get_uri()); + LilvNode* rdfs_range = lilv_new_uri( + world->lilv_world(), LILV_NS_RDFS "range"); + + // Get every class in the range of the port's property + RDFS::URISet ranges; + LilvNodes* range = lilv_world_find_nodes( + world->lilv_world(), designation, rdfs_range, NULL); + LILV_FOREACH(nodes, r, range) { + ranges.insert(Raul::URI(lilv_node_as_string(lilv_nodes_get(range, r)))); + } + RDFS::classes(world, ranges, false); + + // Get all objects in range + RDFS::Objects values = RDFS::instances(world, ranges); + + // Add a menu item for each such class + for (RDFS::Objects::const_iterator i = values.begin(); i != values.end(); ++i) { + if (!i->second.empty()) { + Glib::ustring label = world->rdf_world()->prefixes().qualify(i->first) + + " - " + i->second; + menu->items().push_back(Gtk::Menu_Helpers::MenuElem(label)); + Gtk::MenuItem* menu_item = &(menu->items().back()); + menu_item->signal_activate().connect( + sigc::bind(sigc::mem_fun(this, &Port::on_uri_activated), + i->first)); + } + } + + return menu; +} + bool Port::on_event(GdkEvent* ev) { @@ -229,6 +287,12 @@ Port::on_event(GdkEvent* ev) Gtk::Menu* menu = build_enum_menu(); menu->popup(ev->button.button, ev->button.time); return true; + } else if (model()->is_uri()) { + Gtk::Menu* menu = build_uri_menu(); + if (menu) { + menu->popup(ev->button.button, ev->button.time); + return true; + } } _pressed = true; } else if (ev->button.button == 3) { diff --git a/src/gui/Port.hpp b/src/gui/Port.hpp index 2aab66eb..94f66ecd 100644 --- a/src/gui/Port.hpp +++ b/src/gui/Port.hpp @@ -75,6 +75,7 @@ private: bool flip = false); Gtk::Menu* build_enum_menu(); + Gtk::Menu* build_uri_menu(); GraphBox* get_graph_box() const; void property_changed(const Raul::URI& key, const Raul::Atom& value); @@ -82,6 +83,7 @@ private: void on_value_changed(GVariant* value); void on_scale_point_activated(float f); + void on_uri_activated(const Raul::URI& uri); bool on_event(GdkEvent* ev); App& _app; diff --git a/src/gui/PropertiesWindow.cpp b/src/gui/PropertiesWindow.cpp index f2e2b9cf..b357514d 100644 --- a/src/gui/PropertiesWindow.cpp +++ b/src/gui/PropertiesWindow.cpp @@ -23,12 +23,14 @@ #include "ingen/Interface.hpp" #include "ingen/Log.hpp" +#include "ingen/URIMap.hpp" #include "ingen/World.hpp" #include "ingen/client/BlockModel.hpp" #include "ingen/client/PluginModel.hpp" #include "App.hpp" #include "PropertiesWindow.hpp" +#include "RDFS.hpp" using namespace std; @@ -81,16 +83,17 @@ PropertiesWindow::PropertiesWindow(BaseObjectType* cobject, void PropertiesWindow::reset() { - _table->children().clear(); - _table->resize(1, 3); - _table->property_n_rows() = 1; + _property_connection.disconnect(); - _records.clear(); _key_store->clear(); _value_store->clear(); + _records.clear(); - _property_connection.disconnect(); _model.reset(); + + _table->children().clear(); + _table->resize(1, 3); + _table->property_n_rows() = 1; } void @@ -100,132 +103,6 @@ PropertiesWindow::present(SharedPtr model) Gtk::Window::present(); } -/** Set @p types to its super/sub class closure. - * @param super If true, find all superclasses, otherwise all subclasses - */ -static void -get_classes(World* world, URISet& types, bool super) -{ - LilvNode* rdfs_subClassOf = lilv_new_uri( - world->lilv_world(), LILV_NS_RDFS "subClassOf"); - - unsigned added = 0; - do { - added = 0; - URISet klasses; - for (URISet::iterator t = types.begin(); t != types.end(); ++t) { - LilvNode* type = lilv_new_uri(world->lilv_world(), t->c_str()); - LilvNodes* matches = (super) - ? lilv_world_find_nodes( - world->lilv_world(), type, rdfs_subClassOf, NULL) - : lilv_world_find_nodes( - world->lilv_world(), NULL, rdfs_subClassOf, type); - LILV_FOREACH(nodes, m, matches) { - const LilvNode* klass_node = lilv_nodes_get(matches, m); - if (lilv_node_is_uri(klass_node)) { - Raul::URI klass(lilv_node_as_uri(klass_node)); - if (!types.count(klass)) { - ++added; - klasses.insert(klass); - } - } - } - lilv_nodes_free(matches); - lilv_node_free(type); - } - types.insert(klasses.begin(), klasses.end()); - } while (added > 0); - - lilv_node_free(rdfs_subClassOf); -} - -/** Get all the types which this model is an instance of */ -static URISet -get_types(World* world, SharedPtr model) -{ - typedef Resource::Properties::const_iterator PropIter; - typedef std::pair PropRange; - - // Start with every rdf:type - URISet types; - PropRange range = model->properties().equal_range(world->uris().rdf_type); - for (PropIter t = range.first; t != range.second; ++t) { - types.insert(Raul::URI(t->second.get_uri())); - if (world->uris().ingen_Graph == t->second.get_uri()) { - // Add lv2:Plugin as a type for graphs so plugin properties show up - types.insert(world->uris().lv2_Plugin); - } - } - - // Add every superclass of every type, recursively - get_classes(world, types, true); - - return types; -} - -/** Get all the properties with domains appropriate to this model */ -static URISet -get_properties(World* world, SharedPtr model) -{ - URISet properties; - URISet types = get_types(world, model); - - LilvNode* rdf_type = lilv_new_uri(world->lilv_world(), - LILV_NS_RDF "type"); - LilvNode* rdf_Property = lilv_new_uri(world->lilv_world(), - LILV_NS_RDF "Property"); - LilvNode* rdfs_domain = lilv_new_uri(world->lilv_world(), - LILV_NS_RDFS "domain"); - - LilvNodes* props = lilv_world_find_nodes( - world->lilv_world(), NULL, rdf_type, rdf_Property); - LILV_FOREACH(nodes, p, props) { - const LilvNode* prop = lilv_nodes_get(props, p); - if (lilv_node_is_uri(prop)) { - LilvNodes* domains = lilv_world_find_nodes( - world->lilv_world(), prop, rdfs_domain, NULL); - unsigned n_matching_domains = 0; - LILV_FOREACH(nodes, d, domains) { - const LilvNode* domain_node = lilv_nodes_get(domains, d); - const Raul::URI domain(lilv_node_as_uri(domain_node)); - if (types.count(domain)) { - ++n_matching_domains; - } - } - - if (lilv_nodes_size(domains) == 0 || ( - n_matching_domains > 0 && - n_matching_domains == lilv_nodes_size(domains))) { - properties.insert(Raul::URI(lilv_node_as_uri(prop))); - } - - lilv_nodes_free(domains); - } - } - - lilv_node_free(rdfs_domain); - lilv_node_free(rdf_Property); - lilv_node_free(rdf_type); - - return properties; -} - -static Glib::ustring -get_label(World* world, const LilvNode* node) -{ - LilvNode* rdfs_label = lilv_new_uri( - world->lilv_world(), LILV_NS_RDFS "label"); - LilvNodes* labels = lilv_world_find_nodes( - world->lilv_world(), node, rdfs_label, NULL); - - const LilvNode* first = lilv_nodes_get_first(labels); - Glib::ustring label = first ? lilv_node_as_string(first) : ""; - - lilv_nodes_free(labels); - lilv_node_free(rdfs_label); - return label; -} - void PropertiesWindow::add_property(const Raul::URI& uri, const Raul::Atom& value) { @@ -236,7 +113,7 @@ PropertiesWindow::add_property(const Raul::URI& uri, const Raul::Atom& value) // Column 0: Property LilvNode* prop = lilv_new_uri(world->lilv_world(), uri.c_str()); - Glib::ustring lab_text = get_label(world, prop); + Glib::ustring lab_text = RDFS::label(world, prop); if (lab_text.empty()) { lab_text = world->rdf_world()->prefixes().qualify(uri); } @@ -278,10 +155,10 @@ PropertiesWindow::set_object(SharedPtr model) world->lilv_world(), LILV_NS_RDF "type"); // Populate key combo - const URISet props = get_properties(world, model); + const URISet props = RDFS::properties(world, model); for (URISet::const_iterator p = props.begin(); p != props.end(); ++p) { LilvNode* prop = lilv_new_uri(world->lilv_world(), p->c_str()); - const Glib::ustring label = get_label(world, prop); + const Glib::ustring label = RDFS::label(world, prop); if (label.empty()) { continue; } @@ -293,7 +170,7 @@ PropertiesWindow::set_object(SharedPtr model) LILV_FOREACH(nodes, r, range) { ranges.insert(Raul::URI(lilv_node_as_string(lilv_nodes_get(range, r)))); } - get_classes(world, ranges, false); + RDFS::classes(world, ranges, false); bool show = false; for (URISet::const_iterator i = ranges.begin(); i != ranges.end(); ++i) { @@ -373,6 +250,16 @@ PropertiesWindow::create_value_widget(const Raul::URI& uri, const Raul::Atom& va sigc::mem_fun(this, &PropertiesWindow::value_edited), uri)); return widget; + } else if (value.type() == forge.URID) { + const char* val_uri = _app->world()->uri_map().unmap_uri(value.get_int32()); + Gtk::Entry* widget = manage(new Gtk::Entry()); + if (val_uri) { + widget->set_text(val_uri); + } + widget->signal_changed().connect(sigc::bind( + sigc::mem_fun(this, &PropertiesWindow::value_edited), + uri)); + return widget; } else if (value.type() == forge.String) { Gtk::Entry* widget = manage(new Gtk::Entry()); widget->set_text(value.get_string()); @@ -382,8 +269,8 @@ PropertiesWindow::create_value_widget(const Raul::URI& uri, const Raul::Atom& va return widget; } - _app->log().error(Raul::fmt("Unable to create widget for value %1%\n") - % forge.str(value)); + _app->log().error(Raul::fmt("Unable to create widget for value %1% type %2%\n") + % forge.str(value) % value.type()); return NULL; } @@ -483,19 +370,21 @@ PropertiesWindow::key_changed() { World* world = _app->world(); - const Gtk::ListStore::Row row = *(_key_combo->get_active()); - Glib::ustring prop_uri = row[_combo_columns.uri_col]; + _value_store->clear(); + const Gtk::ListStore::iterator iter = _key_combo->get_active(); + if (!iter) { + return; + } + + const Gtk::ListStore::Row row = *iter; + Glib::ustring prop_uri = row[_combo_columns.uri_col]; if (prop_uri.empty()) { return; } - _value_store->clear(); - LilvNode* rdfs_range = lilv_new_uri( world->lilv_world(), LILV_NS_RDFS "range"); - LilvNode* rdf_type = lilv_new_uri( - world->lilv_world(), LILV_NS_RDF "type"); LilvNode* prop = lilv_new_uri( world->lilv_world(), prop_uri.c_str()); @@ -507,28 +396,13 @@ PropertiesWindow::key_changed() LILV_FOREACH(nodes, r, range) { ranges.insert(Raul::URI(lilv_node_as_string(lilv_nodes_get(range, r)))); } - get_classes(world, ranges, false); + RDFS::classes(world, ranges, false); // Get all objects in range - typedef std::map Values; - Values values; - for (URISet::const_iterator i = ranges.begin(); i != ranges.end(); ++i) { - LilvNode* range = lilv_new_uri(world->lilv_world(), i->c_str()); - LilvNodes* objects = lilv_world_find_nodes( - world->lilv_world(), NULL, rdf_type, range); - LILV_FOREACH(nodes, o, objects) { - const LilvNode* object = lilv_nodes_get(objects, o); - const Glib::ustring label = get_label(world, object); - values.insert( - std::make_pair( - Raul::URI(lilv_node_as_string(object)), - label)); - } - lilv_node_free(range); - } + RDFS::Objects values = RDFS::instances(world, ranges); // Fill value selector with suitable objects - for (Values::const_iterator i = values.begin(); i != values.end(); ++i) { + for (RDFS::Objects::const_iterator i = values.begin(); i != values.end(); ++i) { if (!i->second.empty()) { Gtk::ListStore::iterator vi = _value_store->append(); Gtk::ListStore::Row vrow = *vi; @@ -538,7 +412,6 @@ PropertiesWindow::key_changed() } lilv_node_free(prop); - lilv_node_free(rdf_type); lilv_node_free(rdfs_range); } @@ -587,7 +460,7 @@ void PropertiesWindow::ok_clicked() { apply_clicked(); - cancel_clicked(); + Gtk::Window::hide(); } } // namespace GUI diff --git a/src/gui/RDFS.cpp b/src/gui/RDFS.cpp new file mode 100644 index 00000000..0420d4dd --- /dev/null +++ b/src/gui/RDFS.cpp @@ -0,0 +1,177 @@ +/* + This file is part of Ingen. + Copyright 2007-2012 David Robillard + + Ingen is free software: you can redistribute it and/or modify it under the + terms of the GNU Affero General Public License as published by the Free + Software Foundation, either version 3 of the License, or 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 Affero General Public License for details. + + You should have received a copy of the GNU Affero General Public License + along with Ingen. If not, see . +*/ + +#include "ingen/Resource.hpp" +#include "ingen/World.hpp" +#include "ingen/client/ObjectModel.hpp" +#include "lilv/lilv.h" + +#include "RDFS.hpp" + +namespace Ingen { +namespace GUI { +namespace RDFS { + +Glib::ustring +label(World* world, const LilvNode* node) +{ + LilvNode* rdfs_label = lilv_new_uri( + world->lilv_world(), LILV_NS_RDFS "label"); + LilvNodes* labels = lilv_world_find_nodes( + world->lilv_world(), node, rdfs_label, NULL); + + const LilvNode* first = lilv_nodes_get_first(labels); + Glib::ustring label = first ? lilv_node_as_string(first) : ""; + + lilv_nodes_free(labels); + lilv_node_free(rdfs_label); + return label; +} + +void +classes(World* world, URISet& types, bool super) +{ + LilvNode* rdfs_subClassOf = lilv_new_uri( + world->lilv_world(), LILV_NS_RDFS "subClassOf"); + + unsigned added = 0; + do { + added = 0; + URISet klasses; + for (URISet::iterator t = types.begin(); t != types.end(); ++t) { + LilvNode* type = lilv_new_uri(world->lilv_world(), t->c_str()); + LilvNodes* matches = (super) + ? lilv_world_find_nodes( + world->lilv_world(), type, rdfs_subClassOf, NULL) + : lilv_world_find_nodes( + world->lilv_world(), NULL, rdfs_subClassOf, type); + LILV_FOREACH(nodes, m, matches) { + const LilvNode* klass_node = lilv_nodes_get(matches, m); + if (lilv_node_is_uri(klass_node)) { + Raul::URI klass(lilv_node_as_uri(klass_node)); + if (!types.count(klass)) { + ++added; + klasses.insert(klass); + } + } + } + lilv_nodes_free(matches); + lilv_node_free(type); + } + types.insert(klasses.begin(), klasses.end()); + } while (added > 0); + + lilv_node_free(rdfs_subClassOf); +} + +URISet +types(World* world, SharedPtr model) +{ + typedef Resource::Properties::const_iterator PropIter; + typedef std::pair PropRange; + + // Start with every rdf:type + URISet types; + PropRange range = model->properties().equal_range(world->uris().rdf_type); + for (PropIter t = range.first; t != range.second; ++t) { + types.insert(Raul::URI(t->second.get_uri())); + if (world->uris().ingen_Graph == t->second.get_uri()) { + // Add lv2:Plugin as a type for graphs so plugin properties show up + types.insert(world->uris().lv2_Plugin); + } + } + + // Add every superclass of every type, recursively + RDFS::classes(world, types, true); + + return types; +} + +URISet +properties(World* world, SharedPtr model) +{ + URISet properties; + URISet types = RDFS::types(world, model); + + LilvNode* rdf_type = lilv_new_uri(world->lilv_world(), + LILV_NS_RDF "type"); + LilvNode* rdf_Property = lilv_new_uri(world->lilv_world(), + LILV_NS_RDF "Property"); + LilvNode* rdfs_domain = lilv_new_uri(world->lilv_world(), + LILV_NS_RDFS "domain"); + + LilvNodes* props = lilv_world_find_nodes( + world->lilv_world(), NULL, rdf_type, rdf_Property); + LILV_FOREACH(nodes, p, props) { + const LilvNode* prop = lilv_nodes_get(props, p); + if (lilv_node_is_uri(prop)) { + LilvNodes* domains = lilv_world_find_nodes( + world->lilv_world(), prop, rdfs_domain, NULL); + unsigned n_matching_domains = 0; + LILV_FOREACH(nodes, d, domains) { + const LilvNode* domain_node = lilv_nodes_get(domains, d); + const Raul::URI domain(lilv_node_as_uri(domain_node)); + if (types.count(domain)) { + ++n_matching_domains; + } + } + + if (lilv_nodes_size(domains) == 0 || ( + n_matching_domains > 0 && + n_matching_domains == lilv_nodes_size(domains))) { + properties.insert(Raul::URI(lilv_node_as_uri(prop))); + } + + lilv_nodes_free(domains); + } + } + + lilv_node_free(rdfs_domain); + lilv_node_free(rdf_Property); + lilv_node_free(rdf_type); + + return properties; +} + +Objects +instances(World* world, const URISet& types) +{ + LilvNode* rdf_type = lilv_new_uri( + world->lilv_world(), LILV_NS_RDF "type"); + + Objects result; + for (URISet::const_iterator i = types.begin(); i != types.end(); ++i) { + LilvNode* type = lilv_new_uri(world->lilv_world(), i->c_str()); + LilvNodes* objects = lilv_world_find_nodes( + world->lilv_world(), NULL, rdf_type, type); + LILV_FOREACH(nodes, o, objects) { + const LilvNode* object = lilv_nodes_get(objects, o); + const Glib::ustring label = RDFS::label(world, object); + result.insert( + std::make_pair( + Raul::URI(lilv_node_as_string(object)), + label)); + } + lilv_node_free(type); + } + + lilv_node_free(rdf_type); + return result; +} + +} // namespace RDFS +} // namespace GUI +} // namespace Ingen diff --git a/src/gui/RDFS.hpp b/src/gui/RDFS.hpp new file mode 100644 index 00000000..bdc0a7a1 --- /dev/null +++ b/src/gui/RDFS.hpp @@ -0,0 +1,67 @@ +/* + This file is part of Ingen. + Copyright 2012 David Robillard + + Ingen is free software: you can redistribute it and/or modify it under the + terms of the GNU Affero General Public License as published by the Free + Software Foundation, either version 3 of the License, or 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 Affero General Public License for details. + + You should have received a copy of the GNU Affero General Public License + along with Ingen. If not, see . +*/ + +#ifndef INGEN_GUI_RDF_HPP +#define INGEN_GUI_RDF_HPP + +#include +#include + +#include + +#include "raul/URI.hpp" +#include "raul/SharedPtr.hpp" + +namespace Ingen { + +class World; + +namespace Client { class ObjectModel; } + +namespace GUI { + +namespace RDFS { + +/** Set of URIs. */ +typedef std::set URISet; + +/** Map of object labels, keyed by object URI. */ +typedef std::map Objects; + +/** Return the label of @p node. */ +Glib::ustring +label(World* world, const LilvNode* node); + +/** Set @p types to its super/sub class closure. + * @param super If true, find all superclasses, otherwise all subclasses + */ +void classes(World* world, URISet& types, bool super); + +/** Get all instances of any class in @p types. */ +Objects +instances(World* world, const URISet& types); + +/** Get all the types which @p model is an instance of. */ +URISet types(World* world, SharedPtr model); + +/** Get all the properties with domains appropriate for @p model. */ +URISet properties(World* world, SharedPtr model); + +} // namespace RDFS +} // namespace GUI +} // namespace Ingen + +#endif // INGEN_GUI_RDF_HPP diff --git a/src/gui/wscript b/src/gui/wscript index 1f0a567f..982c93d8 100644 --- a/src/gui/wscript +++ b/src/gui/wscript @@ -48,6 +48,7 @@ def build(bld): PortMenu.cpp PortPropertiesWindow.cpp PropertiesWindow.cpp + RDFS.cpp RenameWindow.cpp Style.cpp SubgraphModule.cpp diff --git a/src/server/Buffer.hpp b/src/server/Buffer.hpp index 0f237e67..c710f4df 100644 --- a/src/server/Buffer.hpp +++ b/src/server/Buffer.hpp @@ -54,6 +54,8 @@ public: inline LV2_URID type() const { return _type; } inline uint32_t capacity() const { return _capacity; } + inline void set_type(LV2_URID t) { _type = t; } + inline bool is_audio() const { return _type == _factory.uris().atom_Sound; } diff --git a/src/server/BufferFactory.cpp b/src/server/BufferFactory.cpp index da459705..064b5080 100644 --- a/src/server/BufferFactory.cpp +++ b/src/server/BufferFactory.cpp @@ -38,6 +38,7 @@ BufferFactory::~BufferFactory() _silent_buffer.reset(); free_list(_free_audio.get()); free_list(_free_control.get()); + free_list(_free_sequence.get()); free_list(_free_object.get()); } @@ -77,6 +78,8 @@ BufferFactory::default_size(LV2_URID type) const return sizeof(LV2_Atom_Float); } else if (type == _uris.atom_Sound) { return audio_buffer_size(_engine.driver()->block_length()); + } else if (type == _uris.atom_URID) { + return sizeof(LV2_Atom_URID); } else if (type == _uris.atom_Sequence) { if (_seq_size == 0) { return _engine.driver()->block_length() * SEQ_BYTES_PER_FRAME; @@ -95,7 +98,7 @@ BufferFactory::get(LV2_URID type, bool force_create) { Raul::AtomicPtr& head_ptr = free_list(type); - Buffer* try_head = NULL; + Buffer* try_head = NULL; if (!force_create) { Buffer* next; @@ -117,6 +120,7 @@ BufferFactory::get(LV2_URID type, } try_head->_next = NULL; + try_head->set_type(type); return BufferRef(try_head); } diff --git a/src/server/BufferFactory.hpp b/src/server/BufferFactory.hpp index e466e969..1fe3a91e 100644 --- a/src/server/BufferFactory.hpp +++ b/src/server/BufferFactory.hpp @@ -74,6 +74,8 @@ private: return _free_control; } else if (type == _uris.atom_Sound) { return _free_audio; + } else if (type == _uris.atom_Sequence) { + return _free_sequence; } else { return _free_object; } @@ -83,6 +85,7 @@ private: Raul::AtomicPtr _free_audio; Raul::AtomicPtr _free_control; + Raul::AtomicPtr _free_sequence; Raul::AtomicPtr _free_object; Glib::Mutex _mutex; diff --git a/src/server/LV2Block.cpp b/src/server/LV2Block.cpp index 47a0af4f..e334c1f9 100644 --- a/src/server/LV2Block.cpp +++ b/src/server/LV2Block.cpp @@ -282,6 +282,13 @@ LV2Block::instantiate(BufferFactory& bufs) } uint32_t port_buffer_size = bufs.default_size(buffer_type); + if (port_buffer_size == 0) { + parent_graph()->engine().log().error( + Raul::fmt("<%1%> port `%2%' has unknown buffer type\n") + % _lv2_plugin->uri().c_str() % port_sym.c_str()); + ret = false; + break; + } if (port_type == PortType::ATOM) { // Get default value, and its length @@ -293,10 +300,18 @@ LV2Block::instantiate(BufferFactory& bufs) const uint32_t str_val_len = strlen(str_val); val = forge.alloc(str_val); port_buffer_size = std::max(port_buffer_size, str_val_len); + } else if (lilv_node_is_uri(d)) { + const char* uri_val = lilv_node_as_uri(d); + val = forge.make_urid( + bufs.engine().world()->uri_map().map_uri(uri_val)); } } lilv_nodes_free(defaults); + if (!val.type() && buffer_type == _uris.atom_URID) { + val = forge.make_urid(0); + } + // Get minimum size, if set in data LilvNodes* sizes = lilv_port_get_value(plug, id, info->rsz_minimumSize); LILV_FOREACH(nodes, i, sizes) { @@ -318,14 +333,15 @@ LV2Block::instantiate(BufferFactory& bufs) if (port_type == PortType::UNKNOWN || direction == UNKNOWN) { parent_graph()->engine().log().error( - Raul::fmt("<%1%> port %2% has unknown type or direction\n") + Raul::fmt("<%1%> port `%2%' has unknown type or direction\n") % _lv2_plugin->uri().c_str() % port_sym.c_str()); ret = false; break; } - if (!val.type()) + if (!val.type() && port_type != PortType::ATOM) { val = forge.make(isnan(def_values[j]) ? 0.0f : def_values[j]); + } PortImpl* port = (direction == INPUT) ? static_cast( @@ -350,7 +366,10 @@ LV2Block::instantiate(BufferFactory& bufs) } // Inherit certain properties from plugin port - LilvNode* preds[] = { info->lv2_portProperty, info->atom_supports, 0 }; + const LilvNode* preds[] = { info->lv2_designation, + info->lv2_portProperty, + info->atom_supports, + 0 }; for (int p = 0; preds[p]; ++p) { LilvNodes* values = lilv_port_get_value(plug, id, preds[p]); LILV_FOREACH(nodes, v, values) { diff --git a/src/server/LV2Info.cpp b/src/server/LV2Info.cpp index 744a30b2..841ee0fd 100644 --- a/src/server/LV2Info.cpp +++ b/src/server/LV2Info.cpp @@ -40,6 +40,7 @@ LV2Info::LV2Info(Ingen::World* world) , lv2_InputPort(lilv_new_uri(world->lilv_world(), LV2_CORE__InputPort)) , lv2_OutputPort(lilv_new_uri(world->lilv_world(), LV2_CORE__OutputPort)) , lv2_default(lilv_new_uri(world->lilv_world(), LV2_CORE__default)) + , lv2_designation(lilv_new_uri(world->lilv_world(), LV2_CORE__designation)) , lv2_portProperty(lilv_new_uri(world->lilv_world(), LV2_CORE__portProperty)) , lv2_sampleRate(lilv_new_uri(world->lilv_world(), LV2_CORE__sampleRate)) , morph_AutoMorphPort(lilv_new_uri(world->lilv_world(), LV2_MORPH__AutoMorphPort)) @@ -64,6 +65,7 @@ LV2Info::~LV2Info() lilv_node_free(lv2_InputPort); lilv_node_free(lv2_OutputPort); lilv_node_free(lv2_default); + lilv_node_free(lv2_designation); lilv_node_free(lv2_portProperty); lilv_node_free(lv2_sampleRate); lilv_node_free(morph_AutoMorphPort); diff --git a/src/server/LV2Info.hpp b/src/server/LV2Info.hpp index fd70ea83..1d38b4e1 100644 --- a/src/server/LV2Info.hpp +++ b/src/server/LV2Info.hpp @@ -40,6 +40,7 @@ public: LilvNode* const lv2_InputPort; LilvNode* const lv2_OutputPort; LilvNode* const lv2_default; + LilvNode* const lv2_designation; LilvNode* const lv2_portProperty; LilvNode* const lv2_sampleRate; LilvNode* const morph_AutoMorphPort; diff --git a/src/server/events/SetPortValue.cpp b/src/server/events/SetPortValue.cpp index 14919cee..b3481861 100644 --- a/src/server/events/SetPortValue.cpp +++ b/src/server/events/SetPortValue.cpp @@ -104,6 +104,8 @@ SetPortValue::apply(Context& context) } else { _status = NO_SPACE; } + } else if (buf->type() == uris.atom_URID) { + ((LV2_Atom_URID*)buf->atom())->body = _value.get_int32(); } else { _status = BAD_VALUE_TYPE; } -- cgit v1.2.1