summaryrefslogtreecommitdiffstats
path: root/src/libs/client
diff options
context:
space:
mode:
authorDavid Robillard <d@drobilla.net>2007-10-08 02:57:21 +0000
committerDavid Robillard <d@drobilla.net>2007-10-08 02:57:21 +0000
commit4675e82dae45a70ee27bf11d10aa6872485c8847 (patch)
tree24210667e721d400a552ad2621e9a5cfe447395c /src/libs/client
parent9d9efa215c52a6b75eef7e9a8b088b11dfd76a07 (diff)
downloadingen-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.cpp15
-rw-r--r--src/libs/client/NodeModel.hpp4
-rw-r--r--src/libs/client/ObjectModel.cpp65
-rw-r--r--src/libs/client/ObjectModel.hpp23
-rw-r--r--src/libs/client/PatchLibrarian.cpp.new833
-rw-r--r--src/libs/client/PatchModel.cpp29
-rw-r--r--src/libs/client/PatchModel.hpp12
-rw-r--r--src/libs/client/PluginModel.cpp2
-rw-r--r--src/libs/client/PortModel.hpp4
-rw-r--r--src/libs/client/Serializer.cpp3
-rw-r--r--src/libs/client/Store.cpp15
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());
- }
- }
}