From b15864870d34a1188eda93ad215734275037278e Mon Sep 17 00:00:00 2001 From: David Robillard Date: Mon, 11 Sep 2006 11:10:35 +0000 Subject: Switched homebrew CountedPtr to boost::shared_ptr. Factories for patch windows, controller. Robustness updated in many places. Tons of cleanups, rewrites, bugfixes, etc. git-svn-id: http://svn.drobilla.net/lad/ingen@128 a436a847-0d15-0410-975c-d299462d15a1 --- src/libs/client/ConnectionModel.cpp | 6 +- src/libs/client/Makefile.am | 2 +- src/libs/client/ModelClientInterface.cpp | 22 +-- src/libs/client/ModelClientInterface.h | 13 +- src/libs/client/NodeModel.cpp | 44 +++-- src/libs/client/NodeModel.h | 8 +- src/libs/client/ObjectModel.cpp | 36 ++-- src/libs/client/ObjectModel.h | 26 +-- src/libs/client/PatchLibrarian.cpp | 80 ++++----- src/libs/client/PatchLibrarian.h | 14 +- src/libs/client/PatchModel.cpp | 50 ++++-- src/libs/client/PatchModel.h | 4 +- src/libs/client/PortModel.h | 2 + src/libs/client/Store.cpp | 299 ++++++++++++++----------------- src/libs/client/Store.h | 42 +++-- 15 files changed, 341 insertions(+), 307 deletions(-) (limited to 'src/libs/client') diff --git a/src/libs/client/ConnectionModel.cpp b/src/libs/client/ConnectionModel.cpp index 778678f7..421b620d 100644 --- a/src/libs/client/ConnectionModel.cpp +++ b/src/libs/client/ConnectionModel.cpp @@ -24,9 +24,7 @@ namespace Client { ConnectionModel::ConnectionModel(const Path& src_port, const Path& dst_port) : _src_port_path(src_port), - _dst_port_path(dst_port), - _src_port(NULL), - _dst_port(NULL) + _dst_port_path(dst_port) { // Be sure connection is within one patch //assert(_src_port_path.parent().parent() @@ -73,7 +71,7 @@ ConnectionModel::patch_path() const // Direct connection from patch input to patch output (pass through) // (parent patch is parent of ports) if (_src_port->parent() == _dst_port->parent()) { - CountedPtr parent_patch = _src_port->parent(); + CountedPtr parent_patch = PtrCast(_src_port->parent()); if (parent_patch) return parent_patch->path(); } diff --git a/src/libs/client/Makefile.am b/src/libs/client/Makefile.am index f29529e5..23723f11 100644 --- a/src/libs/client/Makefile.am +++ b/src/libs/client/Makefile.am @@ -1,4 +1,4 @@ -AM_CXXFLAGS = -I$(top_srcdir)/src/common -fno-exceptions +AM_CXXFLAGS = -I$(top_srcdir)/src/common if BUILD_CLIENT_LIB noinst_LTLIBRARIES = libomclient.la diff --git a/src/libs/client/ModelClientInterface.cpp b/src/libs/client/ModelClientInterface.cpp index 440f2a73..deb37187 100644 --- a/src/libs/client/ModelClientInterface.cpp +++ b/src/libs/client/ModelClientInterface.cpp @@ -26,31 +26,31 @@ namespace Client { void -ModelClientInterface::new_plugin_model(PluginModel* pi) +ModelClientInterface::new_plugin_model(CountedPtr pi) { } void -ModelClientInterface::new_patch_model(PatchModel* pm) +ModelClientInterface::new_patch_model(CountedPtr pm) { } void -ModelClientInterface::new_node_model(NodeModel* nm) +ModelClientInterface::new_node_model(CountedPtr nm) { } void -ModelClientInterface::new_port_model(PortModel* port_info) +ModelClientInterface::new_port_model(CountedPtr port_info) { } void -ModelClientInterface::connection_model(ConnectionModel* cm) +ModelClientInterface::connection_model(CountedPtr cm) { } @@ -67,7 +67,7 @@ ModelClientInterface::new_plugin(string type, string uri, string name) { - PluginModel* plugin = new PluginModel(type, uri); + CountedPtr plugin(new PluginModel(type, uri)); plugin->name(name); new_plugin_model(plugin); } @@ -77,7 +77,7 @@ ModelClientInterface::new_plugin(string type, void ModelClientInterface::new_patch(string path, uint32_t poly) { - PatchModel* pm = new PatchModel(path, poly); + CountedPtr pm(new PatchModel(path, poly)); //PluginModel* pi = new PluginModel(PluginModel::Patch); //pm->plugin(pi); new_patch_model(pm); @@ -94,9 +94,9 @@ ModelClientInterface::new_node(string plugin_type, { cerr << "FIXME: NEW NODE\n"; - PluginModel* plugin = new PluginModel(plugin_type, plugin_uri); + CountedPtr plugin(new PluginModel(plugin_type, plugin_uri)); - NodeModel* nm = new NodeModel(plugin, node_path); + CountedPtr nm(new NodeModel(plugin, node_path)); new_node_model(nm); } @@ -116,7 +116,7 @@ ModelClientInterface::new_port(string path, PortModel::Direction pdir = is_output ? PortModel::OUTPUT : PortModel::INPUT; - PortModel* port_model = new PortModel(path, ptype, pdir); + CountedPtr port_model(new PortModel(path, ptype, pdir)); new_port_model(port_model); } @@ -126,7 +126,7 @@ void ModelClientInterface::connection(string src_port_path, string dst_port_path) { - connection_model(new ConnectionModel(src_port_path, dst_port_path)); + connection_model(CountedPtr(new ConnectionModel(src_port_path, dst_port_path))); } diff --git a/src/libs/client/ModelClientInterface.h b/src/libs/client/ModelClientInterface.h index 84472137..9b467fa6 100644 --- a/src/libs/client/ModelClientInterface.h +++ b/src/libs/client/ModelClientInterface.h @@ -21,6 +21,7 @@ #include using std::string; using std::auto_ptr; #include "interface/ClientInterface.h" +#include "util/CountedPtr.h" namespace Ingen { namespace Client { @@ -49,13 +50,11 @@ public: virtual ~ModelClientInterface() {} - // FIXME: make these auto_ptr's - - virtual void new_plugin_model(PluginModel* pi); - virtual void new_patch_model(PatchModel* pm); - virtual void new_node_model(NodeModel* nm); - virtual void new_port_model(PortModel* port_info); - virtual void connection_model(ConnectionModel* cm); + virtual void new_plugin_model(CountedPtr pi); + virtual void new_patch_model(CountedPtr pm); + virtual void new_node_model(CountedPtr nm); + virtual void new_port_model(CountedPtr port_info); + virtual void connection_model(CountedPtr cm); // ClientInterface functions to drive the above: diff --git a/src/libs/client/NodeModel.cpp b/src/libs/client/NodeModel.cpp index f544e812..05b7b43e 100644 --- a/src/libs/client/NodeModel.cpp +++ b/src/libs/client/NodeModel.cpp @@ -25,16 +25,17 @@ namespace Client { NodeModel::NodeModel(CountedPtr plugin, const Path& path) : ObjectModel(path), m_polyphonic(false), + m_plugin_uri(plugin->uri()), m_plugin(plugin), m_x(0.0f), m_y(0.0f) { } -NodeModel::NodeModel(const Path& path) +NodeModel::NodeModel(const string& plugin_uri, const Path& path) : ObjectModel(path), m_polyphonic(false), - m_plugin(NULL), + m_plugin_uri(plugin_uri), m_x(0.0f), m_y(0.0f) { @@ -80,26 +81,47 @@ NodeModel::set_path(const Path& p) ObjectModel::set_path(p); for (PortModelList::iterator i = m_ports.begin(); i != m_ports.end(); ++i) - (*i)->set_path(m_path + "/" + (*i)->name()); + (*i)->set_path(m_path + "/" + (*i)->path().name()); //if (m_parent && old_path.length() > 0) // parent_patch()->rename_node(old_path, p); } +void +NodeModel::add_child(CountedPtr c) +{ + assert(c->parent().get() == this); + + CountedPtr pm = PtrCast(c); + assert(pm); + add_port(pm); +} + + void NodeModel::add_port(CountedPtr pm) { assert(pm); - assert(pm->name() != ""); - assert(pm->path().length() > m_path.length()); - assert(pm->path().substr(0, m_path.length()) == m_path); + assert(pm->path().is_child_of(m_path)); assert(pm->parent().get() == this); - assert(!get_port(pm->name())); - m_ports.push_back(pm); + PortModelList::iterator existing = m_ports.end(); + for (PortModelList::iterator i = m_ports.begin(); i != m_ports.end(); ++i) { + if ((*i)->path() == pm->path()) { + existing = i; + break; + } + } - new_port_sig.emit(pm); + if (existing != m_ports.end()) { + cerr << "Warning: port clash, assimilating old port " << m_path << endl; + pm->assimilate(*existing); + *existing = pm; + } else { + m_ports.push_back(pm); + new_port_sig.emit(pm); + } } @@ -108,9 +130,9 @@ NodeModel::get_port(const string& port_name) { assert(port_name.find("/") == string::npos); for (PortModelList::iterator i = m_ports.begin(); i != m_ports.end(); ++i) - if ((*i)->name() == port_name) + if ((*i)->path().name() == port_name) return (*i); - return NULL; + return CountedPtr(); } diff --git a/src/libs/client/NodeModel.h b/src/libs/client/NodeModel.h index 2a8b6973..f0bede51 100644 --- a/src/libs/client/NodeModel.h +++ b/src/libs/client/NodeModel.h @@ -44,9 +44,12 @@ class PluginModel; class NodeModel : public ObjectModel { public: + NodeModel(const string& plugin_uri, const Path& path); NodeModel(CountedPtr plugin, const Path& path); virtual ~NodeModel(); + void add_child(CountedPtr c); + CountedPtr get_port(const string& port_name); void add_port(CountedPtr pm); void remove_port(const string& port_path); @@ -57,6 +60,8 @@ public: void add_program(int bank, int program, const string& name); void remove_program(int bank, int program); + string plugin_uri() { return m_plugin_uri; } + CountedPtr plugin() const { return m_plugin; } //void plugin(CountedPtr p) { m_plugin = p; } @@ -79,6 +84,7 @@ protected: bool m_polyphonic; PortModelList m_ports; ///< List of ports (instead of map to preserve order) + string m_plugin_uri; ///< Plugin URI (not redundant if PluginModel unknown CountedPtr m_plugin; ///< The plugin this node is an instance of float m_x; ///< Just metadata, here as an optimization for GUI float m_y; ///< Just metadata, here as an optimization for GUI @@ -91,7 +97,7 @@ private: }; -typedef map > NodeModelMap; +typedef map > NodeModelMap; } // namespace Client diff --git a/src/libs/client/ObjectModel.cpp b/src/libs/client/ObjectModel.cpp index 6309a774..b8688585 100644 --- a/src/libs/client/ObjectModel.cpp +++ b/src/libs/client/ObjectModel.cpp @@ -20,10 +20,8 @@ namespace Ingen { namespace Client { -ObjectModel::ObjectModel(const string& path) -: m_path(path), - m_parent(NULL), - m_controller(NULL) +ObjectModel::ObjectModel(const Path& path) +: m_path(path) { } @@ -37,30 +35,38 @@ ObjectModel::get_metadata(const string& key) const { map::const_iterator i = m_metadata.find(key); if (i != m_metadata.end()) - return (*i).second; + return i->second; else return ""; } -/** The base path for children of this Object. - * - * (This is here to avoid needing special cases for the root patch everywhere). - */ -string -ObjectModel::base_path() const +void +ObjectModel::set_controller(CountedPtr c) { - return (path() == "/") ? "/" : path() + "/"; + m_controller = c; } +/** Merge the data of @a model with self, as much as possible. + * + * This will merge the two models, but with any conflict take the version in + * this as correct. The paths of the two models must be equal. + */ void -ObjectModel::set_controller(ObjectController* c) +ObjectModel::assimilate(CountedPtr model) { - assert(m_controller == NULL); - m_controller = c; + assert(m_path == model->path()); + + for (map::const_iterator i = model->metadata().begin(); + i != model->metadata().end(); ++i) { + map::const_iterator i = m_metadata.find(i->first); + if (i == m_metadata.end()) + m_metadata[i->first] = i->second; + } } + } // namespace Client } // namespace Ingen diff --git a/src/libs/client/ObjectModel.h b/src/libs/client/ObjectModel.h index 9daccfd2..9ee4f8c4 100644 --- a/src/libs/client/ObjectModel.h +++ b/src/libs/client/ObjectModel.h @@ -26,6 +26,7 @@ #include #include "util/Path.h" #include "util/CountedPtr.h" +#include "ObjectController.h" using std::string; using std::map; using std::find; using std::cout; using std::cerr; using std::endl; @@ -42,8 +43,8 @@ class ObjectController; class ObjectModel { public: - ObjectModel(const string& path); - ObjectModel() : m_path("/UNINITIALIZED"), m_parent(NULL) {} // FIXME: remove + ObjectModel(const Path& path); + ObjectModel() : m_path("/UNINITIALIZED") {} // FIXME: remove virtual ~ObjectModel() {} @@ -55,23 +56,24 @@ public: inline const Path& path() const { return m_path; } virtual void set_path(const Path& p) { m_path = p; } - CountedPtr parent() const { return m_parent; } + CountedPtr parent() const { return m_parent; } virtual void set_parent(CountedPtr p) { m_parent = p; } - ObjectController* controller() const { return m_controller; } - - void set_controller(ObjectController* c); + virtual void add_child(CountedPtr c) = 0; - // Convenience functions - string base_path() const; - const string name() const { return m_path.name(); } + CountedPtr controller() const { return m_controller; } + void set_controller(CountedPtr c); + + void assimilate(CountedPtr model); + // Signals sigc::signal metadata_update_sig; + sigc::signal destroyed_sig; protected: - Path m_path; - CountedPtr m_parent; - ObjectController* m_controller; // FIXME: remove + Path m_path; + CountedPtr m_parent; + CountedPtr m_controller; map m_metadata; diff --git a/src/libs/client/PatchLibrarian.cpp b/src/libs/client/PatchLibrarian.cpp index 86f3d407..07a98526 100644 --- a/src/libs/client/PatchLibrarian.cpp +++ b/src/libs/client/PatchLibrarian.cpp @@ -35,7 +35,6 @@ #include #include #include -#include // for usleep #include // for atof #include @@ -120,7 +119,7 @@ PatchLibrarian::translate_load_path(const string& path) * - The patch_model has no (Ingen) path */ void -PatchLibrarian::save_patch(PatchModel* patch_model, const string& filename, bool recursive) +PatchLibrarian::save_patch(CountedPtr patch_model, const string& filename, bool recursive) { assert(filename != ""); assert(patch_model->path() != ""); @@ -132,7 +131,6 @@ PatchLibrarian::save_patch(PatchModel* patch_model, const string& filename, bool string dir = filename.substr(0, filename.find_last_of("/")); NodeModel* nm = NULL; - PatchModel* spm = NULL; // subpatch model xmlDocPtr xml_doc = NULL; xmlNodePtr xml_root_node = NULL; @@ -149,7 +147,7 @@ PatchLibrarian::save_patch(PatchModel* patch_model, const string& filename, bool string patch_name; if (patch_model->path() != "/") { - patch_name = patch_model->name(); + patch_name = patch_model->path().name(); } else { patch_name = filename; if (patch_name.find("/") != string::npos) @@ -186,15 +184,17 @@ PatchLibrarian::save_patch(PatchModel* patch_model, const string& filename, bool nm = i->second.get(); if (nm->plugin()->type() == PluginModel::Patch) { // Subpatch - spm = (PatchModel*)i->second.get(); + CountedPtr spm = PtrCast(i->second); + assert(spm); + xml_node = xmlNewChild(xml_root_node, NULL, (xmlChar*)"subpatch", NULL); - xml_child_node = xmlNewChild(xml_node, NULL, (xmlChar*)"name", (xmlChar*)spm->name().c_str()); + xml_child_node = xmlNewChild(xml_node, NULL, (xmlChar*)"name", (xmlChar*)spm->path().name().c_str()); string ref_filename; // No path if (spm->filename() == "") { - ref_filename = spm->name() + ".om"; + ref_filename = spm->path().name() + ".om"; spm->filename(dir +"/"+ ref_filename); // Absolute path } else if (spm->filename().substr(0, 1) == "/") { @@ -230,7 +230,7 @@ PatchLibrarian::save_patch(PatchModel* patch_model, const string& filename, bool } else { // Normal node xml_node = xmlNewChild(xml_root_node, NULL, (xmlChar*)"node", NULL); - xml_child_node = xmlNewChild(xml_node, NULL, (xmlChar*)"name", (xmlChar*)nm->name().c_str()); + xml_child_node = xmlNewChild(xml_node, NULL, (xmlChar*)"name", (xmlChar*)nm->path().name().c_str()); if (!nm->plugin()) break; @@ -321,7 +321,7 @@ PatchLibrarian::save_patch(PatchModel* patch_model, const string& filename, bool float val = pm->value(); xml_node = xmlNewChild(xml_preset_node, NULL, (xmlChar*)"control", NULL); xml_child_node = xmlNewChild(xml_node, NULL, (xmlChar*)"node-name", - (xmlChar*)nm->name().c_str()); + (xmlChar*)nm->path().name().c_str()); xml_child_node = xmlNewChild(xml_node, NULL, (xmlChar*)"port-name", (xmlChar*)pm->path().name().c_str()); snprintf(temp_buf, temp_buf_length, "%f", val); @@ -371,7 +371,7 @@ PatchLibrarian::save_patch(PatchModel* patch_model, const string& filename, bool * Returns the path of the newly created patch. */ string -PatchLibrarian::load_patch(PatchModel* pm, bool wait, bool existing) +PatchLibrarian::load_patch(CountedPtr pm, bool wait, bool existing) { string filename = pm->filename(); @@ -426,7 +426,7 @@ PatchLibrarian::load_patch(PatchModel* pm, bool wait, bool existing) if (load_name) { assert(key != NULL); if (pm->parent()) { - path = pm->parent()->base_path() + string((char*)key); + path = pm->parent()->path().base() + string((char*)key); } else { path = string("/") + string((char*)key); } @@ -464,7 +464,7 @@ PatchLibrarian::load_patch(PatchModel* pm, bool wait, bool existing) if (wait) { //int id = _engine->get_next_request_id(); //_engine->set_wait_response_id(id); - _engine->create_patch_from_model(pm); + _engine->create_patch_from_model(pm.get()); //bool succeeded = _engine->wait_for_response(); // If creating the patch failed, bail out so we don't load all these nodes @@ -474,7 +474,7 @@ PatchLibrarian::load_patch(PatchModel* pm, bool wait, bool existing) return ""; }*/ // FIXME } else { - _engine->create_patch_from_model(pm); + _engine->create_patch_from_model(pm.get()); } } @@ -486,15 +486,14 @@ PatchLibrarian::load_patch(PatchModel* pm, bool wait, bool existing) _engine->set_metadata(pm->path(), "filename", pm->filename()); // Load nodes - NodeModel* nm = NULL; cur = xmlDocGetRootElement(doc)->xmlChildrenNode; while (cur != NULL) { if ((!xmlStrcmp(cur->name, (const xmlChar*)"node"))) { - nm = parse_node(pm, doc, cur); - if (nm != NULL) { - _engine->create_node_from_model(nm); - _engine->set_all_metadata(nm); + CountedPtr nm = parse_node(pm, doc, cur); + if (nm) { + _engine->create_node_from_model(nm.get()); + _engine->set_all_metadata(nm.get()); for (PortModelList::const_iterator j = nm->ports().begin(); j != nm->ports().end(); ++j) { // FIXME: ew snprintf(temp_buf, temp_buf_length, "%f", (*j)->user_min()); @@ -502,8 +501,6 @@ PatchLibrarian::load_patch(PatchModel* pm, bool wait, bool existing) snprintf(temp_buf, temp_buf_length, "%f", (*j)->user_max()); _engine->set_metadata((*j)->path(), "user-max", temp_buf); } - nm = NULL; - usleep(10000); } } cur = cur->next; @@ -526,7 +523,6 @@ PatchLibrarian::load_patch(PatchModel* pm, bool wait, bool existing) cm = parse_connection(pm, doc, cur); if (cm != NULL) { _engine->connect(cm->src_port_path(), cm->dst_port_path()); - usleep(1000); } } cur = cur->next; @@ -549,7 +545,7 @@ PatchLibrarian::load_patch(PatchModel* pm, bool wait, bool existing) xmlFreeDoc(doc); xmlCleanupParser(); - _engine->set_all_metadata(pm); + _engine->set_all_metadata(pm.get()); if (!existing) _engine->enable_patch(pm->path()); @@ -563,11 +559,11 @@ PatchLibrarian::load_patch(PatchModel* pm, bool wait, bool existing) /** Build a NodeModel given a pointer to a Node in a patch file. */ -NodeModel* -PatchLibrarian::parse_node(const PatchModel* parent, xmlDocPtr doc, const xmlNodePtr node) +CountedPtr +PatchLibrarian::parse_node(const CountedPtr parent, xmlDocPtr doc, const xmlNodePtr node) { - PluginModel* plugin = new PluginModel(); - NodeModel* nm = new NodeModel(plugin, "/UNINITIALIZED"); // FIXME: ew + CountedPtr plugin(new PluginModel()); + CountedPtr nm(new NodeModel(plugin, "/UNINITIALIZED")); // FIXME: ew xmlChar* key; xmlNodePtr cur = node->xmlChildrenNode; @@ -576,7 +572,7 @@ PatchLibrarian::parse_node(const PatchModel* parent, xmlDocPtr doc, const xmlNod key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1); if ((!xmlStrcmp(cur->name, (const xmlChar*)"name"))) { - nm->set_path(parent->base_path() + Path::nameify((char*)key)); + nm->set_path(parent->path().base() + Path::nameify((char*)key)); } else if ((!xmlStrcmp(cur->name, (const xmlChar*)"polyphonic"))) { nm->polyphonic(!strcmp((char*)key, "true")); } else if ((!xmlStrcmp(cur->name, (const xmlChar*)"type"))) { @@ -598,7 +594,7 @@ PatchLibrarian::parse_node(const PatchModel* parent, xmlDocPtr doc, const xmlNod key = xmlNodeListGetString(doc, child->xmlChildrenNode, 1); if ((!xmlStrcmp(child->name, (const xmlChar*)"name"))) { - path = nm->base_path() + Path::nameify((char*)key); + path = nm->path().base() + Path::nameify((char*)key); } else if ((!xmlStrcmp(child->name, (const xmlChar*)"user-min"))) { user_min = atof((char*)key); } else if ((!xmlStrcmp(child->name, (const xmlChar*)"user-max"))) { @@ -612,9 +608,9 @@ PatchLibrarian::parse_node(const PatchModel* parent, xmlDocPtr doc, const xmlNod } // FIXME: nasty assumptions - PortModel* pm = new PortModel(path, + CountedPtr pm(new PortModel(path, PortModel::CONTROL, PortModel::INPUT, PortModel::NONE, - 0.0, user_min, user_max); + 0.0, user_min, user_max)); pm->set_parent(nm); nm->add_port(pm); @@ -678,8 +674,7 @@ PatchLibrarian::parse_node(const PatchModel* parent, xmlDocPtr doc, const xmlNod if (nm->path() == "") { cerr << "[PatchLibrarian] Malformed patch file (node tag has empty children)" << endl; cerr << "[PatchLibrarian] Node ignored." << endl; - delete nm; - return NULL; + return CountedPtr(); // Compatibility hacks for old patches } else if (plugin->type() == PluginModel::Internal) { @@ -716,9 +711,8 @@ PatchLibrarian::parse_node(const PatchModel* parent, xmlDocPtr doc, const xmlNod _load_path_translations[old_path + "/out"] = new_path; nm->set_path(new_path); - _engine->set_all_metadata(nm); - delete nm; - return NULL; + _engine->set_all_metadata(nm.get()); + return CountedPtr(); } else { if (plugin->uri() == "") { if (plugin->plug_label() == "note_in") { @@ -740,12 +734,12 @@ PatchLibrarian::parse_node(const PatchModel* parent, xmlDocPtr doc, const xmlNod void -PatchLibrarian::load_subpatch(PatchModel* parent, xmlDocPtr doc, const xmlNodePtr subpatch) +PatchLibrarian::load_subpatch(const CountedPtr parent, xmlDocPtr doc, const xmlNodePtr subpatch) { xmlChar *key; xmlNodePtr cur = subpatch->xmlChildrenNode; - PatchModel* pm = new PatchModel("/UNINITIALIZED", 1); // FIXME: ew + CountedPtr pm(new PatchModel("/UNINITIALIZED", 1)); // FIXME: ew while (cur != NULL) { key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1); @@ -754,7 +748,7 @@ PatchLibrarian::load_subpatch(PatchModel* parent, xmlDocPtr doc, const xmlNodePt if (parent == NULL) pm->set_path(string("/") + (const char*)key); else - pm->set_path(parent->base_path() + (const char*)key); + pm->set_path(parent->path().base() + (const char*)key); } else if ((!xmlStrcmp(cur->name, (const xmlChar*)"polyphony"))) { pm->poly(atoi((const char*)key)); } else if ((!xmlStrcmp(cur->name, (const xmlChar*)"filename"))) { @@ -781,7 +775,7 @@ PatchLibrarian::load_subpatch(PatchModel* parent, xmlDocPtr doc, const xmlNodePt /** Build a ConnectionModel given a pointer to a connection in a patch file. */ ConnectionModel* -PatchLibrarian::parse_connection(const PatchModel* parent, xmlDocPtr doc, const xmlNodePtr node) +PatchLibrarian::parse_connection(const CountedPtr parent, xmlDocPtr doc, const xmlNodePtr node) { //cerr << "[PatchLibrarian] Parsing connection..." << endl; @@ -822,8 +816,8 @@ PatchLibrarian::parse_connection(const PatchModel* parent, xmlDocPtr doc, const dest_port = Path::nameify(dest_port); ConnectionModel* cm = new ConnectionModel( - translate_load_path(parent->base_path() + source_node +"/"+ source_port), - translate_load_path(parent->base_path() + dest_node +"/"+ dest_port)); + translate_load_path(parent->path().base() + source_node +"/"+ source_port), + translate_load_path(parent->path().base() + dest_node +"/"+ dest_port)); return cm; } @@ -832,12 +826,12 @@ PatchLibrarian::parse_connection(const PatchModel* parent, xmlDocPtr doc, const /** Build a PresetModel given a pointer to a preset in a patch file. */ PresetModel* -PatchLibrarian::parse_preset(const PatchModel* patch, xmlDocPtr doc, const xmlNodePtr node) +PatchLibrarian::parse_preset(const CountedPtr patch, xmlDocPtr doc, const xmlNodePtr node) { xmlNodePtr cur = node->xmlChildrenNode; xmlChar* key; - PresetModel* pm = new PresetModel(patch->base_path()); + PresetModel* pm = new PresetModel(patch->path().base()); while (cur != NULL) { key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1); diff --git a/src/libs/client/PatchLibrarian.h b/src/libs/client/PatchLibrarian.h index cd4b4b7a..a900b22f 100644 --- a/src/libs/client/PatchLibrarian.h +++ b/src/libs/client/PatchLibrarian.h @@ -47,7 +47,7 @@ class PatchLibrarian public: // FIXME: return booleans and set an errstr that can be checked or something? - PatchLibrarian(CountedPtr _engine) + PatchLibrarian(CountedPtr engine) : _patch_search_path("."), _engine(_engine) { assert(_engine); @@ -58,8 +58,8 @@ public: string find_file(const string& filename, const string& additional_path = ""); - void save_patch(PatchModel* patch_model, const string& filename, bool recursive); - string load_patch(PatchModel* pm, bool wait = true, bool existing = false); + void save_patch(CountedPtr patch_model, const string& filename, bool recursive); + string load_patch(CountedPtr pm, bool wait = true, bool existing = false); private: string translate_load_path(const string& path); @@ -70,10 +70,10 @@ private: /// Translations of paths from the loading file to actual paths (for deprecated patches) std::map _load_path_translations; - NodeModel* parse_node(const PatchModel* parent, xmlDocPtr doc, const xmlNodePtr cur); - ConnectionModel* parse_connection(const PatchModel* parent, xmlDocPtr doc, const xmlNodePtr cur); - PresetModel* parse_preset(const PatchModel* parent, xmlDocPtr doc, const xmlNodePtr cur); - void load_subpatch(PatchModel* parent, xmlDocPtr doc, const xmlNodePtr cur); + CountedPtr parse_node(const CountedPtr parent, xmlDocPtr doc, const xmlNodePtr cur); + ConnectionModel* parse_connection(const CountedPtr parent, xmlDocPtr doc, const xmlNodePtr cur); + PresetModel* parse_preset(const CountedPtr parent, xmlDocPtr doc, const xmlNodePtr cur); + void load_subpatch(const CountedPtr parent, xmlDocPtr doc, const xmlNodePtr cur); }; diff --git a/src/libs/client/PatchModel.cpp b/src/libs/client/PatchModel.cpp index 5b1348b2..36e829f3 100644 --- a/src/libs/client/PatchModel.cpp +++ b/src/libs/client/PatchModel.cpp @@ -37,7 +37,7 @@ PatchModel::set_path(const Path& new_path) NodeModel::set_path(new_path); for (NodeModelMap::iterator i = m_nodes.begin(); i != m_nodes.end(); ++i) - (*i).second->set_path(m_path +"/"+ (*i).second->name()); + (*i).second->set_path(m_path +"/"+ (*i).second->path().name()); #ifdef DEBUG // Be sure connection paths are updated and sane @@ -50,12 +50,31 @@ PatchModel::set_path(const Path& new_path) } +void +PatchModel::add_child(CountedPtr c) +{ + assert(c->parent().get() == this); + + CountedPtr pm = PtrCast(c); + if (pm) { + add_port(pm); + return; + } + + CountedPtr nm = PtrCast(c); + if (nm) { + add_node(nm); + return; + } +} + + CountedPtr PatchModel::get_node(const string& name) { assert(name.find("/") == string::npos); NodeModelMap::iterator i = m_nodes.find(name); - return ((i != m_nodes.end()) ? (*i).second : CountedPtr(NULL)); + return ((i != m_nodes.end()) ? (*i).second : CountedPtr()); } @@ -63,13 +82,19 @@ void PatchModel::add_node(CountedPtr nm) { assert(nm); - assert(nm->name().find("/") == string::npos); + assert(nm->path().is_child_of(m_path)); assert(nm->parent().get() == this); - assert(m_nodes.find(nm->name()) == m_nodes.end()); - - m_nodes[nm->name()] = nm; - - new_node_sig.emit(nm); + + NodeModelMap::iterator existing = m_nodes.find(nm->path().name()); + + if (existing != m_nodes.end()) { + cerr << "Warning: node clash, assimilating old node " << m_path << endl; + nm->assimilate((*existing).second); + (*existing).second = nm; + } else { + m_nodes[nm->path().name()] = nm; + new_node_sig.emit(nm); + } } @@ -123,15 +148,14 @@ PatchModel::rename_node(const Path& old_path, const Path& new_path) assert(new_path.parent() == path()); NodeModelMap::iterator i = m_nodes.find(old_path.name()); - NodeModel* nm = NULL; if (i != m_nodes.end()) { - nm = (*i).second.get(); + CountedPtr nm = (*i).second; for (list >::iterator j = m_connections.begin(); j != m_connections.end(); ++j) { if ((*j)->src_port_path().parent() == old_path) - (*j)->src_port_path(new_path.base_path() + (*j)->src_port_path().name()); + (*j)->src_port_path(new_path.base() + (*j)->src_port_path().name()); if ((*j)->dst_port_path().parent() == old_path) - (*j)->dst_port_path(new_path.base_path() + (*j)->dst_port_path().name()); + (*j)->dst_port_path(new_path.base() + (*j)->dst_port_path().name()); } m_nodes.erase(i); assert(nm->path() == new_path); @@ -149,7 +173,7 @@ PatchModel::get_connection(const string& src_port_path, const string& dst_port_p for (list >::iterator i = m_connections.begin(); i != m_connections.end(); ++i) if ((*i)->src_port_path() == src_port_path && (*i)->dst_port_path() == dst_port_path) return (*i); - return NULL; + return CountedPtr(); } diff --git a/src/libs/client/PatchModel.h b/src/libs/client/PatchModel.h index c15f7746..db444de2 100644 --- a/src/libs/client/PatchModel.h +++ b/src/libs/client/PatchModel.h @@ -40,7 +40,7 @@ class PatchModel : public NodeModel { public: PatchModel(const string& patch_path, uint poly) - : NodeModel(patch_path), + : NodeModel("ingen:patch", patch_path), m_enabled(false), m_poly(poly) {} @@ -50,6 +50,8 @@ public: virtual void set_path(const Path& path); + void add_child(CountedPtr c); + CountedPtr get_node(const string& node_name); void add_node(CountedPtr nm); void remove_node(const string& name); diff --git a/src/libs/client/PortModel.h b/src/libs/client/PortModel.h index 3aedc639..7b84c95a 100644 --- a/src/libs/client/PortModel.h +++ b/src/libs/client/PortModel.h @@ -70,6 +70,8 @@ public: { } + void add_child(CountedPtr c) { throw; } + inline float min_val() const { return m_min_val; } inline float user_min() const { return atof(get_metadata("min").c_str()); } // FIXME: haaack //inline void user_min(float f) { m_user_min = f; } diff --git a/src/libs/client/Store.cpp b/src/libs/client/Store.cpp index ef1b7283..36e815d8 100644 --- a/src/libs/client/Store.cpp +++ b/src/libs/client/Store.cpp @@ -54,23 +54,99 @@ Store::clear() } +void +Store::add_plugin_orphan(CountedPtr node) +{ + cerr << "WARNING: Node " << node->path() << " received, but plugin " + << node->plugin_uri() << " unknown." << endl; + + map > >::iterator spawn + = m_plugin_orphans.find(node->plugin_uri()); + + if (spawn != m_plugin_orphans.end()) { + spawn->second.push_back(node); + } else { + list > l; + l.push_back(node); + m_plugin_orphans[node->plugin_uri()] = l; + } +} + + +void +Store::resolve_plugin_orphans(CountedPtr plugin) +{ + map > >::iterator spawn + = m_plugin_orphans.find(plugin->uri()); + + if (spawn != m_plugin_orphans.end()) { + cerr << "XXXXXXXXXX PLUGIN-ORPHAN PLUGIN FOUND!! XXXXXXXXXXXXXXXXX" << endl; + } +} + + +void +Store::add_orphan(CountedPtr child) +{ + cerr << "WARNING: Orphan object " << child->path() << " received." << endl; + + map > >::iterator children + = m_orphans.find(child->path().parent()); + + if (children != m_orphans.end()) { + children->second.push_back(child); + } else { + list > l; + l.push_back(child); + m_orphans[child->path().parent()] = l; + } +} + + +void +Store::resolve_orphans(CountedPtr parent) +{ + map > >::iterator children + = m_orphans.find(parent->path()); + + if (children != m_orphans.end()) { + cerr << "XXXXXXXXXXXXX ORPHAN PARENT FOUND!! XXXXXXXXXXXXXXXXX" << endl; + } +} + + void Store::add_object(CountedPtr object) { assert(object->path() != ""); assert(m_objects.find(object->path()) == m_objects.end()); + if (object->path() != "/") { + CountedPtr parent = this->object(object->path().parent()); + if (parent) { + assert(object->path().is_child_of(parent->path())); + object->set_parent(parent); + parent->add_child(object); + assert(object->parent() == parent); + } else { + add_orphan(object); + } + } + m_objects[object->path()] = object; new_object_sig.emit(object); + + resolve_orphans(object); + //cout << "[Store] Added " << object->path() << endl; } CountedPtr -Store::remove_object(const string& path) +Store::remove_object(const Path& path) { - map >::iterator i = m_objects.find(path); + map >::iterator i = m_objects.find(path); if (i != m_objects.end()) { assert((*i).second->path() == path); @@ -80,7 +156,7 @@ Store::remove_object(const string& path) return result; } else { cerr << "[Store] Unable to find object " << path << " to remove." << endl; - return NULL; + return CountedPtr(); } } @@ -91,84 +167,29 @@ Store::plugin(const string& uri) assert(uri.length() > 0); map >::iterator i = m_plugins.find(uri); if (i == m_plugins.end()) - return NULL; + return CountedPtr(); else return (*i).second; } CountedPtr -Store::object(const string& path) +Store::object(const Path& path) { assert(path.length() > 0); - map >::iterator i = m_objects.find(path); + map >::iterator i = m_objects.find(path); if (i == m_objects.end()) - return NULL; + return CountedPtr(); else return (*i).second; } -#if 0 -CountedPtr -Store::patch(const string& path) -{ - assert(path.length() > 0); - map >::iterator i = m_objects.find(path); - if (i == m_objects.end()) - return NULL; - else - return (CountedPtr)(*i).second; // FIXME -} - - -CountedPtr -Store::node(const string& path) -{ - assert(path.length() > 0); - map >::iterator i = m_objects.find(path); - if (i == m_objects.end()) - return NULL; - else - return (*i).second; -} - - -CountedPtr -Store::port(const string& path) -{ - assert(path.length() > 0); - map >::iterator i = m_objects.find(path); - if (i == m_objects.end()) { - return NULL; - } else { - // Normal port - /*PortModel* const pc = dynamic_cast((*i).second); - if (pc) - return pc;*/ - return (*i).second; - - // Patch port (corresponding Node is in store) - // FIXME - // - /* - NodeModel* const nc = dynamic_cast((*i).second); - if (nc) - return nc->as_port(); // Patch port (maybe) - */ - } - - return NULL; -} -#endif - void Store::add_plugin(CountedPtr pm) { - //if (m_plugins.find(pm->uri()) != m_plugins.end()) { - // cerr << "DUPE PLUGIN: " << pm->uri() << endl; - //} else { - m_plugins[pm->uri()] = pm; - //} + // FIXME: dupes? + + m_plugins[pm->uri()] = pm; } @@ -177,10 +198,9 @@ Store::add_plugin(CountedPtr pm) void -Store::destruction_event(const string& path) +Store::destruction_event(const Path& path) { - // I'm assuming the compiler will optimize out all these const - // pointers into one... + // Hopefully the compiler will optimize all these const pointers into one... CountedPtr obj_ptr = remove_object(path); ObjectModel* const object = obj_ptr.get(); @@ -194,147 +214,94 @@ Store::destruction_event(const string& path) cerr << "Node\n"; PatchModel* const parent = dynamic_cast(object->parent().get()); if (parent) - parent->remove_node(node->name()); + parent->remove_node(node->path().name()); } PortModel* const port = dynamic_cast(object); if (port) { NodeModel* const parent = dynamic_cast(object->parent().get()); assert(parent); - parent->remove_port(port->name()); + parent->remove_port(port->path().name()); } - // FIXME: emit signals + if (object) + object->destroyed_sig.emit(); } void Store::new_plugin_event(const string& type, const string& uri, const string& name) { - PluginModel* const p = new PluginModel(type, uri); + CountedPtr p(new PluginModel(type, uri)); p->name(name); add_plugin(p); + resolve_plugin_orphans(p); } void -Store::new_patch_event(const string& path, uint32_t poly) +Store::new_patch_event(const Path& path, uint32_t poly) { - // FIXME: What to do with a conflict? - - if (m_objects.find(path) == m_objects.end()) { - CountedPtr p(new PatchModel(path, poly)); - add_object(p); - - if (path != "/") { - CountedPtr parent = object(p->path().parent()); - if (parent) { - assert(path.substr(0, parent->path().length()) == parent->path()); - p->set_parent(parent); - parent->add_node(p); - assert(p->parent() == parent); - } else { - cerr << "ERROR: new patch with no parent" << endl; - } - } - } + CountedPtr p(new PatchModel(path, poly)); + add_object(p); } void -Store::new_node_event(const string& plugin_type, const string& plugin_uri, const string& node_path, bool is_polyphonic, uint32_t num_ports) +Store::new_node_event(const string& plugin_type, const string& plugin_uri, const Path& node_path, bool is_polyphonic, uint32_t num_ports) { - // FIXME: What to do with a conflict? - - if (m_objects.find(node_path) == m_objects.end()) { - - CountedPtr plug = plugin(plugin_uri); - assert(plug); - + // FIXME: num_ports unused + + CountedPtr plug = plugin(plugin_uri); + if (!plug) { + CountedPtr n(new NodeModel(plugin_uri, node_path)); + n->polyphonic(is_polyphonic); + add_plugin_orphan(n); + } else { CountedPtr n(new NodeModel(plug, node_path)); n->polyphonic(is_polyphonic); - // FIXME: num_ports unused add_object(n); - - //std::map >::iterator pi = m_objects.find(n->path().parent()); - //if (pi != m_objects.end()) { - CountedPtr parent = object(n->path().parent()); - if (parent) { - n->set_parent(parent); - assert(n->parent() == parent); - parent->add_node(n); - assert(n->parent() == parent); - } else { - cerr << "ERROR: new node with no parent" << endl; - } } } void -Store::new_port_event(const string& path, const string& type, bool is_output) +Store::new_port_event(const Path& path, const string& type, bool is_output) { // FIXME: this sucks - /* - if (m_objects.find(path) == m_objects.end()) { - PortModel::Type ptype = PortModel::CONTROL; - if (type == "AUDIO") ptype = PortModel::AUDIO; - else if (type == "CONTROL") ptype = PortModel::CONTROL; - else if (type== "MIDI") ptype = PortModel::MIDI; - else cerr << "[OSCListener] WARNING: Unknown port type received (" << type << ")" << endl; - - PortModel::Direction pdir = is_output ? PortModel::OUTPUT : PortModel::INPUT; - - PortModel* const p = new PortModel(path, ptype, pdir); - - add_object(p); - } else - */ - if (m_objects.find(path) == m_objects.end()) { - - PortModel::Type ptype = PortModel::CONTROL; - if (type == "AUDIO") ptype = PortModel::AUDIO; - else if (type == "CONTROL") ptype = PortModel::CONTROL; - else if (type== "MIDI") ptype = PortModel::MIDI; - else cerr << "[Store] WARNING: Unknown port type received (" << type << ")" << endl; - - PortModel::Direction pdir = is_output ? PortModel::OUTPUT : PortModel::INPUT; - - CountedPtr p(new PortModel(path, ptype, pdir)); - add_object(p); - - CountedPtr parent = object(p->path().parent()); - if (parent) { - p->set_parent(parent); - assert(p->parent() == parent); - parent->add_port(p); - assert(p->parent() == parent); - } else { - cerr << "ERROR: new port with no parent" << endl; - } - } + + PortModel::Type ptype = PortModel::CONTROL; + if (type == "AUDIO") ptype = PortModel::AUDIO; + else if (type == "CONTROL") ptype = PortModel::CONTROL; + else if (type== "MIDI") ptype = PortModel::MIDI; + else cerr << "[Store] WARNING: Unknown port type received (" << type << ")" << endl; + + PortModel::Direction pdir = is_output ? PortModel::OUTPUT : PortModel::INPUT; + + CountedPtr p(new PortModel(path, ptype, pdir)); + add_object(p); } void -Store::patch_enabled_event(const string& path) +Store::patch_enabled_event(const Path& path) { - CountedPtr patch = object(path); + CountedPtr patch = PtrCast(object(path)); if (patch) patch->enable(); } void -Store::patch_disabled_event(const string& path) +Store::patch_disabled_event(const Path& path) { - CountedPtr patch = object(path); + CountedPtr patch = PtrCast(object(path)); if (patch) patch->disable(); } void -Store::metadata_update_event(const string& subject_path, const string& predicate, const string& value) +Store::metadata_update_event(const Path& subject_path, const string& predicate, const string& value) { CountedPtr subject = object(subject_path); if (subject) @@ -345,9 +312,9 @@ Store::metadata_update_event(const string& subject_path, const string& predicate void -Store::control_change_event(const string& port_path, float value) +Store::control_change_event(const Path& port_path, float value) { - CountedPtr port = object(port_path); + CountedPtr port = PtrCast(object(port_path)); if (port) port->value(value); else @@ -358,8 +325,8 @@ Store::control_change_event(const string& port_path, float value) void Store::connection_event(const Path& src_port_path, const Path& dst_port_path) { - CountedPtr src_port = object(src_port_path); - CountedPtr dst_port = object(dst_port_path); + CountedPtr src_port = PtrCast(object(src_port_path)); + CountedPtr dst_port = PtrCast(object(dst_port_path)); assert(src_port); assert(dst_port); @@ -367,9 +334,9 @@ Store::connection_event(const Path& src_port_path, const Path& dst_port_path) src_port->connected_to(dst_port); dst_port->connected_to(src_port); - CountedPtr cm = new ConnectionModel(src_port, dst_port); + CountedPtr cm(new ConnectionModel(src_port, dst_port)); - CountedPtr patch = this->object(cm->patch_path()); + CountedPtr patch = PtrCast(this->object(cm->patch_path())); if (patch) patch->add_connection(cm); @@ -384,8 +351,8 @@ Store::disconnection_event(const Path& src_port_path, const Path& dst_port_path) // Find the ports and create a ConnectionModel just to get at the parent path // finding logic in ConnectionModel. So I'm lazy. - CountedPtr src_port = object(src_port_path); - CountedPtr dst_port = object(dst_port_path); + CountedPtr src_port = PtrCast(object(src_port_path)); + CountedPtr dst_port = PtrCast(object(dst_port_path)); assert(src_port); assert(dst_port); @@ -393,9 +360,9 @@ Store::disconnection_event(const Path& src_port_path, const Path& dst_port_path) src_port->disconnected_from(dst_port); dst_port->disconnected_from(src_port); - CountedPtr cm = new ConnectionModel(src_port, dst_port); + CountedPtr cm(new ConnectionModel(src_port, dst_port)); - CountedPtr patch = this->object(cm->patch_path()); + CountedPtr patch = PtrCast(this->object(cm->patch_path())); if (patch) patch->remove_connection(src_port_path, dst_port_path); diff --git a/src/libs/client/Store.h b/src/libs/client/Store.h index 44ca5c70..e70c5bc0 100644 --- a/src/libs/client/Store.h +++ b/src/libs/client/Store.h @@ -20,10 +20,11 @@ #include #include #include +#include #include "util/CountedPtr.h" #include #include "util/Path.h" -using std::string; using std::map; +using std::string; using std::map; using std::list; namespace Ingen { namespace Client { @@ -44,10 +45,7 @@ public: Store(CountedPtr emitter); CountedPtr plugin(const string& uri); - CountedPtr object(const string& path); - /*CountedPtr patch(const string& path); - CountedPtr node(const string& path); - CountedPtr port(const string& path);*/ + CountedPtr object(const Path& path); void clear(); @@ -59,25 +57,39 @@ public: private: void add_object(CountedPtr object); - CountedPtr remove_object(const string& path); + CountedPtr remove_object(const Path& path); void add_plugin(CountedPtr plugin); + void add_orphan(CountedPtr orphan); + void resolve_orphans(CountedPtr parent); + + void add_plugin_orphan(CountedPtr orphan); + void resolve_plugin_orphans(CountedPtr plugin); + // Slots for SigClientInterface signals - void destruction_event(const string& path); + void destruction_event(const Path& path); void new_plugin_event(const string& type, const string& uri, const string& name); - void new_patch_event(const string& path, uint32_t poly); - void new_node_event(const string& plugin_type, const string& plugin_uri, const string& node_path, bool is_polyphonic, uint32_t num_ports); - void new_port_event(const string& path, const string& data_type, bool is_output); - void patch_enabled_event(const string& path); - void patch_disabled_event(const string& path); - void metadata_update_event(const string& subject_path, const string& predicate, const string& value); - void control_change_event(const string& port_path, float value); + void new_patch_event(const Path& path, uint32_t poly); + void new_node_event(const string& plugin_type, const string& plugin_uri, const Path& node_path, bool is_polyphonic, uint32_t num_ports); + void new_port_event(const Path& path, const string& data_type, bool is_output); + void patch_enabled_event(const Path& path); + void patch_disabled_event(const Path& path); + void metadata_update_event(const Path& subject_path, const string& predicate, const string& value); + void control_change_event(const Path& port_path, float value); void connection_event(const Path& src_port_path, const Path& dst_port_path); void disconnection_event(const Path& src_port_path, const Path& dst_port_path); - map > m_objects; ///< Keyed by Ingen path + map > m_objects; ///< Keyed by Ingen path map > m_plugins; ///< Keyed by URI + + /** Objects we've received, but depend on the existance of another unknown object. + * Keyed by the path of the depended-on object (for tolerance of orderless comms) */ + map > > m_orphans; + + /** Same idea, except with plugins instead of parents. + * It's unfortunate everything doesn't just have a URI and this was the same.. ahem.. */ + map > > m_plugin_orphans; }; -- cgit v1.2.1