]> git.sesse.net Git - kdenlive/blobdiff - src/customtrackview.cpp
Fix another problem with changing the duration of a clip with a pan and zoom effect
[kdenlive] / src / customtrackview.cpp
index 61e096a92b1ca0233b41924ef6a375fce3576071..754ad483fc06696a959597a2b123460d46b7dc75 100644 (file)
@@ -60,6 +60,7 @@
 #include "configtrackscommand.h"
 #include "rebuildgroupcommand.h"
 #include "razorgroupcommand.h"
+#include "profilesdialog.h"
 
 #include <KDebug>
 #include <KLocale>
@@ -1068,6 +1069,9 @@ void CustomTrackView::rebuildGroup(int childTrack, GenTime childPos)
 void CustomTrackView::rebuildGroup(AbstractGroupItem *group)
 {
     if (group) {
+        resetSelectionGroup(false);
+        m_scene->clearSelection();
+
         QList <QGraphicsItem *> children = group->childItems();
         m_document->clipManager()->removeGroup(group);
         scene()->destroyItemGroup(group);
@@ -1537,7 +1541,7 @@ void CustomTrackView::slotRefreshEffects(ClipItem *clip)
     }
     bool success = true;
     for (int i = 0; i < clip->effectsCount(); i++) {
-        if (!m_document->renderer()->mltAddEffect(track, pos, clip->getEffectArgs(clip->effectAt(i)), false)) success = false;
+        if (!m_document->renderer()->mltAddEffect(track, pos, getEffectArgs(clip->effectAt(i)), false)) success = false;
     }
     if (!success) emit displayMessage(i18n("Problem adding effect to clip"), ErrorMessage);
     m_document->renderer()->doRefresh();
@@ -1545,6 +1549,13 @@ void CustomTrackView::slotRefreshEffects(ClipItem *clip)
 
 void CustomTrackView::addEffect(int track, GenTime pos, QDomElement effect)
 {
+    if (pos < GenTime()) {
+        // Add track effect
+        m_document->addTrackEffect(track - 1, effect);
+        m_document->renderer()->mltAddTrackEffect(track, getEffectArgs(effect));
+        emit showTrackEffects(track, m_document->trackInfoAt(track - 1));
+        return;
+    }
     ClipItem *clip = getClipItemAt((int)pos.frames(m_document->fps()), m_document->tracksCount() - track);
     if (clip) {
         // Special case: speed effect
@@ -1572,6 +1583,13 @@ void CustomTrackView::addEffect(int track, GenTime pos, QDomElement effect)
 void CustomTrackView::deleteEffect(int track, GenTime pos, QDomElement effect)
 {
     QString index = effect.attribute("kdenlive_ix");
+    if (pos < GenTime()) {
+        // Delete track effect
+        m_document->removeTrackEffect(track - 1, effect);
+        m_document->renderer()->mltRemoveTrackEffect(track, index, true);
+        emit showTrackEffects(track, m_document->trackInfoAt(track - 1));
+        return;
+    }
     // Special case: speed effect
     if (effect.attribute("id") == "speed") {
         ClipItem *clip = getClipItemAt((int)pos.frames(m_document->fps()), m_document->tracksCount() - track);
@@ -1672,13 +1690,19 @@ void CustomTrackView::slotAddEffect(QDomElement effect, GenTime pos, int track)
             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)) {
-                    emit displayMessage(i18n("Cannot add an audio effect to this clip"), ErrorMessage);
+                    /* 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.hasAttribute("type") == false) {
+            } else if (effect.attribute("type") == "video" || !effect.hasAttribute("type")) {
                 // Don't add video effect on audio clips
                 if (item->isAudioOnly() || item->clipType() == AUDIO) {
-                    emit displayMessage(i18n("Cannot add a video effect to this clip"), ErrorMessage);
+                    /* 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;
                 }
             }
@@ -1689,9 +1713,13 @@ void CustomTrackView::slotAddEffect(QDomElement effect, GenTime pos, int track)
             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);
+            } else {
+                item->initEffect(effect);
+            }
+
             if (effect.attribute("tag") == "ladspa") {
                 QString ladpsaFile = m_document->getLadspaFile();
                 initEffects::ladspaEffectFile(ladpsaFile, effect.attribute("ladspaid").toInt(), getLadspaParams(effect));
@@ -1706,8 +1734,15 @@ void CustomTrackView::slotAddEffect(QDomElement effect, GenTime pos, int track)
     } else delete effectCommand;
 }
 
-void CustomTrackView::slotDeleteEffect(ClipItem *clip, QDomElement effect, bool affectGroup)
+void CustomTrackView::slotDeleteEffect(ClipItem *clip, int track, QDomElement effect, bool affectGroup)
 {
+    if (clip == NULL) {
+        // delete track effect
+        AddEffectCommand *command = new AddEffectCommand(this, track, GenTime(-1), effect, false);
+        m_commandStack->push(command);
+        setDocumentModified();
+        return;
+    }
     if (affectGroup && clip->parentItem() && clip->parentItem() == m_selectionGroup) {
         //clip is in a group, also remove the effect in other clips of the group
         QList<QGraphicsItem *> items = m_selectionGroup->childItems();
@@ -1753,8 +1788,28 @@ void CustomTrackView::updateEffect(int track, GenTime pos, QDomElement insertedE
         emit displayMessage(i18n("Problem editing effect"), ErrorMessage);
         return;
     }
-    ClipItem *clip = getClipItemAt((int)pos.frames(m_document->fps()), m_document->tracksCount() - track);
     QDomElement effect = insertedEffect.cloneNode().toElement();
+    kDebug() << "// update effect ix: " << effect.attribute("kdenlive_ix");
+    if (pos < GenTime()) {
+        // editing a track effect
+        EffectsParameterList effectParams = getEffectArgs(effect);
+        if (effect.attribute("tag") == "ladspa") {
+            // Update the ladspa affect file
+            initEffects::ladspaEffectFile(effect.attribute("src"), effect.attribute("ladspaid").toInt(), getLadspaParams(effect));
+        }
+        // check if we are trying to reset a keyframe effect
+        if (effectParams.hasParam("keyframes") && effectParams.paramValue("keyframes").isEmpty()) {
+            //clip->initEffect(effect);
+            effectParams = getEffectArgs(effect);
+        }
+        if (!m_document->renderer()->mltEditEffect(m_document->tracksCount() - track, pos, effectParams))
+            emit displayMessage(i18n("Problem editing effect"), ErrorMessage);
+        m_document->setTrackEffect(m_document->tracksCount() - track - 1, ix, effect);
+        setDocumentModified();
+        return;
+
+    }
+    ClipItem *clip = getClipItemAt((int)pos.frames(m_document->fps()), m_document->tracksCount() - track);
     if (clip) {
         // Special case: speed effect
         if (effect.attribute("id") == "speed") {
@@ -1773,7 +1828,7 @@ void CustomTrackView::updateEffect(int track, GenTime pos, QDomElement insertedE
             return;
         }
 
-        EffectsParameterList effectParams = clip->getEffectArgs(effect);
+        EffectsParameterList effectParams = getEffectArgs(effect);
         if (effect.attribute("tag") == "ladspa") {
             // Update the ladspa affect file
             initEffects::ladspaEffectFile(effect.attribute("src"), effect.attribute("ladspaid").toInt(), getLadspaParams(effect));
@@ -1781,7 +1836,7 @@ void CustomTrackView::updateEffect(int track, GenTime pos, QDomElement insertedE
         // check if we are trying to reset a keyframe effect
         if (effectParams.hasParam("keyframes") && effectParams.paramValue("keyframes").isEmpty()) {
             clip->initEffect(effect);
-            effectParams = clip->getEffectArgs(effect);
+            effectParams = getEffectArgs(effect);
         }
         if (!m_document->renderer()->mltEditEffect(m_document->tracksCount() - clip->track(), clip->startPos(), effectParams))
             emit displayMessage(i18n("Problem editing effect"), ErrorMessage);
@@ -1808,6 +1863,19 @@ void CustomTrackView::updateEffect(int track, GenTime pos, QDomElement insertedE
 
 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 (!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->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);
@@ -1825,27 +1893,42 @@ void CustomTrackView::moveEffect(int track, GenTime pos, int oldPos, int newPos)
     } else emit displayMessage(i18n("Cannot move effect"), ErrorMessage);
 }
 
-void CustomTrackView::slotChangeEffectState(ClipItem *clip, int effectPos, bool disable)
+void CustomTrackView::slotChangeEffectState(ClipItem *clip, int track, int effectPos, bool disable)
 {
-    QDomElement effect = clip->effectAt(effectPos);
+    EditEffectCommand *command;
+    QDomElement effect;
+    if (clip == NULL) effect = m_document->getTrackEffect(track - 1, effectPos);
+    else effect = clip->effectAt(effectPos);
     QDomElement oldEffect = effect.cloneNode().toElement();
-
     effect.setAttribute("disable", (int) disable);
-    EditEffectCommand *command = new EditEffectCommand(this, m_document->tracksCount() - clip->track(), clip->startPos(), oldEffect, effect, effectPos, true);
+
+
+    if (clip == NULL) {
+        // editing track effect
+        command = new EditEffectCommand(this, m_document->tracksCount() - track, GenTime(-1), oldEffect, effect, effectPos, true);
+    } else {
+        command = new EditEffectCommand(this, m_document->tracksCount() - clip->track(), clip->startPos(), oldEffect, effect, effectPos, true);
+    }
     m_commandStack->push(command);
     setDocumentModified();;
 }
 
-void CustomTrackView::slotChangeEffectPosition(ClipItem *clip, int currentPos, int newPos)
+void CustomTrackView::slotChangeEffectPosition(ClipItem *clip, int track, int currentPos, int newPos)
 {
-    MoveEffectCommand *command = new MoveEffectCommand(this, m_document->tracksCount() - clip->track(), clip->startPos(), currentPos, newPos);
+    MoveEffectCommand *command;
+    if (clip == NULL) {
+        // editing track effect
+        command = new MoveEffectCommand(this, m_document->tracksCount() - track, GenTime(-1), currentPos, newPos);
+    } else command = new MoveEffectCommand(this, m_document->tracksCount() - clip->track(), clip->startPos(), currentPos, newPos);
     m_commandStack->push(command);
     setDocumentModified();
 }
 
-void CustomTrackView::slotUpdateClipEffect(ClipItem *clip, QDomElement oldeffect, QDomElement effect, int ix)
+void CustomTrackView::slotUpdateClipEffect(ClipItem *clip, int track, QDomElement oldeffect, QDomElement effect, int ix)
 {
-    EditEffectCommand *command = new EditEffectCommand(this, m_document->tracksCount() - clip->track(), clip->startPos(), oldeffect, effect, ix, true);
+    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);
     m_commandStack->push(command);
 }
 
@@ -2243,6 +2326,7 @@ void CustomTrackView::dropEvent(QDropEvent * event)
 
         m_pasteEffectsAction->setEnabled(m_copiedItems.count() == 1);
         if (items.count() > 1) groupSelectedItems(true);
+        else if (items.count() == 1) m_dragItem = static_cast <ClipItem *>(items.at(0));
         event->setDropAction(Qt::MoveAction);
         event->accept();
     } else QGraphicsView::dropEvent(event);
@@ -3122,8 +3206,7 @@ void CustomTrackView::mouseReleaseEvent(QMouseEvent * event)
                     emit displayMessage(i18n("Cannot move clip to position %1", m_document->timecode().getTimecodeFromFrames(m_dragItemInfo.startPos.frames(m_document->fps()))), ErrorMessage);
                 }
                 setDocumentModified();
-            }
-            if (m_dragItem->type() == TRANSITIONWIDGET && (m_dragItemInfo.startPos != info.startPos || m_dragItemInfo.track != info.track)) {
+            } else if (m_dragItem->type() == TRANSITIONWIDGET && (m_dragItemInfo.startPos != info.startPos || m_dragItemInfo.track != info.track)) {
                 Transition *transition = static_cast <Transition *>(m_dragItem);
                 transition->updateTransitionEndTrack(getPreviousVideoTrack(m_dragItem->track()));
                 if (!m_document->renderer()->mltMoveTransition(transition->transitionTag(), (int)(m_document->tracksCount() - m_dragItemInfo.track), (int)(m_document->tracksCount() - m_dragItem->track()), transition->transitionEndTrack(), m_dragItemInfo.startPos, m_dragItemInfo.endPos, info.startPos, info.endPos)) {
@@ -3142,7 +3225,11 @@ void CustomTrackView::mouseReleaseEvent(QMouseEvent * event)
         } else {
             // Moving several clips. We need to delete them and readd them to new position,
             // or they might overlap each other during the move
-            QGraphicsItemGroup *group = static_cast <QGraphicsItemGroup *>(m_dragItem->parentItem());
+            QGraphicsItemGroup *group;
+            if (m_selectionGroup)
+                group = static_cast <QGraphicsItemGroup *>(m_selectionGroup);
+            else
+                group = static_cast <QGraphicsItemGroup *>(m_dragItem->parentItem());
             QList<QGraphicsItem *> items = group->childItems();
 
             QList<ItemInfo> clipsToMove;
@@ -3208,7 +3295,7 @@ void CustomTrackView::mouseReleaseEvent(QMouseEvent * event)
                             prod = clip->baseClip()->producer(info.track);
                         m_document->renderer()->mltInsertClip(info, clip->xml(), prod, m_scene->editMode() == OVERWRITEEDIT, m_scene->editMode() == INSERTEDIT);
                         for (int i = 0; i < clip->effectsCount(); i++) {
-                            m_document->renderer()->mltAddEffect(info.track, info.startPos, clip->getEffectArgs(clip->effectAt(i)), false);
+                            m_document->renderer()->mltAddEffect(info.track, info.startPos, getEffectArgs(clip->effectAt(i)), false);
                         }
                     } else {
                         Transition *tr = static_cast <Transition*>(item);
@@ -3232,6 +3319,22 @@ void CustomTrackView::mouseReleaseEvent(QMouseEvent * event)
                 if (m_selectionGroup) {
                     m_selectionGroupInfo.startPos = GenTime(m_selectionGroup->scenePos().x(), m_document->fps());
                     m_selectionGroupInfo.track = m_selectionGroup->track();
+
+                    for (int i = 0; i < items.count(); ++i) {
+                        if (items.at(i)->type() == GROUPWIDGET) {
+                            rebuildGroup((AbstractGroupItem*)items.at(i));
+                            items.removeAt(i);
+                            --i;
+                        }
+                    }
+                    for (int i = 0; i < items.count(); ++i) {
+                        if (items.at(i)) {
+                            items.at(i)->setSelected(true);
+                            if (items.at(i)->parentItem())
+                                items.at(i)->parentItem()->setSelected(true);
+                        }
+                    }
+                    groupSelectedItems();
                 } else {
                     rebuildGroup((AbstractGroupItem *)group);
                 }
@@ -3297,13 +3400,13 @@ void CustomTrackView::mouseReleaseEvent(QMouseEvent * event)
             int start = item->cropStart().frames(m_document->fps());
             int end = item->fadeIn();
             if (end == 0) {
-                slotDeleteEffect(item, oldeffect, false);
+                slotDeleteEffect(item, -1, oldeffect, false);
             } else {
                 end += start;
                 QDomElement effect = oldeffect.cloneNode().toElement();
                 EffectsList::setParameter(oldeffect, "in", QString::number(start));
                 EffectsList::setParameter(oldeffect, "out", QString::number(end));
-                slotUpdateClipEffect(item, effect, oldeffect, ix);
+                slotUpdateClipEffect(item, -1, effect, oldeffect, ix);
                 emit clipItemSelected(item, ix);
             }
         } else if (item->fadeIn() != 0 && ix2 == -1) {
@@ -3320,13 +3423,13 @@ void CustomTrackView::mouseReleaseEvent(QMouseEvent * event)
             int start = item->cropStart().frames(m_document->fps());
             int end = item->fadeIn();
             if (end == 0) {
-                slotDeleteEffect(item, oldeffect, false);
+                slotDeleteEffect(item, -1, oldeffect, false);
             } else {
                 end += start;
                 QDomElement effect = oldeffect.cloneNode().toElement();
                 EffectsList::setParameter(oldeffect, "in", QString::number(start));
                 EffectsList::setParameter(oldeffect, "out", QString::number(end));
-                slotUpdateClipEffect(item, effect, oldeffect, ix2);
+                slotUpdateClipEffect(item, -1, effect, oldeffect, ix2);
                 emit clipItemSelected(item, ix2);
             }
         }
@@ -3340,14 +3443,14 @@ void CustomTrackView::mouseReleaseEvent(QMouseEvent * event)
             int end = (item->cropDuration() + item->cropStart()).frames(m_document->fps());
             int start = item->fadeOut();
             if (start == 0) {
-                slotDeleteEffect(item, oldeffect, false);
+                slotDeleteEffect(item, -1, oldeffect, false);
             } else {
                 start = end - start;
                 QDomElement effect = oldeffect.cloneNode().toElement();
                 EffectsList::setParameter(oldeffect, "in", QString::number(start));
                 EffectsList::setParameter(oldeffect, "out", QString::number(end));
                 // kDebug()<<"EDIT FADE OUT : "<<start<<"x"<<end;
-                slotUpdateClipEffect(item, effect, oldeffect, ix);
+                slotUpdateClipEffect(item, -1, effect, oldeffect, ix);
                 emit clipItemSelected(item, ix);
             }
         } else if (item->fadeOut() != 0 && ix2 == -1) {
@@ -3365,14 +3468,14 @@ void CustomTrackView::mouseReleaseEvent(QMouseEvent * event)
             int end = (item->cropDuration() + item->cropStart()).frames(m_document->fps());
             int start = item->fadeOut();
             if (start == 0) {
-                slotDeleteEffect(item, oldeffect, false);
+                slotDeleteEffect(item, -1, oldeffect, false);
             } else {
                 start = end - start;
                 QDomElement effect = oldeffect.cloneNode().toElement();
                 EffectsList::setParameter(oldeffect, "in", QString::number(start));
                 EffectsList::setParameter(oldeffect, "out", QString::number(end));
                 // kDebug()<<"EDIT FADE OUT : "<<start<<"x"<<end;
-                slotUpdateClipEffect(item, effect, oldeffect, ix2);
+                slotUpdateClipEffect(item, -1, effect, oldeffect, ix2);
                 emit clipItemSelected(item, ix2);
             }
         }
@@ -3576,9 +3679,12 @@ void CustomTrackView::doChangeClipSpeed(ItemInfo info, ItemInfo speedIndependant
     }
     info.track = m_document->tracksCount() - item->track();
     int endPos;
-    if (item->isVideoOnly()) endPos = m_document->renderer()->mltChangeClipSpeed(info, speedIndependantInfo, speed, oldspeed, strobe, baseclip->videoProducer());
-    else if (item->isAudioOnly()) endPos = m_document->renderer()->mltChangeClipSpeed(info, speedIndependantInfo, speed, oldspeed, strobe, baseclip->audioProducer(item->track()));
-    else endPos = m_document->renderer()->mltChangeClipSpeed(info, speedIndependantInfo, speed, oldspeed, strobe, baseclip->producer());
+    if (item->isVideoOnly())
+        endPos = m_document->renderer()->mltChangeClipSpeed(info, speedIndependantInfo, speed, oldspeed, strobe, baseclip->videoProducer());
+    else if (item->isAudioOnly())
+        endPos = m_document->renderer()->mltChangeClipSpeed(info, speedIndependantInfo, speed, oldspeed, strobe, baseclip->audioProducer(item->track()));
+    else
+        endPos = m_document->renderer()->mltChangeClipSpeed(info, speedIndependantInfo, speed, oldspeed, strobe, baseclip->producer());
     if (endPos >= 0) {
         item->setSpeed(speed, strobe);
         item->updateRectGeometry();
@@ -3593,6 +3699,7 @@ void CustomTrackView::doChangeClipSpeed(ItemInfo info, ItemInfo speedIndependant
 void CustomTrackView::cutSelectedClips()
 {
     QList<QGraphicsItem *> itemList = scene()->selectedItems();
+    QList<AbstractGroupItem *> groups;
     GenTime currentPos = GenTime(m_cursorPos, m_document->fps());
     for (int i = 0; i < itemList.count(); ++i) {
         if (!itemList.at(i))
@@ -3600,45 +3707,22 @@ void CustomTrackView::cutSelectedClips()
         if (itemList.at(i)->type() == AVWIDGET) {
             ClipItem *item = static_cast <ClipItem *>(itemList.at(i));
             if (item->parentItem() && item->parentItem() != m_selectionGroup) {
-                // remove all group children from itemList so we do not attempt to cut them twice
-                QList <QGraphicsItem *> children = item->parentItem()->childItems();
-                QList <int> toRemove;
-                for (int j = 0; j < children.count(); ++j) {
-                    for (int k = 0; k < itemList.count(); ++k) {
-                        if (children.at(j)->pos() == itemList.at(k)->pos()
-                            && children.at(j)->boundingRect() == itemList.at(k)->boundingRect()) {
-                            toRemove.append(k);
-                        }
-                    }
-                }
-                for (int j = 0; j < toRemove.count(); ++j)
-                    itemList.removeAt(toRemove.at(j));
-
-                razorGroup((AbstractGroupItem *)item->parentItem(), currentPos);
+                AbstractGroupItem *group = static_cast <AbstractGroupItem *>(item->parentItem());
+                if (!groups.contains(group))
+                    groups << group;
             } else if (currentPos > item->startPos() && currentPos < item->endPos()) {
                 RazorClipCommand *command = new RazorClipCommand(this, item->info(), currentPos);
                 m_commandStack->push(command);
             }
         } else if (itemList.at(i)->type() == GROUPWIDGET && itemList.at(i) != m_selectionGroup) {
-            // remove all group children from itemList so we do not attempt to cut them twice
             AbstractGroupItem *group = static_cast<AbstractGroupItem *>(itemList.at(i));
-
-            QList <QGraphicsItem *> children = itemList.at(i)->childItems();
-            QList <int> toRemove;
-            for (int j = 0; j < children.count(); ++j) {
-                for (int k = 0; k < itemList.count(); ++k) {
-                    if (children.at(j)->pos() == itemList.at(k)->pos()
-                        && children.at(j)->boundingRect() == itemList.at(k)->boundingRect()) {
-                        toRemove.append(k);
-                    }
-                }
-            }
-            for (int j = 0; j < toRemove.count(); ++j)
-                itemList.removeAt(toRemove.at(j));
-
-            razorGroup(group, currentPos);
+            if (!groups.contains(group))
+                groups << group;
         }
     }
+
+    for (int i = 0; i < groups.count(); ++i)
+        razorGroup(groups.at(i), currentPos);
 }
 
 void CustomTrackView::razorGroup(AbstractGroupItem* group, GenTime cutPos)
@@ -3842,7 +3926,7 @@ void CustomTrackView::addClip(QDomElement xml, const QString &clipId, ItemInfo i
     else prod = baseclip->producer(info.track);
     m_document->renderer()->mltInsertClip(info, xml, prod, overwrite, push);
     for (int i = 0; i < item->effectsCount(); i++) {
-        m_document->renderer()->mltAddEffect(info.track, info.startPos, item->getEffectArgs(item->effectAt(i)), false);
+        m_document->renderer()->mltAddEffect(info.track, info.startPos, getEffectArgs(item->effectAt(i)), false);
     }
     setDocumentModified();
     if (refresh) m_document->renderer()->doRefresh();
@@ -4118,6 +4202,9 @@ void CustomTrackView::moveGroup(QList <ItemInfo> startClip, QList <ItemInfo> sta
                 else
                     prod = clip->baseClip()->producer(info.track);
                 m_document->renderer()->mltInsertClip(info, clip->xml(), prod);
+                for (int i = 0; i < clip->effectsCount(); i++) {
+                    m_document->renderer()->mltAddEffect(info.track, info.startPos, getEffectArgs(clip->effectAt(i)), false);
+                }
             } else if (item->type() == TRANSITIONWIDGET) {
                 Transition *tr = static_cast <Transition*>(item);
                 int newTrack;
@@ -4131,9 +4218,15 @@ void CustomTrackView::moveGroup(QList <ItemInfo> startClip, QList <ItemInfo> sta
                 m_document->renderer()->mltAddTransition(tr->transitionTag(), newTrack, m_document->tracksCount() - info.track, info.startPos, info.endPos, tr->toXML());
             }
         }
-        if (!reverseMove)
-            rebuildGroup(m_selectionGroup);
+
         resetSelectionGroup(false);
+
+        for (int i = 0; i < children.count(); i++) {
+            if (children.at(i)->parentItem())
+                rebuildGroup((AbstractGroupItem*)children.at(i)->parentItem());
+        }
+        clearSelection();
+
         KdenliveSettings::setSnaptopoints(snap);
         m_document->renderer()->doRefresh();
     } else kDebug() << "///////// WARNING; NO GROUP TO MOVE";
@@ -4292,6 +4385,9 @@ void CustomTrackView::prepareResizeClipStart(AbstractClipItem* item, ItemInfo ol
                     new MoveTransitionCommand(this, trInfo, newTrInfo, true, command);
             }
 
+            /*
+                TODO: cleanup the effect update process
+             */
             ClipItem *clip = static_cast < ClipItem * >(item);
             updatePositionEffects(clip, oldInfo);
 
@@ -4308,7 +4404,13 @@ void CustomTrackView::prepareResizeClipStart(AbstractClipItem* item, ItemInfo ol
                 }
             }
 
-            if (clip->checkEffectsKeyframesPos(oldInfo.cropStart.frames(m_document->fps()), clip->cropStart().frames(m_document->fps()), true)) {
+            /*int panZoomPos = clip->hasEffect("affine", "pan_zoom");
+            if (panZoomPos != -1) {
+                doc.appendChild(doc.importNode(clip->effectAt(panZoomPos), true));
+                indexes.append(panZoomPos);
+            }*/
+
+            if (clip->checkEffectsKeyframesPos(oldInfo.cropStart.frames(m_document->fps()), clip->cropStart().frames(m_document->fps()), true, m_document->width(), m_document->height())) {
                 // Keyframes were modified, updateClip
                 QDomNodeList effs = doc.elementsByTagName("effect");
                 // Hack:
@@ -4425,7 +4527,7 @@ void CustomTrackView::prepareResizeClipEnd(AbstractClipItem* item, ItemInfo oldI
                 }
             }
 
-            if (clip->checkEffectsKeyframesPos((oldInfo.cropStart + oldInfo.endPos - oldInfo.startPos).frames(m_document->fps()) - 1, (clip->cropStart() + clip->cropDuration()).frames(m_document->fps()) - 1, false)) {
+            if (clip->checkEffectsKeyframesPos((oldInfo.cropStart + oldInfo.endPos - oldInfo.startPos).frames(m_document->fps()) - 1, (clip->cropStart() + clip->cropDuration()).frames(m_document->fps()) - 1, false, m_document->width(), m_document->height())) {
                 // Keyframes were modified, updateClip
                 QDomNodeList effs = doc.elementsByTagName("effect");
                 // Hack:
@@ -4490,7 +4592,7 @@ void CustomTrackView::updatePositionEffects(ClipItem * item, ItemInfo info)
             end += start;
             EffectsList::setParameter(oldeffect, "in", QString::number(start));
             EffectsList::setParameter(oldeffect, "out", QString::number(end));
-            if (!m_document->renderer()->mltEditEffect(m_document->tracksCount() - item->track(), item->startPos(), item->getEffectArgs(oldeffect)))
+            if (!m_document->renderer()->mltEditEffect(m_document->tracksCount() - item->track(), item->startPos(), getEffectArgs(oldeffect)))
                 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);
@@ -4508,7 +4610,7 @@ void CustomTrackView::updatePositionEffects(ClipItem * item, ItemInfo info)
             end += start;
             EffectsList::setParameter(oldeffect, "in", QString::number(start));
             EffectsList::setParameter(oldeffect, "out", QString::number(end));
-            if (!m_document->renderer()->mltEditEffect(m_document->tracksCount() - item->track(), item->startPos(), item->getEffectArgs(oldeffect)))
+            if (!m_document->renderer()->mltEditEffect(m_document->tracksCount() - item->track(), item->startPos(), getEffectArgs(oldeffect)))
                 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);
@@ -4530,7 +4632,7 @@ void CustomTrackView::updatePositionEffects(ClipItem * item, ItemInfo info)
             start = end - start;
             EffectsList::setParameter(oldeffect, "in", QString::number(start));
             EffectsList::setParameter(oldeffect, "out", QString::number(end));
-            if (!m_document->renderer()->mltEditEffect(m_document->tracksCount() - item->track(), item->startPos(), item->getEffectArgs(oldeffect)))
+            if (!m_document->renderer()->mltEditEffect(m_document->tracksCount() - item->track(), item->startPos(), getEffectArgs(oldeffect)))
                 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);
@@ -4548,7 +4650,7 @@ void CustomTrackView::updatePositionEffects(ClipItem * item, ItemInfo info)
             start = end - start;
             EffectsList::setParameter(oldeffect, "in", QString::number(start));
             EffectsList::setParameter(oldeffect, "out", QString::number(end));
-            if (!m_document->renderer()->mltEditEffect(m_document->tracksCount() - item->track(), item->startPos(), item->getEffectArgs(oldeffect)))
+            if (!m_document->renderer()->mltEditEffect(m_document->tracksCount() - item->track(), item->startPos(), getEffectArgs(oldeffect)))
                 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);
@@ -4580,7 +4682,8 @@ void CustomTrackView::updatePositionEffects(ClipItem * item, ItemInfo info)
         }
         oldeffect.setAttribute("in", start);
         oldeffect.setAttribute("out", max);
-        if (!m_document->renderer()->mltEditEffect(m_document->tracksCount() - item->track(), item->startPos(), item->getEffectArgs(oldeffect)))
+
+        if (!m_document->renderer()->mltEditEffect(m_document->tracksCount() - item->track(), item->startPos(), getEffectArgs(oldeffect)))
             emit displayMessage(i18n("Problem editing effect"), ErrorMessage);
         // if effect is displayed, update the effect edit widget with new clip duration
         if (item->isSelected() && effectPos == item->selectedEffectIndex()) emit clipItemSelected(item, effectPos);
@@ -5150,16 +5253,24 @@ void CustomTrackView::pasteClip()
         return;
     }
     QPoint position;
