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