diff -r 41300fa6a67c -r f7bc934e204c src/3rdparty/phonon/mmf/mmf_medianode.cpp --- a/src/3rdparty/phonon/mmf/mmf_medianode.cpp Tue Feb 02 00:43:10 2010 +0200 +++ b/src/3rdparty/phonon/mmf/mmf_medianode.cpp Wed Mar 31 11:06:36 2010 +0300 @@ -29,92 +29,123 @@ \internal */ -MMF::MediaNode::MediaNode(QObject *parent) : QObject::QObject(parent) - , m_source(0) - , m_target(0) - , m_isApplied(false) +MMF::MediaNode::MediaNode(QObject *parent) + : QObject(parent) + , m_mediaObject(qobject_cast(this)) + , m_input(0) { + } -bool MMF::MediaNode::connectMediaNode(MediaNode *target) +MMF::MediaNode::~MediaNode() { - m_target = target; - m_target->setSource(this); - - return applyNodesOnMediaObject(target); + // Phonon framework ensures nodes are disconnected before being destroyed. + Q_ASSERT_X(!m_mediaObject, Q_FUNC_INFO, + "Media node not disconnected before destruction"); } -bool MMF::MediaNode::disconnectMediaNode(MediaNode *target) -{ - Q_UNUSED(target); - m_target = 0; - m_isApplied = false; - return true; -} - -void MMF::MediaNode::setSource(MediaNode *source) +bool MMF::MediaNode::connectOutput(MediaNode *output) { - m_source = source; -} + Q_ASSERT_X(output, Q_FUNC_INFO, "Null output pointer"); + + bool connected = false; + + // Check that this connection will not result in a graph which + // containing more than one MediaObject + const bool mediaObjectMisMatch = + m_mediaObject + && output->m_mediaObject + && m_mediaObject != output->m_mediaObject; -MMF::MediaNode *MMF::MediaNode::source() const -{ - return m_source; -} + const bool canConnect = + !output->isMediaObject() + && !output->m_input + && !m_outputs.contains(output); -MMF::MediaNode *MMF::MediaNode::target() const -{ - return m_target; + if (canConnect && !mediaObjectMisMatch) { + output->m_input = this; + m_outputs += output; + updateMediaObject(); + connected = true; + } + + return connected; } -bool MMF::MediaNode::applyNodesOnMediaObject(MediaNode *) +bool MMF::MediaNode::disconnectOutput(MediaNode *output) { - // Algorithmically, this can be expressed in a more efficient way by - // exercising available assumptions, but it complicates code for input - // data(length of the graph) which typically is very small. + Q_ASSERT_X(output, Q_FUNC_INFO, "Null output pointer"); - // First, we go to the very beginning of the graph. - MMF::MediaNode *current = this; - do { - MediaNode *const candidate = current->source(); - if (candidate) - current = candidate; - else - break; - } - while (current); - - // Now we do two things, while walking to the other end: - // 1. Find the MediaObject, if present - // 2. Collect a list of all unapplied MediaNodes + bool disconnected = false; - QList unapplied; - MMF::MediaObject *mo = 0; - - do { - if (!current->m_isApplied) - unapplied.append(current); - - if (!mo) - mo = qobject_cast(current); + if (m_outputs.contains(output) && this == output->m_input) { + output->m_input = 0; + const bool removed = m_outputs.removeOne(output); + Q_ASSERT_X(removed, Q_FUNC_INFO, "Output removal failed"); - current = current->target(); - } - while (current); - - // Now, lets activate all the objects, if we found the MediaObject. + Q_ASSERT_X(!m_outputs.contains(output), Q_FUNC_INFO, + "Output list contains duplicate entries"); - if (mo) { - for (int i = 0; i < unapplied.count(); ++i) { - MediaNode *const at = unapplied.at(i); + // Perform traversal across each of the two graphs separately + updateMediaObject(); + output->updateMediaObject(); - // We don't want to apply MediaObject on itself. - if (at != mo) - at->activateOnMediaObject(mo); - } + disconnected = true; } - return true; + return disconnected; +} + +bool MMF::MediaNode::isMediaObject() const +{ + return (qobject_cast(this) != 0); +} + +void MMF::MediaNode::updateMediaObject() +{ + QList nodes; + MediaObject *mediaObject = 0; + + // Traverse the graph, collecting a list of nodes, and locating + // the MediaObject node, if present + visit(nodes, mediaObject); + + MediaNode *node = 0; + foreach(node, nodes) + node->setMediaObject(mediaObject); +} + +void MMF::MediaNode::setMediaObject(MediaObject *mediaObject) +{ + if(!isMediaObject() && m_mediaObject != mediaObject) { + if (!mediaObject) + disconnectMediaObject(m_mediaObject); + else { + Q_ASSERT_X(!m_mediaObject, Q_FUNC_INFO, "MediaObject already set"); + connectMediaObject(mediaObject); + } + m_mediaObject = mediaObject; + } +} + +void MMF::MediaNode::visit(QList& visited, MediaObject*& mediaObject) +{ + if (isMediaObject()) { + // There can never be more than one MediaObject per graph, due to the + // mediaObjectMisMatch test in connectOutput(). + Q_ASSERT_X(!mediaObject, Q_FUNC_INFO, "MediaObject already found"); + mediaObject = static_cast(this); + } + + visited += this; + + if (m_input && !visited.contains(m_input)) + m_input->visit(visited, mediaObject); + + MediaNode *output = 0; + foreach (output, m_outputs) + if (!visited.contains(output)) + output->visit(visited, mediaObject); } QT_END_NAMESPACE