+    int track = -1;
+    GenTime pos = GenTime(-1);
     if (m_menuPosition.isNull()) {
         position = mapFromGlobal(QCursor::pos());
         if (!contentsRect().contains(position) || mapToScene(position).y() / m_tracksHeight > m_document->tracksCount()) {
-            emit displayMessage(i18n("Cannot paste selected clips"), ErrorMessage);
-            return;
+            track = m_selectedTrack;
+            pos = GenTime(m_cursorPos, m_document->fps());
+            /*emit displayMessage(i18n("Cannot paste selected clips"), ErrorMessage);
+            return;*/
         }
-    } else position = m_menuPosition;
+    } else {
+        position = m_menuPosition;
+    }
 
-    GenTime pos = GenTime((int)(mapToScene(position).x()), m_document->fps());
-    int track = (int)(mapToScene(position).y() / m_tracksHeight);
+    if (pos == GenTime(-1))
+        pos = GenTime((int)(mapToScene(position).x()), m_document->fps());
+    if (track == -1)
+        track = (int)(mapToScene(position).y() / m_tracksHeight);
 
     GenTime leftPos = m_copiedItems.at(0)->startPos();
     int lowerTrack = m_copiedItems.at(0)->track();
@@ -5408,7 +5519,7 @@ void CustomTrackView::slotUpdateAllThumbs()
                         item->slotSetEndThumb(pix);
                     }
                 }
