]> git.sesse.net Git - kdenlive/blobdiff - src/customtrackview.cpp
First steps for the incredible filter region
[kdenlive] / src / customtrackview.cpp
index f5e7d91acae8ea22e4b6f0a266b5950375a58ba6..4651997e78b6dd999c84f5562f3878cb4b0a0858 100644 (file)
@@ -602,7 +602,7 @@ void CustomTrackView::mouseMoveEvent(QMouseEvent * event)
             // razor tool over a clip, display current frame in monitor
             if (false && !m_blockRefresh && item->type() == AVWIDGET) {
                 //TODO: solve crash when showing frame when moving razor over clip
-                emit showClipFrame(((ClipItem *) item)->baseClip(), QPoint(), mappedXPos - (clip->startPos() - clip->cropStart()).frames(m_document->fps()));
+                emit showClipFrame(((ClipItem *) item)->baseClip(), QPoint(), false, mappedXPos - (clip->startPos() - clip->cropStart()).frames(m_document->fps()));
             }
             event->accept();
             return;
@@ -1287,7 +1287,7 @@ void CustomTrackView::mouseDoubleClickEvent(QMouseEvent *event)
             //item->updateKeyframeEffect();
             //QString next = item->keyframes(item->selectedEffectIndex());
             QDomElement newEffect = item->selectedEffect().cloneNode().toElement();
-            EditEffectCommand *command = new EditEffectCommand(this, m_document->tracksCount() - item->track(), item->startPos(), oldEffect, newEffect, item->selectedEffectIndex(), false);
+            EditEffectCommand *command = new EditEffectCommand(this, m_document->tracksCount() - item->track(), item->startPos(), oldEffect, newEffect, item->selectedEffectIndex(), false, false);
             //EditKeyFrameCommand *command = new EditKeyFrameCommand(this, m_dragItem->track(), m_dragItem->startPos(), item->selectedEffectIndex(), previous, next, false);
             m_commandStack->push(command);
             updateEffect(m_document->tracksCount() - item->track(), item->startPos(), item->selectedEffect(), item->selectedEffectIndex());
@@ -1597,7 +1597,13 @@ bool CustomTrackView::insertDropClips(const QMimeData *data, const QPoint &pos)
 void CustomTrackView::dragEnterEvent(QDragEnterEvent * event)
 {
     if (insertDropClips(event->mimeData(), event->pos())) {
-        event->acceptProposedAction();
+      if (event->source() == this) {
+             event->setDropAction(Qt::MoveAction);
+             event->accept();
+         } else {
+            event->setDropAction(Qt::MoveAction);
+             event->acceptProposedAction();
+        }
     } else QGraphicsView::dragEnterEvent(event);
 }
 
@@ -1641,8 +1647,7 @@ void CustomTrackView::addEffect(int track, GenTime pos, QDomElement effect)
     if (pos < GenTime()) {
         // Add track effect
         if (effect.attribute("id") == "speed") {
-            // TODO: uncomment after 0.8.2 release
-            // emit displayMessage(i18n("Cannot add speed effect to track"));
+            emit displayMessage(i18n("Cannot add speed effect to track"), ErrorMessage);
             return;
         }
         clearSelection();
@@ -1673,6 +1678,7 @@ void CustomTrackView::addEffect(int track, GenTime pos, QDomElement effect)
         EffectsParameterList params = clip->addEffect(effect);
         if (!m_document->renderer()->mltAddEffect(track, pos, params))
             emit displayMessage(i18n("Problem adding effect to clip"), ErrorMessage);
+       clip->setSelectedEffect(params.paramValue("kdenlive_ix").toInt());
         if (clip->isSelected()) emit clipItemSelected(clip);
     } else emit displayMessage(i18n("Cannot find clip to add effect"), ErrorMessage);
 }
