summaryrefslogtreecommitdiffstats
path: root/src/gui
diff options
context:
space:
mode:
authorDavid Robillard <d@drobilla.net>2013-01-08 04:05:01 +0000
committerDavid Robillard <d@drobilla.net>2013-01-08 04:05:01 +0000
commitac408e8d4ce77389e65d69e9a1ff30fd54a25ada (patch)
tree27d3f568c8a8040c345dd61a890dabd08549cd5c /src/gui
parent63d21b23d262b0c5169d54822aa5723b6200c764 (diff)
downloadingen-ac408e8d4ce77389e65d69e9a1ff30fd54a25ada.tar.gz
ingen-ac408e8d4ce77389e65d69e9a1ff30fd54a25ada.tar.bz2
ingen-ac408e8d4ce77389e65d69e9a1ff30fd54a25ada.zip
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
Diffstat (limited to 'src/gui')
-rw-r--r--src/gui/Port.cpp64
-rw-r--r--src/gui/Port.hpp2
-rw-r--r--src/gui/PropertiesWindow.cpp199
-rw-r--r--src/gui/RDFS.cpp177
-rw-r--r--src/gui/RDFS.hpp67
-rw-r--r--src/gui/wscript1
6 files changed, 347 insertions, 163 deletions
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<const BlockModel> block = PtrCast<BlockModel>(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<const ObjectModel> 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<const ObjectModel> model)
-{
- typedef Resource::Properties::const_iterator PropIter;
- typedef std::pair<PropIter, PropIter> 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<const ObjectModel> 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<const ObjectModel> 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<const ObjectModel> 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<Raul::URI, Glib::ustring> 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 <http://drobilla.net/>
+
+ 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 <http://www.gnu.org/licenses/>.
+*/
+
+#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<const Client::ObjectModel> model)
+{
+ typedef Resource::Properties::const_iterator PropIter;
+ typedef std::pair<PropIter, PropIter> 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<const Client::ObjectModel> 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 <http://drobilla.net/>
+
+ 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 <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef INGEN_GUI_RDF_HPP
+#define INGEN_GUI_RDF_HPP
+
+#include <map>
+#include <set>
+
+#include <glibmm/ustring.h>
+
+#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<Raul::URI> URISet;
+
+/** Map of object labels, keyed by object URI. */
+typedef std::map<Raul::URI, Glib::ustring> 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<const Client::ObjectModel> model);
+
+/** Get all the properties with domains appropriate for @p model. */
+URISet properties(World* world, SharedPtr<const Client::ObjectModel> 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