src/3rdparty/phonon/mmf/mmf_medianode.cpp
branchRCL_3
changeset 4 3b1da2848fc7
parent 0 1918ee327afb
--- a/src/3rdparty/phonon/mmf/mmf_medianode.cpp	Tue Feb 02 00:43:10 2010 +0200
+++ b/src/3rdparty/phonon/mmf/mmf_medianode.cpp	Fri Feb 19 23:40:16 2010 +0200
@@ -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<MediaObject *>(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<MediaNode *> unapplied;
-    MMF::MediaObject *mo = 0;
-
-    do {
-        if (!current->m_isApplied)
-            unapplied.append(current);
-
-        if (!mo)
-            mo = qobject_cast<MMF::MediaObject *>(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<const MediaObject *>(this) != 0);
+}
+
+void MMF::MediaNode::updateMediaObject()
+{
+    QList<MediaNode *> 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<MediaNode *>& 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<MediaObject *>(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