@@ -1722,45 +1728,43 @@ void CustomTrackView::slotAddGroupEffect(QDomElement effect, AbstractGroupItem *
     if (!namenode.isNull()) effectName = i18n(namenode.text().toUtf8().data());
     else effectName = i18n("effect");
     effectCommand->setText(i18n("Add %1", effectName));
-    int count = 0;
     for (int i = 0; i < itemList.count(); i++) {
         if (itemList.at(i)->type() == AVWIDGET) {
             ClipItem *item = static_cast <ClipItem *>(itemList.at(i));
-            if (effect.attribute("type") == "audio") {
-                // Don't add audio effects on video clips
-                if (item->isVideoOnly() || (item->clipType() != AUDIO && item->clipType() != AV && item->clipType() != PLAYLIST)) continue;
-            } else if (effect.hasAttribute("type") == false) {
-                // Don't add video effect on audio clips
-                if (item->isAudioOnly() || item->clipType() == AUDIO) continue;
-            }
-
-            if (effect.attribute("unique", "0") != "0" && item->hasEffect(effect.attribute("tag"), effect.attribute("id")) != -1) {
-                emit displayMessage(i18n("Effect already present in clip"), ErrorMessage);
-                continue;
-            }
-            if (item->isItemLocked()) {
-                continue;
-            }
-            item->initEffect(effect);
-
-            new AddEffectCommand(this, m_document->tracksCount() - item->track(), item->startPos(), effect, true, effectCommand);
-            count++;
+            if (effect.tagName() == "effectgroup") {
+               QDomNodeList effectlist = effect.elementsByTagName("effect");
+               for (int j = 0; j < effectlist.count(); j++) {
+                   processEffect(item, effectlist.at(j).toElement(), effectCommand);
+               }
+           }
+            else {
+               processEffect(item, effect, effectCommand);
+           }
         }
     }
-    if (count > 0) {
+    if (effectCommand->childCount() > 0) {
         m_commandStack->push(effectCommand);
         setDocumentModified();
     } else delete effectCommand;
 }
 
+void CustomTrackView::slotAddEffect(ClipItem *clip, QDomElement effect)
+{
+    if (clip) slotAddEffect(effect, clip->startPos(), clip->track());
+}
+
 void CustomTrackView::slotAddEffect(QDomElement effect, GenTime pos, int track)
 {
     QList<QGraphicsItem *> itemList;
     QUndoCommand *effectCommand = new QUndoCommand();
     QString effectName;
-    QDomElement namenode = effect.firstChildElement("name");
-    if (!namenode.isNull()) effectName = i18n(namenode.text().toUtf8().data());
-    else effectName = i18n("effect");
+    if (effect.tagName() == "effectgroup") {
+       effectName = effect.attribute("name");
+    } else {
+       QDomElement namenode = effect.firstChildElement("name");
+       if (!namenode.isNull()) effectName = i18n(namenode.text().toUtf8().data());
+       else effectName = i18n("effect");
+    }
     effectCommand->setText(i18n("Add %1", effectName));
 
     if (track == -1) itemList = scene()->selectedItems();
@@ -1783,39 +1787,13 @@ void CustomTrackView::slotAddEffect(QDomElement effect, GenTime pos, int track)
     for (int i = 0; i < itemList.count(); i++) {
         if (itemList.at(i)->type() == AVWIDGET) {
             ClipItem *item = static_cast <ClipItem *>(itemList.at(i));
-            if (effect.attribute("type") == "audio") {
-                // Don't add audio effects on video clips
-                if (item->isVideoOnly() || (item->clipType() != AUDIO && item->clipType() != AV && item->clipType() != PLAYLIST)) {
-                    /* do not show error message when item is part of a group as the user probably knows what he does then
-                     * and the message is annoying when working with the split audio feature */
-                    if (!item->parentItem() || item->parentItem() == m_selectionGroup)
-                        emit displayMessage(i18n("Cannot add an audio effect to this clip"), ErrorMessage);
-                    continue;
-                }
-            } else if (effect.attribute("type") == "video" || !effect.hasAttribute("type")) {
-                // Don't add video effect on audio clips
-                if (item->isAudioOnly() || item->clipType() == AUDIO) {
-                    /* do not show error message when item is part of a group as the user probably knows what he does then
-                     * and the message is annoying when working with the split audio feature */
-                    if (!item->parentItem() || item->parentItem() == m_selectionGroup)
-                        emit displayMessage(i18n("Cannot add a video effect to this clip"), ErrorMessage);
-                    continue;
-                }
-            }
-            if (item->hasEffect(effect.attribute("tag"), effect.attribute("id")) != -1 && effect.attribute("unique", "0") != "0") {
-                emit displayMessage(i18n("Effect already present in clip"), ErrorMessage);
-                continue;
-            }
-            if (item->isItemLocked()) {
-                continue;
-            }
-
-            if (effect.attribute("id") == "freeze" && m_cursorPos > item->startPos().frames(m_document->fps()) && m_cursorPos < item->endPos().frames(m_document->fps())) {
-                item->initEffect(effect, m_cursorPos - item->startPos().frames(m_document->fps()));
-            } else {
-                item->initEffect(effect);
-            }
-            new AddEffectCommand(this, m_document->tracksCount() - item->track(), item->startPos(), effect, true, effectCommand);
+           if (effect.tagName() == "effectgroup") {
+               QDomNodeList effectlist = effect.elementsByTagName("effect");
+               for (int j = 0; j < effectlist.count(); j++) {
+                   processEffect(item, effectlist.at(j).toElement(), effectCommand);
+               }
+           }
+            else processEffect(item, effect, effectCommand);
         }
     }
     if (effectCommand->childCount() > 0) {
@@ -1826,12 +1804,12 @@ void CustomTrackView::slotAddEffect(QDomElement effect, GenTime pos, int track)
            for (int i = 0; i < itemList.count(); i++) {
                if (itemList.at(i)->type() == AVWIDGET) {
                    ClipItem *clip = static_cast<ClipItem *>(itemList.at(i));
+                   clip->setSelectedEffect(clip->effectsCount());
                    if (!clip->isSelected()) {
-                       clearSelection();
+                       clearSelection(false);
                        clip->setSelected(true);
+                       emit clipItemSelected(clip);
                    }
-                   clip->setSelectedEffect(clip->effectsCount() - 1);
-                   emit clipItemSelected(clip, clip->effectsCount() - 1);
                    break;
                }
            }
@@ -1839,6 +1817,43 @@ void CustomTrackView::slotAddEffect(QDomElement effect, GenTime pos, int track)
     } else delete effectCommand;
 }
 
+void CustomTrackView::processEffect(ClipItem *item, QDomElement effect, QUndoCommand *effectCommand)
+{
+    if (effect.attribute("type") == "audio") {
+       // Don't add audio effects on video clips
+        if (item->isVideoOnly() || (item->clipType() != AUDIO && item->clipType() != AV && item->clipType() != PLAYLIST)) {
+           /* do not show error message when item is part of a group as the user probably knows what he does then
+            * and the message is annoying when working with the split audio feature */
+            if (!item->parentItem() || item->parentItem() == m_selectionGroup)
+               emit displayMessage(i18n("Cannot add an audio effect to this clip"), ErrorMessage);
+            return;
+        }
+    } else if (effect.attribute("type") == "video" || !effect.hasAttribute("type")) {
+       // Don't add video effect on audio clips
+        if (item->isAudioOnly() || item->clipType() == AUDIO) {
+           /* do not show error message when item is part of a group as the user probably knows what he does then
+            * and the message is annoying when working with the split audio feature */
+            if (!item->parentItem() || item->parentItem() == m_selectionGroup)
+               emit displayMessage(i18n("Cannot add a video effect to this clip"), ErrorMessage);
+            return;
+        }
+    }
+    if (effect.attribute("unique", "0") != "0" && item->hasEffect(effect.attribute("tag"), effect.attribute("id")) != -1) {
+       emit displayMessage(i18n("Effect already present in clip"), ErrorMessage);
+        return;
+    }
+    if (item->isItemLocked()) {
+       return;
+    }
+
+    if (effect.attribute("id") == "freeze" && m_cursorPos > item->startPos().frames(m_document->fps()) && m_cursorPos < item->endPos().frames(m_document->fps())) {
+       item->initEffect(effect, m_cursorPos - item->startPos().frames(m_document->fps()));
+    } else {
+       item->initEffect(effect);
+    }
+    new AddEffectCommand(this, m_document->tracksCount() - item->track(), item->startPos(), effect, true, effectCommand);
+}
+
 void CustomTrackView::slotDeleteEffect(ClipItem *clip, int track, QDomElement effect, bool affectGroup)
 {
     if (clip == NULL) {
@@ -1890,14 +1905,14 @@ void CustomTrackView::slotDeleteEffect(ClipItem *clip, int track, QDomElement ef
     setDocumentModified();
 }
 
-void CustomTrackView::updateEffect(int track, GenTime pos, QDomElement insertedEffect, int ix, bool triggeredByUser)
+void CustomTrackView::updateEffect(int track, GenTime pos, QDomElement insertedEffect, int ix, bool updateEffectStack)
 {
     if (insertedEffect.isNull()) {
         emit displayMessage(i18n("Problem editing effect"), ErrorMessage);
         return;
     }
     QDomElement effect = insertedEffect.cloneNode().toElement();
-    //kDebug() << "// update effect ix: " << effect.attribute("kdenlive_ix")<<", TRACK: "<<track;
+    //kDebug() << "// update effect ix: " << effect.attribute("kdenlive_ix")<<", GAIN: "<<EffectsList::parameter(effect, "gain");
     if (pos < GenTime()) {
         // editing a track effect
         EffectsParameterList effectParams = getEffectArgs(effect);
@@ -1927,12 +1942,13 @@ void CustomTrackView::updateEffect(int track, GenTime pos, QDomElement insertedE
                 if (strobe == 0) strobe = 1;
                 doChangeClipSpeed(clip->info(), clip->speedIndependantInfo(), speed, clip->speed(), strobe, clip->baseClip()->getId());
             }
-            clip->setEffectAt(ix, effect);
-            if (ix == clip->selectedEffectIndex()) {
-                clip->setSelectedEffect(ix);
-                if (!triggeredByUser)
-                    emit clipItemSelected(clip, ix);
-            }
+            clip->updateEffect(effect);
+           if (updateEffectStack && clip->isSelected())
+               emit clipItemSelected(clip);
+           if (ix == clip->selectedEffectIndex()) {
+               // make sure to update display of clip keyframes
+               clip->setSelectedEffect(ix);
+           } else emit displayMessage(i18n("Problem editing effect"), ErrorMessage);
             return;
         }
 
@@ -1954,17 +1970,21 @@ void CustomTrackView::updateEffect(int track, GenTime pos, QDomElement insertedE
                 clip->setFadeOut(pos);
             }
         }
+       bool success = m_document->renderer()->mltEditEffect(m_document->tracksCount() - clip->track(), clip->startPos(), effectParams);
 
-        if (!m_document->renderer()->mltEditEffect(m_document->tracksCount() - clip->track(), clip->startPos(), effectParams))
-            emit displayMessage(i18n("Problem editing effect"), ErrorMessage);
-
-        clip->setEffectAt(ix, effect);
-        if (ix == clip->selectedEffectIndex()) {
-            clip->setSelectedEffect(ix);
-            if (!triggeredByUser)
-                emit clipItemSelected(clip, ix);
-        }
+        if (success) {
+           clip->updateEffect(effect);
+           if (updateEffectStack && clip->isSelected()) {
+               emit clipItemSelected(clip);
+           }
+           if (ix == clip->selectedEffectIndex()) {
+               // make sure to update display of clip keyframes
+               clip->setSelectedEffect(ix);
+           }
+       }
+       else emit displayMessage(i18n("Problem editing effect"), ErrorMessage);
     }
+    else emit displayMessage(i18n("Cannot find clip to update effect"), ErrorMessage);
     setDocumentModified();
 }
 
@@ -1972,30 +1992,40 @@ void CustomTrackView::moveEffect(int track, GenTime pos, int oldPos, int newPos)
 {
     if (pos < GenTime()) {
         // Moving track effect
-        QDomElement act = m_document->getTrackEffect(m_document->tracksCount() - track - 1, newPos - 1);
-        QDomElement before = m_document->getTrackEffect(m_document->tracksCount() - track - 1, oldPos - 1);
-
+        if (newPos > m_document->getTrackEffects(m_document->tracksCount() - track - 1).count()) {
+           newPos = m_document->getTrackEffects(m_document->tracksCount() - track - 1).count();
+       }
+        QDomElement act = m_document->getTrackEffect(m_document->tracksCount() - track - 1, newPos);
+        QDomElement before = m_document->getTrackEffect(m_document->tracksCount() - track - 1, oldPos);
         if (!act.isNull() && !before.isNull()) {
-            m_document->setTrackEffect(m_document->tracksCount() - track - 1, oldPos - 1, act);
-            m_document->setTrackEffect(m_document->tracksCount() - track - 1, newPos - 1, before);
+            //m_document->setTrackEffect(m_document->tracksCount() - track - 1, oldPos, act);
+            m_document->setTrackEffect(m_document->tracksCount() - track - 1, newPos, before);
             m_document->renderer()->mltMoveEffect(m_document->tracksCount() - track, pos, oldPos, newPos);
             emit showTrackEffects(m_document->tracksCount() - track, m_document->trackInfoAt(m_document->tracksCount() - track - 1));
         } else emit displayMessage(i18n("Cannot move effect"), ErrorMessage);
         return;
     }
     ClipItem *clip = getClipItemAt((int)pos.frames(m_document->fps()), m_document->tracksCount() - track);
-    if (clip && !clip->effectAt(newPos - 1).isNull() && !clip->effectAt(oldPos - 1).isNull()) {
-        QDomElement act = clip->effectAt(newPos - 1);
-        QDomElement before = clip->effectAt(oldPos - 1);
-        clip->setEffectAt(oldPos - 1, act);
-        clip->setEffectAt(newPos - 1, before);
+    if (newPos > clip->effectsCount()) {
+       newPos = clip->effectsCount();
+    }
+    if (clip) {
+        QDomElement act = clip->effectAt(newPos);
+        QDomElement before = clip->effectAt(oldPos);
+       if (act.isNull() || before.isNull()) {
+           emit displayMessage(i18n("Cannot move effect"), ErrorMessage);
+           return;
+       }
+        //clip->moveEffect(act, oldPos);
+        clip->moveEffect(before, newPos);
         // special case: speed effect, which is a pseudo-effect, not appearing in MLT's effects
         if (act.attribute("id") == "speed") {
             m_document->renderer()->mltUpdateEffectPosition(track, pos, oldPos, newPos);
         } else if (before.attribute("id") == "speed") {
             m_document->renderer()->mltUpdateEffectPosition(track, pos, newPos, oldPos);
         } else m_document->renderer()->mltMoveEffect(track, pos, oldPos, newPos);
-        emit clipItemSelected(clip, newPos - 1);
+       clip->setSelectedEffect(newPos);
+        emit clipItemSelected(clip);
         setDocumentModified();
     } else emit displayMessage(i18n("Cannot move effect"), ErrorMessage);
 }
@@ -2012,9 +2042,9 @@ void CustomTrackView::slotChangeEffectState(ClipItem *clip, int track, int effec
 
     if (clip == NULL) {
         // editing track effect
-        command = new EditEffectCommand(this, m_document->tracksCount() - track, GenTime(-1), oldEffect, effect, effectPos, true);
+        command = new EditEffectCommand(this, m_document->tracksCount() - track, GenTime(-1), oldEffect, effect, effectPos, false, true);
     } else {
-        command = new EditEffectCommand(this, m_document->tracksCount() - clip->track(), clip->startPos(), oldEffect, effect, effectPos, true);
+        command = new EditEffectCommand(this, m_document->tracksCount() - clip->track(), clip->startPos(), oldEffect, effect, effectPos, false, true);
     }
     m_commandStack->push(command);
     setDocumentModified();;
@@ -2031,11 +2061,11 @@ void CustomTrackView::slotChangeEffectPosition(ClipItem *clip, int track, int cu
     setDocumentModified();
 }
 
-void CustomTrackView::slotUpdateClipEffect(ClipItem *clip, int track, QDomElement oldeffect, QDomElement effect, int ix)
+void CustomTrackView::slotUpdateClipEffect(ClipItem *clip, int track, QDomElement oldeffect, QDomElement effect, int ix, bool refreshEffectStack)
 {
     EditEffectCommand *command;
-    if (clip) command = new EditEffectCommand(this, m_document->tracksCount() - clip->track(), clip->startPos(), oldeffect, effect, ix, true);
-    else command = new EditEffectCommand(this, m_document->tracksCount() - track, GenTime(-1), oldeffect, effect, ix, true);
+    if (clip) command = new EditEffectCommand(this, m_document->tracksCount() - clip->track(), clip->startPos(), oldeffect, effect, ix, refreshEffectStack, true);
+    else command = new EditEffectCommand(this, m_document->tracksCount() - track, GenTime(-1), oldeffect, effect, ix, refreshEffectStack, true);
     m_commandStack->push(command);
 }
 
@@ -2044,7 +2074,7 @@ void CustomTrackView::slotUpdateClipRegion(ClipItem *clip, int ix, QString regio
     QDomElement effect = clip->getEffectAt(ix);
     QDomElement oldeffect = effect.cloneNode().toElement();
     effect.setAttribute("region", region);
-    EditEffectCommand *command = new EditEffectCommand(this, m_document->tracksCount() - clip->track(), clip->startPos(), oldeffect, effect, ix, true);
+    EditEffectCommand *command = new EditEffectCommand(this, m_document->tracksCount() - clip->track(), clip->startPos(), oldeffect, effect, ix, true, true);
     m_commandStack->push(command);
 }
 
@@ -2471,7 +2501,7 @@ void CustomTrackView::dropEvent(QDropEvent * event)
             groupSelectedItems(true);
         } else if (items.count() == 1) {
             m_dragItem = static_cast <AbstractClipItem *>(items.at(0));
-            emit clipItemSelected((ClipItem*)m_dragItem, -1, false);
+            emit clipItemSelected((ClipItem*)m_dragItem, false);
         }
         event->setDropAction(Qt::MoveAction);
         event->accept();
@@ -2638,13 +2668,14 @@ int CustomTrackView::duration() const
 
 void CustomTrackView::addTrack(TrackInfo type, int ix)
 {
+    QList <TransitionInfo> transitionInfos;
     if (ix == -1 || ix == m_document->tracksCount()) {
         m_document->insertTrack(0, type);
-        m_document->renderer()->mltInsertTrack(1, type.type == VIDEOTRACK);
+        transitionInfos = m_document->renderer()->mltInsertTrack(1, type.type == VIDEOTRACK);
     } else {
         m_document->insertTrack(m_document->tracksCount() - ix, type);
         // insert track in MLT playlist
-        m_document->renderer()->mltInsertTrack(m_document->tracksCount() - ix, type.type == VIDEOTRACK);
+        transitionInfos = m_document->renderer()->mltInsertTrack(m_document->tracksCount() - ix, type.type == VIDEOTRACK);
 
         double startY = ix * m_tracksHeight + 1 + m_tracksHeight / 2;
         QRectF r(0, startY, sceneRect().width(), sceneRect().height() - startY);
@@ -2686,14 +2717,24 @@ void CustomTrackView::addTrack(TrackInfo type, int ix)
                         emit displayMessage(i18n("Cannot update clip (time: %1, track: %2)", clipinfo.startPos.frames(m_document->fps()), clipinfo.track), ErrorMessage);
                     }
                 }
-            } else if (item->type() == TRANSITIONWIDGET) {
+            } /*else if (item->type() == TRANSITIONWIDGET) {
                 Transition *tr = static_cast <Transition *>(item);
                 int track = tr->transitionEndTrack();
                 if (track >= ix) {
                     tr->updateTransitionEndTrack(getPreviousVideoTrack(clipinfo.track));
                 }
-            }
-        }
+            }*/
+        }
+        // Sync transition tracks with MLT playlist
+        Transition *tr;        
+       TransitionInfo info;
+       for (int i = 0; i < transitionInfos.count(); i++) {
+           info = transitionInfos.at(i);
+           tr = getTransitionItem(info);
+           if (tr) tr->setForcedTrack(info.forceTrack, info.a_track);
+           else kDebug()<<"// Cannot update TRANSITION AT: "<<info.b_track<<" / "<<info.startPos.frames(m_document->fps()); 
+       }
+       
         resetSelectionGroup(false);
         m_document->renderer()->unlockService(tractor);
     }
