summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorDavid Robillard <d@drobilla.net>2015-04-01 04:21:18 +0000
committerDavid Robillard <d@drobilla.net>2015-04-01 04:21:18 +0000
commit85aaff2bf3420e7c4a1d4db3c093c589b0c25e78 (patch)
tree13d21f618fd689575d3e7ccf912e26f5cf0c2fbc /src
parentc0da1cf368b7d43c9c886b81768b4a62a07fae3f (diff)
downloadingen-85aaff2bf3420e7c4a1d4db3c093c589b0c25e78.tar.gz
ingen-85aaff2bf3420e7c4a1d4db3c093c589b0c25e78.tar.bz2
ingen-85aaff2bf3420e7c4a1d4db3c093c589b0c25e78.zip
Support adding datatype properties.
git-svn-id: http://svn.drobilla.net/lad/trunk/ingen@5649 a436a847-0d15-0410-975c-d299462d15a1
Diffstat (limited to 'src')
-rw-r--r--src/gui/PropertiesWindow.cpp115
-rw-r--r--src/gui/PropertiesWindow.hpp5
-rw-r--r--src/gui/RDFS.cpp36
-rw-r--r--src/gui/RDFS.hpp5
4 files changed, 126 insertions, 35 deletions
diff --git a/src/gui/PropertiesWindow.cpp b/src/gui/PropertiesWindow.cpp
index 6db19e65..78b92c3d 100644
--- a/src/gui/PropertiesWindow.cpp
+++ b/src/gui/PropertiesWindow.cpp
@@ -144,6 +144,56 @@ PropertiesWindow::add_property(const Raul::URI& key, const Atom& value)
lilv_node_free(prop);
}
+bool
+PropertiesWindow::datatype_supported(const RDFS::URISet& types,
+ Raul::URI* widget_type)
+{
+ if (types.find(_app->uris().atom_Int) != types.end()) {
+ *widget_type = _app->uris().atom_Int;
+ return true;
+ } else if (types.find(_app->uris().atom_Float) != types.end()) {
+ *widget_type = _app->uris().atom_Float;
+ return true;
+ } else if (types.find(_app->uris().atom_Bool) != types.end()) {
+ *widget_type = _app->uris().atom_Bool;
+ return true;
+ } else if (types.find(_app->uris().atom_String) != types.end()) {
+ *widget_type = _app->uris().atom_String;
+ return true;
+ } else if (types.find(_app->uris().atom_URID) != types.end()) {
+ *widget_type = _app->uris().atom_URID;
+ return true;
+ }
+
+ return false;
+}
+
+bool
+PropertiesWindow::class_supported(const RDFS::URISet& types)
+{
+ World* world = _app->world();
+ LilvNode* rdf_type = lilv_new_uri(
+ world->lilv_world(), LILV_NS_RDF "type");
+
+ for (const auto& t : types) {
+ LilvNode* range = lilv_new_uri(world->lilv_world(), t.c_str());
+ LilvNodes* instances = lilv_world_find_nodes(
+ world->lilv_world(), NULL, rdf_type, range);
+
+ const bool has_instance = (lilv_nodes_size(instances) > 0);
+
+ lilv_nodes_free(instances);
+ lilv_node_free(range);
+ if (has_instance) {
+ lilv_node_free(rdf_type);
+ return true;
+ }
+ }
+
+ lilv_node_free(rdf_type);
+ return false;
+}
+
/** Set the node this window is associated with.
* This function MUST be called before using this object in any way.
*/
@@ -159,39 +209,37 @@ PropertiesWindow::set_object(SPtr<const ObjectModel> model)
LilvNode* rdf_type = lilv_new_uri(
world->lilv_world(), LILV_NS_RDF "type");
+ LilvNode* rdfs_DataType = lilv_new_uri(
+ world->lilv_world(), LILV_NS_RDFS "Datatype");
// Populate key combo
const URISet props = RDFS::properties(world, model);
std::map<std::string, Raul::URI> entries;
for (const auto& p : props) {
- LilvNode* prop = lilv_new_uri(world->lilv_world(), p.c_str());
- const std::string label = RDFS::label(world, prop);
- if (label.empty()) {
+ LilvNode* prop = lilv_new_uri(world->lilv_world(), p.c_str());
+ const std::string label = RDFS::label(world, prop);
+ URISet ranges = RDFS::range(world, prop, true);
+
+ lilv_node_free(prop);
+ if (label.empty() || ranges.empty()) {
+ // Property has no label or range, can't show a widget for it
continue;
}
- // Get all classes in the range of this property (including subclasses)
- URISet ranges = RDFS::range(world, prop, true);
- bool show = false;
- for (const auto& r : ranges) {
- LilvNode* range = lilv_new_uri(world->lilv_world(), r.c_str());
- LilvNodes* objects = lilv_world_find_nodes(
- world->lilv_world(), NULL, rdf_type, range);
-
- show = lilv_nodes_get_first(objects);
-
- lilv_nodes_free(objects);
- lilv_node_free(range);
- if (show) {
- break; // At least one applicable object
+ LilvNode* range = lilv_new_uri(world->lilv_world(), (*ranges.begin()).c_str());
+ if (RDFS::is_a(world, range, rdfs_DataType)) {
+ // Range is a datatype, show if type or any subtype is supported
+ RDFS::datatypes(_app->world(), ranges, false);
+ Raul::URI widget_type("urn:nothing");
+ if (datatype_supported(ranges, &widget_type)) {
+ entries.insert(std::make_pair(label, p));
+ }
+ } else {
+ // Range is presumably a class, show if any instances are known
+ if (class_supported(ranges)) {
+ entries.insert(std::make_pair(label, p));
}
}
-
- if (show || ranges.empty()) {
- entries.insert(std::make_pair(label, p));
- }
-
- lilv_node_free(prop);
}
for (const auto& e : entries) {
@@ -201,6 +249,7 @@ PropertiesWindow::set_object(SPtr<const ObjectModel> model)
row[_combo_columns.label_col] = e.first;
}
+ lilv_node_free(rdfs_DataType);
lilv_node_free(rdf_type);
for (const auto& p : model->properties()) {
@@ -224,9 +273,20 @@ PropertiesWindow::create_value_widget(const Raul::URI& key,
return NULL;
}
- const Raul::URI type(type_uri);
- Ingen::World* world = _app->world();
- LilvWorld* lworld = world->lilv_world();
+ Raul::URI type(type_uri);
+ Ingen::World* world = _app->world();
+ LilvWorld* lworld = world->lilv_world();
+
+ // See if type is a datatype we support
+ std::set<Raul::URI> types{type};
+ RDFS::datatypes(_app->world(), types, false);
+
+ Raul::URI widget_type("urn:nothing");
+ const bool supported = datatype_supported(types, &widget_type);
+ if (supported) {
+ type = widget_type;
+ _value_type = _app->world()->uri_map().map_uri(type);
+ }
if (type == _app->uris().atom_Int) {
Gtk::SpinButton* widget = manage(new Gtk::SpinButton(0.0, 0));
@@ -449,8 +509,8 @@ PropertiesWindow::active_key() const
void
PropertiesWindow::key_changed()
{
+ _value_bin->remove();
if (!_key_combo->get_active()) {
- _value_bin->remove();
return;
}
@@ -467,7 +527,6 @@ PropertiesWindow::key_changed()
if (value_widget) {
_add_button->set_sensitive(true);
- _value_type = _app->world()->uri_map().map_uri(r);
_value_bin->remove();
_value_bin->add(*Gtk::manage(value_widget));
_value_bin->show_all();
diff --git a/src/gui/PropertiesWindow.hpp b/src/gui/PropertiesWindow.hpp
index 15842c48..48ec6faa 100644
--- a/src/gui/PropertiesWindow.hpp
+++ b/src/gui/PropertiesWindow.hpp
@@ -81,6 +81,11 @@ private:
void remove_property(const Raul::URI& key, const Atom& value);
void on_change(const Raul::URI& key);
+ bool datatype_supported(const std::set<Raul::URI>& types,
+ Raul::URI* widget_type);
+
+ bool class_supported(const std::set<Raul::URI>& type);
+
Gtk::Widget* create_value_widget(const Raul::URI& key,
const char* type_uri,
const Atom& value = Atom());
diff --git a/src/gui/RDFS.cpp b/src/gui/RDFS.cpp
index 458c0bc5..10367bc8 100644
--- a/src/gui/RDFS.cpp
+++ b/src/gui/RDFS.cpp
@@ -57,12 +57,9 @@ comment(World* world, const LilvNode* node)
return comment;
}
-void
-classes(World* world, URISet& types, bool super)
+static void
+closure(World* world, const LilvNode* pred, URISet& types, bool super)
{
- LilvNode* rdfs_subClassOf = lilv_new_uri(
- world->lilv_world(), LILV_NS_RDFS "subClassOf");
-
unsigned added = 0;
do {
added = 0;
@@ -71,9 +68,9 @@ classes(World* world, URISet& types, bool super)
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)
+ world->lilv_world(), type, pred, NULL)
: lilv_world_find_nodes(
- world->lilv_world(), NULL, rdfs_subClassOf, type);
+ world->lilv_world(), NULL, pred, type);
LILV_FOREACH(nodes, m, matches) {
const LilvNode* klass_node = lilv_nodes_get(matches, m);
if (lilv_node_is_uri(klass_node)) {
@@ -89,10 +86,30 @@ classes(World* world, URISet& types, bool super)
}
types.insert(klasses.begin(), klasses.end());
} while (added > 0);
+}
+
+void
+classes(World* world, URISet& types, bool super)
+{
+ LilvNode* rdfs_subClassOf = lilv_new_uri(
+ world->lilv_world(), LILV_NS_RDFS "subClassOf");
+
+ closure(world, rdfs_subClassOf, types, super);
lilv_node_free(rdfs_subClassOf);
}
+void
+datatypes(World* world, URISet& types, bool super)
+{
+ LilvNode* owl_onDatatype = lilv_new_uri(
+ world->lilv_world(), LILV_NS_OWL "onDatatype");
+
+ closure(world, owl_onDatatype, types, super);
+
+ lilv_node_free(owl_onDatatype);
+}
+
URISet
types(World* world, SPtr<const Client::ObjectModel> model)
{
@@ -139,6 +156,11 @@ properties(World* world, SPtr<const Client::ObjectModel> model)
unsigned n_matching_domains = 0;
LILV_FOREACH(nodes, d, domains) {
const LilvNode* domain_node = lilv_nodes_get(domains, d);
+ if (!lilv_node_is_uri(domain_node)) {
+ // TODO: Blank node domains (e.g. unions)
+ continue;
+ }
+
const Raul::URI domain(lilv_node_as_uri(domain_node));
if (types.count(domain)) {
++n_matching_domains;
diff --git a/src/gui/RDFS.hpp b/src/gui/RDFS.hpp
index 52931aaf..bb6e0684 100644
--- a/src/gui/RDFS.hpp
+++ b/src/gui/RDFS.hpp
@@ -52,6 +52,11 @@ std::string comment(World* world, const LilvNode* node);
*/
void classes(World* world, URISet& types, bool super);
+/** Set `types` to its super/sub datatype closure.
+ * @param super If true, find all supertypes, otherwise all subtypes.
+ */
+void datatypes(World* world, URISet& types, bool super);
+
/** Get all instances of any class in `types`. */
Objects instances(World* world, const URISet& types);