-               item->refreshClip(false);
+                item->refreshClip(false);
             }
         }
     }
@@ -6256,3 +6367,78 @@ bool CustomTrackView::hasAudio(int track) const
     }
     return false;
 }
+
+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();
+}
+
+
+EffectsParameterList CustomTrackView::getEffectArgs(const QDomElement effect)
+{
+    EffectsParameterList parameters;
+    parameters.addParam("tag", effect.attribute("tag"));
+    if (effect.hasAttribute("region")) parameters.addParam("region", effect.attribute("region"));
+    parameters.addParam("kdenlive_ix", effect.attribute("kdenlive_ix"));
+    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"));
+
+    QDomNodeList params = effect.elementsByTagName("parameter");
+    for (int i = 0; i < params.count(); i++) {
+        QDomElement e = params.item(i).toElement();
+        //kDebug() << "/ / / /SENDING EFFECT PARAM: " << e.attribute("type") << ", NAME_ " << e.attribute("tag");
+        if (e.attribute("type") == "simplekeyframe") {
+
+            QStringList values = e.attribute("keyframes").split(";", QString::SkipEmptyParts);
+            double factor = e.attribute("factor", "1").toDouble();
+            for (int j = 0; j < values.count(); j++) {
+                QString pos = values.at(j).section(":", 0, 0);
+                double val = values.at(j).section(":", 1, 1).toDouble() / factor;
+                values[j] = pos + "=" + QString::number(val);
+            }
+            // kDebug() << "/ / / /SENDING KEYFR:" << values;
+            parameters.addParam(e.attribute("name"), values.join(";"));
+            /*parameters.addParam(e.attribute("name"), e.attribute("keyframes").replace(":", "="));
+            parameters.addParam("max", e.attribute("max"));
+            parameters.addParam("min", e.attribute("min"));
+            parameters.addParam("factor", e.attribute("factor", "1"));*/
+        } else if (e.attribute("type") == "keyframe") {
+            kDebug() << "/ / / /SENDING KEYFR EFFECT TYPE";
+            parameters.addParam("keyframes", e.attribute("keyframes"));
+            parameters.addParam("max", e.attribute("max"));
+            parameters.addParam("min", e.attribute("min"));
+            parameters.addParam("factor", e.attribute("factor", "1"));
+            parameters.addParam("starttag", e.attribute("starttag", "start"));
+            parameters.addParam("endtag", e.attribute("endtag", "end"));
+        } else if (e.attribute("namedesc").contains(';')) {
+            QString format = e.attribute("format");
+            QStringList separators = format.split("%d", QString::SkipEmptyParts);
+            QStringList values = e.attribute("value").split(QRegExp("[,:;x]"));
+            QString neu;
+            QTextStream txtNeu(&neu);
+            if (values.size() > 0)
+                txtNeu << (int)values[0].toDouble();
+            for (int i = 0; i < separators.size() && i + 1 < values.size(); i++) {
+                txtNeu << separators[i];
+                txtNeu << (int)(values[i+1].toDouble());
+            }
+            parameters.addParam("start", neu);
+        } else {
+            if (e.attribute("factor", "1") != "1") {
+                double fact;
+                if (e.attribute("factor").startsWith('%')) {
+                    fact = ProfilesDialog::getStringEval(m_document->mltProfile(), e.attribute("factor"));
+                } else fact = e.attribute("factor", "1").toDouble();
+                parameters.addParam(e.attribute("name"), QString::number(e.attribute("value").toDouble() / fact));
+            } else {
+                parameters.addParam(e.attribute("name"), e.attribute("value"));
+            }
+        }
+    }
+    return parameters;
+}
\ No newline at end of file