@@ -3647,7 +3688,7 @@ void CustomTrackView::mouseReleaseEvent(QMouseEvent * event)
                 EffectsList::setParameter(oldeffect, "in", QString::number(start));
                 EffectsList::setParameter(oldeffect, "out", QString::number(end));
                 slotUpdateClipEffect(item, -1, effect, oldeffect, ix);
-                emit clipItemSelected(item, ix);
+                emit clipItemSelected(item);
             }
         } else if (item->fadeIn() != 0 && ix2 == -1) {
             QDomElement effect;
@@ -3670,7 +3711,7 @@ void CustomTrackView::mouseReleaseEvent(QMouseEvent * event)
                 EffectsList::setParameter(oldeffect, "in", QString::number(start));
                 EffectsList::setParameter(oldeffect, "out", QString::number(end));
                 slotUpdateClipEffect(item, -1, effect, oldeffect, ix2);
-                emit clipItemSelected(item, ix2);
+                emit clipItemSelected(item);
             }
         }
     } else if (m_operationMode == FADEOUT) {
@@ -3691,7 +3732,7 @@ void CustomTrackView::mouseReleaseEvent(QMouseEvent * event)
                 EffectsList::setParameter(oldeffect, "out", QString::number(end));
                 // kDebug()<<"EDIT FADE OUT : "<<start<<"x"<<end;
                 slotUpdateClipEffect(item, -1, effect, oldeffect, ix);
-                emit clipItemSelected(item, ix);
+                emit clipItemSelected(item);
             }
         } else if (item->fadeOut() != 0 && ix2 == -1) {
             QDomElement effect;
@@ -3716,7 +3757,7 @@ void CustomTrackView::mouseReleaseEvent(QMouseEvent * event)
                 EffectsList::setParameter(oldeffect, "out", QString::number(end));
                 // kDebug()<<"EDIT FADE OUT : "<<start<<"x"<<end;
                 slotUpdateClipEffect(item, -1, effect, oldeffect, ix2);
-                emit clipItemSelected(item, ix2);
+                emit clipItemSelected(item);
             }
         }
     } else if (m_operationMode == KEYFRAME) {
@@ -3743,11 +3784,11 @@ void CustomTrackView::mouseReleaseEvent(QMouseEvent * event)
         //item->updateKeyframeEffect();
         //QString next = item->keyframes(item->selectedEffectIndex());
         //EditKeyFrameCommand *command = new EditKeyFrameCommand(this, item->track(), item->startPos(), item->selectedEffectIndex(), previous, next, false);
-        EditEffectCommand *command = new EditEffectCommand(this, m_document->tracksCount() - item->track(), item->startPos(), oldEffect, newEffect, item->selectedEffectIndex(), false);
+        EditEffectCommand *command = new EditEffectCommand(this, m_document->tracksCount() - item->track(), item->startPos(), oldEffect, newEffect, item->selectedEffectIndex(), false, false);
 
         m_commandStack->push(command);
         updateEffect(m_document->tracksCount() - item->track(), item->startPos(), item->selectedEffect(), item->selectedEffectIndex());
-        emit clipItemSelected(item, item->selectedEffectIndex());
+        emit clipItemSelected(item);
     }
     if (m_dragItem && m_dragItem->type() == TRANSITIONWIDGET && m_dragItem->isSelected()) {
         // A transition is selected
@@ -3777,10 +3818,10 @@ void CustomTrackView::deleteClip(ItemInfo info, bool refresh)
         emit displayMessage(i18n("Error removing clip at %1 on track %2", m_document->timecode().getTimecodeFromFrames(info.startPos.frames(m_document->fps())), info.track), ErrorMessage);
         kDebug()<<"CANNOT REMOVE: "<<info.startPos.frames(m_document->fps())<<", TK: "<<info.track;
         //m_document->renderer()->saveSceneList(QString("/tmp/error%1.mlt").arg(m_ct), QDomElement());
-        exit(1);
         return;
     }
     m_waitingThumbs.removeAll(item);
