diff options
author | David Robillard <d@drobilla.net> | 2007-10-08 02:57:21 +0000 |
---|---|---|
committer | David Robillard <d@drobilla.net> | 2007-10-08 02:57:21 +0000 |
commit | 4675e82dae45a70ee27bf11d10aa6872485c8847 (patch) | |
tree | 24210667e721d400a552ad2621e9a5cfe447395c /src/libs/client | |
parent | 9d9efa215c52a6b75eef7e9a8b088b11dfd76a07 (diff) | |
download | ingen-4675e82dae45a70ee27bf11d10aa6872485c8847.tar.gz ingen-4675e82dae45a70ee27bf11d10aa6872485c8847.tar.bz2 ingen-4675e82dae45a70ee27bf11d10aa6872485c8847.zip |
Eliminate redundant object collections (ObjectModel having a separate collection of its children).
Fix renaming/creation of children (fix ticket 97).
git-svn-id: http://svn.drobilla.net/lad/ingen@844 a436a847-0d15-0410-975c-d299462d15a1
Diffstat (limited to 'src/libs/client')
-rw-r--r-- | src/libs/client/NodeModel.cpp | 15 | ||||
-rw-r--r-- | src/libs/client/NodeModel.hpp | 4 | ||||
-rw-r--r-- | src/libs/client/ObjectModel.cpp | 65 | ||||
-rw-r--r-- | src/libs/client/ObjectModel.hpp | 23 | ||||
-rw-r--r-- | src/libs/client/PatchLibrarian.cpp.new | 833 | ||||
-rw-r--r-- | src/libs/client/PatchModel.cpp | 29 | ||||
-rw-r--r-- | src/libs/client/PatchModel.hpp | 12 | ||||
-rw-r--r-- | src/libs/client/PluginModel.cpp | 2 | ||||
-rw-r--r-- | src/libs/client/PortModel.hpp | 4 | ||||
-rw-r--r-- | src/libs/client/Serializer.cpp | 3 | ||||
-rw-r--r-- | src/libs/client/Store.cpp | 15 |
11 files changed, 77 insertions, 928 deletions
diff --git a/src/libs/client/NodeModel.cpp b/src/libs/client/NodeModel.cpp index 52a4e1e9..b8c8e901 100644 --- a/src/libs/client/NodeModel.cpp +++ b/src/libs/client/NodeModel.cpp @@ -26,15 +26,15 @@ namespace Ingen { namespace Client { -NodeModel::NodeModel(SharedPtr<PluginModel> plugin, const Path& path, bool polyphonic) - : ObjectModel(path, polyphonic) +NodeModel::NodeModel(Store& store, SharedPtr<PluginModel> plugin, const Path& path, bool polyphonic) + : ObjectModel(store, path, polyphonic) , _plugin_uri(plugin->uri()) , _plugin(plugin) { } -NodeModel::NodeModel(const string& plugin_uri, const Path& path, bool polyphonic) - : ObjectModel(path, polyphonic) +NodeModel::NodeModel(Store& store, const string& plugin_uri, const Path& path, bool polyphonic) + : ObjectModel(store, path, polyphonic) , _plugin_uri(plugin_uri) { } @@ -86,7 +86,7 @@ NodeModel::add_child(SharedPtr<ObjectModel> c) { assert(c->parent().get() == this); - ObjectModel::add_child(c); + //ObjectModel::add_child(c); SharedPtr<PortModel> pm = PtrCast<PortModel>(c); assert(pm); @@ -100,13 +100,14 @@ NodeModel::remove_child(SharedPtr<ObjectModel> c) assert(c->path().is_child_of(_path)); assert(c->parent().get() == this); - bool ret = ObjectModel::remove_child(c); + //bool ret = ObjectModel::remove_child(c); SharedPtr<PortModel> pm = PtrCast<PortModel>(c); assert(pm); remove_port(pm); - return ret; + //return ret; + return true; } diff --git a/src/libs/client/NodeModel.hpp b/src/libs/client/NodeModel.hpp index c4f9afe2..a38c519c 100644 --- a/src/libs/client/NodeModel.hpp +++ b/src/libs/client/NodeModel.hpp @@ -67,8 +67,8 @@ public: protected: friend class Store; - NodeModel(const string& plugin_uri, const Path& path, bool polyphonic); - NodeModel(SharedPtr<PluginModel> plugin, const Path& path, bool polyphonic); + NodeModel(Store& store, const string& plugin_uri, const Path& path, bool polyphonic); + NodeModel(Store& store, SharedPtr<PluginModel> plugin, const Path& path, bool polyphonic); NodeModel(const Path& path); void add_child(SharedPtr<ObjectModel> c); diff --git a/src/libs/client/ObjectModel.cpp b/src/libs/client/ObjectModel.cpp index 673a5c60..ca38b42f 100644 --- a/src/libs/client/ObjectModel.cpp +++ b/src/libs/client/ObjectModel.cpp @@ -25,8 +25,9 @@ namespace Ingen { namespace Client { -ObjectModel::ObjectModel(const Path& path, bool polyphonic) - : _path(path) +ObjectModel::ObjectModel(Store& store, const Path& path, bool polyphonic) + : _store(store) + , _path(path) , _polyphonic(polyphonic) { } @@ -35,51 +36,41 @@ ObjectModel::ObjectModel(const Path& path, bool polyphonic) ObjectModel::~ObjectModel() { } + -SharedPtr<ObjectModel> -ObjectModel::get_child(const string& name) const +ObjectModel::const_iterator +ObjectModel::children_begin() const { - assert(name.find("/") == string::npos); - Children::const_iterator i = _children.find(name); - return ((i != _children.end()) ? (*i).second : SharedPtr<ObjectModel>()); + Store::Objects::const_iterator me = _store.objects().find(_path); + assert(me != _store.objects().end()); + ++me; + return me; } -void -ObjectModel::add_child(SharedPtr<ObjectModel> o) + +ObjectModel::const_iterator +ObjectModel::children_end() const { - assert(o); - assert(o->path().is_child_of(_path)); - assert(o->parent().get() == this); - -#ifndef NDEBUG - // Be sure there's no duplicates - Children::iterator existing = _children.find(o->path().name()); - assert(existing == _children.end()); -#endif - - _children.insert(make_pair(o->path().name(), o)); - signal_new_child.emit(o); + Store::Objects::const_iterator me = _store.objects().find(_path); + assert(me != _store.objects().end()); + return _store.objects().find_descendants_end(me); } -bool -ObjectModel::remove_child(SharedPtr<ObjectModel> o) + +SharedPtr<ObjectModel> +ObjectModel::find_child(const string& name) const { - assert(o->path().is_child_of(_path)); - assert(o->parent().get() == this); - - Children::iterator i = _children.find(o->path().name()); - if (i != _children.end()) { - assert(i->second == o); - _children.erase(i); - signal_removed_child.emit(o); - return true; - } else { - cerr << "[ObjectModel::remove_child] " << _path - << ": failed to find child " << o->path().name() << endl; - return false; - } + const_iterator me = _store.objects().find(_path); + assert(me != _store.objects().end()); + const_iterator children_end = _store.objects().find_descendants_end(me); + const_iterator child = _store.objects().find(me, children_end, _path.base() + name); + if (child != _store.objects().end()) + return child->second; + else + return SharedPtr<ObjectModel>(); } + /** Get a piece of metadata for this object. * * @return Metadata value with key @a key, empty string otherwise. diff --git a/src/libs/client/ObjectModel.hpp b/src/libs/client/ObjectModel.hpp index 9ac3e686..ede796e4 100644 --- a/src/libs/client/ObjectModel.hpp +++ b/src/libs/client/ObjectModel.hpp @@ -30,6 +30,7 @@ #include <raul/SharedPtr.hpp> #include <raul/Table.hpp> #include "interface/GraphObject.hpp" +#include "Store.hpp" using std::string; using Raul::Atom; @@ -38,6 +39,8 @@ using Raul::Path; namespace Ingen { namespace Client { +class Store; + /** Base class for all GraphObject models (NodeModel, PatchModel, PortModel). * @@ -59,16 +62,18 @@ public: void set_metadata(const string& key, const Atom& value) { _metadata.insert(make_pair(key, value)); signal_metadata.emit(key, value); } - typedef Raul::Table<string, SharedPtr<ObjectModel> > Children; - const MetadataMap& metadata() const { return _metadata; } - const Children& children() const { return _children; } const Path path() const { return _path; } const string name() const { return _path.name(); } SharedPtr<ObjectModel> parent() const { return _parent; } bool polyphonic() const { return _polyphonic; } - SharedPtr<ObjectModel> get_child(const string& name) const; + typedef Store::Objects::iterator iterator; + typedef Store::Objects::const_iterator const_iterator; + + const_iterator children_begin() const; + const_iterator children_end() const; + SharedPtr<ObjectModel> find_child(const string& name) const; // Signals sigc::signal<void, SharedPtr<ObjectModel> > signal_new_child; @@ -81,24 +86,24 @@ public: protected: friend class Store; - ObjectModel(const Path& path, bool polyphonic); + ObjectModel(Store& store, const Path& path, bool polyphonic); virtual void set_path(const Path& p) { _path = p; signal_renamed.emit(); } virtual void set_parent(SharedPtr<ObjectModel> p) { assert(p); _parent = p; } - virtual void add_child(SharedPtr<ObjectModel> c); - virtual bool remove_child(SharedPtr<ObjectModel> c); - + virtual void add_child(SharedPtr<ObjectModel> c) {} + virtual bool remove_child(SharedPtr<ObjectModel> c) { return true; } + void add_metadata(const MetadataMap& data); void set_polyphonic(bool); void set(SharedPtr<ObjectModel> model); + Store& _store; Path _path; bool _polyphonic; SharedPtr<ObjectModel> _parent; MetadataMap _metadata; - Children _children; }; diff --git a/src/libs/client/PatchLibrarian.cpp.new b/src/libs/client/PatchLibrarian.cpp.new deleted file mode 100644 index 125b7fbd..00000000 --- a/src/libs/client/PatchLibrarian.cpp.new +++ /dev/null @@ -1,833 +0,0 @@ -/* This file is part of Ingen. - * Copyright (C) 2007 Dave Robillard <drobilla.net> - * - * Ingen is free software; you can redistribute it and/or modify it under the - * terms of the GNU General Public License as published by the Free Software - * Foundation; either version 2 of the License, or (at your option) 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 General Public License for details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include "PatchLibrarian.h" -#include <libxml/parser.h> -#include <libxml/tree.h> -#include <libxml/xpath.h> -#include "PatchModel.h" -#include "NodeModel.h" -#include "ConnectionModel.h" -#include "PortModel.h" -#include "PresetModel.h" -#include "OSCController.h" -#include "PluginModel.h" -#include "Path.h" -#include <iostream> -#include <fstream> -#include <vector> -#include <utility> // for pair, make_pair -#include <cassert> -#include <cstring> -#include <string> -#include <unistd.h> // for usleep -#include <cstdlib> // for atof -#include <cmath> - -using std::string; using std::vector; using std::pair; -using std::cerr; using std::cout; using std::endl; - -namespace Ingen { -namespace Client { - - -/** Searches for the filename passed in the path, returning the full - * path of the file, or the empty string if not found. - * - * This function tries to be as friendly a black box as possible - if the path - * passed is an absolute path and the file is found there, it will return - * that path, etc. - * - * additional_path is a list (colon delimeted as usual) of additional - * directories to look in. ie the directory the parent patch resides in would - * be a good idea to pass as additional_path, in the case of a subpatch. - */ -string -PatchLibrarian::find_file(const string& filename, const string& additional_path) -{ - string search_path = additional_path + ":" + m_patch_path; - - // Try to open the raw filename first - std::ifstream is(filename.c_str(), std::ios::in); - if (is.good()) { - is.close(); - return filename; - } - - string directory; - string full_patch_path = ""; - - while (search_path != "") { - directory = search_path.substr(0, search_path.find(':')); - if (search_path.find(':') != string::npos) - search_path = search_path.substr(search_path.find(':')+1); - else - search_path = ""; - - full_patch_path = directory +"/"+ filename; - - std::ifstream is; - is.open(full_patch_path.c_str(), std::ios::in); - - if (is.good()) { - is.close(); - return full_patch_path; - } else { - cerr << "[PatchLibrarian] Could not find patch file " << full_patch_path << endl; - } - } - - return ""; -} - - -/** Save a patch from a PatchModel to a filename. - * - * The filename passed is the true filename the patch will be saved to (with no prefixing or anything - * like that), and the patch_model's filename member will be set accordingly. - * - * This will break if: - * - The filename does not have an extension (ie contain a ".") - * - The patch_model has no (Ingen) path - */ -void -PatchLibrarian::save_patch(PatchModel* patch_model, const string& filename, bool recursive) -{ - assert(filename != ""); - assert(patch_model->path() != ""); - - cout << "Saving patch " << patch_model->path() << " to " << filename << endl; - - patch_model->filename(filename); - - 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; - xmlNodePtr xml_node = NULL; - xmlNodePtr xml_child_node = NULL; - xmlNodePtr xml_grandchild_node = NULL; - - xml_doc = xmlNewDoc((xmlChar*)"1.0"); - xml_root_node = xmlNewNode(NULL, (xmlChar*)"patch"); - xmlDocSetRootElement(xml_doc, xml_root_node); - - const size_t temp_buf_length = 255; - char temp_buf[temp_buf_length]; - - string patch_name; - if (patch_model->path() != "/") { - patch_name = patch_model->name(); - } else { - patch_name = filename; - if (patch_name.find("/") != string::npos) - patch_name = patch_name.substr(patch_name.find_last_of("/") + 1); - if (patch_name.find(".") != string::npos) - patch_name = patch_name.substr(0, patch_name.find_last_of(".")); - } - - assert(patch_name.length() > 0); - xml_node = xmlNewChild(xml_root_node, NULL, (xmlChar*)"name", - (xmlChar*)patch_name.c_str()); - - snprintf(temp_buf, temp_buf_length, "%zd", patch_model->poly()); - xml_node = xmlNewChild(xml_root_node, NULL, (xmlChar*)"polyphony", (xmlChar*)temp_buf); - - // Write metadata - for (map<string, string>::const_iterator i = patch_model->metadata().begin(); - i != patch_model->metadata().end(); ++i) { - // Dirty hack, don't save coordinates in patch file - if ((*i).first != "module-x" && (*i).first != "module-y" - && (*i).first != "filename") - xml_node = xmlNewChild(xml_root_node, NULL, - (xmlChar*)(*i).first.c_str(), (xmlChar*)(*i).second.c_str()); - assert((*i).first != "connection"); - assert((*i).first != "node"); - assert((*i).first != "subpatch"); - assert((*i).first != "name"); - assert((*i).first != "polyphony"); - assert((*i).first != "preset"); - } - - // Save nodes and subpatches - for (NodeModelMap::const_iterator i = patch_model->nodes().begin(); i != patch_model->nodes().end(); ++i) { - nm = i->second; - - if (nm->plugin()->type() == PluginModel::Patch) { // Subpatch - spm = (PatchModel*)i->second; - xml_node = xmlNewChild(xml_root_node, NULL, (xmlChar*)"subpatch", NULL); - - xml_child_node = xmlNewChild(xml_node, NULL, (xmlChar*)"name", (xmlChar*)spm->name().c_str()); - - string ref_filename; - // No path - if (spm->filename() == "") { - ref_filename = spm->name() + ".om"; - spm->filename(dir +"/"+ ref_filename); - // Absolute path - } else if (spm->filename().substr(0, 1) == "/") { - // Attempt to make it a relative path, if it's undernath this patch's dir - if (dir.substr(0, 1) == "/" && spm->filename().substr(0, dir.length()) == dir) { - ref_filename = spm->filename().substr(dir.length()+1); - } else { // FIXME: not good - ref_filename = spm->filename().substr(spm->filename().find_last_of("/")+1); - spm->filename(dir +"/"+ ref_filename); - } - } else { - ref_filename = spm->filename(); - } - - xml_child_node = xmlNewChild(xml_node, NULL, (xmlChar*)"filename", (xmlChar*)ref_filename.c_str()); - - snprintf(temp_buf, temp_buf_length, "%zd", spm->poly()); - xml_child_node = xmlNewChild(xml_node, NULL, (xmlChar*)"polyphony", (xmlChar*)temp_buf); - - // Write metadata - for (map<string, string>::const_iterator i = nm->metadata().begin(); - i != nm->metadata().end(); ++i) { - // Dirty hack, don't save metadata that would be in patch file - if ((*i).first != "polyphony" && (*i).first != "filename" - && (*i).first != "author" && (*i).first != "description") - xml_child_node = xmlNewChild(xml_node, NULL, - (xmlChar*)(*i).first.c_str(), (xmlChar*)(*i).second.c_str()); - } - - if (recursive) - save_patch(spm, spm->filename(), true); - - } 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()); - - if (nm->plugin() == NULL) break; - - xml_child_node = xmlNewChild(xml_node, NULL, (xmlChar*)"polyphonic", - (xmlChar*)((nm->polyphonic()) ? "true" : "false")); - - xml_child_node = xmlNewChild(xml_node, NULL, (xmlChar*)"type", - (xmlChar*)nm->plugin()->type_string()); - /* - xml_child_node = xmlNewChild(xml_node, NULL, (xmlChar*)"plugin-label", - (xmlChar*)(nm->plugin()->plug_label().c_str())); - - if (nm->plugin()->type() != PluginModel::Internal) { - xml_child_node = xmlNewChild(xml_node, NULL, (xmlChar*)"library-name", - (xmlChar*)(nm->plugin()->lib_name().c_str())); - }*/ - xml_child_node = xmlNewChild(xml_node, NULL, (xmlChar*)"plugin-uri", - (xmlChar*)(nm->plugin()->uri().c_str())); - - // Write metadata - for (map<string, string>::const_iterator i = nm->metadata().begin(); i != nm->metadata().end(); ++i) { - // DSSI _hack_ (FIXME: fix OSC to be more like this and not smash DSSI into metadata?) - if ((*i).first.substr(0, 16) == "dssi-configure--") { - xml_child_node = xmlNewChild(xml_node, NULL, (xmlChar*)"dssi-configure", NULL); - xml_grandchild_node = xmlNewChild(xml_child_node, NULL, - (xmlChar*)"key", (xmlChar*)(*i).first.substr(16).c_str()); - xml_grandchild_node = xmlNewChild(xml_child_node, NULL, - (xmlChar*)"value", (xmlChar*)(*i).second.c_str()); - } else if ((*i).first == "dssi-program") { - xml_child_node = xmlNewChild(xml_node, NULL, (xmlChar*)"dssi-program", NULL); - xml_grandchild_node = xmlNewChild(xml_child_node, NULL, - (xmlChar*)"bank", (xmlChar*)(*i).second.substr(0, (*i).second.find("/")).c_str()); - xml_grandchild_node = xmlNewChild(xml_child_node, NULL, - (xmlChar*)"program", (xmlChar*)(*i).second.substr((*i).second.find("/")+1).c_str()); - } else { - xml_child_node = xmlNewChild(xml_node, NULL, - (xmlChar*)(*i).first.c_str(), (xmlChar*)(*i).second.c_str()); - } - } - - PortModel* pm = NULL; - // Write port metadata, if necessary - for (list<PortModel*>::const_iterator i = nm->ports().begin(); i != nm->ports().end(); ++i) { - pm = (*i); - if (pm->is_input() && pm->user_min() != pm->min_val() || pm->user_max() != pm->max_val()) { - xml_child_node = xmlNewChild(xml_node, NULL, (xmlChar*)"port", NULL); - xml_grandchild_node = xmlNewChild(xml_child_node, NULL, (xmlChar*)"name", - (xmlChar*)pm->path().name().c_str()); - snprintf(temp_buf, temp_buf_length, "%f", pm->user_min()); - xml_grandchild_node = xmlNewChild(xml_child_node, NULL, (xmlChar*)"user-min", (xmlChar*)temp_buf); - snprintf(temp_buf, temp_buf_length, "%f", pm->user_max()); - xml_grandchild_node = xmlNewChild(xml_child_node, NULL, (xmlChar*)"user-max", (xmlChar*)temp_buf); - } - } - } - } - - // Save connections - - const list<ConnectionModel*>& cl = patch_model->connections(); - const ConnectionModel* c = NULL; - - for (list<ConnectionModel*>::const_iterator i = cl.begin(); i != cl.end(); ++i) { - c = (*i); - xml_node = xmlNewChild(xml_root_node, NULL, (xmlChar*)"connection", NULL); - xml_child_node = xmlNewChild(xml_node, NULL, (xmlChar*)"source-node", - (xmlChar*)c->src_port_path().parent().name().c_str()); - xml_child_node = xmlNewChild(xml_node, NULL, (xmlChar*)"source-port", - (xmlChar*)c->src_port_path().name().c_str()); - xml_child_node = xmlNewChild(xml_node, NULL, (xmlChar*)"destination-node", - (xmlChar*)c->dst_port_path().parent().name().c_str()); - xml_child_node = xmlNewChild(xml_node, NULL, (xmlChar*)"destination-port", - (xmlChar*)c->dst_port_path().name().c_str()); - } - - // Save control values (ie presets eventually, right now just current control vals) - - xmlNodePtr xml_preset_node = xmlNewChild(xml_root_node, NULL, (xmlChar*)"preset", NULL); - xml_node = xmlNewChild(xml_preset_node, NULL, (xmlChar*)"name", (xmlChar*)"default"); - - PortModel* pm = NULL; - - // Save node port controls - for (NodeModelMap::const_iterator n = patch_model->nodes().begin(); n != patch_model->nodes().end(); ++n) { - nm = n->second; - for (PortModelList::const_iterator p = nm->ports().begin(); p != nm->ports().end(); ++p) { - pm = *p; - if (pm->is_input() && pm->is_control()) { - 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()); - xml_child_node = xmlNewChild(xml_node, NULL, (xmlChar*)"port-name", - (xmlChar*)pm->path().name().c_str()); - snprintf(temp_buf, temp_buf_length, "%f", val); - xml_child_node = xmlNewChild(xml_node, NULL, (xmlChar*)"value", - (xmlChar*)temp_buf); - } - } - } - - // Save patch port controls - for (PortModelList::const_iterator p = patch_model->ports().begin(); - p != patch_model->ports().end(); ++p) { - pm = *p; - if (pm->is_input() && pm->is_control()) { - float val = pm->value(); - xml_node = xmlNewChild(xml_preset_node, NULL, (xmlChar*)"control", NULL); - xml_child_node = xmlNewChild(xml_node, NULL, (xmlChar*)"port-name", - (xmlChar*)pm->path().name().c_str()); - snprintf(temp_buf, temp_buf_length, "%f", val); - xml_child_node = xmlNewChild(xml_node, NULL, (xmlChar*)"value", - (xmlChar*)temp_buf); - } - } - - xmlSaveFormatFile(filename.c_str(), xml_doc, 1); // 1 == pretty print - - xmlFreeDoc(xml_doc); - xmlCleanupParser(); -} - - -/** Load a patch in to the engine (and client) from a patch file. - * - * The name and poly from the passed PatchModel are used. If the name is - * the empty string, the name will be loaded from the file. If the poly - * is 0, it will be loaded from file. Otherwise the given values will - * be used. - * - * If @a wait is set, the patch will be checked for existence before - * loading everything in to it (to prevent messing up existing patches - * that exist at the path this one should load as). - * - * If the @a existing parameter is true, the patch will be loaded into a - * currently existing patch (ie a merging will take place). Errors will - * result if Nodes of conflicting names exist. - * - * Returns the path of the newly created patch. - */ -string -PatchLibrarian::load_patch(PatchModel* pm, bool wait, bool existing) -{ - string filename = pm->filename(); - - string additional_path = (pm->parent() == NULL) - ? "" : ((PatchModel*)pm->parent())->filename(); - additional_path = additional_path.substr(0, additional_path.find_last_of("/")); - - filename = find_file(pm->filename(), additional_path); - - size_t poly = pm->poly(); - - //cerr << "[PatchLibrarian] Loading patch " << filename << "" << endl; - - const size_t temp_buf_length = 255; - char temp_buf[temp_buf_length]; - - bool load_name = (pm->path() == ""); - bool load_poly = (poly == 0); - - xmlDocPtr doc = xmlParseFile(filename.c_str()); - - if (doc == NULL ) { - cerr << "Unable to parse patch file." << endl; - return ""; - } - - xmlNodePtr cur = xmlDocGetRootElement(doc); - - if (cur == NULL) { - cerr << "Empty document." << endl; - xmlFreeDoc(doc); - return ""; - } - - if (xmlStrcmp(cur->name, (const xmlChar*) "patch")) { - cerr << "File is not an Ingen patch file (root node != <patch>)" << endl; - xmlFreeDoc(doc); - return ""; - } - - xmlChar* key = NULL; - cur = cur->xmlChildrenNode; - string path; - - pm->filename(filename); - - // Load Patch attributes - while (cur != NULL) { - key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1); - - if ((!xmlStrcmp(cur->name, (const xmlChar*)"name"))) { - if (load_name) { - assert(key != NULL); - if (pm->parent() != NULL) { - path = pm->parent()->base_path() + string((char*)key); - } else { - path = string("/") + string((char*)key); - } - assert(path.find("//") == string::npos); - assert(path.length() > 0); - pm->set_path(path); - } - } else if ((!xmlStrcmp(cur->name, (const xmlChar*)"polyphony"))) { - if (load_poly) { - poly = atoi((char*)key); - pm->poly(poly); - } - } else if (xmlStrcmp(cur->name, (const xmlChar*)"connection") - && xmlStrcmp(cur->name, (const xmlChar*)"node") - && xmlStrcmp(cur->name, (const xmlChar*)"subpatch") - && xmlStrcmp(cur->name, (const xmlChar*)"preset")) { - // Don't know what this tag is, add it as metadata without overwriting - // (so caller can set arbitrary parameters which will be preserved) - if (key != NULL) - if (pm->get_metadata((const char*)cur->name) == "") - pm->set_metadata((const char*)cur->name, (const char*)key); - } - - xmlFree(key); - key = NULL; // Avoid a (possible?) double free - - cur = cur->next; - } - - if (poly == 0) poly = 1; - - if (!existing) { - // Wait until the patch is created or the node creations may fail - if (wait) { - int id = m_osc_controller->get_next_request_id(); - m_osc_controller->set_wait_response_id(id); - m_osc_controller->create_patch(pm, id); - bool succeeded = m_osc_controller->wait_for_response(); - - // If creating the patch failed, bail out so we don't load all these nodes - // into an already existing patch - if (!succeeded) { - cerr << "[PatchLibrarian] Patch load failed (patch already exists)" << endl; - return ""; - } - } else { - m_osc_controller->create_patch(pm); - } - } - - - // Set the filename metadata. (FIXME) - // This isn't so good, considering multiple clients on multiple machines, and - // absolute filesystem paths obviously aren't going to be correct. But for now - // this is all I can figure out to have Save/Save As work properly for subpatches - m_osc_controller->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) { - m_osc_controller->add_node(nm); - m_osc_controller->set_all_metadata(nm); - for (list<PortModel*>::const_iterator j = nm->ports().begin(); - j != nm->ports().end(); ++j) { - // FIXME: ew - snprintf(temp_buf, temp_buf_length, "%f", (*j)->user_min()); - m_osc_controller->set_metadata((*j)->path(), "user-min", temp_buf); - snprintf(temp_buf, temp_buf_length, "%f", (*j)->user_max()); - m_osc_controller->set_metadata((*j)->path(), "user-max", temp_buf); - } - nm = NULL; - usleep(10000); - } - } - cur = cur->next; - } - - // Load subpatches - cur = xmlDocGetRootElement(doc)->xmlChildrenNode; - while (cur != NULL) { - if ((!xmlStrcmp(cur->name, (const xmlChar*)"subpatch"))) { - load_subpatch(pm, doc, cur); - } - cur = cur->next; - } - - // Load connections - ConnectionModel* cm = NULL; - cur = xmlDocGetRootElement(doc)->xmlChildrenNode; - while (cur != NULL) { - if ((!xmlStrcmp(cur->name, (const xmlChar*)"connection"))) { - cm = parse_connection(pm, doc, cur); - if (cm != NULL) { - m_osc_controller->connect(cm->src_port_path(), cm->dst_port_path()); - usleep(1000); - } - } - cur = cur->next; - } - - - // Load presets (control values) - PresetModel* preset_model = NULL; - cur = xmlDocGetRootElement(doc)->xmlChildrenNode; - while (cur != NULL) { - if ((!xmlStrcmp(cur->name, (const xmlChar*)"preset"))) { - preset_model = parse_preset(pm, doc, cur); - assert(preset_model != NULL); - if (preset_model->name() == "default") - m_osc_controller->set_preset(pm->path(), preset_model); - } - cur = cur->next; - } - - xmlFreeDoc(doc); - xmlCleanupParser(); - - m_osc_controller->set_all_metadata(pm); - - if (!existing) - m_osc_controller->enable_patch(pm->path()); - - string ret = pm->path(); - return ret; -} - - -/** 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) -{ - NodeModel* nm = new NodeModel("/UNINITIALIZED"); // FIXME: ew - PluginModel* plugin = new PluginModel(); - - xmlChar* key; - xmlNodePtr cur = node->xmlChildrenNode; - - bool found_name = false; - - while (cur != NULL) { - key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1); - - if ((!xmlStrcmp(cur->name, (const xmlChar*)"name"))) { - nm->set_path(parent->base_path() + (char*)key); - found_name = true; - } else if ((!xmlStrcmp(cur->name, (const xmlChar*)"polyphonic"))) { - nm->polyphonic(!strcmp((char*)key, "true")); - } else if ((!xmlStrcmp(cur->name, (const xmlChar*)"type"))) { - plugin->set_type((const char*)key); - } else if ((!xmlStrcmp(cur->name, (const xmlChar*)"library-name"))) { - plugin->lib_name((char*)key); - } else if ((!xmlStrcmp(cur->name, (const xmlChar*)"plugin-label"))) { - plugin->plug_label((char*)key); - } else if ((!xmlStrcmp(cur->name, (const xmlChar*)"plugin-uri"))) { - plugin->uri((char*)key); - } else if ((!xmlStrcmp(cur->name, (const xmlChar*)"port"))) { - xmlNodePtr child = cur->xmlChildrenNode; - - string path; - float user_min = 0.0; - float user_max = 0.0; - - while (child != NULL) { - key = xmlNodeListGetString(doc, child->xmlChildrenNode, 1); - - if ((!xmlStrcmp(child->name, (const xmlChar*)"name"))) { - path = nm->base_path() + (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"))) { - user_max = atof((char*)key); - } - - xmlFree(key); - key = NULL; // Avoid a (possible?) double free - - child = child->next; - } - - // FIXME: nasty assumptions - PortModel* pm = new PortModel(path, - PortModel::CONTROL, PortModel::INPUT, PortModel::NONE, - 0.0, user_min, user_max); - nm->add_port(pm); - - // DSSI hacks. Stored in the patch files as special elements, but sent to - // the engine as normal metadata with specially formatted key/values. Not - // sure if this is the best way to go about this, but it's the least damaging - // right now - } else if ((!xmlStrcmp(cur->name, (const xmlChar*)"dssi-program"))) { - xmlNodePtr child = cur->xmlChildrenNode; - - string bank; - string program; - - while (child != NULL) { - key = xmlNodeListGetString(doc, child->xmlChildrenNode, 1); - - if ((!xmlStrcmp(child->name, (const xmlChar*)"bank"))) { - bank = (char*)key; - } else if ((!xmlStrcmp(child->name, (const xmlChar*)"program"))) { - program = (char*)key; - } - - xmlFree(key); - key = NULL; // Avoid a (possible?) double free - child = child->next; - } - nm->set_metadata("dssi-program", bank +"/"+ program); - - } else if ((!xmlStrcmp(cur->name, (const xmlChar*)"dssi-configure"))) { - xmlNodePtr child = cur->xmlChildrenNode; - - string dssi_key; - string dssi_value; - - while (child != NULL) { - key = xmlNodeListGetString(doc, child->xmlChildrenNode, 1); - - if ((!xmlStrcmp(child->name, (const xmlChar*)"key"))) { - dssi_key = (char*)key; - } else if ((!xmlStrcmp(child->name, (const xmlChar*)"value"))) { - dssi_value = (char*)key; - } - - xmlFree(key); - key = NULL; // Avoid a (possible?) double free - - child = child->next; - } - nm->set_metadata(string("dssi-configure--").append(dssi_key), dssi_value); - - } else { // Don't know what this tag is, add it as metadata - if (key != NULL) - nm->set_metadata((const char*)cur->name, (const char*)key); - } - xmlFree(key); - key = NULL; - - cur = cur->next; - } - - if (nm->path() == "") { - cerr << "[PatchLibrarian] Malformed patch file (node tag has empty children)" << endl; - cerr << "[PatchLibrarian] Node ignored." << endl; - delete nm; - return NULL; - } else { - nm->plugin(plugin); - return nm; - } -} - - -void -PatchLibrarian::load_subpatch(PatchModel* parent, xmlDocPtr doc, const xmlNodePtr subpatch) -{ - xmlChar *key; - xmlNodePtr cur = subpatch->xmlChildrenNode; - - PatchModel* pm = new PatchModel("", 1); // FIXME: ew - - while (cur != NULL) { - key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1); - - if ((!xmlStrcmp(cur->name, (const xmlChar*)"name"))) { - if (parent == NULL) - pm->set_path(string("/") + (const char*)key); - else - pm->set_path(parent->base_path() + (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"))) { - pm->filename((const char*)key); - } else { // Don't know what this tag is, add it as metadata - if (key != NULL && strlen((const char*)key) > 0) - pm->set_metadata((const char*)cur->name, (const char*)key); - } - xmlFree(key); - key = NULL; - - cur = cur->next; - } - - // This needs to be done after setting the path above, to prevent - // NodeModel::set_path from calling it's parent's rename_node with - // an invalid (nonexistant) name - pm->set_parent(parent); - - load_patch(pm, false); -} - - -/** 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) -{ - //cerr << "[PatchLibrarian] Parsing connection..." << endl; - - xmlChar *key; - xmlNodePtr cur = node->xmlChildrenNode; - - string source_node, source_port, dest_node, dest_port; - - while (cur != NULL) { - key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1); - - if ((!xmlStrcmp(cur->name, (const xmlChar*)"source-node"))) { - source_node = (char*)key; - } else if ((!xmlStrcmp(cur->name, (const xmlChar*)"source-port"))) { - source_port = (char*)key; - } else if ((!xmlStrcmp(cur->name, (const xmlChar*)"destination-node"))) { - dest_node = (char*)key; - } else if ((!xmlStrcmp(cur->name, (const xmlChar*)"destination-port"))) { - dest_port = (char*)key; - } - - xmlFree(key); - key = NULL; // Avoid a (possible?) double free - - cur = cur->next; - } - - if (source_node == "" || source_port == "" || dest_node == "" || dest_port == "") { - cerr << "[PatchLibrarian] Malformed patch file (connection tag has empty children)" << endl; - cerr << "[PatchLibrarian] Connection ignored." << endl; - return NULL; - } - - // FIXME: temporary compatibility, remove any slashes from port names - // remove this soon once patches have migrated - string::size_type slash_index; - while ((slash_index = source_port.find("/")) != string::npos) - source_port[slash_index] = '-'; - - while ((slash_index = dest_port.find("/")) != string::npos) - dest_port[slash_index] = '-'; - - ConnectionModel* cm = new ConnectionModel(parent->base_path() + source_node +"/"+ source_port, - parent->base_path() + dest_node +"/"+ dest_port); - - return cm; -} - - -/** 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) -{ - xmlNodePtr cur = node->xmlChildrenNode; - xmlChar* key; - - PresetModel* pm = new PresetModel(patch->base_path()); - - while (cur != NULL) { - key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1); - - if ((!xmlStrcmp(cur->name, (const xmlChar*)"name"))) { - assert(key != NULL); - pm->name((char*)key); - } else if ((!xmlStrcmp(cur->name, (const xmlChar*)"control"))) { - xmlNodePtr child = cur->xmlChildrenNode; - - string node_name = "", port_name = ""; - float val = 0.0; - - while (child != NULL) { - key = xmlNodeListGetString(doc, child->xmlChildrenNode, 1); - - if ((!xmlStrcmp(child->name, (const xmlChar*)"node-name"))) { - node_name = (char*)key; - } else if ((!xmlStrcmp(child->name, (const xmlChar*)"port-name"))) { - port_name = (char*)key; - } else if ((!xmlStrcmp(child->name, (const xmlChar*)"value"))) { - val = atof((char*)key); - } - - xmlFree(key); - key = NULL; // Avoid a (possible?) double free - - child = child->next; - } - - if (port_name == "") { - string msg = "Unable to parse control in patch file ( node = "; - msg.append(node_name).append(", port = ").append(port_name).append(")"); - m_client_hooks->error(msg); - } else { - // FIXME: temporary compatibility, remove any slashes from port name - // remove this soon once patches have migrated - string::size_type slash_index; - while ((slash_index = port_name.find("/")) != string::npos) - port_name[slash_index] = '-'; - pm->add_control(node_name, port_name, val); - } - } - xmlFree(key); - key = NULL; - cur = cur->next; - } - if (pm->name() == "") { - m_client_hooks->error("Preset in patch file has no name."); - pm->name("Unnamed"); - } - - return pm; -} - -} // namespace Client -} // namespace Ingen diff --git a/src/libs/client/PatchModel.cpp b/src/libs/client/PatchModel.cpp index 2bd514f3..3997ac77 100644 --- a/src/libs/client/PatchModel.cpp +++ b/src/libs/client/PatchModel.cpp @@ -32,7 +32,7 @@ PatchModel::add_child(SharedPtr<ObjectModel> c) { assert(c->parent().get() == this); - ObjectModel::add_child(c); + //ObjectModel::add_child(c); SharedPtr<PortModel> pm = PtrCast<PortModel>(c); if (pm) { @@ -45,12 +45,13 @@ PatchModel::add_child(SharedPtr<ObjectModel> c) signal_new_node.emit(nm); } +/* SharedPtr<NodeModel> PatchModel::get_node(const string& name) const { return PtrCast<NodeModel>(get_child(name)); } - +*/ bool PatchModel::remove_child(SharedPtr<ObjectModel> o) @@ -82,35 +83,21 @@ PatchModel::remove_child(SharedPtr<ObjectModel> o) j = next; } - if (ObjectModel::remove_child(o)) { - SharedPtr<NodeModel> nm = PtrCast<NodeModel>(o); - if (nm) { - signal_removed_node.emit(nm); - } - return true; - } else { - return false; - } + SharedPtr<NodeModel> nm = PtrCast<NodeModel>(o); + if (nm) + signal_removed_node.emit(nm); + + return true; } void PatchModel::clear() { - //for (list<SharedPtr<ConnectionModel> >::iterator j = _connections.begin(); j != _connections.end(); ++j) - // delete (*j); - - /*for (Children::iterator i = _children.begin(); i != _children.end(); ++i) { - (*i).second->clear(); - //delete (*i).second; - }*/ - - _children.clear(); _connections.clear(); NodeModel::clear(); - assert(_children.empty()); assert(_connections.empty()); assert(_ports.empty()); } diff --git a/src/libs/client/PatchModel.hpp b/src/libs/client/PatchModel.hpp index 1c35b959..642bf34f 100644 --- a/src/libs/client/PatchModel.hpp +++ b/src/libs/client/PatchModel.hpp @@ -46,7 +46,7 @@ public: const Connections& connections() const { return _connections; } SharedPtr<ConnectionModel> get_connection(const string& src_port_path, const string& dst_port_path) const; - SharedPtr<NodeModel> get_node(const string& node_name) const; + //SharedPtr<NodeModel> get_node(const string& node_name) const; void set_filename(const string& filename) { _filename = filename; } @@ -77,11 +77,11 @@ public: private: friend class Store; - PatchModel(const Path& patch_path, size_t internal_poly) - : NodeModel("ingen:patch", patch_path, false), // FIXME - _enabled(false), - _poly(internal_poly), - _editable(true) + PatchModel(Store& store, const Path& patch_path, size_t internal_poly) + : NodeModel(store, "ingen:Patch", patch_path, false) // FIXME + , _enabled(false) + , _poly(internal_poly) + , _editable(true) { } diff --git a/src/libs/client/PluginModel.cpp b/src/libs/client/PluginModel.cpp index ff26abeb..1947ddbd 100644 --- a/src/libs/client/PluginModel.cpp +++ b/src/libs/client/PluginModel.cpp @@ -47,7 +47,7 @@ PluginModel::default_node_name(SharedPtr<PatchModel> parent) snprintf(num_buf, 3, "%d", i+1); name += num_buf; } - if (!parent->get_node(name)) + if (!parent->find_child(name)) break; } diff --git a/src/libs/client/PortModel.hpp b/src/libs/client/PortModel.hpp index 8624c031..06f04e78 100644 --- a/src/libs/client/PortModel.hpp +++ b/src/libs/client/PortModel.hpp @@ -74,8 +74,8 @@ public: private: friend class Store; - PortModel(const Path& path, DataType type, Direction dir) - : ObjectModel(path, true), + PortModel(Store& store, const Path& path, DataType type, Direction dir) + : ObjectModel(store, path, true), _type(type), _direction(dir), _current_val(0.0f), diff --git a/src/libs/client/Serializer.cpp b/src/libs/client/Serializer.cpp index a8683d00..e37391d7 100644 --- a/src/libs/client/Serializer.cpp +++ b/src/libs/client/Serializer.cpp @@ -39,6 +39,7 @@ #include "interface/Connection.hpp" #include "PatchModel.hpp" #include "Serializer.hpp" +#include "Store.hpp" using namespace std; using namespace Raul; @@ -291,7 +292,7 @@ Serializer::serialize_patch(SharedPtr<PatchModel> patch) } } - for (ObjectModel::Children::const_iterator n = patch->children().begin(); n != patch->children().end(); ++n) { + for (Store::Objects::const_iterator n = patch->children_begin(); n != patch->children_end(); ++n) { SharedPtr<PatchModel> patch = PtrCast<PatchModel>(n->second); SharedPtr<NodeModel> node = PtrCast<NodeModel>(n->second); if (patch) { diff --git a/src/libs/client/Store.cpp b/src/libs/client/Store.cpp index af6b33c5..e1744ac0 100644 --- a/src/libs/client/Store.cpp +++ b/src/libs/client/Store.cpp @@ -400,7 +400,7 @@ Store::new_plugin_event(const string& uri, const string& type_uri, const string& void Store::new_patch_event(const Path& path, uint32_t poly) { - SharedPtr<PatchModel> p(new PatchModel(path, poly)); + SharedPtr<PatchModel> p(new PatchModel(*this, path, poly)); add_object(p); } @@ -412,10 +412,10 @@ Store::new_node_event(const string& plugin_uri, const Path& node_path, bool is_p SharedPtr<PluginModel> plug = plugin(plugin_uri); if (!plug) { - SharedPtr<NodeModel> n(new NodeModel(plugin_uri, node_path, is_polyphonic)); + SharedPtr<NodeModel> n(new NodeModel(*this, plugin_uri, node_path, is_polyphonic)); add_plugin_orphan(n); } else { - SharedPtr<NodeModel> n(new NodeModel(plug, node_path, is_polyphonic)); + SharedPtr<NodeModel> n(new NodeModel(*this, plug, node_path, is_polyphonic)); add_object(n); } } @@ -426,7 +426,7 @@ Store::new_port_event(const Path& path, const string& type, bool is_output) { PortModel::Direction pdir = is_output ? PortModel::OUTPUT : PortModel::INPUT; - SharedPtr<PortModel> p(new PortModel(path, type, pdir)); + SharedPtr<PortModel> p(new PortModel(*this, path, type, pdir)); add_object(p); if (p->parent()) resolve_connection_orphans(p); @@ -473,12 +473,9 @@ void Store::patch_cleared_event(const Path& path) { SharedPtr<PatchModel> patch = PtrCast<PatchModel>(object(path)); - if (patch) { - ObjectModel::Children children = patch->children(); // take a copy - for (ObjectModel::Children::iterator i = children.begin(); i != children.end(); ++i) { + if (patch) + for (ObjectModel::const_iterator i = patch->children_begin(); i != patch->children_end(); ++i) destruction_event(i->second->path()); - } - } } |