summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ingen/ClashAvoider.hpp10
-rw-r--r--src/ClashAvoider.cpp47
-rw-r--r--src/Resource.cpp4
-rw-r--r--src/gui/GraphCanvas.cpp23
4 files changed, 78 insertions, 6 deletions
diff --git a/ingen/ClashAvoider.hpp b/ingen/ClashAvoider.hpp
index 23656349..6032351a 100644
--- a/ingen/ClashAvoider.hpp
+++ b/ingen/ClashAvoider.hpp
@@ -41,6 +41,16 @@ public:
bool exists(const Raul::Path& path) const;
+ /** Adjust a new label by increasing the numeric suffix if any.
+ *
+ * @param old_path The old path that was mapped with `map_path()`
+ * @param new_path The new path that `old_path` was mapped to
+ * @param name The old name.
+ */
+ static std::string adjust_name(const Raul::Path& old_path,
+ const Raul::Path& new_path,
+ std::string name);
+
private:
typedef std::map<Raul::Path, unsigned> Offsets;
typedef std::map<Raul::Path, Raul::Path> SymbolMap;
diff --git a/src/ClashAvoider.cpp b/src/ClashAvoider.cpp
index fdbc45b4..dbcc1a7e 100644
--- a/src/ClashAvoider.cpp
+++ b/src/ClashAvoider.cpp
@@ -1,6 +1,6 @@
/*
This file is part of Ingen.
- Copyright 2007-2015 David Robillard <http://drobilla.net/>
+ Copyright 2007-2018 David Robillard <http://drobilla.net/>
Ingen is free software: you can redistribute it and/or modify it under the
terms of the GNU Affero General Public License as published by the Free
@@ -15,11 +15,14 @@
*/
#include <cassert>
+#include <cctype>
#include <cstdio>
#include <sstream>
#include <string>
#include <utility>
+#include <boost/optional.hpp>
+
#include "ingen/ClashAvoider.hpp"
#include "ingen/Store.hpp"
#include "ingen/paths.hpp"
@@ -133,4 +136,46 @@ ClashAvoider::exists(const Raul::Path& path) const
return _store.find(path) != _store.end();
}
+static boost::optional<size_t>
+numeric_suffix_start(const std::string& str)
+{
+ if (!isdigit(str[str.length() - 1])) {
+ return {};
+ }
+
+ size_t i = str.length() - 1;
+ while (i > 0 && isdigit(str[i - 1])) {
+ --i;
+ }
+
+ return i;
+}
+
+std::string
+ClashAvoider::adjust_name(const Raul::Path& old_path,
+ const Raul::Path& new_path,
+ std::string name)
+{
+ const auto name_suffix_start = numeric_suffix_start(name);
+ if (!name_suffix_start) {
+ return name; // No numeric suffix, just re-use old label
+ }
+
+ const auto name_suffix = atoi(name.c_str() + *name_suffix_start);
+ const auto old_suffix_start = numeric_suffix_start(old_path);
+ const auto new_suffix_start = numeric_suffix_start(new_path);
+ if (old_suffix_start && new_suffix_start) {
+ // Add the offset applied to the symbol to the label suffix
+ const auto old_suffix = atoi(old_path.c_str() + *old_suffix_start);
+ const auto new_suffix = atoi(new_path.c_str() + *new_suffix_start);
+ const auto offset = new_suffix - old_suffix;
+ return (name.substr(0, *name_suffix_start) +
+ std::to_string(name_suffix + offset));
+ } else {
+ // Add 1 to previous label suffix
+ return (name.substr(0, *name_suffix_start) +
+ std::to_string(name_suffix + 1));
+ }
+}
+
} // namespace ingen
diff --git a/src/Resource.cpp b/src/Resource.cpp
index 28bdaa52..86403388 100644
--- a/src/Resource.cpp
+++ b/src/Resource.cpp
@@ -221,6 +221,10 @@ Resource::remove_properties(const Properties& props)
Properties
Resource::properties(Resource::Graph ctx) const
{
+ if (ctx == Resource::Graph::DEFAULT) {
+ return properties();
+ }
+
Properties props;
for (const auto& p : _properties) {
if (p.second.context() == ctx) {
diff --git a/src/gui/GraphCanvas.cpp b/src/gui/GraphCanvas.cpp
index 37974d1e..931cc23f 100644
--- a/src/gui/GraphCanvas.cpp
+++ b/src/gui/GraphCanvas.cpp
@@ -734,12 +734,25 @@ GraphCanvas::paste()
const URI& old_uri = path_to_uri(old_path);
const Raul::Path& new_path = avoider.map_path(parent.child(node->path()));
- Properties props{{uris.lv2_prototype,
- _app.forge().make_urid(old_uri)}};
+ // Copy properties, except those that should not be inherited in copies
+ Properties props = node->properties();
+ for (const auto& prop : {uris.lv2_prototype,
+ uris.ingen_canvasX,
+ uris.ingen_canvasY,
+ uris.lv2_index,
+ uris.lv2_symbol}) {
+ props.erase(prop);
+ }
+
+ // Store the old URI as a prototype (keeps provenance around)
+ props.emplace(uris.lv2_prototype, _app.forge().make_urid(old_uri));
- // Set the same types
- const auto t = node->properties().equal_range(uris.rdf_type);
- props.insert(t.first, t.second);
+ // Adjust numeric suffix on name if appropriate
+ auto n = props.find(uris.lv2_name);
+ if (n != props.end()) {
+ n->second = _app.forge().alloc(ClashAvoider::adjust_name(
+ old_path, new_path, n->second.ptr<char>()));
+ }
// Set coordinates so paste origin is at the mouse pointer
PropIter xi = node->properties().find(uris.ingen_canvasX);