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