From 6f78a755b0f8c59f85cdc02e9eeca8db860a2ed2 Mon Sep 17 00:00:00 2001 From: David Robillard Date: Sat, 10 Jun 2006 01:02:08 +0000 Subject: Juggling things around... git-svn-id: http://svn.drobilla.net/lad/grauph@13 a436a847-0d15-0410-975c-d299462d15a1 --- src/engine/events/DisconnectionEvent.cpp | 295 +++++++++++++++++++++++++++++++ 1 file changed, 295 insertions(+) create mode 100644 src/engine/events/DisconnectionEvent.cpp (limited to 'src/engine/events/DisconnectionEvent.cpp') diff --git a/src/engine/events/DisconnectionEvent.cpp b/src/engine/events/DisconnectionEvent.cpp new file mode 100644 index 00000000..e7d06eab --- /dev/null +++ b/src/engine/events/DisconnectionEvent.cpp @@ -0,0 +1,295 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "DisconnectionEvent.h" +#include +#include "Responder.h" +#include "Om.h" +#include "OmApp.h" +#include "ConnectionBase.h" +#include "InputPort.h" +#include "OutputPort.h" +#include "Patch.h" +#include "ClientBroadcaster.h" +#include "Port.h" +#include "PortInfo.h" +#include "Maid.h" +#include "ObjectStore.h" +#include "util/Path.h" + +using std::string; +namespace Om { + + +//// DisconnectionEvent //// + + +DisconnectionEvent::DisconnectionEvent(CountedPtr responder, const string& src_port_path, const string& dst_port_path) +: QueuedEvent(responder), + m_src_port_path(src_port_path), + m_dst_port_path(dst_port_path), + m_patch(NULL), + m_src_port(NULL), + m_dst_port(NULL), + m_lookup(true), + m_typed_event(NULL), + m_error(NO_ERROR) +{ +} + + +DisconnectionEvent::DisconnectionEvent(CountedPtr responder, Port* const src_port, Port* const dst_port) +: QueuedEvent(responder), + m_src_port_path(src_port->path()), + m_dst_port_path(dst_port->path()), + m_patch(src_port->parent_node()->parent_patch()), + m_src_port(src_port), + m_dst_port(dst_port), + m_lookup(false), + m_typed_event(NULL), + m_error(NO_ERROR) +{ + assert(src_port->port_info()->is_output()); + assert(dst_port->port_info()->is_input()); + assert(src_port->port_info()->type() == dst_port->port_info()->type()); + assert(src_port->parent_node()->parent_patch() + == dst_port->parent_node()->parent_patch()); +} + +DisconnectionEvent::~DisconnectionEvent() +{ + delete m_typed_event; +} + + +void +DisconnectionEvent::pre_process() +{ + if (m_lookup) { + if (m_src_port_path.parent().parent() != m_dst_port_path.parent().parent()) { + m_error = PARENT_PATCH_DIFFERENT; + QueuedEvent::pre_process(); + return; + } + + /*m_patch = om->object_store()->find_patch(m_src_port_path.parent().parent()); + + if (m_patch == NULL) { + m_error = PORT_NOT_FOUND; + QueuedEvent::pre_process(); + return; + }*/ + + Port* port1 = om->object_store()->find_port(m_src_port_path); + Port* port2 = om->object_store()->find_port(m_dst_port_path); + + if (port1 == NULL || port2 == NULL) { + m_error = PORT_NOT_FOUND; + QueuedEvent::pre_process(); + return; + } + + if (port1->port_info()->type() != port2->port_info()->type()) { + m_error = TYPE_MISMATCH; + QueuedEvent::pre_process(); + return; + } + + if (port1->port_info()->is_output() && port2->port_info()->is_input()) { + m_src_port = port1; + m_dst_port = port2; + } else if (port2->port_info()->is_output() && port1->port_info()->is_input()) { + m_src_port = port2; + m_dst_port = port1; + } else { + m_error = TYPE_MISMATCH; + QueuedEvent::pre_process(); + return; + } + } + + // Create the typed event to actually do the work + const PortType type = m_src_port->port_info()->type(); + if (type == AUDIO || type == CONTROL) { + m_typed_event = new TypedDisconnectionEvent(m_responder, + (OutputPort*)m_src_port, (InputPort*)m_dst_port); + } else if (type == MIDI) { + m_typed_event = new TypedDisconnectionEvent(m_responder, + (OutputPort*)m_src_port, (InputPort*)m_dst_port); + } else { + m_error = TYPE_MISMATCH; + QueuedEvent::pre_process(); + return; + } + + m_typed_event->pre_process(); + + QueuedEvent::pre_process(); +} + + +void +DisconnectionEvent::execute(samplecount offset) +{ + QueuedEvent::execute(offset); + + if (m_error == NO_ERROR) + m_typed_event->execute(offset); +} + + +void +DisconnectionEvent::post_process() +{ + if (m_error == NO_ERROR) { + m_typed_event->post_process(); + } else { + // FIXME: better error messages + string msg = "Unable to make connection "; + msg.append(m_src_port_path + " -> " + m_dst_port_path); + m_responder->respond_error(msg); + } +} + + + +//// TypedDisconnectionEvent //// + + +template +TypedDisconnectionEvent::TypedDisconnectionEvent(CountedPtr responder, OutputPort* src_port, InputPort* dst_port) +: QueuedEvent(responder), + m_src_port(src_port), + m_dst_port(dst_port), + m_patch(NULL), + m_process_order(NULL), + m_succeeded(true) +{ + assert(src_port != NULL); + assert(dst_port != NULL); +} + +template +TypedDisconnectionEvent::~TypedDisconnectionEvent() +{ + // FIXME: haaaack, prevent a double delete + // this class is unusable by anything other than DisconnectionEvent because of this + //m_responder = NULL; +} + + +template +void +TypedDisconnectionEvent::pre_process() +{ + if (!m_dst_port->is_connected_to(m_src_port)) { + m_succeeded = false; + QueuedEvent::pre_process(); + return; + } + + Node* const src_node = m_src_port->parent_node(); + Node* const dst_node = m_dst_port->parent_node(); + + m_patch = src_node->parent_patch(); + + if (src_node == NULL || dst_node == NULL) { + m_succeeded = false; + QueuedEvent::pre_process(); + return; + } + + if (src_node->parent() != m_patch || dst_node->parent() != m_patch) { + m_succeeded = false; + QueuedEvent::pre_process(); + return; + } + + bool removed = false; + + for (List::iterator i = dst_node->providers()->begin(); i != dst_node->providers()->end(); ++i) + if ((*i) == src_node) { + delete dst_node->providers()->remove(i); + removed = true; + break; + } + assert(removed); + removed = false; + + for (List::iterator i = src_node->dependants()->begin(); i != src_node->dependants()->end(); ++i) + if ((*i) == dst_node) { + delete src_node->dependants()->remove(i); + removed = true; + break; + } + assert(removed); + + if (m_patch->process()) + m_process_order = m_patch->build_process_order(); + + m_succeeded = true; + QueuedEvent::pre_process(); +} + + +template +void +TypedDisconnectionEvent::execute(samplecount offset) +{ + if (m_succeeded) { + + ListNode*>* const port_connection + = m_dst_port->remove_connection(m_src_port); + + if (port_connection != NULL) { + ListNode* const patch_connection + = m_patch->remove_connection(m_src_port, m_dst_port); + + assert((Connection*)port_connection->elem() == patch_connection->elem()); + + // Clean up both the list node and the connection itself... + om->maid()->push(port_connection); + om->maid()->push(patch_connection); + om->maid()->push(port_connection->elem()); + + if (m_patch->process_order() != NULL) + om->maid()->push(m_patch->process_order()); + m_patch->process_order(m_process_order); + } else { + m_succeeded = false; // Ports weren't connected + } + } + QueuedEvent::execute(offset); +} + + +template +void +TypedDisconnectionEvent::post_process() +{ + if (m_succeeded) { + + m_responder->respond_ok(); + + om->client_broadcaster()->send_disconnection(m_src_port->path(), m_dst_port->path()); + } else { + m_responder->respond_error("Unable to disconnect ports."); + } +} + + +} // namespace Om + -- cgit v1.2.1