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