]> git.sesse.net Git - kdenlive/blob - src/customtrackview.cpp
Remember & save monitor zone for each clip:
[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 #include <QMouseEvent>
21 #include <QStylePainter>
22 #include <QGraphicsItem>
23 #include <QDomDocument>
24 #include <QScrollBar>
25 #include <QApplication>
26 #include <QInputDialog>
27
28 #include <KDebug>
29 #include <KLocale>
30 #include <KUrl>
31 #include <KIcon>
32 #include <KCursor>
33
34 #include "customtrackview.h"
35 #include "customtrackscene.h"
36 #include "docclipbase.h"
37 #include "clipitem.h"
38 #include "definitions.h"
39 #include "moveclipcommand.h"
40 #include "movetransitioncommand.h"
41 #include "resizeclipcommand.h"
42 #include "editguidecommand.h"
43 #include "addtimelineclipcommand.h"
44 #include "addeffectcommand.h"
45 #include "editeffectcommand.h"
46 #include "moveeffectcommand.h"
47 #include "addtransitioncommand.h"
48 #include "edittransitioncommand.h"
49 #include "editkeyframecommand.h"
50 #include "changespeedcommand.h"
51 #include "addmarkercommand.h"
52 #include "razorclipcommand.h"
53 #include "kdenlivesettings.h"
54 #include "transition.h"
55 #include "clipitem.h"
56 #include "customtrackview.h"
57 #include "clipmanager.h"
58 #include "renderer.h"
59 #include "markerdialog.h"
60 #include "mainwindow.h"
61 #include "ui_keyframedialog_ui.h"
62 #include "clipdurationdialog.h"
63 #include "abstractgroupitem.h"
64 #include "insertspacecommand.h"
65 #include "spacerdialog.h"
66 #include "addtrackcommand.h"
67 #include "changetrackcommand.h"
68 #include "movegroupcommand.h"
69 #include "ui_addtrack_ui.h"
70 #include "initeffects.h"
71
72 //TODO:
73 // disable animation if user asked it in KDE's global settings
74 // http://lists.kde.org/?l=kde-commits&m=120398724717624&w=2
75 // needs something like below (taken from dolphin)
76 // #include <kglobalsettings.h>
77 // const bool animate = KGlobalSettings::graphicEffectsLevel() & KGlobalSettings::SimpleAnimationEffects;
78 // const int duration = animate ? 1500 : 1;
79
80 CustomTrackView::CustomTrackView(KdenliveDoc *doc, CustomTrackScene* projectscene, QWidget *parent)
81         : QGraphicsView(projectscene, parent), m_scene(projectscene), m_cursorPos(0), m_cursorLine(NULL), m_operationMode(NONE), m_dragItem(NULL), m_visualTip(NULL), m_moveOpMode(NONE), m_animation(NULL), m_projectDuration(0), m_clickPoint(QPoint()), m_document(doc), m_autoScroll(KdenliveSettings::autoscroll()), m_tracksHeight(KdenliveSettings::trackheight()), m_tool(SELECTTOOL), m_dragGuide(NULL), m_findIndex(0), m_menuPosition(QPoint()), m_blockRefresh(false), m_selectionGroup(NULL), m_selectedTrack(0), m_copiedItems(QList<AbstractClipItem *> ()), m_scrollOffset(0) {
82     if (doc) m_commandStack = doc->commandStack();
83     else m_commandStack == NULL;
84     setMouseTracking(true);
85     setAcceptDrops(true);
86     m_animationTimer = new QTimeLine(800);
87     m_animationTimer->setFrameRange(0, 5);
88     m_animationTimer->setUpdateInterval(100);
89     m_animationTimer->setLoopCount(0);
90     m_tipColor = QColor(0, 192, 0, 200);
91     QColor border = QColor(255, 255, 255, 100);
92     m_tipPen.setColor(border);
93     m_tipPen.setWidth(3);
94     setContentsMargins(0, 0, 0, 0);
95     const int maxWidth = m_tracksHeight * m_document->tracksCount();
96     setSceneRect(0, 0, sceneRect().width(), maxWidth);
97     verticalScrollBar()->setMaximum(maxWidth);
98     m_cursorLine = projectscene->addLine(0, 0, 0, maxWidth);
99     m_cursorLine->setZValue(1000);
100
101     KIcon razorIcon("edit-cut");
102     m_razorCursor = QCursor(razorIcon.pixmap(22, 22));
103
104     KIcon spacerIcon("kdenlive-spacer-tool");
105     m_spacerCursor = QCursor(spacerIcon.pixmap(22, 22));
106     verticalScrollBar()->setTracking(true);
107     connect(verticalScrollBar(), SIGNAL(valueChanged(int)), this, SLOT(slotRefreshGuides()));
108     connect(&m_scrollTimer, SIGNAL(timeout()), this, SLOT(slotCheckMouseScrolling()));
109     m_scrollTimer.setInterval(100);
110     m_scrollTimer.setSingleShot(true);
111 }
112
113 CustomTrackView::~CustomTrackView() {
114     qDeleteAll(m_guides);
115 }
116
117 void CustomTrackView::setDocumentModified() {
118     m_document->setModified(true);
119 }
120
121 void CustomTrackView::setContextMenu(QMenu *timeline, QMenu *clip, QMenu *transition) {
122     m_timelineContextMenu = timeline;
123     m_timelineContextClipMenu = clip;
124     m_timelineContextTransitionMenu = transition;
125     QList <QAction *> list = m_timelineContextTransitionMenu->actions();
126     for (int i = 0; i < list.count(); i++)
127         if (list.at(i)->data().toString() == "auto") m_autoTransition = list.at(i);
128 }
129
130 void CustomTrackView::checkAutoScroll() {
131     m_autoScroll = KdenliveSettings::autoscroll();
132 }
133
134 /*sQList <TrackInfo> CustomTrackView::tracksList() const {
135     return m_scene->m_tracksList;
136 }*/
137
138 void CustomTrackView::checkTrackHeight() {
139     if (m_tracksHeight == KdenliveSettings::trackheight()) return;
140     m_tracksHeight = KdenliveSettings::trackheight();
141     emit trackHeightChanged();
142     QList<QGraphicsItem *> itemList = items();
143     ClipItem *item;
144     Transition *transitionitem;
145     bool snap = KdenliveSettings::snaptopoints();
146     KdenliveSettings::setSnaptopoints(false);
147     for (int i = 0; i < itemList.count(); i++) {
148         if (itemList.at(i)->type() == AVWIDGET) {
149             item = (ClipItem*) itemList.at(i);
150             item->setRect(0, 0, item->rect().width(), m_tracksHeight - 1);
151             item->setPos((qreal) item->startPos().frames(m_document->fps()), (qreal) item->track() * m_tracksHeight + 1);
152             item->resetThumbs();
153         } else if (itemList.at(i)->type() == TRANSITIONWIDGET) {
154             transitionitem = (Transition*) itemList.at(i);
155             transitionitem->setRect(0, 0, transitionitem->rect().width(), m_tracksHeight / 3 * 2 - 1);
156             transitionitem->setPos((qreal) transitionitem->startPos().frames(m_document->fps()), (qreal) transitionitem->track() * m_tracksHeight + m_tracksHeight / 3 * 2);
157         }
158     }
159     m_cursorLine->setLine(m_cursorLine->line().x1(), 0, m_cursorLine->line().x1(), m_tracksHeight * m_document->tracksCount());
160
161     for (int i = 0; i < m_guides.count(); i++) {
162         QLineF l = m_guides.at(i)->line();
163         l.setP2(QPointF(l.x2(), m_tracksHeight * m_document->tracksCount()));
164         m_guides.at(i)->setLine(l);
165     }
166
167     setSceneRect(0, 0, sceneRect().width(), m_tracksHeight * m_document->tracksCount());
168 //     verticalScrollBar()->setMaximum(m_tracksHeight * m_document->tracksCount());
169     KdenliveSettings::setSnaptopoints(snap);
170     update();
171 }
172
173 // virtual
174 void CustomTrackView::resizeEvent(QResizeEvent * event) {
175     QGraphicsView::resizeEvent(event);
176 }
177
178 // virtual
179 /** Zoom or move viewport on mousewheel
180  *
181  * If mousewheel+Ctrl, zooms in/out on the timeline.
182  *
183  * With Ctrl, moves viewport towards end of timeline if down/back,
184  * opposite on up/forward.
185  *
186  * See also http://www.kdenlive.org/mantis/view.php?id=265 */
187 void CustomTrackView::wheelEvent(QWheelEvent * e) {
188     if (e->modifiers() == Qt::ControlModifier) {
189         if (e->delta() > 0) emit zoomIn();
190         else emit zoomOut();
191     } else {
192         if (e->delta() <= 0) horizontalScrollBar()->setValue(horizontalScrollBar()->value() + horizontalScrollBar()->singleStep());
193         else  horizontalScrollBar()->setValue(horizontalScrollBar()->value() - horizontalScrollBar()->singleStep());
194     }
195 }
196
197 int CustomTrackView::getPreviousVideoTrack(int track) {
198     track = m_document->tracksCount() - track - 1;
199     track --;
200     for (int i = track; i > -1; i--) {
201         if (m_document->trackInfoAt(i).type == VIDEOTRACK) return i + 1;
202     }
203     return 0;
204 }
205
206
207 void CustomTrackView::slotCheckMouseScrolling() {
208     if (m_scrollOffset == 0) {
209         m_scrollTimer.stop();
210         return;
211     }
212     horizontalScrollBar()->setValue(horizontalScrollBar()->value() + m_scrollOffset);
213     m_scrollTimer.start();
214 }
215
216 void CustomTrackView::slotCheckPositionScrolling() {
217     // If mouse is at a border of the view, scroll
218     if (m_moveOpMode != SEEK) return;
219     int pos = cursorPos();
220     if (mapFromScene(pos, 0).x() < 7) {
221         horizontalScrollBar()->setValue(horizontalScrollBar()->value() - 2);
222         setCursorPos(mapToScene(QPoint()).x() - 1);
223         QTimer::singleShot(200, this, SLOT(slotCheckPositionScrolling()));
224
225     } else if (viewport()->width() - 5 < mapFromScene(pos + 1, 0).x()) {
226         horizontalScrollBar()->setValue(horizontalScrollBar()->value() + 2);
227         setCursorPos(mapToScene(viewport()->width(), 0).x() + 1);
228         QTimer::singleShot(200, this, SLOT(slotCheckPositionScrolling()));
229     }
230 }
231
232
233 // virtual
234
235 void CustomTrackView::mouseMoveEvent(QMouseEvent * event) {
236     int pos = event->x();
237     int mappedXPos = (int)(mapToScene(event->pos()).x() + 0.5);
238     emit mousePosition(mappedXPos);
239     if (event->buttons() & Qt::MidButton) return;
240     if ((event->modifiers() == Qt::ControlModifier && m_tool != SPACERTOOL) || event->modifiers() == Qt::ShiftModifier) {
241         QGraphicsView::mouseMoveEvent(event);
242         m_moveOpMode = NONE;
243         return;
244     }
245
246     if (event->buttons() != Qt::NoButton) {
247         bool move = (event->pos() - m_clickEvent).manhattanLength() >= QApplication::startDragDistance();
248         if (m_dragItem && m_tool == SELECTTOOL) {
249             if (m_operationMode == MOVE && move) {
250                 QGraphicsView::mouseMoveEvent(event);
251                 // If mouse is at a border of the view, scroll
252                 if (pos < 5) {
253                     m_scrollOffset = -30;
254                     m_scrollTimer.start();
255                 } else if (viewport()->width() - pos < 10) {
256                     m_scrollOffset = 30;
257                     m_scrollTimer.start();
258                 } else if (m_scrollTimer.isActive()) m_scrollTimer.stop();
259
260             } else if (m_operationMode == RESIZESTART && move) {
261                 double snappedPos = getSnapPointForPos(mappedXPos);
262                 m_dragItem->resizeStart((int)(snappedPos));
263             } else if (m_operationMode == RESIZEEND && move) {
264                 double snappedPos = getSnapPointForPos(mappedXPos);
265                 m_dragItem->resizeEnd((int)(snappedPos));
266             } else if (m_operationMode == FADEIN && move) {
267                 ((ClipItem*) m_dragItem)->setFadeIn((int)(mappedXPos - m_dragItem->startPos().frames(m_document->fps())));
268             } else if (m_operationMode == FADEOUT && move) {
269                 ((ClipItem*) m_dragItem)->setFadeOut((int)(m_dragItem->endPos().frames(m_document->fps()) - mappedXPos));
270             } else if (m_operationMode == KEYFRAME && move) {
271                 GenTime keyFramePos = GenTime(mappedXPos, m_document->fps()) - m_dragItem->startPos() + m_dragItem->cropStart();
272                 double pos = mapToScene(event->pos()).toPoint().y();
273                 QRectF br = m_dragItem->sceneBoundingRect();
274                 double maxh = 100.0 / br.height();
275                 pos = (br.bottom() - pos) * maxh;
276                 m_dragItem->updateKeyFramePos(keyFramePos, pos);
277             }
278
279             if (m_animation) delete m_animation;
280             m_animation = NULL;
281             if (m_visualTip) delete m_visualTip;
282             m_visualTip = NULL;
283             return;
284         } else if (m_operationMode == MOVEGUIDE) {
285             if (m_animation) delete m_animation;
286             m_animation = NULL;
287             if (m_visualTip) delete m_visualTip;
288             m_visualTip = NULL;
289             QGraphicsView::mouseMoveEvent(event);
290             return;
291         } else if (m_operationMode == SPACER && move) {
292             // spacer tool
293             int mappedClick = (int)(mapToScene(m_clickEvent).x() + 0.5);
294             m_selectionGroup->setPos(mappedXPos + (((int) m_selectionGroup->boundingRect().topLeft().x() + 0.5) - mappedClick) , m_selectionGroup->pos().y());
295         }
296     }
297
298     if (m_tool == RAZORTOOL) {
299         setCursor(m_razorCursor);
300         //QGraphicsView::mouseMoveEvent(event);
301         //return;
302     } else if (m_tool == SPACERTOOL) {
303         setCursor(m_spacerCursor);
304         return;
305     }
306
307     QList<QGraphicsItem *> itemList = items(event->pos());
308     QGraphicsRectItem *item = NULL;
309     OPERATIONTYPE opMode = NONE;
310
311     if (itemList.count() == 1 && itemList.at(0)->type() == GUIDEITEM) {
312         opMode = MOVEGUIDE;
313     } else for (int i = 0; i < itemList.count(); i++) {
314             if (itemList.at(i)->type() == AVWIDGET || itemList.at(i)->type() == TRANSITIONWIDGET) {
315                 item = (QGraphicsRectItem*) itemList.at(i);
316                 break;
317             }
318         }
319
320     if (item && event->buttons() == Qt::NoButton) {
321         AbstractClipItem *clip = static_cast <AbstractClipItem*>(item);
322         if (m_tool == RAZORTOOL) {
323             // razor tool over a clip, display current frame in monitor
324             if (!m_blockRefresh && item->type() == AVWIDGET) {
325                 //TODO: solve crash when showing frame when moving razor over clip
326                 //emit showClipFrame(((ClipItem *) item)->baseClip(), mapToScene(event->pos()).x() / m_scale - (clip->startPos() - clip->cropStart()).frames(m_document->fps()));
327             }
328             event->accept();
329             return;
330         }
331         opMode = clip->operationMode(mapToScene(event->pos()));
332         double size = 5;
333         if (opMode == m_moveOpMode) {
334             QGraphicsView::mouseMoveEvent(event);
335             return;
336         } else {
337             if (m_visualTip) {
338                 if (m_animation) delete m_animation;
339                 m_animation = NULL;
340                 m_animationTimer->stop();
341                 delete m_visualTip;
342                 m_visualTip = NULL;
343             }
344         }
345         m_moveOpMode = opMode;
346         if (opMode == MOVE) {
347             setCursor(Qt::OpenHandCursor);
348         } else if (opMode == RESIZESTART) {
349             setCursor(KCursor("left_side", Qt::SizeHorCursor));
350             if (m_visualTip == NULL) {
351                 QRectF rect = clip->sceneBoundingRect();
352                 QPolygon polygon;
353                 polygon << QPoint(0, rect.height() / 2 - size * 2);
354                 polygon << QPoint(size * 2, (int)(rect.height() / 2));
355                 polygon << QPoint(0, (int)(rect.height() / 2 + size * 2));
356                 polygon << QPoint(0, (int)(rect.height() / 2 - size * 2));
357
358                 m_visualTip = new QGraphicsPolygonItem(polygon);
359                 ((QGraphicsPolygonItem*) m_visualTip)->setBrush(m_tipColor);
360                 ((QGraphicsPolygonItem*) m_visualTip)->setPen(m_tipPen);
361                 m_visualTip->setPos(rect.x(), rect.y());
362                 m_visualTip->setFlags(QGraphicsItem::ItemIgnoresTransformations);
363                 m_visualTip->setZValue(100);
364                 m_animation = new QGraphicsItemAnimation;
365                 m_animation->setItem(m_visualTip);
366                 m_animation->setTimeLine(m_animationTimer);
367                 double scale = 2.0;
368                 m_animation->setScaleAt(.5, scale, 1);
369                 //m_animation->setPosAt(.5, QPointF(rect.x() - rect.x() * scale, 0));
370                 scale = 1.0;
371                 m_animation->setScaleAt(1, scale, 1);
372                 //m_animation->setPosAt(1, QPointF(rect.x() - rect.x() * scale, 0));
373                 scene()->addItem(m_visualTip);
374                 m_animationTimer->start();
375             }
376         } else if (opMode == RESIZEEND) {
377             setCursor(KCursor("right_side", Qt::SizeHorCursor));
378             if (m_visualTip == NULL) {
379                 QRectF rect = clip->sceneBoundingRect();
380                 QPolygon polygon;
381                 polygon << QPoint(0, (int)(rect.height() / 2 - size * 2));
382                 polygon << QPoint(- size * 2, (int)(rect.height() / 2));
383                 polygon << QPoint(0, (int)(rect.height() / 2 + size * 2));
384                 polygon << QPoint(0, (int)(rect.height() / 2 - size * 2));
385
386                 m_visualTip = new QGraphicsPolygonItem(polygon);
387                 ((QGraphicsPolygonItem*) m_visualTip)->setBrush(m_tipColor);
388                 ((QGraphicsPolygonItem*) m_visualTip)->setPen(m_tipPen);
389                 m_visualTip->setFlags(QGraphicsItem::ItemIgnoresTransformations);
390                 m_visualTip->setPos(rect.right(), rect.y());
391                 m_visualTip->setZValue(100);
392                 m_animation = new QGraphicsItemAnimation;
393                 m_animation->setItem(m_visualTip);
394                 m_animation->setTimeLine(m_animationTimer);
395                 double scale = 2.0;
396                 m_animation->setScaleAt(.5, scale, 1);
397                 scale = 1.0;
398                 m_animation->setScaleAt(1, scale, 1);
399                 scene()->addItem(m_visualTip);
400                 m_animationTimer->start();
401             }
402         } else if (opMode == FADEIN) {
403             if (m_visualTip == NULL) {
404                 ClipItem *item = (ClipItem *) clip;
405                 QRectF rect = clip->sceneBoundingRect();
406                 m_visualTip = new QGraphicsEllipseItem(-size, -size, size * 2, size * 2);
407                 ((QGraphicsEllipseItem*) m_visualTip)->setBrush(m_tipColor);
408                 ((QGraphicsEllipseItem*) m_visualTip)->setPen(m_tipPen);
409                 m_visualTip->setPos(rect.x() + item->fadeIn(), rect.y());
410                 m_visualTip->setFlags(QGraphicsItem::ItemIgnoresTransformations);
411                 m_visualTip->setZValue(100);
412                 m_animation = new QGraphicsItemAnimation;
413                 m_animation->setItem(m_visualTip);
414                 m_animation->setTimeLine(m_animationTimer);
415                 double scale = 2.0;
416                 m_animation->setScaleAt(.5, scale, scale);
417                 scale = 1.0;
418                 m_animation->setScaleAt(1, scale, scale);
419                 scene()->addItem(m_visualTip);
420                 m_animationTimer->start();
421             }
422             setCursor(Qt::PointingHandCursor);
423         } else if (opMode == FADEOUT) {
424             if (m_visualTip == NULL) {
425                 ClipItem *item = (ClipItem *) clip;
426                 QRectF rect = clip->sceneBoundingRect();
427                 m_visualTip = new QGraphicsEllipseItem(-size, -size, size * 2, size * 2);
428                 ((QGraphicsEllipseItem*) m_visualTip)->setBrush(m_tipColor);
429                 ((QGraphicsEllipseItem*) m_visualTip)->setPen(m_tipPen);
430                 m_visualTip->setPos(rect.right() - item->fadeOut(), rect.y());
431                 m_visualTip->setFlags(QGraphicsItem::ItemIgnoresTransformations);
432                 m_visualTip->setZValue(100);
433                 m_animation = new QGraphicsItemAnimation;
434                 m_animation->setItem(m_visualTip);
435                 m_animation->setTimeLine(m_animationTimer);
436                 double scale = 2.0;
437                 m_animation->setScaleAt(.5, scale, scale);
438                 scale = 1.0;
439                 m_animation->setScaleAt(1, scale, scale);
440                 scene()->addItem(m_visualTip);
441                 m_animationTimer->start();
442             }
443             setCursor(Qt::PointingHandCursor);
444         } else if (opMode == TRANSITIONSTART) {
445             /*if (m_visualTip == NULL) {
446                 QRectF rect = clip->sceneBoundingRect();
447                 m_visualTip = new QGraphicsEllipseItem(-5, -5 , 10, 10);
448                 ((QGraphicsEllipseItem*) m_visualTip)->setBrush(m_tipColor);
449                 ((QGraphicsEllipseItem*) m_visualTip)->setPen(m_tipPen);
450                 m_visualTip->setZValue(100);
451                 m_animation = new QGraphicsItemAnimation;
452                 m_animation->setItem(m_visualTip);
453                 m_animation->setTimeLine(m_animationTimer);
454                 m_visualTip->setPos(rect.x() + 10, rect.y() + rect.height() / 2 + 12);
455                 double scale = 2.0;
456                 m_animation->setScaleAt(.5, scale, scale);
457                 scale = 1.0;
458                 m_animation->setScaleAt(1, scale, scale);
459                 scene()->addItem(m_visualTip);
460                 m_animationTimer->start();
461             }*/
462             setCursor(Qt::PointingHandCursor);
463         } else if (opMode == TRANSITIONEND) {
464             /*if (m_visualTip == NULL) {
465                 QRectF rect = clip->sceneBoundingRect();
466                 m_visualTip = new QGraphicsEllipseItem(-5, -5 , 10, 10);
467                 ((QGraphicsEllipseItem*) m_visualTip)->setBrush(m_tipColor);
468                 ((QGraphicsEllipseItem*) m_visualTip)->setPen(m_tipPen);
469                 m_visualTip->setZValue(100);
470                 m_animation = new QGraphicsItemAnimation;
471                 m_animation->setItem(m_visualTip);
472                 m_animation->setTimeLine(m_animationTimer);
473                 m_visualTip->setPos(rect.x() + rect.width() - 10 , rect.y() + rect.height() / 2 + 12);
474                 double scale = 2.0;
475                 m_animation->setScaleAt(.5, scale, scale);
476                 scale = 1.0;
477                 m_animation->setScaleAt(1, scale, scale);
478                 scene()->addItem(m_visualTip);
479                 m_animationTimer->start();
480             }*/
481             setCursor(Qt::PointingHandCursor);
482         } else if (opMode == KEYFRAME) {
483             setCursor(Qt::PointingHandCursor);
484         }
485     } // no clip under mouse
486     else if (m_tool == RAZORTOOL) {
487         event->accept();
488         return;
489     } else if (opMode == MOVEGUIDE) {
490         m_moveOpMode = opMode;
491         setCursor(Qt::SplitHCursor);
492     } else {
493         if (event->buttons() != Qt::NoButton && event->modifiers() == Qt::NoModifier) {
494             m_moveOpMode = SEEK;
495             setCursorPos(mappedXPos);
496             slotCheckPositionScrolling();
497         } else m_moveOpMode = NONE;
498         if (m_visualTip) {
499             if (m_animation) delete m_animation;
500             m_animationTimer->stop();
501             m_animation = NULL;
502             delete m_visualTip;
503             m_visualTip = NULL;
504
505         }
506         setCursor(Qt::ArrowCursor);
507     }
508     QGraphicsView::mouseMoveEvent(event);
509 }
510
511 // virtual
512 void CustomTrackView::mousePressEvent(QMouseEvent * event) {
513     m_menuPosition = QPoint();
514     m_blockRefresh = true;
515     bool collision = false;
516
517     if (m_tool != RAZORTOOL) activateMonitor();
518     else if (m_document->renderer()->playSpeed() != 0.0) {
519         m_document->renderer()->pause();
520         return;
521     }
522     m_clickEvent = event->pos();
523
524     // special cases (middle click button or ctrl / shift click
525     if (event->button() == Qt::MidButton) {
526         m_document->renderer()->switchPlay();
527         m_blockRefresh = false;
528         m_operationMode = NONE;
529         return;
530     }
531
532     // check item under mouse
533     QList<QGraphicsItem *> collisionList = items(event->pos());
534
535     if (event->modifiers() == Qt::ControlModifier && m_tool != SPACERTOOL && collisionList.count() == 0) {
536         setDragMode(QGraphicsView::ScrollHandDrag);
537         QGraphicsView::mousePressEvent(event);
538         m_blockRefresh = false;
539         m_operationMode = NONE;
540         return;
541     }
542
543     if (event->modifiers() == Qt::ShiftModifier && collisionList.count() == 0) {
544         setDragMode(QGraphicsView::RubberBandDrag);
545         QGraphicsView::mousePressEvent(event);
546         m_blockRefresh = false;
547         m_operationMode = RUBBERSELECTION;
548         return;
549     }
550
551     if (collisionList.count() == 1 && collisionList.at(0)->type() == GUIDEITEM) {
552         // a guide item was pressed
553         collisionList.at(0)->setFlag(QGraphicsItem::ItemIsMovable, true);
554         m_dragItem = NULL;
555         m_dragGuide = (Guide *) collisionList.at(0);
556         collision = true;
557         m_operationMode = MOVEGUIDE;
558         // deselect all clips so that only the guide will move
559         m_scene->clearSelection();
560         resetSelectionGroup();
561         updateSnapPoints(NULL);
562         QGraphicsView::mousePressEvent(event);
563         return;
564     }
565
566     // Find first clip or transition under mouse
567     int i = 0;
568     m_dragItem = NULL;
569     while (i < collisionList.count()) {
570         if (collisionList.at(i)->type() == AVWIDGET || collisionList.at(i)->type() == TRANSITIONWIDGET) {
571             m_dragItem = static_cast <AbstractClipItem *>(collisionList.at(i));
572             m_dragItemInfo = m_dragItem->info();
573             break;
574         }
575         i++;
576     }
577
578     if (m_dragItem && m_dragItem->type() == TRANSITIONWIDGET) {
579         // update transition menu action
580         m_autoTransition->setChecked(static_cast<Transition *>(m_dragItem)->isAutomatic());
581         m_autoTransition->setEnabled(true);
582     } else m_autoTransition->setEnabled(false);
583
584     // context menu requested
585     if (event->button() == Qt::RightButton) {
586         if (m_dragItem) {
587             if (!m_dragItem->isSelected()) {
588                 resetSelectionGroup(false);
589                 m_scene->clearSelection();
590                 m_dragItem->setSelected(true);
591             }
592         }
593         m_operationMode = NONE;
594         displayContextMenu(event->globalPos(), m_dragItem);
595         m_menuPosition = m_clickEvent;
596         m_dragItem = NULL;
597         event->accept();
598         return;
599     }
600
601     // No item under click
602     if (m_dragItem == NULL || m_tool == SPACERTOOL) {
603         resetSelectionGroup();
604         setCursor(Qt::ArrowCursor);
605         m_scene->clearSelection();
606         event->accept();
607         emit clipItemSelected(NULL);
608         if (m_tool == SPACERTOOL) {
609             QList<QGraphicsItem *> selection;
610             if (event->modifiers() == Qt::ControlModifier) {
611                 // Ctrl + click, select all items on track after click position
612                 int track = (int)(mapToScene(m_clickEvent).y() / m_tracksHeight);
613                 selection = items(m_clickEvent.x(), track * m_tracksHeight + 1, sceneRect().width() - m_clickEvent.x(), m_tracksHeight - 2);
614                 // for (int count = 0; count < selection.size(); count++) {
615                 //   selection.at(count);
616                 // }
617                 kDebug() << "SPACER TOOL + CTRL, SELECTING ALL CLIPS ON TRACK " << track << " WITH SELECTION RECT " << m_clickEvent.x() << "/" <<  track * m_tracksHeight + 1 << "; " << sceneRect().width() - m_clickEvent.x() << "/" << m_tracksHeight - 2;
618             } else {
619                 // Select all items on all tracks after click position
620                 selection = items(event->pos().x(), 1, sceneRect().width() - event->pos().x(), sceneRect().height());
621                 kDebug() << "SELELCTING ELEMENTS WITHIN =" << event->pos().x() << "/" <<  1 << ", " << sceneRect().width() - event->pos().x() << "/" << sceneRect().height();
622             }
623             m_selectionGroup = new AbstractGroupItem(m_document->fps());
624             scene()->addItem(m_selectionGroup);
625
626             for (int i = 0; i < selection.count(); i++) {
627                 if (selection.at(i)->type() == AVWIDGET || selection.at(i)->type() == TRANSITIONWIDGET) {
628                     m_selectionGroup->addToGroup(selection.at(i));
629                     selection.at(i)->setFlags(QGraphicsItem::ItemIsSelectable);
630                 }
631             }
632             kDebug() << "SPACER TOOL: SELECTION GROUP POSITION " << m_selectionGroup->pos().x() << "/" << m_selectionGroup->pos().y();
633             kDebug() << "SPACER TOOL: SELECTION GROUP RECT IS " << m_selectionGroup->boundingRect().top() << "/" << m_selectionGroup->boundingRect().left() << "; " << m_selectionGroup->boundingRect().bottom() << "/" << m_selectionGroup->boundingRect().right();
634             QPointF top = m_selectionGroup->boundingRect().topLeft();
635             // Something goes wrong there
636             m_selectionGroup->setPos(top);
637             m_selectionGroup->translate(-top.x(), -top.y() + 1);
638             kDebug() << "SPACER TOOL: SELECTION GROUP TRANSLATED TO " << m_selectionGroup->pos().x() << "/" << m_selectionGroup->pos().y();
639             m_operationMode = SPACER;
640         } else setCursorPos((int)(mapToScene(event->x(), 0).x()));
641         return;
642     }
643
644     // Razor tool
645     if (m_tool == RAZORTOOL) {
646         if (m_dragItem->type() == TRANSITIONWIDGET) {
647             emit displayMessage(i18n("Cannot cut a transition"), ErrorMessage);
648             event->accept();
649             m_dragItem = NULL;
650             return;
651         }
652         AbstractClipItem *clip = static_cast <AbstractClipItem *>(m_dragItem);
653         RazorClipCommand* command = new RazorClipCommand(this, clip->info(), GenTime((int)(mapToScene(event->pos()).x()), m_document->fps()), true);
654         m_commandStack->push(command);
655         m_document->setModified(true);
656         m_dragItem = NULL;
657         event->accept();
658         return;
659     }
660     updateSnapPoints(m_dragItem);
661     if (m_dragItem->type() == AVWIDGET) emit clipItemSelected((ClipItem*) m_dragItem);
662     else emit clipItemSelected(NULL);
663
664     if (event->modifiers() != Qt::ControlModifier && (m_dragItem->group() || m_dragItem->isSelected())) {
665         // If clicked item is selected, allow move
666         event->accept();
667         if (m_selectionGroup) m_selectionGroup->setSelected(true);
668         if (m_operationMode == NONE) QGraphicsView::mousePressEvent(event);
669     } else {
670         resetSelectionGroup();
671         if (event->modifiers() != Qt::ControlModifier) m_scene->clearSelection();
672         m_dragItem->setSelected(!m_dragItem->isSelected());
673         groupSelectedItems();
674     }
675
676     m_clickPoint = QPoint((int)(mapToScene(event->pos()).x() - m_dragItem->startPos().frames(m_document->fps())), (int)(event->pos().y() - m_dragItem->pos().y()));
677     /*
678                         if (!item->isSelected()) {
679
680                             if (event->modifiers() != Qt::ControlModifier) {
681                                 QList<QGraphicsItem *> itemList = items();
682                                 for (int i = 0; i < itemList.count(); i++) {
683                                     itemList.at(i)->setSelected(false);
684                                     itemList.at(i)->update();
685                                 }
686                             }
687                             item->setSelected(true);
688                             item->update();
689                         }
690
691
692
693                         m_clickPoint = QPoint((int)(mapToScene(event->pos()).x() - m_dragItem->startPos().frames(m_document->fps()) * m_scale), (int)(event->pos().y() - m_dragItem->pos().y()));
694                         m_dragItemInfo.startPos = m_dragItem->startPos();
695                         m_dragItemInfo.endPos = m_dragItem->endPos();
696                         m_dragItemInfo.track = m_dragItem->track();
697
698                         m_selectedClipList.clear();
699                         QList<QGraphicsItem *> selected = scene()->selectedItems();
700                         for (int i = 0; i < selected.count(); i++) {
701                             if (selected.at(i)->type() == AVWIDGET || selected.at(i)->type() == TRANSITIONWIDGET)
702                                 m_selectedClipList.append(static_cast <AbstractClipItem *>(selected.at(i)));
703                         }
704           */
705     m_operationMode = m_dragItem->operationMode(mapToScene(event->pos()));
706
707     if (m_operationMode == KEYFRAME) {
708         m_dragItem->updateSelectedKeyFrame();
709         m_blockRefresh = false;
710         return;
711     } else if (m_operationMode == MOVE) {
712         setCursor(Qt::ClosedHandCursor);
713     } else if (m_operationMode == TRANSITIONSTART) {
714         ItemInfo info;
715         info.startPos = m_dragItem->startPos();
716         info.track = m_dragItem->track();
717         int transitiontrack = getPreviousVideoTrack(info.track);
718         ClipItem *transitionClip = NULL;
719         if (transitiontrack != 0) transitionClip = getClipItemAt((int) info.startPos.frames(m_document->fps()), m_document->tracksCount() - transitiontrack);
720         if (transitionClip && transitionClip->endPos() < m_dragItem->endPos()) {
721             info.endPos = transitionClip->endPos();
722         } else info.endPos = info.startPos + GenTime(65, m_document->fps());
723         if (info.endPos == info.startPos) info.endPos = info.startPos + GenTime(65, m_document->fps());
724         slotAddTransition((ClipItem *) m_dragItem, info, transitiontrack);
725     } else if (m_operationMode == TRANSITIONEND) {
726         ItemInfo info;
727         info.endPos = GenTime(m_dragItem->endPos().frames(m_document->fps()), m_document->fps());
728         info.track = m_dragItem->track();
729         int transitiontrack = getPreviousVideoTrack(info.track);
730         ClipItem *transitionClip = NULL;
731         if (transitiontrack != 0) transitionClip = getClipItemAt((int) info.endPos.frames(m_document->fps()), m_document->tracksCount() - transitiontrack);
732         if (transitionClip && transitionClip->startPos() > m_dragItem->startPos()) {
733             info.startPos = transitionClip->startPos();
734         } else info.startPos = info.endPos - GenTime(65, m_document->fps());
735         if (info.endPos == info.startPos) info.startPos = info.endPos - GenTime(65, m_document->fps());
736         QDomElement transition = MainWindow::transitions.getEffectByName("Luma").cloneNode().toElement();
737         EffectsList::setParameter(transition, "reverse", "1");
738         slotAddTransition((ClipItem *) m_dragItem, info, transitiontrack, transition);
739     } else if ((m_operationMode == RESIZESTART || m_operationMode == RESIZEEND) && m_selectionGroup) {
740         resetSelectionGroup(false);
741         m_dragItem->setSelected(true);
742     }
743
744     m_blockRefresh = false;
745     //kDebug()<<pos;
746     //QGraphicsView::mousePressEvent(event);
747 }
748
749 void CustomTrackView::resetSelectionGroup(bool selectItems) {
750     if (m_selectionGroup) {
751         // delete selection group
752         bool snap = KdenliveSettings::snaptopoints();
753         KdenliveSettings::setSnaptopoints(false);
754         QList<QGraphicsItem *> children = m_selectionGroup->childItems();
755         for (int i = 0; i < children.count(); i++) {
756             children.at(i)->setFlags(QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemIsSelectable);
757             children.at(i)->setSelected(selectItems);
758         }
759         scene()->destroyItemGroup(m_selectionGroup);
760         m_selectionGroup = NULL;
761         KdenliveSettings::setSnaptopoints(snap);
762     }
763 }
764
765 void CustomTrackView::groupSelectedItems() {
766     if (m_selectionGroup) {
767         kDebug() << "///// ERROR, TRYING TO OVERRIDE EXISTING GROUP";
768         return;
769     }
770     QList<QGraphicsItem *> selection = m_scene->selectedItems();
771     if (selection.count() > 1) {
772         m_selectionGroup = new AbstractGroupItem(m_document->fps());
773         scene()->addItem(m_selectionGroup);
774         for (int i = 0; i < selection.count(); i++) {
775             if (selection.at(i)->type() == AVWIDGET || selection.at(i)->type() == TRANSITIONWIDGET) {
776                 m_selectionGroup->addToGroup(selection.at(i));
777                 selection.at(i)->setFlags(QGraphicsItem::ItemIsSelectable);
778             }
779         }
780
781         if (m_selectionGroup) {
782             bool snap = KdenliveSettings::snaptopoints();
783             KdenliveSettings::setSnaptopoints(false);
784             QPointF top = m_selectionGroup->sceneBoundingRect().topLeft();
785             m_selectionGroup->translate(-top.x(), -top.y() + 1);
786             m_selectionGroup->setPos(top);
787             m_selectionGroupInfo.startPos = GenTime(m_selectionGroup->scenePos().x(), m_document->fps());
788             m_selectionGroupInfo.track = m_selectionGroup->track();
789             KdenliveSettings::setSnaptopoints(snap);
790         }
791     } else resetSelectionGroup();
792 }
793
794 void CustomTrackView::mouseDoubleClickEvent(QMouseEvent *event) {
795     kDebug() << "++++++++++++ DBL CLK";
796     if (m_dragItem && m_dragItem->hasKeyFrames()) {
797         if (m_moveOpMode == KEYFRAME) {
798             // user double clicked on a keyframe, open edit dialog
799             QDialog d(parentWidget());
800             Ui::KeyFrameDialog_UI view;
801             view.setupUi(&d);
802             view.kfr_position->setText(m_document->timecode().getTimecode(GenTime(m_dragItem->selectedKeyFramePos(), m_document->fps()) - m_dragItem->cropStart(), m_document->fps()));
803             view.kfr_value->setValue(m_dragItem->selectedKeyFrameValue());
804             view.kfr_value->setFocus();
805             if (d.exec() == QDialog::Accepted) {
806                 int pos = m_document->timecode().getFrameCount(view.kfr_position->text(), m_document->fps());
807                 m_dragItem->updateKeyFramePos(GenTime(pos, m_document->fps()) + m_dragItem->cropStart(), (double) view.kfr_value->value() * m_dragItem->keyFrameFactor());
808                 ClipItem *item = (ClipItem *)m_dragItem;
809                 QString previous = item->keyframes(item->selectedEffectIndex());
810                 item->updateKeyframeEffect();
811                 QString next = item->keyframes(item->selectedEffectIndex());
812                 EditKeyFrameCommand *command = new EditKeyFrameCommand(this, item->track(), item->startPos(), item->selectedEffectIndex(), previous, next, false);
813                 m_commandStack->push(command);
814                 updateEffect(m_document->tracksCount() - item->track(), item->startPos(), item->selectedEffect(), item->selectedEffectIndex());
815             }
816
817         } else  {
818             // add keyframe
819             GenTime keyFramePos = GenTime((int)(mapToScene(event->pos()).x()), m_document->fps()) - m_dragItem->startPos() + m_dragItem->cropStart();
820             m_dragItem->addKeyFrame(keyFramePos, mapToScene(event->pos()).toPoint().y());
821             ClipItem * item = (ClipItem *) m_dragItem;
822             QString previous = item->keyframes(item->selectedEffectIndex());
823             item->updateKeyframeEffect();
824             QString next = item->keyframes(item->selectedEffectIndex());
825             EditKeyFrameCommand *command = new EditKeyFrameCommand(this, m_dragItem->track(), m_dragItem->startPos(), item->selectedEffectIndex(), previous, next, false);
826             m_commandStack->push(command);
827             updateEffect(m_document->tracksCount() - item->track(), item->startPos(), item->selectedEffect(), item->selectedEffectIndex());
828         }
829     } else if (m_dragItem) {
830         ClipDurationDialog d(m_dragItem, m_document->timecode(), this);
831         if (d.exec() == QDialog::Accepted) {
832             if (d.startPos() != m_dragItem->startPos()) {
833                 if (m_dragItem->type() == AVWIDGET) {
834                     ItemInfo startInfo;
835                     startInfo.startPos = m_dragItem->startPos();
836                     startInfo.endPos = m_dragItem->endPos();
837                     startInfo.track = m_dragItem->track();
838                     ItemInfo endInfo;
839                     endInfo.startPos = d.startPos();
840                     endInfo.endPos = m_dragItem->endPos() + (endInfo.startPos - startInfo.startPos);
841                     endInfo.track = m_dragItem->track();
842                     MoveClipCommand *command = new MoveClipCommand(this, startInfo, endInfo, true);
843                     m_commandStack->push(command);
844                 } else {
845                     //TODO: move transition
846                 }
847             }
848             if (d.duration() != m_dragItem->duration()) {
849                 if (m_dragItem->type() == AVWIDGET) {
850                     ItemInfo startInfo;
851                     startInfo.startPos = m_dragItem->startPos();
852                     startInfo.endPos = m_dragItem->endPos();
853                     startInfo.track = m_dragItem->track();
854                     ItemInfo endInfo;
855                     endInfo.startPos = startInfo.startPos;
856                     endInfo.endPos = endInfo.startPos + d.duration();
857                     endInfo.track = m_dragItem->track();
858                     ResizeClipCommand *command = new ResizeClipCommand(this, startInfo, endInfo, true);
859                     m_commandStack->push(command);
860                 } else {
861                     //TODO: resize transition
862                 }
863             }
864         }
865     } else {
866         QList<QGraphicsItem *> collisionList = items(event->pos());
867         if (collisionList.count() == 1 && collisionList.at(0)->type() == GUIDEITEM) {
868             Guide *editGuide = (Guide *) collisionList.at(0);
869             if (editGuide) slotEditGuide(editGuide->info());
870         }
871     }
872 }
873
874
875 void CustomTrackView::editKeyFrame(const GenTime pos, const int track, const int index, const QString keyframes) {
876     ClipItem *clip = getClipItemAt((int)pos.frames(m_document->fps()), track);
877     if (clip) {
878         clip->setKeyframes(index, keyframes);
879         updateEffect(m_document->tracksCount() - clip->track(), clip->startPos(), clip->effectAt(index), index);
880     } else emit displayMessage(i18n("Cannot find clip with keyframe"), ErrorMessage);
881 }
882
883
884 void CustomTrackView::displayContextMenu(QPoint pos, AbstractClipItem *clip) {
885     if (clip == NULL) m_timelineContextMenu->popup(pos);
886     else if (clip->type() == AVWIDGET) m_timelineContextClipMenu->popup(pos);
887     else if (clip->type() == TRANSITIONWIDGET) m_timelineContextTransitionMenu->popup(pos);
888 }
889
890 void CustomTrackView::activateMonitor() {
891     emit activateDocumentMonitor();
892 }
893
894 void CustomTrackView::dragEnterEvent(QDragEnterEvent * event) {
895     if (event->mimeData()->hasFormat("kdenlive/clip")) {
896         resetSelectionGroup();
897
898         QStringList list = QString(event->mimeData()->data("kdenlive/clip")).split(";");
899         m_selectionGroup = new AbstractGroupItem(m_document->fps());
900         QPoint pos = QPoint();
901         DocClipBase *clip = m_document->getBaseClip(list.at(0));
902         if (clip == NULL) kDebug() << " WARNING))))))))) CLIP NOT FOUND : " << list.at(0);
903         ItemInfo info;
904         info.startPos = GenTime(pos.x(), m_document->fps());
905         info.cropStart = GenTime(list.at(1).toInt(), m_document->fps());
906         info.endPos = info.startPos + GenTime(list.at(2).toInt() - list.at(1).toInt(), m_document->fps());
907         info.track = (int)(pos.y() / m_tracksHeight);
908         ClipItem *item = new ClipItem(clip, info, m_document->fps(), 1.0);
909         m_selectionGroup->addToGroup(item);
910         //TODO: check if we do not overlap another clip when first dropping in timeline
911         // if (insertPossible(m_selectionGroup, event->pos()))
912         scene()->addItem(m_selectionGroup);
913         event->acceptProposedAction();
914     } else if (event->mimeData()->hasFormat("kdenlive/producerslist")) {
915         QStringList ids = QString(event->mimeData()->data("kdenlive/producerslist")).split(";");
916         m_scene->clearSelection();
917         resetSelectionGroup(false);
918
919         m_selectionGroup = new AbstractGroupItem(m_document->fps());
920         QPoint pos = QPoint();
921         for (int i = 0; i < ids.size(); ++i) {
922             DocClipBase *clip = m_document->getBaseClip(ids.at(i));
923             if (clip == NULL) kDebug() << " WARNING))))))))) CLIP NOT FOUND : " << ids.at(i);
924             ItemInfo info;
925             info.startPos = GenTime(pos.x(), m_document->fps());
926             info.endPos = info.startPos + clip->duration();
927             info.track = (int)(pos.y() / m_tracksHeight);
928             ClipItem *item = new ClipItem(clip, info, m_document->fps(), 1.0);
929             pos.setX(pos.x() + clip->duration().frames(m_document->fps()));
930             m_selectionGroup->addToGroup(item);
931         }
932         //TODO: check if we do not overlap another clip when first dropping in timeline
933         //if (insertPossible(m_selectionGroup, event->pos()))
934         scene()->addItem(m_selectionGroup);
935         event->acceptProposedAction();
936     } else QGraphicsView::dragEnterEvent(event);
937 }
938
939
940 bool CustomTrackView::insertPossible(AbstractGroupItem *group, const QPoint &pos) const {
941     QPolygonF path;
942     QList<QGraphicsItem *> children = group->childItems();
943     for (int i = 0; i < children.count(); i++) {
944         if (children.at(i)->type() == AVWIDGET) {
945             ClipItem *clip = static_cast <ClipItem *>(children.at(i));
946             ItemInfo info = clip->info();
947             kDebug() << " / / INSERT : " << pos.x();
948             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);
949             kDebug() << " / / INSERT RECT: " << shape;
950             path = path.united(QPolygonF(shape));
951         }
952     }
953
954     QList<QGraphicsItem*> collindingItems = scene()->items(path, Qt::IntersectsItemShape);
955     if (collindingItems.isEmpty()) return true;
956     else {
957         for (int i = 0; i < collindingItems.count(); i++) {
958             QGraphicsItem *collision = collindingItems.at(i);
959             if (collision->type() == AVWIDGET) {
960                 // Collision
961                 kDebug() << "// COLLISIION DETECTED";
962                 return false;
963             }
964         }
965         return true;
966     }
967
968 }
969
970 void CustomTrackView::slotRefreshEffects(ClipItem *clip) {
971     int track = m_document->tracksCount() - clip->track();
972     GenTime pos = clip->startPos();
973     if (!m_document->renderer()->mltRemoveEffect(track, pos, "-1", false, false)) {
974         emit displayMessage(i18n("Problem deleting effect"), ErrorMessage);
975         return;
976     }
977     bool success = true;
978     for (int i = 0; i < clip->effectsCount(); i++) {
979         if (!m_document->renderer()->mltAddEffect(track, pos, clip->getEffectArgs(clip->effectAt(i)), false)) success = false;
980     }
981     if (!success) emit displayMessage(i18n("Problem adding effect to clip"), ErrorMessage);
982     m_document->renderer()->doRefresh();
983 }
984
985 void CustomTrackView::addEffect(int track, GenTime pos, QDomElement effect) {
986     ClipItem *clip = getClipItemAt((int)pos.frames(m_document->fps()) + 1, m_document->tracksCount() - track);
987     if (clip) {
988         if (!m_document->renderer()->mltAddEffect(track, pos, clip->addEffect(effect)))
989             emit displayMessage(i18n("Problem adding effect to clip"), ErrorMessage);
990         emit clipItemSelected(clip);
991     } else emit displayMessage(i18n("Cannot find clip to add effect"), ErrorMessage);
992 }
993
994 void CustomTrackView::deleteEffect(int track, GenTime pos, QDomElement effect) {
995     QString index = effect.attribute("kdenlive_ix");
996     if (!m_document->renderer()->mltRemoveEffect(track, pos, index, true) && effect.attribute("disabled") != "1") {
997         kDebug() << "// ERROR REMOV EFFECT: " << index << ", DISABLE: " << effect.attribute("disabled");
998         emit displayMessage(i18n("Problem deleting effect"), ErrorMessage);
999         return;
1000     }
1001     ClipItem *clip = getClipItemAt((int)pos.frames(m_document->fps()) + 1, m_document->tracksCount() - track);
1002     if (clip) {
1003         clip->deleteEffect(index);
1004         emit clipItemSelected(clip);
1005     }
1006 }
1007
1008 void CustomTrackView::slotAddEffect(QDomElement effect, GenTime pos, int track) {
1009     QList<QGraphicsItem *> itemList;
1010     if (track == -1) itemList = scene()->selectedItems();
1011     if (itemList.isEmpty()) {
1012         ClipItem *clip = getClipItemAt((int)pos.frames(m_document->fps()) + 1, track);
1013         if (clip) itemList.append(clip);
1014         else emit displayMessage(i18n("Select a clip if you want to apply an effect"), ErrorMessage);
1015     }
1016     kDebug() << "// REQUESTING EFFECT ON CLIP: " << pos.frames(25) << ", TRK: " << track << "SELECTED ITEMS: " << itemList.count();
1017     for (int i = 0; i < itemList.count(); i++) {
1018         if (itemList.at(i)->type() == AVWIDGET) {
1019             ClipItem *item = (ClipItem *)itemList.at(i);
1020             item->initEffect(effect);
1021             if (effect.attribute("tag") == "ladspa") {
1022                 QString ladpsaFile = m_document->getLadspaFile();
1023                 initEffects::ladspaEffectFile(ladpsaFile, effect.attribute("ladspaid").toInt(), getLadspaParams(effect));
1024                 effect.setAttribute("src", ladpsaFile);
1025             }
1026             AddEffectCommand *command = new AddEffectCommand(this, m_document->tracksCount() - item->track(), item->startPos(), effect, true);
1027             m_commandStack->push(command);
1028         }
1029     }
1030     m_document->setModified(true);
1031 }
1032
1033 void CustomTrackView::slotDeleteEffect(ClipItem *clip, QDomElement effect) {
1034     AddEffectCommand *command = new AddEffectCommand(this, m_document->tracksCount() - clip->track(), clip->startPos(), effect, false);
1035     m_commandStack->push(command);
1036     m_document->setModified(true);
1037 }
1038
1039 void CustomTrackView::updateEffect(int track, GenTime pos, QDomElement effect, int ix, bool triggeredByUser) {
1040     ClipItem *clip = getClipItemAt((int)pos.frames(m_document->fps()) + 1, m_document->tracksCount() - track);
1041     if (clip) {
1042         EffectsParameterList effectParams = clip->getEffectArgs(effect);
1043         if (effect.attribute("tag") == "ladspa") {
1044             // Update the ladspa affect file
1045             initEffects::ladspaEffectFile(effect.attribute("src"), effect.attribute("ladspaid").toInt(), getLadspaParams(effect));
1046         }
1047         // check if we are trying to reset a keyframe effect
1048         if (effectParams.hasParam("keyframes") && effectParams.paramValue("keyframes").isEmpty()) {
1049             clip->initEffect(effect);
1050             clip->setEffectAt(ix, effect);
1051             effectParams = clip->getEffectArgs(effect);
1052         }
1053         if (effectParams.paramValue("disabled") == "1") {
1054             if (m_document->renderer()->mltRemoveEffect(track, pos, effectParams.paramValue("kdenlive_ix"), false)) {
1055                 kDebug() << "//////  DISABLING EFFECT: " << index << ", CURRENTLA: " << clip->selectedEffectIndex();
1056             } else emit displayMessage(i18n("Problem deleting effect"), ErrorMessage);
1057         } else if (!m_document->renderer()->mltEditEffect(m_document->tracksCount() - clip->track(), clip->startPos(), effectParams))
1058             emit displayMessage(i18n("Problem editing effect"), ErrorMessage);
1059
1060         clip->setEffectAt(ix, effect);
1061         if (ix == clip->selectedEffectIndex()) {
1062             clip->setSelectedEffect(ix);
1063             if (!triggeredByUser) emit clipItemSelected(clip, ix);
1064         }
1065         if (effect.attribute("tag") == "volume") {
1066             // A fade effect was modified, update the clip
1067             if (effect.attribute("id") == "fadein") {
1068                 int pos = effectParams.paramValue("out").toInt() - effectParams.paramValue("in").toInt();
1069                 clip->setFadeIn(pos);
1070             }
1071             if (effect.attribute("id") == "fadeout") {
1072                 int pos = effectParams.paramValue("out").toInt() - effectParams.paramValue("in").toInt();
1073                 clip->setFadeOut(pos);
1074             }
1075
1076         }
1077     }
1078     m_document->setModified(true);
1079 }
1080
1081 void CustomTrackView::moveEffect(int track, GenTime pos, int oldPos, int newPos) {
1082     ClipItem *clip = getClipItemAt((int)pos.frames(m_document->fps()) + 1, m_document->tracksCount() - track);
1083     if (clip) {
1084         m_document->renderer()->mltMoveEffect(track, pos, oldPos, newPos);
1085         QDomElement act = clip->effectAt(newPos - 1).cloneNode().toElement();
1086         QDomElement before = clip->effectAt(oldPos - 1).cloneNode().toElement();
1087         clip->setEffectAt(oldPos - 1, act);
1088         clip->setEffectAt(newPos - 1, before);
1089         emit clipItemSelected(clip, newPos - 1);
1090     }
1091     m_document->setModified(true);
1092 }
1093
1094 void CustomTrackView::slotChangeEffectState(ClipItem *clip, int effectPos, bool disable) {
1095     QDomElement effect = clip->effectAt(effectPos);
1096     QDomElement oldEffect = effect.cloneNode().toElement();
1097     effect.setAttribute("disabled", disable);
1098     EditEffectCommand *command = new EditEffectCommand(this, m_document->tracksCount() - clip->track(), clip->startPos(), oldEffect, effect, effectPos, true);
1099     m_commandStack->push(command);
1100     m_document->setModified(true);
1101 }
1102
1103 void CustomTrackView::slotChangeEffectPosition(ClipItem *clip, int currentPos, int newPos) {
1104     MoveEffectCommand *command = new MoveEffectCommand(this, m_document->tracksCount() - clip->track(), clip->startPos(), currentPos, newPos, true);
1105     m_commandStack->push(command);
1106     m_document->setModified(true);
1107 }
1108
1109 void CustomTrackView::slotUpdateClipEffect(ClipItem *clip, QDomElement oldeffect, QDomElement effect, int ix) {
1110     EditEffectCommand *command = new EditEffectCommand(this, m_document->tracksCount() - clip->track(), clip->startPos(), oldeffect, effect, ix, true);
1111     m_commandStack->push(command);
1112 }
1113
1114 void CustomTrackView::cutClip(ItemInfo info, GenTime cutTime, bool cut) {
1115     if (cut) {
1116         // cut clip
1117         ClipItem *item = getClipItemAt((int) info.startPos.frames(m_document->fps()) + 1, info.track);
1118         if (!item || cutTime >= item->endPos() || cutTime <= item->startPos()) {
1119             emit displayMessage(i18n("Cannot find clip to cut"), ErrorMessage);
1120             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);
1121             m_blockRefresh = false;
1122             return;
1123         }
1124         kDebug() << "/////////  CUTTING CLIP : (" << item->startPos().frames(25) << "-" << item->endPos().frames(25) << "), INFO: (" << info.startPos.frames(25) << "-" << info.endPos.frames(25) << ")" << ", CUT: " << cutTime.frames(25);
1125
1126         m_document->renderer()->mltCutClip(m_document->tracksCount() - info.track, cutTime);
1127         int cutPos = (int) cutTime.frames(m_document->fps());
1128         ItemInfo newPos;
1129         newPos.startPos = cutTime;
1130         newPos.endPos = info.endPos;
1131         newPos.cropStart = item->cropStart() + (cutTime - info.startPos);
1132         newPos.track = info.track;
1133         ClipItem *dup = item->clone(newPos);
1134         kDebug() << "// REsizing item to: " << cutPos;
1135         item->resizeEnd(cutPos, false);
1136         scene()->addItem(dup);
1137         if (item->checkKeyFrames()) slotRefreshEffects(item);
1138         if (dup->checkKeyFrames()) slotRefreshEffects(dup);
1139         item->baseClip()->addReference();
1140         m_document->updateClip(item->baseClip()->getId());
1141         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);
1142         kDebug() << "//  CUTTING CLIP dONE";
1143     } else {
1144         // uncut clip
1145
1146         ClipItem *item = getClipItemAt((int) info.startPos.frames(m_document->fps()), info.track);
1147         ClipItem *dup = getClipItemAt((int) cutTime.frames(m_document->fps()) + 1, info.track);
1148         if (!item || !dup || item == dup) {
1149             emit displayMessage(i18n("Cannot find clip to uncut"), ErrorMessage);
1150             m_blockRefresh = false;
1151             return;
1152         }
1153         if (m_document->renderer()->mltRemoveClip(m_document->tracksCount() - info.track, cutTime) == false) {
1154             emit displayMessage(i18n("Error removing clip at %1 on track %2", m_document->timecode().getTimecodeFromFrames(cutTime.frames(m_document->fps())), info.track), ErrorMessage);
1155             return;
1156         }
1157
1158         kDebug() << "// UNCUTTING CLIPS: ITEM 1 (" << item->startPos().frames(25) << "x" << item->endPos().frames(25) << ")";
1159         kDebug() << "// UNCUTTING CLIPS: ITEM 2 (" << dup->startPos().frames(25) << "x" << dup->endPos().frames(25) << ")";
1160         kDebug() << "// UNCUTTING CLIPS, INFO (" << info.startPos.frames(25) << "x" << info.endPos.frames(25) << ") , CUT: " << cutTime.frames(25);;
1161         //deleteClip(dup->info());
1162
1163
1164         if (dup->isSelected()) emit clipItemSelected(NULL);
1165         dup->baseClip()->removeReference();
1166         m_document->updateClip(dup->baseClip()->getId());
1167         scene()->removeItem(dup);
1168         delete dup;
1169
1170         ItemInfo clipinfo = item->info();
1171         clipinfo.track = m_document->tracksCount() - clipinfo.track;
1172         bool success = m_document->renderer()->mltResizeClipEnd(clipinfo, info.endPos - info.startPos);
1173         if (success) {
1174             item->resizeEnd((int) info.endPos.frames(m_document->fps()));
1175         } else
1176             emit displayMessage(i18n("Error when resizing clip"), ErrorMessage);
1177
1178     }
1179     QTimer::singleShot(3000, this, SLOT(slotEnableRefresh()));
1180 }
1181
1182 void CustomTrackView::slotEnableRefresh() {
1183     m_blockRefresh = false;
1184 }
1185
1186 void CustomTrackView::slotAddTransitionToSelectedClips(QDomElement transition) {
1187     QList<QGraphicsItem *> itemList = scene()->selectedItems();
1188     if (itemList.count() == 1) {
1189         if (itemList.at(0)->type() == AVWIDGET) {
1190             ClipItem *item = (ClipItem *) itemList.at(0);
1191             ItemInfo info;
1192             info.track = item->track();
1193             ClipItem *transitionClip = NULL;
1194             const int transitiontrack = getPreviousVideoTrack(info.track);
1195             GenTime pos = GenTime((int)(mapToScene(m_menuPosition).x()), m_document->fps());
1196             if (pos < item->startPos() + item->duration() / 2) {
1197                 // add transition to clip start
1198                 info.startPos = item->startPos();
1199                 if (transitiontrack != 0) transitionClip = getClipItemAt((int) info.startPos.frames(m_document->fps()), m_document->tracksCount() - transitiontrack);
1200                 if (transitionClip && transitionClip->endPos() < item->endPos()) {
1201                     info.endPos = transitionClip->endPos();
1202                 } else info.endPos = info.startPos + GenTime(65, m_document->fps());
1203             } else {
1204                 // add transition to clip  end
1205                 info.endPos = item->endPos();
1206                 if (transitiontrack != 0) transitionClip = getClipItemAt((int) info.endPos.frames(m_document->fps()), m_document->tracksCount() - transitiontrack);
1207                 if (transitionClip && transitionClip->startPos() > item->startPos()) {
1208                     info.startPos = transitionClip->startPos();
1209                 } else info.startPos = info.endPos - GenTime(65, m_document->fps());
1210                 if (transition.attribute("tag") == "luma") EffectsList::setParameter(transition, "reverse", "1");
1211             }
1212             slotAddTransition(item, info, transitiontrack, transition);
1213         }
1214     } else for (int i = 0; i < itemList.count(); i++) {
1215             if (itemList.at(i)->type() == AVWIDGET) {
1216                 ClipItem *item = (ClipItem *) itemList.at(i);
1217                 ItemInfo info;
1218                 info.startPos = item->startPos();
1219                 info.endPos = info.startPos + GenTime(65, m_document->fps());
1220                 info.track = item->track();
1221                 int transitiontrack = getPreviousVideoTrack(info.track);
1222                 slotAddTransition(item, info, transitiontrack, transition);
1223             }
1224         }
1225 }
1226
1227 void CustomTrackView::slotAddTransition(ClipItem* clip, ItemInfo transitionInfo, int endTrack, QDomElement transition) {
1228     if (transitionInfo.startPos >= transitionInfo.endPos) {
1229         emit displayMessage(i18n("Invalid transition"), ErrorMessage);
1230         return;
1231     }
1232     AddTransitionCommand* command = new AddTransitionCommand(this, transitionInfo, endTrack, transition, false, true);
1233     m_commandStack->push(command);
1234     m_document->setModified(true);
1235 }
1236
1237 void CustomTrackView::addTransition(ItemInfo transitionInfo, int endTrack, QDomElement params) {
1238     Transition *tr = new Transition(transitionInfo, endTrack, m_document->fps(), params, true);
1239     //kDebug() << "---- ADDING transition " << params.attribute("value");
1240     if (m_document->renderer()->mltAddTransition(tr->transitionTag(), endTrack, m_document->tracksCount() - transitionInfo.track, transitionInfo.startPos, transitionInfo.endPos, tr->toXML())) {
1241         scene()->addItem(tr);
1242         m_document->setModified(true);
1243     } else {
1244         emit displayMessage(i18n("Cannot add transition"), ErrorMessage);
1245         delete tr;
1246     }
1247 }
1248
1249 void CustomTrackView::deleteTransition(ItemInfo transitionInfo, int endTrack, QDomElement params) {
1250     Transition *item = getTransitionItemAt((int)transitionInfo.startPos.frames(m_document->fps()), transitionInfo.track);
1251     if (!item) {
1252         emit displayMessage(i18n("Select clip to delete"), ErrorMessage);
1253         return;
1254     }
1255     m_document->renderer()->mltDeleteTransition(item->transitionTag(), endTrack, m_document->tracksCount() - transitionInfo.track, transitionInfo.startPos, transitionInfo.endPos, item->toXML());
1256     if (m_dragItem == item) m_dragItem = NULL;
1257     delete item;
1258     emit transitionItemSelected(NULL);
1259     m_document->setModified(true);
1260 }
1261
1262 void CustomTrackView::slotTransitionUpdated(Transition *tr, QDomElement old) {
1263     EditTransitionCommand *command = new EditTransitionCommand(this, tr->track(), tr->startPos(), old, tr->toXML(), true);
1264     m_commandStack->push(command);
1265     m_document->setModified(true);
1266 }
1267
1268 void CustomTrackView::slotTransitionTrackUpdated(Transition *tr, int track) {
1269     QDomElement old = tr->toXML().cloneNode().toElement();
1270     if (track == 0) {
1271         track = getPreviousVideoTrack(tr->track());
1272         tr->setForcedTrack(false, track);
1273     } else {
1274         tr->setForcedTrack(true, m_document->tracksCount() + 1 - track);
1275     }
1276     EditTransitionCommand *command = new EditTransitionCommand(this, tr->track(), tr->startPos(), old, tr->toXML(), true);
1277     m_commandStack->push(command);
1278     m_document->setModified(true);
1279 }
1280
1281 void CustomTrackView::updateTransition(int track, GenTime pos, QDomElement oldTransition, QDomElement transition, bool updateTransitionWidget) {
1282     Transition *item = getTransitionItemAt((int)pos.frames(m_document->fps()), track);
1283     if (!item) {
1284         kWarning() << "Unable to find transition at pos :" << pos.frames(m_document->fps()) << ", ON track: " << track;
1285         return;
1286     }
1287     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);
1288     item->setTransitionParameters(transition);
1289     if (updateTransitionWidget) emit transitionItemSelected(item, true);
1290     m_document->setModified(true);
1291 }
1292
1293 void CustomTrackView::dragMoveEvent(QDragMoveEvent * event) {
1294     event->setDropAction(Qt::IgnoreAction);
1295     const int track = (int)(mapToScene(event->pos()).y() / m_tracksHeight);
1296     const int pos = mapToScene(event->pos()).x();
1297     //kDebug() << "// DRAG MOVE TO TRACK: " << track;
1298     if (m_selectionGroup) {
1299         m_selectionGroup->setPos(pos, event->pos().y());
1300         event->setDropAction(Qt::MoveAction);
1301         if (event->mimeData()->hasFormat("kdenlive/producerslist") || event->mimeData()->hasFormat("kdenlive/clip")) {
1302             event->acceptProposedAction();
1303         }
1304     } else {
1305         QGraphicsView::dragMoveEvent(event);
1306     }
1307 }
1308
1309 void CustomTrackView::dragLeaveEvent(QDragLeaveEvent * event) {
1310     if (m_selectionGroup) {
1311         QList<QGraphicsItem *> items = m_selectionGroup->childItems();
1312         qDeleteAll(items);
1313         scene()->destroyItemGroup(m_selectionGroup);
1314         m_selectionGroup = NULL;
1315     } else QGraphicsView::dragLeaveEvent(event);
1316 }
1317
1318 void CustomTrackView::dropEvent(QDropEvent * event) {
1319     if (m_selectionGroup) {
1320         QList<QGraphicsItem *> items = m_selectionGroup->childItems();
1321         resetSelectionGroup();
1322         m_scene->clearSelection();
1323         for (int i = 0; i < items.count(); i++) {
1324             ClipItem *item = static_cast <ClipItem *>(items.at(i));
1325             AddTimelineClipCommand *command = new AddTimelineClipCommand(this, item->xml(), item->clipProducer(), item->info(), item->effectList(), false, false);
1326             m_commandStack->push(command);
1327             item->baseClip()->addReference();
1328             m_document->updateClip(item->baseClip()->getId());
1329             ItemInfo info;
1330             info = item->info();
1331             if (item->baseClip()->isTransparent()) {
1332                 // add transparency transition
1333                 int endTrack = getPreviousVideoTrack(info.track);
1334                 Transition *tr = new Transition(info, endTrack, m_document->fps(), MainWindow::transitions.getEffectByTag("composite", "alphatransparency"), true);
1335                 if (m_document->renderer()->mltAddTransition(tr->transitionTag(), endTrack, m_document->tracksCount() - info.track, info.startPos, info.endPos, tr->toXML())) {
1336                     scene()->addItem(tr);
1337                 } else {
1338                     emit displayMessage(i18n("Cannot add transition"), ErrorMessage);
1339                     delete tr;
1340                 }
1341             }
1342             info.track = m_document->tracksCount() - item->track();
1343             m_document->renderer()->mltInsertClip(info, item->xml(), item->baseClip()->producer(item->track()));
1344             item->setSelected(true);
1345         }
1346         m_document->setModified(true);
1347     } else QGraphicsView::dropEvent(event);
1348     setFocus();
1349 }
1350
1351
1352 QStringList CustomTrackView::mimeTypes() const {
1353     QStringList qstrList;
1354     // list of accepted mime types for drop
1355     qstrList.append("text/plain");
1356     qstrList.append("kdenlive/producerslist");
1357     qstrList.append("kdenlive/clip");
1358     return qstrList;
1359 }
1360
1361 Qt::DropActions CustomTrackView::supportedDropActions() const {
1362     // returns what actions are supported when dropping
1363     return Qt::MoveAction;
1364 }
1365
1366 void CustomTrackView::setDuration(int duration) {
1367     if (duration > sceneRect().width())
1368         setSceneRect(0, 0, (duration + 100), sceneRect().height());
1369     m_projectDuration = duration;
1370 }
1371
1372 int CustomTrackView::duration() const {
1373     return m_projectDuration;
1374 }
1375
1376 void CustomTrackView::addTrack(TrackInfo type, int ix) {
1377     if (ix == -1) m_document->insertTrack(ix, type);
1378     else {
1379         m_document->insertTrack(m_document->tracksCount() - ix, type);
1380         // insert track in MLT playlist
1381         m_document->renderer()->mltInsertTrack(m_document->tracksCount() - ix, type.type == VIDEOTRACK);
1382
1383         double startY = ix * m_tracksHeight + 1 + m_tracksHeight / 2;
1384         QRectF r(0, startY, sceneRect().width(), sceneRect().height() - startY);
1385         QList<QGraphicsItem *> selection = m_scene->items(r);
1386         resetSelectionGroup();
1387
1388         m_selectionGroup = new AbstractGroupItem(m_document->fps());
1389         scene()->addItem(m_selectionGroup);
1390         for (int i = 0; i < selection.count(); i++) {
1391             if (selection.at(i)->type() == AVWIDGET || selection.at(i)->type() == TRANSITIONWIDGET)
1392                 m_selectionGroup->addToGroup(selection.at(i));
1393             selection.at(i)->setFlags(QGraphicsItem::ItemIsSelectable);
1394         }
1395         // Move graphic items
1396         m_selectionGroup->translate(0, m_tracksHeight);
1397
1398         // adjust track number
1399         QList<QGraphicsItem *> children = m_selectionGroup->childItems();
1400         for (int i = 0; i < children.count(); i++) {
1401             AbstractClipItem *item = static_cast <AbstractClipItem *>(children.at(i));
1402             item->updateItem();
1403             ItemInfo clipinfo = item->info();
1404             if (item->type() == AVWIDGET) {
1405                 ClipItem *clip = static_cast <ClipItem *>(item);
1406                 // We add a move clip command so that we get the correct producer for new track number
1407                 if (clip->clipType() == AV || clip->clipType() == AUDIO) {
1408                     m_document->renderer()->mltUpdateClipProducer((int)(m_document->tracksCount() - clipinfo.track), clipinfo.startPos.frames(m_document->fps()), clip->baseClip()->producer(clipinfo.track));
1409                     kDebug() << "// UPDATING CLIP TO TRACK PROD: " << clipinfo.track;
1410                 }
1411             } else if (item->type() == TRANSITIONWIDGET) {
1412                 Transition *tr = static_cast <Transition *>(item);
1413                 int track = tr->transitionEndTrack();
1414                 if (track >= ix) {
1415                     tr->updateTransitionEndTrack(getPreviousVideoTrack(clipinfo.track));
1416                 }
1417             }
1418         }
1419         resetSelectionGroup(false);
1420
1421     }
1422     int maxHeight = m_tracksHeight * m_document->tracksCount();
1423     for (int i = 0; i < m_guides.count(); i++) {
1424         QLineF l = m_guides.at(i)->line();
1425         l.setP2(QPointF(l.x2(), maxHeight));
1426         m_guides.at(i)->setLine(l);
1427     }
1428     m_cursorLine->setLine(m_cursorLine->line().x1(), 0, m_cursorLine->line().x1(), maxHeight);
1429     setSceneRect(0, 0, sceneRect().width(), maxHeight);
1430     QTimer::singleShot(300, this, SIGNAL(trackHeightChanged()));
1431     viewport()->update();
1432     //setFixedHeight(50 * m_tracksCount);
1433 }
1434
1435 void CustomTrackView::removeTrack(int ix) {
1436     // Delete track in MLT playlist
1437     m_document->renderer()->mltDeleteTrack(m_document->tracksCount() - ix);
1438     m_document->deleteTrack(m_document->tracksCount() - ix - 1);
1439
1440     double startY = ix * m_tracksHeight + 1 + m_tracksHeight / 2;
1441     QRectF r(0, startY, sceneRect().width(), sceneRect().height() - startY);
1442     QList<QGraphicsItem *> selection = m_scene->items(r);
1443
1444     resetSelectionGroup();
1445
1446     m_selectionGroup = new AbstractGroupItem(m_document->fps());
1447     scene()->addItem(m_selectionGroup);
1448     for (int i = 0; i < selection.count(); i++) {
1449         if (selection.at(i)->type() == AVWIDGET || selection.at(i)->type() == TRANSITIONWIDGET) {
1450             m_selectionGroup->addToGroup(selection.at(i));
1451             selection.at(i)->setFlags(QGraphicsItem::ItemIsSelectable);
1452         }
1453     }
1454     // Move graphic items
1455     qreal ydiff = 0 - (int) m_tracksHeight;
1456     m_selectionGroup->translate(0, ydiff);
1457
1458     // adjust track number
1459     QList<QGraphicsItem *> children = m_selectionGroup->childItems();
1460     //kDebug() << "// FOUND CLIPS TO MOVE: " << children.count();
1461     for (int i = 0; i < children.count(); i++) {
1462         if (children.at(i)->type() == AVWIDGET) {
1463             ClipItem *clip = static_cast <ClipItem *>(children.at(i));
1464             clip->updateItem();
1465             ItemInfo clipinfo = clip->info();
1466             kDebug() << "// CLIP TRK IS: " << clipinfo.track;
1467             // We add a move clip command so that we get the correct producer for new track number
1468             if (clip->clipType() == AV || clip->clipType() == AUDIO)
1469                 m_document->renderer()->mltUpdateClipProducer((int)(m_document->tracksCount() - clipinfo.track), clipinfo.startPos.frames(m_document->fps()), clip->baseClip()->producer(clipinfo.track));
1470         } else if (children.at(i)->type() == TRANSITIONWIDGET) {
1471             Transition *tr = static_cast <Transition *>(children.at(i));
1472             tr->updateItem();
1473             int track = tr->transitionEndTrack();
1474             if (track >= ix) {
1475                 ItemInfo clipinfo = tr->info();
1476                 tr->updateTransitionEndTrack(getPreviousVideoTrack(clipinfo.track));
1477             }
1478         }
1479     }
1480     resetSelectionGroup(false);
1481
1482     int maxHeight = m_tracksHeight * m_document->tracksCount();
1483     for (int i = 0; i < m_guides.count(); i++) {
1484         QLineF l = m_guides.at(i)->line();
1485         l.setP2(QPointF(l.x2(), maxHeight));
1486         m_guides.at(i)->setLine(l);
1487     }
1488     m_cursorLine->setLine(m_cursorLine->line().x1(), 0, m_cursorLine->line().x1(), maxHeight);
1489     setSceneRect(0, 0, sceneRect().width(), maxHeight);
1490     QTimer::singleShot(300, this, SIGNAL(trackHeightChanged()));
1491     viewport()->update();
1492 }
1493
1494 void CustomTrackView::changeTrack(int ix, TrackInfo type) {
1495     int tracknumber = m_document->tracksCount() - ix;
1496     m_document->setTrackType(tracknumber - 1, type);
1497     m_document->renderer()->mltChangeTrackState(tracknumber, m_document->trackInfoAt(tracknumber - 1).isMute, m_document->trackInfoAt(tracknumber - 1).isBlind);
1498     QTimer::singleShot(300, this, SIGNAL(trackHeightChanged()));
1499     viewport()->update();
1500 }
1501
1502
1503 void CustomTrackView::slotSwitchTrackAudio(int ix) {
1504     /*for (int i = 0; i < m_document->tracksCount(); i++)
1505         kDebug() << "TRK " << i << " STATE: " << m_document->trackInfoAt(i).isMute << m_document->trackInfoAt(i).isBlind;*/
1506
1507     int tracknumber = m_document->tracksCount() - ix;
1508
1509     m_document->switchTrackAudio(tracknumber - 1, !m_document->trackInfoAt(tracknumber - 1).isMute);
1510     kDebug() << "NEXT TRK STATE: " << m_document->trackInfoAt(tracknumber - 1).isMute << m_document->trackInfoAt(tracknumber - 1).isBlind;
1511     m_document->renderer()->mltChangeTrackState(tracknumber, m_document->trackInfoAt(tracknumber - 1).isMute, m_document->trackInfoAt(tracknumber - 1).isBlind);
1512     m_document->setModified(true);
1513 }
1514
1515 void CustomTrackView::slotSwitchTrackVideo(int ix) {
1516     int tracknumber = m_document->tracksCount() - ix;
1517     m_document->switchTrackVideo(tracknumber - 1, !m_document->trackInfoAt(tracknumber - 1).isBlind);
1518     m_document->renderer()->mltChangeTrackState(tracknumber, m_document->trackInfoAt(tracknumber - 1).isMute, m_document->trackInfoAt(tracknumber - 1).isBlind);
1519     m_document->setModified(true);
1520 }
1521
1522 void CustomTrackView::slotRemoveSpace() {
1523     GenTime pos;
1524     int track = 0;
1525     if (m_menuPosition.isNull()) {
1526         pos = GenTime(cursorPos(), m_document->fps());
1527         bool ok;
1528         track = QInputDialog::getInteger(this, i18n("Remove Space"), i18n("Track"), 0, 0, m_document->tracksCount() - 1, 1, &ok);
1529         if (!ok) return;
1530     } else {
1531         pos = GenTime((int)(mapToScene(m_menuPosition).x()), m_document->fps());
1532         track = (int)(mapToScene(m_menuPosition).y() / m_tracksHeight);
1533     }
1534     ClipItem *item = getClipItemAt(pos, track);
1535     if (item) {
1536         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);
1537         return;
1538     }
1539     int length = m_document->renderer()->mltGetSpaceLength(pos, m_document->tracksCount() - track, true);
1540     //kDebug() << "// GOT LENGT; " << length;
1541     if (length <= 0) {
1542         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);
1543         return;
1544     }
1545
1546     QRectF r(pos.frames(m_document->fps()), track * m_tracksHeight + m_tracksHeight / 2, sceneRect().width() - pos.frames(m_document->fps()), m_tracksHeight / 2 - 1);
1547     QList<QGraphicsItem *> items = m_scene->items(r);
1548
1549     QList<ItemInfo> clipsToMove = QList<ItemInfo> ();
1550     QList<ItemInfo> transitionsToMove = QList<ItemInfo> ();
1551
1552     for (int i = 0; i < items.count(); i++) {
1553         if (items.at(i)->type() == AVWIDGET || items.at(i)->type() == TRANSITIONWIDGET) {
1554             AbstractClipItem *item = static_cast <AbstractClipItem *>(items.at(i));
1555             ItemInfo info = item->info();
1556             if (item->type() == AVWIDGET) {
1557                 clipsToMove.append(info);
1558             } else if (item->type() == TRANSITIONWIDGET) {
1559                 transitionsToMove.append(info);
1560             }
1561         }
1562     }
1563
1564     InsertSpaceCommand *command = new InsertSpaceCommand(this, clipsToMove, transitionsToMove, track, GenTime(-length, m_document->fps()), true);
1565     m_commandStack->push(command);
1566 }
1567
1568 void CustomTrackView::slotInsertSpace() {
1569     GenTime pos;
1570     int track = 0;
1571     if (m_menuPosition.isNull()) {
1572         pos = GenTime(cursorPos(), m_document->fps());
1573     } else {
1574         pos = GenTime((int)(mapToScene(m_menuPosition).x()), m_document->fps());
1575         track = (int)(mapToScene(m_menuPosition).y() / m_tracksHeight) + 1;
1576     }
1577     SpacerDialog d(GenTime(65, m_document->fps()), m_document->timecode(), track, m_document->tracksCount(), this);
1578     if (d.exec() != QDialog::Accepted) return;
1579     GenTime spaceDuration = d.selectedDuration();
1580     track = d.selectedTrack();
1581     ClipItem *item = getClipItemAt(pos, track);
1582     if (item) pos = item->startPos();
1583
1584     int minh = 0;
1585     int maxh = sceneRect().height();
1586     if (track != -1) {
1587         minh = track * m_tracksHeight + m_tracksHeight / 2;
1588         maxh = m_tracksHeight / 2 - 1;
1589     }
1590
1591     QRectF r(pos.frames(m_document->fps()), minh, sceneRect().width() - pos.frames(m_document->fps()), maxh);
1592     QList<QGraphicsItem *> items = m_scene->items(r);
1593
1594     QList<ItemInfo> clipsToMove = QList<ItemInfo> ();
1595     QList<ItemInfo> transitionsToMove = QList<ItemInfo> ();
1596
1597     for (int i = 0; i < items.count(); i++) {
1598         if (items.at(i)->type() == AVWIDGET || items.at(i)->type() == TRANSITIONWIDGET) {
1599             AbstractClipItem *item = static_cast <AbstractClipItem *>(items.at(i));
1600             ItemInfo info = item->info();
1601             if (item->type() == AVWIDGET) {
1602                 clipsToMove.append(info);
1603             } else if (item->type() == TRANSITIONWIDGET) {
1604                 transitionsToMove.append(info);
1605             }
1606         }
1607     }
1608
1609     InsertSpaceCommand *command = new InsertSpaceCommand(this, clipsToMove, transitionsToMove, track, spaceDuration, true);
1610     m_commandStack->push(command);
1611 }
1612
1613 void CustomTrackView::insertSpace(QList<ItemInfo> clipsToMove, QList<ItemInfo> transToMove, int track, const GenTime duration, const GenTime offset) {
1614     int diff = duration.frames(m_document->fps());
1615     resetSelectionGroup();
1616     m_selectionGroup = new AbstractGroupItem(m_document->fps());
1617     scene()->addItem(m_selectionGroup);
1618     ClipItem *clip;
1619     Transition *transition;
1620
1621     kDebug() << "/// STARTING SPACE INSERT";
1622
1623
1624     // Create lists with start pos for each track
1625     QMap <int, int> trackClipStartList;
1626     QMap <int, int> trackTransitionStartList;
1627
1628     for (int i = 1; i < m_document->tracksCount() + 1; i++) {
1629         trackClipStartList[i] = -1;
1630         trackTransitionStartList[i] = -1;
1631     }
1632
1633     if (!clipsToMove.isEmpty()) for (int i = 0; i < clipsToMove.count(); i++) {
1634             kDebug() << "/// FETCHING CLIP: " << i;
1635             clip = getClipItemAtStart(clipsToMove.at(i).startPos + offset, clipsToMove.at(i).track);
1636             if (clip) {
1637                 m_selectionGroup->addToGroup(clip);
1638                 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))
1639                     trackClipStartList[m_document->tracksCount() - clipsToMove.at(i).track] = clipsToMove.at(i).startPos.frames(m_document->fps());
1640                 clip->setFlags(QGraphicsItem::ItemIsSelectable);
1641             } 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);
1642         }
1643     if (!transToMove.isEmpty()) for (int i = 0; i < transToMove.count(); i++) {
1644             kDebug() << "/// FETCHING TRANS: " << i;
1645             transition = getTransitionItemAtStart(transToMove.at(i).startPos + offset, transToMove.at(i).track);
1646             if (transition) {
1647                 m_selectionGroup->addToGroup(transition);
1648                 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))
1649                     trackTransitionStartList[m_document->tracksCount() - transToMove.at(i).track] = transToMove.at(i).startPos.frames(m_document->fps());
1650                 transition->setFlags(QGraphicsItem::ItemIsSelectable);
1651             } 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);
1652         }
1653     kDebug() << "/// STARTING SPACE DONE";
1654     m_selectionGroup->translate(diff, 0);
1655     resetSelectionGroup(false);
1656     kDebug() << "/// STARTING SPACE DONE2";
1657     if (track != -1) track = m_document->tracksCount() - track;
1658     m_document->renderer()->mltInsertSpace(trackClipStartList, trackTransitionStartList, track, duration, offset);
1659 }
1660
1661 void CustomTrackView::deleteClip(const QString &clipId) {
1662     QList<QGraphicsItem *> itemList = items();
1663     for (int i = 0; i < itemList.count(); i++) {
1664         if (itemList.at(i)->type() == AVWIDGET) {
1665             ClipItem *item = (ClipItem *)itemList.at(i);
1666             if (item->clipProducer() == clipId) {
1667                 AddTimelineClipCommand *command = new AddTimelineClipCommand(this, item->xml(), item->clipProducer(), item->info(), item->effectList(), true, true);
1668                 m_commandStack->push(command);
1669                 //delete item;
1670             }
1671         }
1672     }
1673 }
1674
1675 void CustomTrackView::setCursorPos(int pos, bool seek) {
1676     emit cursorMoved((int)(m_cursorPos), (int)(pos));
1677     m_cursorPos = pos;
1678     m_cursorLine->setPos(pos, 0);
1679     if (seek) m_document->renderer()->seek(GenTime(pos, m_document->fps()));
1680     else if (m_autoScroll) checkScrolling();
1681 }
1682
1683 void CustomTrackView::updateCursorPos() {
1684     m_cursorLine->setPos(m_cursorPos, 0);
1685 }
1686
1687 int CustomTrackView::cursorPos() {
1688     return (int)(m_cursorPos);
1689 }
1690
1691 void CustomTrackView::moveCursorPos(int delta) {
1692     if (m_cursorPos + delta < 0) delta = 0 - m_cursorPos;
1693     emit cursorMoved((int)(m_cursorPos), (int)((m_cursorPos + delta)));
1694     m_cursorPos += delta;
1695     m_cursorLine->setPos(m_cursorPos, 0);
1696     m_document->renderer()->seek(GenTime(m_cursorPos, m_document->fps()));
1697 }
1698
1699 void CustomTrackView::initCursorPos(int pos) {
1700     emit cursorMoved((int)(m_cursorPos), (int)(pos));
1701     m_cursorPos = pos;
1702     m_cursorLine->setPos(pos, 0);
1703     checkScrolling();
1704 }
1705
1706 void CustomTrackView::checkScrolling() {
1707     int vert = verticalScrollBar()->value();
1708     int hor = cursorPos();
1709     ensureVisible(hor, vert + 10, 2, 2, 50, 0);
1710 }
1711
1712 void CustomTrackView::mouseReleaseEvent(QMouseEvent * event) {
1713     if (m_moveOpMode == SEEK) m_moveOpMode = NONE;
1714     QGraphicsView::mouseReleaseEvent(event);
1715     if (m_scrollTimer.isActive()) m_scrollTimer.stop();
1716     if (event->button() == Qt::MidButton) {
1717         return;
1718     }
1719     setDragMode(QGraphicsView::NoDrag);
1720     if (m_operationMode == MOVEGUIDE) {
1721         setCursor(Qt::ArrowCursor);
1722         m_operationMode = NONE;
1723         m_dragGuide->setFlag(QGraphicsItem::ItemIsMovable, false);
1724         EditGuideCommand *command = new EditGuideCommand(this, m_dragGuide->position(), m_dragGuide->label(), GenTime(m_dragGuide->pos().x(), m_document->fps()), m_dragGuide->label(), false);
1725         m_commandStack->push(command);
1726         m_dragGuide->updateGuide(GenTime(m_dragGuide->pos().x(), m_document->fps()));
1727         m_dragGuide = NULL;
1728         m_dragItem = NULL;
1729         return;
1730     } else if (m_operationMode == SPACER) {
1731         int endClick = (int)(mapToScene(event->pos()).x() + 0.5);
1732         int mappedClick = (int)(mapToScene(m_clickEvent).x() + 0.5);
1733         int track = (int)(mapToScene(m_clickEvent).y() / m_tracksHeight);
1734         if (m_selectionGroup->sceneBoundingRect().height() > m_tracksHeight) {
1735             // We are moving all tracks
1736             track = -1;
1737         }
1738
1739         int startPos = (int) m_selectionGroup->boundingRect().topLeft().x();
1740         int diff = ((int) m_selectionGroup->pos().x()) - startPos;
1741         //kDebug()<<"//////// SPACER DIFF: "<<diff<<<<m_selectionGroup->boundingRect().topLeft();
1742         if (diff != 0) {
1743             QList<QGraphicsItem *> items = m_selectionGroup->childItems();
1744
1745             QList<ItemInfo> clipsToMove = QList<ItemInfo> ();
1746             QList<ItemInfo> transitionsToMove = QList<ItemInfo> ();
1747
1748             // Create lists with start pos for each track
1749             QMap <int, int> trackClipStartList;
1750             QMap <int, int> trackTransitionStartList;
1751
1752             for (int i = 1; i < m_document->tracksCount() + 1; i++) {
1753                 trackClipStartList[i] = -1;
1754                 trackTransitionStartList[i] = -1;
1755             }
1756
1757             for (int i = 0; i < items.count(); i++) {
1758                 AbstractClipItem *item = static_cast <AbstractClipItem *>(items.at(i));
1759                 ItemInfo info = item->info();
1760                 if (item->type() == AVWIDGET) {
1761                     clipsToMove.append(info);
1762                     if (trackClipStartList.value(m_document->tracksCount() - info.track) == -1 || info.startPos.frames(m_document->fps()) < trackClipStartList.value(m_document->tracksCount() - info.track))
1763                         trackClipStartList[m_document->tracksCount() - info.track] = info.startPos.frames(m_document->fps());
1764                 } else if (item->type() == TRANSITIONWIDGET) {
1765                     transitionsToMove.append(info);
1766                     if (trackClipStartList.value(m_document->tracksCount() - info.track) == -1 || info.startPos.frames(m_document->fps()) < trackTransitionStartList.value(m_document->tracksCount() - info.track))
1767                         trackTransitionStartList[m_document->tracksCount() - info.track] = info.startPos.frames(m_document->fps());
1768                 }
1769             }
1770
1771             InsertSpaceCommand *command = new InsertSpaceCommand(this, clipsToMove, transitionsToMove, track, GenTime(diff, m_document->fps()), false);
1772             m_commandStack->push(command);
1773             if (track != -1) track = m_document->tracksCount() - track;
1774             m_document->renderer()->mltInsertSpace(trackClipStartList, trackTransitionStartList, track, GenTime(diff, m_document->fps()), GenTime());
1775         }
1776         resetSelectionGroup(false);
1777         m_operationMode = NONE;
1778     } else if (m_operationMode == RUBBERSELECTION) {
1779         kDebug() << "// END RUBBER SELECT";
1780         resetSelectionGroup();
1781         groupSelectedItems();
1782         m_operationMode = NONE;
1783     }
1784
1785     if (m_dragItem == NULL && m_selectionGroup == NULL) {
1786         emit transitionItemSelected(NULL);
1787         return;
1788     }
1789     ItemInfo info;
1790     if (m_dragItem) info = m_dragItem->info();
1791
1792     if (m_operationMode == MOVE) {
1793         setCursor(Qt::OpenHandCursor);
1794
1795         if (m_selectionGroup == NULL) {
1796             // we are moving one clip, easy
1797             if (m_dragItem->type() == AVWIDGET && (m_dragItemInfo.startPos != info.startPos || m_dragItemInfo.track != info.track)) {
1798                 ClipItem *item = static_cast <ClipItem *>(m_dragItem);
1799                 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())), item->baseClip()->producer(info.track));
1800                 if (success) {
1801                     QUndoCommand *moveCommand = new QUndoCommand();
1802                     moveCommand->setText(i18n("Move clip"));
1803                     new MoveClipCommand(this, m_dragItemInfo, info, false, moveCommand);
1804                     // Also move automatic transitions (on lower track)
1805                     Transition *tr = getTransitionItemAtStart(m_dragItemInfo.startPos, m_dragItemInfo.track);
1806                     if (tr && tr->isAutomatic()) {
1807                         ItemInfo trInfo = tr->info();
1808                         ItemInfo newTrInfo = trInfo;
1809                         newTrInfo.track = info.track;
1810                         newTrInfo.startPos = m_dragItem->startPos();
1811                         if (m_dragItemInfo.track == info.track && !item->baseClip()->isTransparent() && getClipItemAtEnd(newTrInfo.endPos, m_document->tracksCount() - tr->transitionEndTrack())) {
1812                             // transition end should stay the same
1813                         } else {
1814                             // transition end should be adjusted to clip
1815                             newTrInfo.endPos = newTrInfo.endPos + (newTrInfo.startPos - trInfo.startPos);
1816                         }
1817                         if (newTrInfo.startPos < newTrInfo.endPos) new MoveTransitionCommand(this, trInfo, newTrInfo, true, moveCommand);
1818                     }
1819                     if (tr == NULL || tr->endPos() < m_dragItemInfo.endPos) {
1820                         // Check if there is a transition at clip end
1821                         tr = getTransitionItemAtEnd(m_dragItemInfo.endPos, m_dragItemInfo.track);
1822                         if (tr && tr->isAutomatic()) {
1823                             ItemInfo trInfo = tr->info();
1824                             ItemInfo newTrInfo = trInfo;
1825                             newTrInfo.track = info.track;
1826                             newTrInfo.endPos = m_dragItem->endPos();
1827                             if (m_dragItemInfo.track == info.track && !item->baseClip()->isTransparent() && getClipItemAtStart(trInfo.startPos, m_document->tracksCount() - tr->transitionEndTrack())) {
1828                                 // transition start should stay the same
1829                             } else {
1830                                 // transition start should be moved
1831                                 newTrInfo.startPos = newTrInfo.startPos + (newTrInfo.endPos - trInfo.endPos);
1832                             }
1833                             if (newTrInfo.startPos < newTrInfo.endPos)
1834                                 new MoveTransitionCommand(this, trInfo, newTrInfo, true, moveCommand);
1835                         }
1836                     }
1837                     // Also move automatic transitions (on upper track)
1838                     tr = getTransitionItemAtStart(m_dragItemInfo.startPos, m_dragItemInfo.track - 1);
1839                     if (m_dragItemInfo.track == info.track && tr && tr->isAutomatic() && (m_document->tracksCount() - tr->transitionEndTrack()) == m_dragItemInfo.track) {
1840                         ItemInfo trInfo = tr->info();
1841                         ItemInfo newTrInfo = trInfo;
1842                         newTrInfo.startPos = m_dragItem->startPos();
1843                         ClipItem * upperClip = getClipItemAt(m_dragItemInfo.startPos, m_dragItemInfo.track - 1);
1844                         if (!upperClip || !upperClip->baseClip()->isTransparent()) {
1845                             if (!getClipItemAtEnd(newTrInfo.endPos, tr->track())) {
1846                                 // transition end should be adjusted to clip on upper track
1847                                 newTrInfo.endPos = newTrInfo.endPos + (newTrInfo.startPos - trInfo.startPos);
1848                             }
1849                             if (newTrInfo.startPos < newTrInfo.endPos) new MoveTransitionCommand(this, trInfo, newTrInfo, true, moveCommand);
1850                         }
1851                     }
1852                     if (m_dragItemInfo.track == info.track && (tr == NULL || tr->endPos() < m_dragItemInfo.endPos)) {
1853                         // Check if there is a transition at clip end
1854                         tr = getTransitionItemAtEnd(m_dragItemInfo.endPos, m_dragItemInfo.track - 1);
1855                         if (tr && tr->isAutomatic() && (m_document->tracksCount() - tr->transitionEndTrack()) == m_dragItemInfo.track) {
1856                             ItemInfo trInfo = tr->info();
1857                             ItemInfo newTrInfo = trInfo;
1858                             newTrInfo.endPos = m_dragItem->endPos();
1859                             ClipItem * upperClip = getClipItemAt(m_dragItemInfo.startPos, m_dragItemInfo.track - 1);
1860                             if (!upperClip || !upperClip->baseClip()->isTransparent()) {
1861                                 if (!getClipItemAtStart(trInfo.startPos, tr->track())) {
1862                                     // transition start should be moved
1863                                     newTrInfo.startPos = newTrInfo.startPos + (newTrInfo.endPos - trInfo.endPos);
1864                                 }
1865                                 if (newTrInfo.startPos < newTrInfo.endPos) new MoveTransitionCommand(this, trInfo, newTrInfo, true, moveCommand);
1866                             }
1867                         }
1868                     }
1869                     m_commandStack->push(moveCommand);
1870                 } else {
1871                     // undo last move and emit error message
1872                     MoveClipCommand *command = new MoveClipCommand(this, info, m_dragItemInfo, true);
1873                     m_commandStack->push(command);
1874                     emit displayMessage(i18n("Cannot move clip to position %1", m_document->timecode().getTimecodeFromFrames(m_dragItemInfo.startPos.frames(m_document->fps()))), ErrorMessage);
1875                 }
1876             }
1877             if (m_dragItem->type() == TRANSITIONWIDGET && (m_dragItemInfo.startPos != info.startPos || m_dragItemInfo.track != info.track)) {
1878                 Transition *transition = static_cast <Transition *>(m_dragItem);
1879                 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)) {
1880                     // Moving transition failed, revert to previous position
1881                     emit displayMessage(i18n("Cannot move transition"), ErrorMessage);
1882                     transition->setPos((int) m_dragItemInfo.startPos.frames(m_document->fps()), (m_dragItemInfo.track) * m_tracksHeight + 1);
1883                 } else {
1884                     MoveTransitionCommand *command = new MoveTransitionCommand(this, m_dragItemInfo, info, false);
1885                     m_commandStack->push(command);
1886                     transition->updateTransitionEndTrack(getPreviousVideoTrack(m_dragItem->track()));
1887                 }
1888             }
1889         } else {
1890             // Moving several clips. We need to delete them and readd them to new position,
1891             // or they might overlap each other during the move
1892
1893             QList<QGraphicsItem *> items = m_selectionGroup->childItems();
1894
1895             QList<ItemInfo> clipsToMove = QList<ItemInfo> ();
1896             QList<ItemInfo> transitionsToMove = QList<ItemInfo> ();
1897
1898             GenTime timeOffset = GenTime(m_selectionGroup->scenePos().x(), m_document->fps()) - m_selectionGroupInfo.startPos;
1899             const int trackOffset = m_selectionGroup->track() - m_selectionGroupInfo.track;
1900             if (timeOffset != GenTime() || trackOffset != 0) {
1901                 QUndoCommand *moveClips = new QUndoCommand();
1902                 moveClips->setText(i18n("Move group"));
1903                 // remove items in MLT playlist
1904                 for (int i = 0; i < items.count(); i++) {
1905                     AbstractClipItem *item = static_cast <AbstractClipItem *>(items.at(i));
1906                     ItemInfo info = item->info();
1907                     if (item->type() == AVWIDGET) {
1908                         if (m_document->renderer()->mltRemoveClip(m_document->tracksCount() - info.track, info.startPos) == false) {
1909                             // error, clip cannot be removed from playlist
1910                             emit displayMessage(i18n("Error removing clip at %1 on track %2", m_document->timecode().getTimecodeFromFrames(info.startPos.frames(m_document->fps())), info.track), ErrorMessage);
1911                         } else {
1912                             clipsToMove.append(info);
1913                         }
1914                     } else {
1915                         transitionsToMove.append(info);
1916                         Transition *tr = static_cast <Transition*>(item);
1917                         m_document->renderer()->mltDeleteTransition(tr->transitionTag(), tr->transitionEndTrack(), m_document->tracksCount() - info.track, info.startPos, info.endPos, tr->toXML());
1918                     }
1919                 }
1920
1921                 for (int i = 0; i < items.count(); i++) {
1922                     // re-add items in correct place
1923                     AbstractClipItem *item = static_cast <AbstractClipItem *>(items.at(i));
1924                     item->updateItem();
1925                     ItemInfo info = item->info();
1926                     if (item->type() == AVWIDGET) {
1927                         ClipItem *clip = static_cast <ClipItem*>(item);
1928                         info.track = m_document->tracksCount() - info.track;
1929                         m_document->renderer()->mltInsertClip(info, clip->xml(), clip->baseClip()->producer(info.track));
1930                         for (int i = 0; i < clip->effectsCount(); i++) {
1931                             m_document->renderer()->mltAddEffect(info.track, info.startPos, clip->getEffectArgs(clip->effectAt(i)), false);
1932                         }
1933                     } else {
1934                         Transition *tr = static_cast <Transition*>(item);
1935                         int newTrack = tr->transitionEndTrack();
1936                         if (!tr->forcedTrack()) {
1937                             newTrack = getPreviousVideoTrack(info.track);
1938                         }
1939                         tr->updateTransitionEndTrack(newTrack);
1940                         m_document->renderer()->mltAddTransition(tr->transitionTag(), newTrack, m_document->tracksCount() - info.track, info.startPos, info.endPos, tr->toXML());
1941                     }
1942                 }
1943
1944                 new MoveGroupCommand(this, clipsToMove, transitionsToMove, timeOffset, trackOffset, false, moveClips);
1945                 m_commandStack->push(moveClips);
1946
1947                 QPointF top = m_selectionGroup->sceneBoundingRect().topLeft();
1948                 //QPointF oldpos = m_selectionGroup->scenePos();
1949                 //kDebug()<<"SELECTION GRP POS: "<<m_selectionGroup->scenePos()<<", TOP: "<<top;
1950                 m_selectionGroup->setPos(top);
1951                 m_selectionGroupInfo.startPos = GenTime(m_selectionGroup->scenePos().x(), m_document->fps());
1952                 m_selectionGroupInfo.track = m_selectionGroup->track();
1953             }
1954         }
1955
1956     } else if (m_operationMode == RESIZESTART && m_dragItem->startPos() != m_dragItemInfo.startPos) {
1957         // resize start
1958         if (m_dragItem->type() == AVWIDGET) {
1959             ItemInfo resizeinfo = m_dragItemInfo;
1960             resizeinfo.track = m_document->tracksCount() - resizeinfo.track;
1961             bool success = m_document->renderer()->mltResizeClipStart(resizeinfo, m_dragItem->startPos() - m_dragItemInfo.startPos);
1962             if (success) {
1963                 QUndoCommand *resizeCommand = new QUndoCommand();
1964                 resizeCommand->setText(i18n("Resize clip"));
1965
1966                 // Check if there is an automatic transition on that clip (lower track)
1967                 Transition *transition = getTransitionItemAtStart(m_dragItemInfo.startPos, m_dragItemInfo.track);
1968                 if (transition && transition->isAutomatic()) {
1969                     ItemInfo trInfo = transition->info();
1970                     ItemInfo newTrInfo = trInfo;
1971                     newTrInfo.startPos = m_dragItem->startPos();
1972                     if (newTrInfo.startPos < newTrInfo.endPos)
1973                         new MoveTransitionCommand(this, trInfo, newTrInfo, true, resizeCommand);
1974                 }
1975                 // Check if there is an automatic transition on that clip (upper track)
1976                 transition = getTransitionItemAtStart(m_dragItemInfo.startPos, m_dragItemInfo.track - 1);
1977                 if (transition && transition->isAutomatic() && (m_document->tracksCount() - transition->transitionEndTrack()) == m_dragItemInfo.track) {
1978                     ItemInfo trInfo = transition->info();
1979                     ItemInfo newTrInfo = trInfo;
1980                     newTrInfo.startPos = m_dragItem->startPos();
1981                     ClipItem * upperClip = getClipItemAt(m_dragItemInfo.startPos, m_dragItemInfo.track - 1);
1982                     if ((!upperClip || !upperClip->baseClip()->isTransparent()) && newTrInfo.startPos < newTrInfo.endPos) {
1983                         new MoveTransitionCommand(this, trInfo, newTrInfo, true, resizeCommand);
1984                     }
1985                 }
1986                 updateClipFade(static_cast <ClipItem *>(m_dragItem));
1987                 new ResizeClipCommand(this, m_dragItemInfo, info, false, resizeCommand);
1988                 m_commandStack->push(resizeCommand);
1989             } else {
1990                 m_dragItem->resizeStart((int) m_dragItemInfo.startPos.frames(m_document->fps()));
1991                 emit displayMessage(i18n("Error when resizing clip"), ErrorMessage);
1992             }
1993         } else if (m_dragItem->type() == TRANSITIONWIDGET) {
1994             Transition *transition = static_cast <Transition *>(m_dragItem);
1995             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)) {
1996                 // Cannot resize transition
1997                 transition->resizeStart((int) m_dragItemInfo.startPos.frames(m_document->fps()));
1998                 emit displayMessage(i18n("Cannot resize transition"), ErrorMessage);
1999             } else {
2000                 MoveTransitionCommand *command = new MoveTransitionCommand(this, m_dragItemInfo, info, false);
2001                 m_commandStack->push(command);
2002             }
2003
2004         }
2005
2006         //m_document->renderer()->doRefresh();
2007     } else if (m_operationMode == RESIZEEND && m_dragItem->endPos() != m_dragItemInfo.endPos) {
2008         // resize end
2009         if (m_dragItem->type() == AVWIDGET) {
2010             ItemInfo resizeinfo = info;
2011             resizeinfo.track = m_document->tracksCount() - resizeinfo.track;
2012             bool success = m_document->renderer()->mltResizeClipEnd(resizeinfo, resizeinfo.endPos - resizeinfo.startPos);
2013             if (success) {
2014                 QUndoCommand *resizeCommand = new QUndoCommand();
2015                 resizeCommand->setText(i18n("Resize clip"));
2016
2017                 // Check if there is an automatic transition on that clip (lower track)
2018                 Transition *tr = getTransitionItemAtEnd(m_dragItemInfo.endPos, m_dragItemInfo.track);
2019                 if (tr && tr->isAutomatic()) {
2020                     ItemInfo trInfo = tr->info();
2021                     ItemInfo newTrInfo = trInfo;
2022                     newTrInfo.endPos = m_dragItem->endPos();
2023                     if (newTrInfo.endPos > newTrInfo.startPos) new MoveTransitionCommand(this, trInfo, newTrInfo, true, resizeCommand);
2024                 }
2025
2026                 // Check if there is an automatic transition on that clip (upper track)
2027                 tr = getTransitionItemAtEnd(m_dragItemInfo.endPos, m_dragItemInfo.track - 1);
2028                 if (tr && tr->isAutomatic() && (m_document->tracksCount() - tr->transitionEndTrack()) == m_dragItemInfo.track) {
2029                     ItemInfo trInfo = tr->info();
2030                     ItemInfo newTrInfo = trInfo;
2031                     newTrInfo.endPos = m_dragItem->endPos();
2032                     ClipItem * upperClip = getClipItemAtEnd(m_dragItemInfo.endPos, m_dragItemInfo.track - 1);
2033                     if ((!upperClip || !upperClip->baseClip()->isTransparent()) && newTrInfo.endPos > newTrInfo.startPos) {
2034                         new MoveTransitionCommand(this, trInfo, newTrInfo, true, resizeCommand);
2035                     }
2036                 }
2037
2038                 new ResizeClipCommand(this, m_dragItemInfo, info, false, resizeCommand);
2039                 m_commandStack->push(resizeCommand);
2040                 updateClipFade(static_cast <ClipItem *>(m_dragItem), true);
2041             } else {
2042                 m_dragItem->resizeEnd((int) m_dragItemInfo.endPos.frames(m_document->fps()));
2043                 emit displayMessage(i18n("Error when resizing clip"), ErrorMessage);
2044             }
2045         } else if (m_dragItem->type() == TRANSITIONWIDGET) {
2046             Transition *transition = static_cast <Transition *>(m_dragItem);
2047             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)) {
2048                 // Cannot resize transition
2049                 transition->resizeEnd((int) m_dragItemInfo.endPos.frames(m_document->fps()));
2050                 emit displayMessage(i18n("Cannot resize transition"), ErrorMessage);
2051             } else {
2052                 MoveTransitionCommand *command = new MoveTransitionCommand(this, m_dragItemInfo, info, false);
2053                 m_commandStack->push(command);
2054             }
2055         }
2056         //m_document->renderer()->doRefresh();
2057     } else if (m_operationMode == FADEIN) {
2058         // resize fade in effect
2059         ClipItem * item = (ClipItem *) m_dragItem;
2060         int ix = item->hasEffect("volume", "fadein");
2061         if (ix != -1) {
2062             QDomElement oldeffect = item->effectAt(ix);
2063             int start = item->cropStart().frames(m_document->fps());
2064             int end = item->fadeIn();
2065             if (end == 0) {
2066                 slotDeleteEffect(item, oldeffect);
2067             } else {
2068                 end += start;
2069                 QDomElement effect = oldeffect.cloneNode().toElement();
2070                 EffectsList::setParameter(oldeffect, "in", QString::number(start));
2071                 EffectsList::setParameter(oldeffect, "out", QString::number(end));
2072                 slotUpdateClipEffect(item, effect, oldeffect, ix);
2073                 emit clipItemSelected(item, ix);
2074             }
2075         } else if (item->fadeIn() != 0) {
2076             QDomElement effect = MainWindow::audioEffects.getEffectByTag("volume", "fadein").cloneNode().toElement();
2077             EffectsList::setParameter(effect, "out", QString::number(item->fadeIn()));
2078             slotAddEffect(effect, m_dragItem->startPos(), m_dragItem->track());
2079         }
2080     } else if (m_operationMode == FADEOUT) {
2081         // resize fade in effect
2082         ClipItem * item = (ClipItem *) m_dragItem;
2083         int ix = item->hasEffect("volume", "fadeout");
2084         if (ix != -1) {
2085             QDomElement oldeffect = item->effectAt(ix);
2086             int end = (item->duration() + item->cropStart()).frames(m_document->fps());
2087             int start = item->fadeOut();
2088             if (start == 0) {
2089                 slotDeleteEffect(item, oldeffect);
2090             } else {
2091                 start = end - start;
2092                 QDomElement effect = oldeffect.cloneNode().toElement();
2093                 EffectsList::setParameter(oldeffect, "in", QString::number(start));
2094                 EffectsList::setParameter(oldeffect, "out", QString::number(end));
2095                 // kDebug()<<"EDIT FADE OUT : "<<start<<"x"<<end;
2096                 slotUpdateClipEffect(item, effect, oldeffect, ix);
2097                 emit clipItemSelected(item, ix);
2098             }
2099         } else if (item->fadeOut() != 0) {
2100             QDomElement effect = MainWindow::audioEffects.getEffectByTag("volume", "fadeout").cloneNode().toElement();
2101             EffectsList::setParameter(effect, "in", QString::number(item->fadeOut()));
2102             EffectsList::setParameter(effect, "out", QString::number(0));
2103             slotAddEffect(effect, m_dragItem->startPos(), m_dragItem->track());
2104         }
2105     } else if (m_operationMode == KEYFRAME) {
2106         // update the MLT effect
2107         ClipItem * item = (ClipItem *) m_dragItem;
2108         QString previous = item->keyframes(item->selectedEffectIndex());
2109         item->updateKeyframeEffect();
2110         QString next = item->keyframes(item->selectedEffectIndex());
2111         EditKeyFrameCommand *command = new EditKeyFrameCommand(this, item->track(), item->startPos(), item->selectedEffectIndex(), previous, next, false);
2112         m_commandStack->push(command);
2113         updateEffect(m_document->tracksCount() - item->track(), item->startPos(), item->selectedEffect(), item->selectedEffectIndex());
2114     }
2115
2116     emit transitionItemSelected((m_dragItem && m_dragItem->type() == TRANSITIONWIDGET) ? static_cast <Transition *>(m_dragItem) : NULL);
2117     m_document->setModified(true);
2118     m_operationMode = NONE;
2119 }
2120
2121 void CustomTrackView::deleteClip(ItemInfo info) {
2122     ClipItem *item = getClipItemAt((int) info.startPos.frames(m_document->fps()) + 1, info.track);
2123
2124     if (!item || m_document->renderer()->mltRemoveClip(m_document->tracksCount() - info.track, info.startPos) == false) {
2125         emit displayMessage(i18n("Error removing clip at %1 on track %2", m_document->timecode().getTimecodeFromFrames(info.startPos.frames(m_document->fps())), info.track), ErrorMessage);
2126         return;
2127     }
2128     if (item->isSelected()) emit clipItemSelected(NULL);
2129     item->baseClip()->removeReference();
2130     m_document->updateClip(item->baseClip()->getId());
2131
2132     if (item->baseClip()->isTransparent()) {
2133         // also remove automatic transition
2134         Transition *tr = getTransitionItemAt((int) info.startPos.frames(m_document->fps()), info.track);
2135         if (tr && tr->isAutomatic()) {
2136             m_document->renderer()->mltDeleteTransition(tr->transitionTag(), tr->transitionEndTrack(), m_document->tracksCount() - info.track, info.startPos, info.endPos, tr->toXML());
2137             scene()->removeItem(tr);
2138             delete tr;
2139         }
2140     }
2141     scene()->removeItem(item);
2142     if (m_dragItem == item) m_dragItem = NULL;
2143     delete item;
2144     m_document->renderer()->doRefresh();
2145 }
2146
2147 void CustomTrackView::deleteSelectedClips() {
2148     QList<QGraphicsItem *> itemList = scene()->selectedItems();
2149     if (itemList.count() == 0) {
2150         emit displayMessage(i18n("Select clip to delete"), ErrorMessage);
2151         return;
2152     }
2153     QUndoCommand *deleteSelected = new QUndoCommand();
2154     deleteSelected->setText(i18n("Delete selected items"));
2155     for (int i = 0; i < itemList.count(); i++) {
2156         if (itemList.at(i)->type() == AVWIDGET) {
2157             ClipItem *item = static_cast <ClipItem *>(itemList.at(i));
2158             new AddTimelineClipCommand(this, item->xml(), item->clipProducer(), item->info(), item->effectList(), true, true, deleteSelected);
2159         } else if (itemList.at(i)->type() == TRANSITIONWIDGET) {
2160             Transition *item = static_cast <Transition *>(itemList.at(i));
2161             ItemInfo info;
2162             info.startPos = item->startPos();
2163             info.endPos = item->endPos();
2164             info.track = item->track();
2165             new AddTransitionCommand(this, info, item->transitionEndTrack(), item->toXML(), true, true, deleteSelected);
2166         }
2167     }
2168     m_commandStack->push(deleteSelected);
2169 }
2170
2171 void CustomTrackView::changeClipSpeed() {
2172     QList<QGraphicsItem *> itemList = scene()->selectedItems();
2173     if (itemList.count() == 0) {
2174         emit displayMessage(i18n("Select clip to change speed"), ErrorMessage);
2175         return;
2176     }
2177     QUndoCommand *changeSelected = new QUndoCommand();
2178     changeSelected->setText("Edit clip speed");
2179     int count = 0;
2180     for (int i = 0; i < itemList.count(); i++) {
2181         if (itemList.at(i)->type() == AVWIDGET) {
2182             ClipItem *item = static_cast <ClipItem *>(itemList.at(i));
2183             ItemInfo info = item->info();
2184             bool ok;
2185             int percent = QInputDialog::getInteger(this, i18n("Edit Clip Speed"), i18n("New speed (percents)"), item->speed() * 100, 1, 300, 1, &ok);
2186             double speed = (double) percent / 100.0;
2187             if (ok && item->speed() != speed) {
2188                 count++;
2189                 new ChangeSpeedCommand(this, info, item->speed(), speed, item->clipProducer(), true, changeSelected);
2190             }
2191         }
2192     }
2193     if (count > 0) m_commandStack->push(changeSelected);
2194     else delete changeSelected;
2195 }
2196
2197 void CustomTrackView::doChangeClipSpeed(ItemInfo info, const double speed, const double oldspeed, const QString &id) {
2198     DocClipBase *baseclip = m_document->clipManager()->getClipById(id);
2199     ClipItem *item = getClipItemAt((int) info.startPos.frames(m_document->fps()) + 1, info.track);
2200     info.track = m_document->tracksCount() - item->track();
2201     int endPos = m_document->renderer()->mltChangeClipSpeed(info, speed, oldspeed, baseclip->producer());
2202     //kDebug() << "//CH CLIP SPEED: " << speed << "x" << oldspeed << ", END POS: " << endPos;
2203     item->setSpeed(speed);
2204     item->updateRectGeometry();
2205     if (item->cropDuration().frames(m_document->fps()) > endPos)
2206         item->AbstractClipItem::resizeEnd(info.startPos.frames(m_document->fps()) + endPos, speed);
2207     m_document->setModified(true);
2208 }
2209
2210 void CustomTrackView::cutSelectedClips() {
2211     QList<QGraphicsItem *> itemList = scene()->selectedItems();
2212     GenTime currentPos = GenTime(m_cursorPos, m_document->fps());
2213     for (int i = 0; i < itemList.count(); i++) {
2214         if (itemList.at(i)->type() == AVWIDGET) {
2215             ClipItem *item = static_cast <ClipItem *>(itemList.at(i));
2216             if (currentPos > item->startPos() && currentPos <  item->endPos()) {
2217                 RazorClipCommand *command = new RazorClipCommand(this, item->info(), currentPos, true);
2218                 m_commandStack->push(command);
2219             }
2220         }
2221     }
2222 }
2223
2224 void CustomTrackView::addClip(QDomElement xml, const QString &clipId, ItemInfo info, EffectsList effects) {
2225     DocClipBase *baseclip = m_document->clipManager()->getClipById(clipId);
2226     if (baseclip == NULL) {
2227         emit displayMessage(i18n("No clip copied"), ErrorMessage);
2228         return;
2229     }
2230     ClipItem *item = new ClipItem(baseclip, info, m_document->fps(), xml.attribute("speed", "1").toDouble());
2231     item->setEffectList(effects);
2232     scene()->addItem(item);
2233     if (item->baseClip()->isTransparent()) {
2234         // add transparency transition
2235         int endTrack = getPreviousVideoTrack(info.track);
2236         Transition *tr = new Transition(info, endTrack, m_document->fps(), MainWindow::transitions.getEffectByTag("composite", "alphatransparency"), true);
2237         if (m_document->renderer()->mltAddTransition(tr->transitionTag(), endTrack, m_document->tracksCount() - info.track, info.startPos, info.endPos, tr->toXML())) scene()->addItem(tr);
2238         else {
2239             emit displayMessage(i18n("Cannot add transition"), ErrorMessage);
2240             delete tr;
2241         }
2242
2243     }
2244
2245     baseclip->addReference();
2246     m_document->updateClip(baseclip->getId());
2247     info.track = m_document->tracksCount() - info.track;
2248     m_document->renderer()->mltInsertClip(info, xml, baseclip->producer(info.track));
2249     for (int i = 0; i < item->effectsCount(); i++) {
2250         m_document->renderer()->mltAddEffect(info.track, info.startPos, item->getEffectArgs(item->effectAt(i)), false);
2251     }
2252     m_document->renderer()->doRefresh();
2253 }
2254
2255 void CustomTrackView::slotUpdateClip(const QString &clipId) {
2256     QList<QGraphicsItem *> list = scene()->items();
2257     ClipItem *clip = NULL;
2258     for (int i = 0; i < list.size(); ++i) {
2259         if (list.at(i)->type() == AVWIDGET) {
2260             clip = static_cast <ClipItem *>(list.at(i));
2261             if (clip->clipProducer() == clipId) {
2262                 clip->refreshClip();
2263                 ItemInfo info = clip->info();
2264                 info.track = m_document->tracksCount() - clip->track();
2265                 m_document->renderer()->mltUpdateClip(info, clip->xml(), clip->baseClip()->producer());
2266             }
2267         }
2268     }
2269 }
2270
2271 ClipItem *CustomTrackView::getClipItemAtEnd(GenTime pos, int track) {
2272     int framepos = (int)(pos.frames(m_document->fps()));
2273     QList<QGraphicsItem *> list = scene()->items(QPointF(framepos - 1, track * m_tracksHeight + m_tracksHeight / 2));
2274     ClipItem *clip = NULL;
2275     for (int i = 0; i < list.size(); i++) {
2276         if (list.at(i)->type() == AVWIDGET) {
2277             ClipItem *test = static_cast <ClipItem *>(list.at(i));
2278             if (test->endPos() == pos) clip = test;
2279             break;
2280         }
2281     }
2282     return clip;
2283 }
2284
2285 ClipItem *CustomTrackView::getClipItemAtStart(GenTime pos, int track) {
2286     QList<QGraphicsItem *> list = scene()->items(QPointF(pos.frames(m_document->fps()), track * m_tracksHeight + m_tracksHeight / 2));
2287     ClipItem *clip = NULL;
2288     for (int i = 0; i < list.size(); i++) {
2289         if (list.at(i)->type() == AVWIDGET) {
2290             ClipItem *test = static_cast <ClipItem *>(list.at(i));
2291             if (test->startPos() == pos) clip = test;
2292             break;
2293         }
2294     }
2295     return clip;
2296 }
2297
2298 ClipItem *CustomTrackView::getClipItemAt(int pos, int track) {
2299     QList<QGraphicsItem *> list = scene()->items(QPointF(pos , track * m_tracksHeight + m_tracksHeight / 2));
2300     ClipItem *clip = NULL;
2301     for (int i = 0; i < list.size(); i++) {
2302         if (list.at(i)->type() == AVWIDGET) {
2303             clip = static_cast <ClipItem *>(list.at(i));
2304             break;
2305         }
2306     }
2307     return clip;
2308 }
2309
2310 ClipItem *CustomTrackView::getClipItemAt(GenTime pos, int track) {
2311     int framepos = (int)(pos.frames(m_document->fps()));
2312     return getClipItemAt(framepos, track);
2313 }
2314
2315 Transition *CustomTrackView::getTransitionItemAt(int pos, int track) {
2316     QList<QGraphicsItem *> list = scene()->items(QPointF(pos, (track + 1) * m_tracksHeight));
2317     Transition *clip = NULL;
2318     for (int i = 0; i < list.size(); i++) {
2319         if (list.at(i)->type() == TRANSITIONWIDGET) {
2320             clip = static_cast <Transition *>(list.at(i));
2321             break;
2322         }
2323     }
2324     return clip;
2325 }
2326
2327 Transition *CustomTrackView::getTransitionItemAt(GenTime pos, int track) {
2328     int framepos = (int)(pos.frames(m_document->fps()));
2329     return getTransitionItemAt(framepos, track);
2330 }
2331
2332 Transition *CustomTrackView::getTransitionItemAtEnd(GenTime pos, int track) {
2333     int framepos = (int)(pos.frames(m_document->fps()));
2334     QList<QGraphicsItem *> list = scene()->items(QPointF(framepos - 1, (track + 1) * m_tracksHeight));
2335     Transition *clip = NULL;
2336     for (int i = 0; i < list.size(); i++) {
2337         if (list.at(i)->type() == TRANSITIONWIDGET) {
2338             Transition *test = static_cast <Transition *>(list.at(i));
2339             if (test->endPos() == pos) clip = test;
2340             break;
2341         }
2342     }
2343     return clip;
2344 }
2345
2346 Transition *CustomTrackView::getTransitionItemAtStart(GenTime pos, int track) {
2347     QList<QGraphicsItem *> list = scene()->items(QPointF(pos.frames(m_document->fps()), (track + 1) * m_tracksHeight));
2348     Transition *clip = NULL;
2349     for (int i = 0; i < list.size(); ++i) {
2350         if (list.at(i)->type() == TRANSITIONWIDGET) {
2351             Transition *test = static_cast <Transition *>(list.at(i));
2352             if (test->startPos() == pos) clip = test;
2353             break;
2354         }
2355     }
2356     return clip;
2357 }
2358
2359 void CustomTrackView::moveClip(const ItemInfo start, const ItemInfo end) {
2360     if (m_selectionGroup) resetSelectionGroup(false);
2361     ClipItem *item = getClipItemAt((int) start.startPos.frames(m_document->fps()) + 1, start.track);
2362     if (!item) {
2363         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);
2364         kDebug() << "----------------  ERROR, CANNOT find clip to move at.. ";
2365         return;
2366     }
2367     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()), item->baseClip()->producer(end.track));
2368     if (success) {
2369         bool snap = KdenliveSettings::snaptopoints();
2370         KdenliveSettings::setSnaptopoints(false);
2371         item->setPos((int) end.startPos.frames(m_document->fps()), (int)(end.track * m_tracksHeight + 1));
2372         m_scene->clearSelection();
2373         item->setSelected(true);
2374         if (item->baseClip()->isTransparent()) {
2375             // Also move automatic transition
2376             Transition *tr = getTransitionItemAt((int) start.startPos.frames(m_document->fps()), start.track);
2377             if (tr && tr->isAutomatic()) {
2378                 tr->updateTransitionEndTrack(getPreviousVideoTrack(end.track));
2379                 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);
2380                 tr->setPos((int) end.startPos.frames(m_document->fps()), (int)(end.track * m_tracksHeight + 1));
2381             }
2382         }
2383         KdenliveSettings::setSnaptopoints(snap);
2384     } else {
2385         // undo last move and emit error message
2386         emit displayMessage(i18n("Cannot move clip to position %1", m_document->timecode().getTimecodeFromFrames(end.startPos.frames(m_document->fps()))), ErrorMessage);
2387     }
2388     kDebug() << " // MOVED CLIP TO: " << end.startPos.frames(25) << ", ITEM START: " << item->startPos().frames(25);
2389 }
2390
2391 void CustomTrackView::moveGroup(QList <ItemInfo> startClip, QList <ItemInfo> startTransition, const GenTime offset, const int trackOffset, bool reverseMove) {
2392     // Group Items
2393     kDebug() << "// GROUP MOVE; OFFSET: " << offset.frames(25) << ", TK OFF: " << trackOffset;
2394     resetSelectionGroup();
2395     m_scene->clearSelection();
2396     for (int i = 0; i < startClip.count(); i++) {
2397         if (reverseMove) {
2398             startClip[i].startPos = startClip.at(i).startPos - offset;
2399             startClip[i].track = startClip.at(i).track - trackOffset;
2400         }
2401         ClipItem *clip = getClipItemAt(startClip.at(i).startPos, startClip.at(i).track);
2402         if (clip) {
2403             clip->setSelected(true);
2404             m_document->renderer()->mltRemoveClip(m_document->tracksCount() - startClip.at(i).track, startClip.at(i).startPos);
2405         }
2406     }
2407     for (int i = 0; i < startTransition.count(); i++) {
2408         if (reverseMove) {
2409             startTransition[i].startPos = startTransition.at(i).startPos - offset;
2410             startTransition[i].track = startTransition.at(i).track - trackOffset;
2411         }
2412         Transition *tr = getTransitionItemAt(startTransition.at(i).startPos, startTransition.at(i).track);
2413         if (tr) {
2414             tr->setSelected(true);
2415             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());
2416         }
2417     }
2418     groupSelectedItems();
2419     if (m_selectionGroup) {
2420         QPointF pos = m_selectionGroup->pos();
2421         qreal posx = pos.x() + offset.frames(m_document->fps());
2422         qreal posy = pos.y() + trackOffset * (qreal) m_tracksHeight;
2423         bool snap = KdenliveSettings::snaptopoints();
2424         KdenliveSettings::setSnaptopoints(false);
2425
2426         m_selectionGroup->setPos(posx, posy);
2427
2428         QPointF top = m_selectionGroup->sceneBoundingRect().topLeft();
2429         m_selectionGroup->setPos(top);
2430         m_selectionGroupInfo.startPos = GenTime(m_selectionGroup->scenePos().x(), m_document->fps());
2431         m_selectionGroupInfo.track = m_selectionGroup->track();
2432
2433         QList<QGraphicsItem *> children = m_selectionGroup->childItems();
2434         for (int i = 0; i < children.count(); i++) {
2435             // re-add items in correct place
2436             AbstractClipItem *item = static_cast <AbstractClipItem *>(children.at(i));
2437             item->updateItem();
2438             ItemInfo info = item->info();
2439             if (item->type() == AVWIDGET) {
2440                 ClipItem *clip = static_cast <ClipItem*>(item);
2441                 info.track = m_document->tracksCount() - info.track;
2442                 m_document->renderer()->mltInsertClip(info, clip->xml(), clip->baseClip()->producer(info.track));
2443             } else {
2444                 Transition *tr = static_cast <Transition*>(item);
2445                 int newTrack = tr->transitionEndTrack();
2446                 kDebug() << "/// TRANSITION CURR TRK: " << newTrack;
2447                 if (!tr->forcedTrack()) {
2448                     newTrack += trackOffset;
2449                     if (newTrack < 0 || newTrack > m_document->tracksCount()) newTrack = getPreviousVideoTrack(info.track);
2450                 }
2451                 tr->updateTransitionEndTrack(newTrack);
2452                 kDebug() << "/// TRANSITION UPDATED TRK: " << newTrack;
2453                 m_document->renderer()->mltAddTransition(tr->transitionTag(), newTrack, m_document->tracksCount() - info.track, info.startPos, info.endPos, tr->toXML());
2454             }
2455         }
2456         KdenliveSettings::setSnaptopoints(snap);
2457     }
2458
2459 }
2460
2461 void CustomTrackView::moveTransition(const ItemInfo start, const ItemInfo end) {
2462     Transition *item = getTransitionItemAt((int)start.startPos.frames(m_document->fps()), start.track);
2463     if (!item) {
2464         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);
2465         kDebug() << "----------------  ERROR, CANNOT find transition to move... ";// << startPos.x() * m_scale * FRAME_SIZE + 1 << ", " << startPos.y() * m_tracksHeight + m_tracksHeight / 2;
2466         return;
2467     }
2468     //kDebug() << "----------------  Move TRANSITION FROM: " << startPos.x() << ", END:" << endPos.x() << ",TRACKS: " << oldtrack << " TO " << newtrack;
2469     bool snap = KdenliveSettings::snaptopoints();
2470     KdenliveSettings::setSnaptopoints(false);
2471     //kDebug()<<"///  RESIZE TRANS START: ("<< startPos.x()<<"x"<< startPos.y()<<") / ("<<endPos.x()<<"x"<< endPos.y()<<")";
2472     if (end.endPos - end.startPos == start.endPos - start.startPos) {
2473         // Transition was moved
2474         item->setPos((int) end.startPos.frames(m_document->fps()), (end.track) * m_tracksHeight + 1);
2475     } else if (end.endPos == start.endPos) {
2476         // Transition start resize
2477         item->resizeStart((int) end.startPos.frames(m_document->fps()));
2478     } else if (end.startPos == start.startPos) {
2479         // Transition end resize;
2480         item->resizeEnd((int) end.endPos.frames(m_document->fps()));
2481     } else {
2482         // Move & resize
2483         item->setPos((int) end.startPos.frames(m_document->fps()), (end.track) * m_tracksHeight + 1);
2484         item->resizeStart((int) end.startPos.frames(m_document->fps()));
2485         item->resizeEnd((int) end.endPos.frames(m_document->fps()));
2486     }
2487     //item->moveTransition(GenTime((int) (endPos.x() - startPos.x()), m_document->fps()));
2488     KdenliveSettings::setSnaptopoints(snap);
2489     item->updateTransitionEndTrack(getPreviousVideoTrack(end.track));
2490     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);
2491 }
2492
2493 void CustomTrackView::resizeClip(const ItemInfo start, const ItemInfo end) {
2494     int offset = 0;
2495     bool resizeClipStart = true;
2496     if (start.startPos == end.startPos) resizeClipStart = false;
2497     /*if (resizeClipStart) offset = 1;
2498     else offset = -1;*/
2499     ClipItem *item = getClipItemAt((int)(start.startPos.frames(m_document->fps()) + offset), start.track);
2500     if (!item) {
2501         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);
2502         kDebug() << "----------------  ERROR, CANNOT find clip to resize at... "; // << startPos;
2503         return;
2504     }
2505     bool snap = KdenliveSettings::snaptopoints();
2506     KdenliveSettings::setSnaptopoints(false);
2507     if (resizeClipStart) {
2508         ItemInfo clipinfo = item->info();
2509         clipinfo.track = m_document->tracksCount() - clipinfo.track;
2510         bool success = m_document->renderer()->mltResizeClipStart(clipinfo, end.startPos - item->startPos());
2511         if (success) {
2512             item->resizeStart((int) end.startPos.frames(m_document->fps()));
2513             updateClipFade(item);
2514         } else emit displayMessage(i18n("Error when resizing clip"), ErrorMessage);
2515     } else {
2516         ItemInfo clipinfo = item->info();
2517         clipinfo.track = m_document->tracksCount() - clipinfo.track;
2518         bool success = m_document->renderer()->mltResizeClipEnd(clipinfo, end.endPos - clipinfo.startPos);
2519         if (success) {
2520             item->resizeEnd((int) end.endPos.frames(m_document->fps()));
2521             updateClipFade(item, true);
2522         } else emit displayMessage(i18n("Error when resizing clip"), ErrorMessage);
2523     }
2524     m_document->renderer()->doRefresh();
2525     KdenliveSettings::setSnaptopoints(snap);
2526 }
2527
2528 void CustomTrackView::updateClipFade(ClipItem * item, bool updateFadeOut) {
2529     if (!updateFadeOut) {
2530         int end = item->fadeIn();
2531         if (end != 0) {
2532             // there is a fade in effect
2533             int effectPos = item->hasEffect("volume", "fadein");
2534             if (effectPos == -1) return;
2535             QDomElement oldeffect = item->effectAt(effectPos);
2536             int start = item->cropStart().frames(m_document->fps());
2537             int max = item->cropDuration().frames(m_document->fps());
2538             if (end > max) {
2539                 item->setFadeIn(max);
2540                 end = item->fadeIn();
2541             }
2542             end += start;
2543             EffectsList::setParameter(oldeffect, "in", QString::number(start));
2544             EffectsList::setParameter(oldeffect, "out", QString::number(end));
2545             if (!m_document->renderer()->mltEditEffect(m_document->tracksCount() - item->track(), item->startPos(), item->getEffectArgs(oldeffect)))
2546                 emit displayMessage(i18n("Problem editing effect"), ErrorMessage);
2547             // if fade effect is displayed, update the effect edit widget with new clip duration
2548             if (item->isSelected() && effectPos == item->selectedEffectIndex()) emit clipItemSelected(item, effectPos);
2549         }
2550     } else {
2551         int start = item->fadeOut();
2552         if (start != 0) {
2553             // there is a fade in effect
2554             int effectPos = item->hasEffect("volume", "fadeout");
2555             if (effectPos == -1) return;
2556             QDomElement oldeffect = item->effectAt(effectPos);
2557             int end = (item->duration() - item->cropStart()).frames(m_document->fps());
2558             int max = item->cropDuration().frames(m_document->fps());
2559             if (end > max) {
2560                 item->setFadeOut(max);
2561                 start = item->fadeOut();
2562             }
2563             start = end - start;
2564             EffectsList::setParameter(oldeffect, "in", QString::number(start));
2565             EffectsList::setParameter(oldeffect, "out", QString::number(end));
2566             if (!m_document->renderer()->mltEditEffect(m_document->tracksCount() - item->track(), item->startPos(), item->getEffectArgs(oldeffect)))
2567                 emit displayMessage(i18n("Problem editing effect"), ErrorMessage);
2568             // if fade effect is displayed, update the effect edit widget with new clip duration
2569             if (item->isSelected() && effectPos == item->selectedEffectIndex()) emit clipItemSelected(item, effectPos);
2570         }
2571     }
2572 }
2573
2574 double CustomTrackView::getSnapPointForPos(double pos) {
2575     return m_scene->getSnapPointForPos(pos, KdenliveSettings::snaptopoints());
2576 }
2577
2578 void CustomTrackView::updateSnapPoints(AbstractClipItem *selected) {
2579     QList <GenTime> snaps;
2580     GenTime offset;
2581     if (selected) offset = selected->duration();
2582     QList<QGraphicsItem *> itemList = items();
2583     for (int i = 0; i < itemList.count(); i++) {
2584         if (itemList.at(i)->type() == AVWIDGET && itemList.at(i) != selected) {
2585             ClipItem *item = static_cast <ClipItem *>(itemList.at(i));
2586             GenTime start = item->startPos();
2587             GenTime end = item->endPos();
2588             snaps.append(start);
2589             snaps.append(end);
2590             QList < GenTime > markers = item->snapMarkers();
2591             for (int i = 0; i < markers.size(); ++i) {
2592                 GenTime t = markers.at(i);
2593                 snaps.append(t);
2594                 if (t > offset) snaps.append(t - offset);
2595             }
2596             if (offset != GenTime()) {
2597                 if (start > offset) snaps.append(start - offset);
2598                 if (end > offset) snaps.append(end - offset);
2599             }
2600         } else if (itemList.at(i)->type() == TRANSITIONWIDGET) {
2601             Transition *transition = static_cast <Transition*>(itemList.at(i));
2602             GenTime start = transition->startPos();
2603             GenTime end = transition->endPos();
2604             snaps.append(start);
2605             snaps.append(end);
2606             if (offset != GenTime()) {
2607                 if (start > offset) snaps.append(start - offset);
2608                 if (end > offset) snaps.append(end - offset);
2609             }
2610         }
2611     }
2612
2613     // add cursor position
2614     GenTime pos = GenTime(m_cursorPos, m_document->fps());
2615     snaps.append(pos);
2616     if (offset != GenTime()) snaps.append(pos - offset);
2617
2618     // add guides
2619     for (int i = 0; i < m_guides.count(); i++) {
2620         snaps.append(m_guides.at(i)->position());
2621         if (offset != GenTime()) snaps.append(m_guides.at(i)->position() - offset);
2622     }
2623
2624     qSort(snaps);
2625     m_scene->setSnapList(snaps);
2626     //for (int i = 0; i < m_snapPoints.size(); ++i)
2627     //    kDebug() << "SNAP POINT: " << m_snapPoints.at(i).frames(25);
2628 }
2629
2630 void CustomTrackView::slotSeekToPreviousSnap() {
2631     updateSnapPoints(NULL);
2632     GenTime res = m_scene->previousSnapPoint(GenTime(m_cursorPos, m_document->fps()));
2633     setCursorPos((int) res.frames(m_document->fps()));
2634     checkScrolling();
2635 }
2636
2637 void CustomTrackView::slotSeekToNextSnap() {
2638     updateSnapPoints(NULL);
2639     GenTime res = m_scene->nextSnapPoint(GenTime(m_cursorPos, m_document->fps()));
2640     setCursorPos((int) res.frames(m_document->fps()));
2641     checkScrolling();
2642 }
2643
2644 void CustomTrackView::clipStart() {
2645     ClipItem *item = getMainActiveClip();
2646     if (item != NULL) {
2647         setCursorPos((int) item->startPos().frames(m_document->fps()));
2648         checkScrolling();
2649     }
2650 }
2651
2652 void CustomTrackView::clipEnd() {
2653     ClipItem *item = getMainActiveClip();
2654     if (item != NULL) {
2655         setCursorPos((int) item->endPos().frames(m_document->fps()) - 1);
2656         checkScrolling();
2657     }
2658 }
2659
2660 void CustomTrackView::slotAddClipMarker(const QString &id, GenTime t, QString c) {
2661     QString oldcomment = m_document->clipManager()->getClipById(id)->markerComment(t);
2662     AddMarkerCommand *command = new AddMarkerCommand(this, oldcomment, c, id, t, true);
2663     m_commandStack->push(command);
2664 }
2665
2666 void CustomTrackView::slotDeleteClipMarker(const QString &comment, const QString &id, const GenTime &position) {
2667     AddMarkerCommand *command = new AddMarkerCommand(this, comment, QString(), id, position, true);
2668     m_commandStack->push(command);
2669 }
2670
2671 void CustomTrackView::slotDeleteAllClipMarkers(const QString &id) {
2672     DocClipBase *base = m_document->clipManager()->getClipById(id);
2673     QList <CommentedTime> markers = base->commentedSnapMarkers();
2674
2675     if (markers.isEmpty()) {
2676         emit displayMessage(i18n("Clip has no markers"), ErrorMessage);
2677         return;
2678     }
2679     QUndoCommand *deleteMarkers = new QUndoCommand();
2680     deleteMarkers->setText("Delete clip markers");
2681
2682     for (int i = 0; i < markers.size(); i++) {
2683         new AddMarkerCommand(this, markers.at(i).comment(), QString(), id, markers.at(i).time(), true, deleteMarkers);
2684     }
2685     m_commandStack->push(deleteMarkers);
2686 }
2687
2688 void CustomTrackView::addMarker(const QString &id, const GenTime &pos, const QString comment) {
2689     DocClipBase *base = m_document->clipManager()->getClipById(id);
2690     if (!comment.isEmpty()) base->addSnapMarker(pos, comment);
2691     else base->deleteSnapMarker(pos);
2692     m_document->setModified(true);
2693     viewport()->update();
2694 }
2695
2696 bool sortGuidesList(const Guide *g1 , const Guide *g2) {
2697     return (*g1).position() < (*g2).position();
2698 }
2699
2700 void CustomTrackView::editGuide(const GenTime oldPos, const GenTime pos, const QString &comment) {
2701     if (oldPos > GenTime() && pos > GenTime()) {
2702         // move guide
2703         for (int i = 0; i < m_guides.count(); i++) {
2704             if (m_guides.at(i)->position() == oldPos) {
2705                 Guide *item = m_guides.at(i);
2706                 item->updateGuide(pos, comment);
2707                 break;
2708             }
2709         }
2710     } else if (pos > GenTime()) addGuide(pos, comment);
2711     else {
2712         // remove guide
2713         bool found = false;
2714         for (int i = 0; i < m_guides.count(); i++) {
2715             if (m_guides.at(i)->position() == oldPos) {
2716                 Guide *item = m_guides.takeAt(i);
2717                 delete item;
2718                 found = true;
2719                 break;
2720             }
2721         }
2722         if (!found) emit displayMessage(i18n("No guide at cursor time"), ErrorMessage);
2723     }
2724     qSort(m_guides.begin(), m_guides.end(), sortGuidesList);
2725     m_document->syncGuides(m_guides);
2726 }
2727
2728 bool CustomTrackView::addGuide(const GenTime pos, const QString &comment) {
2729     for (int i = 0; i < m_guides.count(); i++) {
2730         if (m_guides.at(i)->position() == pos) {
2731             emit displayMessage(i18n("A guide already exists at position %1", m_document->timecode().getTimecodeFromFrames(pos.frames(m_document->fps()))), ErrorMessage);
2732             return false;
2733         }
2734     }
2735     Guide *g = new Guide(this, pos, comment, m_document->fps(), m_tracksHeight * m_document->tracksCount());
2736     scene()->addItem(g);
2737     m_guides.append(g);
2738     qSort(m_guides.begin(), m_guides.end(), sortGuidesList);
2739     m_document->syncGuides(m_guides);
2740     return true;
2741 }
2742
2743 void CustomTrackView::slotAddGuide() {
2744     CommentedTime marker(GenTime(m_cursorPos, m_document->fps()), i18n("Guide"));
2745     MarkerDialog d(NULL, marker, m_document->timecode(), i18n("Add Guide"), this);
2746     if (d.exec() != QDialog::Accepted) return;
2747     if (addGuide(d.newMarker().time(), d.newMarker().comment())) {
2748         EditGuideCommand *command = new EditGuideCommand(this, GenTime(), QString(), d.newMarker().time(), d.newMarker().comment(), false);
2749         m_commandStack->push(command);
2750     }
2751 }
2752
2753 void CustomTrackView::slotEditGuide() {
2754     GenTime pos = GenTime(m_cursorPos, m_document->fps());
2755     bool found = false;
2756     for (int i = 0; i < m_guides.count(); i++) {
2757         if (m_guides.at(i)->position() == pos) {
2758             slotEditGuide(m_guides.at(i)->info());
2759             found = true;
2760             break;
2761         }
2762     }
2763     if (!found) emit displayMessage(i18n("No guide at cursor time"), ErrorMessage);
2764 }
2765
2766 void CustomTrackView::slotEditGuide(CommentedTime guide) {
2767     MarkerDialog d(NULL, guide, m_document->timecode(), i18n("Edit Guide"), this);
2768     if (d.exec() == QDialog::Accepted) {
2769         EditGuideCommand *command = new EditGuideCommand(this, guide.time(), guide.comment(), d.newMarker().time(), d.newMarker().comment(), true);
2770         m_commandStack->push(command);
2771     }
2772 }
2773
2774
2775 void CustomTrackView::slotDeleteGuide() {
2776     GenTime pos = GenTime(m_cursorPos, m_document->fps());
2777     bool found = false;
2778     for (int i = 0; i < m_guides.count(); i++) {
2779         if (m_guides.at(i)->position() == pos) {
2780             EditGuideCommand *command = new EditGuideCommand(this, m_guides.at(i)->position(), m_guides.at(i)->label(), GenTime(), QString(), true);
2781             m_commandStack->push(command);
2782             found = true;
2783             break;
2784         }
2785     }
2786     if (!found) emit displayMessage(i18n("No guide at cursor time"), ErrorMessage);
2787 }
2788
2789 void CustomTrackView::slotDeleteAllGuides() {
2790     QUndoCommand *deleteAll = new QUndoCommand();
2791     deleteAll->setText("Delete all guides");
2792     for (int i = 0; i < m_guides.count(); i++) {
2793         EditGuideCommand *command = new EditGuideCommand(this, m_guides.at(i)->position(), m_guides.at(i)->label(), GenTime(), QString(), true, deleteAll);
2794     }
2795     m_commandStack->push(deleteAll);
2796 }
2797
2798 void CustomTrackView::setTool(PROJECTTOOL tool) {
2799     m_tool = tool;
2800 }
2801
2802 void CustomTrackView::setScale(double scaleFactor) {
2803     QMatrix matrix;
2804     matrix = matrix.scale(scaleFactor, 1);
2805     m_scene->setScale(scaleFactor);
2806     //scale(scaleFactor, 1);
2807     m_animationTimer->stop();
2808     if (m_visualTip) {
2809         delete m_visualTip;
2810         m_visualTip = NULL;
2811     }
2812     if (m_animation) {
2813         delete m_animation;
2814         m_animation = NULL;
2815     }
2816     /*double pos = cursorPos() / m_scale;
2817     m_scale = scaleFactor;
2818     m_scene->setScale(m_scale);
2819     int vert = verticalScrollBar()->value();
2820     kDebug() << " HHHHHHHH  SCALING: " << m_scale;
2821     QList<QGraphicsItem *> itemList = items();
2822     for (int i = 0; i < itemList.count(); i++) {
2823         if (itemList.at(i)->type() == AVWIDGET || itemList.at(i)->type() == TRANSITIONWIDGET) {
2824             AbstractClipItem *clip = (AbstractClipItem *)itemList.at(i);
2825             clip->setRect(0, 0, (qreal) clip->duration().frames(m_document->fps()) * m_scale - .5, clip->rect().height());
2826             clip->setPos((qreal) clip->startPos().frames(m_document->fps()) * m_scale, clip->pos().y());
2827         }
2828     }
2829
2830     for (int i = 0; i < m_guides.count(); i++) {
2831         m_guides.at(i)->updatePosition(m_scale);
2832     }
2833
2834     setSceneRect(0, 0, (m_projectDuration + 100) * m_scale, sceneRect().height());
2835     updateCursorPos();*/
2836     setMatrix(matrix);
2837     centerOn(QPointF(cursorPos(), m_tracksHeight));
2838     //verticalScrollBar()->setValue(vert);*/
2839 }
2840
2841 void CustomTrackView::slotRefreshGuides() {
2842     if (KdenliveSettings::showmarkers()) {
2843         kDebug() << "// refresh GUIDES";
2844         for (int i = 0; i < m_guides.count(); i++) {
2845             m_guides.at(i)->update();
2846         }
2847     }
2848 }
2849
2850 void CustomTrackView::drawBackground(QPainter * painter, const QRectF & rect) {
2851     QColor base = palette().button().color();
2852     QRectF r = rect;
2853     r.setWidth(r.width() + 1);
2854     painter->setClipRect(r);
2855     painter->drawLine(r.left(), 0, r.right(), 0);
2856     uint max = m_document->tracksCount();
2857     for (uint i = 0; i < max;i++) {
2858         /*if (max - i - 1 == m_selectedTrack) painter->fillRect(r.left(), m_tracksHeight * i + 1, r.right() - r.left() + 1, m_tracksHeight - 1, QBrush(QColor(211, 205, 147)));
2859                else*/
2860         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(QColor(240, 240, 255)));
2861         painter->drawLine(r.left(), m_tracksHeight * (i + 1), r.right(), m_tracksHeight * (i + 1));
2862     }
2863     int lowerLimit = m_tracksHeight * m_document->tracksCount() + 1;
2864     if (height() > lowerLimit)
2865         painter->fillRect(QRectF(r.left(), lowerLimit, r.width(), height() - lowerLimit), QBrush(base));
2866 }
2867
2868 bool CustomTrackView::findString(const QString &text) {
2869     QString marker;
2870     for (int i = 0; i < m_searchPoints.size(); ++i) {
2871         marker = m_searchPoints.at(i).comment();
2872         if (marker.contains(text, Qt::CaseInsensitive)) {
2873             setCursorPos(m_searchPoints.at(i).time().frames(m_document->fps()), true);
2874             int vert = verticalScrollBar()->value();
2875             int hor = cursorPos();
2876             ensureVisible(hor, vert + 10, 2, 2, 50, 0);
2877             m_findIndex = i;
2878             return true;
2879         }
2880     }
2881     return false;
2882 }
2883
2884 bool CustomTrackView::findNextString(const QString &text) {
2885     QString marker;
2886     for (int i = m_findIndex + 1; i < m_searchPoints.size(); ++i) {
2887         marker = m_searchPoints.at(i).comment();
2888         if (marker.contains(text, Qt::CaseInsensitive)) {
2889             setCursorPos(m_searchPoints.at(i).time().frames(m_document->fps()), true);
2890             int vert = verticalScrollBar()->value();
2891             int hor = cursorPos();
2892             ensureVisible(hor, vert + 10, 2, 2, 50, 0);
2893             m_findIndex = i;
2894             return true;
2895         }
2896     }
2897     m_findIndex = -1;
2898     return false;
2899 }
2900
2901 void CustomTrackView::initSearchStrings() {
2902     m_searchPoints.clear();
2903     QList<QGraphicsItem *> itemList = items();
2904     for (int i = 0; i < itemList.count(); i++) {
2905         // parse all clip names
2906         if (itemList.at(i)->type() == AVWIDGET) {
2907             ClipItem *item = static_cast <ClipItem *>(itemList.at(i));
2908             GenTime start = item->startPos();
2909             CommentedTime t(start, item->clipName());
2910             m_searchPoints.append(t);
2911             // add all clip markers
2912             QList < CommentedTime > markers = item->commentedSnapMarkers();
2913             m_searchPoints += markers;
2914         }
2915     }
2916
2917     // add guides
2918     for (int i = 0; i < m_guides.count(); i++) {
2919         m_searchPoints.append(m_guides.at(i)->info());
2920     }
2921
2922     qSort(m_searchPoints);
2923 }
2924
2925 void CustomTrackView::clearSearchStrings() {
2926     m_searchPoints.clear();
2927     m_findIndex = 0;
2928 }
2929
2930 void CustomTrackView::copyClip() {
2931     while (m_copiedItems.count() > 0) {
2932         delete m_copiedItems.takeFirst();
2933     }
2934     QList<QGraphicsItem *> itemList = scene()->selectedItems();
2935     if (itemList.count() == 0) {
2936         emit displayMessage(i18n("Select a clip before copying"), ErrorMessage);
2937         return;
2938     }
2939     for (int i = 0; i < itemList.count(); i++) {
2940         if (itemList.at(i)->type() == AVWIDGET) {
2941             ClipItem *dup = static_cast <ClipItem *>(itemList.at(i));
2942             m_copiedItems.append(dup->clone(dup->info()));
2943         } else if (itemList.at(i)->type() == TRANSITIONWIDGET) {
2944             Transition *dup = static_cast <Transition *>(itemList.at(i));
2945             m_copiedItems.append(dup->clone());
2946         }
2947     }
2948 }
2949
2950 bool CustomTrackView::canBePastedTo(ItemInfo info, int type) const {
2951     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));
2952     QList<QGraphicsItem *> collisions = scene()->items(rect, Qt::IntersectsItemBoundingRect);
2953     for (int i = 0; i < collisions.count(); i++) {
2954         if (collisions.at(i)->type() == type) return false;
2955     }
2956     return true;
2957 }
2958
2959 bool CustomTrackView::canBePasted(QList<AbstractClipItem *> items, GenTime offset, int trackOffset) const {
2960     for (int i = 0; i < items.count(); i++) {
2961         ItemInfo info = items.at(i)->info();
2962         info.startPos += offset;
2963         info.endPos += offset;
2964         info.track += trackOffset;
2965         if (!canBePastedTo(info, items.at(i)->type())) return false;
2966     }
2967     return true;
2968 }
2969
2970 bool CustomTrackView::canBeMoved(QList<AbstractClipItem *> items, GenTime offset, int trackOffset) const {
2971     QPainterPath movePath;
2972     movePath.moveTo(0, 0);
2973
2974     for (int i = 0; i < items.count(); i++) {
2975         ItemInfo info = items.at(i)->info();
2976         info.startPos = info.startPos + offset;
2977         info.endPos = info.endPos + offset;
2978         info.track = info.track + trackOffset;
2979         if (info.startPos < GenTime()) {
2980             // No clip should go below 0
2981             return false;
2982         }
2983         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));
2984         movePath.addRect(rect);
2985     }
2986     QList<QGraphicsItem *> collisions = scene()->items(movePath, Qt::IntersectsItemBoundingRect);
2987     for (int i = 0; i < collisions.count(); i++) {
2988         if ((collisions.at(i)->type() == AVWIDGET || collisions.at(i)->type() == TRANSITIONWIDGET) && !items.contains(static_cast <AbstractClipItem *>(collisions.at(i)))) {
2989             kDebug() << "  ////////////   CLIP COLLISION, MOVE NOT ALLOWED";
2990             return false;
2991         }
2992     }
2993     return true;
2994 }
2995
2996 void CustomTrackView::pasteClip() {
2997     if (m_copiedItems.count() == 0) {
2998         emit displayMessage(i18n("No clip copied"), ErrorMessage);
2999         return;
3000     }
3001     QPoint position;
3002     if (m_menuPosition.isNull()) {
3003         position = mapFromGlobal(QCursor::pos());
3004         if (!underMouse() || position.y() > m_tracksHeight * m_document->tracksCount()) {
3005             emit displayMessage(i18n("Cannot paste selected clips"), ErrorMessage);
3006             return;
3007         }
3008     } else position = m_menuPosition;
3009     GenTime pos = GenTime((int)(mapToScene(position).x()), m_document->fps());
3010     int track = (int)(position.y() / m_tracksHeight);
3011     ItemInfo first = m_copiedItems.at(0)->info();
3012
3013     GenTime offset = pos - first.startPos;
3014     int trackOffset = track - first.track;
3015
3016     if (!canBePasted(m_copiedItems, offset, trackOffset)) {
3017         emit displayMessage(i18n("Cannot paste selected clips"), ErrorMessage);
3018         return;
3019     }
3020     QUndoCommand *pasteClips = new QUndoCommand();
3021     pasteClips->setText("Paste clips");
3022
3023     for (int i = 0; i < m_copiedItems.count(); i++) {
3024         // parse all clip names
3025         if (m_copiedItems.at(i) && m_copiedItems.at(i)->type() == AVWIDGET) {
3026             ClipItem *clip = static_cast <ClipItem *>(m_copiedItems.at(i));
3027             ItemInfo info;
3028             info.startPos = clip->startPos() + offset;
3029             info.endPos = clip->endPos() + offset;
3030             info.cropStart = clip->cropStart();
3031             info.track = clip->track() + trackOffset;
3032             if (canBePastedTo(info, AVWIDGET)) {
3033                 new AddTimelineClipCommand(this, clip->xml(), clip->clipProducer(), info, clip->effectList(), true, false, pasteClips);
3034             } else emit displayMessage(i18n("Cannot paste clip to selected place"), ErrorMessage);
3035         } else if (m_copiedItems.at(i) && m_copiedItems.at(i)->type() == TRANSITIONWIDGET) {
3036             Transition *tr = static_cast <Transition *>(m_copiedItems.at(i));
3037             ItemInfo info;
3038             info.startPos = tr->startPos() + offset;
3039             info.endPos = tr->endPos() + offset;
3040             info.track = tr->track() + trackOffset;
3041             if (canBePastedTo(info, TRANSITIONWIDGET)) {
3042                 if (info.startPos >= info.endPos) {
3043                     emit displayMessage(i18n("Invalid transition"), ErrorMessage);
3044                 } else new AddTransitionCommand(this, info, tr->transitionEndTrack() + trackOffset, tr->toXML(), false, true, pasteClips);
3045             } else emit displayMessage(i18n("Cannot paste transition to selected place"), ErrorMessage);
3046         }
3047     }
3048     m_commandStack->push(pasteClips);
3049 }
3050
3051 void CustomTrackView::pasteClipEffects() {
3052     if (m_copiedItems.count() != 1 || m_copiedItems.at(0)->type() != AVWIDGET) {
3053         emit displayMessage(i18n("You must copy exactly one clip before pasting effects"), ErrorMessage);
3054         return;
3055     }
3056     ClipItem *clip = static_cast < ClipItem *>(m_copiedItems.at(0));
3057     EffectsList effects = clip->effectList();
3058
3059     QUndoCommand *paste = new QUndoCommand();
3060     paste->setText("Paste effects");
3061
3062     QList<QGraphicsItem *> clips = scene()->selectedItems();
3063     for (int i = 0; i < clips.count(); ++i) {
3064         if (clips.at(i)->type() == AVWIDGET) {
3065             ClipItem *item = static_cast < ClipItem *>(clips.at(i));
3066             for (int i = 0; i < clip->effectsCount(); i++) {
3067                 new AddEffectCommand(this, m_document->tracksCount() - item->track(), item->startPos(), clip->effectAt(i), true, paste);
3068             }
3069         }
3070     }
3071     m_commandStack->push(paste);
3072 }
3073
3074
3075 ClipItem *CustomTrackView::getClipUnderCursor() const {
3076     QRectF rect((double) m_cursorPos, 0.0, 1.0, (double)(m_tracksHeight * m_document->tracksCount()));
3077     QList<QGraphicsItem *> collisions = scene()->items(rect, Qt::IntersectsItemBoundingRect);
3078     for (int i = 0; i < collisions.count(); i++) {
3079         if (collisions.at(i)->type() == AVWIDGET) {
3080             return static_cast < ClipItem *>(collisions.at(i));
3081         }
3082     }
3083     return NULL;
3084 }
3085
3086 ClipItem *CustomTrackView::getMainActiveClip() const {
3087     QList<QGraphicsItem *> clips = scene()->selectedItems();
3088     if (clips.isEmpty()) {
3089         return getClipUnderCursor();
3090     } else {
3091         ClipItem *item = NULL;
3092         for (int i = 0; i < clips.count(); ++i) {
3093             if (clips.at(i)->type() == AVWIDGET)
3094                 item = static_cast < ClipItem *>(clips.at(i));
3095             if (item->startPos().frames(m_document->fps()) <= m_cursorPos && item->endPos().frames(m_document->fps()) >= m_cursorPos) break;
3096         }
3097         if (item) return item;
3098     }
3099     return NULL;
3100 }
3101
3102 ClipItem *CustomTrackView::getActiveClipUnderCursor(bool allowOutsideCursor) const {
3103     QList<QGraphicsItem *> clips = scene()->selectedItems();
3104     if (clips.isEmpty()) {
3105         return getClipUnderCursor();
3106     } else {
3107         ClipItem *item;
3108         // remove all items in the list that are not clips
3109         for (int i = 0; i < clips.count();) {
3110             if (clips.at(i)->type() != AVWIDGET) clips.removeAt(i);
3111             else i++;
3112         }
3113         if (clips.count() == 1 && allowOutsideCursor) return static_cast < ClipItem *>(clips.at(0));
3114         for (int i = 0; i < clips.count(); ++i) {
3115             if (clips.at(i)->type() == AVWIDGET)
3116                 item = static_cast < ClipItem *>(clips.at(i));
3117             if (item->startPos().frames(m_document->fps()) <= m_cursorPos && item->endPos().frames(m_document->fps()) >= m_cursorPos) return item;
3118         }
3119     }
3120     return NULL;
3121 }
3122
3123 void CustomTrackView::setInPoint() {
3124     ClipItem *clip = getActiveClipUnderCursor(true);
3125     if (clip == NULL) {
3126         emit displayMessage(i18n("You must select one clip for this action"), ErrorMessage);
3127         return;
3128     }
3129     ItemInfo startInfo = clip->info();
3130     ItemInfo endInfo = clip->info();
3131     endInfo.startPos = GenTime(m_cursorPos, m_document->fps());
3132     if (endInfo.startPos >= startInfo.endPos) {
3133         // Check for invalid resize
3134         emit displayMessage(i18n("Invalid action"), ErrorMessage);
3135         return;
3136     } else if (endInfo.startPos < startInfo.startPos) {
3137         int length = m_document->renderer()->mltGetSpaceLength(endInfo.startPos, m_document->tracksCount() - startInfo.track, false);
3138         if (length < (startInfo.startPos - endInfo.startPos).frames(m_document->fps())) {
3139             emit displayMessage(i18n("Invalid action"), ErrorMessage);
3140             return;
3141         }
3142     }
3143     ResizeClipCommand *command = new ResizeClipCommand(this, startInfo, endInfo, true);
3144     m_commandStack->push(command);
3145 }
3146
3147 void CustomTrackView::setOutPoint() {
3148     ClipItem *clip = getActiveClipUnderCursor(true);
3149     if (clip == NULL) {
3150         emit displayMessage(i18n("You must select one clip for this action"), ErrorMessage);
3151         return;
3152     }
3153     ItemInfo startInfo = clip->info();
3154     ItemInfo endInfo = clip->info();
3155     endInfo.endPos = GenTime(m_cursorPos, m_document->fps());
3156     if (endInfo.endPos <= startInfo.startPos) {
3157         // Check for invalid resize
3158         emit displayMessage(i18n("Invalid action"), ErrorMessage);
3159         return;
3160     } else if (endInfo.endPos > startInfo.endPos) {
3161         int length = m_document->renderer()->mltGetSpaceLength(endInfo.endPos, m_document->tracksCount() - startInfo.track, false);
3162         if (length < (endInfo.endPos - startInfo.endPos).frames(m_document->fps())) {
3163             emit displayMessage(i18n("Invalid action"), ErrorMessage);
3164             return;
3165         }
3166     }
3167
3168
3169
3170     ResizeClipCommand *command = new ResizeClipCommand(this, startInfo, endInfo, true);
3171     m_commandStack->push(command);
3172 }
3173
3174 void CustomTrackView::slotUpdateAllThumbs() {
3175     QList<QGraphicsItem *> itemList = items();
3176     //if (itemList.isEmpty()) return;
3177     ClipItem *item;
3178     QString thumbBase = m_document->projectFolder().path() + "/thumbs/";
3179     for (int i = 0; i < itemList.count(); i++) {
3180         if (itemList.at(i)->type() == AVWIDGET) {
3181             item = static_cast <ClipItem *>(itemList.at(i));
3182             if (item->clipType() != COLOR) {
3183                 // Check if we have a cached thumbnail
3184                 if (item->clipType() == IMAGE || item->clipType() == TEXT || item->clipType() == AUDIO) {
3185                     QString thumb = thumbBase + item->baseClip()->getClipHash() + "_0.png";
3186                     if (QFile::exists(thumb)) {
3187                         QPixmap pix(thumb);
3188                         item->slotSetStartThumb(pix);
3189                         item->slotSetEndThumb(pix);
3190                     }
3191                 } else {
3192                     QString startThumb = thumbBase + item->baseClip()->getClipHash() + '_';
3193                     QString endThumb = startThumb;
3194                     startThumb.append(QString::number(item->cropStart().frames(m_document->fps())) + ".png");
3195                     endThumb.append(QString::number((item->cropStart() + item->cropDuration()).frames(m_document->fps()) - 1) + ".png");
3196                     if (QFile::exists(startThumb)) {
3197                         QPixmap pix(startThumb);
3198                         item->slotSetStartThumb(pix);
3199                     }
3200                     if (QFile::exists(endThumb)) {
3201                         QPixmap pix(endThumb);
3202                         item->slotSetEndThumb(pix);
3203                     }
3204                 }
3205             }
3206             item->refreshClip();
3207             qApp->processEvents();
3208         }
3209     }
3210     viewport()->update();
3211 }
3212
3213 void CustomTrackView::saveThumbnails() {
3214     QList<QGraphicsItem *> itemList = items();
3215     ClipItem *item;
3216     QString thumbBase = m_document->projectFolder().path() + "/thumbs/";
3217     for (int i = 0; i < itemList.count(); i++) {
3218         if (itemList.at(i)->type() == AVWIDGET) {
3219             item = static_cast <ClipItem *>(itemList.at(i));
3220             if (item->clipType() != COLOR) {
3221                 // Check if we have a cached thumbnail
3222                 if (item->clipType() == IMAGE || item->clipType() == TEXT || item->clipType() == AUDIO) {
3223                     QString thumb = thumbBase + item->baseClip()->getClipHash() + "_0.png";
3224                     if (!QFile::exists(thumb)) {
3225                         QPixmap pix(item->startThumb());
3226                         pix.save(thumb);
3227                     }
3228                 } else {
3229                     QString startThumb = thumbBase + item->baseClip()->getClipHash() + '_';
3230                     QString endThumb = startThumb;
3231                     startThumb.append(QString::number(item->cropStart().frames(m_document->fps())) + ".png");
3232                     endThumb.append(QString::number((item->cropStart() + item->cropDuration()).frames(m_document->fps()) - 1) + ".png");
3233                     if (!QFile::exists(startThumb)) {
3234                         QPixmap pix(item->startThumb());
3235                         pix.save(startThumb);
3236                     }
3237                     if (!QFile::exists(endThumb)) {
3238                         QPixmap pix(item->endThumb());
3239                         pix.save(endThumb);
3240                     }
3241                 }
3242             }
3243         }
3244     }
3245 }
3246
3247
3248 void CustomTrackView::slotInsertTrack(int ix) {
3249     kDebug() << "// INSERTING TRK: " << ix;
3250     QDialog d(parentWidget());
3251     Ui::AddTrack_UI view;
3252     view.setupUi(&d);
3253     view.track_nb->setMaximum(m_document->tracksCount() - 1);
3254     view.track_nb->setValue(ix);
3255     d.setWindowTitle(i18n("Insert Track"));
3256
3257     if (d.exec() == QDialog::Accepted) {
3258         ix = view.track_nb->value();
3259         if (view.before_select->currentIndex() == 1) {
3260             ix++;
3261         }
3262         TrackInfo info;
3263         if (view.video_track->isChecked()) {
3264             info.type = VIDEOTRACK;
3265             info.isMute = false;
3266             info.isBlind = false;
3267         } else {
3268             info.type = AUDIOTRACK;
3269             info.isMute = false;
3270             info.isBlind = true;
3271         }
3272         AddTrackCommand *addTrack = new AddTrackCommand(this, ix, info, true, true);
3273         m_commandStack->push(addTrack);
3274         m_document->setModified(true);
3275     }
3276 }
3277
3278 void CustomTrackView::slotDeleteTrack(int ix) {
3279     bool ok;
3280     ix = QInputDialog::getInteger(this, i18n("Remove Track"), i18n("Track"), ix, 0, m_document->tracksCount() - 1, 1, &ok);
3281     if (ok) {
3282         TrackInfo info = m_document->trackInfoAt(m_document->tracksCount() - ix - 1);
3283         deleteTimelineTrack(ix, info);
3284         m_document->setModified(true);
3285         /*AddTrackCommand* command = new AddTrackCommand(this, ix, info, false, true);
3286         m_commandStack->push(command);*/
3287     }
3288 }
3289
3290 void CustomTrackView::slotChangeTrack(int ix) {
3291     QDialog d(parentWidget());
3292     Ui::AddTrack_UI view;
3293     view.setupUi(&d);
3294     view.label->setText(i18n("Change track"));
3295     view.before_select->setHidden(true);
3296     view.track_nb->setMaximum(m_document->tracksCount() - 1);
3297     view.track_nb->setValue(ix);
3298     d.setWindowTitle(i18n("Change Track Type"));
3299
3300     if (d.exec() == QDialog::Accepted) {
3301         TrackInfo info;
3302         if (view.video_track->isChecked()) {
3303             info.type = VIDEOTRACK;
3304             info.isMute = false;
3305             info.isBlind = false;
3306         } else {
3307             info.type = AUDIOTRACK;
3308             info.isMute = false;
3309             info.isBlind = true;
3310         }
3311         changeTimelineTrack(ix, info);
3312         m_document->setModified(true);
3313     }
3314 }
3315
3316
3317 void CustomTrackView::deleteTimelineTrack(int ix, TrackInfo trackinfo) {
3318     double startY = ix * m_tracksHeight + 1 + m_tracksHeight / 2;
3319     QRectF r(0, startY, sceneRect().width(), m_tracksHeight / 2 - 1);
3320     QList<QGraphicsItem *> selection = m_scene->items(r);
3321     QUndoCommand *deleteTrack = new QUndoCommand();
3322     deleteTrack->setText("Delete track");
3323
3324     // Delete all clips in selected track
3325     for (int i = 0; i < selection.count(); i++) {
3326         if (selection.at(i)->type() == AVWIDGET) {
3327             ClipItem *item =  static_cast <ClipItem *>(selection.at(i));
3328             new AddTimelineClipCommand(this, item->xml(), item->clipProducer(), item->info(), item->effectList(), false, true, deleteTrack);
3329             m_scene->removeItem(item);
3330             delete item;
3331             item = NULL;
3332         } else if (selection.at(i)->type() == TRANSITIONWIDGET) {
3333             Transition *item =  static_cast <Transition *>(selection.at(i));
3334             new AddTransitionCommand(this, item->info(), item->transitionEndTrack(), item->toXML(), true, false, deleteTrack);
3335             m_scene->removeItem(item);
3336             delete item;
3337             item = NULL;
3338         }
3339     }
3340
3341     new AddTrackCommand(this, ix, trackinfo, false, true, deleteTrack);
3342     m_commandStack->push(deleteTrack);
3343 }
3344
3345 void CustomTrackView::changeTimelineTrack(int ix, TrackInfo trackinfo) {
3346     TrackInfo oldinfo = m_document->trackInfoAt(m_document->tracksCount() - ix);
3347     ChangeTrackCommand *changeTrack = new ChangeTrackCommand(this, ix, oldinfo, trackinfo, true);
3348     m_commandStack->push(changeTrack);
3349 }
3350
3351 void CustomTrackView::autoTransition() {
3352     QList<QGraphicsItem *> itemList = scene()->selectedItems();
3353     if (itemList.count() != 1 || itemList.at(0)->type() != TRANSITIONWIDGET) {
3354         emit displayMessage(i18n("You must select one transition for this action"), ErrorMessage);
3355         return;
3356     }
3357     Transition *tr = static_cast <Transition*>(itemList.at(0));
3358     tr->setAutomatic(!tr->isAutomatic());
3359     QDomElement transition = tr->toXML();
3360     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);
3361 }
3362
3363
3364 QStringList CustomTrackView::getLadspaParams(QDomElement effect) const {
3365     QStringList result;
3366     QDomNodeList params = effect.elementsByTagName("parameter");
3367     for (int i = 0; i < params.count(); i++) {
3368         QDomElement e = params.item(i).toElement();
3369         if (!e.isNull() && e.attribute("type") == "constant") {
3370             if (e.hasAttribute("factor")) {
3371                 double factor = e.attribute("factor").toDouble();
3372                 double value = e.attribute("value").toDouble();
3373                 value = value / factor;
3374                 result.append(QString::number(value));
3375             } else result.append(e.attribute("value"));
3376         }
3377     }
3378     return result;
3379 }
3380
3381 void CustomTrackView::clipNameChanged(const QString id, const QString name) {
3382     QList<QGraphicsItem *> list = scene()->items();
3383     ClipItem *clip = NULL;
3384     for (int i = 0; i < list.size(); ++i) {
3385         if (list.at(i)->type() == AVWIDGET) {
3386             clip = static_cast <ClipItem *>(list.at(i));
3387             if (clip->clipProducer() == id) {
3388                 clip->setClipName(name);
3389             }
3390         }
3391     }
3392     viewport()->update();
3393 }
3394
3395 #include "customtrackview.moc"