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