+    item->stopThumbs();
     if (item->isSelected()) emit clipItemSelected(NULL);
     item->baseClip()->removeReference();
     m_document->updateClip(item->baseClip()->getId());
@@ -3884,34 +3925,6 @@ void CustomTrackView::deleteSelectedClips()
     m_commandStack->push(deleteSelected);
 }
 
-void CustomTrackView::changeClipSpeed()
-{
-  // TODO: remove after string freeze
-    QList<QGraphicsItem *> itemList = scene()->selectedItems();
-    if (itemList.count() == 0) {
-        emit displayMessage(i18n("Select clip to change speed"), ErrorMessage);
-        return;
-    }
-    QUndoCommand *changeSelected = new QUndoCommand();
-    changeSelected->setText("Edit clip speed");
-    int count = 0;
-    int percent = -1;
-    bool ok;
-    for (int i = 0; i < itemList.count(); i++) {
-        if (itemList.at(i)->type() == AVWIDGET) {
-            ClipItem *item = static_cast <ClipItem *>(itemList.at(i));
-            if (percent == -1) percent = QInputDialog::getInteger(this, i18n("Edit Clip Speed"), i18n("New speed (percents)"), item->speed() * 100, 1, 10000, 1, &ok);
-            if (!ok) break;
-            double speed = (double) percent / 100.0;
-            if (item->speed() != speed && (item->clipType() == VIDEO || item->clipType() == AV)) {
-                count++;
-                //new ChangeSpeedCommand(this, info, item->speed(), speed, item->clipProducer(), changeSelected);
-            }
-        }
-    }
-    if (count > 0) m_commandStack->push(changeSelected);
-    else delete changeSelected;
-}
 
 void CustomTrackView::doChangeClipSpeed(ItemInfo info, ItemInfo speedIndependantInfo, const double speed, const double oldspeed, int strobe, const QString &id)
 {
@@ -4133,9 +4146,10 @@ void CustomTrackView::addClip(QDomElement xml, const QString &clipId, ItemInfo i
         emit displayMessage(i18n("Waiting for clip..."), InformationMessage);
         emit forceClipProcessing(clipId);
         qApp->processEvents();
-        for (int i = 0; i < 3; i++) {
+        for (int i = 0; i < 10; i++) {
             if (baseclip->getProducer() == NULL) {
-                m_producerNotReady.wait(&m_mutex, 500 + 500 * i);
+                qApp->processEvents();
+                m_producerNotReady.wait(&m_mutex, 200);
             } else break;
         }
         if (baseclip->getProducer() == NULL) {
@@ -4256,9 +4270,17 @@ ClipItem *CustomTrackView::getClipItemAt(GenTime pos, int track)
     return getClipItemAt((int) pos.frames(m_document->fps()), track);
 }
 
+
+Transition *CustomTrackView::getTransitionItem(TransitionInfo info)
+{
+    int pos = info.startPos.frames(m_document->fps());
+    int track = m_document->tracksCount() - info.b_track;
+    return getTransitionItemAt(pos, track);
+}
+
 Transition *CustomTrackView::getTransitionItemAt(int pos, int track)
 {
-    const QPointF p(pos, (track + 1) * m_tracksHeight);
+    const QPointF p(pos, track * m_tracksHeight + Transition::itemOffset() + 1);
     QList<QGraphicsItem *> list = scene()->items(p);
     Transition *clip = NULL;
     for (int i = 0; i < list.size(); i++) {
@@ -4279,7 +4301,7 @@ Transition *CustomTrackView::getTransitionItemAt(GenTime pos, int track)
 Transition *CustomTrackView::getTransitionItemAtEnd(GenTime pos, int track)
 {
     int framepos = (int)(pos.frames(m_document->fps()));
-    const QPointF p(framepos - 1, (track + 1) * m_tracksHeight);
+    const QPointF p(framepos - 1, track * m_tracksHeight + Transition::itemOffset() + 1);
     QList<QGraphicsItem *> list = scene()->items(p);
     Transition *clip = NULL;
     for (int i = 0; i < list.size(); i++) {
@@ -4295,7 +4317,7 @@ Transition *CustomTrackView::getTransitionItemAtEnd(GenTime pos, int track)
 
 Transition *CustomTrackView::getTransitionItemAtStart(GenTime pos, int track)
 {
-    const QPointF p(pos.frames(m_document->fps()), (track + 1) * m_tracksHeight);
+    const QPointF p(pos.frames(m_document->fps()), track * m_tracksHeight + Transition::itemOffset() + 1);
     QList<QGraphicsItem *> list = scene()->items(p);
     Transition *clip = NULL;
     for (int i = 0; i < list.size(); ++i) {
@@ -4786,7 +4808,7 @@ void CustomTrackView::updatePositionEffects(ClipItem* item, ItemInfo info, bool
                     emit displayMessage(i18n("Problem editing effect"), ErrorMessage);
                 // if fade effect is displayed, update the effect edit widget with new clip duration
                 if (item->isSelected() && effectPos == item->selectedEffectIndex())
-                    emit clipItemSelected(item, effectPos);
+                    emit clipItemSelected(item);
             }
         }
         effectPos = item->hasEffect("brightness", "fade_from_black");
@@ -4807,7 +4829,7 @@ void CustomTrackView::updatePositionEffects(ClipItem* item, ItemInfo info, bool
                     emit displayMessage(i18n("Problem editing effect"), ErrorMessage);
                 // if fade effect is displayed, update the effect edit widget with new clip duration
                 if (item->isSelected() && effectPos == item->selectedEffectIndex())
-                    emit clipItemSelected(item, effectPos);
+                    emit clipItemSelected(item);
             }
         }
     }
@@ -4833,7 +4855,7 @@ void CustomTrackView::updatePositionEffects(ClipItem* item, ItemInfo info, bool
                     emit displayMessage(i18n("Problem editing effect"), ErrorMessage);
                 // if fade effect is displayed, update the effect edit widget with new clip duration
                 if (item->isSelected() && effectPos == item->selectedEffectIndex())
-                    emit clipItemSelected(item, effectPos);
+                    emit clipItemSelected(item);
             }
         }
         effectPos = item->hasEffect("brightness", "fade_to_black");
@@ -4854,7 +4876,7 @@ void CustomTrackView::updatePositionEffects(ClipItem* item, ItemInfo info, bool
                     emit displayMessage(i18n("Problem editing effect"), ErrorMessage);
                 // if fade effect is displayed, update the effect edit widget with new clip duration
                 if (item->isSelected() && effectPos == item->selectedEffectIndex())
-                    emit clipItemSelected(item, effectPos);
+                    emit clipItemSelected(item);
             }
         }
     }
@@ -4869,7 +4891,7 @@ void CustomTrackView::updatePositionEffects(ClipItem* item, ItemInfo info, bool
             EffectsList::setParameter(eff, "frame", QString::number(freeze_pos));
             if (standalone) {
                 if (item->isSelected() && item->selectedEffect().attribute("id") == "freeze") {
-                    emit clipItemSelected(item, item->selectedEffectIndex());
+                    emit clipItemSelected(item);
                 }
             }
         }
@@ -5553,7 +5575,7 @@ void CustomTrackView::pasteClipEffects()
     for (int i = 0; i < clips.count(); ++i) {
         if (clips.at(i)->type() == AVWIDGET) {
             ClipItem *item = static_cast < ClipItem *>(clips.at(i));
-            for (int j = 0; j < clip->effectsCount(); j++) {
+            for (int j = 1; j <= clip->effectsCount(); j++) {
                 QDomElement eff = clip->effectAt(j);
                 if (eff.attribute("unique", "0") == "0" || item->hasEffect(eff.attribute("tag"), eff.attribute("id")) == -1) {
                     adjustKeyfames(clip->cropStart(), item->cropStart(), item->cropDuration(), eff);
@@ -5779,6 +5801,7 @@ void CustomTrackView::slotInsertTrack(int ix)
         info.duration = 0;
         info.isMute = false;
         info.isLocked = false;
+       info.effectsList = EffectsList(true);
         if (d.video_track->isChecked()) {
             info.type = VIDEOTRACK;
             info.isBlind = false;
@@ -6370,6 +6393,33 @@ void CustomTrackView::slotSelectTrack(int ix)
     viewport()->update();
 }
 
+void CustomTrackView::slotSelectClipsInTrack()
+{
+    QRectF rect(0, m_selectedTrack * m_tracksHeight + m_tracksHeight / 2, sceneRect().width(), m_tracksHeight / 2 - 1);
+    QList<QGraphicsItem *> selection = m_scene->items(rect);
+    m_scene->clearSelection();
+    for (int i = 0; i < selection.count(); i++) {
+        if (selection.at(i)->type() == AVWIDGET || selection.at(i)->type() == TRANSITIONWIDGET || selection.at(i)->type() == GROUPWIDGET) {
+            selection.at(i)->setSelected(true);
+        }
+    }    
+    resetSelectionGroup();
+    groupSelectedItems();
+}
+
+void CustomTrackView::slotSelectAllClips()
+{
+    QList<QGraphicsItem *> selection = m_scene->items();
+    m_scene->clearSelection();
+    for (int i = 0; i < selection.count(); i++) {
+        if (selection.at(i)->type() == AVWIDGET || selection.at(i)->type() == TRANSITIONWIDGET  || selection.at(i)->type() == GROUPWIDGET) {
+            selection.at(i)->setSelected(true);
+        }
+    }
+    resetSelectionGroup();
+    groupSelectedItems();
+}
+
 void CustomTrackView::selectClip(bool add, bool group, int track, int pos)
 {
     QRectF rect;
@@ -6474,12 +6524,12 @@ void CustomTrackView::insertZoneOverwrite(QStringList data, int in)
         splitAudio();
 }
 
-void CustomTrackView::clearSelection()
+void CustomTrackView::clearSelection(bool emitInfo)
 {
     resetSelectionGroup();
     scene()->clearSelection();
     m_dragItem = NULL;
-    emit clipItemSelected(NULL);
+    if (emitInfo) emit clipItemSelected(NULL);
 }
 
 void CustomTrackView::updatePalette()
@@ -6491,7 +6541,6 @@ void CustomTrackView::updatePalette()
         pen1.setColor(palette().text().color());
         m_cursorLine->setPen(pen1);
     }
-    emit tracksChanged();
 }
 
 void CustomTrackView::removeTipAnimation()
@@ -6598,9 +6647,42 @@ bool CustomTrackView::hasAudio(int track) const
 
 void CustomTrackView::slotAddTrackEffect(const QDomElement &effect, int ix)
 {
-    AddEffectCommand *command = new AddEffectCommand(this, m_document->tracksCount() - ix, GenTime(-1), effect, true);
-    m_commandStack->push(command);
-    setDocumentModified();
+    
+    QUndoCommand *effectCommand = new QUndoCommand();
+    QString effectName;
+    if (effect.tagName() == "effectgroup") {
+        effectName = effect.attribute("name");
+    } else {
+        QDomElement namenode = effect.firstChildElement("name");
+        if (!namenode.isNull()) effectName = i18n(namenode.text().toUtf8().data());
+        else effectName = i18n("effect");
+    }
+    effectCommand->setText(i18n("Add %1", effectName));
+    if (effect.tagName() == "effectgroup") {
+        QDomNodeList effectlist = effect.elementsByTagName("effect");
+        for (int j = 0; j < effectlist.count(); j++) {
+            QDomElement trackeffect = effectlist.at(j).toElement();
+            if (trackeffect.attribute("unique", "0") != "0" && m_document->hasTrackEffect(m_document->tracksCount() - ix - 1, trackeffect.attribute("tag"), trackeffect.attribute("id")) != -1) {
+                emit displayMessage(i18n("Effect already present in track"), ErrorMessage);
+                continue;
+            }
+            new AddEffectCommand(this, m_document->tracksCount() - ix, GenTime(-1), trackeffect, true, effectCommand);
+        }
+    }
+    else {
+        if (effect.attribute("unique", "0") != "0" && m_document->hasTrackEffect(m_document->tracksCount() - ix - 1, effect.attribute("tag"), effect.attribute("id")) != -1) {
+            emit displayMessage(i18n("Effect already present in track"), ErrorMessage);
+            delete effectCommand;
+            return;
+        }
+        new AddEffectCommand(this, m_document->tracksCount() - ix, GenTime(-1), effect, true, effectCommand);
+    }
+
+    if (effectCommand->childCount() > 0) {
+        m_commandStack->push(effectCommand);
+        setDocumentModified();
+    }
+    else delete effectCommand;
 }
 
 
@@ -6609,23 +6691,45 @@ EffectsParameterList CustomTrackView::getEffectArgs(const QDomElement &effect)
     EffectsParameterList parameters;
     QLocale locale;
     parameters.addParam("tag", effect.attribute("tag"));
-    if (effect.hasAttribute("region")) parameters.addParam("region", effect.attribute("region"));
+    //if (effect.hasAttribute("region")) parameters.addParam("region", effect.attribute("region"));
     parameters.addParam("kdenlive_ix", effect.attribute("kdenlive_ix"));
+    parameters.addParam("kdenlive_info", effect.attribute("kdenlive_info"));
     parameters.addParam("id", effect.attribute("id"));
     if (effect.hasAttribute("src")) parameters.addParam("src", effect.attribute("src"));
     if (effect.hasAttribute("disable")) parameters.addParam("disable", effect.attribute("disable"));
     if (effect.hasAttribute("in")) parameters.addParam("in", effect.attribute("in"));
     if (effect.hasAttribute("out")) parameters.addParam("out", effect.attribute("out"));
+    if (effect.attribute("id") == "region") {
+       QDomNodeList subeffects = effect.elementsByTagName("effect");
+       for (int i = 0; i < subeffects.count(); i++) {
+           QDomElement subeffect = subeffects.at(i).toElement();
+           int subeffectix = subeffect.attribute("region_ix").toInt();
+           parameters.addParam(QString("filter%1").arg(subeffectix), subeffect.attribute("id"));
+           parameters.addParam(QString("filter%1.tag").arg(subeffectix), subeffect.attribute("tag"));
+           parameters.addParam(QString("filter%1.kdenlive_info").arg(subeffectix), subeffect.attribute("kdenlive_info"));
+           QDomNodeList subparams = subeffect.elementsByTagName("parameter");
+           adjustEffectParameters(parameters, subparams, QString("filter%1.").arg(subeffectix));
+       }
+    }
 
     QDomNodeList params = effect.elementsByTagName("parameter");
-    for (int i = 0; i < params.count(); i++) {
+    adjustEffectParameters(parameters, params);
+    
+    return parameters;
+}
+
+
+void CustomTrackView::adjustEffectParameters(EffectsParameterList &parameters, QDomNodeList params, const QString &prefix)
+{
+  QLocale locale;
+  for (int i = 0; i < params.count(); i++) {
         QDomElement e = params.item(i).toElement();
+       QString paramname = prefix + e.attribute("name");
         if (e.attribute("type") == "geometry" && !e.hasAttribute("fixed")) {
             // effects with geometry param need in / out synced with the clip, request it...
             parameters.addParam("_sync_in_out", "1");
         }
         if (e.attribute("type") == "simplekeyframe") {
-
             QStringList values = e.attribute("keyframes").split(";", QString::SkipEmptyParts);
             double factor = e.attribute("factor", "1").toDouble();
             double offset = e.attribute("offset", "0").toDouble();
@@ -6635,7 +6739,7 @@ EffectsParameterList CustomTrackView::getEffectArgs(const QDomElement &effect)
                 values[j] = pos + "=" + locale.toString(val);
             }
             // kDebug() << "/ / / /SENDING KEYFR:" << values;
-            parameters.addParam(e.attribute("name"), values.join(";"));
+            parameters.addParam(paramname, values.join(";"));
             /*parameters.addParam(e.attribute("name"), e.attribute("keyframes").replace(":", "="));
             parameters.addParam("max", e.attribute("max"));
             parameters.addParam("min", e.attribute("min"));
@@ -6671,15 +6775,15 @@ EffectsParameterList CustomTrackView::getEffectArgs(const QDomElement &effect)
                     fact = e.attribute("factor", "1").toDouble();
                 }
                 double offset = e.attribute("offset", "0").toDouble();
-                parameters.addParam(e.attribute("name"), locale.toString((e.attribute("value").toDouble() - offset) / fact));
+                parameters.addParam(paramname, locale.toString((e.attribute("value").toDouble() - offset) / fact));
             } else {
-                parameters.addParam(e.attribute("name"), e.attribute("value"));
+                parameters.addParam(paramname, e.attribute("value"));
             }
         }
     }
-    return parameters;
 }
 
+
 void CustomTrackView::updateTrackNames(int track, bool added)
 {
     QList <TrackInfo> tracks = m_document->tracksList();
@@ -6769,10 +6873,35 @@ void CustomTrackView::adjustEffects(ClipItem* item, ItemInfo oldInfo, QUndoComma
     if (effects.count()) {
         QMap<int, QDomElement>::const_iterator i = effects.constBegin();
         while (i != effects.constEnd()) {
-            new EditEffectCommand(this, m_document->tracksCount() - item->track(), item->startPos(), i.value(), item->effectAt(i.key()), i.key(), false, command);
+            new EditEffectCommand(this, m_document->tracksCount() - item->track(), item->startPos(), i.value(), item->effectAt(i.key()), i.key(), false, false, command);
+            ++i;
+        }
+    }
+}
+
+
+void CustomTrackView::slotGotFilterJobResults(const QString &/*id*/, int startPos, int track, const QString &filter, stringMap filterParams)
+{
+    ClipItem *clip = getClipItemAt(GenTime(startPos, m_document->fps()), track);
+    if (clip == NULL) {
+        emit displayMessage(i18n("Cannot find clip for effect update %1.", filter), ErrorMessage);
+        return;
+    }
+    QDomElement newEffect;
+    QDomElement effect = clip->getEffectAt(clip->selectedEffectIndex());
+    if (effect.attribute("id") == filter) {
+        newEffect = effect.cloneNode().toElement();
+        QMap<QString, QString>::const_iterator i = filterParams.constBegin();
+        while (i != filterParams.constEnd()) {
+            EffectsList::setParameter(newEffect, i.key(), i.value());
+            kDebug()<<"// RESULT FILTER: "<<i.key()<<"="<< i.value();
             ++i;
         }
+        EditEffectCommand *command = new EditEffectCommand(this, m_document->tracksCount() - clip->track(), clip->startPos(), effect, newEffect, clip->selectedEffectIndex(), true, true);
+        m_commandStack->push(command);
+        emit clipItemSelected(clip);
     }
+    
 }