]> git.sesse.net Git - kdenlive/blob - src/customtrackview.cpp
cleanup
[kdenlive] / src / customtrackview.cpp
1 /***************************************************************************
2  *   Copyright (C) 2007 by Jean-Baptiste Mardelle (jb@kdenlive.org)        *
3  *                                                                         *
4  *   This program is free software; you can redistribute it and/or modify  *
5  *   it under the terms of the GNU General Public License as published by  *
6  *   the Free Software Foundation; either version 2 of the License, or     *
7  *   (at your option) any later version.                                   *
8  *                                                                         *
9  *   This program is distributed in the hope that it will be useful,       *
10  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
11  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
12  *   GNU General Public License for more details.                          *
13  *                                                                         *
14  *   You should have received a copy of the GNU General Public License     *
15  *   along with this program; if not, write to the                         *
16  *   Free Software Foundation, Inc.,                                       *
17  *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA          *
18  ***************************************************************************/
19
20
21 #include "customtrackview.h"
22 #include "docclipbase.h"
23 #include "clipitem.h"
24 #include "definitions.h"
25 #include "moveclipcommand.h"
26 #include "movetransitioncommand.h"
27 #include "resizeclipcommand.h"
28 #include "editguidecommand.h"
29 #include "addtimelineclipcommand.h"
30 #include "addeffectcommand.h"
31 #include "editeffectcommand.h"
32 #include "moveeffectcommand.h"
33 #include "addtransitioncommand.h"
34 #include "edittransitioncommand.h"
35 #include "editkeyframecommand.h"
36 #include "changespeedcommand.h"
37 #include "addmarkercommand.h"
38 #include "razorclipcommand.h"
39 #include "kdenlivesettings.h"
40 #include "transition.h"
41 #include "clipmanager.h"
42 #include "renderer.h"
43 #include "markerdialog.h"
44 #include "mainwindow.h"
45 #include "ui_keyframedialog_ui.h"
46 #include "clipdurationdialog.h"
47 #include "abstractgroupitem.h"
48 #include "insertspacecommand.h"
49 #include "spacerdialog.h"
50 #include "addtrackcommand.h"
51 #include "changetrackcommand.h"
52 #include "movegroupcommand.h"
53 #include "ui_addtrack_ui.h"
54 #include "initeffects.h"
55 #include "locktrackcommand.h"
56 #include "groupclipscommand.h"
57 #include "splitaudiocommand.h"
58 #include "changecliptypecommand.h"
59 #include "trackdialog.h"
60
61 #include <KDebug>
62 #include <KLocale>
63 #include <KUrl>
64 #include <KIcon>
65 #include <KCursor>
66 #include <KColorScheme>
67
68 #include <QMouseEvent>
69 #include <QStylePainter>
70 #include <QGraphicsItem>
71 #include <QDomDocument>
72 #include <QScrollBar>
73 #include <QApplication>
74 #include <QInputDialog>
75 #include <KMessageBox>
76
77 #if QT_VERSION >= 0x040600
78 #include <QGraphicsDropShadowEffect>
79 #endif
80
81 bool sortGuidesList(const Guide *g1 , const Guide *g2)
82 {
83     return (*g1).position() < (*g2).position();
84 }
85
86
87 //TODO:
88 // disable animation if user asked it in KDE's global settings
89 // http://lists.kde.org/?l=kde-commits&m=120398724717624&w=2
90 // needs something like below (taken from dolphin)
91 // #include <kglobalsettings.h>
92 // const bool animate = KGlobalSettings::graphicEffectsLevel() & KGlobalSettings::SimpleAnimationEffects;
93 // const int duration = animate ? 1500 : 1;
94
95 CustomTrackView::CustomTrackView(KdenliveDoc *doc, CustomTrackScene* projectscene, QWidget *parent) :
96         QGraphicsView(projectscene, parent),
97         m_tracksHeight(KdenliveSettings::trackheight()),
98         m_projectDuration(0),
99         m_cursorPos(0),
100         m_document(doc),
101         m_scene(projectscene),
102         m_cursorLine(NULL),
103         m_operationMode(NONE),
104         m_moveOpMode(NONE),
105         m_dragItem(NULL),
106         m_dragGuide(NULL),
107         m_visualTip(NULL),
108         m_animation(NULL),
109         m_clickPoint(),
110         m_autoScroll(KdenliveSettings::autoscroll()),
111         m_pasteEffectsAction(NULL),
112         m_ungroupAction(NULL),
113         m_scrollOffset(0),
114         m_clipDrag(false),
115         m_findIndex(0),
116         m_tool(SELECTTOOL),
117         m_copiedItems(),
118         m_menuPosition(),
119         m_blockRefresh(false),
120         m_selectionGroup(NULL),
121         m_selectedTrack(0)
122 {
123     if (doc) m_commandStack = doc->commandStack();
124     else m_commandStack = NULL;
125     setMouseTracking(true);
126     setAcceptDrops(true);
127     setFrameShape(QFrame::NoFrame);
128     setLineWidth(0);
129     //setCacheMode(QGraphicsView::CacheBackground);
130     //setViewportUpdateMode(QGraphicsView::FullViewportUpdate);
131
132     KdenliveSettings::setTrackheight(m_tracksHeight);
133     m_animationTimer = new QTimeLine(800);
134     m_animationTimer->setFrameRange(0, 5);
135     m_animationTimer->setUpdateInterval(100);
136     m_animationTimer->setLoopCount(0);
137     m_tipColor = QColor(0, 192, 0, 200);
138     QColor border = QColor(255, 255, 255, 100);
139     m_tipPen.setColor(border);
140     m_tipPen.setWidth(3);
141     setContentsMargins(0, 0, 0, 0);
142     const int maxHeight = m_tracksHeight * m_document->tracksCount();
143     setSceneRect(0, 0, sceneRect().width(), maxHeight);
144     verticalScrollBar()->setMaximum(maxHeight);
145     m_cursorLine = projectscene->addLine(0, 0, 0, maxHeight);
146     m_cursorLine->setZValue(1000);
147
148     QPen pen1 = QPen();
149     pen1.setWidth(1);
150     pen1.setColor(palette().text().color());
151     m_cursorLine->setPen(pen1);
152     m_cursorLine->setFlag(QGraphicsItem::ItemIgnoresTransformations, true);
153
154     KIcon razorIcon("edit-cut");
155     m_razorCursor = QCursor(razorIcon.pixmap(22, 22));
156
157     KIcon spacerIcon("kdenlive-spacer-tool");
158     m_spacerCursor = QCursor(spacerIcon.pixmap(22, 22));
159     verticalScrollBar()->setTracking(true);
160     // Line below was supposed to scroll guides label with scrollbar, not implemented yet
161     //connect(verticalScrollBar(), SIGNAL(valueChanged(int)), this, SLOT(slotRefreshGuides()));
162     connect(&m_scrollTimer, SIGNAL(timeout()), this, SLOT(slotCheckMouseScrolling()));
163     m_scrollTimer.setInterval(100);
164     m_scrollTimer.setSingleShot(true);
165
166     connect(&m_thumbsTimer, SIGNAL(timeout()), this, SLOT(slotFetchNextThumbs()));
167     m_thumbsTimer.setInterval(500);
168     m_thumbsTimer.setSingleShot(true);
169 }
170
171 CustomTrackView::~CustomTrackView()
172 {
173     qDeleteAll(m_guides);
174     m_waitingThumbs.clear();
175 }
176
177 //virtual
178 void CustomTrackView::keyPressEvent(QKeyEvent * event)
179 {
180     if (event->key() == Qt::Key_Up) {
181         slotTrackUp();
182         event->accept();
183     } else if (event->key() == Qt::Key_Down) {
184         slotTrackDown();
185         event->accept();
186     } else QWidget::keyPressEvent(event);
187 }
188
189 void CustomTrackView::setDocumentModified()
190 {
191     m_document->setModified(true);
192 }
193
194 void CustomTrackView::setContextMenu(QMenu *timeline, QMenu *clip, QMenu *transition, QActionGroup *clipTypeGroup)
195 {
196     m_timelineContextMenu = timeline;
197     m_timelineContextClipMenu = clip;
198     m_clipTypeGroup = clipTypeGroup;
199     QList <QAction *> list = m_timelineContextClipMenu->actions();
200     for (int i = 0; i < list.count(); i++) {
201         if (list.at(i)->data().toString() == "paste_effects") m_pasteEffectsAction = list.at(i);
202         else if (list.at(i)->data().toString() == "ungroup_clip") m_ungroupAction = list.at(i);
203     }
204
205     m_timelineContextTransitionMenu = transition;
206     list = m_timelineContextTransitionMenu->actions();
207     for (int i = 0; i < list.count(); i++) {
208         if (list.at(i)->data().toString() == "auto") {
209             m_autoTransition = list.at(i);
210             break;
211         }
212     }
213
214     m_timelineContextMenu->addSeparator();
215     m_deleteGuide = new KAction(KIcon("edit-delete"), i18n("Delete Guide"), this);
216     connect(m_deleteGuide, SIGNAL(triggered()), this, SLOT(slotDeleteTimeLineGuide()));
217     m_timelineContextMenu->addAction(m_deleteGuide);
218
219     m_editGuide = new KAction(KIcon("document-properties"), i18n("Edit Guide"), this);
220     connect(m_editGuide, SIGNAL(triggered()), this, SLOT(slotEditTimeLineGuide()));
221     m_timelineContextMenu->addAction(m_editGuide);
222 }
223
224 void CustomTrackView::checkAutoScroll()
225 {
226     m_autoScroll = KdenliveSettings::autoscroll();
227 }
228
229 /*sQList <TrackInfo> CustomTrackView::tracksList() const {
230     return m_scene->m_tracksList;
231 }*/
232
233 void CustomTrackView::checkTrackHeight()
234 {
235     if (m_tracksHeight == KdenliveSettings::trackheight()) return;
236     m_tracksHeight = KdenliveSettings::trackheight();
237     emit trackHeightChanged();
238     QList<QGraphicsItem *> itemList = items();
239     ClipItem *item;
240     Transition *transitionitem;
241     bool snap = KdenliveSettings::snaptopoints();
242     KdenliveSettings::setSnaptopoints(false);
243     for (int i = 0; i < itemList.count(); i++) {
244         if (itemList.at(i)->type() == AVWIDGET) {
245             item = (ClipItem*) itemList.at(i);
246             item->setRect(0, 0, item->rect().width(), m_tracksHeight - 1);
247             item->setPos((qreal) item->startPos().frames(m_document->fps()), (qreal) item->track() * m_tracksHeight + 1);
248             item->resetThumbs(true);
249         } else if (itemList.at(i)->type() == TRANSITIONWIDGET) {
250             transitionitem = (Transition*) itemList.at(i);
251             transitionitem->setRect(0, 0, transitionitem->rect().width(), m_tracksHeight / 3 * 2 - 1);
252             transitionitem->setPos((qreal) transitionitem->startPos().frames(m_document->fps()), (qreal) transitionitem->track() * m_tracksHeight + m_tracksHeight / 3 * 2);
253         }
254     }
255     m_cursorLine->setLine(m_cursorLine->line().x1(), 0, m_cursorLine->line().x1(), m_tracksHeight * m_document->tracksCount());
256
257     for (int i = 0; i < m_guides.count(); i++) {
258         QLineF l = m_guides.at(i)->line();
259         l.setP2(QPointF(l.x2(), m_tracksHeight * m_document->tracksCount()));
260         m_guides.at(i)->setLine(l);
261     }
262
263     setSceneRect(0, 0, sceneRect().width(), m_tracksHeight * m_document->tracksCount());
264 //     verticalScrollBar()->setMaximum(m_tracksHeight * m_document->tracksCount());
265     KdenliveSettings::setSnaptopoints(snap);
266     viewport()->update();
267 }
268
269 /** Zoom or move viewport on mousewheel
270  *
271  * If mousewheel+Ctrl, zooms in/out on the timeline.
272  *
273  * With Ctrl, moves viewport towards end of timeline if down/back,
274  * opposite on up/forward.
275  *
276  * See also http://www.kdenlive.org/mantis/view.php?id=265 */
277 void CustomTrackView::wheelEvent(QWheelEvent * e)
278 {
279     if (e->modifiers() == Qt::ControlModifier) {
280         if (e->delta() > 0) emit zoomIn();
281         else emit zoomOut();
282     } else {
283         if (e->delta() <= 0) horizontalScrollBar()->setValue(horizontalScrollBar()->value() + horizontalScrollBar()->singleStep());
284         else  horizontalScrollBar()->setValue(horizontalScrollBar()->value() - horizontalScrollBar()->singleStep());
285     }
286 }
287
288 int CustomTrackView::getPreviousVideoTrack(int track)
289 {
290     track = m_document->tracksCount() - track - 1;
291     track --;
292     for (int i = track; i > -1; i--) {
293         if (m_document->trackInfoAt(i).type == VIDEOTRACK) return i + 1;
294     }
295     return 0;
296 }
297
298
299 void CustomTrackView::slotFetchNextThumbs()
300 {
301     if (!m_waitingThumbs.isEmpty()) {
302         ClipItem *item = m_waitingThumbs.takeFirst();
303         while ((item == NULL) && !m_waitingThumbs.isEmpty()) {
304             item = m_waitingThumbs.takeFirst();
305         }
306         if (item) item->slotFetchThumbs();
307         if (!m_waitingThumbs.isEmpty()) m_thumbsTimer.start();
308     }
309 }
310
311 void CustomTrackView::slotCheckMouseScrolling()
312 {
313     if (m_scrollOffset == 0) {
314         m_scrollTimer.stop();
315         return;
316     }
317     horizontalScrollBar()->setValue(horizontalScrollBar()->value() + m_scrollOffset);
318     m_scrollTimer.start();
319 }
320
321 void CustomTrackView::slotCheckPositionScrolling()
322 {
323     // If mouse is at a border of the view, scroll
324     if (m_moveOpMode != SEEK) return;
325     if (mapFromScene(m_cursorPos, 0).x() < 3) {
326         horizontalScrollBar()->setValue(horizontalScrollBar()->value() - 2);
327         QTimer::singleShot(200, this, SLOT(slotCheckPositionScrolling()));
328         setCursorPos(mapToScene(QPoint(-2, 0)).x());
329     } else if (viewport()->width() - 3 < mapFromScene(m_cursorPos + 1, 0).x()) {
330         horizontalScrollBar()->setValue(horizontalScrollBar()->value() + 2);
331         setCursorPos(mapToScene(QPoint(viewport()->width(), 0)).x() + 1);
332         QTimer::singleShot(200, this, SLOT(slotCheckPositionScrolling()));
333     }
334 }
335
336
337 // virtual
338 void CustomTrackView::mouseMoveEvent(QMouseEvent * event)
339 {
340     int pos = event->x();
341     int mappedXPos = qMax((int)(mapToScene(event->pos()).x() + 0.5), 0);
342     double snappedPos = getSnapPointForPos(mappedXPos);
343     emit mousePosition(mappedXPos);
344
345     if (event->buttons() & Qt::MidButton) return;
346     if (dragMode() == QGraphicsView::RubberBandDrag || (event->modifiers() == Qt::ControlModifier && m_tool != SPACERTOOL)) {
347         event->setAccepted(true);
348         m_moveOpMode = NONE;
349         QGraphicsView::mouseMoveEvent(event);
350         return;
351     }
352
353     if (event->buttons() != Qt::NoButton) {
354         bool move = (event->pos() - m_clickEvent).manhattanLength() >= QApplication::startDragDistance();
355         if (m_dragItem && m_tool == SELECTTOOL) {
356             if (m_operationMode == MOVE && move) {
357                 QGraphicsView::mouseMoveEvent(event);
358                 // If mouse is at a border of the view, scroll
359                 if (pos < 5) {
360                     m_scrollOffset = -30;
361                     m_scrollTimer.start();
362                 } else if (viewport()->width() - pos < 10) {
363                     m_scrollOffset = 30;
364                     m_scrollTimer.start();
365                 } else if (m_scrollTimer.isActive()) m_scrollTimer.stop();
366
367             } else if (m_operationMode == RESIZESTART && move) {
368                 m_document->renderer()->pause();
369                 m_dragItem->resizeStart((int)(snappedPos));
370             } else if (m_operationMode == RESIZEEND && move) {
371                 m_document->renderer()->pause();
372                 m_dragItem->resizeEnd((int)(snappedPos));
373             } else if (m_operationMode == FADEIN && move) {
374                 ((ClipItem*) m_dragItem)->setFadeIn((int)(mappedXPos - m_dragItem->startPos().frames(m_document->fps())));
375             } else if (m_operationMode == FADEOUT && move) {
376                 ((ClipItem*) m_dragItem)->setFadeOut((int)(m_dragItem->endPos().frames(m_document->fps()) - mappedXPos));
377             } else if (m_operationMode == KEYFRAME && move) {
378                 GenTime keyFramePos = GenTime(mappedXPos, m_document->fps()) - m_dragItem->startPos() + m_dragItem->cropStart();
379                 double pos = mapToScene(event->pos()).toPoint().y();
380                 QRectF br = m_dragItem->sceneBoundingRect();
381                 double maxh = 100.0 / br.height();
382                 pos = (br.bottom() - pos) * maxh;
383                 m_dragItem->updateKeyFramePos(keyFramePos, pos);
384             }
385             if (m_visualTip) {
386                 scene()->removeItem(m_visualTip);
387                 m_animationTimer->stop();
388                 delete m_animation;
389                 m_animation = NULL;
390                 delete m_visualTip;
391                 m_visualTip = NULL;
392             }
393             return;
394         } else if (m_operationMode == MOVEGUIDE) {
395             if (m_visualTip) {
396                 scene()->removeItem(m_visualTip);
397                 m_animationTimer->stop();
398                 delete m_animation;
399                 m_animation = NULL;
400                 delete m_visualTip;
401                 m_visualTip = NULL;
402             }
403             QGraphicsView::mouseMoveEvent(event);
404             return;
405         } else if (m_operationMode == SPACER && move && m_selectionGroup) {
406             // spacer tool
407             if (snappedPos < 0) snappedPos = 0;
408             // Make sure there is no collision
409             QList<QGraphicsItem *> children = m_selectionGroup->childItems();
410             QPainterPath shape = m_selectionGroup->clipGroupShape(QPointF(snappedPos - m_selectionGroup->sceneBoundingRect().left(), 0));
411             QList<QGraphicsItem*> collidingItems = scene()->items(shape, Qt::IntersectsItemShape);
412             collidingItems.removeAll(m_selectionGroup);
413             for (int i = 0; i < children.count(); i++) {
414                 collidingItems.removeAll(children.at(i));
415             }
416             bool collision = false;
417             for (int i = 0; i < collidingItems.count(); i++) {
418                 if (!collidingItems.at(i)->isEnabled()) continue;
419                 if (collidingItems.at(i)->type() == AVWIDGET) {
420                     collision = true;
421                     break;
422                 }
423             }
424             if (!collision) {
425                 // Check transitions
426                 shape = m_selectionGroup->transitionGroupShape(QPointF(snappedPos - m_selectionGroup->sceneBoundingRect().left(), 0));
427                 collidingItems = scene()->items(shape, Qt::IntersectsItemShape);
428                 collidingItems.removeAll(m_selectionGroup);
429                 for (int i = 0; i < children.count(); i++) {
430                     collidingItems.removeAll(children.at(i));
431                 }
432                 for (int i = 0; i < collidingItems.count(); i++) {
433                     if (collidingItems.at(i)->type() == TRANSITIONWIDGET) {
434                         collision = true;
435                         break;
436                     }
437                 }
438             }
439
440             if (!collision)
441                 m_selectionGroup->translate(snappedPos - m_selectionGroup->sceneBoundingRect().left(), 0);
442             //m_selectionGroup->setPos(mappedXPos + (((int) m_selectionGroup->boundingRect().topLeft().x() + 0.5) - mappedClick) , m_selectionGroup->pos().y());
443         }
444     }
445
446     if (m_tool == RAZORTOOL) {
447         setCursor(m_razorCursor);
448         //QGraphicsView::mouseMoveEvent(event);
449         //return;
450     } else if (m_tool == SPACERTOOL) {
451         setCursor(m_spacerCursor);
452         return;
453     }
454
455     QList<QGraphicsItem *> itemList = items(event->pos());
456     QGraphicsRectItem *item = NULL;
457     OPERATIONTYPE opMode = NONE;
458
459     if (itemList.count() == 1 && itemList.at(0)->type() == GUIDEITEM) {
460         opMode = MOVEGUIDE;
461     } else for (int i = 0; i < itemList.count(); i++) {
462             if (itemList.at(i)->type() == AVWIDGET || itemList.at(i)->type() == TRANSITIONWIDGET) {
463                 item = (QGraphicsRectItem*) itemList.at(i);
464                 break;
465             }
466         }
467
468     if (item && event->buttons() == Qt::NoButton) {
469         AbstractClipItem *clip = static_cast <AbstractClipItem*>(item);
470         if (m_tool == RAZORTOOL) {
471             // razor tool over a clip, display current frame in monitor
472             if (false && !m_blockRefresh && item->type() == AVWIDGET) {
473                 //TODO: solve crash when showing frame when moving razor over clip
474                 emit showClipFrame(((ClipItem *) item)->baseClip(), mappedXPos - (clip->startPos() - clip->cropStart()).frames(m_document->fps()));
475             }
476             event->accept();
477             return;
478         }
479         opMode = clip->operationMode(mapToScene(event->pos()));
480         const double size = 5;
481         if (opMode == m_moveOpMode) {
482             QGraphicsView::mouseMoveEvent(event);
483             return;
484         } else {
485             if (m_visualTip) {
486                 scene()->removeItem(m_visualTip);
487                 m_animationTimer->stop();
488                 delete m_animation;
489                 m_animation = NULL;
490                 delete m_visualTip;
491                 m_visualTip = NULL;
492             }
493         }
494         m_moveOpMode = opMode;
495         if (opMode == MOVE) {
496             setCursor(Qt::OpenHandCursor);
497         } else if (opMode == RESIZESTART) {
498             setCursor(KCursor("left_side", Qt::SizeHorCursor));
499             if (m_visualTip == NULL) {
500                 QRectF rect = clip->sceneBoundingRect();
501                 QPolygon polygon;
502                 polygon << QPoint(0, - size * 2);
503                 polygon << QPoint(size * 2, 0);
504                 polygon << QPoint(0, size * 2);
505                 polygon << QPoint(0, - size * 2);
506
507                 m_visualTip = new QGraphicsPolygonItem(polygon);
508                 ((QGraphicsPolygonItem*) m_visualTip)->setBrush(m_tipColor);
509                 ((QGraphicsPolygonItem*) m_visualTip)->setPen(m_tipPen);
510                 m_visualTip->setPos(rect.x(), rect.y() + rect.height() / 2);
511                 m_visualTip->setFlags(QGraphicsItem::ItemIgnoresTransformations);
512                 m_visualTip->setZValue(100);
513                 m_animation = new QGraphicsItemAnimation;
514                 m_animation->setItem(m_visualTip);
515                 m_animation->setTimeLine(m_animationTimer);
516                 m_animation->setScaleAt(.5, 2, 1);
517                 m_animation->setScaleAt(1, 1, 1);
518                 scene()->addItem(m_visualTip);
519                 m_animationTimer->start();
520             }
521         } else if (opMode == RESIZEEND) {
522             setCursor(KCursor("right_side", Qt::SizeHorCursor));
523             if (m_visualTip == NULL) {
524                 QRectF rect = clip->sceneBoundingRect();
525                 QPolygon polygon;
526                 polygon << QPoint(0, - size * 2);
527                 polygon << QPoint(- size * 2, 0);
528                 polygon << QPoint(0, size * 2);
529                 polygon << QPoint(0, - size * 2);
530
531                 m_visualTip = new QGraphicsPolygonItem(polygon);
532                 ((QGraphicsPolygonItem*) m_visualTip)->setBrush(m_tipColor);
533                 ((QGraphicsPolygonItem*) m_visualTip)->setPen(m_tipPen);
534                 m_visualTip->setFlags(QGraphicsItem::ItemIgnoresTransformations);
535                 m_visualTip->setPos(rect.right(), rect.y() + rect.height() / 2);
536                 m_visualTip->setZValue(100);
537                 m_animation = new QGraphicsItemAnimation;
538                 m_animation->setItem(m_visualTip);
539                 m_animation->setTimeLine(m_animationTimer);
540                 m_animation->setScaleAt(.5, 2, 1);
541                 m_animation->setScaleAt(1, 1, 1);
542                 scene()->addItem(m_visualTip);
543                 m_animationTimer->start();
544             }
545         } else if (opMode == FADEIN) {
546             if (m_visualTip == NULL) {
547                 ClipItem *item = (ClipItem *) clip;
548                 QRectF rect = clip->sceneBoundingRect();
549                 m_visualTip = new QGraphicsEllipseItem(-size, -size, size * 2, size * 2);
550                 ((QGraphicsEllipseItem*) m_visualTip)->setBrush(m_tipColor);
551                 ((QGraphicsEllipseItem*) m_visualTip)->setPen(m_tipPen);
552                 m_visualTip->setPos(rect.x() + item->fadeIn(), rect.y());
553                 m_visualTip->setFlags(QGraphicsItem::ItemIgnoresTransformations);
554                 m_visualTip->setZValue(100);
555                 m_animation = new QGraphicsItemAnimation;
556                 m_animation->setItem(m_visualTip);
557                 m_animation->setTimeLine(m_animationTimer);
558                 m_animation->setScaleAt(.5, 2, 2);
559                 m_animation->setScaleAt(1, 1, 1);
560                 scene()->addItem(m_visualTip);
561                 m_animationTimer->start();
562             }
563             setCursor(Qt::PointingHandCursor);
564         } else if (opMode == FADEOUT) {
565             if (m_visualTip == NULL) {
566                 ClipItem *item = (ClipItem *) clip;
567                 QRectF rect = clip->sceneBoundingRect();
568                 m_visualTip = new QGraphicsEllipseItem(-size, -size, size * 2, size * 2);
569                 ((QGraphicsEllipseItem*) m_visualTip)->setBrush(m_tipColor);
570                 ((QGraphicsEllipseItem*) m_visualTip)->setPen(m_tipPen);
571                 m_visualTip->setPos(rect.right() - item->fadeOut(), rect.y());
572                 m_visualTip->setFlags(QGraphicsItem::ItemIgnoresTransformations);
573                 m_visualTip->setZValue(100);
574                 m_animation = new QGraphicsItemAnimation;
575                 m_animation->setItem(m_visualTip);
576                 m_animation->setTimeLine(m_animationTimer);
577                 m_animation->setScaleAt(.5, 2, 2);
578                 m_animation->setScaleAt(1, 1, 1);
579                 scene()->addItem(m_visualTip);
580                 m_animationTimer->start();
581             }
582             setCursor(Qt::PointingHandCursor);
583         } else if (opMode == TRANSITIONSTART) {
584             if (m_visualTip == NULL) {
585                 QRectF rect = clip->sceneBoundingRect();
586                 QPolygon polygon;
587                 polygon << QPoint(0, - size * 2);
588                 polygon << QPoint(size * 2, 0);
589                 polygon << QPoint(0, 0);
590                 polygon << QPoint(0, - size * 2);
591
592                 m_visualTip = new QGraphicsPolygonItem(polygon);
593                 ((QGraphicsPolygonItem*) m_visualTip)->setBrush(m_tipColor);
594                 ((QGraphicsPolygonItem*) m_visualTip)->setPen(m_tipPen);
595                 m_visualTip->setPos(rect.x(), rect.bottom());
596                 m_visualTip->setFlags(QGraphicsItem::ItemIgnoresTransformations);
597                 m_visualTip->setZValue(100);
598                 m_animation = new QGraphicsItemAnimation;
599                 m_animation->setItem(m_visualTip);
600                 m_animation->setTimeLine(m_animationTimer);
601                 m_animation->setScaleAt(.5, 2, 2);
602                 m_animation->setScaleAt(1, 1, 1);
603                 scene()->addItem(m_visualTip);
604                 m_animationTimer->start();
605             }
606             setCursor(Qt::PointingHandCursor);
607         } else if (opMode == TRANSITIONEND) {
608             if (m_visualTip == NULL) {
609                 QRectF rect = clip->sceneBoundingRect();
610                 QPolygon polygon;
611                 polygon << QPoint(0, - size * 2);
612                 polygon << QPoint(- size * 2, 0);
613                 polygon << QPoint(0, 0);
614                 polygon << QPoint(0, - size * 2);
615
616                 m_visualTip = new QGraphicsPolygonItem(polygon);
617                 ((QGraphicsPolygonItem*) m_visualTip)->setBrush(m_tipColor);
618                 ((QGraphicsPolygonItem*) m_visualTip)->setPen(m_tipPen);
619                 m_visualTip->setPos(rect.right(), rect.bottom());
620                 m_visualTip->setFlags(QGraphicsItem::ItemIgnoresTransformations);
621                 m_visualTip->setZValue(100);
622                 m_animation = new QGraphicsItemAnimation;
623                 m_animation->setItem(m_visualTip);
624                 m_animation->setTimeLine(m_animationTimer);
625                 m_animation->setScaleAt(.5, 2, 2);
626                 m_animation->setScaleAt(1, 1, 1);
627                 scene()->addItem(m_visualTip);
628                 m_animationTimer->start();
629             }
630             setCursor(Qt::PointingHandCursor);
631         } else if (opMode == KEYFRAME) {
632             setCursor(Qt::PointingHandCursor);
633         }
634     } // no clip under mouse
635     else if (m_tool == RAZORTOOL) {
636         event->accept();
637         return;
638     } else if (opMode == MOVEGUIDE) {
639         m_moveOpMode = opMode;
640         setCursor(Qt::SplitHCursor);
641     } else {
642         if (m_visualTip) {
643             scene()->removeItem(m_visualTip);
644             m_animationTimer->stop();
645             delete m_animation;
646             m_animation = NULL;
647             delete m_visualTip;
648             m_visualTip = NULL;
649
650         }
651         setCursor(Qt::ArrowCursor);
652         if (event->buttons() != Qt::NoButton && event->modifiers() == Qt::NoModifier) {
653             QGraphicsView::mouseMoveEvent(event);
654             m_moveOpMode = SEEK;
655             setCursorPos(mappedXPos);
656             slotCheckPositionScrolling();
657             return;
658         } else m_moveOpMode = NONE;
659     }
660     QGraphicsView::mouseMoveEvent(event);
661 }
662
663 // virtual
664 void CustomTrackView::mousePressEvent(QMouseEvent * event)
665 {
666     setFocus(Qt::MouseFocusReason);
667     m_menuPosition = QPoint();
668
669     // special cases (middle click button or ctrl / shift click
670     if (event->button() == Qt::MidButton) {
671         m_document->renderer()->switchPlay();
672         m_blockRefresh = false;
673         m_operationMode = NONE;
674         return;
675     }
676
677     if (event->modifiers() & Qt::ShiftModifier) {
678         // Rectangle selection
679         setViewportUpdateMode(QGraphicsView::FullViewportUpdate);
680         setDragMode(QGraphicsView::RubberBandDrag);
681         if (!(event->modifiers() & Qt::ControlModifier)) {
682             resetSelectionGroup();
683             scene()->clearSelection();
684         }
685         m_blockRefresh = false;
686         m_operationMode = RUBBERSELECTION;
687         QGraphicsView::mousePressEvent(event);
688         return;
689     }
690
691     m_blockRefresh = true;
692     m_dragGuide = NULL;
693     bool collision = false;
694
695     if (m_tool != RAZORTOOL) activateMonitor();
696     else if (m_document->renderer()->playSpeed() != 0.0) {
697         m_document->renderer()->pause();
698         return;
699     }
700     m_clickEvent = event->pos();
701
702     // check item under mouse
703     QList<QGraphicsItem *> collisionList = items(m_clickEvent);
704
705     if (event->modifiers() == Qt::ControlModifier && m_tool != SPACERTOOL && collisionList.count() == 0) {
706         // Pressing Ctrl + left mouse button in an empty area scrolls the timeline
707         setDragMode(QGraphicsView::ScrollHandDrag);
708         QGraphicsView::mousePressEvent(event);
709         m_blockRefresh = false;
710         m_operationMode = NONE;
711         return;
712     }
713
714     // if a guide and a clip were pressed, just select the guide
715     for (int i = 0; i < collisionList.count(); ++i) {
716         if (collisionList.at(i)->type() == GUIDEITEM) {
717             // a guide item was pressed
718             m_dragGuide = (Guide *) collisionList.at(i);
719             if (event->button() == Qt::LeftButton) { // move it
720                 m_dragGuide->setFlag(QGraphicsItem::ItemIsMovable, true);
721                 collision = true;
722                 m_operationMode = MOVEGUIDE;
723                 // deselect all clips so that only the guide will move
724                 m_scene->clearSelection();
725                 resetSelectionGroup(false);
726                 updateSnapPoints(NULL);
727                 QGraphicsView::mousePressEvent(event);
728                 return;
729             } else // show context menu
730                 break;
731         }
732     }
733
734     // Find first clip, transition or group under mouse (when no guides selected)
735     int ct = 0;
736     AbstractGroupItem *dragGroup = NULL;
737     AbstractClipItem *collisionClip = NULL;
738     bool found = false;
739     while (!m_dragGuide && ct < collisionList.count()) {
740         if (collisionList.at(ct)->type() == AVWIDGET || collisionList.at(ct)->type() == TRANSITIONWIDGET) {
741             collisionClip = static_cast <AbstractClipItem *>(collisionList.at(ct));
742             if (collisionClip == m_dragItem) {
743                 collisionClip = NULL;
744             } else m_dragItem = collisionClip;
745             found = true;
746             m_dragItemInfo = m_dragItem->info();
747             if (m_dragItem->parentItem() && m_dragItem->parentItem()->type() == GROUPWIDGET && m_dragItem->parentItem() != m_selectionGroup) {
748                 // kDebug()<<"// KLIK FOUND GRP: "<<m_dragItem->sceneBoundingRect();
749                 dragGroup = static_cast <AbstractGroupItem *>(m_dragItem->parentItem());
750             }
751             break;
752         }
753         ct++;
754     }
755     if (!found) {
756         if (m_dragItem) emit clipItemSelected(NULL);
757         m_dragItem = NULL;
758     }
759 #if QT_VERSION >= 0x040600
760     // Add shadow to dragged item, currently disabled because of painting artifacts
761     //TODO: re-enable when fixed
762     /*QGraphicsDropShadowEffect *eff = new QGraphicsDropShadowEffect();
763     eff->setBlurRadius(5);
764     eff->setOffset(3, 3);
765     m_dragItem->setGraphicsEffect(eff);*/
766 #endif
767     if (m_dragItem && m_dragItem->type() == TRANSITIONWIDGET) {
768         // update transition menu action
769         m_autoTransition->setChecked(static_cast<Transition *>(m_dragItem)->isAutomatic());
770         m_autoTransition->setEnabled(true);
771     } else m_autoTransition->setEnabled(false);
772
773     // context menu requested
774     if (event->button() == Qt::RightButton) {
775         if (m_dragItem) {
776             if (dragGroup) dragGroup->setSelected(true);
777             else if (!m_dragItem->isSelected()) {
778                 resetSelectionGroup(false);
779                 m_scene->clearSelection();
780                 m_dragItem->setSelected(true);
781             }
782         } else if (!m_dragGuide) {
783             // check if there is a guide close to mouse click
784             QList<QGraphicsItem *> guidesCollisionList = items(event->pos().x() - 5, event->pos().y(), 10, 2); // a rect of height < 2 does not always collide with the guide
785             for (int i = 0; i < guidesCollisionList.count(); i++) {
786                 if (guidesCollisionList.at(i)->type() == GUIDEITEM) {
787                     m_dragGuide = static_cast <Guide *>(guidesCollisionList.at(i));
788                     break;
789                 }
790             }
791             // keep this to support multiple guides context menu in the future (?)
792             /*if (guidesCollisionList.at(0)->type() != GUIDEITEM)
793                 guidesCollisionList.removeAt(0);
794             }
795             if (!guidesCollisionList.isEmpty())
796             m_dragGuide = static_cast <Guide *>(guidesCollisionList.at(0));*/
797         }
798
799         m_operationMode = NONE;
800         displayContextMenu(event->globalPos(), m_dragItem, dragGroup);
801         m_menuPosition = m_clickEvent;
802         m_dragItem = NULL;
803         event->accept();
804         return;
805     }
806
807     // No item under click
808     if (m_dragItem == NULL || m_tool == SPACERTOOL) {
809         resetSelectionGroup(false);
810         setCursor(Qt::ArrowCursor);
811         m_scene->clearSelection();
812         //event->accept();
813         updateClipTypeActions(NULL);
814         if (m_tool == SPACERTOOL) {
815             QList<QGraphicsItem *> selection;
816             if (event->modifiers() == Qt::ControlModifier) {
817                 // Ctrl + click, select all items on track after click position
818                 int track = (int)(mapToScene(m_clickEvent).y() / m_tracksHeight);
819                 if (m_document->trackInfoAt(m_document->tracksCount() - track - 1).isLocked) {
820                     // Cannot use spacer on locked track
821                     emit displayMessage(i18n("Cannot use spacer in a locked track"), ErrorMessage);
822                     return;               
823                 }  
824   
825                 QRectF rect(mapToScene(m_clickEvent).x(), track * m_tracksHeight + m_tracksHeight / 2, sceneRect().width() - mapToScene(m_clickEvent).x(), m_tracksHeight / 2 - 2);
826
827                 bool isOk;
828                 selection = checkForGroups(rect, &isOk);
829                 if (!isOk) {
830                     // groups found on track, do not allow the move
831                     emit displayMessage(i18n("Cannot use spacer in a track with a group"), ErrorMessage);
832                     return;
833                 }
834
835                 kDebug() << "SPACER TOOL + CTRL, SELECTING ALL CLIPS ON TRACK " << track << " WITH SELECTION RECT " << m_clickEvent.x() << "/" <<  track * m_tracksHeight + 1 << "; " << mapFromScene(sceneRect().width(), 0).x() - m_clickEvent.x() << "/" << m_tracksHeight - 2;
836             } else {
837                 // Select all items on all tracks after click position
838                 selection = items(event->pos().x(), 1, mapFromScene(sceneRect().width(), 0).x() - event->pos().x(), sceneRect().height());
839                 kDebug() << "SELELCTING ELEMENTS WITHIN =" << event->pos().x() << "/" <<  1 << ", " << mapFromScene(sceneRect().width(), 0).x() - event->pos().x() << "/" << sceneRect().height();
840             }
841
842             // create group to hold selected items
843             m_selectionGroup = new AbstractGroupItem(m_document->fps());
844             scene()->addItem(m_selectionGroup);
845             QList <GenTime> offsetList;
846             for (int i = 0; i < selection.count(); i++) {
847                 if (selection.at(i)->parentItem() == 0 && (selection.at(i)->type() == AVWIDGET || selection.at(i)->type() == TRANSITIONWIDGET)) {
848                     AbstractClipItem *item = static_cast<AbstractClipItem *>(selection.at(i));
849                     if (item->isItemLocked()) continue;
850                     offsetList.append(item->startPos());
851                     offsetList.append(item->endPos());
852                     m_selectionGroup->addToGroup(selection.at(i));
853                     selection.at(i)->setFlag(QGraphicsItem::ItemIsMovable, false);
854                 } else if (selection.at(i)->parentItem() == 0 && selection.at(i)->type() == GROUPWIDGET) {
855                     if (static_cast<AbstractGroupItem *>(selection.at(i))->isItemLocked()) continue;
856                     QList<QGraphicsItem *> children = selection.at(i)->childItems();
857                     for (int j = 0; j < children.count(); j++) {
858                         AbstractClipItem *item = static_cast<AbstractClipItem *>(children.at(j));
859                         offsetList.append(item->startPos());
860                         offsetList.append(item->endPos());
861                     }
862                     m_selectionGroup->addToGroup(selection.at(i));
863                     selection.at(i)->setFlag(QGraphicsItem::ItemIsMovable, false);
864                 } else if (selection.at(i)->parentItem()) {
865                     if (static_cast<AbstractGroupItem *>(selection.at(i)->parentItem())->isItemLocked()) continue;
866                     m_selectionGroup->addToGroup(selection.at(i)->parentItem());
867                     selection.at(i)->parentItem()->setFlag(QGraphicsItem::ItemIsMovable, false);
868                 }
869             }
870
871             if (!offsetList.isEmpty()) {
872                 qSort(offsetList);
873                 QList <GenTime> cleandOffsetList;
874                 GenTime startOffset = offsetList.takeFirst();
875                 for (int k = 0; k < offsetList.size(); k++) {
876                     GenTime newoffset = offsetList.at(k) - startOffset;
877                     if (newoffset != GenTime() && !cleandOffsetList.contains(newoffset)) {
878                         cleandOffsetList.append(newoffset);
879                     }
880                 }
881                 updateSnapPoints(NULL, cleandOffsetList, true);
882             }
883             m_operationMode = SPACER;
884         } else {
885             setCursorPos((int)(mapToScene(event->x(), 0).x()));
886         }
887         QGraphicsView::mousePressEvent(event);
888         return;
889     }
890
891     // Razor tool
892     if (m_tool == RAZORTOOL && m_dragItem) {
893         if (m_dragItem->type() == TRANSITIONWIDGET) {
894             emit displayMessage(i18n("Cannot cut a transition"), ErrorMessage);
895             event->accept();
896             m_dragItem = NULL;
897             return;
898         } else if (m_dragItem->parentItem() && m_dragItem->parentItem() != m_selectionGroup) {
899             emit displayMessage(i18n("Cannot cut a clip in a group"), ErrorMessage);
900             event->accept();
901             m_dragItem = NULL;
902             return;
903         }
904         AbstractClipItem *clip = static_cast <AbstractClipItem *>(m_dragItem);
905         RazorClipCommand* command = new RazorClipCommand(this, clip->info(), GenTime((int)(mapToScene(event->pos()).x()), m_document->fps()));
906         m_document->renderer()->pause();
907         m_commandStack->push(command);
908         setDocumentModified();
909         m_dragItem = NULL;
910         event->accept();
911         return;
912     }
913
914     bool itemSelected = false;
915     if (m_dragItem->isSelected()) itemSelected = true;
916     else if (m_dragItem->parentItem() && m_dragItem->parentItem()->isSelected()) itemSelected = true;
917     else if (dragGroup && dragGroup->isSelected()) itemSelected = true;
918
919     if (event->modifiers() == Qt::ControlModifier || itemSelected == false) {
920         if (event->modifiers() != Qt::ControlModifier) {
921             resetSelectionGroup(false);
922             m_scene->clearSelection();
923             // A refresh seems necessary otherwise in zoomed mode, some clips disappear
924             viewport()->update();
925         } else resetSelectionGroup();
926         dragGroup = NULL;
927         if (m_dragItem->parentItem() && m_dragItem->parentItem()->type() == GROUPWIDGET) {
928             //kDebug()<<"// KLIK FOUND GRP: "<<m_dragItem->sceneBoundingRect();
929             dragGroup = static_cast <AbstractGroupItem *>(m_dragItem->parentItem());
930         }
931         bool selected = !m_dragItem->isSelected();
932         if (dragGroup) dragGroup->setSelected(selected);
933         else m_dragItem->setSelected(selected);
934
935         groupSelectedItems();
936         ClipItem *clip = static_cast <ClipItem *>(m_dragItem);
937         updateClipTypeActions(dragGroup == NULL ? clip : NULL);
938         m_pasteEffectsAction->setEnabled(m_copiedItems.count() == 1);
939     }
940
941     if (collisionClip != NULL || m_dragItem == NULL) {
942         if (m_dragItem && m_dragItem->type() == AVWIDGET && !m_dragItem->isItemLocked()) {
943             ClipItem *selected = static_cast <ClipItem*>(m_dragItem);
944             emit clipItemSelected(selected);
945         } else emit clipItemSelected(NULL);
946     }
947
948     // If clicked item is selected, allow move
949     if (event->modifiers() != Qt::ControlModifier && m_operationMode == NONE) QGraphicsView::mousePressEvent(event);
950
951     m_clickPoint = QPoint((int)(mapToScene(event->pos()).x() - m_dragItem->startPos().frames(m_document->fps())), (int)(event->pos().y() - m_dragItem->pos().y()));
952     m_operationMode = m_dragItem->operationMode(mapToScene(event->pos()));
953
954     // Update snap points
955     if (m_selectionGroup == NULL) {
956         if (m_operationMode == RESIZEEND || m_operationMode == RESIZESTART) updateSnapPoints(NULL);
957         else updateSnapPoints(m_dragItem);
958     } else {
959         QList <GenTime> offsetList;
960         QList<QGraphicsItem *> children = m_selectionGroup->childItems();
961         for (int i = 0; i < children.count(); i++) {
962             if (children.at(i)->type() == AVWIDGET || children.at(i)->type() == TRANSITIONWIDGET) {
963                 AbstractClipItem *item = static_cast <AbstractClipItem *>(children.at(i));
964                 offsetList.append(item->startPos());
965                 offsetList.append(item->endPos());
966             }
967         }
968         if (!offsetList.isEmpty()) {
969             qSort(offsetList);
970             GenTime startOffset = offsetList.takeFirst();
971             QList <GenTime> cleandOffsetList;
972             for (int k = 0; k < offsetList.size(); k++) {
973                 GenTime newoffset = offsetList.at(k) - startOffset;
974                 if (newoffset != GenTime() && !cleandOffsetList.contains(newoffset)) {
975                     cleandOffsetList.append(newoffset);
976                 }
977             }
978             updateSnapPoints(NULL, cleandOffsetList, true);
979         }
980     }
981
982     if (m_operationMode == KEYFRAME) {
983         m_dragItem->updateSelectedKeyFrame();
984         m_blockRefresh = false;
985         return;
986     } else if (m_operationMode == MOVE) {
987         setCursor(Qt::ClosedHandCursor);
988         if (m_dragItem) m_dragItem->setZValue(10);
989         if (m_selectionGroup) m_selectionGroup->setZValue(10);
990     } else if (m_operationMode == TRANSITIONSTART && event->modifiers() != Qt::ControlModifier) {
991         ItemInfo info;
992         info.startPos = m_dragItem->startPos();
993         info.track = m_dragItem->track();
994         int transitiontrack = getPreviousVideoTrack(info.track);
995         ClipItem *transitionClip = NULL;
996         if (transitiontrack != 0) transitionClip = getClipItemAt((int) info.startPos.frames(m_document->fps()), m_document->tracksCount() - transitiontrack);
997         if (transitionClip && transitionClip->endPos() < m_dragItem->endPos()) {
998             info.endPos = transitionClip->endPos();
999         } else {
1000             GenTime transitionDuration(65, m_document->fps());
1001             if (m_dragItem->cropDuration() < transitionDuration) info.endPos = m_dragItem->endPos();
1002             else info.endPos = info.startPos + transitionDuration;
1003         }
1004         if (info.endPos == info.startPos) info.endPos = info.startPos + GenTime(65, m_document->fps());
1005         // Check there is no other transition at that place
1006         double startY = info.track * m_tracksHeight + 1 + m_tracksHeight / 2;
1007         QRectF r(info.startPos.frames(m_document->fps()), startY, (info.endPos - info.startPos).frames(m_document->fps()), m_tracksHeight / 2);
1008         QList<QGraphicsItem *> selection = m_scene->items(r);
1009         bool transitionAccepted = true;
1010         for (int i = 0; i < selection.count(); i++) {
1011             if (selection.at(i)->type() == TRANSITIONWIDGET) {
1012                 Transition *tr = static_cast <Transition *>(selection.at(i));
1013                 if (tr->startPos() - info.startPos > GenTime(5, m_document->fps())) {
1014                     if (tr->startPos() < info.endPos) info.endPos = tr->startPos();
1015                 } else transitionAccepted = false;
1016             }
1017         }
1018         if (transitionAccepted) slotAddTransition((ClipItem *) m_dragItem, info, transitiontrack);
1019         else emit displayMessage(i18n("Cannot add transition"), ErrorMessage);
1020     } else if (m_operationMode == TRANSITIONEND && event->modifiers() != Qt::ControlModifier) {
1021         ItemInfo info;
1022         info.endPos = GenTime(m_dragItem->endPos().frames(m_document->fps()), m_document->fps());
1023         info.track = m_dragItem->track();
1024         int transitiontrack = getPreviousVideoTrack(info.track);
1025         ClipItem *transitionClip = NULL;
1026         if (transitiontrack != 0) transitionClip = getClipItemAt((int) info.endPos.frames(m_document->fps()), m_document->tracksCount() - transitiontrack);
1027         if (transitionClip && transitionClip->startPos() > m_dragItem->startPos()) {
1028             info.startPos = transitionClip->startPos();
1029         } else {
1030             GenTime transitionDuration(65, m_document->fps());
1031             if (m_dragItem->cropDuration() < transitionDuration) info.startPos = m_dragItem->startPos();
1032             else info.startPos = info.endPos - transitionDuration;
1033         }
1034         if (info.endPos == info.startPos) info.startPos = info.endPos - GenTime(65, m_document->fps());
1035         QDomElement transition = MainWindow::transitions.getEffectByTag("luma", "dissolve").cloneNode().toElement();
1036         EffectsList::setParameter(transition, "reverse", "1");
1037
1038         // Check there is no other transition at that place
1039         double startY = info.track * m_tracksHeight + 1 + m_tracksHeight / 2;
1040         QRectF r(info.startPos.frames(m_document->fps()), startY, (info.endPos - info.startPos).frames(m_document->fps()), m_tracksHeight / 2);
1041         QList<QGraphicsItem *> selection = m_scene->items(r);
1042         bool transitionAccepted = true;
1043         for (int i = 0; i < selection.count(); i++) {
1044             if (selection.at(i)->type() == TRANSITIONWIDGET) {
1045                 Transition *tr = static_cast <Transition *>(selection.at(i));
1046                 if (info.endPos - tr->endPos() > GenTime(5, m_document->fps())) {
1047                     if (tr->endPos() > info.startPos) info.startPos = tr->endPos();
1048                 } else transitionAccepted = false;
1049             }
1050         }
1051         if (transitionAccepted) slotAddTransition((ClipItem *) m_dragItem, info, transitiontrack, transition);
1052         else emit displayMessage(i18n("Cannot add transition"), ErrorMessage);
1053
1054     } else if ((m_operationMode == RESIZESTART || m_operationMode == RESIZEEND) && m_selectionGroup) {
1055         resetSelectionGroup(false);
1056         m_dragItem->setSelected(true);
1057     }
1058
1059     m_blockRefresh = false;
1060     //kDebug()<<pos;
1061     QGraphicsView::mousePressEvent(event);
1062 }
1063
1064 void CustomTrackView::resetSelectionGroup(bool selectItems)
1065 {
1066     if (m_selectionGroup) {
1067         // delete selection group
1068         bool snap = KdenliveSettings::snaptopoints();
1069         KdenliveSettings::setSnaptopoints(false);
1070
1071         QList<QGraphicsItem *> children = m_selectionGroup->childItems();
1072         scene()->destroyItemGroup(m_selectionGroup);
1073         for (int i = 0; i < children.count(); i++) {
1074             if (children.at(i)->parentItem() == 0 && (children.at(i)->type() == AVWIDGET || children.at(i)->type() == TRANSITIONWIDGET)) {
1075                 if (!static_cast <AbstractClipItem *>(children.at(i))->isItemLocked()) {
1076                     children.at(i)->setFlag(QGraphicsItem::ItemIsMovable, true);
1077                     children.at(i)->setSelected(selectItems);
1078                 }
1079             } else if (children.at(i)->type() == GROUPWIDGET) {
1080                 children.at(i)->setFlag(QGraphicsItem::ItemIsMovable, true);
1081                 children.at(i)->setSelected(selectItems);
1082             }
1083         }
1084         m_selectionGroup = NULL;
1085         KdenliveSettings::setSnaptopoints(snap);
1086     }
1087 }
1088
1089 void CustomTrackView::groupSelectedItems(bool force, bool createNewGroup)
1090 {
1091     if (m_selectionGroup) {
1092         kDebug() << "///// ERROR, TRYING TO OVERRIDE EXISTING GROUP";
1093         return;
1094     }
1095     QList<QGraphicsItem *> selection = m_scene->selectedItems();
1096     if (selection.isEmpty()) return;
1097     QRectF rectUnion;
1098     // Find top left position of selection
1099     for (int i = 0; i < selection.count(); i++) {
1100         if (selection.at(i)->parentItem() == 0 && (selection.at(i)->type() == AVWIDGET || selection.at(i)->type() == TRANSITIONWIDGET || selection.at(i)->type() == GROUPWIDGET)) {
1101             rectUnion = rectUnion.united(selection.at(i)->sceneBoundingRect());
1102         } else if (selection.at(i)->parentItem()) {
1103             rectUnion = rectUnion.united(selection.at(i)->parentItem()->sceneBoundingRect());
1104         }
1105     }
1106
1107     if (force || selection.count() > 1) {
1108         bool snap = KdenliveSettings::snaptopoints();
1109         KdenliveSettings::setSnaptopoints(false);
1110         if (createNewGroup) {
1111             AbstractGroupItem *newGroup = m_document->clipManager()->createGroup();
1112             newGroup->setPos(rectUnion.left(), rectUnion.top() - 1);
1113             QPointF diff = newGroup->pos();
1114             newGroup->translate(-diff.x(), -diff.y());
1115             //newGroup->translate((int) -rectUnion.left(), (int) -rectUnion.top() + 1);
1116
1117             scene()->addItem(newGroup);
1118
1119             // CHeck if we are trying to include a group in a group
1120             QList <AbstractGroupItem *> groups;
1121             for (int i = 0; i < selection.count(); i++) {
1122                 if (selection.at(i)->type() == GROUPWIDGET && !groups.contains(static_cast<AbstractGroupItem *>(selection.at(i)))) {
1123                     groups.append(static_cast<AbstractGroupItem *>(selection.at(i)));
1124                 } else if (selection.at(i)->parentItem() && !groups.contains(static_cast<AbstractGroupItem *>(selection.at(i)->parentItem()))) groups.append(static_cast<AbstractGroupItem *>(selection.at(i)->parentItem()));
1125             }
1126             if (!groups.isEmpty()) {
1127                 // ungroup previous groups
1128                 while (!groups.isEmpty()) {
1129                     AbstractGroupItem *grp = groups.takeFirst();
1130                     m_document->clipManager()->removeGroup(grp);
1131                     scene()->destroyItemGroup(grp);
1132                 }
1133                 selection = m_scene->selectedItems();
1134             }
1135
1136             for (int i = 0; i < selection.count(); i++) {
1137                 if (selection.at(i)->type() == AVWIDGET || selection.at(i)->type() == TRANSITIONWIDGET) {
1138                     newGroup->addToGroup(selection.at(i));
1139                     selection.at(i)->setFlag(QGraphicsItem::ItemIsMovable, false);
1140                 }
1141             }
1142             KdenliveSettings::setSnaptopoints(snap);
1143         } else {
1144             m_selectionGroup = new AbstractGroupItem(m_document->fps());
1145             m_selectionGroup->setPos(rectUnion.left(), rectUnion.top() - 1);
1146             QPointF diff = m_selectionGroup->pos();
1147             //m_selectionGroup->translate((int) - rectUnion.left(), (int) -rectUnion.top() + 1);
1148             m_selectionGroup->translate(- diff.x(), -diff.y());
1149
1150             scene()->addItem(m_selectionGroup);
1151             for (int i = 0; i < selection.count(); i++) {
1152                 if (selection.at(i)->parentItem() == 0 && (selection.at(i)->type() == AVWIDGET || selection.at(i)->type() == TRANSITIONWIDGET || selection.at(i)->type() == GROUPWIDGET)) {
1153                     m_selectionGroup->addToGroup(selection.at(i));
1154                     selection.at(i)->setFlag(QGraphicsItem::ItemIsMovable, false);
1155                 }
1156             }
1157             KdenliveSettings::setSnaptopoints(snap);
1158             if (m_selectionGroup) {
1159                 m_selectionGroupInfo.startPos = GenTime(m_selectionGroup->scenePos().x(), m_document->fps());
1160                 m_selectionGroupInfo.track = m_selectionGroup->track();
1161             }
1162         }
1163     } else resetSelectionGroup();
1164 }
1165
1166 void CustomTrackView::mouseDoubleClickEvent(QMouseEvent *event)
1167 {
1168     if (m_dragItem && m_dragItem->hasKeyFrames()) {
1169         if (m_moveOpMode == KEYFRAME) {
1170             // user double clicked on a keyframe, open edit dialog
1171             QDialog d(parentWidget());
1172             Ui::KeyFrameDialog_UI view;
1173             view.setupUi(&d);
1174             view.kfr_position->setText(m_document->timecode().getTimecode(GenTime(m_dragItem->selectedKeyFramePos(), m_document->fps()) - m_dragItem->cropStart()));
1175             view.kfr_value->setValue(m_dragItem->selectedKeyFrameValue());
1176             view.kfr_value->setFocus();
1177             if (d.exec() == QDialog::Accepted) {
1178                 int pos = m_document->timecode().getFrameCount(view.kfr_position->text());
1179                 m_dragItem->updateKeyFramePos(GenTime(pos, m_document->fps()) + m_dragItem->cropStart(), (double) view.kfr_value->value() * m_dragItem->keyFrameFactor());
1180                 ClipItem *item = static_cast <ClipItem *>(m_dragItem);
1181                 QString previous = item->keyframes(item->selectedEffectIndex());
1182                 item->updateKeyframeEffect();
1183                 QString next = item->keyframes(item->selectedEffectIndex());
1184                 EditKeyFrameCommand *command = new EditKeyFrameCommand(this, item->track(), item->startPos(), item->selectedEffectIndex(), previous, next, false);
1185                 m_commandStack->push(command);
1186                 updateEffect(m_document->tracksCount() - item->track(), item->startPos(), item->selectedEffect(), item->selectedEffectIndex());
1187                 emit clipItemSelected(item, item->selectedEffectIndex());
1188             }
1189
1190         } else  {
1191             // add keyframe
1192             GenTime keyFramePos = GenTime((int)(mapToScene(event->pos()).x()), m_document->fps()) - m_dragItem->startPos() + m_dragItem->cropStart();
1193             m_dragItem->addKeyFrame(keyFramePos, mapToScene(event->pos()).toPoint().y());
1194             ClipItem * item = static_cast <ClipItem *>(m_dragItem);
1195             QString previous = item->keyframes(item->selectedEffectIndex());
1196             item->updateKeyframeEffect();
1197             QString next = item->keyframes(item->selectedEffectIndex());
1198             EditKeyFrameCommand *command = new EditKeyFrameCommand(this, m_dragItem->track(), m_dragItem->startPos(), item->selectedEffectIndex(), previous, next, false);
1199             m_commandStack->push(command);
1200             updateEffect(m_document->tracksCount() - item->track(), item->startPos(), item->selectedEffect(), item->selectedEffectIndex());
1201             emit clipItemSelected(item, item->selectedEffectIndex());
1202         }
1203     } else if (m_dragItem && !m_dragItem->isItemLocked()) {
1204         ClipDurationDialog d(m_dragItem, m_document->timecode(), this);
1205         GenTime minimum;
1206         GenTime maximum;
1207         if (m_dragItem->type() == TRANSITIONWIDGET) {
1208             getTransitionAvailableSpace(m_dragItem, minimum, maximum);
1209         } else {
1210             getClipAvailableSpace(m_dragItem, minimum, maximum);
1211         }
1212         //kDebug()<<"// GOT MOVE POS: "<<minimum.frames(25)<<" - "<<maximum.frames(25);
1213         d.setMargins(minimum, maximum);
1214         if (d.exec() == QDialog::Accepted) {
1215             if (m_dragItem->type() == TRANSITIONWIDGET) {
1216                 // move & resize transition
1217                 ItemInfo startInfo;
1218                 startInfo.startPos = m_dragItem->startPos();
1219                 startInfo.endPos = m_dragItem->endPos();
1220                 startInfo.track = m_dragItem->track();
1221                 ItemInfo endInfo;
1222                 endInfo.startPos = d.startPos();
1223                 endInfo.endPos = endInfo.startPos + d.duration();
1224                 endInfo.track = m_dragItem->track();
1225                 MoveTransitionCommand *command = new MoveTransitionCommand(this, startInfo, endInfo, true);
1226                 m_commandStack->push(command);
1227             } else {
1228                 // move and resize clip
1229                 QUndoCommand *moveCommand = new QUndoCommand();
1230                 moveCommand->setText(i18n("Edit clip"));
1231                 ItemInfo clipInfo = m_dragItem->info();
1232                 if (d.duration() < m_dragItem->cropDuration() || d.cropStart() != clipInfo.cropStart) {
1233                     // duration was reduced, so process it first
1234                     ItemInfo startInfo = clipInfo;
1235                     clipInfo.endPos = clipInfo.startPos + d.duration();
1236                     clipInfo.cropStart = d.cropStart();
1237                     new ResizeClipCommand(this, startInfo, clipInfo, true, false, moveCommand);
1238                 }
1239                 if (d.startPos() != clipInfo.startPos) {
1240                     ItemInfo startInfo = clipInfo;
1241                     clipInfo.startPos = d.startPos();
1242                     clipInfo.endPos = m_dragItem->endPos() + (clipInfo.startPos - startInfo.startPos);
1243                     new MoveClipCommand(this, startInfo, clipInfo, true, moveCommand);
1244                 }
1245                 if (d.duration() > m_dragItem->cropDuration()) {
1246                     // duration was increased, so process it after move
1247                     ItemInfo startInfo = clipInfo;
1248                     clipInfo.endPos = clipInfo.startPos + d.duration();
1249                     clipInfo.cropStart = d.cropStart();
1250                     new ResizeClipCommand(this, startInfo, clipInfo, true, false, moveCommand);
1251                 }
1252                 m_commandStack->push(moveCommand);
1253             }
1254         }
1255     } else {
1256         QList<QGraphicsItem *> collisionList = items(event->pos());
1257         if (collisionList.count() == 1 && collisionList.at(0)->type() == GUIDEITEM) {
1258             Guide *editGuide = (Guide *) collisionList.at(0);
1259             if (editGuide) slotEditGuide(editGuide->info());
1260         }
1261     }
1262 }
1263
1264
1265 void CustomTrackView::editKeyFrame(const GenTime pos, const int track, const int index, const QString keyframes)
1266 {
1267     ClipItem *clip = getClipItemAt((int)pos.frames(m_document->fps()), track);
1268     if (clip) {
1269         clip->setKeyframes(index, keyframes);
1270         updateEffect(m_document->tracksCount() - clip->track(), clip->startPos(), clip->effectAt(index), index, false);
1271     } else emit displayMessage(i18n("Cannot find clip with keyframe"), ErrorMessage);
1272 }
1273
1274
1275 void CustomTrackView::displayContextMenu(QPoint pos, AbstractClipItem *clip, AbstractGroupItem *group)
1276 {
1277     m_deleteGuide->setEnabled(m_dragGuide != NULL);
1278     m_editGuide->setEnabled(m_dragGuide != NULL);
1279     if (clip == NULL) m_timelineContextMenu->popup(pos);
1280     else if (group != NULL) {
1281         m_pasteEffectsAction->setEnabled(m_copiedItems.count() == 1);
1282         m_ungroupAction->setEnabled(true);
1283         updateClipTypeActions(NULL);
1284         m_timelineContextClipMenu->popup(pos);
1285     } else {
1286         m_ungroupAction->setEnabled(false);
1287         if (clip->type() == AVWIDGET) {
1288             ClipItem *item = static_cast <ClipItem*>(clip);
1289             updateClipTypeActions(item);
1290             m_pasteEffectsAction->setEnabled(m_copiedItems.count() == 1);
1291             m_timelineContextClipMenu->popup(pos);
1292         } else if (clip->type() == TRANSITIONWIDGET) m_timelineContextTransitionMenu->popup(pos);
1293     }
1294 }
1295
1296 void CustomTrackView::activateMonitor()
1297 {
1298     emit activateDocumentMonitor();
1299 }
1300
1301 bool CustomTrackView::insertDropClips(const QMimeData *data, const QPoint pos)
1302 {
1303     if (data->hasFormat("kdenlive/clip")) {
1304         m_clipDrag = true;
1305         resetSelectionGroup();
1306         QStringList list = QString(data->data("kdenlive/clip")).split(';');
1307         DocClipBase *clip = m_document->getBaseClip(list.at(0));
1308         if (clip == NULL) {
1309             kDebug() << " WARNING))))))))) CLIP NOT FOUND : " << list.at(0);
1310             return false;
1311         }
1312         const QPointF framePos = mapToScene(pos);
1313         ItemInfo info;
1314         info.startPos = GenTime();
1315         info.cropStart = GenTime(list.at(1).toInt(), m_document->fps());
1316         info.endPos = GenTime(list.at(2).toInt() - list.at(1).toInt(), m_document->fps());
1317         info.cropDuration = info.endPos - info.startPos;
1318         info.track = 0;
1319
1320         // Check if clip can be inserted at that position
1321         ItemInfo pasteInfo = info;
1322         pasteInfo.startPos = GenTime((int)(framePos.x() + 0.5), m_document->fps());
1323         pasteInfo.endPos = pasteInfo.startPos + info.endPos;
1324         pasteInfo.track = (int)(framePos.y() / m_tracksHeight);
1325         if (!canBePastedTo(pasteInfo, AVWIDGET)) {
1326             return true;
1327         }
1328         m_selectionGroup = new AbstractGroupItem(m_document->fps());
1329         ClipItem *item = new ClipItem(clip, info, m_document->fps(), 1.0, 1);
1330         m_selectionGroup->addToGroup(item);
1331         item->setFlag(QGraphicsItem::ItemIsMovable, false);
1332
1333         QList <GenTime> offsetList;
1334         offsetList.append(info.endPos);
1335         updateSnapPoints(NULL, offsetList);
1336         m_selectionGroup->setPos(framePos);
1337         scene()->addItem(m_selectionGroup);
1338         m_selectionGroup->setZValue(10);
1339         return true;
1340     } else if (data->hasFormat("kdenlive/producerslist")) {
1341         m_clipDrag = true;
1342         QStringList ids = QString(data->data("kdenlive/producerslist")).split(';');
1343         m_scene->clearSelection();
1344         resetSelectionGroup(false);
1345
1346         QList <GenTime> offsetList;
1347         QList <ItemInfo> infoList;
1348         const QPointF framePos = mapToScene(pos);
1349         GenTime start = GenTime((int)(framePos.x() + 0.5), m_document->fps());
1350         int track = (int)(framePos.y() / m_tracksHeight);
1351
1352         // Check if clips can be inserted at that position
1353         for (int i = 0; i < ids.size(); ++i) {
1354             DocClipBase *clip = m_document->getBaseClip(ids.at(i));
1355             if (clip == NULL) {
1356                 kDebug() << " WARNING))))))))) CLIP NOT FOUND : " << ids.at(i);
1357                 return false;
1358             }
1359             ItemInfo info;
1360             info.startPos = start;
1361             info.cropDuration = clip->duration();
1362             info.endPos = info.startPos + info.cropDuration;
1363             info.track = track;
1364             infoList.append(info);
1365             start += clip->duration();
1366         }
1367         if (!canBePastedTo(infoList, AVWIDGET)) {
1368             return true;
1369         }
1370         m_selectionGroup = new AbstractGroupItem(m_document->fps());
1371         start = GenTime();
1372         for (int i = 0; i < ids.size(); ++i) {
1373             DocClipBase *clip = m_document->getBaseClip(ids.at(i));
1374             ItemInfo info;
1375             info.startPos = start;
1376             info.cropDuration = clip->duration();
1377             info.endPos = info.startPos + info.cropDuration;
1378             info.track = 0;
1379             start += info.cropDuration;
1380             offsetList.append(start);
1381             ClipItem *item = new ClipItem(clip, info, m_document->fps(), 1.0, 1, false);
1382             item->setZValue(10);
1383             item->setFlag(QGraphicsItem::ItemIsMovable, false);
1384             m_selectionGroup->addToGroup(item);
1385             m_waitingThumbs.append(item);
1386         }
1387
1388         updateSnapPoints(NULL, offsetList);
1389         m_selectionGroup->setPos(framePos);
1390         scene()->addItem(m_selectionGroup);
1391         m_selectionGroup->setZValue(10);
1392         m_thumbsTimer.start();
1393         return true;
1394
1395     } else {
1396         // the drag is not a clip (may be effect, ...)
1397         m_clipDrag = false;
1398         return false;
1399     }
1400 }
1401
1402
1403
1404 void CustomTrackView::dragEnterEvent(QDragEnterEvent * event)
1405 {
1406     if (insertDropClips(event->mimeData(), event->pos())) {
1407         event->acceptProposedAction();
1408     } else QGraphicsView::dragEnterEvent(event);
1409 }
1410
1411 bool CustomTrackView::itemCollision(AbstractClipItem *item, ItemInfo newPos)
1412 {
1413     QRectF shape = QRectF(newPos.startPos.frames(m_document->fps()), newPos.track * m_tracksHeight + 1, (newPos.endPos - newPos.startPos).frames(m_document->fps()) - 0.02, m_tracksHeight - 1);
1414     QList<QGraphicsItem*> collindingItems = scene()->items(shape, Qt::IntersectsItemShape);
1415     collindingItems.removeAll(item);
1416     if (collindingItems.isEmpty()) return false;
1417     else {
1418         for (int i = 0; i < collindingItems.count(); i++) {
1419             QGraphicsItem *collision = collindingItems.at(i);
1420             if (collision->type() == item->type()) {
1421                 // Collision
1422                 kDebug() << "// COLLISIION DETECTED";
1423                 return true;
1424             }
1425         }
1426         return false;
1427     }
1428 }
1429
1430 void CustomTrackView::slotRefreshEffects(ClipItem *clip)
1431 {
1432     int track = m_document->tracksCount() - clip->track();
1433     GenTime pos = clip->startPos();
1434     if (!m_document->renderer()->mltRemoveEffect(track, pos, "-1", false, false)) {
1435         emit displayMessage(i18n("Problem deleting effect"), ErrorMessage);
1436         return;
1437     }
1438     bool success = true;
1439     for (int i = 0; i < clip->effectsCount(); i++) {
1440         if (!m_document->renderer()->mltAddEffect(track, pos, clip->getEffectArgs(clip->effectAt(i)), false)) success = false;
1441     }
1442     if (!success) emit displayMessage(i18n("Problem adding effect to clip"), ErrorMessage);
1443     m_document->renderer()->doRefresh();
1444 }
1445
1446 void CustomTrackView::addEffect(int track, GenTime pos, QDomElement effect)
1447 {
1448     ClipItem *clip = getClipItemAt((int)pos.frames(m_document->fps()), m_document->tracksCount() - track);
1449     if (clip) {
1450         // Special case: speed effect
1451         if (effect.attribute("id") == "speed") {
1452             if (clip->clipType() != VIDEO && clip->clipType() != AV && clip->clipType() != PLAYLIST) {
1453                 emit displayMessage(i18n("Problem adding effect to clip"), ErrorMessage);
1454                 return;
1455             }
1456             double speed = EffectsList::parameter(effect, "speed").toDouble() / 100.0;
1457             int strobe = EffectsList::parameter(effect, "strobe").toInt();
1458             if (strobe == 0) strobe = 1;
1459             doChangeClipSpeed(clip->info(), clip->speedIndependantInfo(), speed, 1.0, strobe, clip->baseClip()->getId());
1460             EffectsParameterList params = clip->addEffect(effect);
1461             m_document->renderer()->mltAddEffect(track, pos, params);
1462             if (clip->isSelected()) emit clipItemSelected(clip);
1463             return;
1464         }
1465         EffectsParameterList params = clip->addEffect(effect);
1466         if (effect.attribute("disabled") == "1") {
1467             // Effect is disabled, don't add it to MLT playlist
1468             if (clip->isSelected()) emit clipItemSelected(clip);
1469             return;
1470         }
1471         if (!m_document->renderer()->mltAddEffect(track, pos, params))
1472             emit displayMessage(i18n("Problem adding effect to clip"), ErrorMessage);
1473         if (clip->isSelected()) emit clipItemSelected(clip);
1474     } else emit displayMessage(i18n("Cannot find clip to add effect"), ErrorMessage);
1475 }
1476
1477 void CustomTrackView::deleteEffect(int track, GenTime pos, QDomElement effect)
1478 {
1479     QString index = effect.attribute("kdenlive_ix");
1480     // Special case: speed effect
1481     if (effect.attribute("id") == "speed") {
1482         ClipItem *clip = getClipItemAt((int)pos.frames(m_document->fps()), m_document->tracksCount() - track);
1483         if (clip) {
1484             doChangeClipSpeed(clip->info(), clip->speedIndependantInfo(), 1.0, clip->speed(), 1, clip->baseClip()->getId());
1485             clip->deleteEffect(index);
1486             emit clipItemSelected(clip);
1487             m_document->renderer()->mltRemoveEffect(track, pos, index, true);
1488             return;
1489         }
1490     }
1491     if (!m_document->renderer()->mltRemoveEffect(track, pos, index, true) && effect.attribute("disabled") != "1") {
1492         kDebug() << "// ERROR REMOV EFFECT: " << index << ", DISABLE: " << effect.attribute("disabled");
1493         emit displayMessage(i18n("Problem deleting effect"), ErrorMessage);
1494         return;
1495     }
1496     ClipItem *clip = getClipItemAt((int)pos.frames(m_document->fps()), m_document->tracksCount() - track);
1497     if (clip) {
1498         clip->deleteEffect(index);
1499         emit clipItemSelected(clip);
1500     }
1501 }
1502
1503 void CustomTrackView::slotAddGroupEffect(QDomElement effect, AbstractGroupItem *group)
1504 {
1505     QList<QGraphicsItem *> itemList = group->childItems();
1506     QUndoCommand *effectCommand = new QUndoCommand();
1507     QString effectName;
1508     QDomNode namenode = effect.elementsByTagName("name").item(0);
1509     if (!namenode.isNull()) effectName = i18n(namenode.toElement().text().toUtf8().data());
1510     else effectName = i18n("effect");
1511     effectCommand->setText(i18n("Add %1", effectName));
1512     int count = 0;
1513     for (int i = 0; i < itemList.count(); i++) {
1514         if (itemList.at(i)->type() == AVWIDGET) {
1515             ClipItem *item = static_cast <ClipItem *>(itemList.at(i));
1516             if (effect.attribute("type") == "audio") {
1517                 // Don't add audio effects on video clips
1518                 if (item->isVideoOnly() || (item->clipType() != AUDIO && item->clipType() != AV && item->clipType() != PLAYLIST)) continue;
1519             } else if (effect.hasAttribute("type") == false) {
1520                 // Don't add video effect on audio clips
1521                 if (item->isAudioOnly() || item->clipType() == AUDIO) continue;
1522             }
1523
1524             if (effect.attribute("unique", "0") != "0" && item->hasEffect(effect.attribute("tag"), effect.attribute("id")) != -1) {
1525                 emit displayMessage(i18n("Effect already present in clip"), ErrorMessage);
1526                 continue;
1527             }
1528             if (item->isItemLocked()) {
1529                 continue;
1530             }
1531             item->initEffect(effect);
1532             if (effect.attribute("tag") == "ladspa") {
1533                 QString ladpsaFile = m_document->getLadspaFile();
1534                 initEffects::ladspaEffectFile(ladpsaFile, effect.attribute("ladspaid").toInt(), getLadspaParams(effect));
1535                 effect.setAttribute("src", ladpsaFile);
1536             }
1537             new AddEffectCommand(this, m_document->tracksCount() - item->track(), item->startPos(), effect, true, effectCommand);
1538             count++;
1539         }
1540     }
1541     if (count > 0) {
1542         m_commandStack->push(effectCommand);
1543         setDocumentModified();
1544     } else delete effectCommand;
1545 }
1546
1547 void CustomTrackView::slotAddEffect(QDomElement effect, GenTime pos, int track)
1548 {
1549     QList<QGraphicsItem *> itemList;
1550     QUndoCommand *effectCommand = new QUndoCommand();
1551     QString effectName;
1552     QDomNode namenode = effect.elementsByTagName("name").item(0);
1553     if (!namenode.isNull()) effectName = i18n(namenode.toElement().text().toUtf8().data());
1554     else effectName = i18n("effect");
1555     effectCommand->setText(i18n("Add %1", effectName));
1556     int count = 0;
1557     if (track == -1) itemList = scene()->selectedItems();
1558     if (itemList.isEmpty()) {
1559         ClipItem *clip = getClipItemAt((int) pos.frames(m_document->fps()), track);
1560         if (clip) itemList.append(clip);
1561         else emit displayMessage(i18n("Select a clip if you want to apply an effect"), ErrorMessage);
1562     }
1563     kDebug() << "// REQUESTING EFFECT ON CLIP: " << pos.frames(25) << ", TRK: " << track << "SELECTED ITEMS: " << itemList.count();
1564     for (int i = 0; i < itemList.count(); i++) {
1565         if (itemList.at(i)->type() == AVWIDGET) {
1566             ClipItem *item = static_cast <ClipItem *>(itemList.at(i));
1567             if (effect.attribute("type") == "audio") {
1568                 // Don't add audio effects on video clips
1569                 if (item->isVideoOnly() || (item->clipType() != AUDIO && item->clipType() != AV && item->clipType() != PLAYLIST)) {
1570                     emit displayMessage(i18n("Cannot add an audio effect to this clip"), ErrorMessage);
1571                     continue;
1572                 }
1573             } else if (effect.hasAttribute("type") == false) {
1574                 // Don't add video effect on audio clips
1575                 if (item->isAudioOnly() || item->clipType() == AUDIO) {
1576                     emit displayMessage(i18n("Cannot add a video effect to this clip"), ErrorMessage);
1577                     continue;
1578                 }
1579             }
1580             if (item->hasEffect(effect.attribute("tag"), effect.attribute("id")) != -1 && effect.attribute("unique", "0") != "0") {
1581                 emit displayMessage(i18n("Effect already present in clip"), ErrorMessage);
1582                 continue;
1583             }
1584             if (item->isItemLocked()) {
1585                 continue;
1586             }
1587             if (effect.attribute("id") == "freeze" && m_cursorPos > item->startPos().frames(m_document->fps()) && m_cursorPos < item->endPos().frames(m_document->fps())) {
1588                 item->initEffect(effect, m_cursorPos - item->startPos().frames(m_document->fps()));
1589             } else item->initEffect(effect);
1590             if (effect.attribute("tag") == "ladspa") {
1591                 QString ladpsaFile = m_document->getLadspaFile();
1592                 initEffects::ladspaEffectFile(ladpsaFile, effect.attribute("ladspaid").toInt(), getLadspaParams(effect));
1593                 effect.setAttribute("src", ladpsaFile);
1594             }
1595             new AddEffectCommand(this, m_document->tracksCount() - item->track(), item->startPos(), effect, true, effectCommand);
1596             count++;
1597         }
1598     }
1599     if (count > 0) {
1600         m_commandStack->push(effectCommand);
1601         setDocumentModified();
1602     } else delete effectCommand;
1603 }
1604
1605 void CustomTrackView::slotDeleteEffect(ClipItem *clip, QDomElement effect)
1606 {
1607     AddEffectCommand *command = new AddEffectCommand(this, m_document->tracksCount() - clip->track(), clip->startPos(), effect, false);
1608     m_commandStack->push(command);
1609     setDocumentModified();
1610 }
1611
1612 void CustomTrackView::updateEffect(int track, GenTime pos, QDomElement insertedEffect, int ix, bool triggeredByUser)
1613 {
1614     if (insertedEffect.isNull()) {
1615         emit displayMessage(i18n("Problem editing effect"), ErrorMessage);
1616         return;
1617     }
1618     ClipItem *clip = getClipItemAt((int)pos.frames(m_document->fps()), m_document->tracksCount() - track);
1619     QDomElement effect = insertedEffect.cloneNode().toElement();
1620     if (clip) {
1621         // Special case: speed effect
1622         if (effect.attribute("id") == "speed") {
1623             if (effect.attribute("disabled") == "1") doChangeClipSpeed(clip->info(), clip->speedIndependantInfo(), 1.0, clip->speed(), 1, clip->baseClip()->getId());
1624             else {
1625                 double speed = EffectsList::parameter(effect, "speed").toDouble() / 100.0;
1626                 int strobe = EffectsList::parameter(effect, "strobe").toInt();
1627                 if (strobe == 0) strobe = 1;
1628                 doChangeClipSpeed(clip->info(), clip->speedIndependantInfo(), speed, clip->speed(), strobe, clip->baseClip()->getId());
1629             }
1630             clip->setEffectAt(ix, effect);
1631             if (ix == clip->selectedEffectIndex()) {
1632                 clip->setSelectedEffect(ix);
1633                 if (!triggeredByUser) emit clipItemSelected(clip, ix);
1634             }
1635             return;
1636         }
1637
1638         EffectsParameterList effectParams = clip->getEffectArgs(effect);
1639         if (effect.attribute("tag") == "ladspa") {
1640             // Update the ladspa affect file
1641             initEffects::ladspaEffectFile(effect.attribute("src"), effect.attribute("ladspaid").toInt(), getLadspaParams(effect));
1642         }
1643         // check if we are trying to reset a keyframe effect
1644         if (effectParams.hasParam("keyframes") && effectParams.paramValue("keyframes").isEmpty()) {
1645             clip->initEffect(effect);
1646             effectParams = clip->getEffectArgs(effect);
1647         }
1648         if (effectParams.paramValue("disabled") == "1") {
1649             if (m_document->renderer()->mltRemoveEffect(track, pos, effectParams.paramValue("kdenlive_ix"), false)) {
1650                 kDebug() << "//////  DISABLING EFFECT: " << ix << ", CURRENTLA: " << clip->selectedEffectIndex();
1651             } else emit displayMessage(i18n("Problem deleting effect"), ErrorMessage);
1652         } else if (!m_document->renderer()->mltEditEffect(m_document->tracksCount() - clip->track(), clip->startPos(), effectParams))
1653             emit displayMessage(i18n("Problem editing effect"), ErrorMessage);
1654
1655         clip->setEffectAt(ix, effect);
1656         if (ix == clip->selectedEffectIndex()) {
1657             clip->setSelectedEffect(ix);
1658             if (!triggeredByUser) emit clipItemSelected(clip, ix);
1659         }
1660         if (effect.attribute("tag") == "volume" || effect.attribute("tag") == "brightness") {
1661             // A fade effect was modified, update the clip
1662             if (effect.attribute("id") == "fadein" || effect.attribute("id") == "fade_from_black") {
1663                 int pos = effectParams.paramValue("out").toInt() - effectParams.paramValue("in").toInt();
1664                 clip->setFadeIn(pos);
1665             }
1666             if (effect.attribute("id") == "fadeout" || effect.attribute("id") == "fade_to_black") {
1667                 int pos = effectParams.paramValue("out").toInt() - effectParams.paramValue("in").toInt();
1668                 clip->setFadeOut(pos);
1669             }
1670         }
1671     }
1672     setDocumentModified();
1673 }
1674
1675 void CustomTrackView::moveEffect(int track, GenTime pos, int oldPos, int newPos)
1676 {
1677     ClipItem *clip = getClipItemAt((int)pos.frames(m_document->fps()), m_document->tracksCount() - track);
1678     if (clip && !clip->effectAt(newPos - 1).isNull() && !clip->effectAt(oldPos - 1).isNull()) {
1679         QDomElement act = clip->effectAt(newPos - 1);
1680         QDomElement before = clip->effectAt(oldPos - 1);
1681         clip->setEffectAt(oldPos - 1, act);
1682         clip->setEffectAt(newPos - 1, before);
1683         // special case: speed effect, which is a pseudo-effect, not appearing in MLT's effects
1684         if (act.attribute("id") == "speed") {
1685             m_document->renderer()->mltUpdateEffectPosition(track, pos, oldPos, newPos);
1686         } else if (before.attribute("id") == "speed") {
1687             m_document->renderer()->mltUpdateEffectPosition(track, pos, newPos, oldPos);
1688         } else m_document->renderer()->mltMoveEffect(track, pos, oldPos, newPos);
1689         emit clipItemSelected(clip, newPos - 1);
1690         setDocumentModified();
1691     } else emit displayMessage(i18n("Cannot move effect"), ErrorMessage);
1692 }
1693
1694 void CustomTrackView::slotChangeEffectState(ClipItem *clip, int effectPos, bool disable)
1695 {
1696     QDomElement effect = clip->effectAt(effectPos);
1697     QDomElement oldEffect = effect.cloneNode().toElement();
1698
1699     effect.setAttribute("disabled", (int) disable);
1700     EditEffectCommand *command = new EditEffectCommand(this, m_document->tracksCount() - clip->track(), clip->startPos(), oldEffect, effect, effectPos, true);
1701     m_commandStack->push(command);
1702     setDocumentModified();;
1703 }
1704
1705 void CustomTrackView::slotChangeEffectPosition(ClipItem *clip, int currentPos, int newPos)
1706 {
1707     MoveEffectCommand *command = new MoveEffectCommand(this, m_document->tracksCount() - clip->track(), clip->startPos(), currentPos, newPos);
1708     m_commandStack->push(command);
1709     setDocumentModified();
1710 }
1711
1712 void CustomTrackView::slotUpdateClipEffect(ClipItem *clip, QDomElement oldeffect, QDomElement effect, int ix)
1713 {
1714     EditEffectCommand *command = new EditEffectCommand(this, m_document->tracksCount() - clip->track(), clip->startPos(), oldeffect, effect, ix, true);
1715     m_commandStack->push(command);
1716 }
1717
1718 ClipItem *CustomTrackView::cutClip(ItemInfo info, GenTime cutTime, bool cut, bool execute)
1719 {
1720     if (cut) {
1721         // cut clip
1722         ClipItem *item = getClipItemAt((int) info.startPos.frames(m_document->fps()), info.track);
1723         if (!item || cutTime >= item->endPos() || cutTime <= item->startPos()) {
1724             emit displayMessage(i18n("Cannot find clip to cut"), ErrorMessage);
1725             kDebug() << "/////////  ERROR CUTTING CLIP : (" << item->startPos().frames(25) << "-" << item->endPos().frames(25) << "), INFO: (" << info.startPos.frames(25) << "-" << info.endPos.frames(25) << ")" << ", CUT: " << cutTime.frames(25);
1726             m_blockRefresh = false;
1727             return NULL;
1728         }
1729         if (item->parentItem()) {
1730             // Item is part of a group, reset group
1731             resetSelectionGroup();
1732         }
1733         kDebug() << "/////////  CUTTING CLIP : (" << item->startPos().frames(25) << "-" << item->endPos().frames(25) << "), INFO: (" << info.startPos.frames(25) << "-" << info.endPos.frames(25) << ")" << ", CUT: " << cutTime.frames(25);
1734
1735         if (execute) m_document->renderer()->mltCutClip(m_document->tracksCount() - info.track, cutTime);
1736         int cutPos = (int) cutTime.frames(m_document->fps());
1737         ItemInfo newPos;
1738         newPos.startPos = cutTime;
1739         newPos.endPos = info.endPos;
1740         newPos.cropStart = item->info().cropStart + (cutTime - info.startPos);
1741         newPos.track = info.track;
1742         newPos.cropDuration = newPos.endPos - newPos.startPos;
1743
1744         bool snap = KdenliveSettings::snaptopoints();
1745         KdenliveSettings::setSnaptopoints(false);
1746         ClipItem *dup = item->clone(newPos);
1747         // remove unwanted effects (fade in) from 2nd part of cutted clip
1748         int ix = dup->hasEffect(QString(), "fadein");
1749         if (ix != -1) {
1750             QDomElement oldeffect = item->effectAt(ix);
1751             dup->deleteEffect(oldeffect.attribute("kdenlive_ix"));
1752         }
1753         ix = dup->hasEffect(QString(), "fade_from_black");
1754         if (ix != -1) {
1755             QDomElement oldeffect = item->effectAt(ix);
1756             dup->deleteEffect(oldeffect.attribute("kdenlive_ix"));
1757         }
1758         item->resizeEnd(cutPos);
1759         scene()->addItem(dup);
1760         if (item->checkKeyFrames()) slotRefreshEffects(item);
1761         if (dup->checkKeyFrames()) slotRefreshEffects(dup);
1762         item->baseClip()->addReference();
1763         m_document->updateClip(item->baseClip()->getId());
1764         setDocumentModified();
1765         KdenliveSettings::setSnaptopoints(snap);
1766         return dup;
1767         //kDebug() << "/////////  CUTTING CLIP RESULT: (" << item->startPos().frames(25) << "-" << item->endPos().frames(25) << "), DUP: (" << dup->startPos().frames(25) << "-" << dup->endPos().frames(25) << ")" << ", CUT: " << cutTime.frames(25);
1768     } else {
1769         // uncut clip
1770
1771         ClipItem *item = getClipItemAt((int) info.startPos.frames(m_document->fps()), info.track);
1772         ClipItem *dup = getClipItemAt((int) cutTime.frames(m_document->fps()), info.track);
1773
1774         if (!item || !dup || item == dup) {
1775             emit displayMessage(i18n("Cannot find clip to uncut"), ErrorMessage);
1776             m_blockRefresh = false;
1777             return NULL;
1778         }
1779         if (m_document->renderer()->mltRemoveClip(m_document->tracksCount() - info.track, cutTime) == false) {
1780             emit displayMessage(i18n("Error removing clip at %1 on track %2", m_document->timecode().getTimecodeFromFrames(cutTime.frames(m_document->fps())), info.track), ErrorMessage);
1781             return NULL;
1782         }
1783
1784         /*kDebug() << "// UNCUTTING CLIPS: ITEM 1 (" << item->startPos().frames(25) << "x" << item->endPos().frames(25) << ")";
1785         kDebug() << "// UNCUTTING CLIPS: ITEM 2 (" << dup->startPos().frames(25) << "x" << dup->endPos().frames(25) << ")";
1786         kDebug() << "// UNCUTTING CLIPS, INFO (" << info.startPos.frames(25) << "x" << info.endPos.frames(25) << ") , CUT: " << cutTime.frames(25);;*/
1787         //deleteClip(dup->info());
1788
1789         bool snap = KdenliveSettings::snaptopoints();
1790         KdenliveSettings::setSnaptopoints(false);
1791
1792         if (dup->isSelected()) emit clipItemSelected(NULL);
1793         dup->baseClip()->removeReference();
1794         m_document->updateClip(dup->baseClip()->getId());
1795         scene()->removeItem(dup);
1796         delete dup;
1797
1798         ItemInfo clipinfo = item->info();
1799         clipinfo.track = m_document->tracksCount() - clipinfo.track;
1800         bool success = m_document->renderer()->mltResizeClipEnd(clipinfo, info.endPos - info.startPos);
1801         if (success) {
1802             item->resizeEnd((int) info.endPos.frames(m_document->fps()));
1803             setDocumentModified();
1804         } else
1805             emit displayMessage(i18n("Error when resizing clip"), ErrorMessage);
1806         KdenliveSettings::setSnaptopoints(snap);
1807         return item;
1808
1809     }
1810     //QTimer::singleShot(3000, this, SLOT(slotEnableRefresh()));
1811 }
1812
1813 void CustomTrackView::slotEnableRefresh()
1814 {
1815     m_blockRefresh = false;
1816 }
1817
1818 void CustomTrackView::slotAddTransitionToSelectedClips(QDomElement transition)
1819 {
1820     QList<QGraphicsItem *> itemList = scene()->selectedItems();
1821     if (itemList.count() == 1) {
1822         if (itemList.at(0)->type() == AVWIDGET) {
1823             ClipItem *item = (ClipItem *) itemList.at(0);
1824             ItemInfo info;
1825             info.track = item->track();
1826             ClipItem *transitionClip = NULL;
1827             const int transitiontrack = getPreviousVideoTrack(info.track);
1828             GenTime pos = GenTime((int)(mapToScene(m_menuPosition).x()), m_document->fps());
1829             if (pos < item->startPos() + item->cropDuration() / 2) {
1830                 // add transition to clip start
1831                 info.startPos = item->startPos();
1832                 if (transitiontrack != 0) transitionClip = getClipItemAt((int) info.startPos.frames(m_document->fps()), m_document->tracksCount() - transitiontrack);
1833                 if (transitionClip && transitionClip->endPos() < item->endPos()) {
1834                     info.endPos = transitionClip->endPos();
1835                 } else info.endPos = info.startPos + GenTime(65, m_document->fps());
1836                 // Check there is no other transition at that place
1837                 double startY = info.track * m_tracksHeight + 1 + m_tracksHeight / 2;
1838                 QRectF r(info.startPos.frames(m_document->fps()), startY, (info.endPos - info.startPos).frames(m_document->fps()), m_tracksHeight / 2);
1839                 QList<QGraphicsItem *> selection = m_scene->items(r);
1840                 bool transitionAccepted = true;
1841                 for (int i = 0; i < selection.count(); i++) {
1842                     if (selection.at(i)->type() == TRANSITIONWIDGET) {
1843                         Transition *tr = static_cast <Transition *>(selection.at(i));
1844                         if (tr->startPos() - info.startPos > GenTime(5, m_document->fps())) {
1845                             if (tr->startPos() < info.endPos) info.endPos = tr->startPos();
1846                         } else transitionAccepted = false;
1847                     }
1848                 }
1849                 if (transitionAccepted) slotAddTransition(item, info, transitiontrack, transition);
1850                 else emit displayMessage(i18n("Cannot add transition"), ErrorMessage);
1851
1852             } else {
1853                 // add transition to clip  end
1854                 info.endPos = item->endPos();
1855                 if (transitiontrack != 0) transitionClip = getClipItemAt((int) info.endPos.frames(m_document->fps()), m_document->tracksCount() - transitiontrack);
1856                 if (transitionClip && transitionClip->startPos() > item->startPos()) {
1857                     info.startPos = transitionClip->startPos();
1858                 } else info.startPos = info.endPos - GenTime(65, m_document->fps());
1859                 if (transition.attribute("tag") == "luma") EffectsList::setParameter(transition, "reverse", "1");
1860                 else if (transition.attribute("id") == "slide") EffectsList::setParameter(transition, "invert", "1");
1861
1862                 // Check there is no other transition at that place
1863                 double startY = info.track * m_tracksHeight + 1 + m_tracksHeight / 2;
1864                 QRectF r(info.startPos.frames(m_document->fps()), startY, (info.endPos - info.startPos).frames(m_document->fps()), m_tracksHeight / 2);
1865                 QList<QGraphicsItem *> selection = m_scene->items(r);
1866                 bool transitionAccepted = true;
1867                 for (int i = 0; i < selection.count(); i++) {
1868                     if (selection.at(i)->type() == TRANSITIONWIDGET) {
1869                         Transition *tr = static_cast <Transition *>(selection.at(i));
1870                         if (info.endPos - tr->endPos() > GenTime(5, m_document->fps())) {
1871                             if (tr->endPos() > info.startPos) info.startPos = tr->endPos();
1872                         } else transitionAccepted = false;
1873                     }
1874                 }
1875                 if (transitionAccepted) slotAddTransition(item, info, transitiontrack, transition);
1876                 else emit displayMessage(i18n("Cannot add transition"), ErrorMessage);
1877             }
1878         }
1879     } else for (int i = 0; i < itemList.count(); i++) {
1880             if (itemList.at(i)->type() == AVWIDGET) {
1881                 ClipItem *item = (ClipItem *) itemList.at(i);
1882                 ItemInfo info;
1883                 info.startPos = item->startPos();
1884                 info.endPos = info.startPos + GenTime(65, m_document->fps());
1885                 info.track = item->track();
1886
1887                 // Check there is no other transition at that place
1888                 double startY = info.track * m_tracksHeight + 1 + m_tracksHeight / 2;
1889                 QRectF r(info.startPos.frames(m_document->fps()), startY, (info.endPos - info.startPos).frames(m_document->fps()), m_tracksHeight / 2);
1890                 QList<QGraphicsItem *> selection = m_scene->items(r);
1891                 bool transitionAccepted = true;
1892                 for (int i = 0; i < selection.count(); i++) {
1893                     if (selection.at(i)->type() == TRANSITIONWIDGET) {
1894                         Transition *tr = static_cast <Transition *>(selection.at(i));
1895                         if (tr->startPos() - info.startPos > GenTime(5, m_document->fps())) {
1896                             if (tr->startPos() < info.endPos) info.endPos = tr->startPos();
1897                         } else transitionAccepted = false;
1898                     }
1899                 }
1900                 int transitiontrack = getPreviousVideoTrack(info.track);
1901                 if (transitionAccepted) slotAddTransition(item, info, transitiontrack, transition);
1902                 else emit displayMessage(i18n("Cannot add transition"), ErrorMessage);
1903             }
1904         }
1905 }
1906
1907 void CustomTrackView::slotAddTransition(ClipItem* /*clip*/, ItemInfo transitionInfo, int endTrack, QDomElement transition)
1908 {
1909     if (transitionInfo.startPos >= transitionInfo.endPos) {
1910         emit displayMessage(i18n("Invalid transition"), ErrorMessage);
1911         return;
1912     }
1913     AddTransitionCommand* command = new AddTransitionCommand(this, transitionInfo, endTrack, transition, false, true);
1914     m_commandStack->push(command);
1915     setDocumentModified();
1916 }
1917
1918 void CustomTrackView::addTransition(ItemInfo transitionInfo, int endTrack, QDomElement params, bool refresh)
1919 {
1920     Transition *tr = new Transition(transitionInfo, endTrack, m_document->fps(), params, true);
1921     //kDebug() << "---- ADDING transition " << params.attribute("value");
1922     if (m_document->renderer()->mltAddTransition(tr->transitionTag(), endTrack, m_document->tracksCount() - transitionInfo.track, transitionInfo.startPos, transitionInfo.endPos, tr->toXML(), refresh)) {
1923         scene()->addItem(tr);
1924         setDocumentModified();
1925     } else {
1926         emit displayMessage(i18n("Cannot add transition"), ErrorMessage);
1927         delete tr;
1928     }
1929 }
1930
1931 void CustomTrackView::deleteTransition(ItemInfo transitionInfo, int endTrack, QDomElement /*params*/, bool refresh)
1932 {
1933     Transition *item = getTransitionItemAt(transitionInfo.startPos, transitionInfo.track);
1934     if (!item) {
1935         emit displayMessage(i18n("Select clip to delete"), ErrorMessage);
1936         return;
1937     }
1938     m_document->renderer()->mltDeleteTransition(item->transitionTag(), endTrack, m_document->tracksCount() - transitionInfo.track, transitionInfo.startPos, transitionInfo.endPos, item->toXML(), refresh);
1939     if (m_dragItem == item) m_dragItem = NULL;
1940
1941 #if QT_VERSION >= 0x040600
1942     // animate item deletion
1943     item->closeAnimation();
1944 #else
1945     delete item;
1946 #endif
1947     emit transitionItemSelected(NULL);
1948     setDocumentModified();
1949 }
1950
1951 void CustomTrackView::slotTransitionUpdated(Transition *tr, QDomElement old)
1952 {
1953     //kDebug() << "TRANS UPDATE, TRACKS: " << old.attribute("transition_btrack") << ", NEW: " << tr->toXML().attribute("transition_btrack");
1954     EditTransitionCommand *command = new EditTransitionCommand(this, tr->track(), tr->startPos(), old, tr->toXML(), false);
1955     m_commandStack->push(command);
1956     setDocumentModified();
1957 }
1958
1959 void CustomTrackView::updateTransition(int track, GenTime pos, QDomElement oldTransition, QDomElement transition, bool updateTransitionWidget)
1960 {
1961     Transition *item = getTransitionItemAt(pos, track);
1962     if (!item) {
1963         kWarning() << "Unable to find transition at pos :" << pos.frames(m_document->fps()) << ", ON track: " << track;
1964         return;
1965     }
1966     m_document->renderer()->mltUpdateTransition(oldTransition.attribute("tag"), transition.attribute("tag"), transition.attribute("transition_btrack").toInt(), m_document->tracksCount() - transition.attribute("transition_atrack").toInt(), item->startPos(), item->endPos(), transition);
1967     //kDebug() << "ORIGINAL TRACK: "<< oldTransition.attribute("transition_btrack") << ", NEW TRACK: "<<transition.attribute("transition_btrack");
1968     item->setTransitionParameters(transition);
1969     if (updateTransitionWidget) {
1970         ItemInfo info = item->info();
1971         QPoint p;
1972         ClipItem *transitionClip = getClipItemAt(info.startPos, info.track);
1973         if (transitionClip && transitionClip->baseClip()) {
1974             QString size = transitionClip->baseClip()->getProperty("frame_size");
1975             double factor = transitionClip->baseClip()->getProperty("aspect_ratio").toDouble();
1976             p.setX((int)(size.section('x', 0, 0).toInt() * factor + 0.5));
1977             p.setY(size.section('x', 1, 1).toInt());
1978         }
1979         emit transitionItemSelected(item, getPreviousVideoTrack(info.track), p, true);
1980     }
1981     setDocumentModified();
1982 }
1983
1984 void CustomTrackView::dragMoveEvent(QDragMoveEvent * event)
1985 {
1986     if (m_clipDrag) {
1987         const QPointF pos = mapToScene(event->pos());
1988         if (m_selectionGroup) {
1989             m_selectionGroup->setPos(pos);
1990             emit mousePosition((int)(m_selectionGroup->scenePos().x() + 0.5));
1991             event->acceptProposedAction();
1992         } else {
1993             // Drag enter was not possible, try again at mouse position
1994             insertDropClips(event->mimeData(), event->pos());
1995             event->accept();
1996         }
1997     } else {
1998         QGraphicsView::dragMoveEvent(event);
1999     }
2000 }
2001
2002 void CustomTrackView::dragLeaveEvent(QDragLeaveEvent * event)
2003 {
2004     if (m_selectionGroup && m_clipDrag) {
2005         m_thumbsTimer.stop();
2006         m_waitingThumbs.clear();
2007         QList<QGraphicsItem *> items = m_selectionGroup->childItems();
2008         qDeleteAll(items);
2009         scene()->destroyItemGroup(m_selectionGroup);
2010         m_selectionGroup = NULL;
2011     } else QGraphicsView::dragLeaveEvent(event);
2012 }
2013
2014 void CustomTrackView::dropEvent(QDropEvent * event)
2015 {
2016     if (m_selectionGroup && m_clipDrag) {
2017         QList<QGraphicsItem *> items = m_selectionGroup->childItems();
2018         resetSelectionGroup();
2019         m_scene->clearSelection();
2020         bool hasVideoClip = false;
2021         QUndoCommand *addCommand = new QUndoCommand();
2022         addCommand->setText(i18n("Add timeline clip"));
2023
2024         for (int i = 0; i < items.count(); i++) {
2025             ClipItem *item = static_cast <ClipItem *>(items.at(i));
2026             if (!hasVideoClip && (item->clipType() == AV || item->clipType() == VIDEO)) hasVideoClip = true;
2027             if (items.count() == 1) {
2028                 updateClipTypeActions(item);
2029             } else {
2030                 updateClipTypeActions(NULL);
2031             }
2032
2033             //TODO: take care of edit mode for undo
2034             item->baseClip()->addReference();
2035             item->setZValue(item->defaultZValue());
2036             m_document->updateClip(item->baseClip()->getId());
2037             ItemInfo info = item->info();
2038
2039             int tracknumber = m_document->tracksCount() - info.track - 1;
2040             bool isLocked = m_document->trackInfoAt(tracknumber).isLocked;
2041             if (isLocked) item->setItemLocked(true);
2042             ItemInfo clipInfo = info;
2043             clipInfo.track = m_document->tracksCount() - item->track();
2044             if (m_document->renderer()->mltInsertClip(clipInfo, item->xml(), item->baseClip()->producer(item->track()), m_scene->editMode() == OVERWRITEEDIT, m_scene->editMode() == INSERTEDIT) == -1) {
2045                 emit displayMessage(i18n("Cannot insert clip in timeline"), ErrorMessage);
2046             }
2047             adjustTimelineClips(m_scene->editMode(), item, ItemInfo(), addCommand);
2048
2049             new AddTimelineClipCommand(this, item->xml(), item->clipProducer(), item->info(), item->effectList(), m_scene->editMode() == OVERWRITEEDIT, m_scene->editMode() == INSERTEDIT, false, false, addCommand);
2050
2051             if (item->baseClip()->isTransparent() && getTransitionItemAtStart(info.startPos, info.track) == NULL) {
2052                 // add transparency transition
2053                 QDomElement trans = MainWindow::transitions.getEffectByTag("composite", "composite").cloneNode().toElement();
2054                 new AddTransitionCommand(this, info, getPreviousVideoTrack(info.track), trans, false, true, addCommand);
2055             }
2056             item->setSelected(true);
2057         }
2058         m_commandStack->push(addCommand);
2059         setDocumentModified();
2060
2061         /*
2062         // debug info
2063         QRectF rect(0, 1 * m_tracksHeight + m_tracksHeight / 2, sceneRect().width(), 2);
2064         QList<QGraphicsItem *> selection = m_scene->items(rect);
2065         QStringList timelineList;
2066
2067         kDebug()<<"// ITEMS on TRACK: "<<selection.count();
2068         for (int i = 0; i < selection.count(); i++) {
2069                if (selection.at(i)->type() == AVWIDGET) {
2070                    ClipItem *clip = static_cast <ClipItem *>(selection.at(i));
2071                    int start = clip->startPos().frames(m_document->fps());
2072                    int end = clip->endPos().frames(m_document->fps());
2073                    timelineList.append(QString::number(start) + "-" + QString::number(end));
2074             }
2075         }
2076         kDebug() << "// COMPARE:\n" << timelineList << "\n-------------------";
2077         */
2078
2079         m_pasteEffectsAction->setEnabled(m_copiedItems.count() == 1);
2080         if (items.count() > 1) groupSelectedItems(true);
2081         event->setDropAction(Qt::MoveAction);
2082         event->accept();
2083     } else QGraphicsView::dropEvent(event);
2084     setFocus();
2085 }
2086
2087 void CustomTrackView::adjustTimelineClips(EDITMODE mode, ClipItem *item, ItemInfo posinfo, QUndoCommand *command)
2088 {
2089     bool snap = KdenliveSettings::snaptopoints();
2090     KdenliveSettings::setSnaptopoints(false);
2091     if (mode == OVERWRITEEDIT) {
2092         // if we are in overwrite mode, move clips accordingly
2093         ItemInfo info;
2094         if (item == NULL) info = posinfo;
2095         else info = item->info();
2096         QRectF rect(info.startPos.frames(m_document->fps()), info.track * m_tracksHeight + m_tracksHeight / 2, (info.endPos - info.startPos).frames(m_document->fps()) - 1, 5);
2097         QList<QGraphicsItem *> selection = m_scene->items(rect);
2098         if (item) selection.removeAll(item);
2099         for (int i = 0; i < selection.count(); i++) {
2100             if (!selection.at(i)->isEnabled()) continue;
2101             if (selection.at(i)->type() == AVWIDGET) {
2102                 ClipItem *clip = static_cast<ClipItem *>(selection.at(i));
2103                 if (clip->startPos() < info.startPos) {
2104                     if (clip->endPos() > info.endPos) {
2105                         ItemInfo clipInfo = clip->info();
2106                         ItemInfo dupInfo = clipInfo;
2107                         GenTime diff = info.startPos - clipInfo.startPos;
2108                         dupInfo.startPos = info.startPos;
2109                         dupInfo.cropStart += diff;
2110                         dupInfo.cropDuration = clipInfo.endPos - info.startPos;
2111                         ItemInfo newdupInfo = dupInfo;
2112                         GenTime diff2 = info.endPos - info.startPos;
2113                         newdupInfo.startPos = info.endPos;
2114                         newdupInfo.cropStart += diff2;
2115                         newdupInfo.cropDuration = clipInfo.endPos - info.endPos;
2116                         new RazorClipCommand(this, clipInfo, info.startPos, false, command);
2117                         new ResizeClipCommand(this, dupInfo, newdupInfo, false, false, command);
2118                         ClipItem *dup = cutClip(clipInfo, info.startPos, true, false);
2119                         if (dup) dup->resizeStart(info.endPos.frames(m_document->fps()));
2120                     } else {
2121                         ItemInfo newclipInfo = clip->info();
2122                         newclipInfo.endPos = info.startPos;
2123                         new ResizeClipCommand(this, clip->info(), newclipInfo, false, false, command);
2124                         clip->resizeEnd(info.startPos.frames(m_document->fps()));
2125                     }
2126                 } else if (clip->endPos() < info.endPos) {
2127                     new AddTimelineClipCommand(this, clip->xml(), clip->clipProducer(), clip->info(), clip->effectList(), false, false, false, true, command);
2128                     scene()->removeItem(clip);
2129                     delete clip;
2130                     clip = NULL;
2131                 } else {
2132                     ItemInfo newclipInfo = clip->info();
2133                     newclipInfo.startPos = info.endPos;
2134                     new ResizeClipCommand(this, clip->info(), newclipInfo, false, false, command);
2135                     clip->resizeStart(info.endPos.frames(m_document->fps()));
2136                 }
2137             }
2138         }
2139     } else if (mode == INSERTEDIT) {
2140         // if we are in push mode, move clips accordingly
2141         ItemInfo info;
2142         if (item == NULL) info = posinfo;
2143         else info = item->info();
2144         QRectF rect(info.startPos.frames(m_document->fps()), info.track * m_tracksHeight + m_tracksHeight / 2, (info.endPos - info.startPos).frames(m_document->fps()) - 1, 5);
2145         QList<QGraphicsItem *> selection = m_scene->items(rect);
2146         if (item) selection.removeAll(item);
2147         for (int i = 0; i < selection.count(); i++) {
2148             if (selection.at(i)->type() == AVWIDGET) {
2149                 ClipItem *clip = static_cast<ClipItem *>(selection.at(i));
2150                 if (clip->startPos() < info.startPos) {
2151                     if (clip->endPos() > info.startPos) {
2152                         ItemInfo clipInfo = clip->info();
2153                         ItemInfo dupInfo = clipInfo;
2154                         GenTime diff = info.startPos - clipInfo.startPos;
2155                         dupInfo.startPos = info.startPos;
2156                         dupInfo.cropStart += diff;
2157                         dupInfo.cropDuration = clipInfo.endPos - info.startPos;
2158                         new RazorClipCommand(this, clipInfo, info.startPos, false, command);
2159                         ClipItem *dup = cutClip(clipInfo, info.startPos, true, false);
2160                     }
2161                 }
2162                 // TODO: add insertspacecommand
2163             }
2164         }
2165     }
2166
2167     KdenliveSettings::setSnaptopoints(snap);
2168 }
2169
2170
2171 void CustomTrackView::adjustTimelineTransitions(EDITMODE mode, Transition *item, QUndoCommand *command)
2172 {
2173     if (mode == OVERWRITEEDIT) {
2174         // if we are in overwrite or push mode, move clips accordingly
2175         bool snap = KdenliveSettings::snaptopoints();
2176         KdenliveSettings::setSnaptopoints(false);
2177         ItemInfo info = item->info();
2178         QRectF rect(info.startPos.frames(m_document->fps()), info.track * m_tracksHeight + m_tracksHeight, (info.endPos - info.startPos).frames(m_document->fps()) - 1, 5);
2179         QList<QGraphicsItem *> selection = m_scene->items(rect);
2180         selection.removeAll(item);
2181         for (int i = 0; i < selection.count(); i++) {
2182             if (!selection.at(i)->isEnabled()) continue;
2183             if (selection.at(i)->type() == TRANSITIONWIDGET) {
2184                 Transition *tr = static_cast<Transition *>(selection.at(i));
2185                 if (tr->startPos() < info.startPos) {
2186                     ItemInfo firstPos = tr->info();
2187                     ItemInfo newPos = firstPos;
2188                     firstPos.endPos = item->startPos();
2189                     newPos.startPos = item->endPos();
2190                     new MoveTransitionCommand(this, tr->info(), firstPos, true, command);
2191                     if (tr->endPos() > info.endPos) {
2192                         // clone transition
2193                         new AddTransitionCommand(this, newPos, tr->transitionEndTrack(), tr->toXML(), false, true, command);
2194                     }
2195                 } else if (tr->endPos() > info.endPos) {
2196                     // just resize
2197                     ItemInfo firstPos = tr->info();
2198                     firstPos.startPos = item->endPos();
2199                     new MoveTransitionCommand(this, tr->info(), firstPos, true, command);
2200                 } else {
2201                     // remove transition
2202                     new AddTransitionCommand(this, tr->info(), tr->transitionEndTrack(), tr->toXML(), true, true, command);
2203                 }
2204             }
2205         }
2206         KdenliveSettings::setSnaptopoints(snap);
2207     }
2208 }
2209
2210 QStringList CustomTrackView::mimeTypes() const
2211 {
2212     QStringList qstrList;
2213     // list of accepted mime types for drop
2214     qstrList.append("text/plain");
2215     qstrList.append("kdenlive/producerslist");
2216     qstrList.append("kdenlive/clip");
2217     return qstrList;
2218 }
2219
2220 Qt::DropActions CustomTrackView::supportedDropActions() const
2221 {
2222     // returns what actions are supported when dropping
2223     return Qt::MoveAction;
2224 }
2225
2226 void CustomTrackView::setDuration(int duration)
2227 {
2228     int diff = qAbs(duration - sceneRect().width());
2229     if (diff * matrix().m11() > -50) {
2230         if (matrix().m11() < 0.4) setSceneRect(0, 0, (duration + 100 / matrix().m11()), sceneRect().height());
2231         else setSceneRect(0, 0, (duration + 300), sceneRect().height());
2232     }
2233     m_projectDuration = duration;
2234 }
2235
2236 int CustomTrackView::duration() const
2237 {
2238     return m_projectDuration;
2239 }
2240
2241 void CustomTrackView::addTrack(TrackInfo type, int ix)
2242 {
2243     if (ix == -1 || ix == m_document->tracksCount()) {
2244         m_document->insertTrack(ix, type);
2245         m_document->renderer()->mltInsertTrack(1, type.type == VIDEOTRACK);
2246     } else {
2247         m_document->insertTrack(m_document->tracksCount() - ix, type);
2248         // insert track in MLT playlist
2249         m_document->renderer()->mltInsertTrack(m_document->tracksCount() - ix, type.type == VIDEOTRACK);
2250
2251         double startY = ix * m_tracksHeight + 1 + m_tracksHeight / 2;
2252         QRectF r(0, startY, sceneRect().width(), sceneRect().height() - startY);
2253         QList<QGraphicsItem *> selection = m_scene->items(r);
2254         resetSelectionGroup();
2255
2256         m_selectionGroup = new AbstractGroupItem(m_document->fps());
2257         scene()->addItem(m_selectionGroup);
2258         for (int i = 0; i < selection.count(); i++) {
2259             if ((!selection.at(i)->parentItem()) && (selection.at(i)->type() == AVWIDGET || selection.at(i)->type() == TRANSITIONWIDGET || selection.at(i)->type() == GROUPWIDGET)) {
2260                 m_selectionGroup->addToGroup(selection.at(i));
2261                 selection.at(i)->setFlag(QGraphicsItem::ItemIsMovable, false);
2262             }
2263         }
2264         // Move graphic items
2265         m_selectionGroup->translate(0, m_tracksHeight);
2266
2267         // adjust track number
2268         QList<QGraphicsItem *> children = m_selectionGroup->childItems();
2269         for (int i = 0; i < children.count(); i++) {
2270             if (children.at(i)->type() == GROUPWIDGET) {
2271                 AbstractGroupItem *grp = static_cast<AbstractGroupItem*>(children.at(i));
2272                 children << grp->childItems();
2273                 continue;
2274             }
2275             AbstractClipItem *item = static_cast <AbstractClipItem *>(children.at(i));
2276             item->updateItem();
2277             ItemInfo clipinfo = item->info();
2278             if (item->type() == AVWIDGET) {
2279                 ClipItem *clip = static_cast <ClipItem *>(item);
2280                 // We add a move clip command so that we get the correct producer for new track number
2281                 if (clip->clipType() == AV || clip->clipType() == AUDIO) {
2282                     Mlt::Producer *prod;
2283                     if (clip->isAudioOnly()) prod = clip->baseClip()->audioProducer(clipinfo.track);
2284                     else if (clip->isVideoOnly()) prod = clip->baseClip()->videoProducer();
2285                     else prod = clip->baseClip()->producer(clipinfo.track);
2286                     if (m_document->renderer()->mltUpdateClipProducer((int)(m_document->tracksCount() - clipinfo.track), clipinfo.startPos.frames(m_document->fps()), prod) == false) {
2287                         // problem updating clip
2288                         emit displayMessage(i18n("Cannot update clip (time: %1, track: %2)", clipinfo.startPos.frames(m_document->fps()), clipinfo.track), ErrorMessage);
2289                     }
2290                 }
2291             } else if (item->type() == TRANSITIONWIDGET) {
2292                 Transition *tr = static_cast <Transition *>(item);
2293                 int track = tr->transitionEndTrack();
2294                 if (track >= ix) {
2295                     tr->updateTransitionEndTrack(getPreviousVideoTrack(clipinfo.track));
2296                 }
2297             }
2298         }
2299         resetSelectionGroup(false);
2300     }
2301
2302     int maxHeight = m_tracksHeight * m_document->tracksCount();
2303     for (int i = 0; i < m_guides.count(); i++) {
2304         QLineF l = m_guides.at(i)->line();
2305         l.setP2(QPointF(l.x2(), maxHeight));
2306         m_guides.at(i)->setLine(l);
2307     }
2308     m_cursorLine->setLine(m_cursorLine->line().x1(), 0, m_cursorLine->line().x1(), maxHeight);
2309     setSceneRect(0, 0, sceneRect().width(), maxHeight);
2310     viewport()->update();
2311     emit tracksChanged();
2312     //QTimer::singleShot(500, this, SIGNAL(trackHeightChanged()));
2313     //setFixedHeight(50 * m_tracksCount);
2314 }
2315
2316 void CustomTrackView::removeTrack(int ix)
2317 {
2318     // Delete track in MLT playlist
2319     m_document->renderer()->mltDeleteTrack(m_document->tracksCount() - ix);
2320     m_document->deleteTrack(m_document->tracksCount() - ix - 1);
2321
2322     double startY = ix * (m_tracksHeight + 1) + m_tracksHeight / 2;
2323     QRectF r(0, startY, sceneRect().width(), sceneRect().height() - startY);
2324     QList<QGraphicsItem *> selection = m_scene->items(r);
2325
2326     resetSelectionGroup();
2327
2328     m_selectionGroup = new AbstractGroupItem(m_document->fps());
2329     scene()->addItem(m_selectionGroup);
2330     for (int i = 0; i < selection.count(); i++) {
2331         if ((!selection.at(i)->parentItem()) && (selection.at(i)->type() == AVWIDGET || selection.at(i)->type() == TRANSITIONWIDGET || selection.at(i)->type() == GROUPWIDGET)) {
2332             m_selectionGroup->addToGroup(selection.at(i));
2333             selection.at(i)->setFlag(QGraphicsItem::ItemIsMovable, false);
2334         }
2335     }
2336     // Move graphic items
2337     qreal ydiff = 0 - (int) m_tracksHeight;
2338     m_selectionGroup->translate(0, ydiff);
2339
2340     // adjust track number
2341     QList<QGraphicsItem *> children = m_selectionGroup->childItems();
2342     //kDebug() << "// FOUND CLIPS TO MOVE: " << children.count();
2343     for (int i = 0; i < children.count(); i++) {
2344         if (children.at(i)->type() == GROUPWIDGET) {
2345             AbstractGroupItem *grp = static_cast<AbstractGroupItem*>(children.at(i));
2346             children << grp->childItems();
2347             continue;
2348         }
2349         if (children.at(i)->type() == AVWIDGET) {
2350             ClipItem *clip = static_cast <ClipItem *>(children.at(i));
2351             clip->updateItem();
2352             ItemInfo clipinfo = clip->info();
2353             // We add a move clip command so that we get the correct producer for new track number
2354             if (clip->clipType() == AV || clip->clipType() == AUDIO) {
2355                 Mlt::Producer *prod;
2356                 if (clip->isAudioOnly()) prod = clip->baseClip()->audioProducer(clipinfo.track);
2357                 else if (clip->isVideoOnly()) prod = clip->baseClip()->videoProducer();
2358                 else prod = clip->baseClip()->producer(clipinfo.track);
2359                 if (!m_document->renderer()->mltUpdateClipProducer((int)(m_document->tracksCount() - clipinfo.track), clipinfo.startPos.frames(m_document->fps()), prod)) {
2360                     emit displayMessage(i18n("Cannot update clip (time: %1, track: %2)", clipinfo.startPos.frames(m_document->fps()), clipinfo.track), ErrorMessage);
2361                 }
2362             }
2363         } else if (children.at(i)->type() == TRANSITIONWIDGET) {
2364             Transition *tr = static_cast <Transition *>(children.at(i));
2365             tr->updateItem();
2366             int track = tr->transitionEndTrack();
2367             if (track >= ix) {
2368                 ItemInfo clipinfo = tr->info();
2369                 tr->updateTransitionEndTrack(getPreviousVideoTrack(clipinfo.track));
2370             }
2371         }
2372     }
2373     resetSelectionGroup(false);
2374
2375     int maxHeight = m_tracksHeight * m_document->tracksCount();
2376     for (int i = 0; i < m_guides.count(); i++) {
2377         QLineF l = m_guides.at(i)->line();
2378         l.setP2(QPointF(l.x2(), maxHeight));
2379         m_guides.at(i)->setLine(l);
2380     }
2381     m_cursorLine->setLine(m_cursorLine->line().x1(), 0, m_cursorLine->line().x1(), maxHeight);
2382     setSceneRect(0, 0, sceneRect().width(), maxHeight);
2383
2384     m_selectedTrack = qMin(m_selectedTrack, m_document->tracksCount() - 1);
2385     viewport()->update();
2386     emit tracksChanged();
2387     //QTimer::singleShot(500, this, SIGNAL(trackHeightChanged()));
2388 }
2389
2390 void CustomTrackView::changeTrack(int ix, TrackInfo type)
2391 {
2392     int tracknumber = m_document->tracksCount() - ix;
2393     m_document->setTrackType(tracknumber - 1, type);
2394     m_document->renderer()->mltChangeTrackState(tracknumber, m_document->trackInfoAt(tracknumber - 1).isMute, m_document->trackInfoAt(tracknumber - 1).isBlind);
2395     QTimer::singleShot(300, this, SIGNAL(trackHeightChanged()));
2396     viewport()->update();
2397 }
2398
2399
2400 void CustomTrackView::slotSwitchTrackAudio(int ix)
2401 {
2402     /*for (int i = 0; i < m_document->tracksCount(); i++)
2403         kDebug() << "TRK " << i << " STATE: " << m_document->trackInfoAt(i).isMute << m_document->trackInfoAt(i).isBlind;*/
2404     int tracknumber = m_document->tracksCount() - ix - 1;
2405     m_document->switchTrackAudio(tracknumber, !m_document->trackInfoAt(tracknumber).isMute);
2406     kDebug() << "NEXT TRK STATE: " << m_document->trackInfoAt(tracknumber).isMute << m_document->trackInfoAt(tracknumber).isBlind;
2407     m_document->renderer()->mltChangeTrackState(tracknumber + 1, m_document->trackInfoAt(tracknumber).isMute, m_document->trackInfoAt(tracknumber).isBlind);
2408     setDocumentModified();
2409 }
2410
2411 void CustomTrackView::slotSwitchTrackLock(int ix)
2412 {
2413     int tracknumber = m_document->tracksCount() - ix - 1;
2414     LockTrackCommand *command = new LockTrackCommand(this, ix, !m_document->trackInfoAt(tracknumber).isLocked);
2415     m_commandStack->push(command);
2416 }
2417
2418
2419 void CustomTrackView::lockTrack(int ix, bool lock)
2420 {
2421     int tracknumber = m_document->tracksCount() - ix - 1;
2422     m_document->switchTrackLock(tracknumber, lock);
2423     emit doTrackLock(ix, lock);
2424     QList<QGraphicsItem *> selection = m_scene->items(0, ix * m_tracksHeight + m_tracksHeight / 2, sceneRect().width(), m_tracksHeight / 2 - 2);
2425
2426     for (int i = 0; i < selection.count(); i++) {
2427         if (selection.at(i)->type() != AVWIDGET && selection.at(i)->type() != TRANSITIONWIDGET) continue;
2428         if (selection.at(i)->isSelected()) {
2429             if (selection.at(i)->type() == AVWIDGET) emit clipItemSelected(NULL);
2430             else emit transitionItemSelected(NULL);
2431         }
2432         static_cast <AbstractClipItem *>(selection.at(i))->setItemLocked(lock);
2433     }
2434     kDebug() << "NEXT TRK STATE: " << m_document->trackInfoAt(tracknumber).isLocked;
2435     viewport()->update();
2436     setDocumentModified();
2437 }
2438
2439 void CustomTrackView::slotSwitchTrackVideo(int ix)
2440 {
2441     int tracknumber = m_document->tracksCount() - ix;
2442     m_document->switchTrackVideo(tracknumber - 1, !m_document->trackInfoAt(tracknumber - 1).isBlind);
2443     m_document->renderer()->mltChangeTrackState(tracknumber, m_document->trackInfoAt(tracknumber - 1).isMute, m_document->trackInfoAt(tracknumber - 1).isBlind);
2444     setDocumentModified();
2445 }
2446
2447 QList<QGraphicsItem *> CustomTrackView::checkForGroups(const QRectF &rect, bool *ok)
2448 {
2449     // Check there is no group going over several tracks there, or that would result in timeline corruption
2450     QList<QGraphicsItem *> selection = scene()->items(rect);
2451     *ok = true;
2452     int maxHeight = m_tracksHeight * 1.5;
2453     for (int i = 0; i < selection.count(); i++) {
2454         // Check that we don't try to move a group with clips on other tracks
2455         if (selection.at(i)->type() == GROUPWIDGET && (selection.at(i)->boundingRect().height() >= maxHeight)) {
2456             *ok = false;
2457             break;
2458         } else if (selection.at(i)->parentItem() && (selection.at(i)->parentItem()->boundingRect().height() >= maxHeight)) {
2459             *ok = false;
2460             break;
2461         }
2462     }
2463     return selection;
2464 }
2465
2466 void CustomTrackView::slotRemoveSpace()
2467 {
2468     GenTime pos;
2469     int track = 0;
2470     if (m_menuPosition.isNull()) {
2471         pos = GenTime(cursorPos(), m_document->fps());
2472         bool ok;
2473         track = QInputDialog::getInteger(this, i18n("Remove Space"), i18n("Track"), 0, 0, m_document->tracksCount() - 1, 1, &ok);
2474         if (!ok) return;
2475     } else {
2476         pos = GenTime((int)(mapToScene(m_menuPosition).x()), m_document->fps());
2477         track = (int)(mapToScene(m_menuPosition).y() / m_tracksHeight);
2478     }
2479
2480     ClipItem *item = getClipItemAt(pos, track);
2481     if (item) {
2482         emit displayMessage(i18n("You must be in an empty space to remove space (time: %1, track: %2)", m_document->timecode().getTimecodeFromFrames(mapToScene(m_menuPosition).x()), track), ErrorMessage);
2483         return;
2484     }
2485     int length = m_document->renderer()->mltGetSpaceLength(pos, m_document->tracksCount() - track, true);
2486     //kDebug() << "// GOT LENGT; " << length;
2487     if (length <= 0) {
2488         emit displayMessage(i18n("You must be in an empty space to remove space (time: %1, track:%2)", m_document->timecode().getTimecodeFromFrames(mapToScene(m_menuPosition).x()), track), ErrorMessage);
2489         return;
2490     }
2491
2492     // Make sure there is no group in the way
2493     QRectF rect(pos.frames(m_document->fps()), track * m_tracksHeight + m_tracksHeight / 2, sceneRect().width() - pos.frames(m_document->fps()), m_tracksHeight / 2 - 2);
2494
2495     bool isOk;
2496     QList<QGraphicsItem *> items = checkForGroups(rect, &isOk);
2497     if (!isOk) {
2498         // groups found on track, do not allow the move
2499         emit displayMessage(i18n("Cannot remove space in a track with a group"), ErrorMessage);
2500         return;
2501     }
2502
2503     QList<ItemInfo> clipsToMove;
2504     QList<ItemInfo> transitionsToMove;
2505
2506     for (int i = 0; i < items.count(); i++) {
2507         if (items.at(i)->type() == AVWIDGET || items.at(i)->type() == TRANSITIONWIDGET) {
2508             AbstractClipItem *item = static_cast <AbstractClipItem *>(items.at(i));
2509             ItemInfo info = item->info();
2510             if (item->type() == AVWIDGET) {
2511                 clipsToMove.append(info);
2512             } else if (item->type() == TRANSITIONWIDGET) {
2513                 transitionsToMove.append(info);
2514             }
2515         }
2516     }
2517
2518     InsertSpaceCommand *command = new InsertSpaceCommand(this, clipsToMove, transitionsToMove, track, GenTime(-length, m_document->fps()), true);
2519     m_commandStack->push(command);
2520 }
2521
2522 void CustomTrackView::slotInsertSpace()
2523 {
2524     GenTime pos;
2525     int track = 0;
2526     if (m_menuPosition.isNull()) {
2527         pos = GenTime(cursorPos(), m_document->fps());
2528     } else {
2529         pos = GenTime((int)(mapToScene(m_menuPosition).x()), m_document->fps());
2530         track = (int)(mapToScene(m_menuPosition).y() / m_tracksHeight) + 1;
2531     }
2532     SpacerDialog d(GenTime(65, m_document->fps()), m_document->timecode(), track, m_document->tracksCount(), this);
2533     if (d.exec() != QDialog::Accepted) return;
2534     GenTime spaceDuration = d.selectedDuration();
2535     track = d.selectedTrack();
2536
2537     ClipItem *item = getClipItemAt(pos, track);
2538     if (item) pos = item->startPos();
2539
2540     // Make sure there is no group in the way
2541     QRectF rect(pos.frames(m_document->fps()), track * m_tracksHeight + m_tracksHeight / 2, sceneRect().width() - pos.frames(m_document->fps()), m_tracksHeight / 2 - 2);
2542     bool isOk;
2543     QList<QGraphicsItem *> items = checkForGroups(rect, &isOk);
2544     if (!isOk) {
2545         // groups found on track, do not allow the move
2546         emit displayMessage(i18n("Cannot insert space in a track with a group"), ErrorMessage);
2547         return;
2548     }
2549
2550     QList<ItemInfo> clipsToMove;
2551     QList<ItemInfo> transitionsToMove;
2552
2553     for (int i = 0; i < items.count(); i++) {
2554         if (items.at(i)->type() == AVWIDGET || items.at(i)->type() == TRANSITIONWIDGET) {
2555             AbstractClipItem *item = static_cast <AbstractClipItem *>(items.at(i));
2556             ItemInfo info = item->info();
2557             if (item->type() == AVWIDGET) {
2558                 clipsToMove.append(info);
2559             } else if (item->type() == TRANSITIONWIDGET) {
2560                 transitionsToMove.append(info);
2561             }
2562         }
2563     }
2564
2565     InsertSpaceCommand *command = new InsertSpaceCommand(this, clipsToMove, transitionsToMove, track, spaceDuration, true);
2566     m_commandStack->push(command);
2567 }
2568
2569 void CustomTrackView::insertSpace(QList<ItemInfo> clipsToMove, QList<ItemInfo> transToMove, int track, const GenTime duration, const GenTime offset)
2570 {
2571     int diff = duration.frames(m_document->fps());
2572     resetSelectionGroup();
2573     m_selectionGroup = new AbstractGroupItem(m_document->fps());
2574     scene()->addItem(m_selectionGroup);
2575     ClipItem *clip;
2576     Transition *transition;
2577
2578     // Create lists with start pos for each track
2579     QMap <int, int> trackClipStartList;
2580     QMap <int, int> trackTransitionStartList;
2581
2582     for (int i = 1; i < m_document->tracksCount() + 1; i++) {
2583         trackClipStartList[i] = -1;
2584         trackTransitionStartList[i] = -1;
2585     }
2586
2587     if (!clipsToMove.isEmpty()) for (int i = 0; i < clipsToMove.count(); i++) {
2588             clip = getClipItemAtStart(clipsToMove.at(i).startPos + offset, clipsToMove.at(i).track);
2589             if (clip) {
2590                 if (clip->parentItem()) {
2591                     m_selectionGroup->addToGroup(clip->parentItem());
2592                     clip->parentItem()->setFlag(QGraphicsItem::ItemIsMovable, false);
2593                 } else {
2594                     m_selectionGroup->addToGroup(clip);
2595                     clip->setFlag(QGraphicsItem::ItemIsMovable, false);
2596                 }
2597                 if (trackClipStartList.value(m_document->tracksCount() - clipsToMove.at(i).track) == -1 || clipsToMove.at(i).startPos.frames(m_document->fps()) < trackClipStartList.value(m_document->tracksCount() - clipsToMove.at(i).track))
2598                     trackClipStartList[m_document->tracksCount() - clipsToMove.at(i).track] = clipsToMove.at(i).startPos.frames(m_document->fps());
2599             } else emit {
2600                     displayMessage(i18n("Cannot move clip at position %1, track %2", m_document->timecode().getTimecodeFromFrames((clipsToMove.at(i).startPos + offset).frames(m_document->fps())), clipsToMove.at(i).track), ErrorMessage);
2601                 }
2602             }
2603     if (!transToMove.isEmpty()) for (int i = 0; i < transToMove.count(); i++) {
2604             transition = getTransitionItemAtStart(transToMove.at(i).startPos + offset, transToMove.at(i).track);
2605             if (transition) {
2606                 if (transition->parentItem()) {
2607                     m_selectionGroup->addToGroup(transition->parentItem());
2608                     transition->parentItem()->setFlag(QGraphicsItem::ItemIsMovable, false);
2609                 } else {
2610                     m_selectionGroup->addToGroup(transition);
2611                     transition->setFlag(QGraphicsItem::ItemIsMovable, false);
2612                 }
2613                 if (trackTransitionStartList.value(m_document->tracksCount() - transToMove.at(i).track) == -1 || transToMove.at(i).startPos.frames(m_document->fps()) < trackTransitionStartList.value(m_document->tracksCount() - transToMove.at(i).track))
2614                     trackTransitionStartList[m_document->tracksCount() - transToMove.at(i).track] = transToMove.at(i).startPos.frames(m_document->fps());
2615             } else emit displayMessage(i18n("Cannot move transition at position %1, track %2", m_document->timecode().getTimecodeFromFrames(transToMove.at(i).startPos.frames(m_document->fps())), transToMove.at(i).track), ErrorMessage);
2616         }
2617     m_selectionGroup->translate(diff, 0);
2618
2619     // update items coordinates
2620     QList<QGraphicsItem *> itemList = m_selectionGroup->childItems();
2621
2622     for (int i = 0; i < itemList.count(); i++) {
2623         if (itemList.at(i)->type() == AVWIDGET || itemList.at(i)->type() == TRANSITIONWIDGET) {
2624             static_cast < AbstractClipItem *>(itemList.at(i))->updateItem();
2625         } else if (itemList.at(i)->type() == GROUPWIDGET) {
2626             QList<QGraphicsItem *> children = itemList.at(i)->childItems();
2627             for (int j = 0; j < children.count(); j++) {
2628                 AbstractClipItem * clp = static_cast < AbstractClipItem *>(children.at(j));
2629                 clp->updateItem();
2630             }
2631         }
2632     }
2633     resetSelectionGroup(false);
2634     if (track != -1) track = m_document->tracksCount() - track;
2635     m_document->renderer()->mltInsertSpace(trackClipStartList, trackTransitionStartList, track, duration, offset);
2636 }
2637
2638 void CustomTrackView::deleteClip(const QString &clipId)
2639 {
2640     resetSelectionGroup();
2641     QList<QGraphicsItem *> itemList = items();
2642     QUndoCommand *deleteCommand = new QUndoCommand();
2643     int count = 0;
2644     for (int i = 0; i < itemList.count(); i++) {
2645         if (itemList.at(i)->type() == AVWIDGET) {
2646             ClipItem *item = (ClipItem *)itemList.at(i);
2647             if (item->clipProducer() == clipId) {
2648                 count++;
2649                 if (item->parentItem()) {
2650                     // Clip is in a group, destroy the group
2651                     new GroupClipsCommand(this, QList<ItemInfo>() << item->info(), QList<ItemInfo>(), false, deleteCommand);
2652                 }
2653                 new AddTimelineClipCommand(this, item->xml(), item->clipProducer(), item->info(), item->effectList(), false, false, true, true, deleteCommand);
2654             }
2655         }
2656     }
2657     deleteCommand->setText(i18np("Delete timeline clip", "Delete timeline clips", count));
2658     if (count == 0) delete deleteCommand;
2659     else m_commandStack->push(deleteCommand);
2660 }
2661
2662 void CustomTrackView::setCursorPos(int pos, bool seek)
2663 {
2664     if (pos == m_cursorPos) return;
2665     emit cursorMoved((int)(m_cursorPos), (int)(pos));
2666     m_cursorPos = pos;
2667     if (seek) m_document->renderer()->seek(GenTime(m_cursorPos, m_document->fps()));
2668     else if (m_autoScroll) checkScrolling();
2669     m_cursorLine->setPos(m_cursorPos, 0);
2670 }
2671
2672 void CustomTrackView::updateCursorPos()
2673 {
2674     m_cursorLine->setPos(m_cursorPos, 0);
2675 }
2676
2677 int CustomTrackView::cursorPos()
2678 {
2679     return (int)(m_cursorPos);
2680 }
2681
2682 void CustomTrackView::moveCursorPos(int delta)
2683 {
2684     if (m_cursorPos + delta < 0) delta = 0 - m_cursorPos;
2685     emit cursorMoved((int)(m_cursorPos), (int)((m_cursorPos + delta)));
2686     m_cursorPos += delta;
2687     m_cursorLine->setPos(m_cursorPos, 0);
2688     m_document->renderer()->seek(GenTime(m_cursorPos, m_document->fps()));
2689 }
2690
2691 void CustomTrackView::initCursorPos(int pos)
2692 {
2693     emit cursorMoved((int)(m_cursorPos), (int)(pos));
2694     m_cursorPos = pos;
2695     m_cursorLine->setPos(pos, 0);
2696     checkScrolling();
2697 }
2698
2699 void CustomTrackView::checkScrolling()
2700 {
2701     ensureVisible(m_cursorPos, verticalScrollBar()->value() + 10, 2, 2, 50, 0);
2702 }
2703
2704 void CustomTrackView::mouseReleaseEvent(QMouseEvent * event)
2705 {
2706     if (m_moveOpMode == SEEK) m_moveOpMode = NONE;
2707     QGraphicsView::mouseReleaseEvent(event);
2708     setViewportUpdateMode(QGraphicsView::MinimalViewportUpdate);
2709 #if QT_VERSION >= 0x040600
2710     if (m_dragItem) m_dragItem->setGraphicsEffect(NULL);
2711 #endif
2712     if (m_scrollTimer.isActive()) m_scrollTimer.stop();
2713     if (event->button() == Qt::MidButton) {
2714         return;
2715     }
2716     setDragMode(QGraphicsView::NoDrag);
2717     if (m_operationMode == MOVEGUIDE) {
2718         setCursor(Qt::ArrowCursor);
2719         m_operationMode = NONE;
2720         m_dragGuide->setFlag(QGraphicsItem::ItemIsMovable, false);
2721         GenTime newPos = GenTime(m_dragGuide->pos().x(), m_document->fps());
2722         if (newPos != m_dragGuide->position()) {
2723             EditGuideCommand *command = new EditGuideCommand(this, m_dragGuide->position(), m_dragGuide->label(), newPos, m_dragGuide->label(), false);
2724             m_commandStack->push(command);
2725             m_dragGuide->updateGuide(GenTime(m_dragGuide->pos().x(), m_document->fps()));
2726             qSort(m_guides.begin(), m_guides.end(), sortGuidesList);
2727             m_document->syncGuides(m_guides);
2728         }
2729         m_dragGuide = NULL;
2730         m_dragItem = NULL;
2731         return;
2732     } else if (m_operationMode == SPACER && m_selectionGroup) {
2733         int track;
2734         if (event->modifiers() != Qt::ControlModifier) {
2735             // We are moving all tracks
2736             track = -1;
2737         } else track = (int)(mapToScene(m_clickEvent).y() / m_tracksHeight);
2738         GenTime timeOffset = GenTime((int)(m_selectionGroup->scenePos().x()), m_document->fps()) - m_selectionGroupInfo.startPos;
2739
2740         if (timeOffset != GenTime()) {
2741             QList<QGraphicsItem *> items = m_selectionGroup->childItems();
2742
2743             QList<ItemInfo> clipsToMove;
2744             QList<ItemInfo> transitionsToMove;
2745
2746             // Create lists with start pos for each track
2747             QMap <int, int> trackClipStartList;
2748             QMap <int, int> trackTransitionStartList;
2749
2750             for (int i = 1; i < m_document->tracksCount() + 1; i++) {
2751                 trackClipStartList[i] = -1;
2752                 trackTransitionStartList[i] = -1;
2753             }
2754
2755             for (int i = 0; i < items.count(); i++) {
2756                 if (items.at(i)->type() == GROUPWIDGET)
2757                     items += items.at(i)->childItems();
2758             }
2759
2760             for (int i = 0; i < items.count(); i++) {
2761                 if (items.at(i)->type() == AVWIDGET) {
2762                     AbstractClipItem *item = static_cast <AbstractClipItem *>(items.at(i));
2763                     ItemInfo info = item->info();
2764                     clipsToMove.append(info);
2765                     item->updateItem();
2766                     if (trackClipStartList.value(m_document->tracksCount() - info.track) == -1 || info.startPos.frames(m_document->fps()) < trackClipStartList.value(m_document->tracksCount() - info.track))
2767                         trackClipStartList[m_document->tracksCount() - info.track] = info.startPos.frames(m_document->fps());
2768                 } else if (items.at(i)->type() == TRANSITIONWIDGET) {
2769                     AbstractClipItem *item = static_cast <AbstractClipItem *>(items.at(i));
2770                     ItemInfo info = item->info();
2771                     transitionsToMove.append(info);
2772                     item->updateItem();
2773                     if (trackTransitionStartList.value(m_document->tracksCount() - info.track) == -1 || info.startPos.frames(m_document->fps()) < trackTransitionStartList.value(m_document->tracksCount() - info.track))
2774                         trackTransitionStartList[m_document->tracksCount() - info.track] = info.startPos.frames(m_document->fps());
2775                 }
2776             }
2777
2778             InsertSpaceCommand *command = new InsertSpaceCommand(this, clipsToMove, transitionsToMove, track, timeOffset, false);
2779             m_commandStack->push(command);
2780             if (track != -1) track = m_document->tracksCount() - track;
2781             kDebug() << "SPACER TRACK:" << track;
2782             m_document->renderer()->mltInsertSpace(trackClipStartList, trackTransitionStartList, track, timeOffset, GenTime());
2783         }
2784         resetSelectionGroup(false);
2785         m_operationMode = NONE;
2786     } else if (m_operationMode == RUBBERSELECTION) {
2787         //kDebug() << "// END RUBBER SELECT";
2788         resetSelectionGroup();
2789         groupSelectedItems();
2790         m_operationMode = NONE;
2791     }
2792
2793     if (m_dragItem == NULL && m_selectionGroup == NULL) {
2794         emit transitionItemSelected(NULL);
2795         return;
2796     }
2797     ItemInfo info;
2798     if (m_dragItem) info = m_dragItem->info();
2799
2800     if (m_operationMode == MOVE) {
2801         setCursor(Qt::OpenHandCursor);
2802         if (m_dragItem) m_dragItem->setZValue(m_dragItem->defaultZValue());
2803         if (m_selectionGroup) m_selectionGroup->setZValue(1);
2804         if (m_dragItem->parentItem() == 0) {
2805             // we are moving one clip, easy
2806             if (m_dragItem->type() == AVWIDGET && (m_dragItemInfo.startPos != info.startPos || m_dragItemInfo.track != info.track)) {
2807                 ClipItem *item = static_cast <ClipItem *>(m_dragItem);
2808                 Mlt::Producer *prod;
2809                 if (item->isAudioOnly()) prod = item->baseClip()->audioProducer(m_dragItemInfo.track);
2810                 else if (item->isVideoOnly()) prod = item->baseClip()->videoProducer();
2811                 else prod = item->baseClip()->producer(m_dragItemInfo.track);
2812                 bool success = m_document->renderer()->mltMoveClip((int)(m_document->tracksCount() - m_dragItemInfo.track), (int)(m_document->tracksCount() - m_dragItem->track()), (int) m_dragItemInfo.startPos.frames(m_document->fps()), (int)(m_dragItem->startPos().frames(m_document->fps())), prod, m_scene->editMode() == OVERWRITEEDIT, m_scene->editMode() == INSERTEDIT);
2813
2814                 if (success) {
2815                     QUndoCommand *moveCommand = new QUndoCommand();
2816                     moveCommand->setText(i18n("Move clip"));
2817                     adjustTimelineClips(m_scene->editMode(), item, ItemInfo(), moveCommand);
2818
2819                     int tracknumber = m_document->tracksCount() - item->track() - 1;
2820                     bool isLocked = m_document->trackInfoAt(tracknumber).isLocked;
2821                     if (isLocked) item->setItemLocked(true);
2822                     new MoveClipCommand(this, m_dragItemInfo, info, false, moveCommand);
2823                     // Also move automatic transitions (on lower track)
2824                     Transition *startTransition = getTransitionItemAtStart(m_dragItemInfo.startPos, m_dragItemInfo.track);
2825                     ItemInfo startTrInfo;
2826                     ItemInfo newStartTrInfo;
2827                     bool moveStartTrans = false;
2828                     bool moveEndTrans = false;
2829                     if (startTransition && startTransition->isAutomatic()) {
2830                         startTrInfo = startTransition->info();
2831                         newStartTrInfo = startTrInfo;
2832                         newStartTrInfo.track = info.track;
2833                         newStartTrInfo.startPos = info.startPos;
2834                         if (m_dragItemInfo.track == info.track && !item->baseClip()->isTransparent() && getClipItemAtEnd(newStartTrInfo.endPos, m_document->tracksCount() - startTransition->transitionEndTrack())) {
2835                             // transition end should stay the same
2836                         } else {
2837                             // transition end should be adjusted to clip
2838                             newStartTrInfo.endPos = newStartTrInfo.endPos + (newStartTrInfo.startPos - startTrInfo.startPos);
2839                         }
2840                         if (newStartTrInfo.startPos < newStartTrInfo.endPos) moveStartTrans = true;
2841                     }
2842                     if (startTransition == NULL || startTransition->endPos() < m_dragItemInfo.endPos) {
2843                         // Check if there is a transition at clip end
2844                         Transition *tr = getTransitionItemAtEnd(m_dragItemInfo.endPos, m_dragItemInfo.track);
2845                         if (tr && tr->isAutomatic()) {
2846                             ItemInfo trInfo = tr->info();
2847                             ItemInfo newTrInfo = trInfo;
2848                             newTrInfo.track = info.track;
2849                             newTrInfo.endPos = m_dragItem->endPos();
2850                             if (m_dragItemInfo.track == info.track && !item->baseClip()->isTransparent() && getClipItemAtStart(trInfo.startPos, m_document->tracksCount() - tr->transitionEndTrack())) {
2851                                 // transition start should stay the same
2852                             } else {
2853                                 // transition start should be moved
2854                                 newTrInfo.startPos = newTrInfo.startPos + (newTrInfo.endPos - trInfo.endPos);
2855                             }
2856                             if (newTrInfo.startPos < newTrInfo.endPos) {
2857                                 moveEndTrans = true;
2858                                 if (moveStartTrans) {
2859                                     // we have to move both transitions, remove the start one so that there is no collision
2860                                     new AddTransitionCommand(this, startTrInfo, startTransition->transitionEndTrack(), startTransition->toXML(), true, true, moveCommand);
2861                                 }
2862                                 adjustTimelineTransitions(m_scene->editMode(), tr, moveCommand);
2863                                 new MoveTransitionCommand(this, trInfo, newTrInfo, true, moveCommand);
2864                                 if (moveStartTrans) {
2865                                     // re-add transition in correct place
2866                                     int transTrack = startTransition->transitionEndTrack();
2867                                     if (m_dragItemInfo.track != info.track && !startTransition->forcedTrack()) {
2868                                         transTrack = getPreviousVideoTrack(info.track);
2869                                     }
2870                                     adjustTimelineTransitions(m_scene->editMode(), startTransition, moveCommand);
2871                                     new AddTransitionCommand(this, newStartTrInfo, transTrack, startTransition->toXML(), false, true, moveCommand);
2872                                 }
2873                             }
2874                         }
2875                     }
2876
2877                     if (moveStartTrans && !moveEndTrans) {
2878                         adjustTimelineTransitions(m_scene->editMode(), startTransition, moveCommand);
2879                         new MoveTransitionCommand(this, startTrInfo, newStartTrInfo, true, moveCommand);
2880                     }
2881
2882                     // Also move automatic transitions (on upper track)
2883                     Transition *tr = getTransitionItemAtStart(m_dragItemInfo.startPos, m_dragItemInfo.track - 1);
2884                     if (m_dragItemInfo.track == info.track && tr && tr->isAutomatic() && (m_document->tracksCount() - tr->transitionEndTrack()) == m_dragItemInfo.track) {
2885                         ItemInfo trInfo = tr->info();
2886                         ItemInfo newTrInfo = trInfo;
2887                         newTrInfo.startPos = m_dragItem->startPos();
2888                         ClipItem * upperClip = getClipItemAt(m_dragItemInfo.startPos, m_dragItemInfo.track - 1);
2889                         if (!upperClip || !upperClip->baseClip()->isTransparent()) {
2890                             if (!getClipItemAtEnd(newTrInfo.endPos, tr->track())) {
2891                                 // transition end should be adjusted to clip on upper track
2892                                 newTrInfo.endPos = newTrInfo.endPos + (newTrInfo.startPos - trInfo.startPos);
2893                             }
2894                             if (newTrInfo.startPos < newTrInfo.endPos) {
2895                                 adjustTimelineTransitions(m_scene->editMode(), tr, moveCommand);
2896                                 new MoveTransitionCommand(this, trInfo, newTrInfo, true, moveCommand);
2897                             }
2898                         }
2899                     }
2900                     if (m_dragItemInfo.track == info.track && (tr == NULL || tr->endPos() < m_dragItemInfo.endPos)) {
2901                         // Check if there is a transition at clip end
2902                         tr = getTransitionItemAtEnd(m_dragItemInfo.endPos, m_dragItemInfo.track - 1);
2903                         if (tr && tr->isAutomatic() && (m_document->tracksCount() - tr->transitionEndTrack()) == m_dragItemInfo.track) {
2904                             ItemInfo trInfo = tr->info();
2905                             ItemInfo newTrInfo = trInfo;
2906                             newTrInfo.endPos = m_dragItem->endPos();
2907                             kDebug() << "CLIP ENDS AT: " << newTrInfo.endPos.frames(25);
2908                             kDebug() << "CLIP STARTS AT: " << newTrInfo.startPos.frames(25);
2909                             ClipItem * upperClip = getClipItemAt(m_dragItemInfo.startPos, m_dragItemInfo.track - 1);
2910                             if (!upperClip || !upperClip->baseClip()->isTransparent()) {
2911                                 if (!getClipItemAtStart(trInfo.startPos, tr->track())) {
2912                                     // transition start should be moved
2913                                     newTrInfo.startPos = newTrInfo.startPos + (newTrInfo.endPos - trInfo.endPos);
2914                                 }
2915                                 if (newTrInfo.startPos < newTrInfo.endPos) {
2916                                     adjustTimelineTransitions(m_scene->editMode(), tr, moveCommand);
2917                                     new MoveTransitionCommand(this, trInfo, newTrInfo, true, moveCommand);
2918                                 }
2919                             }
2920                         }
2921                     }
2922                     m_commandStack->push(moveCommand);
2923                     //checkTrackSequence(m_dragItem->track());
2924                 } else {
2925                     // undo last move and emit error message
2926                     bool snap = KdenliveSettings::snaptopoints();
2927                     KdenliveSettings::setSnaptopoints(false);
2928                     item->setPos((int) m_dragItemInfo.startPos.frames(m_document->fps()), (int)(m_dragItemInfo.track * m_tracksHeight + 1));
2929                     KdenliveSettings::setSnaptopoints(snap);
2930                     emit displayMessage(i18n("Cannot move clip to position %1", m_document->timecode().getTimecodeFromFrames(m_dragItemInfo.startPos.frames(m_document->fps()))), ErrorMessage);
2931                 }
2932                 setDocumentModified();
2933             }
2934             if (m_dragItem->type() == TRANSITIONWIDGET && (m_dragItemInfo.startPos != info.startPos || m_dragItemInfo.track != info.track)) {
2935                 Transition *transition = static_cast <Transition *>(m_dragItem);
2936                 transition->updateTransitionEndTrack(getPreviousVideoTrack(m_dragItem->track()));
2937                 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)) {
2938                     // Moving transition failed, revert to previous position
2939                     emit displayMessage(i18n("Cannot move transition"), ErrorMessage);
2940                     transition->setPos((int) m_dragItemInfo.startPos.frames(m_document->fps()), (m_dragItemInfo.track) * m_tracksHeight + 1);
2941                 } else {
2942                     QUndoCommand *moveCommand = new QUndoCommand();
2943                     moveCommand->setText(i18n("Move transition"));
2944                     adjustTimelineTransitions(m_scene->editMode(), transition, moveCommand);
2945                     new MoveTransitionCommand(this, m_dragItemInfo, info, false, moveCommand);
2946                     m_commandStack->push(moveCommand);
2947                 }
2948             }
2949         } else {
2950             // Moving several clips. We need to delete them and readd them to new position,
2951             // or they might overlap each other during the move
2952             QGraphicsItemGroup *group = static_cast <QGraphicsItemGroup *>(m_dragItem->parentItem());
2953             QList<QGraphicsItem *> items = group->childItems();
2954
2955             QList<ItemInfo> clipsToMove;
2956             QList<ItemInfo> transitionsToMove;
2957
2958             GenTime timeOffset = GenTime(m_dragItem->scenePos().x(), m_document->fps()) - m_dragItemInfo.startPos;
2959             const int trackOffset = (int)(m_dragItem->scenePos().y() / m_tracksHeight) - m_dragItemInfo.track;
2960             //kDebug() << "// MOVED SEVERAL CLIPS" << timeOffset.frames(25);
2961             QUndoCommand *moveGroup = new QUndoCommand();
2962             moveGroup->setText(i18n("Move group"));
2963             if (timeOffset != GenTime() || trackOffset != 0) {
2964                 // remove items in MLT playlist
2965
2966                 // Expand groups
2967                 int max = items.count();
2968                 for (int i = 0; i < max; i++) {
2969                     if (items.at(i)->type() == GROUPWIDGET) {
2970                         items += items.at(i)->childItems();
2971                     }
2972                 }
2973                 m_document->renderer()->blockSignals(true);
2974                 for (int i = 0; i < items.count(); i++) {
2975                     if (items.at(i)->type() != AVWIDGET && items.at(i)->type() != TRANSITIONWIDGET) continue;
2976                     AbstractClipItem *item = static_cast <AbstractClipItem *>(items.at(i));
2977                     ItemInfo info = item->info();
2978                     if (item->type() == AVWIDGET) {
2979                         if (m_document->renderer()->mltRemoveClip(m_document->tracksCount() - info.track, info.startPos) == false) {
2980                             // error, clip cannot be removed from playlist
2981                             emit displayMessage(i18n("Error removing clip at %1 on track %2", m_document->timecode().getTimecodeFromFrames(info.startPos.frames(m_document->fps())), info.track), ErrorMessage);
2982                         } else {
2983                             clipsToMove.append(info);
2984                         }
2985                     } else {
2986                         transitionsToMove.append(info);
2987                         Transition *tr = static_cast <Transition*>(item);
2988                         m_document->renderer()->mltDeleteTransition(tr->transitionTag(), tr->transitionEndTrack(), m_document->tracksCount() - info.track, info.startPos, info.endPos, tr->toXML());
2989                     }
2990                 }
2991                 m_document->renderer()->blockSignals(false);
2992                 for (int i = 0; i < items.count(); i++) {
2993                     // re-add items in correct place
2994                     if (items.at(i)->type() != AVWIDGET && items.at(i)->type() != TRANSITIONWIDGET) continue;
2995                     AbstractClipItem *item = static_cast <AbstractClipItem *>(items.at(i));
2996                     item->updateItem();
2997                     ItemInfo info = item->info();
2998                     int tracknumber = m_document->tracksCount() - info.track - 1;
2999                     bool isLocked = m_document->trackInfoAt(tracknumber).isLocked;
3000                     if (isLocked) {
3001                         group->removeFromGroup(item);
3002                         item->setItemLocked(true);
3003                     }
3004
3005                     if (item->type() == AVWIDGET) {
3006                         ClipItem *clip = static_cast <ClipItem*>(item);
3007                         info.track = m_document->tracksCount() - info.track;
3008                         Mlt::Producer *prod;
3009                         adjustTimelineClips(m_scene->editMode(), clip, ItemInfo(), moveGroup);
3010                         if (clip->isAudioOnly()) prod = clip->baseClip()->audioProducer(info.track);
3011                         else if (clip->isVideoOnly()) prod = clip->baseClip()->videoProducer();
3012                         else prod = clip->baseClip()->producer(info.track);
3013                         m_document->renderer()->mltInsertClip(info, clip->xml(), prod, m_scene->editMode() == OVERWRITEEDIT, m_scene->editMode() == INSERTEDIT);
3014                         for (int i = 0; i < clip->effectsCount(); i++) {
3015                             m_document->renderer()->mltAddEffect(info.track, info.startPos, clip->getEffectArgs(clip->effectAt(i)), false);
3016                         }
3017                     } else {
3018                         Transition *tr = static_cast <Transition*>(item);
3019                         int newTrack = tr->transitionEndTrack();
3020                         if (!tr->forcedTrack()) {
3021                             newTrack = getPreviousVideoTrack(info.track);
3022                         }
3023                         tr->updateTransitionEndTrack(newTrack);
3024                         adjustTimelineTransitions(m_scene->editMode(), tr, moveGroup);
3025                         m_document->renderer()->mltAddTransition(tr->transitionTag(), newTrack, m_document->tracksCount() - info.track, info.startPos, info.endPos, tr->toXML());
3026                     }
3027                 }
3028
3029                 new MoveGroupCommand(this, clipsToMove, transitionsToMove, timeOffset, trackOffset, false, moveGroup);
3030                 m_commandStack->push(moveGroup);
3031
3032                 //QPointF top = group->sceneBoundingRect().topLeft();
3033                 //QPointF oldpos = m_selectionGroup->scenePos();
3034                 //kDebug()<<"SELECTION GRP POS: "<<m_selectionGroup->scenePos()<<", TOP: "<<top;
3035                 //group->setPos(top);
3036                 //TODO: get rid of the 3 lines below
3037                 if (m_selectionGroup) {
3038                     m_selectionGroupInfo.startPos = GenTime(m_selectionGroup->scenePos().x(), m_document->fps());
3039                     m_selectionGroupInfo.track = m_selectionGroup->track();
3040                 }
3041                 setDocumentModified();
3042             }
3043         }
3044         m_document->renderer()->doRefresh();
3045     } else if (m_operationMode == RESIZESTART && m_dragItem->startPos() != m_dragItemInfo.startPos) {
3046         // resize start
3047         if (m_dragItem->type() == AVWIDGET) {
3048             ItemInfo resizeinfo = m_dragItemInfo;
3049             resizeinfo.track = m_document->tracksCount() - resizeinfo.track;
3050             bool success = m_document->renderer()->mltResizeClipStart(resizeinfo, m_dragItem->startPos() - m_dragItemInfo.startPos);
3051             if (success) {
3052                 QUndoCommand *resizeCommand = new QUndoCommand();
3053                 resizeCommand->setText(i18n("Resize clip"));
3054
3055                 // Check if there is an automatic transition on that clip (lower track)
3056                 Transition *transition = getTransitionItemAtStart(m_dragItemInfo.startPos, m_dragItemInfo.track);
3057                 if (transition && transition->isAutomatic()) {
3058                     ItemInfo trInfo = transition->info();
3059                     ItemInfo newTrInfo = trInfo;
3060                     newTrInfo.startPos = m_dragItem->startPos();
3061                     if (newTrInfo.startPos < newTrInfo.endPos)
3062                         new MoveTransitionCommand(this, trInfo, newTrInfo, true, resizeCommand);
3063                 }
3064                 // Check if there is an automatic transition on that clip (upper track)
3065                 transition = getTransitionItemAtStart(m_dragItemInfo.startPos, m_dragItemInfo.track - 1);
3066                 if (transition && transition->isAutomatic() && (m_document->tracksCount() - transition->transitionEndTrack()) == m_dragItemInfo.track) {
3067                     ItemInfo trInfo = transition->info();
3068                     ItemInfo newTrInfo = trInfo;
3069                     newTrInfo.startPos = m_dragItem->startPos();
3070                     ClipItem * upperClip = getClipItemAt(m_dragItemInfo.startPos, m_dragItemInfo.track - 1);
3071                     if ((!upperClip || !upperClip->baseClip()->isTransparent()) && newTrInfo.startPos < newTrInfo.endPos) {
3072                         new MoveTransitionCommand(this, trInfo, newTrInfo, true, resizeCommand);
3073                     }
3074                 }
3075
3076                 ClipItem *clip = static_cast < ClipItem * >(m_dragItem);
3077                 updatePositionEffects(clip, m_dragItemInfo);
3078
3079                 // check keyframes
3080                 QDomDocument doc;
3081                 QDomElement root = doc.createElement("list");
3082                 doc.appendChild(root);
3083                 QList <int> indexes;
3084                 for (int i = 0; i < clip->effectsCount(); i++) {
3085                     QDomElement effect = clip->effectAt(i);
3086                     if (EffectsList::hasKeyFrames(effect)) {
3087                         doc.appendChild(doc.importNode(effect, true));
3088                         indexes.append(i);
3089                     }
3090                 }
3091
3092                 if (clip->checkEffectsKeyframesPos(m_dragItemInfo.cropStart.frames(m_document->fps()), clip->cropStart().frames(m_document->fps()), true)) {
3093                     // Keyframes were modified, updateClip
3094                     QDomNodeList effs = doc.elementsByTagName("effect");
3095                     // Hack:
3096                     // Since we must always resize clip before updating the keyframes, we
3097                     // put a resize command before & after checking keyframes so that
3098                     // we are sure the resize is performed before whenever we do or undo the action
3099
3100                     new ResizeClipCommand(this, m_dragItemInfo, info, false, true, resizeCommand);
3101                     for (int i = 0; i < indexes.count(); i++) {
3102                         new EditEffectCommand(this, m_document->tracksCount() - clip->track(), clip->startPos(), effs.at(i).cloneNode().toElement(), clip->effectAt(indexes.at(i)), indexes.at(i), false, resizeCommand);
3103                         updateEffect(m_document->tracksCount() - clip->track(), clip->startPos(), clip->effectAt(indexes.at(i)), indexes.at(i));
3104                     }
3105                     new ResizeClipCommand(this, m_dragItemInfo, info, false, true, resizeCommand);
3106                     emit clipItemSelected(clip);
3107                 } else new ResizeClipCommand(this, m_dragItemInfo, info, false, false, resizeCommand);
3108
3109                 m_commandStack->push(resizeCommand);
3110             } else {
3111                 bool snap = KdenliveSettings::snaptopoints();
3112                 KdenliveSettings::setSnaptopoints(false);
3113                 m_dragItem->resizeStart((int) m_dragItemInfo.startPos.frames(m_document->fps()));
3114                 KdenliveSettings::setSnaptopoints(snap);
3115                 emit displayMessage(i18n("Error when resizing clip"), ErrorMessage);
3116             }
3117         } else if (m_dragItem->type() == TRANSITIONWIDGET) {
3118             Transition *transition = static_cast <Transition *>(m_dragItem);
3119             if (!m_document->renderer()->mltMoveTransition(transition->transitionTag(), (int)(m_document->tracksCount() - m_dragItemInfo.track), (int)(m_document->tracksCount() - m_dragItemInfo.track), transition->transitionEndTrack(), m_dragItemInfo.startPos, m_dragItemInfo.endPos, info.startPos, info.endPos)) {
3120                 // Cannot resize transition
3121                 bool snap = KdenliveSettings::snaptopoints();
3122                 KdenliveSettings::setSnaptopoints(false);
3123                 transition->resizeStart((int) m_dragItemInfo.startPos.frames(m_document->fps()));
3124                 KdenliveSettings::setSnaptopoints(snap);
3125                 emit displayMessage(i18n("Cannot resize transition"), ErrorMessage);
3126             } else {
3127                 MoveTransitionCommand *command = new MoveTransitionCommand(this, m_dragItemInfo, info, false);
3128                 m_commandStack->push(command);
3129             }
3130
3131         }
3132         if (m_dragItem->parentItem() && m_dragItem->parentItem() != m_selectionGroup) {
3133             // Item was resized, rebuild group;
3134             AbstractGroupItem *group = static_cast <AbstractGroupItem *>(m_dragItem->parentItem());
3135             QList <QGraphicsItem *> children = group->childItems();
3136             m_document->clipManager()->removeGroup(group);
3137             scene()->destroyItemGroup(group);
3138             for (int i = 0; i < children.count(); i++) {
3139                 children.at(i)->setSelected(true);
3140             }
3141             groupSelectedItems(false, true);
3142         }
3143         //m_document->renderer()->doRefresh();
3144     } else if (m_operationMode == RESIZEEND && m_dragItem->endPos() != m_dragItemInfo.endPos) {
3145         // resize end
3146         if (m_dragItem->type() == AVWIDGET) {
3147             ItemInfo resizeinfo = info;
3148             resizeinfo.track = m_document->tracksCount() - resizeinfo.track;
3149             bool success = m_document->renderer()->mltResizeClipEnd(resizeinfo, resizeinfo.endPos - resizeinfo.startPos);
3150             if (success) {
3151                 QUndoCommand *resizeCommand = new QUndoCommand();
3152                 resizeCommand->setText(i18n("Resize clip"));
3153
3154                 // Check if there is an automatic transition on that clip (lower track)
3155                 Transition *tr = getTransitionItemAtEnd(m_dragItemInfo.endPos, m_dragItemInfo.track);
3156                 if (tr && tr->isAutomatic()) {
3157                     ItemInfo trInfo = tr->info();
3158                     ItemInfo newTrInfo = trInfo;
3159                     newTrInfo.endPos = m_dragItem->endPos();
3160                     if (newTrInfo.endPos > newTrInfo.startPos) new MoveTransitionCommand(this, trInfo, newTrInfo, true, resizeCommand);
3161                 }
3162
3163                 // Check if there is an automatic transition on that clip (upper track)
3164                 tr = getTransitionItemAtEnd(m_dragItemInfo.endPos, m_dragItemInfo.track - 1);
3165                 if (tr && tr->isAutomatic() && (m_document->tracksCount() - tr->transitionEndTrack()) == m_dragItemInfo.track) {
3166                     ItemInfo trInfo = tr->info();
3167                     ItemInfo newTrInfo = trInfo;
3168                     newTrInfo.endPos = m_dragItem->endPos();
3169                     ClipItem * upperClip = getClipItemAtEnd(m_dragItemInfo.endPos, m_dragItemInfo.track - 1);
3170                     if ((!upperClip || !upperClip->baseClip()->isTransparent()) && newTrInfo.endPos > newTrInfo.startPos) {
3171                         new MoveTransitionCommand(this, trInfo, newTrInfo, true, resizeCommand);
3172                     }
3173                 }
3174
3175                 // check keyframes
3176                 ClipItem *clip = static_cast < ClipItem * >(m_dragItem);
3177                 QDomDocument doc;
3178                 QDomElement root = doc.createElement("list");
3179                 doc.appendChild(root);
3180                 QList <int> indexes;
3181                 for (int i = 0; i < clip->effectsCount(); i++) {
3182                     QDomElement effect = clip->effectAt(i);
3183                     if (EffectsList::hasKeyFrames(effect)) {
3184                         doc.appendChild(doc.importNode(effect, true));
3185                         indexes.append(i);
3186                     }
3187                 }
3188
3189                 if (clip->checkEffectsKeyframesPos((m_dragItemInfo.cropStart + m_dragItemInfo.endPos - m_dragItemInfo.startPos).frames(m_document->fps()) - 1, (clip->cropStart() + clip->cropDuration()).frames(m_document->fps()) - 1, false)) {
3190                     // Keyframes were modified, updateClip
3191                     QDomNodeList effs = doc.elementsByTagName("effect");
3192                     // Hack:
3193                     // Since we must always resize clip before updating the keyframes, we
3194                     // put a resize command before & after checking keyframes so that
3195                     // we are sure the resize is performed before whenever we do or undo the action
3196
3197                     new ResizeClipCommand(this, m_dragItemInfo, info, false, true, resizeCommand);
3198                     for (int i = 0; i < indexes.count(); i++) {
3199                         new EditEffectCommand(this, m_document->tracksCount() - clip->track(), clip->startPos(), effs.at(i).cloneNode().toElement(), clip->effectAt(indexes.at(i)), indexes.at(i), false, resizeCommand);
3200                         updateEffect(m_document->tracksCount() - clip->track(), clip->startPos(), clip->effectAt(indexes.at(i)), indexes.at(i));
3201                     }
3202                     new ResizeClipCommand(this, m_dragItemInfo, info, false, true, resizeCommand);
3203                     emit clipItemSelected(clip);
3204                 } else new ResizeClipCommand(this, m_dragItemInfo, info, false, false, resizeCommand);
3205
3206                 m_commandStack->push(resizeCommand);
3207                 updatePositionEffects(clip, m_dragItemInfo);
3208             } else {
3209                 m_dragItem->resizeEnd((int) m_dragItemInfo.endPos.frames(m_document->fps()));
3210                 emit displayMessage(i18n("Error when resizing clip"), ErrorMessage);
3211             }
3212         } else if (m_dragItem->type() == TRANSITIONWIDGET) {
3213             Transition *transition = static_cast <Transition *>(m_dragItem);
3214             if (!m_document->renderer()->mltMoveTransition(transition->transitionTag(), (int)(m_document->tracksCount() - m_dragItemInfo.track), (int)(m_document->tracksCount() - m_dragItemInfo.track), transition->transitionEndTrack(), m_dragItemInfo.startPos, m_dragItemInfo.endPos, info.startPos, info.endPos)) {
3215                 // Cannot resize transition
3216                 transition->resizeEnd((int) m_dragItemInfo.endPos.frames(m_document->fps()));
3217                 emit displayMessage(i18n("Cannot resize transition"), ErrorMessage);
3218             } else {
3219                 MoveTransitionCommand *command = new MoveTransitionCommand(this, m_dragItemInfo, info, false);
3220                 m_commandStack->push(command);
3221             }
3222         }
3223         if (m_dragItem->parentItem() && m_dragItem->parentItem() != m_selectionGroup) {
3224             // Item was resized, rebuild group;
3225             AbstractGroupItem *group = static_cast <AbstractGroupItem *>(m_dragItem->parentItem());
3226             QList <QGraphicsItem *> children = group->childItems();
3227             m_document->clipManager()->removeGroup(group);
3228             scene()->destroyItemGroup(group);
3229             for (int i = 0; i < children.count(); i++) {
3230                 children.at(i)->setSelected(true);
3231             }
3232             groupSelectedItems(false, true);
3233         }
3234         //m_document->renderer()->doRefresh();
3235     } else if (m_operationMode == FADEIN) {
3236         // resize fade in effect
3237         ClipItem * item = static_cast <ClipItem *>(m_dragItem);
3238         int ix = item->hasEffect("volume", "fadein");
3239         int ix2 = item->hasEffect("", "fade_from_black");
3240         if (ix != -1) {
3241             QDomElement oldeffect = item->effectAt(ix);
3242             int start = item->cropStart().frames(m_document->fps());
3243             int end = item->fadeIn();
3244             if (end == 0) {
3245                 slotDeleteEffect(item, oldeffect);
3246             } else {
3247                 end += start;
3248                 QDomElement effect = oldeffect.cloneNode().toElement();
3249                 EffectsList::setParameter(oldeffect, "in", QString::number(start));
3250                 EffectsList::setParameter(oldeffect, "out", QString::number(end));
3251                 slotUpdateClipEffect(item, effect, oldeffect, ix);
3252                 emit clipItemSelected(item, ix);
3253             }
3254         } else if (item->fadeIn() != 0 && ix2 == -1) {
3255             QDomElement effect;
3256             if (item->isVideoOnly() || (item->clipType() != AUDIO && item->clipType() != AV && item->clipType() != PLAYLIST)) {
3257                 // add video fade
3258                 effect = MainWindow::videoEffects.getEffectByTag("", "fade_from_black").cloneNode().toElement();
3259             } else effect = MainWindow::audioEffects.getEffectByTag("volume", "fadein").cloneNode().toElement();
3260             EffectsList::setParameter(effect, "out", QString::number(item->fadeIn()));
3261             slotAddEffect(effect, m_dragItem->startPos(), m_dragItem->track());
3262         }
3263         if (ix2 != -1) {
3264             QDomElement oldeffect = item->effectAt(ix2);
3265             int start = item->cropStart().frames(m_document->fps());
3266             int end = item->fadeIn();
3267             if (end == 0) {
3268                 slotDeleteEffect(item, oldeffect);
3269             } else {
3270                 end += start;
3271                 QDomElement effect = oldeffect.cloneNode().toElement();
3272                 EffectsList::setParameter(oldeffect, "in", QString::number(start));
3273                 EffectsList::setParameter(oldeffect, "out", QString::number(end));
3274                 slotUpdateClipEffect(item, effect, oldeffect, ix2);
3275                 emit clipItemSelected(item, ix2);
3276             }
3277         }
3278     } else if (m_operationMode == FADEOUT) {
3279         // resize fade in effect
3280         ClipItem * item = static_cast <ClipItem *>(m_dragItem);
3281         int ix = item->hasEffect("volume", "fadeout");
3282         int ix2 = item->hasEffect("", "fade_to_black");
3283         if (ix != -1) {
3284             QDomElement oldeffect = item->effectAt(ix);
3285             int end = (item->cropDuration() + item->cropStart()).frames(m_document->fps());
3286             int start = item->fadeOut();
3287             if (start == 0) {
3288                 slotDeleteEffect(item, oldeffect);
3289             } else {
3290                 start = end - start;
3291                 QDomElement effect = oldeffect.cloneNode().toElement();
3292                 EffectsList::setParameter(oldeffect, "in", QString::number(start));
3293                 EffectsList::setParameter(oldeffect, "out", QString::number(end));
3294                 // kDebug()<<"EDIT FADE OUT : "<<start<<"x"<<end;
3295                 slotUpdateClipEffect(item, effect, oldeffect, ix);
3296                 emit clipItemSelected(item, ix);
3297             }
3298         } else if (item->fadeOut() != 0 && ix2 == -1) {
3299             QDomElement effect;
3300             if (item->isVideoOnly() || (item->clipType() != AUDIO && item->clipType() != AV && item->clipType() != PLAYLIST)) {
3301                 // add video fade
3302                 effect = MainWindow::videoEffects.getEffectByTag("", "fade_to_black").cloneNode().toElement();
3303             } else effect = MainWindow::audioEffects.getEffectByTag("volume", "fadeout").cloneNode().toElement();
3304             EffectsList::setParameter(effect, "in", QString::number(item->fadeOut()));
3305             EffectsList::setParameter(effect, "out", QString::number(0));
3306             slotAddEffect(effect, m_dragItem->startPos(), m_dragItem->track());
3307         }
3308         if (ix2 != -1) {
3309             QDomElement oldeffect = item->effectAt(ix2);
3310             int end = (item->cropDuration() + item->cropStart()).frames(m_document->fps());
3311             int start = item->fadeOut();
3312             if (start == 0) {
3313                 slotDeleteEffect(item, oldeffect);
3314             } else {
3315                 start = end - start;
3316                 QDomElement effect = oldeffect.cloneNode().toElement();
3317                 EffectsList::setParameter(oldeffect, "in", QString::number(start));
3318                 EffectsList::setParameter(oldeffect, "out", QString::number(end));
3319                 // kDebug()<<"EDIT FADE OUT : "<<start<<"x"<<end;
3320                 slotUpdateClipEffect(item, effect, oldeffect, ix2);
3321                 emit clipItemSelected(item, ix2);
3322             }
3323         }
3324     } else if (m_operationMode == KEYFRAME) {
3325         // update the MLT effect
3326         ClipItem * item = static_cast <ClipItem *>(m_dragItem);
3327         QString previous = item->keyframes(item->selectedEffectIndex());
3328         item->updateKeyframeEffect();
3329         QString next = item->keyframes(item->selectedEffectIndex());
3330         EditKeyFrameCommand *command = new EditKeyFrameCommand(this, item->track(), item->startPos(), item->selectedEffectIndex(), previous, next, false);
3331         m_commandStack->push(command);
3332         updateEffect(m_document->tracksCount() - item->track(), item->startPos(), item->selectedEffect(), item->selectedEffectIndex());
3333         emit clipItemSelected(item, item->selectedEffectIndex());
3334     }
3335     if (m_dragItem && m_dragItem->type() == TRANSITIONWIDGET && m_dragItem->isSelected()) {
3336         // A transition is selected
3337         QPoint p;
3338         ClipItem *transitionClip = getClipItemAt(m_dragItemInfo.startPos, m_dragItemInfo.track);
3339         if (transitionClip && transitionClip->baseClip()) {
3340             QString size = transitionClip->baseClip()->getProperty("frame_size");
3341             double factor = transitionClip->baseClip()->getProperty("aspect_ratio").toDouble();
3342             p.setX((int)(size.section('x', 0, 0).toInt() * factor + 0.5));
3343             p.setY(size.section('x', 1, 1).toInt());
3344         }
3345         emit transitionItemSelected(static_cast <Transition *>(m_dragItem), getPreviousVideoTrack(m_dragItem->track()), p);
3346     } else emit transitionItemSelected(NULL);
3347     if (m_operationMode != NONE && m_operationMode != MOVE) setDocumentModified();
3348     m_operationMode = NONE;
3349 }
3350
3351 void CustomTrackView::deleteClip(ItemInfo info, bool refresh)
3352 {
3353     ClipItem *item = getClipItemAt((int) info.startPos.frames(m_document->fps()), info.track);
3354
3355     if (!item || m_document->renderer()->mltRemoveClip(m_document->tracksCount() - info.track, info.startPos) == false) {
3356         emit displayMessage(i18n("Error removing clip at %1 on track %2", m_document->timecode().getTimecodeFromFrames(info.startPos.frames(m_document->fps())), info.track), ErrorMessage);
3357         return;
3358     }
3359     if (item->isSelected()) emit clipItemSelected(NULL);
3360     item->baseClip()->removeReference();
3361     m_document->updateClip(item->baseClip()->getId());
3362
3363     /*if (item->baseClip()->isTransparent()) {
3364         // also remove automatic transition
3365         Transition *tr = getTransitionItemAt(info.startPos, info.track);
3366         if (tr && tr->isAutomatic()) {
3367             m_document->renderer()->mltDeleteTransition(tr->transitionTag(), tr->transitionEndTrack(), m_document->tracksCount() - info.track, info.startPos, info.endPos, tr->toXML());
3368             scene()->removeItem(tr);
3369             delete tr;
3370         }
3371     }*/
3372     m_waitingThumbs.removeAll(item);
3373     if (m_dragItem == item) m_dragItem = NULL;
3374 #if QT_VERSION >= 0x040600
3375     // animate item deletion
3376     item->closeAnimation();
3377     /*if (refresh) item->closeAnimation();
3378     else {
3379         // no refresh, means we have several operations chained, we need to delete clip immediatly
3380         // so that it does not get in the way of the other
3381         delete item;
3382         item = NULL;
3383     }*/
3384 #else
3385     delete item;
3386     item = NULL;
3387 #endif
3388
3389     setDocumentModified();
3390     if (refresh) m_document->renderer()->doRefresh();
3391 }
3392
3393 void CustomTrackView::deleteSelectedClips()
3394 {
3395     resetSelectionGroup();
3396     QList<QGraphicsItem *> itemList = scene()->selectedItems();
3397     if (itemList.count() == 0) {
3398         emit displayMessage(i18n("Select clip to delete"), ErrorMessage);
3399         return;
3400     }
3401     scene()->clearSelection();
3402     QUndoCommand *deleteSelected = new QUndoCommand();
3403
3404     bool resetGroup = false;
3405     int groupCount = 0;
3406     int clipCount = 0;
3407     int transitionCount = 0;
3408     // expand & destroy groups
3409     for (int i = 0; i < itemList.count(); i++) {
3410         if (itemList.at(i)->type() == GROUPWIDGET) {
3411             groupCount++;
3412             QList<QGraphicsItem *> children = itemList.at(i)->childItems();
3413             itemList += children;
3414             QList <ItemInfo> clipInfos;
3415             QList <ItemInfo> transitionInfos;
3416             GenTime currentPos = GenTime(m_cursorPos, m_document->fps());
3417             for (int j = 0; j < children.count(); j++) {
3418                 if (children.at(j)->type() == AVWIDGET) {
3419                     AbstractClipItem *clip = static_cast <AbstractClipItem *>(children.at(j));
3420                     if (!clip->isItemLocked()) clipInfos.append(clip->info());
3421                 } else if (children.at(j)->type() == TRANSITIONWIDGET) {
3422                     AbstractClipItem *clip = static_cast <AbstractClipItem *>(children.at(j));
3423                     if (!clip->isItemLocked()) transitionInfos.append(clip->info());
3424                 }
3425             }
3426             if (clipInfos.count() > 0) {
3427                 new GroupClipsCommand(this, clipInfos, transitionInfos, false, deleteSelected);
3428             }
3429         }
3430     }
3431
3432     for (int i = 0; i < itemList.count(); i++) {
3433         if (itemList.at(i)->type() == AVWIDGET) {
3434             clipCount++;
3435             ClipItem *item = static_cast <ClipItem *>(itemList.at(i));
3436             if (item->parentItem()) resetGroup = true;
3437             //kDebug()<<"// DELETE CLP AT: "<<item->info().startPos.frames(25);
3438             new AddTimelineClipCommand(this, item->xml(), item->clipProducer(), item->info(), item->effectList(), false, false, true, true, deleteSelected);
3439             emit clipItemSelected(NULL);
3440         } else if (itemList.at(i)->type() == TRANSITIONWIDGET) {
3441             transitionCount++;
3442             Transition *item = static_cast <Transition *>(itemList.at(i));
3443             //kDebug()<<"// DELETE TRANS AT: "<<item->info().startPos.frames(25);
3444             if (item->parentItem()) resetGroup = true;
3445             new AddTransitionCommand(this, item->info(), item->transitionEndTrack(), item->toXML(), true, true, deleteSelected);
3446             emit transitionItemSelected(NULL);
3447         }
3448     }
3449     if (groupCount > 0 && clipCount == 0 && transitionCount == 0)
3450         deleteSelected->setText(i18np("Delete selected group", "Delete selected groups", groupCount));
3451     else if (clipCount > 0 && groupCount == 0 && transitionCount == 0)
3452         deleteSelected->setText(i18np("Delete selected clip", "Delete selected clips", clipCount));
3453     else if (transitionCount > 0 && groupCount == 0 && clipCount == 0)
3454         deleteSelected->setText(i18np("Delete selected transition", "Delete selected transitions", transitionCount));
3455     else deleteSelected->setText(i18n("Delete selected items"));
3456     m_commandStack->push(deleteSelected);
3457 }
3458
3459 void CustomTrackView::changeClipSpeed()
3460 {
3461     QList<QGraphicsItem *> itemList = scene()->selectedItems();
3462     if (itemList.count() == 0) {
3463         emit displayMessage(i18n("Select clip to change speed"), ErrorMessage);
3464         return;
3465     }
3466     QUndoCommand *changeSelected = new QUndoCommand();
3467     changeSelected->setText("Edit clip speed");
3468     int count = 0;
3469     int percent = -1;
3470     bool ok;
3471     for (int i = 0; i < itemList.count(); i++) {
3472         if (itemList.at(i)->type() == AVWIDGET) {
3473             ClipItem *item = static_cast <ClipItem *>(itemList.at(i));
3474             ItemInfo info = item->info();
3475             if (percent == -1) percent = QInputDialog::getInteger(this, i18n("Edit Clip Speed"), i18n("New speed (percents)"), item->speed() * 100, 1, 10000, 1, &ok);
3476             if (!ok) break;
3477             double speed = (double) percent / 100.0;
3478             if (item->speed() != speed && (item->clipType() == VIDEO || item->clipType() == AV)) {
3479                 count++;
3480                 //new ChangeSpeedCommand(this, info, item->speed(), speed, item->clipProducer(), changeSelected);
3481             }
3482         }
3483     }
3484     if (count > 0) m_commandStack->push(changeSelected);
3485     else delete changeSelected;
3486 }
3487
3488 void CustomTrackView::doChangeClipSpeed(ItemInfo info, ItemInfo speedIndependantInfo, const double speed, const double oldspeed, int strobe, const QString &id)
3489 {
3490     DocClipBase *baseclip = m_document->clipManager()->getClipById(id);
3491     ClipItem *item = getClipItemAt((int) info.startPos.frames(m_document->fps()), info.track);
3492     if (!item) {
3493         kDebug() << "ERROR: Cannot find clip for speed change";
3494         emit displayMessage(i18n("Cannot find clip for speed change"), ErrorMessage);
3495         return;
3496     }
3497     info.track = m_document->tracksCount() - item->track();
3498     int endPos = m_document->renderer()->mltChangeClipSpeed(info, speedIndependantInfo, speed, oldspeed, strobe, baseclip->producer());
3499     if (endPos >= 0) {
3500         item->setSpeed(speed, strobe);
3501         item->updateRectGeometry();
3502         if (item->cropDuration().frames(m_document->fps()) != endPos) {
3503             item->resizeEnd((int) info.startPos.frames(m_document->fps()) + endPos - 1);
3504         }
3505         updatePositionEffects(item, info);
3506         setDocumentModified();
3507     } else emit displayMessage(i18n("Invalid clip"), ErrorMessage);
3508 }
3509
3510 void CustomTrackView::cutSelectedClips()
3511 {
3512     QList<QGraphicsItem *> itemList = scene()->selectedItems();
3513     GenTime currentPos = GenTime(m_cursorPos, m_document->fps());
3514     for (int i = 0; i < itemList.count(); i++) {
3515         if (itemList.at(i)->type() == AVWIDGET) {
3516             ClipItem *item = static_cast <ClipItem *>(itemList.at(i));
3517             if (item->parentItem() && item->parentItem() != m_selectionGroup) {
3518                 emit displayMessage(i18n("Cannot cut a clip in a group"), ErrorMessage);
3519             } else if (currentPos > item->startPos() && currentPos <  item->endPos()) {
3520                 RazorClipCommand *command = new RazorClipCommand(this, item->info(), currentPos);
3521                 m_commandStack->push(command);
3522             }
3523         }
3524     }
3525 }
3526
3527 void CustomTrackView::groupClips(bool group)
3528 {
3529     QList<QGraphicsItem *> itemList = scene()->selectedItems();
3530     QList <ItemInfo> clipInfos;
3531     QList <ItemInfo> transitionInfos;
3532     GenTime currentPos = GenTime(m_cursorPos, m_document->fps());
3533
3534     // Expand groups
3535     int max = itemList.count();
3536     for (int i = 0; i < max; i++) {
3537         if (itemList.at(i)->type() == GROUPWIDGET) {
3538             itemList += itemList.at(i)->childItems();
3539         }
3540     }
3541
3542     for (int i = 0; i < itemList.count(); i++) {
3543         if (itemList.at(i)->type() == AVWIDGET) {
3544             AbstractClipItem *clip = static_cast <AbstractClipItem *>(itemList.at(i));
3545             if (!clip->isItemLocked()) clipInfos.append(clip->info());
3546         } else if (itemList.at(i)->type() == TRANSITIONWIDGET) {
3547             AbstractClipItem *clip = static_cast <AbstractClipItem *>(itemList.at(i));
3548             if (!clip->isItemLocked()) transitionInfos.append(clip->info());
3549         }
3550     }
3551     if (clipInfos.count() > 0) {
3552         GroupClipsCommand *command = new GroupClipsCommand(this, clipInfos, transitionInfos, group);
3553         m_commandStack->push(command);
3554     }
3555 }
3556
3557 void CustomTrackView::doGroupClips(QList <ItemInfo> clipInfos, QList <ItemInfo> transitionInfos, bool group)
3558 {
3559     resetSelectionGroup();
3560     m_scene->clearSelection();
3561     if (!group) {
3562         for (int i = 0; i < clipInfos.count(); i++) {
3563             ClipItem *clip = getClipItemAt(clipInfos.at(i).startPos, clipInfos.at(i).track);
3564             if (clip == NULL) continue;
3565             if (clip->parentItem() && clip->parentItem()->type() == GROUPWIDGET) {
3566                 AbstractGroupItem *grp = static_cast <AbstractGroupItem *>(clip->parentItem());
3567                 m_document->clipManager()->removeGroup(grp);
3568                 scene()->destroyItemGroup(grp);
3569             }
3570             clip->setFlag(QGraphicsItem::ItemIsMovable, true);
3571         }
3572         for (int i = 0; i < transitionInfos.count(); i++) {
3573             Transition *tr = getTransitionItemAt(transitionInfos.at(i).startPos, transitionInfos.at(i).track);
3574             if (tr == NULL) continue;
3575             if (tr->parentItem() && tr->parentItem()->type() == GROUPWIDGET) {
3576                 AbstractGroupItem *grp = static_cast <AbstractGroupItem *>(tr->parentItem());
3577                 m_document->clipManager()->removeGroup(grp);
3578                 scene()->destroyItemGroup(grp);
3579             }
3580             tr->setFlag(QGraphicsItem::ItemIsMovable, true);
3581         }
3582         setDocumentModified();
3583         return;
3584     }
3585
3586     QList <QGraphicsItemGroup *> groups;
3587     for (int i = 0; i < clipInfos.count(); i++) {
3588         ClipItem *clip = getClipItemAt(clipInfos.at(i).startPos, clipInfos.at(i).track);
3589         if (clip) {
3590             clip->setSelected(true);
3591         }
3592     }
3593     for (int i = 0; i < transitionInfos.count(); i++) {
3594         Transition *clip = getTransitionItemAt(transitionInfos.at(i).startPos, transitionInfos.at(i).track);
3595         if (clip) {
3596             clip->setSelected(true);
3597         }
3598     }
3599
3600     groupSelectedItems(false, true);
3601     setDocumentModified();
3602 }
3603
3604 void CustomTrackView::addClip(QDomElement xml, const QString &clipId, ItemInfo info, EffectsList effects, bool overwrite, bool push, bool refresh)
3605 {
3606     DocClipBase *baseclip = m_document->clipManager()->getClipById(clipId);
3607     if (baseclip == NULL) {
3608         emit displayMessage(i18n("No clip copied"), ErrorMessage);
3609         return;
3610     }
3611     ClipItem *item = new ClipItem(baseclip, info, m_document->fps(), xml.attribute("speed", "1").toDouble(), xml.attribute("strobe", "1").toInt());
3612     item->setEffectList(effects);
3613     if (xml.hasAttribute("audio_only")) item->setAudioOnly(true);
3614     else if (xml.hasAttribute("video_only")) item->setVideoOnly(true);
3615     scene()->addItem(item);
3616
3617     int tracknumber = m_document->tracksCount() - info.track - 1;
3618     bool isLocked = m_document->trackInfoAt(tracknumber).isLocked;
3619     if (isLocked) item->setItemLocked(true);
3620
3621     baseclip->addReference();
3622     m_document->updateClip(baseclip->getId());
3623     info.track = m_document->tracksCount() - info.track;
3624     Mlt::Producer *prod;
3625     if (item->isAudioOnly()) prod = baseclip->audioProducer(info.track);
3626     else if (item->isVideoOnly()) prod = baseclip->videoProducer();
3627     else prod = baseclip->producer(info.track);
3628     m_document->renderer()->mltInsertClip(info, xml, prod, overwrite, push);
3629     for (int i = 0; i < item->effectsCount(); i++) {
3630         m_document->renderer()->mltAddEffect(info.track, info.startPos, item->getEffectArgs(item->effectAt(i)), false);
3631     }
3632     setDocumentModified();
3633     if (refresh) m_document->renderer()->doRefresh();
3634     m_waitingThumbs.append(item);
3635     m_thumbsTimer.start();
3636 }
3637
3638 void CustomTrackView::slotUpdateClip(const QString &clipId, bool reload)
3639 {
3640     QList<QGraphicsItem *> list = scene()->items();
3641     ClipItem *clip = NULL;
3642     for (int i = 0; i < list.size(); ++i) {
3643         if (list.at(i)->type() == AVWIDGET) {
3644             clip = static_cast <ClipItem *>(list.at(i));
3645             if (clip->clipProducer() == clipId) {
3646                 ItemInfo info = clip->info();
3647                 info.track = m_document->tracksCount() - clip->track();
3648                 if (reload && !m_document->renderer()->mltUpdateClip(info, clip->xml(), clip->baseClip()->producer())) {
3649                     emit displayMessage(i18n("Cannot update clip (time: %1, track: %2)", info.startPos.frames(m_document->fps()), info.track), ErrorMessage);
3650                 }
3651                 clip->refreshClip(true);
3652                 clip->update();
3653             }
3654         }
3655     }
3656 }
3657
3658 ClipItem *CustomTrackView::getClipItemAtEnd(GenTime pos, int track)
3659 {
3660     int framepos = (int)(pos.frames(m_document->fps()));
3661     QList<QGraphicsItem *> list = scene()->items(QPointF(framepos - 1, track * m_tracksHeight + m_tracksHeight / 2));
3662     ClipItem *clip = NULL;
3663     for (int i = 0; i < list.size(); i++) {
3664         if (!list.at(i)->isEnabled()) continue;
3665         if (list.at(i)->type() == AVWIDGET) {
3666             ClipItem *test = static_cast <ClipItem *>(list.at(i));
3667             if (test->endPos() == pos) clip = test;
3668             break;
3669         }
3670     }
3671     return clip;
3672 }
3673
3674 ClipItem *CustomTrackView::getClipItemAtStart(GenTime pos, int track)
3675 {
3676     QList<QGraphicsItem *> list = scene()->items(QPointF(pos.frames(m_document->fps()), track * m_tracksHeight + m_tracksHeight / 2));
3677     ClipItem *clip = NULL;
3678     for (int i = 0; i < list.size(); i++) {
3679         if (!list.at(i)->isEnabled()) continue;
3680         if (list.at(i)->type() == AVWIDGET) {
3681             ClipItem *test = static_cast <ClipItem *>(list.at(i));
3682             if (test->startPos() == pos) clip = test;
3683             break;
3684         }
3685     }
3686     return clip;
3687 }
3688
3689 ClipItem *CustomTrackView::getClipItemAt(int pos, int track)
3690 {
3691     const QPointF p(pos, track * m_tracksHeight + m_tracksHeight / 2);
3692     QList<QGraphicsItem *> list = scene()->items(p);
3693     ClipItem *clip = NULL;
3694     for (int i = 0; i < list.size(); i++) {
3695         if (!list.at(i)->isEnabled()) continue;
3696         if (list.at(i)->type() == AVWIDGET) {
3697             clip = static_cast <ClipItem *>(list.at(i));
3698             break;
3699         }
3700     }
3701     return clip;
3702 }
3703
3704 ClipItem *CustomTrackView::getClipItemAt(GenTime pos, int track)
3705 {
3706     return getClipItemAt((int) pos.frames(m_document->fps()), track);
3707 }
3708
3709 Transition *CustomTrackView::getTransitionItemAt(int pos, int track)
3710 {
3711     const QPointF p(pos, (track + 1) * m_tracksHeight);
3712     QList<QGraphicsItem *> list = scene()->items(p);
3713     Transition *clip = NULL;
3714     for (int i = 0; i < list.size(); i++) {
3715         if (!list.at(i)->isEnabled()) continue;
3716         if (list.at(i)->type() == TRANSITIONWIDGET) {
3717             clip = static_cast <Transition *>(list.at(i));
3718             break;
3719         }
3720     }
3721     return clip;
3722 }
3723
3724 Transition *CustomTrackView::getTransitionItemAt(GenTime pos, int track)
3725 {
3726     return getTransitionItemAt(pos.frames(m_document->fps()), track);
3727 }
3728
3729 Transition *CustomTrackView::getTransitionItemAtEnd(GenTime pos, int track)
3730 {
3731     int framepos = (int)(pos.frames(m_document->fps()));
3732     const QPointF p(framepos - 1, (track + 1) * m_tracksHeight);
3733     QList<QGraphicsItem *> list = scene()->items(p);
3734     Transition *clip = NULL;
3735     for (int i = 0; i < list.size(); i++) {
3736         if (!list.at(i)->isEnabled()) continue;
3737         if (list.at(i)->type() == TRANSITIONWIDGET) {
3738             Transition *test = static_cast <Transition *>(list.at(i));
3739             if (test->endPos() == pos) clip = test;
3740             break;
3741         }
3742     }
3743     return clip;
3744 }
3745
3746 Transition *CustomTrackView::getTransitionItemAtStart(GenTime pos, int track)
3747 {
3748     const QPointF p(pos.frames(m_document->fps()), (track + 1) * m_tracksHeight);
3749     QList<QGraphicsItem *> list = scene()->items(p);
3750     Transition *clip = NULL;
3751     for (int i = 0; i < list.size(); ++i) {
3752         if (!list.at(i)->isEnabled()) continue;
3753         if (list.at(i)->type() == TRANSITIONWIDGET) {
3754             Transition *test = static_cast <Transition *>(list.at(i));
3755             if (test->startPos() == pos) clip = test;
3756             break;
3757         }
3758     }
3759     return clip;
3760 }
3761
3762 void CustomTrackView::moveClip(const ItemInfo start, const ItemInfo end, bool refresh)
3763 {
3764     if (m_selectionGroup) resetSelectionGroup(false);
3765     ClipItem *item = getClipItemAt((int) start.startPos.frames(m_document->fps()), start.track);
3766     if (!item) {
3767         emit displayMessage(i18n("Cannot move clip at time: %1 on track %2", m_document->timecode().getTimecodeFromFrames(start.startPos.frames(m_document->fps())), start.track), ErrorMessage);
3768         kDebug() << "----------------  ERROR, CANNOT find clip to move at.. ";
3769         return;
3770     }
3771     Mlt::Producer *prod;
3772     if (item->isAudioOnly()) prod = item->baseClip()->audioProducer(end.track);
3773     else if (item->isVideoOnly()) prod = item->baseClip()->videoProducer();
3774     else prod = item->baseClip()->producer(end.track);
3775
3776     bool success = m_document->renderer()->mltMoveClip((int)(m_document->tracksCount() - start.track), (int)(m_document->tracksCount() - end.track), (int) start.startPos.frames(m_document->fps()), (int)end.startPos.frames(m_document->fps()), prod);
3777     if (success) {
3778         bool snap = KdenliveSettings::snaptopoints();
3779         KdenliveSettings::setSnaptopoints(false);
3780         item->setPos((int) end.startPos.frames(m_document->fps()), (int)(end.track * m_tracksHeight + 1));
3781
3782         int tracknumber = m_document->tracksCount() - end.track - 1;
3783         bool isLocked = m_document->trackInfoAt(tracknumber).isLocked;
3784         m_scene->clearSelection();
3785         if (isLocked) item->setItemLocked(true);
3786         else {
3787             if (item->isItemLocked()) item->setItemLocked(false);
3788             item->setSelected(true);
3789         }
3790         if (item->baseClip()->isTransparent()) {
3791             // Also move automatic transition
3792             Transition *tr = getTransitionItemAt(start.startPos, start.track);
3793             if (tr && tr->isAutomatic()) {
3794                 tr->updateTransitionEndTrack(getPreviousVideoTrack(end.track));
3795                 m_document->renderer()->mltMoveTransition(tr->transitionTag(), m_document->tracksCount() - start.track, m_document->tracksCount() - end.track, tr->transitionEndTrack(), start.startPos, start.endPos, end.startPos, end.endPos);
3796                 tr->setPos((int) end.startPos.frames(m_document->fps()), (int)(end.track * m_tracksHeight + 1));
3797             }
3798         }
3799         KdenliveSettings::setSnaptopoints(snap);
3800         setDocumentModified();
3801     } else {
3802         // undo last move and emit error message
3803         emit displayMessage(i18n("Cannot move clip to position %1", m_document->timecode().getTimecodeFromFrames(end.startPos.frames(m_document->fps()))), ErrorMessage);
3804     }
3805     if (refresh) m_document->renderer()->doRefresh();
3806     //kDebug() << " // MOVED CLIP TO: " << end.startPos.frames(25) << ", ITEM START: " << item->startPos().frames(25);
3807 }
3808
3809 void CustomTrackView::moveGroup(QList <ItemInfo> startClip, QList <ItemInfo> startTransition, const GenTime offset, const int trackOffset, bool reverseMove)
3810 {
3811     // Group Items
3812     /*kDebug() << "//GRP MOVE, REVERS:" << reverseMove;
3813     kDebug() << "// GROUP MOV; OFFSET: " << offset.frames(25) << ", TK OFF: " << trackOffset;*/
3814     resetSelectionGroup();
3815     m_scene->clearSelection();
3816
3817     m_selectionGroup = new AbstractGroupItem(m_document->fps());
3818     scene()->addItem(m_selectionGroup);
3819
3820     m_document->renderer()->blockSignals(true);
3821     for (int i = 0; i < startClip.count(); i++) {
3822         if (reverseMove) {
3823             startClip[i].startPos = startClip.at(i).startPos - offset;
3824             startClip[i].track = startClip.at(i).track - trackOffset;
3825         }
3826         //kDebug()<<"//LKING FR CLIP AT:"<<startClip.at(i).startPos.frames(25)<<", TK:"<<startClip.at(i).track;
3827         ClipItem *clip = getClipItemAt(startClip.at(i).startPos, startClip.at(i).track);
3828         if (clip) {
3829             clip->setItemLocked(false);
3830             if (clip->parentItem()) {
3831                 m_selectionGroup->addToGroup(clip->parentItem());
3832                 clip->parentItem()->setFlag(QGraphicsItem::ItemIsMovable, false);
3833             } else {
3834                 m_selectionGroup->addToGroup(clip);
3835                 clip->setFlag(QGraphicsItem::ItemIsMovable, false);
3836             }
3837             m_document->renderer()->mltRemoveClip(m_document->tracksCount() - startClip.at(i).track, startClip.at(i).startPos);
3838         } else kDebug() << "//MISSING CLIP AT: " << startClip.at(i).startPos.frames(25);
3839     }
3840     for (int i = 0; i < startTransition.count(); i++) {
3841         if (reverseMove) {
3842             startTransition[i].startPos = startTransition.at(i).startPos - offset;
3843             startTransition[i].track = startTransition.at(i).track - trackOffset;
3844         }
3845         Transition *tr = getTransitionItemAt(startTransition.at(i).startPos, startTransition.at(i).track);
3846         if (tr) {
3847             tr->setItemLocked(false);
3848             if (tr->parentItem()) {
3849                 m_selectionGroup->addToGroup(tr->parentItem());
3850                 tr->parentItem()->setFlag(QGraphicsItem::ItemIsMovable, false);
3851             } else {
3852                 m_selectionGroup->addToGroup(tr);
3853                 tr->setFlag(QGraphicsItem::ItemIsMovable, false);
3854             }
3855             m_document->renderer()->mltDeleteTransition(tr->transitionTag(), tr->transitionEndTrack(), m_document->tracksCount() - startTransition.at(i).track, startTransition.at(i).startPos, startTransition.at(i).endPos, tr->toXML());
3856         } else kDebug() << "//MISSING TRANSITION AT: " << startTransition.at(i).startPos.frames(25);
3857     }
3858     m_document->renderer()->blockSignals(false);
3859
3860     if (m_selectionGroup) {
3861         bool snap = KdenliveSettings::snaptopoints();
3862         KdenliveSettings::setSnaptopoints(false);
3863
3864         m_selectionGroup->translate(offset.frames(m_document->fps()), trackOffset *(qreal) m_tracksHeight);
3865         //m_selectionGroup->moveBy(offset.frames(m_document->fps()), trackOffset *(qreal) m_tracksHeight);
3866
3867         QList<QGraphicsItem *> children = m_selectionGroup->childItems();
3868         // Expand groups
3869         int max = children.count();
3870         for (int i = 0; i < max; i++) {
3871             if (children.at(i)->type() == GROUPWIDGET) {
3872                 children += children.at(i)->childItems();
3873                 //AbstractGroupItem *grp = static_cast<AbstractGroupItem *>(children.at(i));
3874                 //grp->moveBy(offset.frames(m_document->fps()), trackOffset *(qreal) m_tracksHeight);
3875                 /*m_document->clipManager()->removeGroup(grp);
3876                 m_scene->destroyItemGroup(grp);*/
3877                 children.removeAll(children.at(i));
3878                 i--;
3879             }
3880         }
3881
3882         for (int i = 0; i < children.count(); i++) {
3883             // re-add items in correct place
3884             if (children.at(i)->type() != AVWIDGET && children.at(i)->type() != TRANSITIONWIDGET) continue;
3885             AbstractClipItem *item = static_cast <AbstractClipItem *>(children.at(i));
3886             item->updateItem();
3887             ItemInfo info = item->info();
3888             int tracknumber = m_document->tracksCount() - info.track - 1;
3889             bool isLocked = m_document->trackInfoAt(tracknumber).isLocked;
3890             if (isLocked) item->setItemLocked(true);
3891             else if (item->isItemLocked()) item->setItemLocked(false);
3892
3893             if (item->type() == AVWIDGET) {
3894                 ClipItem *clip = static_cast <ClipItem*>(item);
3895                 info.track = m_document->tracksCount() - info.track;
3896                 Mlt::Producer *prod;
3897                 if (clip->isAudioOnly()) prod = clip->baseClip()->audioProducer(info.track);
3898                 else if (clip->isVideoOnly()) prod = clip->baseClip()->videoProducer();
3899                 else prod = clip->baseClip()->producer(info.track);
3900                 m_document->renderer()->mltInsertClip(info, clip->xml(), prod);
3901             } else if (item->type() == TRANSITIONWIDGET) {
3902                 Transition *tr = static_cast <Transition*>(item);
3903                 int newTrack;
3904                 if (!tr->forcedTrack()) newTrack = getPreviousVideoTrack(info.track);
3905                 else {
3906                     newTrack = tr->transitionEndTrack() + trackOffset;
3907                     if (newTrack < 0 || newTrack > m_document->tracksCount()) newTrack = getPreviousVideoTrack(info.track);
3908                 }
3909                 tr->updateTransitionEndTrack(newTrack);
3910                 m_document->renderer()->mltAddTransition(tr->transitionTag(), newTrack, m_document->tracksCount() - info.track, info.startPos, info.endPos, tr->toXML());
3911             }
3912         }
3913         resetSelectionGroup(false);
3914         KdenliveSettings::setSnaptopoints(snap);
3915         m_document->renderer()->doRefresh();
3916     } else kDebug() << "///////// WARNING; NO GROUP TO MOVE";
3917 }
3918
3919 void CustomTrackView::moveTransition(const ItemInfo start, const ItemInfo end, bool m_refresh)
3920 {
3921     Transition *item = getTransitionItemAt(start.startPos, start.track);
3922     if (!item) {
3923         emit displayMessage(i18n("Cannot move transition at time: %1 on track %2", m_document->timecode().getTimecodeFromFrames(start.startPos.frames(m_document->fps())), start.track), ErrorMessage);
3924         kDebug() << "----------------  ERROR, CANNOT find transition to move... ";// << startPos.x() * m_scale * FRAME_SIZE + 1 << ", " << startPos.y() * m_tracksHeight + m_tracksHeight / 2;
3925         return;
3926     }
3927     //kDebug() << "----------------  Move TRANSITION FROM: " << startPos.x() << ", END:" << endPos.x() << ",TRACKS: " << oldtrack << " TO " << newtrack;
3928     bool snap = KdenliveSettings::snaptopoints();
3929     KdenliveSettings::setSnaptopoints(false);
3930     //kDebug()<<"///  RESIZE TRANS START: ("<< startPos.x()<<"x"<< startPos.y()<<") / ("<<endPos.x()<<"x"<< endPos.y()<<")";
3931     if (end.endPos - end.startPos == start.endPos - start.startPos) {
3932         // Transition was moved
3933         item->setPos((int) end.startPos.frames(m_document->fps()), (end.track) * m_tracksHeight + 1);
3934     } else if (end.endPos == start.endPos) {
3935         // Transition start resize
3936         item->resizeStart((int) end.startPos.frames(m_document->fps()));
3937     } else if (end.startPos == start.startPos) {
3938         // Transition end resize;
3939         kDebug() << "// resize END: " << end.endPos.frames(m_document->fps());
3940         item->resizeEnd((int) end.endPos.frames(m_document->fps()));
3941     } else {
3942         // Move & resize
3943         item->setPos((int) end.startPos.frames(m_document->fps()), (end.track) * m_tracksHeight + 1);
3944         item->resizeStart((int) end.startPos.frames(m_document->fps()));
3945         item->resizeEnd((int) end.endPos.frames(m_document->fps()));
3946     }
3947     //item->moveTransition(GenTime((int) (endPos.x() - startPos.x()), m_document->fps()));
3948     KdenliveSettings::setSnaptopoints(snap);
3949     item->updateTransitionEndTrack(getPreviousVideoTrack(end.track));
3950     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);
3951     if (m_dragItem && m_dragItem == item) {
3952         QPoint p;
3953         ClipItem *transitionClip = getClipItemAt(item->startPos(), item->track());
3954         if (transitionClip && transitionClip->baseClip()) {
3955             QString size = transitionClip->baseClip()->getProperty("frame_size");
3956             double factor = transitionClip->baseClip()->getProperty("aspect_ratio").toDouble();
3957             p.setX((int)(size.section('x', 0, 0).toInt() * factor + 0.5));
3958             p.setY(size.section('x', 1, 1).toInt());
3959         }
3960         emit transitionItemSelected(item, getPreviousVideoTrack(item->track()), p);
3961     }
3962     if (m_refresh) m_document->renderer()->doRefresh();
3963     setDocumentModified();
3964 }
3965
3966 void CustomTrackView::resizeClip(const ItemInfo start, const ItemInfo end, bool dontWorry)
3967 {
3968     bool resizeClipStart = (start.startPos != end.startPos);
3969     ClipItem *item = getClipItemAtStart(start.startPos, start.track);
3970     if (!item) {
3971         if (dontWorry) return;
3972         emit displayMessage(i18n("Cannot move clip at time: %1 on track %2", m_document->timecode().getTimecodeFromFrames(start.startPos.frames(m_document->fps())), start.track), ErrorMessage);
3973         kDebug() << "----------------  ERROR, CANNOT find clip to resize at... "; // << startPos;
3974         return;
3975     }
3976     if (item->parentItem()) {
3977         // Item is part of a group, reset group
3978         resetSelectionGroup();
3979     }
3980
3981     bool snap = KdenliveSettings::snaptopoints();
3982     KdenliveSettings::setSnaptopoints(false);
3983     if (resizeClipStart) {
3984         ItemInfo clipinfo = item->info();
3985         clipinfo.track = m_document->tracksCount() - clipinfo.track;
3986         bool success = m_document->renderer()->mltResizeClipStart(clipinfo, end.startPos - clipinfo.startPos);
3987         if (success) {
3988             kDebug() << "RESIZE CLP STRAT TO:" << end.startPos.frames(m_document->fps()) << ", OLD ST: " << start.startPos.frames(25);
3989             item->resizeStart((int) end.startPos.frames(m_document->fps()));
3990             updatePositionEffects(item, clipinfo);
3991         } else emit displayMessage(i18n("Error when resizing clip"), ErrorMessage);
3992     } else {
3993         ItemInfo clipinfo = item->info();
3994         clipinfo.track = m_document->tracksCount() - clipinfo.track;
3995         bool success = m_document->renderer()->mltResizeClipEnd(clipinfo, end.endPos - clipinfo.startPos);
3996         if (success) {
3997             item->resizeEnd((int) end.endPos.frames(m_document->fps()));
3998             updatePositionEffects(item, clipinfo);
3999         } else emit displayMessage(i18n("Error when resizing clip"), ErrorMessage);
4000     }
4001     if (!resizeClipStart && end.cropStart != start.cropStart) {
4002         kDebug() << "// RESIZE CROP, DIFF: " << (end.cropStart - start.cropStart).frames(25);
4003         ItemInfo clipinfo = end;
4004         clipinfo.track = m_document->tracksCount() - end.track;
4005         bool success = m_document->renderer()->mltResizeClipCrop(clipinfo, end.cropStart - start.cropStart);
4006         if (success) {
4007             item->setCropStart(end.cropStart);
4008             item->resetThumbs(true);
4009         }
4010     }
4011     m_document->renderer()->doRefresh();
4012     KdenliveSettings::setSnaptopoints(snap);
4013     setDocumentModified();
4014 }
4015
4016 void CustomTrackView::updatePositionEffects(ClipItem * item, ItemInfo info)
4017 {
4018     int end = item->fadeIn();
4019     if (end != 0) {
4020         // there is a fade in effect
4021         int effectPos = item->hasEffect("volume", "fadein");
4022         if (effectPos != -1) {
4023             QDomElement oldeffect = item->effectAt(effectPos);
4024             int start = item->cropStart().frames(m_document->fps());
4025             int max = item->cropDuration().frames(m_document->fps());
4026             if (end > max) {
4027                 // Make sure the fade effect is not longer than the clip
4028                 item->setFadeIn(max);
4029                 end = item->fadeIn();
4030             }
4031             end += start;
4032             EffectsList::setParameter(oldeffect, "in", QString::number(start));
4033             EffectsList::setParameter(oldeffect, "out", QString::number(end));
4034             if (!m_document->renderer()->mltEditEffect(m_document->tracksCount() - item->track(), item->startPos(), item->getEffectArgs(oldeffect)))
4035                 emit displayMessage(i18n("Problem editing effect"), ErrorMessage);
4036             // if fade effect is displayed, update the effect edit widget with new clip duration
4037             if (item->isSelected() && effectPos == item->selectedEffectIndex()) emit clipItemSelected(item, effectPos);
4038         }
4039         effectPos = item->hasEffect("brightness", "fade_from_black");
4040         if (effectPos != -1) {
4041             QDomElement oldeffect = item->effectAt(effectPos);
4042             int start = item->cropStart().frames(m_document->fps());
4043             int max = item->cropDuration().frames(m_document->fps());
4044             if (end > max) {
4045                 // Make sure the fade effect is not longer than the clip
4046                 item->setFadeIn(max);
4047                 end = item->fadeIn();
4048             }
4049             end += start;
4050             EffectsList::setParameter(oldeffect, "in", QString::number(start));
4051             EffectsList::setParameter(oldeffect, "out", QString::number(end));
4052             if (!m_document->renderer()->mltEditEffect(m_document->tracksCount() - item->track(), item->startPos(), item->getEffectArgs(oldeffect)))
4053                 emit displayMessage(i18n("Problem editing effect"), ErrorMessage);
4054             // if fade effect is displayed, update the effect edit widget with new clip duration
4055             if (item->isSelected() && effectPos == item->selectedEffectIndex()) emit clipItemSelected(item, effectPos);
4056         }
4057     }
4058     int start = item->fadeOut();
4059     if (start != 0) {
4060         // there is a fade out effect
4061         int effectPos = item->hasEffect("volume", "fadeout");
4062         if (effectPos != -1) {
4063             QDomElement oldeffect = item->effectAt(effectPos);
4064             int max = item->cropDuration().frames(m_document->fps());
4065             int end = max + item->cropStart().frames(m_document->fps());
4066             if (start > max) {
4067                 // Make sure the fade effect is not longer than the clip
4068                 item->setFadeOut(max);
4069                 start = item->fadeOut();
4070             }
4071             start = end - start;
4072             EffectsList::setParameter(oldeffect, "in", QString::number(start));
4073             EffectsList::setParameter(oldeffect, "out", QString::number(end));
4074             if (!m_document->renderer()->mltEditEffect(m_document->tracksCount() - item->track(), item->startPos(), item->getEffectArgs(oldeffect)))
4075                 emit displayMessage(i18n("Problem editing effect"), ErrorMessage);
4076             // if fade effect is displayed, update the effect edit widget with new clip duration
4077             if (item->isSelected() && effectPos == item->selectedEffectIndex()) emit clipItemSelected(item, effectPos);
4078         }
4079         effectPos = item->hasEffect("brightness", "fade_to_black");
4080         if (effectPos != -1) {
4081             QDomElement oldeffect = item->effectAt(effectPos);
4082             int max = item->cropDuration().frames(m_document->fps());
4083             int end = max + item->cropStart().frames(m_document->fps());
4084             if (start > max) {
4085                 // Make sure the fade effect is not longer than the clip
4086                 item->setFadeOut(max);
4087                 start = item->fadeOut();
4088             }
4089             start = end - start;
4090             EffectsList::setParameter(oldeffect, "in", QString::number(start));
4091             EffectsList::setParameter(oldeffect, "out", QString::number(end));
4092             if (!m_document->renderer()->mltEditEffect(m_document->tracksCount() - item->track(), item->startPos(), item->getEffectArgs(oldeffect)))
4093                 emit displayMessage(i18n("Problem editing effect"), ErrorMessage);
4094             // if fade effect is displayed, update the effect edit widget with new clip duration
4095             if (item->isSelected() && effectPos == item->selectedEffectIndex()) emit clipItemSelected(item, effectPos);
4096         }
4097     }
4098
4099     int effectPos = item->hasEffect("freeze", "freeze");
4100     if (effectPos != -1) {
4101         // Freeze effect needs to be adjusted with clip resize
4102         int diff = (info.startPos - item->startPos()).frames(m_document->fps());
4103         QDomElement eff = item->getEffectAt(effectPos);
4104         if (!eff.isNull() && diff != 0) {
4105             int freeze_pos = EffectsList::parameter(eff, "frame").toInt() + diff;
4106             EffectsList::setParameter(eff, "frame", QString::number(freeze_pos));
4107             if (item->isSelected() && item->selectedEffect().attribute("id") == "freeze") {
4108                 emit clipItemSelected(item, item->selectedEffectIndex());
4109             }
4110         }
4111     }
4112 }
4113
4114 double CustomTrackView::getSnapPointForPos(double pos)
4115 {
4116     return m_scene->getSnapPointForPos(pos, KdenliveSettings::snaptopoints());
4117 }
4118
4119 void CustomTrackView::updateSnapPoints(AbstractClipItem *selected, QList <GenTime> offsetList, bool skipSelectedItems)
4120 {
4121     QList <GenTime> snaps;
4122     if (selected && offsetList.isEmpty()) offsetList.append(selected->cropDuration());
4123     QList<QGraphicsItem *> itemList = items();
4124     for (int i = 0; i < itemList.count(); i++) {
4125         if (itemList.at(i) == selected) continue;
4126         if (skipSelectedItems && itemList.at(i)->isSelected()) continue;
4127         if (itemList.at(i)->type() == AVWIDGET) {
4128             ClipItem *item = static_cast <ClipItem *>(itemList.at(i));
4129             GenTime start = item->startPos();
4130             GenTime end = item->endPos();
4131             snaps.append(start);
4132             snaps.append(end);
4133             if (!offsetList.isEmpty()) {
4134                 for (int j = 0; j < offsetList.size(); j++) {
4135                     if (start > offsetList.at(j)) snaps.append(start - offsetList.at(j));
4136                     if (end > offsetList.at(j)) snaps.append(end - offsetList.at(j));
4137                 }
4138             }
4139             // Add clip markers
4140             QList < GenTime > markers = item->snapMarkers();
4141             for (int j = 0; j < markers.size(); ++j) {
4142                 GenTime t = markers.at(j);
4143                 snaps.append(t);
4144                 if (!offsetList.isEmpty()) {
4145                     for (int k = 0; k < offsetList.size(); k++) {
4146                         if (t > offsetList.at(k)) snaps.append(t - offsetList.at(k));
4147                     }
4148                 }
4149             }
4150         } else if (itemList.at(i)->type() == TRANSITIONWIDGET) {
4151             Transition *transition = static_cast <Transition*>(itemList.at(i));
4152             GenTime start = transition->startPos();
4153             GenTime end = transition->endPos();
4154             snaps.append(start);
4155             snaps.append(end);
4156             if (!offsetList.isEmpty()) {
4157                 for (int j = 0; j < offsetList.size(); j++) {
4158                     if (start > offsetList.at(j)) snaps.append(start - offsetList.at(j));
4159                     if (end > offsetList.at(j)) snaps.append(end - offsetList.at(j));
4160                 }
4161             }
4162         }
4163     }
4164
4165     // add cursor position
4166     GenTime pos = GenTime(m_cursorPos, m_document->fps());
4167     snaps.append(pos);
4168     if (!offsetList.isEmpty()) {
4169         for (int j = 0; j < offsetList.size(); j++) {
4170             snaps.append(pos - offsetList.at(j));
4171         }
4172     }
4173
4174     // add guides
4175     for (int i = 0; i < m_guides.count(); i++) {
4176         snaps.append(m_guides.at(i)->position());
4177         if (!offsetList.isEmpty()) {
4178             for (int j = 0; j < offsetList.size(); j++) {
4179                 snaps.append(m_guides.at(i)->position() - offsetList.at(j));
4180             }
4181         }
4182     }
4183
4184     qSort(snaps);
4185     m_scene->setSnapList(snaps);
4186     //for (int i = 0; i < m_snapPoints.size(); ++i)
4187     //    kDebug() << "SNAP POINT: " << m_snapPoints.at(i).frames(25);
4188 }
4189
4190 void CustomTrackView::slotSeekToPreviousSnap()
4191 {
4192     updateSnapPoints(NULL);
4193     GenTime res = m_scene->previousSnapPoint(GenTime(m_cursorPos, m_document->fps()));
4194     setCursorPos((int) res.frames(m_document->fps()));
4195     checkScrolling();
4196 }
4197
4198 void CustomTrackView::slotSeekToNextSnap()
4199 {
4200     updateSnapPoints(NULL);
4201     GenTime res = m_scene->nextSnapPoint(GenTime(m_cursorPos, m_document->fps()));
4202     setCursorPos((int) res.frames(m_document->fps()));
4203     checkScrolling();
4204 }
4205
4206 void CustomTrackView::clipStart()
4207 {
4208     AbstractClipItem *item = getMainActiveClip();
4209     if (item != NULL) {
4210         setCursorPos((int) item->startPos().frames(m_document->fps()));
4211         checkScrolling();
4212     }
4213 }
4214
4215 void CustomTrackView::clipEnd()
4216 {
4217     AbstractClipItem *item = getMainActiveClip();
4218     if (item != NULL) {
4219         setCursorPos((int) item->endPos().frames(m_document->fps()) - 1);
4220         checkScrolling();
4221     }
4222 }
4223
4224 void CustomTrackView::slotAddClipMarker(const QString &id, GenTime t, QString c)
4225 {
4226     QString oldcomment = m_document->clipManager()->getClipById(id)->markerComment(t);
4227     AddMarkerCommand *command = new AddMarkerCommand(this, oldcomment, c, id, t);
4228     m_commandStack->push(command);
4229 }
4230
4231 void CustomTrackView::slotDeleteClipMarker(const QString &comment, const QString &id, const GenTime &position)
4232 {
4233     AddMarkerCommand *command = new AddMarkerCommand(this, comment, QString(), id, position);
4234     m_commandStack->push(command);
4235 }
4236
4237 void CustomTrackView::slotDeleteAllClipMarkers(const QString &id)
4238 {
4239     DocClipBase *base = m_document->clipManager()->getClipById(id);
4240     QList <CommentedTime> markers = base->commentedSnapMarkers();
4241
4242     if (markers.isEmpty()) {
4243         emit displayMessage(i18n("Clip has no markers"), ErrorMessage);
4244         return;
4245     }
4246     QUndoCommand *deleteMarkers = new QUndoCommand();
4247     deleteMarkers->setText("Delete clip markers");
4248
4249     for (int i = 0; i < markers.size(); i++) {
4250         new AddMarkerCommand(this, markers.at(i).comment(), QString(), id, markers.at(i).time(), deleteMarkers);
4251     }
4252     m_commandStack->push(deleteMarkers);
4253 }
4254
4255 void CustomTrackView::addMarker(const QString &id, const GenTime &pos, const QString comment)
4256 {
4257     DocClipBase *base = m_document->clipManager()->getClipById(id);
4258     if (!comment.isEmpty()) base->addSnapMarker(pos, comment);
4259     else base->deleteSnapMarker(pos);
4260     emit updateClipMarkers(base);
4261     setDocumentModified();
4262     viewport()->update();
4263 }
4264
4265 int CustomTrackView::hasGuide(int pos, int offset)
4266 {
4267     for (int i = 0; i < m_guides.count(); i++) {
4268         int guidePos = m_guides.at(i)->position().frames(m_document->fps());
4269         if (qAbs(guidePos - pos) <= offset) return guidePos;
4270         else if (guidePos > pos) return -1;
4271     }
4272     return -1;
4273 }
4274
4275 void CustomTrackView::editGuide(const GenTime oldPos, const GenTime pos, const QString &comment)
4276 {
4277     if (oldPos > GenTime() && pos > GenTime()) {
4278         // move guide
4279         for (int i = 0; i < m_guides.count(); i++) {
4280             if (m_guides.at(i)->position() == oldPos) {
4281                 Guide *item = m_guides.at(i);
4282                 item->updateGuide(pos, comment);
4283                 break;
4284             }
4285         }
4286     } else if (pos > GenTime()) addGuide(pos, comment);
4287     else {
4288         // remove guide
4289         bool found = false;
4290         for (int i = 0; i < m_guides.count(); i++) {
4291             if (m_guides.at(i)->position() == oldPos) {
4292                 delete m_guides.takeAt(i);
4293                 found = true;
4294                 break;
4295             }
4296         }
4297         if (!found) emit displayMessage(i18n("No guide at cursor time"), ErrorMessage);
4298     }
4299     qSort(m_guides.begin(), m_guides.end(), sortGuidesList);
4300     m_document->syncGuides(m_guides);
4301 }
4302
4303 bool CustomTrackView::addGuide(const GenTime pos, const QString &comment)
4304 {
4305     for (int i = 0; i < m_guides.count(); i++) {
4306         if (m_guides.at(i)->position() == pos) {
4307             emit displayMessage(i18n("A guide already exists at position %1", m_document->timecode().getTimecodeFromFrames(pos.frames(m_document->fps()))), ErrorMessage);
4308             return false;
4309         }
4310     }
4311     Guide *g = new Guide(this, pos, comment, m_tracksHeight * m_document->tracksCount());
4312     scene()->addItem(g);
4313     m_guides.append(g);
4314     qSort(m_guides.begin(), m_guides.end(), sortGuidesList);
4315     m_document->syncGuides(m_guides);
4316     return true;
4317 }
4318
4319 void CustomTrackView::slotAddGuide()
4320 {
4321     CommentedTime marker(GenTime(m_cursorPos, m_document->fps()), i18n("Guide"));
4322     MarkerDialog d(NULL, marker, m_document->timecode(), i18n("Add Guide"), this);
4323     if (d.exec() != QDialog::Accepted) return;
4324     if (addGuide(d.newMarker().time(), d.newMarker().comment())) {
4325         EditGuideCommand *command = new EditGuideCommand(this, GenTime(), QString(), d.newMarker().time(), d.newMarker().comment(), false);
4326         m_commandStack->push(command);
4327     }
4328 }
4329
4330 void CustomTrackView::slotEditGuide(int guidePos)
4331 {
4332     GenTime pos;
4333     if (guidePos == -1) pos = GenTime(m_cursorPos, m_document->fps());
4334     else pos = GenTime(guidePos, m_document->fps());
4335     bool found = false;
4336     for (int i = 0; i < m_guides.count(); i++) {
4337         if (m_guides.at(i)->position() == pos) {
4338             slotEditGuide(m_guides.at(i)->info());
4339             found = true;
4340             break;
4341         }
4342     }
4343     if (!found) emit displayMessage(i18n("No guide at cursor time"), ErrorMessage);
4344 }
4345
4346 void CustomTrackView::slotEditGuide(CommentedTime guide)
4347 {
4348     MarkerDialog d(NULL, guide, m_document->timecode(), i18n("Edit Guide"), this);
4349     if (d.exec() == QDialog::Accepted) {
4350         EditGuideCommand *command = new EditGuideCommand(this, guide.time(), guide.comment(), d.newMarker().time(), d.newMarker().comment(), true);
4351         m_commandStack->push(command);
4352     }
4353 }
4354
4355
4356 void CustomTrackView::slotEditTimeLineGuide()
4357 {
4358     if (m_dragGuide == NULL) return;
4359     CommentedTime guide = m_dragGuide->info();
4360     MarkerDialog d(NULL, guide, m_document->timecode(), i18n("Edit Guide"), this);
4361     if (d.exec() == QDialog::Accepted) {
4362         EditGuideCommand *command = new EditGuideCommand(this, guide.time(), guide.comment(), d.newMarker().time(), d.newMarker().comment(), true);
4363         m_commandStack->push(command);
4364     }
4365 }
4366
4367 void CustomTrackView::slotDeleteGuide(int guidePos)
4368 {
4369     GenTime pos;
4370     if (guidePos == -1) pos = GenTime(m_cursorPos, m_document->fps());
4371     else pos = GenTime(guidePos, m_document->fps());
4372     bool found = false;
4373     for (int i = 0; i < m_guides.count(); i++) {
4374         if (m_guides.at(i)->position() == pos) {
4375             EditGuideCommand *command = new EditGuideCommand(this, m_guides.at(i)->position(), m_guides.at(i)->label(), GenTime(), QString(), true);
4376             m_commandStack->push(command);
4377             found = true;
4378             break;
4379         }
4380     }
4381     if (!found) emit displayMessage(i18n("No guide at cursor time"), ErrorMessage);
4382 }
4383
4384
4385 void CustomTrackView::slotDeleteTimeLineGuide()
4386 {
4387     if (m_dragGuide == NULL) return;
4388     EditGuideCommand *command = new EditGuideCommand(this, m_dragGuide->position(), m_dragGuide->label(), GenTime(), QString(), true);
4389     m_commandStack->push(command);
4390 }
4391
4392
4393 void CustomTrackView::slotDeleteAllGuides()
4394 {
4395     QUndoCommand *deleteAll = new QUndoCommand();
4396     deleteAll->setText("Delete all guides");
4397     for (int i = 0; i < m_guides.count(); i++) {
4398         new EditGuideCommand(this, m_guides.at(i)->position(), m_guides.at(i)->label(), GenTime(), QString(), true, deleteAll);
4399     }
4400     m_commandStack->push(deleteAll);
4401 }
4402
4403 void CustomTrackView::setTool(PROJECTTOOL tool)
4404 {
4405     m_tool = tool;
4406 }
4407
4408 void CustomTrackView::setScale(double scaleFactor, double verticalScale)
4409 {
4410     QMatrix matrix;
4411     matrix = matrix.scale(scaleFactor, verticalScale);
4412     m_scene->setScale(scaleFactor, verticalScale);
4413     if (m_visualTip) {
4414         scene()->removeItem(m_visualTip);
4415         m_animationTimer->stop();
4416         delete m_animation;
4417         m_animation = NULL;
4418         delete m_visualTip;
4419         m_visualTip = NULL;
4420     }
4421     double verticalPos = mapToScene(QPoint(0, viewport()->height() / 2)).y();
4422     setMatrix(matrix);
4423     m_cursorLine->setLine(m_cursorLine->line().x1(), 0, m_cursorLine->line().x1(), m_tracksHeight * m_document->tracksCount() * verticalScale);
4424     int diff = sceneRect().width() - m_projectDuration;
4425     if (diff * matrix.m11() < 50) {
4426         if (matrix.m11() < 0.4) setSceneRect(0, 0, (m_projectDuration + 100 / matrix.m11()), sceneRect().height());
4427         else setSceneRect(0, 0, (m_projectDuration + 300), sceneRect().height());
4428     }
4429     centerOn(QPointF(cursorPos(), verticalPos));
4430 }
4431
4432 void CustomTrackView::slotRefreshGuides()
4433 {
4434     if (KdenliveSettings::showmarkers()) {
4435         for (int i = 0; i < m_guides.count(); i++) {
4436             m_guides.at(i)->update();
4437         }
4438     }
4439 }
4440
4441 void CustomTrackView::drawBackground(QPainter * painter, const QRectF &rect)
4442 {
4443     //kDebug() << "// DRAW BG: " << rect.width();
4444     painter->setClipRect(rect);
4445     KColorScheme scheme(palette().currentColorGroup(), KColorScheme::Window);
4446     QPen pen1 = painter->pen();
4447     pen1.setColor(scheme.shade(KColorScheme::DarkShade));
4448     painter->setPen(pen1);
4449     double min = rect.left();
4450     double max = rect.right();
4451     painter->drawLine(QPointF(min, 0), QPointF(max, 0));
4452     int maxTrack = m_document->tracksCount();
4453     QColor lockedColor = scheme.background(KColorScheme::NegativeBackground).color();
4454     QColor audioColor = palette().alternateBase().color();
4455     QColor base = scheme.background(KColorScheme::NormalBackground).color();
4456     for (int i = 0; i < maxTrack; i++) {
4457         TrackInfo info = m_document->trackInfoAt(maxTrack - i - 1);
4458         if (info.isLocked || info.type == AUDIOTRACK || i == m_selectedTrack) {
4459             const QRectF track(min, m_tracksHeight * i + 1, max - min, m_tracksHeight - 1);
4460             if (i == m_selectedTrack) painter->fillRect(track, scheme.background(KColorScheme::ActiveBackground).color());
4461             else painter->fillRect(track, info.isLocked ? lockedColor : audioColor);
4462         }
4463         painter->drawLine(QPointF(min, m_tracksHeight *(i + 1)), QPointF(max, m_tracksHeight *(i + 1)));
4464     }
4465     int lowerLimit = m_tracksHeight * maxTrack + 1;
4466     if (height() > lowerLimit) {
4467         const QRectF bg(min, lowerLimit, max - min, height() - lowerLimit);
4468         painter->fillRect(bg, base);
4469     }
4470 }
4471
4472 bool CustomTrackView::findString(const QString &text)
4473 {
4474     QString marker;
4475     for (int i = 0; i < m_searchPoints.size(); ++i) {
4476         marker = m_searchPoints.at(i).comment();
4477         if (marker.contains(text, Qt::CaseInsensitive)) {
4478             setCursorPos(m_searchPoints.at(i).time().frames(m_document->fps()), true);
4479             int vert = verticalScrollBar()->value();
4480             int hor = cursorPos();
4481             ensureVisible(hor, vert + 10, 2, 2, 50, 0);
4482             m_findIndex = i;
4483             return true;
4484         }
4485     }
4486     return false;
4487 }
4488
4489 bool CustomTrackView::findNextString(const QString &text)
4490 {
4491     QString marker;
4492     for (int i = m_findIndex + 1; i < m_searchPoints.size(); ++i) {
4493         marker = m_searchPoints.at(i).comment();
4494         if (marker.contains(text, Qt::CaseInsensitive)) {
4495             setCursorPos(m_searchPoints.at(i).time().frames(m_document->fps()), true);
4496             int vert = verticalScrollBar()->value();
4497             int hor = cursorPos();
4498             ensureVisible(hor, vert + 10, 2, 2, 50, 0);
4499             m_findIndex = i;
4500             return true;
4501         }
4502     }
4503     m_findIndex = -1;
4504     return false;
4505 }
4506
4507 void CustomTrackView::initSearchStrings()
4508 {
4509     m_searchPoints.clear();
4510     QList<QGraphicsItem *> itemList = items();
4511     for (int i = 0; i < itemList.count(); i++) {
4512         // parse all clip names
4513         if (itemList.at(i)->type() == AVWIDGET) {
4514             ClipItem *item = static_cast <ClipItem *>(itemList.at(i));
4515             GenTime start = item->startPos();
4516             CommentedTime t(start, item->clipName());
4517             m_searchPoints.append(t);
4518             // add all clip markers
4519             QList < CommentedTime > markers = item->commentedSnapMarkers();
4520             m_searchPoints += markers;
4521         }
4522     }
4523
4524     // add guides
4525     for (int i = 0; i < m_guides.count(); i++) {
4526         m_searchPoints.append(m_guides.at(i)->info());
4527     }
4528
4529     qSort(m_searchPoints);
4530 }
4531
4532 void CustomTrackView::clearSearchStrings()
4533 {
4534     m_searchPoints.clear();
4535     m_findIndex = 0;
4536 }
4537
4538 void CustomTrackView::copyClip()
4539 {
4540     qDeleteAll(m_copiedItems);
4541     m_copiedItems.clear();
4542     QList<QGraphicsItem *> itemList = scene()->selectedItems();
4543     if (itemList.count() == 0) {
4544         emit displayMessage(i18n("Select a clip before copying"), ErrorMessage);
4545         return;
4546     }
4547     for (int i = 0; i < itemList.count(); i++) {
4548         if (itemList.at(i)->type() == AVWIDGET) {
4549             ClipItem *clip = static_cast <ClipItem *>(itemList.at(i));
4550             ClipItem *clone = clip->clone(clip->info());
4551             m_copiedItems.append(clone);
4552         } else if (itemList.at(i)->type() == TRANSITIONWIDGET) {
4553             Transition *dup = static_cast <Transition *>(itemList.at(i));
4554             m_copiedItems.append(dup->clone());
4555         }
4556     }
4557 }
4558
4559 bool CustomTrackView::canBePastedTo(ItemInfo info, int type) const
4560 {
4561     if (m_scene->editMode() != NORMALEDIT) {
4562         // If we are in overwrite mode, always allow the move
4563         return true;
4564     }
4565     QRectF rect((double) info.startPos.frames(m_document->fps()), (double)(info.track * m_tracksHeight + 1), (double)(info.endPos - info.startPos).frames(m_document->fps()), (double)(m_tracksHeight - 1));
4566     QList<QGraphicsItem *> collisions = scene()->items(rect, Qt::IntersectsItemBoundingRect);
4567     for (int i = 0; i < collisions.count(); i++) {
4568         if (collisions.at(i)->type() == type) return false;
4569     }
4570     return true;
4571 }
4572
4573 bool CustomTrackView::canBePastedTo(QList <ItemInfo> infoList, int type) const
4574 {
4575     QPainterPath path;
4576     for (int i = 0; i < infoList.count(); i++) {
4577         const QRectF rect((double) infoList.at(i).startPos.frames(m_document->fps()), (double)(infoList.at(i).track * m_tracksHeight + 1), (double)(infoList.at(i).endPos - infoList.at(i).startPos).frames(m_document->fps()), (double)(m_tracksHeight - 1));
4578         path.addRect(rect);
4579     }
4580     QList<QGraphicsItem *> collisions = scene()->items(path);
4581     for (int i = 0; i < collisions.count(); i++) {
4582         if (collisions.at(i)->type() == type) return false;
4583     }
4584     return true;
4585 }
4586
4587 bool CustomTrackView::canBePasted(QList<AbstractClipItem *> items, GenTime offset, int trackOffset) const
4588 {
4589     for (int i = 0; i < items.count(); i++) {
4590         ItemInfo info = items.at(i)->info();
4591         info.startPos += offset;
4592         info.endPos += offset;
4593         info.track += trackOffset;
4594         if (!canBePastedTo(info, items.at(i)->type())) return false;
4595     }
4596     return true;
4597 }
4598
4599 bool CustomTrackView::canBeMoved(QList<AbstractClipItem *> items, GenTime offset, int trackOffset) const
4600 {
4601     QPainterPath movePath;
4602     movePath.moveTo(0, 0);
4603
4604     for (int i = 0; i < items.count(); i++) {
4605         ItemInfo info = items.at(i)->info();
4606         info.startPos = info.startPos + offset;
4607         info.endPos = info.endPos + offset;
4608         info.track = info.track + trackOffset;
4609         if (info.startPos < GenTime()) {
4610             // No clip should go below 0
4611             return false;
4612         }
4613         QRectF rect((double) info.startPos.frames(m_document->fps()), (double)(info.track * m_tracksHeight + 1), (double)(info.endPos - info.startPos).frames(m_document->fps()), (double)(m_tracksHeight - 1));
4614         movePath.addRect(rect);
4615     }
4616     QList<QGraphicsItem *> collisions = scene()->items(movePath, Qt::IntersectsItemBoundingRect);
4617     for (int i = 0; i < collisions.count(); i++) {
4618         if ((collisions.at(i)->type() == AVWIDGET || collisions.at(i)->type() == TRANSITIONWIDGET) && !items.contains(static_cast <AbstractClipItem *>(collisions.at(i)))) {
4619             kDebug() << "  ////////////   CLIP COLLISION, MOVE NOT ALLOWED";
4620             return false;
4621         }
4622     }
4623     return true;
4624 }
4625
4626 void CustomTrackView::pasteClip()
4627 {
4628     if (m_copiedItems.count() == 0) {
4629         emit displayMessage(i18n("No clip copied"), ErrorMessage);
4630         return;
4631     }
4632     QPoint position;
4633     if (m_menuPosition.isNull()) {
4634         position = mapFromGlobal(QCursor::pos());
4635         if (!underMouse() || position.y() > m_tracksHeight * m_document->tracksCount()) {
4636             emit displayMessage(i18n("Cannot paste selected clips"), ErrorMessage);
4637             return;
4638         }
4639     } else position = m_menuPosition;
4640     GenTime pos = GenTime((int)(mapToScene(position).x()), m_document->fps());
4641     int track = (int)(position.y() / m_tracksHeight);
4642     ItemInfo first = m_copiedItems.at(0)->info();
4643
4644     GenTime offset = pos - first.startPos;
4645     int trackOffset = track - first.track;
4646
4647     if (!canBePasted(m_copiedItems, offset, trackOffset)) {
4648         emit displayMessage(i18n("Cannot paste selected clips"), ErrorMessage);
4649         return;
4650     }
4651     QUndoCommand *pasteClips = new QUndoCommand();
4652     pasteClips->setText("Paste clips");
4653
4654     for (int i = 0; i < m_copiedItems.count(); i++) {
4655         // parse all clip names
4656         if (m_copiedItems.at(i) && m_copiedItems.at(i)->type() == AVWIDGET) {
4657             ClipItem *clip = static_cast <ClipItem *>(m_copiedItems.at(i));
4658             ItemInfo info = clip->info();
4659             info.startPos += offset;
4660             info.endPos += offset;
4661             info.track += trackOffset;
4662             if (canBePastedTo(info, AVWIDGET)) {
4663                 new AddTimelineClipCommand(this, clip->xml(), clip->clipProducer(), info, clip->effectList(), m_scene->editMode() == OVERWRITEEDIT, m_scene->editMode() == INSERTEDIT, true, false, pasteClips);
4664             } else emit displayMessage(i18n("Cannot paste clip to selected place"), ErrorMessage);
4665         } else if (m_copiedItems.at(i) && m_copiedItems.at(i)->type() == TRANSITIONWIDGET) {
4666             Transition *tr = static_cast <Transition *>(m_copiedItems.at(i));
4667             ItemInfo info;
4668             info.startPos = tr->startPos() + offset;
4669             info.endPos = tr->endPos() + offset;
4670             info.track = tr->track() + trackOffset;
4671             int transitionEndTrack;
4672             if (!tr->forcedTrack()) transitionEndTrack = getPreviousVideoTrack(info.track);
4673             else transitionEndTrack = tr->transitionEndTrack();
4674             if (canBePastedTo(info, TRANSITIONWIDGET)) {
4675                 if (info.startPos >= info.endPos) {
4676                     emit displayMessage(i18n("Invalid transition"), ErrorMessage);
4677                 } else new AddTransitionCommand(this, info, transitionEndTrack, tr->toXML(), false, true, pasteClips);
4678             } else emit displayMessage(i18n("Cannot paste transition to selected place"), ErrorMessage);
4679         }
4680     }
4681     m_commandStack->push(pasteClips);
4682 }
4683
4684 void CustomTrackView::pasteClipEffects()
4685 {
4686     if (m_copiedItems.count() != 1 || m_copiedItems.at(0)->type() != AVWIDGET) {
4687         emit displayMessage(i18n("You must copy exactly one clip before pasting effects"), ErrorMessage);
4688         return;
4689     }
4690     ClipItem *clip = static_cast < ClipItem *>(m_copiedItems.at(0));
4691
4692     QUndoCommand *paste = new QUndoCommand();
4693     paste->setText("Paste effects");
4694
4695     QList<QGraphicsItem *> clips = scene()->selectedItems();
4696     for (int i = 0; i < clips.count(); ++i) {
4697         if (clips.at(i)->type() == AVWIDGET) {
4698             ClipItem *item = static_cast < ClipItem *>(clips.at(i));
4699             for (int j = 0; j < clip->effectsCount(); j++) {
4700                 QDomElement eff = clip->effectAt(j);
4701                 if (eff.attribute("unique", "0") == "0" || item->hasEffect(eff.attribute("tag"), eff.attribute("id")) == -1) {
4702                     new AddEffectCommand(this, m_document->tracksCount() - item->track(), item->startPos(), eff, true, paste);
4703                 }
4704             }
4705         }
4706     }
4707     m_commandStack->push(paste);
4708
4709     // adjust effects (fades, ...)
4710     for (int i = 0; i < clips.count(); ++i) {
4711         ClipItem *item = static_cast < ClipItem *>(clips.at(i));
4712         updatePositionEffects(item, item->info());
4713     }
4714 }
4715
4716
4717 ClipItem *CustomTrackView::getClipUnderCursor() const
4718 {
4719     QRectF rect((double) m_cursorPos, 0.0, 1.0, (double)(m_tracksHeight * m_document->tracksCount()));
4720     QList<QGraphicsItem *> collisions = scene()->items(rect, Qt::IntersectsItemBoundingRect);
4721     for (int i = 0; i < collisions.count(); i++) {
4722         if (collisions.at(i)->type() == AVWIDGET) {
4723             return static_cast < ClipItem *>(collisions.at(i));
4724         }
4725     }
4726     return NULL;
4727 }
4728
4729 AbstractClipItem *CustomTrackView::getMainActiveClip() const
4730 {
4731     QList<QGraphicsItem *> clips = scene()->selectedItems();
4732     if (clips.isEmpty()) {
4733         return getClipUnderCursor();
4734     } else {
4735         AbstractClipItem *item = NULL;
4736         for (int i = 0; i < clips.count(); ++i) {
4737             if (clips.count() == 1 || clips.at(i)->type() == AVWIDGET) {
4738                 item = static_cast < AbstractClipItem *>(clips.at(i));
4739                 if (clips.count() > 1 && item->startPos().frames(m_document->fps()) <= m_cursorPos && item->endPos().frames(m_document->fps()) >= m_cursorPos) break;
4740             }
4741         }
4742         if (item) return item;
4743     }
4744     return NULL;
4745 }
4746
4747 ClipItem *CustomTrackView::getActiveClipUnderCursor(bool allowOutsideCursor) const
4748 {
4749     QList<QGraphicsItem *> clips = scene()->selectedItems();
4750     if (clips.isEmpty()) {
4751         return getClipUnderCursor();
4752     } else {
4753         ClipItem *item;
4754         // remove all items in the list that are not clips
4755         for (int i = 0; i < clips.count();) {
4756             if (clips.at(i)->type() != AVWIDGET) clips.removeAt(i);
4757             else i++;
4758         }
4759         if (clips.count() == 1 && allowOutsideCursor) return static_cast < ClipItem *>(clips.at(0));
4760         for (int i = 0; i < clips.count(); ++i) {
4761             if (clips.at(i)->type() == AVWIDGET) {
4762                 item = static_cast < ClipItem *>(clips.at(i));
4763                 if (item->startPos().frames(m_document->fps()) <= m_cursorPos && item->endPos().frames(m_document->fps()) >= m_cursorPos)
4764                     return item;
4765             }
4766         }
4767     }
4768     return NULL;
4769 }
4770
4771 void CustomTrackView::setInPoint()
4772 {
4773     AbstractClipItem *clip = getActiveClipUnderCursor(true);
4774     if (clip == NULL) {
4775         if (m_dragItem && m_dragItem->type() == TRANSITIONWIDGET) {
4776             clip = m_dragItem;
4777         } else {
4778             emit displayMessage(i18n("You must select one clip for this action"), ErrorMessage);
4779             return;
4780         }
4781     }
4782     ItemInfo startInfo = clip->info();
4783     ItemInfo endInfo = startInfo;
4784     endInfo.startPos = GenTime(m_cursorPos, m_document->fps());
4785     if (endInfo.startPos >= startInfo.endPos || endInfo.startPos < startInfo.startPos - startInfo.cropStart) {
4786         // Check for invalid resize
4787         emit displayMessage(i18n("Invalid action"), ErrorMessage);
4788         return;
4789     } else if (endInfo.startPos < startInfo.startPos) {
4790         int length = m_document->renderer()->mltGetSpaceLength(endInfo.startPos, m_document->tracksCount() - startInfo.track, false);
4791         if ((clip->type() == TRANSITIONWIDGET && itemCollision(clip, endInfo) == true) || (
4792                     (clip->type() == AVWIDGET) && length < (startInfo.startPos - endInfo.startPos).frames(m_document->fps()))) {
4793             emit displayMessage(i18n("Invalid action"), ErrorMessage);
4794             return;
4795         }
4796     }
4797     if (clip->type() == TRANSITIONWIDGET) {
4798         m_commandStack->push(new MoveTransitionCommand(this, startInfo, endInfo, true));
4799     } else m_commandStack->push(new ResizeClipCommand(this, startInfo, endInfo, true, false));
4800 }
4801
4802 void CustomTrackView::setOutPoint()
4803 {
4804     AbstractClipItem *clip = getActiveClipUnderCursor(true);
4805     if (clip == NULL) {
4806         if (m_dragItem && m_dragItem->type() == TRANSITIONWIDGET) {
4807             clip = m_dragItem;
4808         } else {
4809             emit displayMessage(i18n("You must select one clip for this action"), ErrorMessage);
4810             return;
4811         }
4812     }
4813     ItemInfo startInfo = clip->info();
4814     ItemInfo endInfo = clip->info();
4815     endInfo.endPos = GenTime(m_cursorPos, m_document->fps());
4816     CLIPTYPE type = (CLIPTYPE) static_cast <ClipItem *>(clip)->clipType();
4817     if (endInfo.endPos <= startInfo.startPos || (type != IMAGE && type != COLOR && type != TEXT && endInfo.endPos > startInfo.startPos + clip->maxDuration() - startInfo.cropStart)) {
4818         // Check for invalid resize
4819         emit displayMessage(i18n("Invalid action"), ErrorMessage);
4820         return;
4821     } else if (endInfo.endPos > startInfo.endPos) {
4822         int length = m_document->renderer()->mltGetSpaceLength(startInfo.endPos, m_document->tracksCount() - startInfo.track, false);
4823         if ((clip->type() == TRANSITIONWIDGET && itemCollision(clip, endInfo) == true) || (clip->type() == AVWIDGET && length != -1 && length < (endInfo.endPos - startInfo.endPos).frames(m_document->fps()))) {
4824             kDebug() << " RESIZE ERROR, BLNK: " << length << ", RESIZE: " << (endInfo.endPos - startInfo.endPos).frames(m_document->fps());
4825             emit displayMessage(i18n("Invalid action"), ErrorMessage);
4826             return;
4827         }
4828     }
4829
4830
4831     if (clip->type() == TRANSITIONWIDGET) {
4832         m_commandStack->push(new MoveTransitionCommand(this, startInfo, endInfo, true));
4833     } else m_commandStack->push(new ResizeClipCommand(this, startInfo, endInfo, true, false));
4834 }
4835
4836 void CustomTrackView::slotUpdateAllThumbs()
4837 {
4838     QList<QGraphicsItem *> itemList = items();
4839     //if (itemList.isEmpty()) return;
4840     ClipItem *item;
4841     const QString thumbBase = m_document->projectFolder().path() + "/thumbs/";
4842     for (int i = 0; i < itemList.count(); i++) {
4843         if (itemList.at(i)->type() == AVWIDGET) {
4844             item = static_cast <ClipItem *>(itemList.at(i));
4845             if (item->clipType() != COLOR && item->clipType() != AUDIO) {
4846                 // Check if we have a cached thumbnail
4847                 if (item->clipType() == IMAGE || item->clipType() == TEXT) {
4848                     QString thumb = thumbBase + item->baseClip()->getClipHash() + "_0.png";
4849                     if (QFile::exists(thumb)) {
4850                         QPixmap pix(thumb);
4851                         item->slotSetStartThumb(pix);
4852                     }
4853                 } else {
4854                     QString startThumb = thumbBase + item->baseClip()->getClipHash() + '_';
4855                     QString endThumb = startThumb;
4856                     startThumb.append(QString::number(item->speedIndependantCropStart().frames(m_document->fps())) + ".png");
4857                     endThumb.append(QString::number((item->speedIndependantCropStart() + item->speedIndependantCropDuration()).frames(m_document->fps()) - 1) + ".png");
4858                     if (QFile::exists(startThumb)) {
4859                         QPixmap pix(startThumb);
4860                         item->slotSetStartThumb(pix);
4861                     }
4862                     if (QFile::exists(endThumb)) {
4863                         QPixmap pix(endThumb);
4864                         item->slotSetEndThumb(pix);
4865                     }
4866                 }
4867             }
4868             item->refreshClip(false);
4869             qApp->processEvents();
4870         }
4871     }
4872     viewport()->update();
4873 }
4874
4875 void CustomTrackView::saveThumbnails()
4876 {
4877     QList<QGraphicsItem *> itemList = items();
4878     ClipItem *item;
4879     QString thumbBase = m_document->projectFolder().path() + "/thumbs/";
4880     for (int i = 0; i < itemList.count(); i++) {
4881         if (itemList.at(i)->type() == AVWIDGET) {
4882             item = static_cast <ClipItem *>(itemList.at(i));
4883             if (item->clipType() != COLOR) {
4884                 // Check if we have a cached thumbnail
4885                 if (item->clipType() == IMAGE || item->clipType() == TEXT || item->clipType() == AUDIO) {
4886                     QString thumb = thumbBase + item->baseClip()->getClipHash() + "_0.png";
4887                     if (!QFile::exists(thumb)) {
4888                         QPixmap pix(item->startThumb());
4889                         pix.save(thumb);
4890                     }
4891                 } else {
4892                     QString startThumb = thumbBase + item->baseClip()->getClipHash() + '_';
4893                     QString endThumb = startThumb;
4894                     startThumb.append(QString::number(item->speedIndependantCropStart().frames(m_document->fps())) + ".png");
4895                     endThumb.append(QString::number((item->speedIndependantCropStart() + item->speedIndependantCropDuration()).frames(m_document->fps()) - 1) + ".png");
4896                     if (!QFile::exists(startThumb)) {
4897                         QPixmap pix(item->startThumb());
4898                         pix.save(startThumb);
4899                     }
4900                     if (!QFile::exists(endThumb)) {
4901                         QPixmap pix(item->endThumb());
4902                         pix.save(endThumb);
4903                     }
4904                 }
4905             }
4906         }
4907     }
4908 }
4909
4910
4911 void CustomTrackView::slotInsertTrack(int ix)
4912 {
4913     TrackDialog d(m_document, parentWidget());
4914     d.label->setText(i18n("Insert track"));
4915     d.track_nb->setMaximum(m_document->tracksCount() - 1);
4916     d.track_nb->setValue(ix);
4917     d.setWindowTitle(i18n("Insert New Track"));
4918     d.slotUpdateName(ix);
4919
4920     if (d.exec() == QDialog::Accepted) {
4921         ix = d.track_nb->value();
4922         if (d.before_select->currentIndex() == 1) {
4923             ix++;
4924         }
4925         TrackInfo info;
4926         if (d.video_track->isChecked()) {
4927             info.type = VIDEOTRACK;
4928             info.isMute = false;
4929             info.isBlind = false;
4930             info.isLocked = false;
4931         } else {
4932             info.type = AUDIOTRACK;
4933             info.isMute = false;
4934             info.isBlind = true;
4935             info.isLocked = false;
4936         }
4937         AddTrackCommand *addTrack = new AddTrackCommand(this, ix, info, true);
4938         m_commandStack->push(addTrack);
4939         setDocumentModified();
4940     }
4941 }
4942
4943 void CustomTrackView::slotDeleteTrack(int ix)
4944 {
4945     TrackDialog d(m_document, parentWidget());
4946     d.label->setText(i18n("Delete track"));
4947     d.before_select->setHidden(true);
4948     d.track_nb->setMaximum(m_document->tracksCount() - 1);
4949     d.track_nb->setValue(ix);
4950     d.slotUpdateName(ix);
4951     d.setWindowTitle(i18n("Delete Track"));
4952     d.video_track->setHidden(true);
4953     d.audio_track->setHidden(true);
4954     if (d.exec() == QDialog::Accepted) {
4955         ix = d.track_nb->value();
4956         TrackInfo info = m_document->trackInfoAt(m_document->tracksCount() - ix - 1);
4957         deleteTimelineTrack(ix, info);
4958         setDocumentModified();
4959         /*AddTrackCommand* command = new AddTrackCommand(this, ix, info, false);
4960         m_commandStack->push(command);*/
4961     }
4962 }
4963
4964 void CustomTrackView::slotChangeTrack(int ix)
4965 {
4966     TrackDialog d(m_document, parentWidget());
4967     d.label->setText(i18n("Change track"));
4968     d.before_select->setHidden(true);
4969     d.track_nb->setMaximum(m_document->tracksCount() - 1);
4970     d.track_nb->setValue(ix);
4971     d.slotUpdateName(ix);
4972     d.setWindowTitle(i18n("Change Track Type"));
4973
4974     if (m_document->trackInfoAt(m_document->tracksCount() - ix - 1).type == VIDEOTRACK)
4975         d.video_track->setChecked(true);
4976     else
4977         d.audio_track->setChecked(true);
4978
4979     if (d.exec() == QDialog::Accepted) {
4980         TrackInfo info;
4981         info.isLocked = false;
4982         info.isMute = false;
4983         ix = d.track_nb->value();
4984
4985         if (d.video_track->isChecked()) {
4986             info.type = VIDEOTRACK;
4987             info.isBlind = false;
4988         } else {
4989             info.type = AUDIOTRACK;
4990             info.isBlind = true;
4991         }
4992         changeTimelineTrack(ix, info);
4993         setDocumentModified();
4994     }
4995 }
4996
4997
4998 void CustomTrackView::deleteTimelineTrack(int ix, TrackInfo trackinfo)
4999 {
5000     double startY = ix * m_tracksHeight + 1 + m_tracksHeight / 2;
5001     QRectF r(0, startY, sceneRect().width(), m_tracksHeight / 2 - 1);
5002     QList<QGraphicsItem *> selection = m_scene->items(r);
5003     QUndoCommand *deleteTrack = new QUndoCommand();
5004     deleteTrack->setText("Delete track");
5005
5006     // Delete all clips in selected track
5007     for (int i = 0; i < selection.count(); i++) {
5008         if (selection.at(i)->type() == AVWIDGET) {
5009             ClipItem *item =  static_cast <ClipItem *>(selection.at(i));
5010             new AddTimelineClipCommand(this, item->xml(), item->clipProducer(), item->info(), item->effectList(), false, false, false, true, deleteTrack);
5011             m_scene->removeItem(item);
5012             delete item;
5013             item = NULL;
5014         } else if (selection.at(i)->type() == TRANSITIONWIDGET) {
5015             Transition *item =  static_cast <Transition *>(selection.at(i));
5016             new AddTransitionCommand(this, item->info(), item->transitionEndTrack(), item->toXML(), true, false, deleteTrack);
5017             m_scene->removeItem(item);
5018             delete item;
5019             item = NULL;
5020         }
5021     }
5022
5023     new AddTrackCommand(this, ix, trackinfo, false, deleteTrack);
5024     m_commandStack->push(deleteTrack);
5025 }
5026
5027 void CustomTrackView::changeTimelineTrack(int ix, TrackInfo trackinfo)
5028 {
5029     TrackInfo oldinfo = m_document->trackInfoAt(m_document->tracksCount() - ix - 1);
5030     ChangeTrackCommand *changeTrack = new ChangeTrackCommand(this, ix, oldinfo, trackinfo);
5031     m_commandStack->push(changeTrack);
5032 }
5033
5034 void CustomTrackView::autoTransition()
5035 {
5036     QList<QGraphicsItem *> itemList = scene()->selectedItems();
5037     if (itemList.count() != 1 || itemList.at(0)->type() != TRANSITIONWIDGET) {
5038         emit displayMessage(i18n("You must select one transition for this action"), ErrorMessage);
5039         return;
5040     }
5041     Transition *tr = static_cast <Transition*>(itemList.at(0));
5042     tr->setAutomatic(!tr->isAutomatic());
5043     QDomElement transition = tr->toXML();
5044     m_document->renderer()->mltUpdateTransition(transition.attribute("tag"), transition.attribute("tag"), transition.attribute("transition_btrack").toInt(), m_document->tracksCount() - transition.attribute("transition_atrack").toInt(), tr->startPos(), tr->endPos(), transition);
5045     setDocumentModified();
5046 }
5047
5048
5049 QStringList CustomTrackView::getLadspaParams(QDomElement effect) const
5050 {
5051     QStringList result;
5052     QDomNodeList params = effect.elementsByTagName("parameter");
5053     for (int i = 0; i < params.count(); i++) {
5054         QDomElement e = params.item(i).toElement();
5055         if (!e.isNull() && e.attribute("type") == "constant") {
5056             if (e.hasAttribute("factor")) {
5057                 double factor = e.attribute("factor").toDouble();
5058                 double value = e.attribute("value").toDouble();
5059                 value = value / factor;
5060                 result.append(QString::number(value));
5061             } else result.append(e.attribute("value"));
5062         }
5063     }
5064     return result;
5065 }
5066
5067 void CustomTrackView::clipNameChanged(const QString id, const QString name)
5068 {
5069     QList<QGraphicsItem *> list = scene()->items();
5070     ClipItem *clip = NULL;
5071     for (int i = 0; i < list.size(); ++i) {
5072         if (list.at(i)->type() == AVWIDGET) {
5073             clip = static_cast <ClipItem *>(list.at(i));
5074             if (clip->clipProducer() == id) {
5075                 clip->setClipName(name);
5076             }
5077         }
5078     }
5079     viewport()->update();
5080 }
5081
5082 void CustomTrackView::getClipAvailableSpace(AbstractClipItem *item, GenTime &minimum, GenTime &maximum)
5083 {
5084     minimum = GenTime();
5085     maximum = GenTime();
5086     QList<QGraphicsItem *> selection;
5087     selection = m_scene->items(0, item->track() * m_tracksHeight + m_tracksHeight / 2, sceneRect().width(), 2);
5088     selection.removeAll(item);
5089     for (int i = 0; i < selection.count(); i++) {
5090         AbstractClipItem *clip = static_cast <AbstractClipItem *>(selection.at(i));
5091         if (clip && clip->type() == AVWIDGET) {
5092             if (clip->endPos() <= item->startPos() && clip->endPos() > minimum) minimum = clip->endPos();
5093             if (clip->startPos() > item->startPos() && (clip->startPos() < maximum || maximum == GenTime())) maximum = clip->startPos();
5094         }
5095     }
5096 }
5097
5098 void CustomTrackView::getTransitionAvailableSpace(AbstractClipItem *item, GenTime &minimum, GenTime &maximum)
5099 {
5100     minimum = GenTime();
5101     maximum = GenTime();
5102     QList<QGraphicsItem *> selection;
5103     selection = m_scene->items(0, (item->track() + 1) * m_tracksHeight, sceneRect().width(), 2);
5104     selection.removeAll(item);
5105     for (int i = 0; i < selection.count(); i++) {
5106         AbstractClipItem *clip = static_cast <AbstractClipItem *>(selection.at(i));
5107         if (clip && clip->type() == TRANSITIONWIDGET) {
5108             if (clip->endPos() <= item->startPos() && clip->endPos() > minimum) minimum = clip->endPos();
5109             if (clip->startPos() > item->startPos() && (clip->startPos() < maximum || maximum == GenTime())) maximum = clip->startPos();
5110         }
5111     }
5112 }
5113
5114
5115 void CustomTrackView::loadGroups(const QDomNodeList groups)
5116 {
5117     for (int i = 0; i < groups.count(); i++) {
5118         QDomNodeList children = groups.at(i).childNodes();
5119         scene()->clearSelection();
5120         for (int nodeindex = 0; nodeindex < children.count(); nodeindex++) {
5121             QDomNode n = children.item(nodeindex);
5122             QDomElement elem = n.toElement();
5123             int pos = elem.attribute("position").toInt();
5124             int track = elem.attribute("track").toInt();
5125             if (elem.tagName() == "clipitem") {
5126                 ClipItem *clip = getClipItemAt(pos, track); //m_document->tracksCount() - transitiontrack);
5127                 if (clip) clip->setSelected(true);
5128             } else {
5129                 Transition *clip = getTransitionItemAt(pos, track); //m_document->tracksCount() - transitiontrack);
5130                 if (clip) clip->setSelected(true);
5131             }
5132         }
5133         groupSelectedItems(false, true);
5134     }
5135 }
5136
5137 void CustomTrackView::splitAudio()
5138 {
5139     resetSelectionGroup();
5140     QList<QGraphicsItem *> selection = scene()->selectedItems();
5141     if (selection.isEmpty()) {
5142         emit displayMessage(i18n("You must select one clip for this action"), ErrorMessage);
5143         return;
5144     }
5145     QUndoCommand *splitCommand = new QUndoCommand();
5146     splitCommand->setText(i18n("Split audio"));
5147     for (int i = 0; i < selection.count(); i++) {
5148         if (selection.at(i)->type() == AVWIDGET) {
5149             ClipItem *clip = static_cast <ClipItem *>(selection.at(i));
5150             if (clip->clipType() == AV || clip->clipType() == PLAYLIST) {
5151                 if (clip->parentItem()) {
5152                     emit displayMessage(i18n("Cannot split audio of grouped clips"), ErrorMessage);
5153                 } else {
5154                     new SplitAudioCommand(this, clip->track(), clip->startPos(), splitCommand);
5155                 }
5156             }
5157         }
5158     }
5159     m_commandStack->push(splitCommand);
5160 }
5161
5162 void CustomTrackView::doSplitAudio(const GenTime &pos, int track, bool split)
5163 {
5164     ClipItem *clip = getClipItemAt(pos, track);
5165     if (clip == NULL) {
5166         kDebug() << "// Cannot find clip to split!!!";
5167         return;
5168     }
5169     if (split) {
5170         int start = pos.frames(m_document->fps());
5171         int freetrack = m_document->tracksCount() - track - 1;
5172         for (; freetrack > 0; freetrack--) {
5173             kDebug() << "// CHK DOC TRK:" << freetrack << ", DUR:" << m_document->renderer()->mltTrackDuration(freetrack);
5174             if (m_document->trackInfoAt(freetrack - 1).type == AUDIOTRACK) {
5175                 kDebug() << "// CHK DOC TRK:" << freetrack << ", DUR:" << m_document->renderer()->mltTrackDuration(freetrack);
5176                 if (m_document->renderer()->mltTrackDuration(freetrack) < start || m_document->renderer()->mltGetSpaceLength(pos, freetrack, false) >= clip->cropDuration().frames(m_document->fps())) {
5177                     kDebug() << "FOUND SPACE ON TRK: " << freetrack;
5178                     break;
5179                 }
5180             }
5181         }
5182         kDebug() << "GOT TRK: " << track;
5183         if (freetrack == 0) {
5184             emit displayMessage(i18n("No empty space to put clip audio"), ErrorMessage);
5185         } else {
5186             ItemInfo info = clip->info();
5187             info.track = m_document->tracksCount() - freetrack;
5188             addClip(clip->xml(), clip->clipProducer(), info, clip->effectList());
5189             scene()->clearSelection();
5190             clip->setSelected(true);
5191             ClipItem *audioClip = getClipItemAt(start, info.track);
5192             if (audioClip) {
5193                 clip->setVideoOnly(true);
5194                 if (m_document->renderer()->mltUpdateClipProducer(m_document->tracksCount() - track, start, clip->baseClip()->videoProducer()) == false) {
5195                     emit displayMessage(i18n("Cannot update clip (time: %1, track: %2)", start, track), ErrorMessage);
5196                 }
5197                 if (m_document->renderer()->mltUpdateClipProducer(m_document->tracksCount() - info.track, start, clip->baseClip()->audioProducer(info.track)) == false) {
5198                     emit displayMessage(i18n("Cannot update clip (time: %1, track: %2)", start, info.track), ErrorMessage);
5199                 }
5200                 audioClip->setSelected(true);
5201                 audioClip->setAudioOnly(true);
5202                 groupSelectedItems(false, true);
5203             }
5204         }
5205     } else {
5206         // unsplit clip: remove audio part and change video part to normal clip
5207         if (clip->parentItem() == NULL || clip->parentItem()->type() != GROUPWIDGET) {
5208             kDebug() << "//CANNOT FIND CLP GRP";
5209             return;
5210         }
5211         AbstractGroupItem *grp = static_cast <AbstractGroupItem *>(clip->parentItem());
5212         QList<QGraphicsItem *> children = grp->childItems();
5213         if (children.count() != 2) {
5214             kDebug() << "//SOMETHING IS WRONG WITH CLP GRP";
5215             return;
5216         }
5217         for (int i = 0; i < children.count(); i++) {
5218             if (children.at(i) != clip) {
5219                 ClipItem *clp = static_cast <ClipItem *>(children.at(i));
5220                 ItemInfo info = clip->info();
5221                 deleteClip(clp->info());
5222                 clip->setVideoOnly(false);
5223                 if (!m_document->renderer()->mltUpdateClipProducer(m_document->tracksCount() - info.track, info.startPos.frames(m_document->fps()), clip->baseClip()->producer(info.track))) {
5224                     emit displayMessage(i18n("Cannot update clip (time: %1, track: %2)", info.startPos.frames(m_document->fps()), info.track), ErrorMessage);
5225                 }
5226                 break;
5227             }
5228         }
5229         clip->setFlag(QGraphicsItem::ItemIsMovable, true);
5230         m_document->clipManager()->removeGroup(grp);
5231         scene()->destroyItemGroup(grp);
5232     }
5233 }
5234
5235 void CustomTrackView::setVideoOnly()
5236 {
5237     resetSelectionGroup();
5238     QList<QGraphicsItem *> selection = scene()->selectedItems();
5239     if (selection.isEmpty()) {
5240         emit displayMessage(i18n("You must select one clip for this action"), ErrorMessage);
5241         return;
5242     }
5243     QUndoCommand *videoCommand = new QUndoCommand();
5244     videoCommand->setText(i18n("Video only"));
5245     for (int i = 0; i < selection.count(); i++) {
5246         if (selection.at(i)->type() == AVWIDGET) {
5247             ClipItem *clip = static_cast <ClipItem *>(selection.at(i));
5248             if (clip->clipType() == AV || clip->clipType() == PLAYLIST) {
5249                 if (clip->parentItem()) {
5250                     emit displayMessage(i18n("Cannot change grouped clips"), ErrorMessage);
5251                 } else {
5252                     new ChangeClipTypeCommand(this, clip->track(), clip->startPos(), true, false, clip->isVideoOnly(), clip->isAudioOnly(), videoCommand);
5253                 }
5254             }
5255         }
5256     }
5257     m_commandStack->push(videoCommand);
5258 }
5259
5260 void CustomTrackView::setAudioOnly()
5261 {
5262     resetSelectionGroup();
5263     QList<QGraphicsItem *> selection = scene()->selectedItems();
5264     if (selection.isEmpty()) {
5265         emit displayMessage(i18n("You must select one clip for this action"), ErrorMessage);
5266         return;
5267     }
5268     QUndoCommand *videoCommand = new QUndoCommand();
5269     videoCommand->setText(i18n("Audio only"));
5270     for (int i = 0; i < selection.count(); i++) {
5271         if (selection.at(i)->type() == AVWIDGET) {
5272             ClipItem *clip = static_cast <ClipItem *>(selection.at(i));
5273             if (clip->clipType() == AV || clip->clipType() == PLAYLIST) {
5274                 if (clip->parentItem()) {
5275                     emit displayMessage(i18n("Cannot change grouped clips"), ErrorMessage);
5276                 } else {
5277                     new ChangeClipTypeCommand(this, clip->track(), clip->startPos(), false, true, clip->isVideoOnly(), clip->isAudioOnly(), videoCommand);
5278                 }
5279             }
5280         }
5281     }
5282     m_commandStack->push(videoCommand);
5283 }
5284
5285 void CustomTrackView::setAudioAndVideo()
5286 {
5287     resetSelectionGroup();
5288     QList<QGraphicsItem *> selection = scene()->selectedItems();
5289     if (selection.isEmpty()) {
5290         emit displayMessage(i18n("You must select one clip for this action"), ErrorMessage);
5291         return;
5292     }
5293     QUndoCommand *videoCommand = new QUndoCommand();
5294     videoCommand->setText(i18n("Audio and Video"));
5295     for (int i = 0; i < selection.count(); i++) {
5296         if (selection.at(i)->type() == AVWIDGET) {
5297             ClipItem *clip = static_cast <ClipItem *>(selection.at(i));
5298             if (clip->clipType() == AV || clip->clipType() == PLAYLIST) {
5299                 if (clip->parentItem()) {
5300                     emit displayMessage(i18n("Cannot change grouped clips"), ErrorMessage);
5301                 } else {
5302                     new ChangeClipTypeCommand(this, clip->track(), clip->startPos(), false, false, clip->isVideoOnly(), clip->isAudioOnly(), videoCommand);
5303                 }
5304             }
5305         }
5306     }
5307     m_commandStack->push(videoCommand);
5308 }
5309
5310 void CustomTrackView::doChangeClipType(const GenTime &pos, int track, bool videoOnly, bool audioOnly)
5311 {
5312     ClipItem *clip = getClipItemAt(pos, track);
5313     if (clip == NULL) {
5314         kDebug() << "// Cannot find clip to split!!!";
5315         return;
5316     }
5317     if (videoOnly) {
5318         int start = pos.frames(m_document->fps());
5319         clip->setVideoOnly(true);
5320         clip->setAudioOnly(false);
5321         if (m_document->renderer()->mltUpdateClipProducer(m_document->tracksCount() - track, start, clip->baseClip()->videoProducer()) == false) {
5322             emit displayMessage(i18n("Cannot update clip (time: %1, track: %2)", start, track), ErrorMessage);
5323         }
5324     } else if (audioOnly) {
5325         int start = pos.frames(m_document->fps());
5326         clip->setAudioOnly(true);
5327         clip->setVideoOnly(false);
5328         if (m_document->renderer()->mltUpdateClipProducer(m_document->tracksCount() - track, start, clip->baseClip()->audioProducer(track)) == false) {
5329             emit displayMessage(i18n("Cannot update clip (time: %1, track: %2)", start, track), ErrorMessage);
5330         }
5331     } else {
5332         int start = pos.frames(m_document->fps());
5333         clip->setAudioOnly(false);
5334         clip->setVideoOnly(false);
5335         if (m_document->renderer()->mltUpdateClipProducer(m_document->tracksCount() - track, start, clip->baseClip()->producer(track)) == false) {
5336             emit displayMessage(i18n("Cannot update clip (time: %1, track: %2)", start, track), ErrorMessage);
5337         }
5338     }
5339     clip->update();
5340     setDocumentModified();
5341 }
5342
5343 void CustomTrackView::updateClipTypeActions(ClipItem *clip)
5344 {
5345     if (clip == NULL || (clip->clipType() != AV && clip->clipType() != PLAYLIST)) {
5346         m_clipTypeGroup->setEnabled(false);
5347     } else {
5348         m_clipTypeGroup->setEnabled(true);
5349         QList <QAction *> actions = m_clipTypeGroup->actions();
5350         QString lookup;
5351         if (clip->isAudioOnly()) lookup = "clip_audio_only";
5352         else if (clip->isVideoOnly()) lookup = "clip_video_only";
5353         else  lookup = "clip_audio_and_video";
5354         for (int i = 0; i < actions.count(); i++) {
5355             if (actions.at(i)->data().toString() == lookup) {
5356                 actions.at(i)->setChecked(true);
5357                 break;
5358             }
5359         }
5360     }
5361 }
5362
5363 void CustomTrackView::reloadTransitionLumas()
5364 {
5365     QString lumaNames;
5366     QString lumaFiles;
5367     QDomElement lumaTransition = MainWindow::transitions.getEffectByTag("luma", "luma");
5368     QDomNodeList params = lumaTransition.elementsByTagName("parameter");
5369     for (int i = 0; i < params.count(); i++) {
5370         QDomElement e = params.item(i).toElement();
5371         if (e.attribute("tag") == "resource") {
5372             lumaNames = e.attribute("paramlistdisplay");
5373             lumaFiles = e.attribute("paramlist");
5374             break;
5375         }
5376     }
5377
5378     QList<QGraphicsItem *> itemList = items();
5379     Transition *transitionitem;
5380     QDomElement transitionXml;
5381     for (int i = 0; i < itemList.count(); i++) {
5382         if (itemList.at(i)->type() == TRANSITIONWIDGET) {
5383             transitionitem = static_cast <Transition*>(itemList.at(i));
5384             transitionXml = transitionitem->toXML();
5385             if (transitionXml.attribute("id") == "luma" && transitionXml.attribute("tag") == "luma") {
5386                 QDomNodeList params = transitionXml.elementsByTagName("parameter");
5387                 for (int i = 0; i < params.count(); i++) {
5388                     QDomElement e = params.item(i).toElement();
5389                     if (e.attribute("tag") == "resource") {
5390                         e.setAttribute("paramlistdisplay", lumaNames);
5391                         e.setAttribute("paramlist", lumaFiles);
5392                         break;
5393                     }
5394                 }
5395             }
5396             if (transitionXml.attribute("id") == "composite" && transitionXml.attribute("tag") == "composite") {
5397                 QDomNodeList params = transitionXml.elementsByTagName("parameter");
5398                 for (int i = 0; i < params.count(); i++) {
5399                     QDomElement e = params.item(i).toElement();
5400                     if (e.attribute("tag") == "luma") {
5401                         e.setAttribute("paramlistdisplay", lumaNames);
5402                         e.setAttribute("paramlist", lumaFiles);
5403                         break;
5404                     }
5405                 }
5406             }
5407         }
5408     }
5409     emit transitionItemSelected(NULL);
5410 }
5411
5412 double CustomTrackView::fps() const
5413 {
5414     return m_document->fps();
5415 }
5416
5417 void CustomTrackView::updateProjectFps()
5418 {
5419     // update all clips to the new fps
5420     resetSelectionGroup();
5421     scene()->clearSelection();
5422     m_dragItem = NULL;
5423     QList<QGraphicsItem *> itemList = items();
5424     for (int i = 0; i < itemList.count(); i++) {
5425         // remove all items and re-add them one by one
5426         if (itemList.at(i) != m_cursorLine && itemList.at(i)->parentItem() == NULL) m_scene->removeItem(itemList.at(i));
5427     }
5428     for (int i = 0; i < itemList.count(); i++) {
5429         if (itemList.at(i)->parentItem() == 0 && (itemList.at(i)->type() == AVWIDGET || itemList.at(i)->type() == TRANSITIONWIDGET)) {
5430             AbstractClipItem *clip = static_cast <AbstractClipItem *>(itemList.at(i));
5431             clip->updateFps(m_document->fps());
5432             m_scene->addItem(clip);
5433         } else if (itemList.at(i)->type() == GROUPWIDGET) {
5434             AbstractGroupItem *grp = static_cast <AbstractGroupItem *>(itemList.at(i));
5435             QList<QGraphicsItem *> children = grp->childItems();
5436             for (int j = 0; j < children.count(); j++) {
5437                 if (children.at(j)->type() == AVWIDGET || children.at(j)->type() == TRANSITIONWIDGET) {
5438                     AbstractClipItem *clip = static_cast <AbstractClipItem *>(children.at(j));
5439                     clip->setFlag(QGraphicsItem::ItemIsMovable, true);
5440                     clip->updateFps(m_document->fps());
5441                 }
5442             }
5443             m_document->clipManager()->removeGroup(grp);
5444             m_scene->addItem(grp);
5445             scene()->destroyItemGroup(grp);
5446             for (int j = 0; j < children.count(); j++) {
5447                 if (children.at(j)->type() == AVWIDGET || children.at(j)->type() == TRANSITIONWIDGET) {
5448                     //children.at(j)->setParentItem(0);
5449                     children.at(j)->setSelected(true);
5450                 }
5451             }
5452             groupSelectedItems(true, true);
5453         } else if (itemList.at(i)->type() == GUIDEITEM) {
5454             Guide *g = static_cast<Guide *>(itemList.at(i));
5455             g->updatePos();
5456             m_scene->addItem(g);
5457         }
5458     }
5459     viewport()->update();
5460 }
5461
5462 void CustomTrackView::slotTrackDown()
5463 {
5464     if (m_selectedTrack > m_document->tracksCount() - 2) m_selectedTrack = 0;
5465     else m_selectedTrack++;
5466     emit updateTrackHeaders();
5467     QRectF rect(mapToScene(QPoint()).x(), m_selectedTrack * m_tracksHeight, 10, m_tracksHeight);
5468     ensureVisible(rect);
5469     viewport()->update();
5470 }
5471
5472 void CustomTrackView::slotTrackUp()
5473 {
5474     if (m_selectedTrack > 0) m_selectedTrack--;
5475     else m_selectedTrack = m_document->tracksCount() - 1;
5476     emit updateTrackHeaders();
5477     QRectF rect(mapToScene(QPoint()).x(), m_selectedTrack * m_tracksHeight, 10, m_tracksHeight);
5478     ensureVisible(rect);
5479     viewport()->update();
5480 }
5481
5482 int CustomTrackView::selectedTrack() const
5483 {
5484     return m_selectedTrack;
5485 }
5486
5487 void CustomTrackView::slotSelectTrack(int ix)
5488 {
5489     m_selectedTrack = qMax(0, ix);
5490     m_selectedTrack = qMin(ix, m_document->tracksCount() - 1);
5491     emit updateTrackHeaders();
5492     QRectF rect(mapToScene(QPoint()).x(), m_selectedTrack * m_tracksHeight, 10, m_tracksHeight);
5493     ensureVisible(rect);
5494     viewport()->update();
5495 }
5496
5497 void CustomTrackView::selectClip(bool add, bool group)
5498 {
5499     QRectF rect(m_cursorPos, m_selectedTrack * m_tracksHeight + m_tracksHeight / 2, 1, 1);
5500     QList<QGraphicsItem *> selection = m_scene->items(rect);
5501     resetSelectionGroup(group);
5502     if (!group) m_scene->clearSelection();
5503     for (int i = 0; i < selection.count(); i++) {
5504         if (selection.at(i)->type() == AVWIDGET) {
5505             selection.at(i)->setSelected(add);
5506             break;
5507         }
5508     }
5509     if (group) groupSelectedItems();
5510 }
5511
5512 void CustomTrackView::selectTransition(bool add, bool group)
5513 {
5514     QRectF rect(m_cursorPos, m_selectedTrack * m_tracksHeight + m_tracksHeight, 1, 1);
5515     QList<QGraphicsItem *> selection = m_scene->items(rect);
5516     resetSelectionGroup(group);
5517     if (!group) m_scene->clearSelection();
5518     for (int i = 0; i < selection.count(); i++) {
5519         if (selection.at(i)->type() == TRANSITIONWIDGET) {
5520             selection.at(i)->setSelected(add);
5521             break;
5522         }
5523     }
5524     if (group) groupSelectedItems();
5525 }
5526
5527 QStringList CustomTrackView::extractTransitionsLumas()
5528 {
5529     QStringList urls;
5530     QList<QGraphicsItem *> itemList = items();
5531     Transition *transitionitem;
5532     QDomElement transitionXml;
5533     for (int i = 0; i < itemList.count(); i++) {
5534         if (itemList.at(i)->type() == TRANSITIONWIDGET) {
5535             transitionitem = static_cast <Transition*>(itemList.at(i));
5536             transitionXml = transitionitem->toXML();
5537             QString luma = EffectsList::parameter(transitionXml, "luma");
5538             if (!luma.isEmpty()) urls << luma;
5539         }
5540     }
5541     return urls;
5542 }
5543
5544 void CustomTrackView::setEditMode(EDITMODE mode)
5545 {
5546     m_scene->setEditMode(mode);
5547 }
5548
5549 void CustomTrackView::checkTrackSequence(int track)
5550 {
5551     QList <int> times = m_document->renderer()->checkTrackSequence(m_document->tracksCount() - track);
5552     //track = m_document->tracksCount() -track;
5553     QRectF rect(0, track * m_tracksHeight + m_tracksHeight / 2, sceneRect().width(), 2);
5554     QList<QGraphicsItem *> selection = m_scene->items(rect);
5555     QList <int> timelineList;
5556     timelineList.append(0);
5557     for (int i = 0; i < selection.count(); i++) {
5558         if (selection.at(i)->type() == AVWIDGET) {
5559             ClipItem *clip = static_cast <ClipItem *>(selection.at(i));
5560             int start = clip->startPos().frames(m_document->fps());
5561             int end = clip->endPos().frames(m_document->fps());
5562             if (!timelineList.contains(start)) timelineList.append(start);
5563             if (!timelineList.contains(end)) timelineList.append(end);
5564         }
5565     }
5566     qSort(timelineList);
5567     kDebug() << "// COMPARE:\n" << times << "\n" << timelineList << "\n-------------------";
5568     if (times != timelineList) KMessageBox::sorry(this, i18n("error"), i18n("TRACTOR"));
5569 }
5570
5571 void CustomTrackView::insertZoneOverwrite(QStringList data, int in)
5572 {
5573     DocClipBase *clip = m_document->getBaseClip(data.at(0));
5574     ItemInfo info;
5575     info.startPos = GenTime(in, m_document->fps());
5576     info.cropStart = GenTime(data.at(1).toInt(), m_document->fps());
5577     info.endPos = info.startPos + GenTime(data.at(2).toInt(), m_document->fps()) - info.cropStart;
5578     info.cropDuration = info.endPos - info.startPos;
5579     info.track = m_selectedTrack;
5580     QUndoCommand *addCommand = new QUndoCommand();
5581     addCommand->setText(i18n("Insert clip"));
5582     adjustTimelineClips(OVERWRITEEDIT, NULL, info, addCommand);
5583     new AddTimelineClipCommand(this, clip->toXML(), clip->getId(), info, EffectsList(), true, false, true, false, addCommand);
5584     m_commandStack->push(addCommand);
5585 }