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