/* This file is part of Ingen. Copyright 2007-2016 David Robillard 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 Software Foundation, either version 3 of the License, or 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 Affero General Public License for details. You should have received a copy of the GNU Affero General Public License along with Ingen. If not, see . */ #include #include #include "ingen/Store.hpp" #include "raul/Array.hpp" #include "raul/Maid.hpp" #include "raul/Path.hpp" #include "ArcImpl.hpp" #include "BlockImpl.hpp" #include "Broadcaster.hpp" #include "Engine.hpp" #include "GraphImpl.hpp" #include "InputPort.hpp" #include "PortImpl.hpp" #include "PreProcessContext.hpp" #include "events/Disconnect.hpp" #include "events/DisconnectAll.hpp" #include "util.hpp" namespace Ingen { namespace Server { namespace Events { DisconnectAll::DisconnectAll(Engine& engine, SPtr client, int32_t id, SampleCount timestamp, const Raul::Path& parent_path, const Raul::Path& path) : Event(engine, client, id, timestamp) , _parent_path(parent_path) , _path(path) , _parent(NULL) , _block(NULL) , _port(NULL) , _compiled_graph(NULL) , _deleting(false) { } /** Internal version for use by other events. */ DisconnectAll::DisconnectAll(Engine& engine, GraphImpl* parent, Node* object) : Event(engine) , _parent_path(parent->path()) , _path(object->path()) , _parent(parent) , _block(dynamic_cast(object)) , _port(dynamic_cast(object)) , _compiled_graph(NULL) , _deleting(true) { } DisconnectAll::~DisconnectAll() { for (auto& i : _impls) delete i; delete _compiled_graph; } bool DisconnectAll::pre_process(PreProcessContext& ctx) { std::unique_lock lock(_engine.store()->mutex(), std::defer_lock); if (!_deleting) { lock.lock(); _parent = dynamic_cast(_engine.store()->get(_parent_path)); if (!_parent) { return Event::pre_process_done(Status::PARENT_NOT_FOUND, _parent_path); } NodeImpl* const object = dynamic_cast( _engine.store()->get(_path)); if (!object) { return Event::pre_process_done(Status::NOT_FOUND, _path); } if (object->parent_graph() != _parent && object->parent()->parent_graph() != _parent) { return Event::pre_process_done(Status::INVALID_PARENT, _parent_path); } // Only one of these will succeed _block = dynamic_cast(object); _port = dynamic_cast(object); if (!_block && !_port) { return Event::pre_process_done(Status::INTERNAL_ERROR, _path); } } // Find set of arcs to remove std::set to_remove; for (const auto& a : _parent->arcs()) { ArcImpl* const arc = (ArcImpl*)a.second.get(); if (_block) { if (arc->tail()->parent_block() == _block || arc->head()->parent_block() == _block) { to_remove.insert(arc); } } else if (_port) { if (arc->tail() == _port || arc->head() == _port) { to_remove.insert(arc); } } } // Create disconnect events (which erases from _parent->arcs()) for (const auto& a : to_remove) { _impls.push_back(new Disconnect::Impl( _engine, _parent, dynamic_cast(a->tail()), dynamic_cast(a->head()))); } if (!_deleting && ctx.must_compile(_parent)) { if (!(_compiled_graph = CompiledGraph::compile(_parent))) { return Event::pre_process_done(Status::COMPILATION_FAILED); } } return Event::pre_process_done(Status::SUCCESS); } void DisconnectAll::execute(RunContext& context) { if (_status == Status::SUCCESS) { for (auto& i : _impls) { i->execute(context, !_deleting || (i->head()->parent_block() != _block)); } } if (_compiled_graph) { _compiled_graph = _parent->swap_compiled_graph(_compiled_graph); } } void DisconnectAll::post_process() { Broadcaster::Transfer t(*_engine.broadcaster()); if (respond() == Status::SUCCESS) { _engine.broadcaster()->disconnect_all(_parent_path, _path); } } void DisconnectAll::undo(Interface& target) { for (auto& i : _impls) { target.connect(i->tail()->path(), i->head()->path()); } } } // namespace Events } // namespace Server } // namespace Ingen