From f2d3c77c9a470f20506c90098ab5cf4d3e5c9eff Mon Sep 17 00:00:00 2001 From: David Robillard Date: Sat, 16 Dec 2017 22:27:22 +0100 Subject: Adjust indices when ports are deleted --- src/server/events/CreatePort.cpp | 29 +++++++++++++++++++---------- src/server/events/Delete.cpp | 38 ++++++++++++++++++++++++++++++++++++++ src/server/events/Delete.hpp | 7 +++++++ src/server/events/Delta.cpp | 8 ++++++++ src/server/events/Delta.hpp | 1 + 5 files changed, 73 insertions(+), 10 deletions(-) (limited to 'src/server/events') diff --git a/src/server/events/CreatePort.cpp b/src/server/events/CreatePort.cpp index 3adf2f8b..bc43ca41 100644 --- a/src/server/events/CreatePort.cpp +++ b/src/server/events/CreatePort.cpp @@ -115,14 +115,22 @@ CreatePort::pre_process(PreProcessContext& ctx) typedef Properties::const_iterator PropIter; PropIter index_i = _properties.find(uris.lv2_index); - if (index_i == _properties.end()) { + int32_t index = 0; + if (index_i != _properties.end()) { + // Ensure given index is sane and not taken + if (index_i->second.type() != uris.forge.Int) { + return Event::pre_process_done(Status::BAD_REQUEST); + } + + index = index_i->second.get(); + if (_graph->has_port_with_index(index)) { + return Event::pre_process_done(Status::BAD_INDEX); + } + } else { // No index given, append - index_i = _properties.insert( - std::make_pair(uris.lv2_index, - _engine.world()->forge().make(old_n_ports))); - } else if (index_i->second.type() != uris.forge.Int || - index_i->second.get() != old_n_ports) { - return Event::pre_process_done(Status::BAD_INDEX, _path); + index = old_n_ports; + index_i = _properties.emplace(uris.lv2_index, + _engine.world()->forge().make(index)); } const PropIter poly_i = _properties.find(uris.ingen_polyphonic); @@ -138,7 +146,7 @@ CreatePort::pre_process(PreProcessContext& ctx) // Create port _graph_port = new DuplexPort(bufs, _graph, Raul::Symbol(_path.symbol()), - _graph->num_ports_non_rt(), + index, polyphonic, _port_type, _buf_type, buf_size, value, _flow == Flow::OUTPUT); @@ -164,7 +172,6 @@ CreatePort::pre_process(PreProcessContext& ctx) assert(_graph_port->index() == (uint32_t)index_i->second.get()); assert(_graph->num_ports_non_rt() == (uint32_t)old_n_ports + 1); - assert(_graph_port->index() == (uint32_t)old_n_ports); assert(_ports_array->size() == _graph->num_ports_non_rt()); assert(_graph_port->index() < _ports_array->size()); return Event::pre_process_done(Status::SUCCESS); @@ -177,7 +184,9 @@ CreatePort::execute(RunContext& context) const MPtr& old_ports = _graph->external_ports(); if (old_ports) { for (uint32_t i = 0; i < old_ports->size(); ++i) { - (*_ports_array)[i] = (*old_ports)[i]; + const auto* const old_port = (*old_ports)[i]; + assert(old_port->index() < _ports_array->size()); + (*_ports_array)[old_port->index()] = (*old_ports)[i]; } } assert(!(*_ports_array)[_graph_port->index()]); diff --git a/src/server/events/Delete.cpp b/src/server/events/Delete.cpp index 6153540e..0a065a8a 100644 --- a/src/server/events/Delete.cpp +++ b/src/server/events/Delete.cpp @@ -61,6 +61,7 @@ Delete::~Delete() bool Delete::pre_process(PreProcessContext& ctx) { + const Ingen::URIs& uris = _engine.world()->uris(); if (_path.is_root() || _path == "/control" || _path == "/notify") { return Event::pre_process_done(Status::NOT_DELETABLE, _path); } @@ -104,6 +105,19 @@ Delete::pre_process(PreProcessContext& ctx) if (parent->enabled()) { _ports_array = parent->build_ports_array(*_engine.maid()); assert(_ports_array->size() == parent->num_ports_non_rt()); + + // Adjust port indices if necessary and record changes for later + for (size_t i = 0; i < _ports_array->size(); ++i) { + PortImpl* const port = _ports_array->at(i); + if (port->index() != i) { + _port_index_changes.emplace( + port->path(), std::make_pair(port->index(), i)); + port->remove_property(uris.lv2_index, uris.patch_wildcard); + port->set_property( + uris.lv2_index, + _engine.buffer_factory()->forge().make((int32_t)i)); + } + } } if (!parent->parent()) { @@ -131,6 +145,15 @@ Delete::execute(RunContext& context) GraphImpl* parent = _block ? _block->parent_graph() : NULL; if (_port) { + // Adjust port indices if necessary + for (size_t i = 0; i < _ports_array->size(); ++i) { + PortImpl* const port = _ports_array->at(i); + if (port->index() != i) { + port->set_index(context, i); + } + } + + // Replace ports array in graph parent = _port->parent_graph(); parent->set_external_ports(std::move(_ports_array)); @@ -165,12 +188,27 @@ Delete::post_process() void Delete::undo(Interface& target) { + const Ingen::URIs& uris = _engine.world()->uris(); + Ingen::Forge& forge = _engine.buffer_factory()->forge(); + auto i = _removed_objects.find(_path); if (i != _removed_objects.end()) { + // Undo disconnect if (_disconnect_event) { _disconnect_event->undo(target); } + + // Put deleted item back target.put(_uri, i->second->properties()); + + // Adjust port indices + for (const auto& c : _port_index_changes) { + if (c.first != _uri) { + target.set_property(path_to_uri(c.first), + uris.lv2_index, + forge.make(int32_t(c.second.first))); + } + } } } diff --git a/src/server/events/Delete.hpp b/src/server/events/Delete.hpp index 0003e821..03c994fe 100644 --- a/src/server/events/Delete.hpp +++ b/src/server/events/Delete.hpp @@ -17,6 +17,9 @@ #ifndef INGEN_EVENTS_DELETE_HPP #define INGEN_EVENTS_DELETE_HPP +#include +#include + #include "ingen/Store.hpp" #include "CompiledGraph.hpp" @@ -60,6 +63,9 @@ public: void undo(Interface& target); private: + using IndexChange = std::pair; + using IndexChanges = std::map; + Raul::URI _uri; Raul::Path _path; SPtr _block; ///< Non-NULL iff a block @@ -69,6 +75,7 @@ private: MPtr _compiled_graph; ///< Graph's new process order DisconnectAll* _disconnect_event; Store::Objects _removed_objects; + IndexChanges _port_index_changes; std::vector _removed_bindings; }; diff --git a/src/server/events/Delta.cpp b/src/server/events/Delta.cpp index 0c50aabc..fccb887c 100644 --- a/src/server/events/Delta.cpp +++ b/src/server/events/Delta.cpp @@ -312,6 +312,9 @@ Delta::pre_process(PreProcessContext& ctx) } else { _status = Status::BAD_OBJECT_TYPE; } + } else if (key == uris.lv2_index) { + op = SpecialType::PORT_INDEX; + port->set_property(key, value); } } else if ((block = dynamic_cast(_object))) { if (key == uris.midi_binding && value == uris.patch_wildcard) { @@ -498,6 +501,11 @@ Delta::execute(RunContext& context) _status = Status::INTERNAL_ERROR; } break; + case SpecialType::PORT_INDEX: + if (port) { + port->set_index(context, value.get()); + } + break; case SpecialType::CONTROL_BINDING: if (port) { if (!_engine.control_bindings()->set_port_binding(context, port, _binding, value)) { diff --git a/src/server/events/Delta.hpp b/src/server/events/Delta.hpp index 40c65ef8..24d58b99 100644 --- a/src/server/events/Delta.hpp +++ b/src/server/events/Delta.hpp @@ -87,6 +87,7 @@ private: ENABLE_BROADCAST, POLYPHONY, POLYPHONIC, + PORT_INDEX, CONTROL_BINDING, PRESET, LOADED_BUNDLE -- cgit v1.2.1