]> git.sesse.net Git - kdenlive/blob - src/customtrackview.cpp
Spacer tool (can only add space for the moment)
[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
67 //TODO:
68 // disable animation if user asked it in KDE's global settings
69 // http://lists.kde.org/?l=kde-commits&m=120398724717624&w=2
70 // needs something like below (taken from dolphin)
71 // #include <kglobalsettings.h>
72 // const bool animate = KGlobalSettings::graphicEffectsLevel() & KGlobalSettings::SimpleAnimationEffects;
73 // const int duration = animate ? 1500 : 1;
74
75 CustomTrackView::CustomTrackView(KdenliveDoc *doc, CustomTrackScene* projectscene, QWidget *parent)
76         : 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) {
77     if (doc) m_commandStack = doc->commandStack();
78     else m_commandStack == NULL;
79     setMouseTracking(true);
80     setAcceptDrops(true);
81     m_animationTimer = new QTimeLine(800);
82     m_animationTimer->setFrameRange(0, 5);
83     m_animationTimer->setUpdateInterval(100);
84     m_animationTimer->setLoopCount(0);
85     m_tipColor = QColor(0, 192, 0, 200);
86     QColor border = QColor(255, 255, 255, 100);
87     m_tipPen.setColor(border);
88     m_tipPen.setWidth(3);
89     setContentsMargins(0, 0, 0, 0);
90     if (projectscene) {
91         m_cursorLine = projectscene->addLine(0, 0, 0, m_tracksHeight);
92         m_cursorLine->setZValue(1000);
93     }
94
95     KIcon razorIcon("edit-cut");
96     m_razorCursor = QCursor(razorIcon.pixmap(22, 22));
97
98     KIcon spacerIcon("kdenlive-spacer-tool");
99     m_spacerCursor = QCursor(spacerIcon.pixmap(22, 22));
100     verticalScrollBar()->setTracking(true);
101     connect(verticalScrollBar(), SIGNAL(valueChanged(int)), this, SLOT(slotRefreshGuides()));
102     connect(&m_scrollTimer, SIGNAL(timeout()), this, SLOT(slotCheckMouseScrolling()));
103     m_scrollTimer.setInterval(100);
104     m_scrollTimer.setSingleShot(true);
105 }
106
107 CustomTrackView::~CustomTrackView() {
108     qDeleteAll(m_guides);
109 }
110
111 void CustomTrackView::setDocumentModified() {
112     m_document->setModified(true);
113 }
114
115 void CustomTrackView::setContextMenu(QMenu *timeline, QMenu *clip, QMenu *transition) {
116     m_timelineContextMenu = timeline;
117     m_timelineContextClipMenu = clip;
118     m_timelineContextTransitionMenu = transition;
119 }
120
121 void CustomTrackView::checkAutoScroll() {
122     m_autoScroll = KdenliveSettings::autoscroll();
123 }
124
125 QList <TrackInfo> CustomTrackView::tracksList() const {
126     return m_scene->m_tracksList;
127 }
128
129 void CustomTrackView::checkTrackHeight() {
130     if (m_tracksHeight == KdenliveSettings::trackheight()) return;
131     m_tracksHeight = KdenliveSettings::trackheight();
132     emit trackHeightChanged();
133     QList<QGraphicsItem *> itemList = items();
134     ClipItem *item;
135     Transition *transitionitem;
136     for (int i = 0; i < itemList.count(); i++) {
137         if (itemList.at(i)->type() == AVWIDGET) {
138             item = (ClipItem*) itemList.at(i);
139             item->setRect(0, 0, item->rect().width(), m_tracksHeight - 1);
140             item->setPos((qreal) item->startPos().frames(m_document->fps()), (qreal) item->track() * m_tracksHeight + 1);
141             item->resetThumbs();
142         } else if (itemList.at(i)->type() == TRANSITIONWIDGET) {
143             transitionitem = (Transition*) itemList.at(i);
144             transitionitem->setRect(0, 0, transitionitem->rect().width(), m_tracksHeight / 3 * 2 - 1);
145             transitionitem->setPos((qreal) transitionitem->startPos().frames(m_document->fps()), (qreal) transitionitem->track() * m_tracksHeight + m_tracksHeight / 3 * 2);
146         }
147     }
148     m_cursorLine->setLine(m_cursorLine->line().x1(), 0, m_cursorLine->line().x1(), m_tracksHeight * m_scene->m_tracksList.count());
149
150     for (int i = 0; i < m_guides.count(); i++) {
151         QLineF l = m_guides.at(i)->line();
152         l.setP2(QPointF(l.x2(), m_tracksHeight * m_scene->m_tracksList.count()));
153         m_guides.at(i)->setLine(l);
154     }
155
156     setSceneRect(0, 0, sceneRect().width(), m_tracksHeight * m_scene->m_tracksList.count());
157     verticalScrollBar()->setMaximum(m_tracksHeight * m_scene->m_tracksList.count());
158     update();
159 }
160
161 // virtual
162 void CustomTrackView::resizeEvent(QResizeEvent * event) {
163     QGraphicsView::resizeEvent(event);
164 }
165
166 // virtual
167 /** Zoom or move viewport on mousewheel
168  *
169  * If mousewheel+Ctrl, zooms in/out on the timeline.
170  *
171  * With Ctrl, moves viewport towards end of timeline if down/back,
172  * opposite on up/forward.
173  *
174  * See also http://www.kdenlive.org/mantis/view.php?id=265 */
175 void CustomTrackView::wheelEvent(QWheelEvent * e) {
176     if (e->modifiers() == Qt::ControlModifier) {
177         if (e->delta() > 0) emit zoomIn();
178         else emit zoomOut();
179     } else {
180         if (e->delta() <= 0) horizontalScrollBar()->setValue(horizontalScrollBar()->value() + horizontalScrollBar()->singleStep());
181         else  horizontalScrollBar()->setValue(horizontalScrollBar()->value() - horizontalScrollBar()->singleStep());
182     }
183 }
184
185 int CustomTrackView::getPreviousVideoTrack(int track) {
186     track = m_scene->m_tracksList.count() - track - 1;
187     track --;
188     for (int i = track; i > -1; i--) {
189         if (m_scene->m_tracksList.at(i).type == VIDEOTRACK) return i + 1;
190     }
191     return 0;
192 }
193
194
195 void CustomTrackView::slotCheckMouseScrolling() {
196     if (m_scrollOffset == 0) {
197         m_scrollTimer.stop();
198         return;
199     }
200     horizontalScrollBar()->setValue(horizontalScrollBar()->value() + m_scrollOffset);
201     m_scrollTimer.start();
202 }
203
204 void CustomTrackView::slotCheckPositionScrolling() {
205     // If mouse is at a border of the view, scroll
206     if (m_moveOpMode != SEEK) return;
207     int pos = cursorPos();
208     if (mapFromScene(pos, 0).x() < 7) {
209         horizontalScrollBar()->setValue(horizontalScrollBar()->value() - 2);
210         setCursorPos(mapToScene(QPoint()).x() - 1);
211         QTimer::singleShot(200, this, SLOT(slotCheckPositionScrolling()));
212
213     } else if (viewport()->width() - 5 < mapFromScene(pos + 1, 0).x()) {
214         horizontalScrollBar()->setValue(horizontalScrollBar()->value() + 2);
215         setCursorPos(mapToScene(viewport()->width(), 0).x() + 1);
216         QTimer::singleShot(200, this, SLOT(slotCheckPositionScrolling()));
217     }
218 }
219
220
221 // virtual
222
223 void CustomTrackView::mouseMoveEvent(QMouseEvent * event) {
224     int pos = event->x();
225     int mappedXPos = (int)(mapToScene(event->pos()).x() + 0.5);
226     emit mousePosition(mappedXPos);
227     if (event->buttons() & Qt::MidButton) return;
228     if (event->buttons() != Qt::NoButton) {
229         bool move = (event->pos() - m_clickEvent).manhattanLength() >= QApplication::startDragDistance();
230         if (m_dragItem && m_tool == SELECTTOOL) {
231             if (m_operationMode == MOVE && move) {
232                 QGraphicsView::mouseMoveEvent(event);
233                 // If mouse is at a border of the view, scroll
234                 if (pos < 5) {
235                     m_scrollOffset = -30;
236                     m_scrollTimer.start();
237                 } else if (viewport()->width() - pos < 10) {
238                     m_scrollOffset = 30;
239                     m_scrollTimer.start();
240                 } else if (m_scrollTimer.isActive()) m_scrollTimer.stop();
241
242             } else if (m_operationMode == RESIZESTART && move) {
243                 double snappedPos = getSnapPointForPos(mappedXPos);
244                 m_dragItem->resizeStart((int)(snappedPos));
245             } else if (m_operationMode == RESIZEEND && move) {
246                 double snappedPos = getSnapPointForPos(mappedXPos);
247                 m_dragItem->resizeEnd((int)(snappedPos));
248             } else if (m_operationMode == FADEIN && move) {
249                 ((ClipItem*) m_dragItem)->setFadeIn((int)(mappedXPos - m_dragItem->startPos().frames(m_document->fps())));
250             } else if (m_operationMode == FADEOUT && move) {
251                 ((ClipItem*) m_dragItem)->setFadeOut((int)(m_dragItem->endPos().frames(m_document->fps()) - mappedXPos));
252             } else if (m_operationMode == KEYFRAME && move) {
253                 GenTime keyFramePos = GenTime(mappedXPos, m_document->fps()) - m_dragItem->startPos() + m_dragItem->cropStart();
254                 double pos = mapToScene(event->pos()).toPoint().y();
255                 QRectF br = m_dragItem->sceneBoundingRect();
256                 double maxh = 100.0 / br.height();
257                 pos = (br.bottom() - pos) * maxh;
258                 m_dragItem->updateKeyFramePos(keyFramePos, pos);
259             }
260
261             if (m_animation) delete m_animation;
262             m_animation = NULL;
263             if (m_visualTip) delete m_visualTip;
264             m_visualTip = NULL;
265             return;
266         } else if (m_operationMode == MOVEGUIDE) {
267             if (m_animation) delete m_animation;
268             m_animation = NULL;
269             if (m_visualTip) delete m_visualTip;
270             m_visualTip = NULL;
271             QGraphicsView::mouseMoveEvent(event);
272             return;
273         } else if (m_operationMode == SPACER && move) {
274             // spacer tool
275             int mappedClick = (int)(mapToScene(m_clickEvent).x() + 0.5);
276             if (mappedXPos > mappedClick)
277                 m_selectionGroup->setPos(mappedXPos + (m_spacerStart - mappedClick) , m_selectionGroup->pos().y());
278         }
279     }
280
281     if (m_tool == RAZORTOOL) {
282         setCursor(m_razorCursor);
283         //QGraphicsView::mouseMoveEvent(event);
284         //return;
285     } else if (m_tool == SPACERTOOL) {
286         setCursor(m_spacerCursor);
287         return;
288     }
289
290     QList<QGraphicsItem *> itemList = items(event->pos());
291     QGraphicsRectItem *item = NULL;
292     OPERATIONTYPE opMode = NONE;
293
294     if (itemList.count() == 1 && itemList.at(0)->type() == GUIDEITEM) {
295         opMode = MOVEGUIDE;
296     } else for (int i = 0; i < itemList.count(); i++) {
297             if (itemList.at(i)->type() == AVWIDGET || itemList.at(i)->type() == TRANSITIONWIDGET) {
298                 item = (QGraphicsRectItem*) itemList.at(i);
299                 break;
300             }
301         }
302
303     if (item && event->buttons() == Qt::NoButton) {
304         AbstractClipItem *clip = static_cast <AbstractClipItem*>(item);
305         if (m_tool == RAZORTOOL) {
306             // razor tool over a clip, display current frame in monitor
307             if (!m_blockRefresh && item->type() == AVWIDGET) {
308                 //TODO: solve crash when showing frame when moving razor over clip
309                 //emit showClipFrame(((ClipItem *) item)->baseClip(), mapToScene(event->pos()).x() / m_scale - (clip->startPos() - clip->cropStart()).frames(m_document->fps()));
310             }
311             event->accept();
312             return;
313         }
314         opMode = clip->operationMode(mapToScene(event->pos()));
315         double size = 5;
316         if (opMode == m_moveOpMode) {
317             QGraphicsView::mouseMoveEvent(event);
318             return;
319         } else {
320             if (m_visualTip) {
321                 if (m_animation) delete m_animation;
322                 m_animation = NULL;
323                 m_animationTimer->stop();
324                 delete m_visualTip;
325                 m_visualTip = NULL;
326             }
327         }
328         m_moveOpMode = opMode;
329         if (opMode == MOVE) {
330             setCursor(Qt::OpenHandCursor);
331         } else if (opMode == RESIZESTART) {
332             setCursor(KCursor("left_side", Qt::SizeHorCursor));
333             if (m_visualTip == NULL) {
334                 QRectF rect = clip->sceneBoundingRect();
335                 QPolygon polygon;
336                 polygon << QPoint(0, rect.height() / 2 - size * 2);
337                 polygon << QPoint(size * 2, (int)(rect.height() / 2));
338                 polygon << QPoint(0, (int)(rect.height() / 2 + size * 2));
339                 polygon << QPoint(0, (int)(rect.height() / 2 - size * 2));
340
341                 m_visualTip = new QGraphicsPolygonItem(polygon);
342                 ((QGraphicsPolygonItem*) m_visualTip)->setBrush(m_tipColor);
343                 ((QGraphicsPolygonItem*) m_visualTip)->setPen(m_tipPen);
344                 m_visualTip->setPos(rect.x(), rect.y());
345                 m_visualTip->setFlags(QGraphicsItem::ItemIgnoresTransformations);
346                 m_visualTip->setZValue(100);
347                 m_animation = new QGraphicsItemAnimation;
348                 m_animation->setItem(m_visualTip);
349                 m_animation->setTimeLine(m_animationTimer);
350                 double scale = 2.0;
351                 m_animation->setScaleAt(.5, scale, 1);
352                 //m_animation->setPosAt(.5, QPointF(rect.x() - rect.x() * scale, 0));
353                 scale = 1.0;
354                 m_animation->setScaleAt(1, scale, 1);
355                 //m_animation->setPosAt(1, QPointF(rect.x() - rect.x() * scale, 0));
356                 scene()->addItem(m_visualTip);
357                 m_animationTimer->start();
358             }
359         } else if (opMode == RESIZEEND) {
360             setCursor(KCursor("right_side", Qt::SizeHorCursor));
361             if (m_visualTip == NULL) {
362                 QRectF rect = clip->sceneBoundingRect();
363                 QPolygon polygon;
364                 polygon << QPoint(0, (int)(rect.height() / 2 - size * 2));
365                 polygon << QPoint(- size * 2, (int)(rect.height() / 2));
366                 polygon << QPoint(0, (int)(rect.height() / 2 + size * 2));
367                 polygon << QPoint(0, (int)(rect.height() / 2 - size * 2));
368
369                 m_visualTip = new QGraphicsPolygonItem(polygon);
370                 ((QGraphicsPolygonItem*) m_visualTip)->setBrush(m_tipColor);
371                 ((QGraphicsPolygonItem*) m_visualTip)->setPen(m_tipPen);
372                 m_visualTip->setFlags(QGraphicsItem::ItemIgnoresTransformations);
373                 m_visualTip->setPos(rect.right(), rect.y());
374                 m_visualTip->setZValue(100);
375                 m_animation = new QGraphicsItemAnimation;
376                 m_animation->setItem(m_visualTip);
377                 m_animation->setTimeLine(m_animationTimer);
378                 double scale = 2.0;
379                 m_animation->setScaleAt(.5, scale, 1);
380                 scale = 1.0;
381                 m_animation->setScaleAt(1, scale, 1);
382                 scene()->addItem(m_visualTip);
383                 m_animationTimer->start();
384             }
385         } else if (opMode == FADEIN) {
386             if (m_visualTip == NULL) {
387                 ClipItem *item = (ClipItem *) clip;
388                 QRectF rect = clip->sceneBoundingRect();
389                 m_visualTip = new QGraphicsEllipseItem(-size, -size, size * 2, size * 2);
390                 ((QGraphicsEllipseItem*) m_visualTip)->setBrush(m_tipColor);
391                 ((QGraphicsEllipseItem*) m_visualTip)->setPen(m_tipPen);
392                 m_visualTip->setPos(rect.x() + item->fadeIn(), rect.y());
393                 m_visualTip->setFlags(QGraphicsItem::ItemIgnoresTransformations);
394                 m_visualTip->setZValue(100);
395                 m_animation = new QGraphicsItemAnimation;
396                 m_animation->setItem(m_visualTip);
397                 m_animation->setTimeLine(m_animationTimer);
398                 double scale = 2.0;
399                 m_animation->setScaleAt(.5, scale, scale);
400                 scale = 1.0;
401                 m_animation->setScaleAt(1, scale, scale);
402                 scene()->addItem(m_visualTip);
403                 m_animationTimer->start();
404             }
405             setCursor(Qt::PointingHandCursor);
406         } else if (opMode == FADEOUT) {
407             if (m_visualTip == NULL) {
408                 ClipItem *item = (ClipItem *) clip;
409                 QRectF rect = clip->sceneBoundingRect();
410                 m_visualTip = new QGraphicsEllipseItem(-size, -size, size * 2, size * 2);
411                 ((QGraphicsEllipseItem*) m_visualTip)->setBrush(m_tipColor);
412                 ((QGraphicsEllipseItem*) m_visualTip)->setPen(m_tipPen);
413                 m_visualTip->setPos(rect.right() - item->fadeOut(), rect.y());
414                 m_visualTip->setFlags(QGraphicsItem::ItemIgnoresTransformations);
415                 m_visualTip->setZValue(100);
416                 m_animation = new QGraphicsItemAnimation;
417                 m_animation->setItem(m_visualTip);
418                 m_animation->setTimeLine(m_animationTimer);
419                 double scale = 2.0;
420                 m_animation->setScaleAt(.5, scale, scale);
421                 scale = 1.0;
422                 m_animation->setScaleAt(1, scale, scale);
423                 scene()->addItem(m_visualTip);
424                 m_animationTimer->start();
425             }
426             setCursor(Qt::PointingHandCursor);
427         } else if (opMode == TRANSITIONSTART) {
428             /*if (m_visualTip == NULL) {
429                 QRectF rect = clip->sceneBoundingRect();
430                 m_visualTip = new QGraphicsEllipseItem(-5, -5 , 10, 10);
431                 ((QGraphicsEllipseItem*) m_visualTip)->setBrush(m_tipColor);
432                 ((QGraphicsEllipseItem*) m_visualTip)->setPen(m_tipPen);
433                 m_visualTip->setZValue(100);
434                 m_animation = new QGraphicsItemAnimation;
435                 m_animation->setItem(m_visualTip);
436                 m_animation->setTimeLine(m_animationTimer);
437                 m_visualTip->setPos(rect.x() + 10, rect.y() + rect.height() / 2 + 12);
438                 double scale = 2.0;
439                 m_animation->setScaleAt(.5, scale, scale);
440                 scale = 1.0;
441                 m_animation->setScaleAt(1, scale, scale);
442                 scene()->addItem(m_visualTip);
443                 m_animationTimer->start();
444             }*/
445             setCursor(Qt::PointingHandCursor);
446         } else if (opMode == TRANSITIONEND) {
447             /*if (m_visualTip == NULL) {
448                 QRectF rect = clip->sceneBoundingRect();
449                 m_visualTip = new QGraphicsEllipseItem(-5, -5 , 10, 10);
450                 ((QGraphicsEllipseItem*) m_visualTip)->setBrush(m_tipColor);
451                 ((QGraphicsEllipseItem*) m_visualTip)->setPen(m_tipPen);
452                 m_visualTip->setZValue(100);
453                 m_animation = new QGraphicsItemAnimation;
454                 m_animation->setItem(m_visualTip);
455                 m_animation->setTimeLine(m_animationTimer);
456                 m_visualTip->setPos(rect.x() + rect.width() - 10 , rect.y() + rect.height() / 2 + 12);
457                 double scale = 2.0;
458                 m_animation->setScaleAt(.5, scale, scale);
459                 scale = 1.0;
460                 m_animation->setScaleAt(1, scale, scale);
461                 scene()->addItem(m_visualTip);
462                 m_animationTimer->start();
463             }*/
464             setCursor(Qt::PointingHandCursor);
465         } else if (opMode == KEYFRAME) {
466             setCursor(Qt::PointingHandCursor);
467         }
468     } // no clip under mouse
469     else if (m_tool == RAZORTOOL) {
470         event->accept();
471         return;
472     } else if (opMode == MOVEGUIDE) {
473         m_moveOpMode = opMode;
474         setCursor(Qt::SplitHCursor);
475     } else {
476         if (event->buttons() != Qt::NoButton && event->modifiers() == Qt::NoModifier) {
477             m_moveOpMode = SEEK;
478             setCursorPos(mappedXPos);
479             slotCheckPositionScrolling();
480         } else m_moveOpMode = NONE;
481         if (m_visualTip) {
482             if (m_animation) delete m_animation;
483             m_animationTimer->stop();
484             m_animation = NULL;
485             delete m_visualTip;
486             m_visualTip = NULL;
487
488         }
489         setCursor(Qt::ArrowCursor);
490     }
491     QGraphicsView::mouseMoveEvent(event);
492 }
493
494 // virtual
495 void CustomTrackView::mousePressEvent(QMouseEvent * event) {
496     m_menuPosition = QPoint();
497     m_blockRefresh = true;
498     bool collision = false;
499
500     if (m_tool != RAZORTOOL) activateMonitor();
501     else if (m_document->renderer()->playSpeed() != 0.0) {
502         m_document->renderer()->pause();
503         return;
504     }
505     m_clickEvent = event->pos();
506
507     // special cases (middle click button or ctrl / shift click
508     if (event->button() == Qt::MidButton) {
509         m_document->renderer()->switchPlay();
510         m_blockRefresh = false;
511         return;
512     }
513
514     // check item under mouse
515     QList<QGraphicsItem *> collisionList = items(event->pos());
516
517     if (event->modifiers() == Qt::ControlModifier && collisionList.count() == 0) {
518         setDragMode(QGraphicsView::ScrollHandDrag);
519         QGraphicsView::mousePressEvent(event);
520         m_blockRefresh = false;
521         return;
522     }
523
524     if (event->modifiers() == Qt::ShiftModifier && collisionList.count() == 0) {
525         setDragMode(QGraphicsView::RubberBandDrag);
526         QGraphicsView::mousePressEvent(event);
527         m_blockRefresh = false;
528         return;
529     }
530
531     if (collisionList.count() == 1 && collisionList.at(0)->type() == GUIDEITEM) {
532         // a guide item was pressed
533         collisionList.at(0)->setFlag(QGraphicsItem::ItemIsMovable, true);
534         m_dragItem = NULL;
535         m_dragGuide = (Guide *) collisionList.at(0);
536         collision = true;
537         m_operationMode = MOVEGUIDE;
538         // deselect all clips so that only the guide will move
539         m_scene->clearSelection();
540         if (m_selectionGroup) {
541             scene()->destroyItemGroup(m_selectionGroup);
542             m_selectionGroup = NULL;
543         }
544         updateSnapPoints(NULL);
545         QGraphicsView::mousePressEvent(event);
546         return;
547     }
548
549     // Find first clip or transition under mouse
550     int i = 0;
551     m_dragItem = NULL;
552     while (i < collisionList.count()) {
553         if (collisionList.at(i)->type() == AVWIDGET || collisionList.at(i)->type() == TRANSITIONWIDGET) {
554             m_dragItem = static_cast <AbstractClipItem *>(collisionList.at(i));
555             m_dragItemInfo = m_dragItem->info();
556             break;
557         }
558         i++;
559     }
560
561     // context menu requested
562     if (event->button() == Qt::RightButton) {
563         if (m_dragItem) {
564             if (!m_dragItem->isSelected()) {
565                 m_scene->clearSelection();
566                 if (m_selectionGroup) {
567                     scene()->destroyItemGroup(m_selectionGroup);
568                     m_selectionGroup = NULL;
569                 }
570                 m_dragItem->setSelected(true);
571             }
572         }
573         m_operationMode = NONE;
574         displayContextMenu(event->globalPos(), m_dragItem);
575         m_menuPosition = event->pos();
576         m_dragItem = NULL;
577         event->accept();
578         return;
579     }
580
581     // No item under click
582     if (m_dragItem == NULL || m_tool == SPACERTOOL) {
583         if (m_selectionGroup) {
584             scene()->destroyItemGroup(m_selectionGroup);
585             m_selectionGroup = NULL;
586         }
587         setCursor(Qt::ArrowCursor);
588         m_scene->clearSelection();
589         event->accept();
590         emit clipItemSelected(NULL);
591         if (m_tool == SPACERTOOL) {
592             // Select all items on track after click position
593             int track = (int)(mapToScene(m_clickEvent).y() / m_tracksHeight);
594             QList<QGraphicsItem *> selection = items(event->pos().x(), track * m_tracksHeight + 1, sceneRect().width() - event->pos().x(), m_tracksHeight - 2);
595             m_selectionGroup = new AbstractGroupItem(m_document->fps());
596             scene()->addItem(m_selectionGroup);
597             m_spacerStart = -1;
598             int itemStart;
599             for (int i = 0; i < selection.count(); i++) {
600                 if (selection.at(i)->type() == AVWIDGET || selection.at(i)->type() == TRANSITIONWIDGET) {
601                     m_selectionGroup->addToGroup(selection.at(i));
602                     AbstractClipItem *item = static_cast <AbstractClipItem *>(selection.at(i));
603                     itemStart = item->startPos().frames(m_document->fps());
604                     if (m_spacerStart == -1 || itemStart < m_spacerStart)
605                         m_spacerStart = itemStart;
606                 }
607             }
608             QPointF top = m_selectionGroup->boundingRect().topLeft();
609             const int width = m_selectionGroup->boundingRect().width();
610             const int height = m_selectionGroup->boundingRect().height();
611             m_selectionGroup->setPos(top);
612             m_selectionGroup->translate(-top.x(), -top.y() + 1);
613             //kDebug()<<"// SPACER START GRP: "<<m_spacerStart;
614             m_operationMode = SPACER;
615         } else setCursorPos((int)(mapToScene(event->x(), 0).x()));
616         return;
617     }
618
619     // Razor tool
620     if (m_tool == RAZORTOOL) {
621         if (m_dragItem->type() == TRANSITIONWIDGET) {
622             emit displayMessage(i18n("Cannot cut a transition"), ErrorMessage);
623             event->accept();
624             m_dragItem = NULL;
625             return;
626         }
627         AbstractClipItem *clip = static_cast <AbstractClipItem *>(m_dragItem);
628         RazorClipCommand* command = new RazorClipCommand(this, clip->info(), GenTime((int)(mapToScene(event->pos()).x()), m_document->fps()), true);
629         m_commandStack->push(command);
630         m_document->setModified(true);
631         m_dragItem = NULL;
632         event->accept();
633         return;
634     }
635     updateSnapPoints(m_dragItem);
636     if (m_dragItem && m_dragItem->type() == AVWIDGET) emit clipItemSelected((ClipItem*) m_dragItem);
637     else emit clipItemSelected(NULL);
638
639     if (m_selectionGroup) {
640         // delete selection group
641         scene()->destroyItemGroup(m_selectionGroup);
642         m_selectionGroup = NULL;
643     }
644
645     if (m_dragItem && m_operationMode == NONE) QGraphicsView::mousePressEvent(event);
646
647     QList<QGraphicsItem *> selection = m_scene->selectedItems();
648     if (selection.count() > 1) {
649         m_selectionGroup = new AbstractGroupItem(m_document->fps());
650         scene()->addItem(m_selectionGroup);
651         for (int i = 0; i < selection.count(); i++) {
652             if (selection.at(i)->type() == AVWIDGET || selection.at(i)->type() == TRANSITIONWIDGET)
653                 m_selectionGroup->addToGroup(selection.at(i));
654         }
655         QPointF top = m_selectionGroup->boundingRect().topLeft();
656         const int width = m_selectionGroup->boundingRect().width();
657         const int height = m_selectionGroup->boundingRect().height();
658         m_selectionGroup->setPos(top);
659         m_selectionGroup->translate(-top.x(), -top.y() + 1);
660         m_selectionGroupInfo.startPos = GenTime(m_selectionGroup->scenePos().x(), m_document->fps());
661         m_selectionGroupInfo.track = m_selectionGroup->track();
662     }
663
664     m_clickPoint = QPoint((int)(mapToScene(event->pos()).x() - m_dragItem->startPos().frames(m_document->fps())), (int)(event->pos().y() - m_dragItem->pos().y()));
665     /*
666                         if (!item->isSelected()) {
667
668                             if (event->modifiers() != Qt::ControlModifier) {
669                                 QList<QGraphicsItem *> itemList = items();
670                                 for (int i = 0; i < itemList.count(); i++) {
671                                     itemList.at(i)->setSelected(false);
672                                     itemList.at(i)->update();
673                                 }
674                             }
675                             item->setSelected(true);
676                             item->update();
677                         }
678
679
680
681                         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()));
682                         m_dragItemInfo.startPos = m_dragItem->startPos();
683                         m_dragItemInfo.endPos = m_dragItem->endPos();
684                         m_dragItemInfo.track = m_dragItem->track();
685
686                         m_selectedClipList.clear();
687                         QList<QGraphicsItem *> selected = scene()->selectedItems();
688                         for (int i = 0; i < selected.count(); i++) {
689                             if (selected.at(i)->type() == AVWIDGET || selected.at(i)->type() == TRANSITIONWIDGET)
690                                 m_selectedClipList.append(static_cast <AbstractClipItem *>(selected.at(i)));
691                         }
692           */
693     m_operationMode = m_dragItem->operationMode(mapToScene(event->pos()));
694
695     if (m_operationMode == KEYFRAME) {
696         m_dragItem->updateSelectedKeyFrame();
697         m_blockRefresh = false;
698         return;
699     } else if (m_operationMode == MOVE) {
700         setCursor(Qt::ClosedHandCursor);
701     } else if (m_operationMode == TRANSITIONSTART) {
702         ItemInfo info;
703         info.startPos = m_dragItem->startPos();
704         info.track = m_dragItem->track();
705         int transitiontrack = getPreviousVideoTrack(info.track);
706         ClipItem *transitionClip = NULL;
707         if (transitiontrack != 0) transitionClip = getClipItemAt((int) info.startPos.frames(m_document->fps()), m_scene->m_tracksList.count() - transitiontrack);
708         if (transitionClip && transitionClip->endPos() < m_dragItem->endPos()) {
709             info.endPos = transitionClip->endPos();
710         } else info.endPos = info.startPos + GenTime(65, m_document->fps());
711         if (info.endPos == info.startPos) info.endPos = info.startPos + GenTime(65, m_document->fps());
712         slotAddTransition((ClipItem *) m_dragItem, info, transitiontrack);
713     } else if (m_operationMode == TRANSITIONEND) {
714         ItemInfo info;
715         info.endPos = GenTime(m_dragItem->endPos().frames(m_document->fps()), m_document->fps());
716         info.track = m_dragItem->track();
717         int transitiontrack = getPreviousVideoTrack(info.track);
718         ClipItem *transitionClip = NULL;
719         if (transitiontrack != 0) transitionClip = getClipItemAt((int) info.endPos.frames(m_document->fps()), m_scene->m_tracksList.count() - transitiontrack);
720         if (transitionClip && transitionClip->startPos() > m_dragItem->startPos()) {
721             info.startPos = transitionClip->startPos();
722         } else info.startPos = info.endPos - GenTime(65, m_document->fps());
723         if (info.endPos == info.startPos) info.startPos = info.endPos - GenTime(65, m_document->fps());
724         QDomElement transition = MainWindow::transitions.getEffectByName("Luma").cloneNode().toElement();
725         EffectsList::setParameter(transition, "reverse", "1");
726         slotAddTransition((ClipItem *) m_dragItem, info, transitiontrack, transition);
727     }
728
729     m_blockRefresh = false;
730     //kDebug()<<pos;
731     //QGraphicsView::mousePressEvent(event);
732 }
733
734 void CustomTrackView::mouseDoubleClickEvent(QMouseEvent *event) {
735     kDebug() << "++++++++++++ DBL CLK";
736     if (m_dragItem && m_dragItem->hasKeyFrames()) {
737         if (m_moveOpMode == KEYFRAME) {
738             // user double clicked on a keyframe, open edit dialog
739             QDialog d(parentWidget());
740             Ui::KeyFrameDialog_UI view;
741             view.setupUi(&d);
742             view.kfr_position->setText(m_document->timecode().getTimecode(GenTime(m_dragItem->selectedKeyFramePos(), m_document->fps()) - m_dragItem->cropStart(), m_document->fps()));
743             view.kfr_value->setValue(m_dragItem->selectedKeyFrameValue());
744             view.kfr_value->setFocus();
745             if (d.exec() == QDialog::Accepted) {
746                 int pos = m_document->timecode().getFrameCount(view.kfr_position->text(), m_document->fps());
747                 m_dragItem->updateKeyFramePos(GenTime(pos, m_document->fps()) + m_dragItem->cropStart(), (double) view.kfr_value->value() * m_dragItem->keyFrameFactor());
748                 ClipItem *item = (ClipItem *)m_dragItem;
749                 QString previous = item->keyframes(item->selectedEffectIndex());
750                 item->updateKeyframeEffect();
751                 QString next = item->keyframes(item->selectedEffectIndex());
752                 EditKeyFrameCommand *command = new EditKeyFrameCommand(this, item->track(), item->startPos(), item->selectedEffectIndex(), previous, next, false);
753                 m_commandStack->push(command);
754                 updateEffect(m_scene->m_tracksList.count() - item->track(), item->startPos(), item->selectedEffect(), item->selectedEffectIndex());
755             }
756
757         } else  {
758             // add keyframe
759             GenTime keyFramePos = GenTime((int)(mapToScene(event->pos()).x()), m_document->fps()) - m_dragItem->startPos() + m_dragItem->cropStart();
760             m_dragItem->addKeyFrame(keyFramePos, mapToScene(event->pos()).toPoint().y());
761             ClipItem * item = (ClipItem *) m_dragItem;
762             QString previous = item->keyframes(item->selectedEffectIndex());
763             item->updateKeyframeEffect();
764             QString next = item->keyframes(item->selectedEffectIndex());
765             EditKeyFrameCommand *command = new EditKeyFrameCommand(this, m_dragItem->track(), m_dragItem->startPos(), item->selectedEffectIndex(), previous, next, false);
766             m_commandStack->push(command);
767             updateEffect(m_scene->m_tracksList.count() - item->track(), item->startPos(), item->selectedEffect(), item->selectedEffectIndex());
768         }
769     } else if (m_dragItem) {
770         ClipDurationDialog d(m_dragItem, m_document->timecode(), this);
771         if (d.exec() == QDialog::Accepted) {
772             if (d.startPos() != m_dragItem->startPos()) {
773                 if (m_dragItem->type() == AVWIDGET) {
774                     ItemInfo startInfo;
775                     startInfo.startPos = m_dragItem->startPos();
776                     startInfo.endPos = m_dragItem->endPos();
777                     startInfo.track = m_dragItem->track();
778                     ItemInfo endInfo;
779                     endInfo.startPos = d.startPos();
780                     endInfo.endPos = m_dragItem->endPos() + (endInfo.startPos - startInfo.startPos);
781                     endInfo.track = m_dragItem->track();
782                     MoveClipCommand *command = new MoveClipCommand(this, startInfo, endInfo, true);
783                     m_commandStack->push(command);
784                 } else {
785                     //TODO: move transition
786                 }
787             }
788             if (d.duration() != m_dragItem->duration()) {
789                 if (m_dragItem->type() == AVWIDGET) {
790                     ItemInfo startInfo;
791                     startInfo.startPos = m_dragItem->startPos();
792                     startInfo.endPos = m_dragItem->endPos();
793                     startInfo.track = m_dragItem->track();
794                     ItemInfo endInfo;
795                     endInfo.startPos = startInfo.startPos;
796                     endInfo.endPos = endInfo.startPos + d.duration();
797                     endInfo.track = m_dragItem->track();
798                     ResizeClipCommand *command = new ResizeClipCommand(this, startInfo, endInfo, true);
799                     m_commandStack->push(command);
800                 } else {
801                     //TODO: resize transition
802                 }
803             }
804         }
805     } else {
806         QList<QGraphicsItem *> collisionList = items(event->pos());
807         if (collisionList.count() == 1 && collisionList.at(0)->type() == GUIDEITEM) {
808             Guide *editGuide = (Guide *) collisionList.at(0);
809             if (editGuide) slotEditGuide(editGuide->info());
810         }
811     }
812 }
813
814
815 void CustomTrackView::editKeyFrame(const GenTime pos, const int track, const int index, const QString keyframes) {
816     ClipItem *clip = getClipItemAt((int)pos.frames(m_document->fps()), track);
817     if (clip) {
818         clip->setKeyframes(index, keyframes);
819         updateEffect(m_scene->m_tracksList.count() - clip->track(), clip->startPos(), clip->effectAt(index), index);
820     } else emit displayMessage(i18n("Cannot find clip with keyframe"), ErrorMessage);
821 }
822
823
824 void CustomTrackView::displayContextMenu(QPoint pos, AbstractClipItem *clip) {
825     if (clip == NULL) m_timelineContextMenu->popup(pos);
826     else if (clip->type() == AVWIDGET) m_timelineContextClipMenu->popup(pos);
827     else if (clip->type() == TRANSITIONWIDGET) m_timelineContextTransitionMenu->popup(pos);
828 }
829
830 void CustomTrackView::activateMonitor() {
831     emit activateDocumentMonitor();
832 }
833
834 void CustomTrackView::dragEnterEvent(QDragEnterEvent * event) {
835     if (event->mimeData()->hasFormat("kdenlive/clip")) {
836         if (m_selectionGroup) {
837             scene()->destroyItemGroup(m_selectionGroup);
838             m_selectionGroup = NULL;
839         }
840
841         QStringList list = QString(event->mimeData()->data("kdenlive/clip")).split(";");
842         m_selectionGroup = new AbstractGroupItem(m_document->fps());
843         QPoint pos = QPoint();
844         DocClipBase *clip = m_document->getBaseClip(list.at(0));
845         if (clip == NULL) kDebug() << " WARNING))))))))) CLIP NOT FOUND : " << list.at(0);
846         ItemInfo info;
847         info.startPos = GenTime(pos.x(), m_document->fps());
848         info.cropStart = GenTime(list.at(1).toInt(), m_document->fps());
849         info.endPos = info.startPos + GenTime(list.at(2).toInt() - list.at(1).toInt(), m_document->fps());
850         info.track = (int)(pos.y() / m_tracksHeight);
851         ClipItem *item = new ClipItem(clip, info, m_document->fps());
852         m_selectionGroup->addToGroup(item);
853         //TODO: check if we do not overlap another clip when first dropping in timeline
854         // if (insertPossible(m_selectionGroup, event->pos()))
855         scene()->addItem(m_selectionGroup);
856         event->acceptProposedAction();
857     } else if (event->mimeData()->hasFormat("kdenlive/producerslist")) {
858         QStringList ids = QString(event->mimeData()->data("kdenlive/producerslist")).split(";");
859         m_scene->clearSelection();
860         if (m_selectionGroup) {
861             scene()->destroyItemGroup(m_selectionGroup);
862             m_selectionGroup = NULL;
863         }
864
865         m_selectionGroup = new AbstractGroupItem(m_document->fps());
866         QPoint pos = QPoint();
867         for (int i = 0; i < ids.size(); ++i) {
868             DocClipBase *clip = m_document->getBaseClip(ids.at(i));
869             if (clip == NULL) kDebug() << " WARNING))))))))) CLIP NOT FOUND : " << ids.at(i);
870             ItemInfo info;
871             info.startPos = GenTime(pos.x(), m_document->fps());
872             info.endPos = info.startPos + clip->duration();
873             info.track = (int)(pos.y() / m_tracksHeight);
874             ClipItem *item = new ClipItem(clip, info, m_document->fps());
875             pos.setX(pos.x() + clip->duration().frames(m_document->fps()));
876             m_selectionGroup->addToGroup(item);
877         }
878         //TODO: check if we do not overlap another clip when first dropping in timeline
879         //if (insertPossible(m_selectionGroup, event->pos()))
880         scene()->addItem(m_selectionGroup);
881         event->acceptProposedAction();
882     } else QGraphicsView::dragEnterEvent(event);
883 }
884
885
886 bool CustomTrackView::insertPossible(AbstractGroupItem *group, const QPoint &pos) const {
887     QPolygonF path;
888     QList<QGraphicsItem *> children = group->childItems();
889     for (int i = 0; i < children.count(); i++) {
890         if (children.at(i)->type() == AVWIDGET) {
891             ClipItem *clip = static_cast <ClipItem *>(children.at(i));
892             ItemInfo info = clip->info();
893             kDebug() << " / / INSERT : " << pos.x();
894             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);
895             kDebug() << " / / INSERT RECT: " << shape;
896             path = path.united(QPolygonF(shape));
897         }
898     }
899
900     QList<QGraphicsItem*> collindingItems = scene()->items(path, Qt::IntersectsItemShape);
901     if (collindingItems.isEmpty()) return true;
902     else {
903         for (int i = 0; i < collindingItems.count(); i++) {
904             QGraphicsItem *collision = collindingItems.at(i);
905             if (collision->type() == AVWIDGET) {
906                 // Collision
907                 kDebug() << "// COLLISIION DETECTED";
908                 return false;
909             }
910         }
911         return true;
912     }
913
914 }
915
916 void CustomTrackView::slotRefreshEffects(ClipItem *clip) {
917     int track = m_scene->m_tracksList.count() - clip->track();
918     GenTime pos = clip->startPos();
919     if (!m_document->renderer()->mltRemoveEffect(track, pos, "-1", false)) {
920         emit displayMessage(i18n("Problem deleting effect"), ErrorMessage);
921         return;
922     }
923     bool success = true;
924     for (int i = 0; i < clip->effectsCount(); i++) {
925         if (!m_document->renderer()->mltAddEffect(track, pos, clip->getEffectArgs(clip->effectAt(i)), false)) success = false;
926     }
927     if (!success) emit displayMessage(i18n("Problem adding effect to clip"), ErrorMessage);
928     m_document->renderer()->doRefresh();
929 }
930
931 void CustomTrackView::addEffect(int track, GenTime pos, QDomElement effect) {
932     ClipItem *clip = getClipItemAt((int)pos.frames(m_document->fps()) + 1, m_scene->m_tracksList.count() - track);
933     if (clip) {
934         QHash <QString, QString> effectParams = clip->addEffect(effect);
935         if (!m_document->renderer()->mltAddEffect(track, pos, effectParams))
936             emit displayMessage(i18n("Problem adding effect to clip"), ErrorMessage);
937         emit clipItemSelected(clip);
938     } else emit displayMessage(i18n("Cannot find clip to add effect"), ErrorMessage);
939 }
940
941 void CustomTrackView::deleteEffect(int track, GenTime pos, QDomElement effect) {
942     QString index = effect.attribute("kdenlive_ix");
943     if (effect.attribute("disabled") != "1" && !m_document->renderer()->mltRemoveEffect(track, pos, index)) {
944         emit displayMessage(i18n("Problem deleting effect"), ErrorMessage);
945         return;
946     }
947     ClipItem *clip = getClipItemAt((int)pos.frames(m_document->fps()) + 1, m_scene->m_tracksList.count() - track);
948     if (clip) {
949         clip->deleteEffect(index);
950         emit clipItemSelected(clip);
951     }
952 }
953
954 void CustomTrackView::slotAddEffect(QDomElement effect, GenTime pos, int track) {
955     QList<QGraphicsItem *> itemList;
956     if (track == -1) itemList = scene()->selectedItems();
957     if (itemList.isEmpty()) {
958         ClipItem *clip = getClipItemAt((int)pos.frames(m_document->fps()) + 1, track);
959         if (clip) itemList.append(clip);
960         else emit displayMessage(i18n("Select a clip if you want to apply an effect"), ErrorMessage);
961     }
962     kDebug() << "// REQUESTING EFFECT ON CLIP: " << pos.frames(25) << ", TRK: " << track << "SELECTED ITEMS: " << itemList.count();
963     for (int i = 0; i < itemList.count(); i++) {
964         if (itemList.at(i)->type() == AVWIDGET) {
965             ClipItem *item = (ClipItem *)itemList.at(i);
966             item->initEffect(effect);
967             AddEffectCommand *command = new AddEffectCommand(this, m_scene->m_tracksList.count() - item->track(), item->startPos(), effect, true);
968             m_commandStack->push(command);
969         }
970     }
971     m_document->setModified(true);
972 }
973
974 void CustomTrackView::slotDeleteEffect(ClipItem *clip, QDomElement effect) {
975     AddEffectCommand *command = new AddEffectCommand(this, m_scene->m_tracksList.count() - clip->track(), clip->startPos(), effect, false);
976     m_commandStack->push(command);
977     m_document->setModified(true);
978 }
979
980 void CustomTrackView::updateEffect(int track, GenTime pos, QDomElement effect, int ix, bool triggeredByUser) {
981     ClipItem *clip = getClipItemAt((int)pos.frames(m_document->fps()) + 1, m_scene->m_tracksList.count() - track);
982     if (clip) {
983         QHash <QString, QString> effectParams = clip->getEffectArgs(effect);
984         // check if we are trying to reset a keyframe effect
985         if (effectParams.contains("keyframes") && effectParams.value("keyframes").isEmpty()) {
986             clip->initEffect(effect);
987             clip->setEffectAt(ix, effect);
988             effectParams = clip->getEffectArgs(effect);
989         }
990         if (effectParams.value("disabled") == "1") {
991             if (m_document->renderer()->mltRemoveEffect(track, pos, effectParams.value("kdenlive_ix"))) {
992                 kDebug() << "//////  DISABLING EFFECT: " << index << ", CURRENTLA: " << clip->selectedEffectIndex();
993             } else emit displayMessage(i18n("Problem deleting effect"), ErrorMessage);
994         } else if (!m_document->renderer()->mltEditEffect(m_scene->m_tracksList.count() - clip->track(), clip->startPos(), effectParams))
995             emit displayMessage(i18n("Problem editing effect"), ErrorMessage);
996
997         clip->setEffectAt(ix, effect);
998         if (ix == clip->selectedEffectIndex()) {
999             clip->setSelectedEffect(ix);
1000             if (!triggeredByUser) emit clipItemSelected(clip, ix);
1001         }
1002         if (effect.attribute("tag") == "volume") {
1003             // A fade effect was modified, update the clip
1004             if (effect.attribute("id") == "fadein") {
1005                 int pos = effectParams.value("out").toInt() - effectParams.value("in").toInt();
1006                 clip->setFadeIn(pos);
1007             }
1008             if (effect.attribute("id") == "fadeout") {
1009                 int pos = effectParams.value("out").toInt() - effectParams.value("in").toInt();
1010                 clip->setFadeOut(pos);
1011             }
1012
1013         }
1014     }
1015     m_document->setModified(true);
1016 }
1017
1018 void CustomTrackView::moveEffect(int track, GenTime pos, int oldPos, int newPos) {
1019     ClipItem *clip = getClipItemAt((int)pos.frames(m_document->fps()) + 1, m_scene->m_tracksList.count() - track);
1020     if (clip) {
1021         m_document->renderer()->mltMoveEffect(track, pos, oldPos, newPos);
1022         QDomElement act = clip->effectAt(newPos - 1).cloneNode().toElement();
1023         QDomElement before = clip->effectAt(oldPos - 1).cloneNode().toElement();
1024         clip->setEffectAt(oldPos - 1, act);
1025         clip->setEffectAt(newPos - 1, before);
1026         emit clipItemSelected(clip, newPos - 1);
1027     }
1028     m_document->setModified(true);
1029 }
1030
1031 void CustomTrackView::slotChangeEffectState(ClipItem *clip, int effectPos, bool disable) {
1032     QDomElement effect = clip->effectAt(effectPos);
1033     QDomElement oldEffect = effect.cloneNode().toElement();
1034     effect.setAttribute("disabled", disable);
1035     EditEffectCommand *command = new EditEffectCommand(this, m_scene->m_tracksList.count() - clip->track(), clip->startPos(), oldEffect, effect, effectPos, true);
1036     m_commandStack->push(command);
1037     m_document->setModified(true);
1038 }
1039
1040 void CustomTrackView::slotChangeEffectPosition(ClipItem *clip, int currentPos, int newPos) {
1041     MoveEffectCommand *command = new MoveEffectCommand(this, m_scene->m_tracksList.count() - clip->track(), clip->startPos(), currentPos, newPos, true);
1042     m_commandStack->push(command);
1043     m_document->setModified(true);
1044 }
1045
1046 void CustomTrackView::slotUpdateClipEffect(ClipItem *clip, QDomElement oldeffect, QDomElement effect, int ix) {
1047     EditEffectCommand *command = new EditEffectCommand(this, m_scene->m_tracksList.count() - clip->track(), clip->startPos(), oldeffect, effect, ix, true);
1048     m_commandStack->push(command);
1049 }
1050
1051 void CustomTrackView::cutClip(ItemInfo info, GenTime cutTime, bool cut) {
1052     if (cut) {
1053         // cut clip
1054         ClipItem *item = getClipItemAt((int) info.startPos.frames(m_document->fps()) + 1, info.track);
1055         if (!item || cutTime >= item->endPos() || cutTime <= item->startPos()) {
1056             emit displayMessage(i18n("Cannot find clip to cut"), ErrorMessage);
1057             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);
1058             m_blockRefresh = false;
1059             return;
1060         }
1061         kDebug() << "/////////  CUTTING CLIP : (" << item->startPos().frames(25) << "-" << item->endPos().frames(25) << "), INFO: (" << info.startPos.frames(25) << "-" << info.endPos.frames(25) << ")" << ", CUT: " << cutTime.frames(25);
1062
1063         m_document->renderer()->mltCutClip(m_scene->m_tracksList.count() - info.track, cutTime);
1064         int cutPos = (int) cutTime.frames(m_document->fps());
1065         ItemInfo newPos;
1066         newPos.startPos = cutTime;
1067         newPos.endPos = info.endPos;
1068         newPos.cropStart = item->cropStart() + (cutTime - info.startPos);
1069         newPos.track = info.track;
1070         ClipItem *dup = item->clone(newPos);
1071         kDebug() << "// REsizing item to: " << cutPos;
1072         item->resizeEnd(cutPos, false);
1073         scene()->addItem(dup);
1074         if (item->checkKeyFrames()) slotRefreshEffects(item);
1075         if (dup->checkKeyFrames()) slotRefreshEffects(dup);
1076         item->baseClip()->addReference();
1077         m_document->updateClip(item->baseClip()->getId());
1078         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);
1079         kDebug() << "//  CUTTING CLIP dONE";
1080     } else {
1081         // uncut clip
1082
1083         ClipItem *item = getClipItemAt((int) info.startPos.frames(m_document->fps()), info.track);
1084         ClipItem *dup = getClipItemAt((int) cutTime.frames(m_document->fps()) + 1, info.track);
1085         if (!item || !dup || item == dup) {
1086             emit displayMessage(i18n("Cannot find clip to uncut"), ErrorMessage);
1087             m_blockRefresh = false;
1088             return;
1089         }
1090
1091         kDebug() << "// UNCUTTING CLIPS: ITEM 1 (" << item->startPos().frames(25) << "x" << item->endPos().frames(25) << ")";
1092         kDebug() << "// UNCUTTING CLIPS: ITEM 2 (" << dup->startPos().frames(25) << "x" << dup->endPos().frames(25) << ")";
1093         kDebug() << "// UNCUTTING CLIPS, INFO (" << info.startPos.frames(25) << "x" << info.endPos.frames(25) << ") , CUT: " << cutTime.frames(25);;
1094         //deleteClip(dup->info());
1095
1096
1097         if (dup->isSelected()) emit clipItemSelected(NULL);
1098         dup->baseClip()->removeReference();
1099         m_document->updateClip(dup->baseClip()->getId());
1100         scene()->removeItem(dup);
1101         delete dup;
1102         m_document->renderer()->mltRemoveClip(m_scene->m_tracksList.count() - info.track, cutTime);
1103
1104         ItemInfo clipinfo = item->info();
1105         clipinfo.track = m_scene->m_tracksList.count() - clipinfo.track;
1106         bool success = m_document->renderer()->mltResizeClipEnd(clipinfo, info.endPos - info.startPos);
1107         if (success) {
1108             item->resizeEnd((int) info.endPos.frames(m_document->fps()));
1109         } else
1110             emit displayMessage(i18n("Error when resizing clip"), ErrorMessage);
1111
1112     }
1113     QTimer::singleShot(3000, this, SLOT(slotEnableRefresh()));
1114 }
1115
1116 void CustomTrackView::slotEnableRefresh() {
1117     m_blockRefresh = false;
1118 }
1119
1120 void CustomTrackView::slotAddTransitionToSelectedClips(QDomElement transition) {
1121     QList<QGraphicsItem *> itemList = scene()->selectedItems();
1122     if (itemList.count() == 1) {
1123         if (itemList.at(0)->type() == AVWIDGET) {
1124             ClipItem *item = (ClipItem *) itemList.at(0);
1125             ItemInfo info;
1126             info.track = item->track();
1127             ClipItem *transitionClip = NULL;
1128             const int transitiontrack = getPreviousVideoTrack(info.track);
1129             GenTime pos = GenTime((int)(mapToScene(m_menuPosition).x()), m_document->fps());
1130             if (pos < item->startPos() + item->duration() / 2) {
1131                 // add transition to clip start
1132                 info.startPos = item->startPos();
1133                 if (transitiontrack != 0) transitionClip = getClipItemAt((int) info.startPos.frames(m_document->fps()), m_scene->m_tracksList.count() - transitiontrack);
1134                 if (transitionClip && transitionClip->endPos() < item->endPos()) {
1135                     info.endPos = transitionClip->endPos();
1136                 } else info.endPos = info.startPos + GenTime(65, m_document->fps());
1137             } else {
1138                 // add transition to clip  end
1139                 info.endPos = item->endPos();
1140                 if (transitiontrack != 0) transitionClip = getClipItemAt((int) info.endPos.frames(m_document->fps()), m_scene->m_tracksList.count() - transitiontrack);
1141                 if (transitionClip && transitionClip->startPos() > item->startPos()) {
1142                     info.startPos = transitionClip->startPos();
1143                 } else info.startPos = info.endPos - GenTime(65, m_document->fps());
1144                 if (transition.attribute("tag") == "luma") EffectsList::setParameter(transition, "reverse", "1");
1145             }
1146             slotAddTransition(item, info, transitiontrack, transition);
1147         }
1148     } else for (int i = 0; i < itemList.count(); i++) {
1149             if (itemList.at(i)->type() == AVWIDGET) {
1150                 ClipItem *item = (ClipItem *) itemList.at(i);
1151                 ItemInfo info;
1152                 info.startPos = item->startPos();
1153                 info.endPos = info.startPos + GenTime(65, m_document->fps());
1154                 info.track = item->track();
1155                 int transitiontrack = getPreviousVideoTrack(info.track);
1156                 slotAddTransition(item, info, transitiontrack, transition);
1157             }
1158         }
1159 }
1160
1161 void CustomTrackView::slotAddTransition(ClipItem* clip, ItemInfo transitionInfo, int endTrack, QDomElement transition) {
1162     AddTransitionCommand* command = new AddTransitionCommand(this, transitionInfo, endTrack, transition, false, true);
1163     m_commandStack->push(command);
1164     m_document->setModified(true);
1165 }
1166
1167 void CustomTrackView::addTransition(ItemInfo transitionInfo, int endTrack, QDomElement params) {
1168     Transition *tr = new Transition(transitionInfo, endTrack, m_document->fps(), params);
1169     scene()->addItem(tr);
1170
1171     //kDebug() << "---- ADDING transition " << params.attribute("value");
1172     m_document->renderer()->mltAddTransition(tr->transitionTag(), endTrack, m_scene->m_tracksList.count() - transitionInfo.track, transitionInfo.startPos, transitionInfo.endPos, tr->toXML());
1173     m_document->setModified(true);
1174 }
1175
1176 void CustomTrackView::deleteTransition(ItemInfo transitionInfo, int endTrack, QDomElement params) {
1177     Transition *item = getTransitionItemAt((int)transitionInfo.startPos.frames(m_document->fps()), transitionInfo.track);
1178     if (!item) {
1179         emit displayMessage(i18n("Select clip to delete"), ErrorMessage);
1180         return;
1181     }
1182     m_document->renderer()->mltDeleteTransition(item->transitionTag(), endTrack, m_scene->m_tracksList.count() - transitionInfo.track, transitionInfo.startPos, transitionInfo.endPos, item->toXML());
1183     if (m_dragItem == item) m_dragItem = NULL;
1184     delete item;
1185     emit transitionItemSelected(NULL);
1186     m_document->setModified(true);
1187 }
1188
1189 void CustomTrackView::slotTransitionUpdated(Transition *tr, QDomElement old) {
1190     EditTransitionCommand *command = new EditTransitionCommand(this, tr->track(), tr->startPos(), old, tr->toXML(), true);
1191     m_commandStack->push(command);
1192     m_document->setModified(true);
1193 }
1194
1195 void CustomTrackView::slotTransitionTrackUpdated(Transition *tr, int track) {
1196     QDomElement old = tr->toXML().cloneNode().toElement();
1197     if (track == 0) {
1198         track = getPreviousVideoTrack(tr->track());
1199         tr->setForcedTrack(false, track);
1200     } else {
1201         tr->setForcedTrack(true, m_scene->m_tracksList.count() + 1 - track);
1202     }
1203     EditTransitionCommand *command = new EditTransitionCommand(this, tr->track(), tr->startPos(), old, tr->toXML(), true);
1204     m_commandStack->push(command);
1205     m_document->setModified(true);
1206 }
1207
1208 void CustomTrackView::updateTransition(int track, GenTime pos, QDomElement oldTransition, QDomElement transition, bool updateTransitionWidget) {
1209     Transition *item = getTransitionItemAt((int)pos.frames(m_document->fps()), track);
1210     if (!item) {
1211         kWarning() << "Unable to find transition at pos :" << pos.frames(m_document->fps()) << ", ON track: " << track;
1212         return;
1213     }
1214     m_document->renderer()->mltUpdateTransition(oldTransition.attribute("tag"), transition.attribute("tag"), transition.attribute("transition_btrack").toInt(), m_scene->m_tracksList.count() - transition.attribute("transition_atrack").toInt(), item->startPos(), item->endPos(), transition);
1215     item->setTransitionParameters(transition);
1216     if (updateTransitionWidget) emit transitionItemSelected(item, true);
1217     m_document->setModified(true);
1218 }
1219
1220 void CustomTrackView::dragMoveEvent(QDragMoveEvent * event) {
1221     event->setDropAction(Qt::IgnoreAction);
1222     const int track = (int)(mapToScene(event->pos()).y() / m_tracksHeight);
1223     const int pos = mapToScene(event->pos()).x();
1224     //kDebug() << "// DRAG MOVE TO TRACK: " << track;
1225     if (m_selectionGroup) {
1226         m_selectionGroup->setPos(pos, event->pos().y());
1227         event->setDropAction(Qt::MoveAction);
1228         if (event->mimeData()->hasFormat("kdenlive/producerslist") || event->mimeData()->hasFormat("kdenlive/clip")) {
1229             event->acceptProposedAction();
1230         }
1231     } else {
1232         QGraphicsView::dragMoveEvent(event);
1233     }
1234 }
1235
1236 void CustomTrackView::dragLeaveEvent(QDragLeaveEvent * event) {
1237     if (m_selectionGroup) {
1238         QList<QGraphicsItem *> items = m_selectionGroup->childItems();
1239         qDeleteAll(items);
1240         scene()->destroyItemGroup(m_selectionGroup);
1241         m_selectionGroup = NULL;
1242     } else QGraphicsView::dragLeaveEvent(event);
1243 }
1244
1245 void CustomTrackView::dropEvent(QDropEvent * event) {
1246     if (m_selectionGroup) {
1247         QList<QGraphicsItem *> items = m_selectionGroup->childItems();
1248         m_scene->clearSelection();
1249         if (m_selectionGroup) {
1250             scene()->destroyItemGroup(m_selectionGroup);
1251             m_selectionGroup = NULL;
1252         }
1253         for (int i = 0; i < items.count(); i++) {
1254             ClipItem *item = static_cast <ClipItem *>(items.at(i));
1255             AddTimelineClipCommand *command = new AddTimelineClipCommand(this, item->xml(), item->clipProducer(), item->info(), item->effectList(), false, false);
1256             m_commandStack->push(command);
1257             item->baseClip()->addReference();
1258             m_document->updateClip(item->baseClip()->getId());
1259             ItemInfo info;
1260             info = item->info();
1261             if (item->baseClip()->isTransparent()) {
1262                 // add transparency transition
1263                 int endTrack = getPreviousVideoTrack(info.track);
1264                 Transition *tr = new Transition(info, endTrack, m_document->fps(), MainWindow::transitions.getEffectByTag("composite", "alphatransparency"), true);
1265                 scene()->addItem(tr);
1266                 m_document->renderer()->mltAddTransition(tr->transitionTag(), endTrack, m_scene->m_tracksList.count() - info.track, info.startPos, info.endPos, tr->toXML());
1267             }
1268             info.track = m_scene->m_tracksList.count() - item->track();
1269             m_document->renderer()->mltInsertClip(info, item->xml(), item->baseClip()->producer(item->track()));
1270             item->setSelected(true);
1271         }
1272         m_document->setModified(true);
1273     } else QGraphicsView::dropEvent(event);
1274     setFocus();
1275 }
1276
1277
1278 QStringList CustomTrackView::mimeTypes() const {
1279     QStringList qstrList;
1280     // list of accepted mime types for drop
1281     qstrList.append("text/plain");
1282     qstrList.append("kdenlive/producerslist");
1283     qstrList.append("kdenlive/clip");
1284     return qstrList;
1285 }
1286
1287 Qt::DropActions CustomTrackView::supportedDropActions() const {
1288     // returns what actions are supported when dropping
1289     return Qt::MoveAction;
1290 }
1291
1292 void CustomTrackView::setDuration(int duration) {
1293     if (duration > sceneRect().width())
1294         setSceneRect(0, 0, (duration + 100), sceneRect().height());
1295     m_projectDuration = duration;
1296 }
1297
1298 int CustomTrackView::duration() const {
1299     return m_projectDuration;
1300 }
1301
1302 void CustomTrackView::addTrack(TrackInfo type) {
1303     m_scene->m_tracksList << type;
1304     m_cursorLine->setLine(m_cursorLine->line().x1(), 0, m_cursorLine->line().x1(), m_tracksHeight * m_scene->m_tracksList.count());
1305     setSceneRect(0, 0, sceneRect().width(), m_tracksHeight * m_scene->m_tracksList.count());
1306     verticalScrollBar()->setMaximum(m_tracksHeight * m_scene->m_tracksList.count());
1307     //setFixedHeight(50 * m_tracksCount);
1308 }
1309
1310 void CustomTrackView::removeTrack() {
1311     // TODO: implement track deletion
1312     //m_tracksCount--;
1313     m_cursorLine->setLine(m_cursorLine->line().x1(), 0, m_cursorLine->line().x1(), m_tracksHeight * m_scene->m_tracksList.count());
1314 }
1315
1316
1317 void CustomTrackView::slotSwitchTrackAudio(int ix) {
1318     int tracknumber = m_scene->m_tracksList.count() - ix;
1319     kDebug() << "/////  MUTING TRK: " << ix << "; PL NUM: " << tracknumber;
1320     m_scene->m_tracksList[tracknumber - 1].isMute = !m_scene->m_tracksList.at(tracknumber - 1).isMute;
1321     m_document->renderer()->mltChangeTrackState(tracknumber, m_scene->m_tracksList.at(tracknumber - 1).isMute, m_scene->m_tracksList.at(tracknumber - 1).isBlind);
1322 }
1323
1324 void CustomTrackView::slotSwitchTrackVideo(int ix) {
1325     int tracknumber = m_scene->m_tracksList.count() - ix;
1326     m_scene->m_tracksList[tracknumber - 1].isBlind = !m_scene->m_tracksList.at(tracknumber - 1).isBlind;
1327     m_document->renderer()->mltChangeTrackState(tracknumber, m_scene->m_tracksList.at(tracknumber - 1).isMute, m_scene->m_tracksList.at(tracknumber - 1).isBlind);
1328 }
1329
1330 void CustomTrackView::slotInsertSpace() {
1331     GenTime pos;
1332     int track = 0;
1333     if (m_menuPosition.isNull()) {
1334         pos = GenTime(cursorPos(), m_document->fps());
1335     } else {
1336         pos = GenTime((int)(mapToScene(m_menuPosition).x()), m_document->fps());
1337         track = (int)(mapToScene(m_menuPosition).y() / m_tracksHeight) + 1;
1338     }
1339     SpacerDialog d(GenTime(65, m_document->fps()), m_document->timecode(), track, m_scene->m_tracksList.count(), this);
1340     if (d.exec() != QDialog::Accepted) return;
1341     GenTime spaceDuration = d.selectedDuration();
1342     track = d.selectedTrack();
1343     InsertSpaceCommand *command = new InsertSpaceCommand(this, pos, track, spaceDuration, true);
1344     m_commandStack->push(command);
1345 }
1346
1347 void CustomTrackView::insertSpace(const GenTime &pos, int track, const GenTime duration, bool add) {
1348     int diff = duration.frames(m_document->fps());
1349     if (!add) diff = -diff;
1350     QList<QGraphicsItem *> itemList;
1351     if (track == -1) itemList = items();
1352     else itemList = scene()->items(pos.frames(m_document->fps()) , track * m_tracksHeight + m_tracksHeight / 2, sceneRect().width() - pos.frames(m_document->fps()), m_tracksHeight / 4);
1353     if (m_selectionGroup) {
1354         scene()->destroyItemGroup(m_selectionGroup);
1355         m_selectionGroup = NULL;
1356     }
1357     m_selectionGroup = new AbstractGroupItem(m_document->fps());
1358     scene()->addItem(m_selectionGroup);
1359     for (int i = 0; i < itemList.count(); i++) {
1360         if (itemList.at(i)->type() == AVWIDGET || itemList.at(i)->type() == TRANSITIONWIDGET) {
1361             /*AbstractClipItem *item = static_cast <AbstractClipItem *> (itemList.at(i));
1362             if (item->endPos() > pos)*/
1363             m_selectionGroup->addToGroup(itemList.at(i));
1364             //item->moveBy(diff, 0);
1365         }
1366     }
1367     QPointF top = m_selectionGroup->boundingRect().topLeft();
1368     const int width = m_selectionGroup->boundingRect().width();
1369     const int height = m_selectionGroup->boundingRect().height();
1370     m_selectionGroup->setPos(top);
1371     m_selectionGroup->translate(-top.x(), -top.y() + 1);
1372     m_selectionGroup->moveBy(diff, 0);
1373     if (m_selectionGroup) {
1374         scene()->destroyItemGroup(m_selectionGroup);
1375         m_selectionGroup = NULL;
1376     }
1377     if (track != -1) track = m_scene->m_tracksList.count() - track;
1378     m_document->renderer()->mltInsertSpace(pos, track, duration, add);
1379 }
1380
1381 void CustomTrackView::deleteClip(const QString &clipId) {
1382     QList<QGraphicsItem *> itemList = items();
1383     for (int i = 0; i < itemList.count(); i++) {
1384         if (itemList.at(i)->type() == AVWIDGET) {
1385             ClipItem *item = (ClipItem *)itemList.at(i);
1386             if (item->clipProducer() == clipId) {
1387                 AddTimelineClipCommand *command = new AddTimelineClipCommand(this, item->xml(), item->clipProducer(), item->info(), item->effectList(), true, true);
1388                 m_commandStack->push(command);
1389                 //delete item;
1390             }
1391         }
1392     }
1393 }
1394
1395 void CustomTrackView::setCursorPos(int pos, bool seek) {
1396     emit cursorMoved((int)(m_cursorPos), (int)(pos));
1397     m_cursorPos = pos;
1398     m_cursorLine->setPos(pos, 0);
1399     if (seek) m_document->renderer()->seek(GenTime(pos, m_document->fps()));
1400     else if (m_autoScroll) checkScrolling();
1401 }
1402
1403 void CustomTrackView::updateCursorPos() {
1404     m_cursorLine->setPos(m_cursorPos, 0);
1405 }
1406
1407 int CustomTrackView::cursorPos() {
1408     return (int)(m_cursorPos);
1409 }
1410
1411 void CustomTrackView::moveCursorPos(int delta) {
1412     if (m_cursorPos + delta < 0) delta = 0 - m_cursorPos;
1413     emit cursorMoved((int)(m_cursorPos), (int)((m_cursorPos + delta)));
1414     m_cursorPos += delta;
1415     m_cursorLine->setPos(m_cursorPos, 0);
1416     m_document->renderer()->seek(GenTime(m_cursorPos, m_document->fps()));
1417     //if (m_autoScroll && m_scale < 50) checkScrolling();
1418 }
1419
1420 void CustomTrackView::checkScrolling() {
1421     int vert = verticalScrollBar()->value();
1422     int hor = cursorPos();
1423     ensureVisible(hor, vert + 10, 2, 2, 50, 0);
1424     //centerOn(QPointF(cursorPos(), m_tracksHeight));
1425     /*QRect rectInView = viewport()->rect();
1426     int delta = rectInView.width() / 3;
1427     int max = rectInView.right() + horizontalScrollBar()->value() - delta;
1428     //kDebug() << "CURSOR POS: "<<m_cursorPos<< "Scale: "<<m_scale;
1429     if (m_cursorPos * m_scale >= max) horizontalScrollBar()->setValue((int)(horizontalScrollBar()->value() + 1 + m_scale));*/
1430 }
1431
1432 void CustomTrackView::mouseReleaseEvent(QMouseEvent * event) {
1433     if (m_moveOpMode == SEEK) m_moveOpMode = NONE;
1434     QGraphicsView::mouseReleaseEvent(event);
1435     if (m_scrollTimer.isActive()) m_scrollTimer.stop();
1436     if (event->button() == Qt::MidButton) {
1437         return;
1438     }
1439     setDragMode(QGraphicsView::NoDrag);
1440     if (m_operationMode == MOVEGUIDE) {
1441         setCursor(Qt::ArrowCursor);
1442         m_operationMode = NONE;
1443         m_dragGuide->setFlag(QGraphicsItem::ItemIsMovable, false);
1444         EditGuideCommand *command = new EditGuideCommand(this, m_dragGuide->position(), m_dragGuide->label(), GenTime(m_dragGuide->pos().x(), m_document->fps()), m_dragGuide->label(), false);
1445         m_commandStack->push(command);
1446         m_dragGuide->updateGuide(GenTime(m_dragGuide->pos().x(), m_document->fps()));
1447         m_dragGuide = NULL;
1448         m_dragItem = NULL;
1449         return;
1450     } else if (m_operationMode == SPACER) {
1451         int endClick = (int)(mapToScene(event->pos()).x() + 0.5);
1452         int mappedClick = (int)(mapToScene(m_clickEvent).x() + 0.5);
1453         int diff = endClick - mappedClick;
1454         int track = (int)(mapToScene(m_clickEvent).y() / m_tracksHeight);
1455         InsertSpaceCommand *command = new InsertSpaceCommand(this, GenTime(mappedClick, m_document->fps()), track, GenTime(diff, m_document->fps()), false);
1456         m_commandStack->push(command);
1457         track = m_scene->m_tracksList.count() - track;
1458         m_document->renderer()->mltInsertSpace(GenTime(mappedClick, m_document->fps()), track, GenTime(diff, m_document->fps()), true);
1459         if (m_selectionGroup) {
1460             scene()->destroyItemGroup(m_selectionGroup);
1461             m_selectionGroup = NULL;
1462         }
1463         m_operationMode = NONE;
1464     }
1465
1466     if (m_dragItem == NULL && m_selectionGroup == NULL) {
1467         emit transitionItemSelected(NULL);
1468         return;
1469     }
1470     ItemInfo info;
1471     if (m_dragItem) info = m_dragItem->info();
1472
1473     if (m_operationMode == MOVE) {
1474         setCursor(Qt::OpenHandCursor);
1475
1476         if (m_selectionGroup == NULL) {
1477             // we are moving one clip, easy
1478             if (m_dragItem->type() == AVWIDGET && (m_dragItemInfo.startPos != info.startPos || m_dragItemInfo.track != info.track)) {
1479                 ClipItem *item = static_cast <ClipItem *>(m_dragItem);
1480                 bool success = m_document->renderer()->mltMoveClip((int)(m_scene->m_tracksList.count() - m_dragItemInfo.track), (int)(m_scene->m_tracksList.count() - m_dragItem->track()), (int) m_dragItemInfo.startPos.frames(m_document->fps()), (int)(m_dragItem->startPos().frames(m_document->fps())), item->baseClip()->producer(info.track));
1481                 if (success) {
1482                     MoveClipCommand *command = new MoveClipCommand(this, m_dragItemInfo, info, false);
1483                     m_commandStack->push(command);
1484                     if (item->baseClip()->isTransparent()) {
1485                         // Also move automatic transition
1486                         Transition *tr = getTransitionItemAt((int) m_dragItemInfo.startPos.frames(m_document->fps()), m_dragItemInfo.track);
1487                         if (tr && tr->isAutomatic()) {
1488                             tr->updateTransitionEndTrack(getPreviousVideoTrack(info.track));
1489                             m_document->renderer()->mltMoveTransition(tr->transitionTag(), m_scene->m_tracksList.count() - m_dragItemInfo.track, m_scene->m_tracksList.count() - info.track, tr->transitionEndTrack(), m_dragItemInfo.startPos, m_dragItemInfo.endPos, info.startPos, info.endPos);
1490                             tr->setPos((int) info.startPos.frames(m_document->fps()), (int)(info.track * m_tracksHeight + 1));
1491                         }
1492                     }
1493                 } else {
1494                     // undo last move and emit error message
1495                     MoveClipCommand *command = new MoveClipCommand(this, info, m_dragItemInfo, true);
1496                     m_commandStack->push(command);
1497                     emit displayMessage(i18n("Cannot move clip to position %1seconds", QString::number(m_dragItemInfo.startPos.seconds(), 'g', 2)), ErrorMessage);
1498                 }
1499             }
1500             if (m_dragItem->type() == TRANSITIONWIDGET && (m_dragItemInfo.startPos != info.startPos || m_dragItemInfo.track != info.track)) {
1501                 MoveTransitionCommand *command = new MoveTransitionCommand(this, m_dragItemInfo, info, false);
1502                 m_commandStack->push(command);
1503                 Transition *transition = (Transition *) m_dragItem;
1504                 transition->updateTransitionEndTrack(getPreviousVideoTrack(m_dragItem->track()));
1505                 m_document->renderer()->mltMoveTransition(transition->transitionTag(), (int)(m_scene->m_tracksList.count() - m_dragItemInfo.track), (int)(m_scene->m_tracksList.count() - m_dragItem->track()), transition->transitionEndTrack(), m_dragItemInfo.startPos, m_dragItemInfo.endPos, info.startPos, info.endPos);
1506             }
1507         } else {
1508             // Moving several clips. We need to delete them and readd them to new position,
1509             // or they might overlap each other during the move
1510
1511             QList<QGraphicsItem *> items = m_selectionGroup->childItems();
1512
1513             GenTime timeOffset = GenTime(m_selectionGroup->scenePos().x(), m_document->fps()) - m_selectionGroupInfo.startPos;
1514             const int trackOffset = m_selectionGroup->track() - m_selectionGroupInfo.track;
1515             //kDebug() << "&DROPPED GRPOUP:" << timeOffset.frames(25) << "x" << trackOffset;
1516             if (timeOffset != GenTime() || trackOffset != 0) {
1517                 QUndoCommand *moveClips = new QUndoCommand();
1518                 moveClips->setText("Move clips");
1519                 // remove items in MLT playlist
1520                 for (int i = 0; i < items.count(); i++) {
1521                     AbstractClipItem *item = static_cast <AbstractClipItem *>(items.at(i));
1522                     ItemInfo info = item->info();
1523                     /*info.startPos = info.startPos - timeOffset;
1524                     info.endPos = info.endPos - timeOffset;
1525                     info.track = info.track - trackOffset;*/
1526                     //kDebug() << "REM CLP:" << i << ", START:" << info.startPos.frames(25);
1527                     if (item->type() == AVWIDGET) {
1528                         ClipItem *clip = static_cast <ClipItem*>(item);
1529                         new AddTimelineClipCommand(this, clip->xml(), clip->clipProducer(), info, clip->effectList(), false, true, moveClips);
1530                         m_document->renderer()->mltRemoveClip(m_scene->m_tracksList.count() - info.track, info.startPos);
1531                     } else {
1532                         Transition *tr = static_cast <Transition*>(item);
1533                         new AddTransitionCommand(this, info, tr->transitionEndTrack(), tr->toXML(), false, true, moveClips);
1534                         m_document->renderer()->mltDeleteTransition(tr->transitionTag(), tr->transitionEndTrack(), m_scene->m_tracksList.count() - info.track, info.startPos, info.endPos, tr->toXML());
1535                     }
1536                 }
1537
1538                 for (int i = 0; i < items.count(); i++) {
1539                     // re-add items in correct place
1540                     AbstractClipItem *item = static_cast <AbstractClipItem *>(items.at(i));
1541                     ItemInfo info = item->info();
1542                     info.startPos = info.startPos + timeOffset;
1543                     info.endPos = info.endPos + timeOffset;
1544                     info.track = info.track + trackOffset;
1545                     if (item->type() == AVWIDGET) {
1546                         ClipItem *clip = static_cast <ClipItem*>(item);
1547                         new AddTimelineClipCommand(this, clip->xml(), clip->clipProducer(), info, clip->effectList(), false, false, moveClips);
1548                         info.track = m_scene->m_tracksList.count() - info.track;
1549                         m_document->renderer()->mltInsertClip(info, clip->xml(), clip->baseClip()->producer(info.track));
1550                     } else {
1551                         Transition *tr = static_cast <Transition*>(item);
1552                         ItemInfo transitionInfo = tr->info();
1553                         new AddTransitionCommand(this, info, tr->transitionEndTrack(), tr->toXML(), false, false, moveClips);
1554                         m_document->renderer()->mltAddTransition(tr->transitionTag(), tr->transitionEndTrack() + trackOffset, m_scene->m_tracksList.count() - transitionInfo.track, transitionInfo.startPos, transitionInfo.endPos, tr->toXML());
1555                     }
1556                 }
1557                 m_commandStack->push(moveClips);
1558             }
1559         }
1560
1561     } else if (m_operationMode == RESIZESTART && m_dragItem->startPos() != m_dragItemInfo.startPos) {
1562         // resize start
1563         if (m_dragItem->type() == AVWIDGET) {
1564             ItemInfo resizeinfo = m_dragItemInfo;
1565             resizeinfo.track = m_scene->m_tracksList.count() - resizeinfo.track;
1566             bool success = m_document->renderer()->mltResizeClipStart(resizeinfo, m_dragItem->startPos() - m_dragItemInfo.startPos);
1567             if (success) {
1568                 updateClipFade(static_cast <ClipItem *>(m_dragItem));
1569                 ResizeClipCommand *command = new ResizeClipCommand(this, m_dragItemInfo, info, false);
1570                 m_commandStack->push(command);
1571             } else {
1572                 m_dragItem->resizeStart((int) m_dragItemInfo.startPos.frames(m_document->fps()));
1573                 emit displayMessage(i18n("Error when resizing clip"), ErrorMessage);
1574             }
1575         } else if (m_dragItem->type() == TRANSITIONWIDGET) {
1576             MoveTransitionCommand *command = new MoveTransitionCommand(this, m_dragItemInfo, info, false);
1577             m_commandStack->push(command);
1578             Transition *transition = static_cast <Transition *>(m_dragItem);
1579             m_document->renderer()->mltMoveTransition(transition->transitionTag(), (int)(m_scene->m_tracksList.count() - m_dragItemInfo.track), (int)(m_scene->m_tracksList.count() - m_dragItemInfo.track), 0, m_dragItemInfo.startPos, m_dragItemInfo.endPos, info.startPos, info.endPos);
1580         }
1581
1582         //m_document->renderer()->doRefresh();
1583     } else if (m_operationMode == RESIZEEND && m_dragItem->endPos() != m_dragItemInfo.endPos) {
1584         // resize end
1585         if (m_dragItem->type() == AVWIDGET) {
1586             ItemInfo resizeinfo = info;
1587             resizeinfo.track = m_scene->m_tracksList.count() - resizeinfo.track;
1588             bool success = m_document->renderer()->mltResizeClipEnd(resizeinfo, resizeinfo.endPos - resizeinfo.startPos);
1589             if (success) {
1590                 ResizeClipCommand *command = new ResizeClipCommand(this, m_dragItemInfo, info, false);
1591                 m_commandStack->push(command);
1592                 updateClipFade(static_cast <ClipItem *>(m_dragItem), true);
1593             } else {
1594                 m_dragItem->resizeEnd((int) m_dragItemInfo.endPos.frames(m_document->fps()));
1595                 emit displayMessage(i18n("Error when resizing clip"), ErrorMessage);
1596             }
1597         } else if (m_dragItem->type() == TRANSITIONWIDGET) {
1598             MoveTransitionCommand *command = new MoveTransitionCommand(this, m_dragItemInfo, info, false);
1599             m_commandStack->push(command);
1600             Transition *transition = static_cast <Transition *>(m_dragItem);
1601             m_document->renderer()->mltMoveTransition(transition->transitionTag(), (int)(m_scene->m_tracksList.count() - m_dragItemInfo.track), (int)(m_scene->m_tracksList.count() - m_dragItemInfo.track), 0, m_dragItemInfo.startPos, m_dragItemInfo.endPos, info.startPos, info.endPos);
1602         }
1603         //m_document->renderer()->doRefresh();
1604     } else if (m_operationMode == FADEIN) {
1605         // resize fade in effect
1606         ClipItem * item = (ClipItem *) m_dragItem;
1607         int ix = item->hasEffect("volume", "fadein");
1608         if (ix != -1) {
1609             QDomElement oldeffect = item->effectAt(ix);
1610             int start = item->cropStart().frames(m_document->fps());
1611             int end = item->fadeIn();
1612             if (end == 0) {
1613                 slotDeleteEffect(item, oldeffect);
1614             } else {
1615                 end += start;
1616                 QDomElement effect = oldeffect.cloneNode().toElement();
1617                 EffectsList::setParameter(oldeffect, "in", QString::number(start));
1618                 EffectsList::setParameter(oldeffect, "out", QString::number(end));
1619                 slotUpdateClipEffect(item, effect, oldeffect, ix);
1620                 emit clipItemSelected(item, ix);
1621             }
1622         } else if (item->fadeIn() != 0) {
1623             QDomElement effect = MainWindow::audioEffects.getEffectByTag("volume", "fadein").cloneNode().toElement();
1624             EffectsList::setParameter(effect, "out", QString::number(item->fadeIn()));
1625             slotAddEffect(effect, m_dragItem->startPos(), m_dragItem->track());
1626         }
1627     } else if (m_operationMode == FADEOUT) {
1628         // resize fade in effect
1629         ClipItem * item = (ClipItem *) m_dragItem;
1630         int ix = item->hasEffect("volume", "fadeout");
1631         if (ix != -1) {
1632             QDomElement oldeffect = item->effectAt(ix);
1633             int end = (item->duration() + item->cropStart()).frames(m_document->fps());
1634             int start = item->fadeOut();
1635             if (start == 0) {
1636                 slotDeleteEffect(item, oldeffect);
1637             } else {
1638                 start = end - start;
1639                 QDomElement effect = oldeffect.cloneNode().toElement();
1640                 EffectsList::setParameter(oldeffect, "in", QString::number(start));
1641                 EffectsList::setParameter(oldeffect, "out", QString::number(end));
1642                 slotUpdateClipEffect(item, effect, oldeffect, ix);
1643                 emit clipItemSelected(item, ix);
1644             }
1645         } else if (item->fadeOut() != 0) {
1646             QDomElement effect = MainWindow::audioEffects.getEffectByTag("volume", "fadeout").cloneNode().toElement();
1647             EffectsList::setParameter(effect, "out", QString::number(item->fadeOut()));
1648             slotAddEffect(effect, m_dragItem->startPos(), m_dragItem->track());
1649         }
1650     } else if (m_operationMode == KEYFRAME) {
1651         // update the MLT effect
1652         ClipItem * item = (ClipItem *) m_dragItem;
1653         QString previous = item->keyframes(item->selectedEffectIndex());
1654         item->updateKeyframeEffect();
1655         QString next = item->keyframes(item->selectedEffectIndex());
1656         EditKeyFrameCommand *command = new EditKeyFrameCommand(this, item->track(), item->startPos(), item->selectedEffectIndex(), previous, next, false);
1657         m_commandStack->push(command);
1658         updateEffect(m_scene->m_tracksList.count() - item->track(), item->startPos(), item->selectedEffect(), item->selectedEffectIndex());
1659     }
1660
1661     emit transitionItemSelected((m_dragItem && m_dragItem->type() == TRANSITIONWIDGET) ? static_cast <Transition *>(m_dragItem) : NULL);
1662     m_document->setModified(true);
1663     m_operationMode = NONE;
1664 }
1665
1666 void CustomTrackView::deleteClip(ItemInfo info) {
1667     ClipItem *item = getClipItemAt((int) info.startPos.frames(m_document->fps()) + 1, info.track);
1668     if (!item) {
1669         kDebug() << "----------------  ERROR, CANNOT find clip to delete at...";// << rect.x();
1670         return;
1671     }
1672     if (item->isSelected()) emit clipItemSelected(NULL);
1673     item->baseClip()->removeReference();
1674     m_document->updateClip(item->baseClip()->getId());
1675
1676     if (item->baseClip()->isTransparent()) {
1677         // also remove automatic transition
1678         Transition *tr = getTransitionItemAt((int) info.startPos.frames(m_document->fps()), info.track);
1679         if (tr && tr->isAutomatic()) {
1680             m_document->renderer()->mltDeleteTransition(tr->transitionTag(), tr->transitionEndTrack(), m_scene->m_tracksList.count() - info.track, info.startPos, info.endPos, tr->toXML());
1681             scene()->removeItem(tr);
1682             delete tr;
1683         }
1684     }
1685     scene()->removeItem(item);
1686     if (m_dragItem == item) m_dragItem = NULL;
1687     delete item;
1688     m_document->renderer()->mltRemoveClip(m_scene->m_tracksList.count() - info.track, info.startPos);
1689     m_document->renderer()->doRefresh();
1690 }
1691
1692 void CustomTrackView::deleteSelectedClips() {
1693     QList<QGraphicsItem *> itemList = scene()->selectedItems();
1694     if (itemList.count() == 0) {
1695         emit displayMessage(i18n("Select clip to delete"), ErrorMessage);
1696         return;
1697     }
1698     QUndoCommand *deleteSelected = new QUndoCommand();
1699     deleteSelected->setText(i18n("Delete selected items"));
1700     for (int i = 0; i < itemList.count(); i++) {
1701         if (itemList.at(i)->type() == AVWIDGET) {
1702             ClipItem *item = static_cast <ClipItem *>(itemList.at(i));
1703             new AddTimelineClipCommand(this, item->xml(), item->clipProducer(), item->info(), item->effectList(), true, true, deleteSelected);
1704         } else if (itemList.at(i)->type() == TRANSITIONWIDGET) {
1705             Transition *item = static_cast <Transition *>(itemList.at(i));
1706             ItemInfo info;
1707             info.startPos = item->startPos();
1708             info.endPos = item->endPos();
1709             info.track = item->track();
1710             new AddTransitionCommand(this, info, item->transitionEndTrack(), item->toXML(), true, true, deleteSelected);
1711         }
1712     }
1713     m_commandStack->push(deleteSelected);
1714 }
1715
1716 void CustomTrackView::changeClipSpeed() {
1717     QList<QGraphicsItem *> itemList = scene()->selectedItems();
1718     if (itemList.count() == 0) {
1719         emit displayMessage(i18n("Select clip to change speed"), ErrorMessage);
1720         return;
1721     }
1722     QUndoCommand *changeSelected = new QUndoCommand();
1723     changeSelected->setText("Edit clip speed");
1724     for (int i = 0; i < itemList.count(); i++) {
1725         if (itemList.at(i)->type() == AVWIDGET) {
1726             ClipItem *item = static_cast <ClipItem *>(itemList.at(i));
1727             ItemInfo info = item->info();
1728             int percent = QInputDialog::getInteger(this, i18n("Edit Clip Speed"), i18n("New speed (percents)"), item->speed() * 100, 1, 300);
1729             double speed = (double) percent / 100.0;
1730             if (item->speed() != speed)
1731                 new ChangeSpeedCommand(this, info, item->speed(), speed, item->clipProducer(), true, changeSelected);
1732         }
1733     }
1734     m_commandStack->push(changeSelected);
1735 }
1736
1737 void CustomTrackView::doChangeClipSpeed(ItemInfo info, const double speed, const double oldspeed, const QString &id) {
1738
1739     DocClipBase *baseclip = m_document->clipManager()->getClipById(id);
1740     ClipItem *item = getClipItemAt((int) info.startPos.frames(m_document->fps()) + 1, info.track);
1741     info.track = m_scene->m_tracksList.count() - item->track();
1742     int endPos = m_document->renderer()->mltChangeClipSpeed(info, speed, oldspeed, baseclip->producer());
1743     //kDebug() << "//CH CLIP SPEED: " << speed << "x" << oldspeed << ", END POS: " << endPos;
1744     item->setSpeed(speed);
1745     item->updateRectGeometry();
1746     if (item->cropDuration().frames(m_document->fps()) > endPos)
1747         item->AbstractClipItem::resizeEnd(info.startPos.frames(m_document->fps()) + endPos, speed);
1748 }
1749
1750 void CustomTrackView::cutSelectedClips() {
1751     QList<QGraphicsItem *> itemList = scene()->selectedItems();
1752     GenTime currentPos = GenTime(m_cursorPos, m_document->fps());
1753     for (int i = 0; i < itemList.count(); i++) {
1754         if (itemList.at(i)->type() == AVWIDGET) {
1755             ClipItem *item = static_cast <ClipItem *>(itemList.at(i));
1756             if (currentPos > item->startPos() && currentPos <  item->endPos()) {
1757                 RazorClipCommand *command = new RazorClipCommand(this, item->info(), currentPos, true);
1758                 m_commandStack->push(command);
1759             }
1760         }
1761     }
1762 }
1763
1764 void CustomTrackView::addClip(QDomElement xml, const QString &clipId, ItemInfo info, EffectsList effects) {
1765     DocClipBase *baseclip = m_document->clipManager()->getClipById(clipId);
1766     if (baseclip == NULL) {
1767         emit displayMessage(i18n("No clip copied"), ErrorMessage);
1768         return;
1769     }
1770     ClipItem *item = new ClipItem(baseclip, info, m_document->fps());
1771     item->setEffectList(effects);
1772     scene()->addItem(item);
1773     if (item->baseClip()->isTransparent()) {
1774         // add transparency transition
1775         int endTrack = getPreviousVideoTrack(info.track);
1776         Transition *tr = new Transition(info, endTrack, m_document->fps(), MainWindow::transitions.getEffectByTag("composite", "alphatransparency"), true);
1777         scene()->addItem(tr);
1778         m_document->renderer()->mltAddTransition(tr->transitionTag(), endTrack, m_scene->m_tracksList.count() - info.track, info.startPos, info.endPos, tr->toXML());
1779     }
1780
1781     baseclip->addReference();
1782     m_document->updateClip(baseclip->getId());
1783     info.track = m_scene->m_tracksList.count() - info.track;
1784     m_document->renderer()->mltInsertClip(info, xml, baseclip->producer(info.track));
1785     for (int i = 0; i < item->effectsCount(); i++) {
1786         m_document->renderer()->mltAddEffect(info.track, info.startPos, item->getEffectArgs(item->effectAt(i)), false);
1787     }
1788     m_document->renderer()->doRefresh();
1789 }
1790
1791 void CustomTrackView::slotUpdateClip(const QString &clipId) {
1792     QList<QGraphicsItem *> list = scene()->items();
1793     ClipItem *clip = NULL;
1794     for (int i = 0; i < list.size(); ++i) {
1795         if (list.at(i)->type() == AVWIDGET) {
1796             clip = static_cast <ClipItem *>(list.at(i));
1797             if (clip->clipProducer() == clipId) {
1798                 clip->refreshClip();
1799                 ItemInfo info = clip->info();
1800                 info.track = m_scene->m_tracksList.count() - clip->track();
1801                 m_document->renderer()->mltUpdateClip(info, clip->xml(), clip->baseClip()->producer());
1802             }
1803         }
1804     }
1805 }
1806
1807 ClipItem *CustomTrackView::getClipItemAt(int pos, int track) {
1808     QList<QGraphicsItem *> list = scene()->items(QPointF(pos , track * m_tracksHeight + m_tracksHeight / 2));
1809     ClipItem *clip = NULL;
1810     for (int i = 0; i < list.size(); ++i) {
1811         if (list.at(i)->type() == AVWIDGET) {
1812             clip = static_cast <ClipItem *>(list.at(i));
1813             break;
1814         }
1815     }
1816     return clip;
1817 }
1818
1819 ClipItem *CustomTrackView::getClipItemAt(GenTime pos, int track) {
1820     int framepos = (int)(pos.frames(m_document->fps()));
1821     return getClipItemAt(framepos, track);
1822 }
1823
1824 Transition *CustomTrackView::getTransitionItemAt(int pos, int track) {
1825     QList<QGraphicsItem *> list = scene()->items(QPointF(pos, (track + 1) * m_tracksHeight));
1826     Transition *clip = NULL;
1827     for (int i = 0; i < list.size(); ++i) {
1828         if (list.at(i)->type() == TRANSITIONWIDGET) {
1829             clip = static_cast <Transition *>(list.at(i));
1830             break;
1831         }
1832     }
1833     return clip;
1834 }
1835
1836 Transition *CustomTrackView::getTransitionItemAt(GenTime pos, int track) {
1837     int framepos = (int)(pos.frames(m_document->fps()));
1838     return getTransitionItemAt(framepos, track);
1839 }
1840
1841 void CustomTrackView::moveClip(const ItemInfo start, const ItemInfo end) {
1842     ClipItem *item = getClipItemAt((int) start.startPos.frames(m_document->fps()) + 1, start.track);
1843     if (!item) {
1844         emit displayMessage(i18n("Cannot move clip at time: %1s on track %2", QString::number(start.startPos.seconds(), 'g', 2), start.track), ErrorMessage);
1845         kDebug() << "----------------  ERROR, CANNOT find clip to move at.. ";// << startPos.x() * m_scale * FRAME_SIZE + 1 << ", " << startPos.y() * m_tracksHeight + m_tracksHeight / 2;
1846         return;
1847     }
1848     //kDebug() << "----------------  Move CLIP FROM: " << startPos.x() << ", END:" << endPos.x() << ",TRACKS: " << startPos.y() << " TO " << endPos.y();
1849
1850     bool success = m_document->renderer()->mltMoveClip((int)(m_scene->m_tracksList.count() - start.track), (int)(m_scene->m_tracksList.count() - end.track), (int) start.startPos.frames(m_document->fps()), (int)end.startPos.frames(m_document->fps()), item->baseClip()->producer(end.track));
1851     if (success) {
1852         item->setPos((int) end.startPos.frames(m_document->fps()), (int)(end.track * m_tracksHeight + 1));
1853         if (item->baseClip()->isTransparent()) {
1854             // Also move automatic transition
1855             Transition *tr = getTransitionItemAt((int) start.startPos.frames(m_document->fps()), start.track);
1856             if (tr && tr->isAutomatic()) {
1857                 tr->updateTransitionEndTrack(getPreviousVideoTrack(end.track));
1858                 m_document->renderer()->mltMoveTransition(tr->transitionTag(), m_scene->m_tracksList.count() - start.track, m_scene->m_tracksList.count() - end.track, tr->transitionEndTrack(), start.startPos, start.endPos, end.startPos, end.endPos);
1859                 tr->setPos((int) end.startPos.frames(m_document->fps()), (int)(end.track * m_tracksHeight + 1));
1860             }
1861         }
1862     } else {
1863         // undo last move and emit error message
1864         emit displayMessage(i18n("Cannot move clip to position %1seconds", QString::number(end.startPos.seconds(), 'g', 2)), ErrorMessage);
1865     }
1866 }
1867
1868 void CustomTrackView::moveTransition(const ItemInfo start, const ItemInfo end) {
1869     Transition *item = getTransitionItemAt((int)start.startPos.frames(m_document->fps()), start.track);
1870     if (!item) {
1871         emit displayMessage(i18n("Cannot move transition at time: %1s on track %2", start.startPos.seconds(), start.track), ErrorMessage);
1872         kDebug() << "----------------  ERROR, CANNOT find transition to move... ";// << startPos.x() * m_scale * FRAME_SIZE + 1 << ", " << startPos.y() * m_tracksHeight + m_tracksHeight / 2;
1873         return;
1874     }
1875     //kDebug() << "----------------  Move TRANSITION FROM: " << startPos.x() << ", END:" << endPos.x() << ",TRACKS: " << oldtrack << " TO " << newtrack;
1876
1877     //kDebug()<<"///  RESIZE TRANS START: ("<< startPos.x()<<"x"<< startPos.y()<<") / ("<<endPos.x()<<"x"<< endPos.y()<<")";
1878     if (end.endPos - end.startPos == start.endPos - start.startPos) {
1879         // Transition was moved
1880         item->setPos((int) end.startPos.frames(m_document->fps()), (end.track) * m_tracksHeight + 1);
1881     } else if (end.endPos == start.endPos) {
1882         // Transition start resize
1883         item->resizeStart((int) end.startPos.frames(m_document->fps()));
1884     } else {
1885         // Transition end resize;
1886         item->resizeEnd((int) end.endPos.frames(m_document->fps()));
1887     }
1888     //item->moveTransition(GenTime((int) (endPos.x() - startPos.x()), m_document->fps()));
1889     item->updateTransitionEndTrack(getPreviousVideoTrack(end.track));
1890     m_document->renderer()->mltMoveTransition(item->transitionTag(), m_scene->m_tracksList.count() - start.track, m_scene->m_tracksList.count() - end.track, item->transitionEndTrack(), start.startPos, start.endPos, end.startPos, end.endPos);
1891 }
1892
1893 void CustomTrackView::resizeClip(const ItemInfo start, const ItemInfo end) {
1894     int offset = 0;
1895     bool resizeClipStart = true;
1896     if (start.startPos == end.startPos) resizeClipStart = false;
1897     /*if (resizeClipStart) offset = 1;
1898     else offset = -1;*/
1899     ClipItem *item = getClipItemAt((int)(start.startPos.frames(m_document->fps()) + offset), start.track);
1900     if (!item) {
1901         emit displayMessage(i18n("Cannot move clip at time: %1s on track %2", start.startPos.seconds(), start.track), ErrorMessage);
1902         kDebug() << "----------------  ERROR, CANNOT find clip to resize at... "; // << startPos;
1903         return;
1904     }
1905     if (resizeClipStart) {
1906         ItemInfo clipinfo = item->info();
1907         clipinfo.track = m_scene->m_tracksList.count() - clipinfo.track;
1908         bool success = m_document->renderer()->mltResizeClipStart(clipinfo, end.startPos - item->startPos());
1909         if (success) {
1910             item->resizeStart((int) end.startPos.frames(m_document->fps()));
1911             updateClipFade(item);
1912         } else emit displayMessage(i18n("Error when resizing clip"), ErrorMessage);
1913     } else {
1914         ItemInfo clipinfo = item->info();
1915         clipinfo.track = m_scene->m_tracksList.count() - clipinfo.track;
1916         bool success = m_document->renderer()->mltResizeClipEnd(clipinfo, end.endPos - clipinfo.startPos);
1917         if (success) {
1918             item->resizeEnd((int) end.endPos.frames(m_document->fps()));
1919             updateClipFade(item, true);
1920         } else emit displayMessage(i18n("Error when resizing clip"), ErrorMessage);
1921     }
1922     m_document->renderer()->doRefresh();
1923 }
1924
1925 void CustomTrackView::updateClipFade(ClipItem * item, bool updateFadeOut) {
1926     if (!updateFadeOut) {
1927         int end = item->fadeIn();
1928         if (end != 0) {
1929             // there is a fade in effect
1930             int effectPos = item->hasEffect("volume", "fadein");
1931             if (effectPos == -1) return;
1932             QDomElement oldeffect = item->effectAt(effectPos);
1933             int start = item->cropStart().frames(m_document->fps());
1934             int max = item->cropDuration().frames(m_document->fps());
1935             if (end > max) {
1936                 item->setFadeIn(max);
1937                 end = item->fadeIn();
1938             }
1939             end += start;
1940             EffectsList::setParameter(oldeffect, "in", QString::number(start));
1941             EffectsList::setParameter(oldeffect, "out", QString::number(end));
1942             QHash <QString, QString> effectParams = item->getEffectArgs(oldeffect);
1943             if (!m_document->renderer()->mltEditEffect(m_scene->m_tracksList.count() - item->track(), item->startPos(), effectParams))
1944                 emit displayMessage(i18n("Problem editing effect"), ErrorMessage);
1945             // if fade effect is displayed, update the effect edit widget with new clip duration
1946             if (item->isSelected() && effectPos == item->selectedEffectIndex()) emit clipItemSelected(item, effectPos);
1947         }
1948     } else {
1949         int start = item->fadeOut();
1950         if (start != 0) {
1951             // there is a fade in effect
1952             int effectPos = item->hasEffect("volume", "fadeout");
1953             if (effectPos == -1) return;
1954             QDomElement oldeffect = item->effectAt(effectPos);
1955             int end = (item->duration() - item->cropStart()).frames(m_document->fps());
1956             int max = item->cropDuration().frames(m_document->fps());
1957             if (end > max) {
1958                 item->setFadeOut(max);
1959                 start = item->fadeOut();
1960             }
1961             start = end - start;
1962             EffectsList::setParameter(oldeffect, "in", QString::number(start));
1963             EffectsList::setParameter(oldeffect, "out", QString::number(end));
1964             QHash <QString, QString> effectParams = item->getEffectArgs(oldeffect);
1965             if (!m_document->renderer()->mltEditEffect(m_scene->m_tracksList.count() - item->track(), item->startPos(), effectParams))
1966                 emit displayMessage(i18n("Problem editing effect"), ErrorMessage);
1967             // if fade effect is displayed, update the effect edit widget with new clip duration
1968             if (item->isSelected() && effectPos == item->selectedEffectIndex()) emit clipItemSelected(item, effectPos);
1969         }
1970     }
1971 }
1972
1973 double CustomTrackView::getSnapPointForPos(double pos) {
1974     return m_scene->getSnapPointForPos(pos, KdenliveSettings::snaptopoints());
1975 }
1976
1977 void CustomTrackView::updateSnapPoints(AbstractClipItem *selected) {
1978     QList <GenTime> snaps;
1979     GenTime offset;
1980     if (selected) offset = selected->duration();
1981     QList<QGraphicsItem *> itemList = items();
1982     for (int i = 0; i < itemList.count(); i++) {
1983         if (itemList.at(i)->type() == AVWIDGET && itemList.at(i) != selected) {
1984             ClipItem *item = static_cast <ClipItem *>(itemList.at(i));
1985             GenTime start = item->startPos();
1986             GenTime end = item->endPos();
1987             snaps.append(start);
1988             snaps.append(end);
1989             QList < GenTime > markers = item->snapMarkers();
1990             for (int i = 0; i < markers.size(); ++i) {
1991                 GenTime t = markers.at(i);
1992                 snaps.append(t);
1993                 if (t > offset) snaps.append(t - offset);
1994             }
1995             if (offset != GenTime()) {
1996                 if (start > offset) snaps.append(start - offset);
1997                 if (end > offset) snaps.append(end - offset);
1998             }
1999         } else if (itemList.at(i)->type() == TRANSITIONWIDGET) {
2000             Transition *transition = static_cast <Transition*>(itemList.at(i));
2001             GenTime start = transition->startPos();
2002             GenTime end = transition->endPos();
2003             snaps.append(start);
2004             snaps.append(end);
2005             if (offset != GenTime()) {
2006                 if (start > offset) snaps.append(start - offset);
2007                 if (end > offset) snaps.append(end - offset);
2008             }
2009         }
2010     }
2011
2012     // add cursor position
2013     GenTime pos = GenTime(m_cursorPos, m_document->fps());
2014     snaps.append(pos);
2015     if (offset != GenTime()) snaps.append(pos - offset);
2016
2017     // add guides
2018     for (int i = 0; i < m_guides.count(); i++) {
2019         snaps.append(m_guides.at(i)->position());
2020         if (offset != GenTime()) snaps.append(m_guides.at(i)->position() - offset);
2021     }
2022
2023     qSort(snaps);
2024     m_scene->setSnapList(snaps);
2025     //for (int i = 0; i < m_snapPoints.size(); ++i)
2026     //    kDebug() << "SNAP POINT: " << m_snapPoints.at(i).frames(25);
2027 }
2028
2029 void CustomTrackView::slotSeekToPreviousSnap() {
2030     updateSnapPoints(NULL);
2031     GenTime res = m_scene->previousSnapPoint(GenTime(m_cursorPos, m_document->fps()));
2032     setCursorPos((int) res.frames(m_document->fps()));
2033     checkScrolling();
2034 }
2035
2036 void CustomTrackView::slotSeekToNextSnap() {
2037     updateSnapPoints(NULL);
2038     GenTime res = m_scene->nextSnapPoint(GenTime(m_cursorPos, m_document->fps()));
2039     setCursorPos((int) res.frames(m_document->fps()));
2040     checkScrolling();
2041 }
2042
2043 void CustomTrackView::clipStart() {
2044     ClipItem *item = getMainActiveClip();
2045     if (item != NULL) {
2046         setCursorPos((int) item->startPos().frames(m_document->fps()));
2047         checkScrolling();
2048     }
2049 }
2050
2051 void CustomTrackView::clipEnd() {
2052     ClipItem *item = getMainActiveClip();
2053     if (item != NULL) {
2054         setCursorPos((int) item->endPos().frames(m_document->fps()));
2055         checkScrolling();
2056     }
2057 }
2058
2059 void CustomTrackView::slotAddClipMarker() {
2060     QList<QGraphicsItem *> itemList = scene()->selectedItems();
2061     if (itemList.count() != 1) {
2062         emit displayMessage(i18n("Cannot add marker if more than one clip is selected"), ErrorMessage);
2063         kDebug() << "// CANNOT ADD MARKER IF MORE TAN ONE CLIP IS SELECTED....";
2064         return;
2065     }
2066     AbstractClipItem *item = (AbstractClipItem *)itemList.at(0);
2067     if (item->type() != AVWIDGET) return;
2068     GenTime pos = GenTime(m_cursorPos, m_document->fps());
2069     if (item->startPos() > pos || item->endPos() < pos) return;
2070     ClipItem *clip = (ClipItem *) item;
2071     QString id = clip->baseClip()->getId();
2072     GenTime position = pos - item->startPos() + item->cropStart();
2073     CommentedTime marker(position, i18n("Marker"));
2074     MarkerDialog d(clip->baseClip(), marker, m_document->timecode(), i18n("Add Marker"), this);
2075     if (d.exec() == QDialog::Accepted) {
2076         slotAddClipMarker(id, d.newMarker().time(), d.newMarker().comment());
2077     }
2078 }
2079
2080 void CustomTrackView::slotAddClipMarker(const QString &id, GenTime t, QString c) {
2081     QString oldcomment = m_document->clipManager()->getClipById(id)->markerComment(t);
2082     AddMarkerCommand *command = new AddMarkerCommand(this, oldcomment, c, id, t, true);
2083     m_commandStack->push(command);
2084 }
2085
2086 void CustomTrackView::slotDeleteClipMarker() {
2087     QList<QGraphicsItem *> itemList = scene()->selectedItems();
2088     if (itemList.count() != 1) {
2089         emit displayMessage(i18n("Cannot delete marker if more than one clip is selected"), ErrorMessage);
2090         kDebug() << "// CANNOT DELETE MARKER IF MORE TAN ONE CLIP IS SELECTED....";
2091         return;
2092     }
2093     AbstractClipItem *item = (AbstractClipItem *)itemList.at(0);
2094     if (item->type() != AVWIDGET) {
2095         emit displayMessage(i18n("No clip selected"), ErrorMessage);
2096         return;
2097     }
2098     GenTime pos = GenTime(m_cursorPos, m_document->fps());
2099     if (item->startPos() > pos || item->endPos() < pos) {
2100         emit displayMessage(i18n("No selected clip at cursor time"), ErrorMessage);
2101         return;
2102     }
2103     ClipItem *clip = (ClipItem *) item;
2104     QString id = clip->baseClip()->getId();
2105     GenTime position = pos - item->startPos() + item->cropStart();
2106     QString comment = clip->baseClip()->markerComment(position);
2107     if (comment.isEmpty()) {
2108         emit displayMessage(i18n("No marker found at cursor time"), ErrorMessage);
2109         return;
2110     }
2111     AddMarkerCommand *command = new AddMarkerCommand(this, comment, QString(), id, position, true);
2112     m_commandStack->push(command);
2113 }
2114
2115 void CustomTrackView::slotDeleteAllClipMarkers() {
2116     QList<QGraphicsItem *> itemList = scene()->selectedItems();
2117     if (itemList.count() != 1) {
2118         emit displayMessage(i18n("Cannot delete marker if more than one clip is selected"), ErrorMessage);
2119         kDebug() << "// CANNOT DELETE MARKER IF MORE TAN ONE CLIP IS SELECTED....";
2120         return;
2121     }
2122     AbstractClipItem *item = (AbstractClipItem *)itemList.at(0);
2123     if (item->type() != AVWIDGET) {
2124         emit displayMessage(i18n("No clip selected"), ErrorMessage);
2125         return;
2126     }
2127
2128     ClipItem *clip = static_cast <ClipItem *>(item);
2129     QList <CommentedTime> markers = clip->baseClip()->commentedSnapMarkers();
2130
2131     if (markers.isEmpty()) {
2132         emit displayMessage(i18n("Clip has no markers"), ErrorMessage);
2133         return;
2134     }
2135     QString id = clip->baseClip()->getId();
2136     QUndoCommand *deleteMarkers = new QUndoCommand();
2137     deleteMarkers->setText("Delete clip markers");
2138
2139     for (int i = 0; i < markers.size(); i++) {
2140         new AddMarkerCommand(this, markers.at(i).comment(), QString(), id, markers.at(i).time(), true, deleteMarkers);
2141     }
2142     m_commandStack->push(deleteMarkers);
2143 }
2144
2145 void CustomTrackView::slotEditClipMarker() {
2146     QList<QGraphicsItem *> itemList = scene()->selectedItems();
2147     if (itemList.count() != 1) {
2148         emit displayMessage(i18n("Cannot edit marker if more than one clip is selected"), ErrorMessage);
2149         kDebug() << "// CANNOT DELETE MARKER IF MORE TAN ONE CLIP IS SELECTED....";
2150         return;
2151     }
2152     AbstractClipItem *item = (AbstractClipItem *)itemList.at(0);
2153     if (item->type() != AVWIDGET) {
2154         emit displayMessage(i18n("No clip at cursor time"), ErrorMessage);
2155         return;
2156     }
2157     GenTime pos = GenTime(m_cursorPos, m_document->fps());
2158     if (item->startPos() > pos || item->endPos() < pos) {
2159         emit displayMessage(i18n("No selected clip at cursor time"), ErrorMessage);
2160         return;
2161     }
2162     ClipItem *clip = (ClipItem *) item;
2163     QString id = clip->baseClip()->getId();
2164     GenTime position = pos - item->startPos() + item->cropStart();
2165     QString oldcomment = clip->baseClip()->markerComment(position);
2166     if (oldcomment.isEmpty()) {
2167         emit displayMessage(i18n("No marker found at cursor time"), ErrorMessage);
2168         return;
2169     }
2170
2171     CommentedTime marker(position, oldcomment);
2172     MarkerDialog d(clip->baseClip(), marker, m_document->timecode(), i18n("Edit Marker"), this);
2173     if (d.exec() == QDialog::Accepted) {
2174         if (d.newMarker().time() == position) {
2175             // marker position was not changed, only text
2176             AddMarkerCommand *command = new AddMarkerCommand(this, oldcomment, d.newMarker().comment(), id, position, true);
2177             m_commandStack->push(command);
2178         } else {
2179             // marker text and position were changed, remove previous marker and add new one
2180             AddMarkerCommand *command1 = new AddMarkerCommand(this, oldcomment, QString(), id, position, true);
2181             AddMarkerCommand *command2 = new AddMarkerCommand(this, QString(), d.newMarker().comment(), id, d.newMarker().time(), true);
2182             m_commandStack->push(command1);
2183             m_commandStack->push(command2);
2184         }
2185     }
2186 }
2187
2188 void CustomTrackView::addMarker(const QString &id, const GenTime &pos, const QString comment) {
2189     DocClipBase *base = m_document->clipManager()->getClipById(id);
2190     if (!comment.isEmpty()) base->addSnapMarker(pos, comment);
2191     else base->deleteSnapMarker(pos);
2192     m_document->setModified(true);
2193     viewport()->update();
2194 }
2195
2196 bool sortGuidesList(const Guide *g1 , const Guide *g2) {
2197     return (*g1).position() < (*g2).position();
2198 }
2199
2200 void CustomTrackView::editGuide(const GenTime oldPos, const GenTime pos, const QString &comment) {
2201     if (oldPos > GenTime() && pos > GenTime()) {
2202         // move guide
2203         for (int i = 0; i < m_guides.count(); i++) {
2204             if (m_guides.at(i)->position() == oldPos) {
2205                 Guide *item = m_guides.at(i);
2206                 item->updateGuide(pos, comment);
2207                 break;
2208             }
2209         }
2210     } else if (pos > GenTime()) addGuide(pos, comment);
2211     else {
2212         // remove guide
2213         bool found = false;
2214         for (int i = 0; i < m_guides.count(); i++) {
2215             if (m_guides.at(i)->position() == oldPos) {
2216                 Guide *item = m_guides.takeAt(i);
2217                 delete item;
2218                 found = true;
2219                 break;
2220             }
2221         }
2222         if (!found) emit displayMessage(i18n("No guide at cursor time"), ErrorMessage);
2223     }
2224     qSort(m_guides.begin(), m_guides.end(), sortGuidesList);
2225     m_document->syncGuides(m_guides);
2226 }
2227
2228 bool CustomTrackView::addGuide(const GenTime pos, const QString &comment) {
2229     for (int i = 0; i < m_guides.count(); i++) {
2230         if (m_guides.at(i)->position() == pos) {
2231             emit displayMessage(i18n("A guide already exists at that position"), ErrorMessage);
2232             return false;
2233         }
2234     }
2235     Guide *g = new Guide(this, pos, comment, m_document->fps(), m_tracksHeight * m_scene->m_tracksList.count());
2236     scene()->addItem(g);
2237     m_guides.append(g);
2238     qSort(m_guides.begin(), m_guides.end(), sortGuidesList);
2239     m_document->syncGuides(m_guides);
2240     return true;
2241 }
2242
2243 void CustomTrackView::slotAddGuide() {
2244     CommentedTime marker(GenTime(m_cursorPos, m_document->fps()), i18n("Guide"));
2245     MarkerDialog d(NULL, marker, m_document->timecode(), i18n("Add Guide"), this);
2246     if (d.exec() != QDialog::Accepted) return;
2247     if (addGuide(d.newMarker().time(), d.newMarker().comment())) {
2248         EditGuideCommand *command = new EditGuideCommand(this, GenTime(), QString(), d.newMarker().time(), d.newMarker().comment(), false);
2249         m_commandStack->push(command);
2250     }
2251 }
2252
2253 void CustomTrackView::slotEditGuide() {
2254     GenTime pos = GenTime(m_cursorPos, m_document->fps());
2255     bool found = false;
2256     for (int i = 0; i < m_guides.count(); i++) {
2257         if (m_guides.at(i)->position() == pos) {
2258             slotEditGuide(m_guides.at(i)->info());
2259             found = true;
2260             break;
2261         }
2262     }
2263     if (!found) emit displayMessage(i18n("No guide at cursor time"), ErrorMessage);
2264 }
2265
2266 void CustomTrackView::slotEditGuide(CommentedTime guide) {
2267     MarkerDialog d(NULL, guide, m_document->timecode(), i18n("Edit Guide"), this);
2268     if (d.exec() == QDialog::Accepted) {
2269         EditGuideCommand *command = new EditGuideCommand(this, guide.time(), guide.comment(), d.newMarker().time(), d.newMarker().comment(), true);
2270         m_commandStack->push(command);
2271     }
2272 }
2273
2274
2275 void CustomTrackView::slotDeleteGuide() {
2276     GenTime pos = GenTime(m_cursorPos, m_document->fps());
2277     bool found = false;
2278     for (int i = 0; i < m_guides.count(); i++) {
2279         if (m_guides.at(i)->position() == pos) {
2280             EditGuideCommand *command = new EditGuideCommand(this, m_guides.at(i)->position(), m_guides.at(i)->label(), GenTime(), QString(), true);
2281             m_commandStack->push(command);
2282             found = true;
2283             break;
2284         }
2285     }
2286     if (!found) emit displayMessage(i18n("No guide at cursor time"), ErrorMessage);
2287 }
2288
2289 void CustomTrackView::slotDeleteAllGuides() {
2290     QUndoCommand *deleteAll = new QUndoCommand();
2291     deleteAll->setText("Delete all guides");
2292     for (int i = 0; i < m_guides.count(); i++) {
2293         EditGuideCommand *command = new EditGuideCommand(this, m_guides.at(i)->position(), m_guides.at(i)->label(), GenTime(), QString(), true, deleteAll);
2294     }
2295     m_commandStack->push(deleteAll);
2296 }
2297
2298 void CustomTrackView::setTool(PROJECTTOOL tool) {
2299     m_tool = tool;
2300 }
2301
2302 void CustomTrackView::setScale(double scaleFactor) {
2303     QMatrix matrix;
2304     matrix = matrix.scale(scaleFactor, 1);
2305     m_scene->setScale(scaleFactor);
2306     //scale(scaleFactor, 1);
2307     m_animationTimer->stop();
2308     if (m_visualTip) {
2309         delete m_visualTip;
2310         m_visualTip = NULL;
2311     }
2312     if (m_animation) {
2313         delete m_animation;
2314         m_animation = NULL;
2315     }
2316     /*double pos = cursorPos() / m_scale;
2317     m_scale = scaleFactor;
2318     m_scene->setScale(m_scale);
2319     int vert = verticalScrollBar()->value();
2320     kDebug() << " HHHHHHHH  SCALING: " << m_scale;
2321     QList<QGraphicsItem *> itemList = items();
2322     for (int i = 0; i < itemList.count(); i++) {
2323         if (itemList.at(i)->type() == AVWIDGET || itemList.at(i)->type() == TRANSITIONWIDGET) {
2324             AbstractClipItem *clip = (AbstractClipItem *)itemList.at(i);
2325             clip->setRect(0, 0, (qreal) clip->duration().frames(m_document->fps()) * m_scale - .5, clip->rect().height());
2326             clip->setPos((qreal) clip->startPos().frames(m_document->fps()) * m_scale, clip->pos().y());
2327         }
2328     }
2329
2330     for (int i = 0; i < m_guides.count(); i++) {
2331         m_guides.at(i)->updatePosition(m_scale);
2332     }
2333
2334     setSceneRect(0, 0, (m_projectDuration + 100) * m_scale, sceneRect().height());
2335     updateCursorPos();*/
2336     setMatrix(matrix);
2337     centerOn(QPointF(cursorPos(), m_tracksHeight));
2338     //verticalScrollBar()->setValue(vert);*/
2339 }
2340
2341 void CustomTrackView::slotRefreshGuides() {
2342     if (KdenliveSettings::showmarkers()) {
2343         kDebug() << "// refresh GUIDES";
2344         for (int i = 0; i < m_guides.count(); i++) {
2345             m_guides.at(i)->update();
2346         }
2347     }
2348 }
2349
2350 void CustomTrackView::drawBackground(QPainter * painter, const QRectF & rect) {
2351     QColor base = palette().button().color();
2352     QRectF r = rect;
2353     r.setWidth(r.width() + 1);
2354     painter->setClipRect(r);
2355     painter->drawLine(r.left(), 0, r.right(), 0);
2356     uint max = m_scene->m_tracksList.count();
2357     for (uint i = 0; i < max;i++) {
2358         /*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)));
2359                else*/
2360         if (m_scene->m_tracksList.at(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)));
2361         painter->drawLine(r.left(), m_tracksHeight * (i + 1), r.right(), m_tracksHeight * (i + 1));
2362     }
2363     int lowerLimit = m_tracksHeight * m_scene->m_tracksList.count() + 1;
2364     if (height() > lowerLimit)
2365         painter->fillRect(QRectF(r.left(), lowerLimit, r.width(), height() - lowerLimit), QBrush(base));
2366 }
2367
2368 bool CustomTrackView::findString(const QString &text) {
2369     QString marker;
2370     for (int i = 0; i < m_searchPoints.size(); ++i) {
2371         marker = m_searchPoints.at(i).comment();
2372         if (marker.contains(text, Qt::CaseInsensitive)) {
2373             setCursorPos(m_searchPoints.at(i).time().frames(m_document->fps()), true);
2374             int vert = verticalScrollBar()->value();
2375             int hor = cursorPos();
2376             ensureVisible(hor, vert + 10, 2, 2, 50, 0);
2377             m_findIndex = i;
2378             return true;
2379         }
2380     }
2381     return false;
2382 }
2383
2384 bool CustomTrackView::findNextString(const QString &text) {
2385     QString marker;
2386     for (int i = m_findIndex + 1; i < m_searchPoints.size(); ++i) {
2387         marker = m_searchPoints.at(i).comment();
2388         if (marker.contains(text, Qt::CaseInsensitive)) {
2389             setCursorPos(m_searchPoints.at(i).time().frames(m_document->fps()), true);
2390             int vert = verticalScrollBar()->value();
2391             int hor = cursorPos();
2392             ensureVisible(hor, vert + 10, 2, 2, 50, 0);
2393             m_findIndex = i;
2394             return true;
2395         }
2396     }
2397     m_findIndex = -1;
2398     return false;
2399 }
2400
2401 void CustomTrackView::initSearchStrings() {
2402     m_searchPoints.clear();
2403     QList<QGraphicsItem *> itemList = items();
2404     for (int i = 0; i < itemList.count(); i++) {
2405         // parse all clip names
2406         if (itemList.at(i)->type() == AVWIDGET) {
2407             ClipItem *item = static_cast <ClipItem *>(itemList.at(i));
2408             GenTime start = item->startPos();
2409             CommentedTime t(start, item->clipName());
2410             m_searchPoints.append(t);
2411             // add all clip markers
2412             QList < CommentedTime > markers = item->commentedSnapMarkers();
2413             m_searchPoints += markers;
2414         }
2415     }
2416
2417     // add guides
2418     for (int i = 0; i < m_guides.count(); i++) {
2419         m_searchPoints.append(m_guides.at(i)->info());
2420     }
2421
2422     qSort(m_searchPoints);
2423 }
2424
2425 void CustomTrackView::clearSearchStrings() {
2426     m_searchPoints.clear();
2427     m_findIndex = 0;
2428 }
2429
2430 void CustomTrackView::copyClip() {
2431     while (m_copiedItems.count() > 0) {
2432         delete m_copiedItems.takeFirst();
2433     }
2434     QList<QGraphicsItem *> itemList = scene()->selectedItems();
2435     if (itemList.count() == 0) {
2436         emit displayMessage(i18n("Select a clip before copying"), ErrorMessage);
2437         return;
2438     }
2439     for (int i = 0; i < itemList.count(); i++) {
2440         if (itemList.at(i)->type() == AVWIDGET) {
2441             ClipItem *dup = static_cast <ClipItem *>(itemList.at(i));
2442             m_copiedItems.append(dup->clone(dup->info()));
2443         } else if (itemList.at(i)->type() == TRANSITIONWIDGET) {
2444             Transition *dup = static_cast <Transition *>(itemList.at(i));
2445             m_copiedItems.append(dup->clone());
2446         }
2447     }
2448 }
2449
2450 bool CustomTrackView::canBePastedTo(ItemInfo info, int type) const {
2451     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));
2452     QList<QGraphicsItem *> collisions = scene()->items(rect, Qt::IntersectsItemBoundingRect);
2453     for (int i = 0; i < collisions.count(); i++) {
2454         if (collisions.at(i)->type() == type) return false;
2455     }
2456     return true;
2457 }
2458
2459 bool CustomTrackView::canBePasted(QList<AbstractClipItem *> items, GenTime offset, int trackOffset) const {
2460     for (int i = 0; i < items.count(); i++) {
2461         ItemInfo info = items.at(i)->info();
2462         info.startPos += offset;
2463         info.endPos += offset;
2464         info.track += trackOffset;
2465         if (!canBePastedTo(info, items.at(i)->type())) return false;
2466     }
2467     return true;
2468 }
2469
2470 bool CustomTrackView::canBeMoved(QList<AbstractClipItem *> items, GenTime offset, int trackOffset) const {
2471     QPainterPath movePath;
2472     movePath.moveTo(0, 0);
2473
2474     for (int i = 0; i < items.count(); i++) {
2475         ItemInfo info = items.at(i)->info();
2476         info.startPos = info.startPos + offset;
2477         info.endPos = info.endPos + offset;
2478         info.track = info.track + trackOffset;
2479         if (info.startPos < GenTime()) {
2480             // No clip should go below 0
2481             return false;
2482         }
2483         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));
2484         movePath.addRect(rect);
2485     }
2486     QList<QGraphicsItem *> collisions = scene()->items(movePath, Qt::IntersectsItemBoundingRect);
2487     for (int i = 0; i < collisions.count(); i++) {
2488         if ((collisions.at(i)->type() == AVWIDGET || collisions.at(i)->type() == TRANSITIONWIDGET) && !items.contains(static_cast <AbstractClipItem *>(collisions.at(i)))) {
2489             kDebug() << "  ////////////   CLIP COLLISION, MOVE NOT ALLOWED";
2490             return false;
2491         }
2492     }
2493     return true;
2494 }
2495
2496 void CustomTrackView::pasteClip() {
2497     if (m_copiedItems.count() == 0) {
2498         emit displayMessage(i18n("No clip copied"), ErrorMessage);
2499         return;
2500     }
2501     QPoint position;
2502     if (m_menuPosition.isNull()) position = mapFromGlobal(QCursor::pos());
2503     else position = m_menuPosition;
2504     GenTime pos = GenTime((int)(mapToScene(position).x()), m_document->fps());
2505     int track = (int)(position.y() / m_tracksHeight);
2506     ItemInfo first = m_copiedItems.at(0)->info();
2507
2508     GenTime offset = pos - first.startPos;
2509     int trackOffset = track - first.track;
2510
2511     if (!canBePasted(m_copiedItems, offset, trackOffset)) {
2512         emit displayMessage(i18n("Cannot paste selected clips"), ErrorMessage);
2513         return;
2514     }
2515     QUndoCommand *pasteClips = new QUndoCommand();
2516     pasteClips->setText("Paste clips");
2517
2518     for (int i = 0; i < m_copiedItems.count(); i++) {
2519         // parse all clip names
2520         if (m_copiedItems.at(i) && m_copiedItems.at(i)->type() == AVWIDGET) {
2521             ClipItem *clip = static_cast <ClipItem *>(m_copiedItems.at(i));
2522             ItemInfo info;
2523             info.startPos = clip->startPos() + offset;
2524             info.endPos = clip->endPos() + offset;
2525             info.cropStart = clip->cropStart();
2526             info.track = clip->track() + trackOffset;
2527             if (canBePastedTo(info, AVWIDGET)) {
2528                 new AddTimelineClipCommand(this, clip->xml(), clip->clipProducer(), info, clip->effectList(), true, false, pasteClips);
2529             } else emit displayMessage(i18n("Cannot paste clip to selected place"), ErrorMessage);
2530         } else if (m_copiedItems.at(i) && m_copiedItems.at(i)->type() == TRANSITIONWIDGET) {
2531             Transition *tr = static_cast <Transition *>(m_copiedItems.at(i));
2532             ItemInfo info;
2533             info.startPos = tr->startPos() + offset;
2534             info.endPos = tr->endPos() + offset;
2535             info.track = tr->track() + trackOffset;
2536             if (canBePastedTo(info, TRANSITIONWIDGET)) {
2537                 new AddTransitionCommand(this, info, tr->transitionEndTrack() + trackOffset, tr->toXML(), false, true, pasteClips);
2538             } else emit displayMessage(i18n("Cannot paste transition to selected place"), ErrorMessage);
2539         }
2540     }
2541     m_commandStack->push(pasteClips);
2542 }
2543
2544 void CustomTrackView::pasteClipEffects() {
2545     if (m_copiedItems.count() != 1 || m_copiedItems.at(0)->type() != AVWIDGET) {
2546         emit displayMessage(i18n("You must copy exactly one clip before pasting effects"), ErrorMessage);
2547         return;
2548     }
2549     ClipItem *clip = static_cast < ClipItem *>(m_copiedItems.at(0));
2550     EffectsList effects = clip->effectList();
2551
2552     QUndoCommand *paste = new QUndoCommand();
2553     paste->setText("Paste effects");
2554
2555     QList<QGraphicsItem *> clips = scene()->selectedItems();
2556     for (int i = 0; i < clips.count(); ++i) {
2557         if (clips.at(i)->type() == AVWIDGET) {
2558             ClipItem *item = static_cast < ClipItem *>(clips.at(i));
2559             for (int i = 0; i < clip->effectsCount(); i++) {
2560                 new AddEffectCommand(this, m_scene->m_tracksList.count() - item->track(), item->startPos(), clip->effectAt(i), true, paste);
2561             }
2562         }
2563     }
2564     m_commandStack->push(paste);
2565 }
2566
2567
2568 ClipItem *CustomTrackView::getClipUnderCursor() const {
2569     QRectF rect((double) m_cursorPos, 0.0, 1.0, (double)(m_tracksHeight * m_scene->m_tracksList.count()));
2570     QList<QGraphicsItem *> collisions = scene()->items(rect, Qt::IntersectsItemBoundingRect);
2571     for (int i = 0; i < collisions.count(); i++) {
2572         if (collisions.at(i)->type() == AVWIDGET) {
2573             return static_cast < ClipItem *>(collisions.at(i));
2574         }
2575     }
2576     return NULL;
2577 }
2578
2579 ClipItem *CustomTrackView::getMainActiveClip() const {
2580     QList<QGraphicsItem *> clips = scene()->selectedItems();
2581     if (clips.isEmpty()) {
2582         return getClipUnderCursor();
2583     } else {
2584         ClipItem *item = NULL;
2585         for (int i = 0; i < clips.count(); ++i) {
2586             if (clips.at(i)->type() == AVWIDGET)
2587                 item = static_cast < ClipItem *>(clips.at(i));
2588             if (item->startPos().frames(m_document->fps()) <= m_cursorPos && item->endPos().frames(m_document->fps()) >= m_cursorPos) break;
2589         }
2590         if (item) return item;
2591     }
2592     return NULL;
2593 }
2594
2595 ClipItem *CustomTrackView::getActiveClipUnderCursor() const {
2596     QList<QGraphicsItem *> clips = scene()->selectedItems();
2597     if (clips.isEmpty()) {
2598         return getClipUnderCursor();
2599     } else {
2600         ClipItem *item;
2601         // remove all items in the list that are not clips
2602         for (int i = 0; i < clips.count();) {
2603             if (clips.at(i)->type() != AVWIDGET) clips.removeAt(i);
2604             else i++;
2605         }
2606         if (clips.count() == 1) return static_cast < ClipItem *>(clips.at(0));
2607         for (int i = 0; i < clips.count(); ++i) {
2608             if (clips.at(i)->type() == AVWIDGET)
2609                 item = static_cast < ClipItem *>(clips.at(i));
2610             if (item->startPos().frames(m_document->fps()) <= m_cursorPos && item->endPos().frames(m_document->fps()) >= m_cursorPos) return item;
2611         }
2612     }
2613     return NULL;
2614 }
2615
2616 void CustomTrackView::setInPoint() {
2617     ClipItem *clip = getActiveClipUnderCursor();
2618     if (clip == NULL) {
2619         emit displayMessage(i18n("You must select one clip for this action"), ErrorMessage);
2620         return;
2621     }
2622     ItemInfo startInfo = clip->info();
2623     ItemInfo endInfo = clip->info();
2624     endInfo.startPos = GenTime(m_cursorPos, m_document->fps());
2625     ResizeClipCommand *command = new ResizeClipCommand(this, startInfo, endInfo, true);
2626     m_commandStack->push(command);
2627 }
2628
2629 void CustomTrackView::setOutPoint() {
2630     ClipItem *clip = getActiveClipUnderCursor();
2631     if (clip == NULL) {
2632         emit displayMessage(i18n("You must select one clip for this action"), ErrorMessage);
2633         return;
2634     }
2635     ItemInfo startInfo = clip->info();
2636     ItemInfo endInfo = clip->info();
2637     endInfo.endPos = GenTime(m_cursorPos, m_document->fps());
2638     ResizeClipCommand *command = new ResizeClipCommand(this, startInfo, endInfo, true);
2639     m_commandStack->push(command);
2640 }
2641
2642 void CustomTrackView::slotUpdateAllThumbs() {
2643     QList<QGraphicsItem *> itemList = items();
2644     ClipItem *item;
2645     Transition *transitionitem;
2646     for (int i = 0; i < itemList.count(); i++) {
2647         if (itemList.at(i)->type() == AVWIDGET) {
2648             item = static_cast <ClipItem *>(itemList.at(i));
2649             item->refreshClip();
2650             qApp->processEvents();
2651         }
2652     }
2653 }
2654
2655 #include "customtrackview.moc"