]> git.sesse.net Git - kdenlive/blobdiff - src/customtrackview.cpp
Prepare checking of removed / deleted files in a project:
[kdenlive] / src / customtrackview.cpp
index 607f1a75e87343c111443ffcd3268a609d4b77b6..5481cd81e1d399690eeea9f210bb85ff2d390647 100644 (file)
@@ -194,11 +194,16 @@ void CustomTrackView::setDocumentModified()
     m_document->setModified(true);
 }
 
-void CustomTrackView::setContextMenu(QMenu *timeline, QMenu *clip, QMenu *transition, QActionGroup *clipTypeGroup)
+void CustomTrackView::setContextMenu(QMenu *timeline, QMenu *clip, QMenu *transition, QActionGroup *clipTypeGroup, QMenu *markermenu)
 {
     m_timelineContextMenu = timeline;
     m_timelineContextClipMenu = clip;
     m_clipTypeGroup = clipTypeGroup;
+
+    m_markerMenu = new QMenu(i18n("Go to marker..."), this);
+    m_markerMenu->setEnabled(false);
+    markermenu->addMenu(m_markerMenu);
+    connect(m_markerMenu, SIGNAL(triggered(QAction *)), this, SLOT(slotGoToMarker(QAction *)));
     QList <QAction *> list = m_timelineContextClipMenu->actions();
     for (int i = 0; i < list.count(); i++) {
         if (list.at(i)->data().toString() == "paste_effects") m_pasteEffectsAction = list.at(i);
@@ -410,15 +415,49 @@ void CustomTrackView::mouseMoveEvent(QMouseEvent * event)
             // spacer tool
             snappedPos = getSnapPointForPos(mappedXPos + m_spacerOffset);
             if (snappedPos < 0) snappedPos = 0;
+
             // Make sure there is no collision
             QList<QGraphicsItem *> children = m_selectionGroup->childItems();
             QPainterPath shape = m_selectionGroup->clipGroupShape(QPointF(snappedPos - m_selectionGroup->sceneBoundingRect().left(), 0));
             QList<QGraphicsItem*> collidingItems = scene()->items(shape, Qt::IntersectsItemShape);
             collidingItems.removeAll(m_selectionGroup);
             for (int i = 0; i < children.count(); i++) {
+                if (children.at(i)->type() == GROUPWIDGET) {
+                    QList<QGraphicsItem *> subchildren = children.at(i)->childItems();
+                    for (int j = 0; j < subchildren.count(); j++) {
+                        collidingItems.removeAll(subchildren.at(j));
+                    }
+                }
                 collidingItems.removeAll(children.at(i));
             }
             bool collision = false;
+            int offset = 0;
+            for (int i = 0; i < collidingItems.count(); i++) {
+                if (!collidingItems.at(i)->isEnabled()) continue;
+                if (collidingItems.at(i)->type() == AVWIDGET && snappedPos < m_selectionGroup->sceneBoundingRect().left()) {
+                    AbstractClipItem *item = static_cast <AbstractClipItem *>(collidingItems.at(i));
+                    // Moving backward, determine best pos
+                    QPainterPath clipPath;
+                    clipPath.addRect(item->sceneBoundingRect());
+                    QPainterPath res = shape.intersected(clipPath);
+                    offset = qMax(offset, (int)(res.boundingRect().width() + 0.5));
+                }
+            }
+            snappedPos += offset;
+            // make sure we have no collision
+            shape = m_selectionGroup->clipGroupShape(QPointF(snappedPos - m_selectionGroup->sceneBoundingRect().left(), 0));
+            collidingItems = scene()->items(shape, Qt::IntersectsItemShape);
+            collidingItems.removeAll(m_selectionGroup);
+            for (int i = 0; i < children.count(); i++) {
+                if (children.at(i)->type() == GROUPWIDGET) {
+                    QList<QGraphicsItem *> subchildren = children.at(i)->childItems();
+                    for (int j = 0; j < subchildren.count(); j++) {
+                        collidingItems.removeAll(subchildren.at(j));
+                    }
+                }
+                collidingItems.removeAll(children.at(i));
+            }
+
             for (int i = 0; i < collidingItems.count(); i++) {
                 if (!collidingItems.at(i)->isEnabled()) continue;
                 if (collidingItems.at(i)->type() == AVWIDGET) {
@@ -426,12 +465,47 @@ void CustomTrackView::mouseMoveEvent(QMouseEvent * event)
                     break;
                 }
             }
+
+
             if (!collision) {
                 // Check transitions
                 shape = m_selectionGroup->transitionGroupShape(QPointF(snappedPos - m_selectionGroup->sceneBoundingRect().left(), 0));
                 collidingItems = scene()->items(shape, Qt::IntersectsItemShape);
                 collidingItems.removeAll(m_selectionGroup);
                 for (int i = 0; i < children.count(); i++) {
+                    if (children.at(i)->type() == GROUPWIDGET) {
+                        QList<QGraphicsItem *> subchildren = children.at(i)->childItems();
+                        for (int j = 0; j < subchildren.count(); j++) {
+                            collidingItems.removeAll(subchildren.at(j));
+                        }
+                    }
+                    collidingItems.removeAll(children.at(i));
+                }
+                offset = 0;
+
+                for (int i = 0; i < collidingItems.count(); i++) {
+                    if (collidingItems.at(i)->type() == TRANSITIONWIDGET && snappedPos < m_selectionGroup->sceneBoundingRect().left()) {
+                        AbstractClipItem *item = static_cast <AbstractClipItem *>(collidingItems.at(i));
+                        // Moving backward, determine best pos
+                        QPainterPath clipPath;
+                        clipPath.addRect(item->sceneBoundingRect());
+                        QPainterPath res = shape.intersected(clipPath);
+                        offset = qMax(offset, (int)(res.boundingRect().width() + 0.5));
+                    }
+                }
+
+                snappedPos += offset;
+                // make sure we have no collision
+                shape = m_selectionGroup->transitionGroupShape(QPointF(snappedPos - m_selectionGroup->sceneBoundingRect().left(), 0));
+                collidingItems = scene()->items(shape, Qt::IntersectsItemShape);
+                collidingItems.removeAll(m_selectionGroup);
+                for (int i = 0; i < children.count(); i++) {
+                    if (children.at(i)->type() == GROUPWIDGET) {
+                        QList<QGraphicsItem *> subchildren = children.at(i)->childItems();
+                        for (int j = 0; j < subchildren.count(); j++) {
+                            collidingItems.removeAll(subchildren.at(j));
+                        }
+                    }
                     collidingItems.removeAll(children.at(i));
                 }
                 for (int i = 0; i < collidingItems.count(); i++) {
@@ -844,10 +918,11 @@ void CustomTrackView::mousePressEvent(QMouseEvent * event)
                 kDebug() << "SELELCTING ELEMENTS WITHIN =" << event->pos().x() << "/" <<  1 << ", " << mapFromScene(sceneRect().width(), 0).x() - event->pos().x() << "/" << sceneRect().height();
             }
 
+            QList <GenTime> offsetList;
             // create group to hold selected items
             m_selectionGroup = new AbstractGroupItem(m_document->fps());
             scene()->addItem(m_selectionGroup);
-            QList <GenTime> offsetList;
+
             for (int i = 0; i < selection.count(); i++) {
                 if (selection.at(i)->parentItem() == 0 && (selection.at(i)->type() == AVWIDGET || selection.at(i)->type() == TRANSITIONWIDGET)) {
                     AbstractClipItem *item = static_cast<AbstractClipItem *>(selection.at(i));
@@ -856,7 +931,7 @@ void CustomTrackView::mousePressEvent(QMouseEvent * event)
                     offsetList.append(item->endPos());
                     m_selectionGroup->addToGroup(selection.at(i));
                     selection.at(i)->setFlag(QGraphicsItem::ItemIsMovable, false);
-                } else if (selection.at(i)->parentItem() == 0 && selection.at(i)->type() == GROUPWIDGET) {
+                } else if (/*selection.at(i)->parentItem() == 0 && */selection.at(i)->type() == GROUPWIDGET) {
                     if (static_cast<AbstractGroupItem *>(selection.at(i))->isItemLocked()) continue;
                     QList<QGraphicsItem *> children = selection.at(i)->childItems();
                     for (int j = 0; j < children.count(); j++) {
@@ -866,8 +941,9 @@ void CustomTrackView::mousePressEvent(QMouseEvent * event)
                     }
                     m_selectionGroup->addToGroup(selection.at(i));
                     selection.at(i)->setFlag(QGraphicsItem::ItemIsMovable, false);
-                } else if (selection.at(i)->parentItem()) {
+                } else if (selection.at(i)->parentItem() && !selection.contains(selection.at(i)->parentItem())) {
                     if (static_cast<AbstractGroupItem *>(selection.at(i)->parentItem())->isItemLocked()) continue;
+                    //AbstractGroupItem *grp = static_cast<AbstractGroupItem *>(selection.at(i)->parentItem());
                     m_selectionGroup->addToGroup(selection.at(i)->parentItem());
                     selection.at(i)->parentItem()->setFlag(QGraphicsItem::ItemIsMovable, false);
                 }
@@ -1169,8 +1245,9 @@ void CustomTrackView::groupSelectedItems(bool force, bool createNewGroup)
 void CustomTrackView::mouseDoubleClickEvent(QMouseEvent *event)
 {
     if (m_dragItem && m_dragItem->hasKeyFrames()) {
-        if (m_moveOpMode == KEYFRAME) {
+        /*if (m_moveOpMode == KEYFRAME) {
             // user double clicked on a keyframe, open edit dialog
+            //TODO: update for effects with several values per keyframe
             QDialog d(parentWidget());
             Ui::KeyFrameDialog_UI view;
             view.setupUi(&d);
@@ -1190,49 +1267,75 @@ void CustomTrackView::mouseDoubleClickEvent(QMouseEvent *event)
                 emit clipItemSelected(item, item->selectedEffectIndex());
             }
 
-        } else  {
+        } else*/  {
             // add keyframe
             GenTime keyFramePos = GenTime((int)(mapToScene(event->pos()).x()), m_document->fps()) - m_dragItem->startPos() + m_dragItem->cropStart();
-            m_dragItem->addKeyFrame(keyFramePos, mapToScene(event->pos()).toPoint().y());
+            int val = m_dragItem->addKeyFrame(keyFramePos, mapToScene(event->pos()).toPoint().y());
             ClipItem * item = static_cast <ClipItem *>(m_dragItem);
-            QString previous = item->keyframes(item->selectedEffectIndex());
-            item->updateKeyframeEffect();
-            QString next = item->keyframes(item->selectedEffectIndex());
-            EditKeyFrameCommand *command = new EditKeyFrameCommand(this, m_dragItem->track(), m_dragItem->startPos(), item->selectedEffectIndex(), previous, next, false);
+            //QString previous = item->keyframes(item->selectedEffectIndex());
+            QDomElement oldEffect = item->selectedEffect().cloneNode().toElement();
+            item->insertKeyframe(item->getEffectAt(item->selectedEffectIndex()), keyFramePos.frames(m_document->fps()), val);
+            //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);
+            //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());
             emit clipItemSelected(item, item->selectedEffectIndex());
         }
     } else if (m_dragItem && !m_dragItem->isItemLocked()) {
-        ClipDurationDialog d(m_dragItem, m_document->timecode(), this);
+        editClipDuration();
+    } else {
+        QList<QGraphicsItem *> collisionList = items(event->pos());
+        if (collisionList.count() == 1 && collisionList.at(0)->type() == GUIDEITEM) {
+            Guide *editGuide = (Guide *) collisionList.at(0);
+            if (editGuide) slotEditGuide(editGuide->info());
+        }
+    }
+}
+
+void CustomTrackView::editClipDuration()
+{
+    AbstractClipItem *item;
+    if (m_dragItem) {
+       item = m_dragItem;
+    }
+    else {
+        GenTime pos = GenTime((int)(mapToScene(m_menuPosition).x()), m_document->fps());
+        int track = (int)(mapToScene(m_menuPosition).y() / m_tracksHeight);
+        item = getClipItemAt(pos, track);
+    }
+
+    if (item && !item->isItemLocked()) {
         GenTime minimum;
         GenTime maximum;
-        if (m_dragItem->type() == TRANSITIONWIDGET) {
-            getTransitionAvailableSpace(m_dragItem, minimum, maximum);
+        if (item->type() == TRANSITIONWIDGET) {
+            getTransitionAvailableSpace(item, minimum, maximum);
         } else {
-            getClipAvailableSpace(m_dragItem, minimum, maximum);
+            getClipAvailableSpace(item, minimum, maximum);
         }
         //kDebug()<<"// GOT MOVE POS: "<<minimum.frames(25)<<" - "<<maximum.frames(25);
-        d.setMargins(minimum, maximum);
+        ClipDurationDialog d(item, m_document->timecode(), minimum, maximum, this);
         if (d.exec() == QDialog::Accepted) {
-            if (m_dragItem->type() == TRANSITIONWIDGET) {
+            if (item->type() == TRANSITIONWIDGET) {
                 // move & resize transition
                 ItemInfo startInfo;
-                startInfo.startPos = m_dragItem->startPos();
-                startInfo.endPos = m_dragItem->endPos();
-                startInfo.track = m_dragItem->track();
+                startInfo.startPos = item->startPos();
+                startInfo.endPos = item->endPos();
+                startInfo.track = item->track();
                 ItemInfo endInfo;
                 endInfo.startPos = d.startPos();
                 endInfo.endPos = endInfo.startPos + d.duration();
-                endInfo.track = m_dragItem->track();
+                endInfo.track = item->track();
                 MoveTransitionCommand *command = new MoveTransitionCommand(this, startInfo, endInfo, true);
                 m_commandStack->push(command);
             } else {
                 // move and resize clip
                 QUndoCommand *moveCommand = new QUndoCommand();
                 moveCommand->setText(i18n("Edit clip"));
-                ItemInfo clipInfo = m_dragItem->info();
-                if (d.duration() < m_dragItem->cropDuration() || d.cropStart() != clipInfo.cropStart) {
+                ItemInfo clipInfo = item->info();
+                if (d.duration() < item->cropDuration() || d.cropStart() != clipInfo.cropStart) {
                     // duration was reduced, so process it first
                     ItemInfo startInfo = clipInfo;
                     clipInfo.endPos = clipInfo.startPos + d.duration();
@@ -1242,10 +1345,10 @@ void CustomTrackView::mouseDoubleClickEvent(QMouseEvent *event)
                 if (d.startPos() != clipInfo.startPos) {
                     ItemInfo startInfo = clipInfo;
                     clipInfo.startPos = d.startPos();
-                    clipInfo.endPos = m_dragItem->endPos() + (clipInfo.startPos - startInfo.startPos);
+                    clipInfo.endPos = item->endPos() + (clipInfo.startPos - startInfo.startPos);
                     new MoveClipCommand(this, startInfo, clipInfo, true, moveCommand);
                 }
-                if (d.duration() > m_dragItem->cropDuration()) {
+                if (d.duration() > item->cropDuration()) {
                     // duration was increased, so process it after move
                     ItemInfo startInfo = clipInfo;
                     clipInfo.endPos = clipInfo.startPos + d.duration();
@@ -1255,16 +1358,9 @@ void CustomTrackView::mouseDoubleClickEvent(QMouseEvent *event)
                 m_commandStack->push(moveCommand);
             }
         }
-    } else {
-        QList<QGraphicsItem *> collisionList = items(event->pos());
-        if (collisionList.count() == 1 && collisionList.at(0)->type() == GUIDEITEM) {
-            Guide *editGuide = (Guide *) collisionList.at(0);
-            if (editGuide) slotEditGuide(editGuide->info());
-        }
     }
 }
 
-
 void CustomTrackView::editKeyFrame(const GenTime pos, const int track, const int index, const QString keyframes)
 {
     ClipItem *clip = getClipItemAt((int)pos.frames(m_document->fps()), track);
@@ -1279,8 +1375,11 @@ void CustomTrackView::displayContextMenu(QPoint pos, AbstractClipItem *clip, Abs
 {
     m_deleteGuide->setEnabled(m_dragGuide != NULL);
     m_editGuide->setEnabled(m_dragGuide != NULL);
-    if (clip == NULL) m_timelineContextMenu->popup(pos);
-    else if (group != NULL) {
+    m_markerMenu->clear();
+    m_markerMenu->setEnabled(false);
+    if (clip == NULL) {
+        m_timelineContextMenu->popup(pos);
+    } else if (group != NULL) {
         m_pasteEffectsAction->setEnabled(m_copiedItems.count() == 1);
         m_ungroupAction->setEnabled(true);
         updateClipTypeActions(NULL);
@@ -1289,10 +1388,26 @@ void CustomTrackView::displayContextMenu(QPoint pos, AbstractClipItem *clip, Abs
         m_ungroupAction->setEnabled(false);
         if (clip->type() == AVWIDGET) {
             ClipItem *item = static_cast <ClipItem*>(clip);
+            //build go to marker menu
+            if (item->baseClip()) {
+                QList <CommentedTime> markers = item->baseClip()->commentedSnapMarkers();
+                int offset = item->startPos().frames(m_document->fps());
+                if (!markers.isEmpty()) {
+                    for (int i = 0; i < markers.count(); i++) {
+                        int pos = (int) markers.at(i).time().frames(m_document->timecode().fps());
+                        QString position = m_document->timecode().getTimecode(markers.at(i).time()) + ' ' + markers.at(i).comment();
+                        QAction *go = m_markerMenu->addAction(position);
+                        go->setData(pos + offset);
+                    }
+                }
+                m_markerMenu->setEnabled(!m_markerMenu->isEmpty());
+            }
             updateClipTypeActions(item);
             m_pasteEffectsAction->setEnabled(m_copiedItems.count() == 1);
             m_timelineContextClipMenu->popup(pos);
-        } else if (clip->type() == TRANSITIONWIDGET) m_timelineContextTransitionMenu->popup(pos);
+        } else if (clip->type() == TRANSITIONWIDGET) {
+            m_timelineContextTransitionMenu->popup(pos);
+        }
     }
 }
 
@@ -1329,7 +1444,8 @@ bool CustomTrackView::insertDropClips(const QMimeData *data, const QPoint pos)
 {
     if (data->hasFormat("kdenlive/clip")) {
         m_clipDrag = true;
-        resetSelectionGroup();
+        m_scene->clearSelection();
+        resetSelectionGroup(false);
         QStringList list = QString(data->data("kdenlive/clip")).split(';');
         DocClipBase *clip = m_document->getBaseClip(list.at(0));
         if (clip == NULL) {
@@ -1364,7 +1480,7 @@ bool CustomTrackView::insertDropClips(const QMimeData *data, const QPoint pos)
         updateSnapPoints(NULL, offsetList);
         m_selectionGroup->setPos(framePos);
         scene()->addItem(m_selectionGroup);
-        //m_selectionGroup->setZValue(10);
+        m_selectionGroup->setSelected(true);
         return true;
     } else if (data->hasFormat("kdenlive/producerslist")) {
         m_clipDrag = true;
@@ -1410,7 +1526,6 @@ bool CustomTrackView::insertDropClips(const QMimeData *data, const QPoint pos)
             start += info.cropDuration;
             offsetList.append(start);
             ClipItem *item = new ClipItem(clip, info, m_document->fps(), 1.0, 1, false);
-            //item->setZValue(10);
             item->setFlag(QGraphicsItem::ItemIsMovable, false);
             m_selectionGroup->addToGroup(item);
             if (!clip->isPlaceHolder()) m_waitingThumbs.append(item);
@@ -1494,11 +1609,6 @@ void CustomTrackView::addEffect(int track, GenTime pos, QDomElement effect)
             return;
         }
         EffectsParameterList params = clip->addEffect(effect);
-        if (effect.attribute("disabled") == "1") {
-            // Effect is disabled, don't add it to MLT playlist
-            if (clip->isSelected()) emit clipItemSelected(clip);
-            return;
-        }
         if (!m_document->renderer()->mltAddEffect(track, pos, params))
             emit displayMessage(i18n("Problem adding effect to clip"), ErrorMessage);
         if (clip->isSelected()) emit clipItemSelected(clip);
@@ -1519,8 +1629,8 @@ void CustomTrackView::deleteEffect(int track, GenTime pos, QDomElement effect)
             return;
         }
     }
-    if (!m_document->renderer()->mltRemoveEffect(track, pos, index, true) && effect.attribute("disabled") != "1") {
-        kDebug() << "// ERROR REMOV EFFECT: " << index << ", DISABLE: " << effect.attribute("disabled");
+    if (!m_document->renderer()->mltRemoveEffect(track, pos, index, true)) {
+        kDebug() << "// ERROR REMOV EFFECT: " << index << ", DISABLE: " << effect.attribute("disable");
         emit displayMessage(i18n("Problem deleting effect"), ErrorMessage);
         return;
     }
@@ -1584,14 +1694,24 @@ void CustomTrackView::slotAddEffect(QDomElement effect, GenTime pos, int track)
     if (!namenode.isNull()) effectName = i18n(namenode.toElement().text().toUtf8().data());
     else effectName = i18n("effect");
     effectCommand->setText(i18n("Add %1", effectName));
-    int count = 0;
+
     if (track == -1) itemList = scene()->selectedItems();
     if (itemList.isEmpty()) {
         ClipItem *clip = getClipItemAt((int) pos.frames(m_document->fps()), track);
         if (clip) itemList.append(clip);
         else emit displayMessage(i18n("Select a clip if you want to apply an effect"), ErrorMessage);
     }
-    kDebug() << "// REQUESTING EFFECT ON CLIP: " << pos.frames(25) << ", TRK: " << track << "SELECTED ITEMS: " << itemList.count();
+
+    //expand groups
+    for (int i = 0; i < itemList.count(); i++) {
+        if (itemList.at(i)->type() == GROUPWIDGET) {
+            QList<QGraphicsItem *> subitems = itemList.at(i)->childItems();
+            for (int j = 0; j < subitems.count(); j++) {
+                if (!itemList.contains(subitems.at(j))) itemList.append(subitems.at(j));
+            }
+        }
+    }
+
     for (int i = 0; i < itemList.count(); i++) {
         if (itemList.at(i)->type() == AVWIDGET) {
             ClipItem *item = static_cast <ClipItem *>(itemList.at(i));
@@ -1624,17 +1744,50 @@ void CustomTrackView::slotAddEffect(QDomElement effect, GenTime pos, int track)
                 effect.setAttribute("src", ladpsaFile);
             }
             new AddEffectCommand(this, m_document->tracksCount() - item->track(), item->startPos(), effect, true, effectCommand);
-            count++;
         }
     }
-    if (count > 0) {
+    if (effectCommand->childCount() > 0) {
         m_commandStack->push(effectCommand);
         setDocumentModified();
     } else delete effectCommand;
 }
 
-void CustomTrackView::slotDeleteEffect(ClipItem *clip, QDomElement effect)
+void CustomTrackView::slotDeleteEffect(ClipItem *clip, QDomElement effect, bool affectGroup)
 {
+    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();
+        QUndoCommand *delCommand = new QUndoCommand();
+        QString effectName;
+        QDomNode namenode = effect.elementsByTagName("name").item(0);
+        if (!namenode.isNull()) effectName = i18n(namenode.toElement().text().toUtf8().data());
+        else effectName = i18n("effect");
+        delCommand->setText(i18n("Delete %1", effectName));
+
+        //expand groups
+        for (int i = 0; i < items.count(); i++) {
+            if (items.at(i)->type() == GROUPWIDGET) {
+                QList<QGraphicsItem *> subitems = items.at(i)->childItems();
+                for (int j = 0; j < subitems.count(); j++) {
+                    if (!items.contains(subitems.at(j))) items.append(subitems.at(j));
+                }
+            }
+        }
+
+        for (int i = 0; i < items.count(); i++) {
+            if (items.at(i)->type() == AVWIDGET) {
+                ClipItem *item = static_cast <ClipItem *>(items.at(i));
+                int ix = item->hasEffect(effect.attribute("tag"), effect.attribute("id"));
+                if (ix != -1) {
+                    QDomElement eff = item->effectAt(ix);
+                    new AddEffectCommand(this, m_document->tracksCount() - item->track(), item->startPos(), eff, false, delCommand);
+                }
+            }
+        }
+        if (delCommand->childCount() > 0) m_commandStack->push(delCommand);
+        else delete delCommand;
+        return;
+    }
     AddEffectCommand *command = new AddEffectCommand(this, m_document->tracksCount() - clip->track(), clip->startPos(), effect, false);
     m_commandStack->push(command);
     setDocumentModified();
@@ -1651,7 +1804,7 @@ void CustomTrackView::updateEffect(int track, GenTime pos, QDomElement insertedE
     if (clip) {
         // Special case: speed effect
         if (effect.attribute("id") == "speed") {
-            if (effect.attribute("disabled") == "1") doChangeClipSpeed(clip->info(), clip->speedIndependantInfo(), 1.0, clip->speed(), 1, clip->baseClip()->getId());
+            if (effect.attribute("disable") == "1") doChangeClipSpeed(clip->info(), clip->speedIndependantInfo(), 1.0, clip->speed(), 1, clip->baseClip()->getId());
             else {
                 double speed = EffectsList::parameter(effect, "speed").toDouble() / 100.0;
                 int strobe = EffectsList::parameter(effect, "strobe").toInt();
@@ -1676,11 +1829,7 @@ void CustomTrackView::updateEffect(int track, GenTime pos, QDomElement insertedE
             clip->initEffect(effect);
             effectParams = clip->getEffectArgs(effect);
         }
-        if (effectParams.paramValue("disabled") == "1") {
-            if (m_document->renderer()->mltRemoveEffect(track, pos, effectParams.paramValue("kdenlive_ix"), false)) {
-                kDebug() << "//////  DISABLING EFFECT: " << ix << ", CURRENTLA: " << clip->selectedEffectIndex();
-            } else emit displayMessage(i18n("Problem deleting effect"), ErrorMessage);
-        } else if (!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);
@@ -1727,7 +1876,7 @@ void CustomTrackView::slotChangeEffectState(ClipItem *clip, int effectPos, bool
     QDomElement effect = clip->effectAt(effectPos);
     QDomElement oldEffect = effect.cloneNode().toElement();
 
-    effect.setAttribute("disabled", (int) disable);
+    effect.setAttribute("disable", (int) disable);
     EditEffectCommand *command = new EditEffectCommand(this, m_document->tracksCount() - clip->track(), clip->startPos(), oldEffect, effect, effectPos, true);
     m_commandStack->push(command);
     setDocumentModified();;
@@ -2194,7 +2343,9 @@ void CustomTrackView::adjustTimelineClips(EDITMODE mode, ClipItem *item, ItemInf
                         dupInfo.cropStart += diff;
                         dupInfo.cropDuration = clipInfo.endPos - info.startPos;
                         new RazorClipCommand(this, clipInfo, info.startPos, false, command);
-                        ClipItem *dup = cutClip(clipInfo, info.startPos, true, false);
+                        // Commented out; variable dup unused. --granjow
+                        //ClipItem *dup = cutClip(clipInfo, info.startPos, true, false);
+                        cutClip(clipInfo, info.startPos, true, false);
                     }
                 }
                 // TODO: add insertspacecommand
@@ -3280,7 +3431,7 @@ void CustomTrackView::mouseReleaseEvent(QMouseEvent * event)
             int start = item->cropStart().frames(m_document->fps());
             int end = item->fadeIn();
             if (end == 0) {
-                slotDeleteEffect(item, oldeffect);
+                slotDeleteEffect(item, oldeffect, false);
             } else {
                 end += start;
                 QDomElement effect = oldeffect.cloneNode().toElement();
@@ -3303,7 +3454,7 @@ void CustomTrackView::mouseReleaseEvent(QMouseEvent * event)
             int start = item->cropStart().frames(m_document->fps());
             int end = item->fadeIn();
             if (end == 0) {
-                slotDeleteEffect(item, oldeffect);
+                slotDeleteEffect(item, oldeffect, false);
             } else {
                 end += start;
                 QDomElement effect = oldeffect.cloneNode().toElement();
@@ -3323,7 +3474,7 @@ 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);
+                slotDeleteEffect(item, oldeffect, false);
             } else {
                 start = end - start;
                 QDomElement effect = oldeffect.cloneNode().toElement();
@@ -3348,7 +3499,7 @@ 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);
+                slotDeleteEffect(item, oldeffect, false);
             } else {
                 start = end - start;
                 QDomElement effect = oldeffect.cloneNode().toElement();
@@ -3362,10 +3513,26 @@ void CustomTrackView::mouseReleaseEvent(QMouseEvent * event)
     } else if (m_operationMode == KEYFRAME) {
         // update the MLT effect
         ClipItem * item = static_cast <ClipItem *>(m_dragItem);
-        QString previous = item->keyframes(item->selectedEffectIndex());
-        item->updateKeyframeEffect();
-        QString next = item->keyframes(item->selectedEffectIndex());
-        EditKeyFrameCommand *command = new EditKeyFrameCommand(this, item->track(), item->startPos(), item->selectedEffectIndex(), previous, next, false);
+        QDomElement oldEffect = item->selectedEffect().cloneNode().toElement();
+
+        // check if we want to remove keyframe
+        double val = mapToScene(event->pos()).toPoint().y();
+        QRectF br = item->sceneBoundingRect();
+        double maxh = 100.0 / br.height();
+        val = (br.bottom() - val) * maxh;
+        int start = item->cropStart().frames(m_document->fps());
+        int end = (item->cropStart() + item->cropDuration()).frames(m_document->fps()) - 1;
+        if ((val < -50 || val > 150) && item->editedKeyFramePos() != start && item->editedKeyFramePos() != end) {
+            //delete keyframe
+            kDebug() << "// DELETE KFR: " << item->editedKeyFramePos();
+            item->movedKeyframe(item->getEffectAt(item->selectedEffectIndex()), item->selectedKeyFramePos(), -1, 0);
+        } else item->movedKeyframe(item->getEffectAt(item->selectedEffectIndex()), item->selectedKeyFramePos(), item->editedKeyFramePos(), item->editedKeyFrameValue());
+        QDomElement newEffect = item->selectedEffect().cloneNode().toElement();
+        //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);
+
         m_commandStack->push(command);
         updateEffect(m_document->tracksCount() - item->track(), item->startPos(), item->selectedEffect(), item->selectedEffectIndex());
         emit clipItemSelected(item, item->selectedEffectIndex());
@@ -3988,7 +4155,7 @@ void CustomTrackView::moveTransition(const ItemInfo start, const ItemInfo end, b
     //item->moveTransition(GenTime((int) (endPos.x() - startPos.x()), m_document->fps()));
     KdenliveSettings::setSnaptopoints(snap);
     item->updateTransitionEndTrack(getPreviousVideoTrack(end.track));
-    m_document->renderer()->mltMoveTransition(item->transitionTag(), m_document->tracksCount() - start.track, m_document->tracksCount() - end.track, item->transitionEndTrack(), start.startPos, start.endPos, end.startPos, end.endPos);
+    m_document->renderer()->mltMoveTransition(item->transitionTag(), m_document->tracksCount() - start.track, m_document->tracksCount() - item->track(), item->transitionEndTrack(), start.startPos, start.endPos, item->startPos(), item->endPos());
     if (m_dragItem && m_dragItem == item) {
         QPoint p;
         ClipItem *transitionClip = getClipItemAt(item->startPos(), item->track());
@@ -4746,6 +4913,20 @@ void CustomTrackView::pasteClipEffects()
     paste->setText("Paste effects");
 
     QList<QGraphicsItem *> clips = scene()->selectedItems();
+
+    // expand groups
+    for (int i = 0; i < clips.count(); ++i) {
+        if (clips.at(i)->type() == GROUPWIDGET) {
+            QList<QGraphicsItem *> children = clips.at(i)->childItems();
+            for (int j = 0; j < children.count(); j++) {
+                if (children.at(j)->type() == AVWIDGET && !clips.contains(children.at(j))) {
+                    clips.append(children.at(j));
+                }
+            }
+        }
+    }
+
+
     for (int i = 0; i < clips.count(); ++i) {
         if (clips.at(i)->type() == AVWIDGET) {
             ClipItem *item = static_cast < ClipItem *>(clips.at(i));
@@ -4758,12 +4939,15 @@ void CustomTrackView::pasteClipEffects()
             }
         }
     }
-    m_commandStack->push(paste);
+    if (paste->childCount() > 0) m_commandStack->push(paste);
+    else delete paste;
 
-    // adjust effects (fades, ...)
+    //adjust effects (fades, ...)
     for (int i = 0; i < clips.count(); ++i) {
-        ClipItem *item = static_cast < ClipItem *>(clips.at(i));
-        updatePositionEffects(item, item->info());
+        if (clips.at(i)->type() == AVWIDGET) {
+            ClipItem *item = static_cast < ClipItem *>(clips.at(i));
+            updatePositionEffects(item, item->info());
+        }
     }
 }
 
@@ -5056,8 +5240,9 @@ void CustomTrackView::slotChangeTrack(int ix)
     d.track_nb->setValue(ix);
     d.slotUpdateName(ix);
     d.setWindowTitle(i18n("Change Track Type"));
-
-    if (m_document->trackInfoAt(m_document->tracksCount() - ix - 1).type == VIDEOTRACK)
+    
+    TrackInfo oldInfo = m_document->trackInfoAt(m_document->tracksCount() - ix - 1);
+    if (oldInfo.type == VIDEOTRACK)
         d.video_track->setChecked(true);
     else
         d.audio_track->setChecked(true);
@@ -5066,6 +5251,7 @@ void CustomTrackView::slotChangeTrack(int ix)
         TrackInfo info;
         info.isLocked = false;
         info.isMute = false;
+        info.trackName = oldInfo.trackName;
         ix = d.track_nb->value();
 
         if (d.video_track->isChecked()) {
@@ -5446,6 +5632,12 @@ void CustomTrackView::updateClipTypeActions(ClipItem *clip)
     }
 }
 
+void CustomTrackView::slotGoToMarker(QAction *action)
+{
+    int pos = action->data().toInt();
+    setCursorPos(pos, true);
+}
+
 void CustomTrackView::reloadTransitionLumas()
 {
     QString lumaNames;
@@ -5669,3 +5861,12 @@ void CustomTrackView::insertZoneOverwrite(QStringList data, int in)
     new AddTimelineClipCommand(this, clip->toXML(), clip->getId(), info, EffectsList(), true, false, true, false, addCommand);
     m_commandStack->push(addCommand);
 }
+
+void CustomTrackView::clearSelection()
+{
+    resetSelectionGroup();
+    scene()->clearSelection();
+    m_dragItem = NULL;
+    emit clipItemSelected(NULL);
+}
+