]> git.sesse.net Git - kdenlive/blob - src/customtrackview.cpp
By default, transitions are now "automatic". So when you move or resize a clip, the...
[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     m_cursorLine->setLine(m_cursorLine->line().x1(), 0, m_cursorLine->line().x1(), m_tracksHeight * m_document->tracksCount());
1383     setSceneRect(0, 0, sceneRect().width(), m_tracksHeight * m_document->tracksCount());
1384     verticalScrollBar()->setMaximum(m_tracksHeight * m_document->tracksCount());
1385     QTimer::singleShot(300, this, SIGNAL(trackHeightChanged()));
1386
1387     //setFixedHeight(50 * m_tracksCount);
1388 }
1389
1390 void CustomTrackView::removeTrack(int ix) {
1391     // Delete track in MLT playlist
1392     m_document->renderer()->mltDeleteTrack(m_document->tracksCount() - ix);
1393     m_document->deleteTrack(m_document->tracksCount() - ix - 1);
1394
1395     double startY = ix * m_tracksHeight + 1 + m_tracksHeight / 2;
1396     QRectF r(0, startY, sceneRect().width(), sceneRect().height() - startY);
1397     QList<QGraphicsItem *> selection = m_scene->items(r);
1398
1399     resetSelectionGroup();
1400
1401     m_selectionGroup = new AbstractGroupItem(m_document->fps());
1402     scene()->addItem(m_selectionGroup);
1403     for (int i = 0; i < selection.count(); i++) {
1404         if (selection.at(i)->type() == AVWIDGET || selection.at(i)->type() == TRANSITIONWIDGET)
1405             m_selectionGroup->addToGroup(selection.at(i));
1406         selection.at(i)->setFlags(QGraphicsItem::ItemIsSelectable);
1407     }
1408     // Move graphic items
1409     qreal ydiff = 0 - (int) m_tracksHeight;
1410     m_selectionGroup->translate(0, ydiff);
1411
1412     // adjust track number
1413     QList<QGraphicsItem *> children = m_selectionGroup->childItems();
1414     //kDebug() << "// FOUND CLIPS TO MOVE: " << children.count();
1415     for (int i = 0; i < children.count(); i++) {
1416         if (children.at(i)->type() == AVWIDGET) {
1417             ClipItem *clip = static_cast <ClipItem *>(children.at(i));
1418             clip->updateItem();
1419             ItemInfo clipinfo = clip->info();
1420             kDebug() << "// CLIP TRK IS: " << clipinfo.track;
1421             // We add a move clip command so that we get the correct producer for new track number
1422             if (clip->clipType() == AV || clip->clipType() == AUDIO)
1423                 m_document->renderer()->mltUpdateClipProducer((int)(m_document->tracksCount() - clipinfo.track), clipinfo.startPos.frames(m_document->fps()), clip->baseClip()->producer(clipinfo.track));
1424         } else if (children.at(i)->type() == TRANSITIONWIDGET) {
1425             Transition *tr = static_cast <Transition *>(children.at(i));
1426             tr->updateItem();
1427             int track = tr->transitionEndTrack();
1428             if (track >= ix) {
1429                 ItemInfo clipinfo = tr->info();
1430                 tr->updateTransitionEndTrack(getPreviousVideoTrack(clipinfo.track));
1431             }
1432         }
1433     }
1434     resetSelectionGroup(false);
1435
1436     m_cursorLine->setLine(m_cursorLine->line().x1(), 0, m_cursorLine->line().x1(), m_tracksHeight * m_document->tracksCount());
1437     setSceneRect(0, 0, sceneRect().width(), m_tracksHeight * m_document->tracksCount());
1438     verticalScrollBar()->setMaximum(m_tracksHeight * m_document->tracksCount());
1439     QTimer::singleShot(300, this, SIGNAL(trackHeightChanged()));
1440     viewport()->update();
1441 }
1442
1443 void CustomTrackView::changeTrack(int ix, TrackInfo type) {
1444     int tracknumber = m_document->tracksCount() - ix;
1445     m_document->setTrackType(tracknumber - 1, type);
1446     m_document->renderer()->mltChangeTrackState(tracknumber, m_document->trackInfoAt(tracknumber - 1).isMute, m_document->trackInfoAt(tracknumber - 1).isBlind);
1447     QTimer::singleShot(300, this, SIGNAL(trackHeightChanged()));
1448     viewport()->update();
1449 }
1450
1451
1452 void CustomTrackView::slotSwitchTrackAudio(int ix) {
1453     /*for (int i = 0; i < m_document->tracksCount(); i++)
1454         kDebug() << "TRK " << i << " STATE: " << m_document->trackInfoAt(i).isMute << m_document->trackInfoAt(i).isBlind;*/
1455
1456     int tracknumber = m_document->tracksCount() - ix;
1457
1458     m_document->switchTrackAudio(tracknumber - 1, !m_document->trackInfoAt(tracknumber - 1).isMute);
1459     kDebug() << "NEXT TRK STATE: " << m_document->trackInfoAt(tracknumber - 1).isMute << m_document->trackInfoAt(tracknumber - 1).isBlind;
1460     m_document->renderer()->mltChangeTrackState(tracknumber, m_document->trackInfoAt(tracknumber - 1).isMute, m_document->trackInfoAt(tracknumber - 1).isBlind);
1461     m_document->setModified(true);
1462 }
1463
1464 void CustomTrackView::slotSwitchTrackVideo(int ix) {
1465     int tracknumber = m_document->tracksCount() - ix;
1466     m_document->switchTrackVideo(tracknumber - 1, !m_document->trackInfoAt(tracknumber - 1).isBlind);
1467     m_document->renderer()->mltChangeTrackState(tracknumber, m_document->trackInfoAt(tracknumber - 1).isMute, m_document->trackInfoAt(tracknumber - 1).isBlind);
1468     m_document->setModified(true);
1469 }
1470
1471 void CustomTrackView::slotRemoveSpace() {
1472     GenTime pos;
1473     int track = 0;
1474     if (m_menuPosition.isNull()) {
1475         pos = GenTime(cursorPos(), m_document->fps());
1476         bool ok;
1477         track = QInputDialog::getInteger(this, i18n("Remove Space"), i18n("Track"), 0, 0, m_document->tracksCount() - 1, 1, &ok);
1478         if (!ok) return;
1479     } else {
1480         pos = GenTime((int)(mapToScene(m_menuPosition).x()), m_document->fps());
1481         track = (int)(mapToScene(m_menuPosition).y() / m_tracksHeight);
1482     }
1483     ClipItem *item = getClipItemAt(pos, track);
1484     if (item) {
1485         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);
1486         return;
1487     }
1488     int length = m_document->renderer()->mltGetSpaceLength(pos, m_document->tracksCount() - track);
1489     //kDebug() << "// GOT LENGT; " << length;
1490     if (length <= 0) {
1491         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);
1492         return;
1493     }
1494     InsertSpaceCommand *command = new InsertSpaceCommand(this, pos, track, GenTime(-length, m_document->fps()), true);
1495     m_commandStack->push(command);
1496 }
1497
1498 void CustomTrackView::slotInsertSpace() {
1499     GenTime pos;
1500     int track = 0;
1501     if (m_menuPosition.isNull()) {
1502         pos = GenTime(cursorPos(), m_document->fps());
1503     } else {
1504         pos = GenTime((int)(mapToScene(m_menuPosition).x()), m_document->fps());
1505         track = (int)(mapToScene(m_menuPosition).y() / m_tracksHeight) + 1;
1506     }
1507     SpacerDialog d(GenTime(65, m_document->fps()), m_document->timecode(), track, m_document->tracksCount(), this);
1508     if (d.exec() != QDialog::Accepted) return;
1509     GenTime spaceDuration = d.selectedDuration();
1510     track = d.selectedTrack();
1511     ClipItem *item = getClipItemAt(pos, track);
1512     if (item) pos = item->startPos();
1513
1514     InsertSpaceCommand *command = new InsertSpaceCommand(this, pos, track, spaceDuration, true);
1515     m_commandStack->push(command);
1516 }
1517
1518 void CustomTrackView::insertSpace(const GenTime &pos, int track, const GenTime duration) {
1519     int diff = duration.frames(m_document->fps());
1520     QList<QGraphicsItem *> itemList;
1521     if (track == -1) itemList = scene()->items(pos.frames(m_document->fps()) , 1, sceneRect().width() - pos.frames(m_document->fps()), sceneRect().height());
1522     else itemList = scene()->items(pos.frames(m_document->fps()) , track * m_tracksHeight + 1, sceneRect().width() - pos.frames(m_document->fps()), m_tracksHeight - 2);
1523     resetSelectionGroup();
1524     m_selectionGroup = new AbstractGroupItem(m_document->fps());
1525     scene()->addItem(m_selectionGroup);
1526     for (int i = 0; i < itemList.count(); i++) {
1527         if (itemList.at(i)->type() == AVWIDGET || itemList.at(i)->type() == TRANSITIONWIDGET) {
1528             m_selectionGroup->addToGroup(itemList.at(i));
1529             itemList.at(i)->setFlags(QGraphicsItem::ItemIsSelectable);
1530         }
1531     }
1532
1533     m_selectionGroup->translate(diff, 0);
1534     resetSelectionGroup(false);
1535     if (track != -1) track = m_document->tracksCount() - track;
1536     m_document->renderer()->mltInsertSpace(pos, track, duration);
1537 }
1538
1539 void CustomTrackView::deleteClip(const QString &clipId) {
1540     QList<QGraphicsItem *> itemList = items();
1541     for (int i = 0; i < itemList.count(); i++) {
1542         if (itemList.at(i)->type() == AVWIDGET) {
1543             ClipItem *item = (ClipItem *)itemList.at(i);
1544             if (item->clipProducer() == clipId) {
1545                 AddTimelineClipCommand *command = new AddTimelineClipCommand(this, item->xml(), item->clipProducer(), item->info(), item->effectList(), true, true);
1546                 m_commandStack->push(command);
1547                 //delete item;
1548             }
1549         }
1550     }
1551 }
1552
1553 void CustomTrackView::setCursorPos(int pos, bool seek) {
1554     emit cursorMoved((int)(m_cursorPos), (int)(pos));
1555     m_cursorPos = pos;
1556     m_cursorLine->setPos(pos, 0);
1557     if (seek) m_document->renderer()->seek(GenTime(pos, m_document->fps()));
1558     else if (m_autoScroll) checkScrolling();
1559 }
1560
1561 void CustomTrackView::updateCursorPos() {
1562     m_cursorLine->setPos(m_cursorPos, 0);
1563 }
1564
1565 int CustomTrackView::cursorPos() {
1566     return (int)(m_cursorPos);
1567 }
1568
1569 void CustomTrackView::moveCursorPos(int delta) {
1570     if (m_cursorPos + delta < 0) delta = 0 - m_cursorPos;
1571     emit cursorMoved((int)(m_cursorPos), (int)((m_cursorPos + delta)));
1572     m_cursorPos += delta;
1573     m_cursorLine->setPos(m_cursorPos, 0);
1574     m_document->renderer()->seek(GenTime(m_cursorPos, m_document->fps()));
1575     //if (m_autoScroll && m_scale < 50) checkScrolling();
1576 }
1577
1578 void CustomTrackView::checkScrolling() {
1579     int vert = verticalScrollBar()->value();
1580     int hor = cursorPos();
1581     ensureVisible(hor, vert + 10, 2, 2, 50, 0);
1582     //centerOn(QPointF(cursorPos(), m_tracksHeight));
1583     /*QRect rectInView = viewport()->rect();
1584     int delta = rectInView.width() / 3;
1585     int max = rectInView.right() + horizontalScrollBar()->value() - delta;
1586     //kDebug() << "CURSOR POS: "<<m_cursorPos<< "Scale: "<<m_scale;
1587     if (m_cursorPos * m_scale >= max) horizontalScrollBar()->setValue((int)(horizontalScrollBar()->value() + 1 + m_scale));*/
1588 }
1589
1590 void CustomTrackView::mouseReleaseEvent(QMouseEvent * event) {
1591     if (m_moveOpMode == SEEK) m_moveOpMode = NONE;
1592     QGraphicsView::mouseReleaseEvent(event);
1593     if (m_scrollTimer.isActive()) m_scrollTimer.stop();
1594     if (event->button() == Qt::MidButton) {
1595         return;
1596     }
1597     setDragMode(QGraphicsView::NoDrag);
1598     if (m_operationMode == MOVEGUIDE) {
1599         setCursor(Qt::ArrowCursor);
1600         m_operationMode = NONE;
1601         m_dragGuide->setFlag(QGraphicsItem::ItemIsMovable, false);
1602         EditGuideCommand *command = new EditGuideCommand(this, m_dragGuide->position(), m_dragGuide->label(), GenTime(m_dragGuide->pos().x(), m_document->fps()), m_dragGuide->label(), false);
1603         m_commandStack->push(command);
1604         m_dragGuide->updateGuide(GenTime(m_dragGuide->pos().x(), m_document->fps()));
1605         m_dragGuide = NULL;
1606         m_dragItem = NULL;
1607         return;
1608     } else if (m_operationMode == SPACER) {
1609         int endClick = (int)(mapToScene(event->pos()).x() + 0.5);
1610         int mappedClick = (int)(mapToScene(m_clickEvent).x() + 0.5);
1611         int track = (int)(mapToScene(m_clickEvent).y() / m_tracksHeight);
1612         if (m_selectionGroup->sceneBoundingRect().height() > m_tracksHeight) {
1613             // We are moving all tracks
1614             track = -1;
1615         }
1616         ClipItem *item = getClipItemAt(mappedClick, track);
1617         if (item) mappedClick = item->startPos().frames(m_document->fps());
1618         int diff = m_selectionGroup->pos().x() - m_spacerStart;//endClick - mappedClick;
1619         kDebug() << "// MOVING SPACER DIFF:" << diff;
1620         if (diff < 0) mappedClick += diff;
1621         InsertSpaceCommand *command = new InsertSpaceCommand(this, GenTime(mappedClick, m_document->fps()), track, GenTime(diff, m_document->fps()), false);
1622         m_commandStack->push(command);
1623         if (track != -1) track = m_document->tracksCount() - track;
1624         m_document->renderer()->mltInsertSpace(GenTime(mappedClick, m_document->fps()), track, GenTime(diff, m_document->fps()));
1625         resetSelectionGroup(false);
1626         m_operationMode = NONE;
1627     } else if (m_operationMode == RUBBERSELECTION) {
1628         resetSelectionGroup();
1629         groupSelectedItems();
1630         m_operationMode = NONE;
1631     }
1632
1633     if (m_dragItem == NULL && m_selectionGroup == NULL) {
1634         emit transitionItemSelected(NULL);
1635         return;
1636     }
1637     ItemInfo info;
1638     if (m_dragItem) info = m_dragItem->info();
1639
1640     if (m_operationMode == MOVE) {
1641         setCursor(Qt::OpenHandCursor);
1642
1643         if (m_selectionGroup == NULL) {
1644             // we are moving one clip, easy
1645             if (m_dragItem->type() == AVWIDGET && (m_dragItemInfo.startPos != info.startPos || m_dragItemInfo.track != info.track)) {
1646                 ClipItem *item = static_cast <ClipItem *>(m_dragItem);
1647                 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));
1648                 if (success) {
1649                     QUndoCommand *moveCommand = new QUndoCommand();
1650                     moveCommand->setText(i18n("Move clip"));
1651                     new MoveClipCommand(this, m_dragItemInfo, info, false, moveCommand);
1652                     // Also move automatic transitions (on lower track)
1653                     Transition *tr = getTransitionItemAtStart(m_dragItemInfo.startPos, m_dragItemInfo.track);
1654                     if (tr && tr->isAutomatic()) {
1655                         tr->updateTransitionEndTrack(getPreviousVideoTrack(info.track));
1656                         ItemInfo trInfo = tr->info();
1657                         ItemInfo newTrInfo = trInfo;
1658                         newTrInfo.startPos = m_dragItem->startPos();
1659                         if (m_dragItemInfo.track == info.track && !item->baseClip()->isTransparent() && !getClipItemAtEnd(newTrInfo.endPos, m_document->tracksCount() - tr->transitionEndTrack())) {
1660                             // transition end should be adjusted to clip on lower track
1661                             newTrInfo.endPos = newTrInfo.endPos + (newTrInfo.startPos - trInfo.startPos);
1662                         }
1663                         new MoveTransitionCommand(this, trInfo, newTrInfo, true, moveCommand);
1664                     }
1665                     if (tr == NULL || tr->endPos() < item->endPos()) {
1666                         // Check if there is a transition at clip end
1667                         tr = getTransitionItemAtEnd(m_dragItemInfo.endPos, m_dragItemInfo.track);
1668                         if (tr && tr->isAutomatic()) {
1669                             tr->updateTransitionEndTrack(getPreviousVideoTrack(info.track));
1670                             ItemInfo trInfo = tr->info();
1671                             ItemInfo newTrInfo = trInfo;
1672                             newTrInfo.endPos = m_dragItem->endPos();
1673                             if (m_dragItemInfo.track == info.track && !item->baseClip()->isTransparent() && !getClipItemAtStart(trInfo.startPos, m_document->tracksCount() - tr->transitionEndTrack())) {
1674                                 // transition end should be moved
1675                                 newTrInfo.startPos = newTrInfo.startPos + (newTrInfo.endPos - trInfo.endPos);
1676                             }
1677                             new MoveTransitionCommand(this, trInfo, newTrInfo, true, moveCommand);
1678                         }
1679                     }
1680                     // Also move automatic transitions (on upper track)
1681                     tr = getTransitionItemAtStart(m_dragItemInfo.startPos, m_dragItemInfo.track - 1);
1682                     if (m_dragItemInfo.track == info.track && tr && tr->isAutomatic() && (m_document->tracksCount() - tr->transitionEndTrack()) == m_dragItemInfo.track) {
1683                         ItemInfo trInfo = tr->info();
1684                         ItemInfo newTrInfo = trInfo;
1685                         newTrInfo.startPos = m_dragItem->startPos();
1686                         ClipItem * upperClip = getClipItemAt(m_dragItemInfo.startPos, m_dragItemInfo.track - 1);
1687                         if ((!upperClip || !upperClip->baseClip()->isTransparent()) && !getClipItemAtEnd(newTrInfo.endPos, tr->track())) {
1688                             // transition end should be adjusted to clip on upper track
1689                             newTrInfo.endPos = newTrInfo.endPos + (newTrInfo.startPos - trInfo.startPos);
1690                         }
1691                         new MoveTransitionCommand(this, trInfo, newTrInfo, true, moveCommand);
1692                     }
1693                     if (m_dragItemInfo.track == info.track && (tr == NULL || tr->endPos() < item->endPos())) {
1694                         // Check if there is a transition at clip end
1695                         tr = getTransitionItemAtEnd(m_dragItemInfo.endPos, m_dragItemInfo.track - 1);
1696                         if (tr && tr->isAutomatic() && (m_document->tracksCount() - tr->transitionEndTrack()) == m_dragItemInfo.track) {
1697                             ItemInfo trInfo = tr->info();
1698                             ItemInfo newTrInfo = trInfo;
1699                             newTrInfo.endPos = m_dragItem->endPos();
1700                             ClipItem * upperClip = getClipItemAt(m_dragItemInfo.startPos, m_dragItemInfo.track - 1);
1701                             if ((!upperClip || !upperClip->baseClip()->isTransparent()) && !getClipItemAtStart(trInfo.startPos, tr->track())) {
1702                                 // transition start should be moved
1703                                 newTrInfo.startPos = newTrInfo.startPos + (newTrInfo.endPos - trInfo.endPos);
1704                             }
1705                             new MoveTransitionCommand(this, trInfo, newTrInfo, true, moveCommand);
1706                         }
1707                     }
1708                     m_commandStack->push(moveCommand);
1709                 } else {
1710                     // undo last move and emit error message
1711                     MoveClipCommand *command = new MoveClipCommand(this, info, m_dragItemInfo, true);
1712                     m_commandStack->push(command);
1713                     emit displayMessage(i18n("Cannot move clip to position %1", m_document->timecode().getTimecodeFromFrames(m_dragItemInfo.startPos.frames(m_document->fps()))), ErrorMessage);
1714                 }
1715             }
1716             if (m_dragItem->type() == TRANSITIONWIDGET && (m_dragItemInfo.startPos != info.startPos || m_dragItemInfo.track != info.track)) {
1717                 MoveTransitionCommand *command = new MoveTransitionCommand(this, m_dragItemInfo, info, false);
1718                 m_commandStack->push(command);
1719                 Transition *transition = (Transition *) m_dragItem;
1720                 transition->updateTransitionEndTrack(getPreviousVideoTrack(m_dragItem->track()));
1721                 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);
1722             }
1723         } else {
1724             // Moving several clips. We need to delete them and readd them to new position,
1725             // or they might overlap each other during the move
1726
1727             QList<QGraphicsItem *> items = m_selectionGroup->childItems();
1728
1729             QList<ItemInfo> clipsToMove = QList<ItemInfo> ();
1730             QList<ItemInfo> transitionsToMove = QList<ItemInfo> ();
1731
1732             GenTime timeOffset = GenTime(m_selectionGroup->scenePos().x(), m_document->fps()) - m_selectionGroupInfo.startPos;
1733             const int trackOffset = m_selectionGroup->track() - m_selectionGroupInfo.track;
1734             if (timeOffset != GenTime() || trackOffset != 0) {
1735                 QUndoCommand *moveClips = new QUndoCommand();
1736                 moveClips->setText(i18n("Move group"));
1737                 // remove items in MLT playlist
1738                 for (int i = 0; i < items.count(); i++) {
1739                     AbstractClipItem *item = static_cast <AbstractClipItem *>(items.at(i));
1740                     ItemInfo info = item->info();
1741                     if (item->type() == AVWIDGET) {
1742                         if (m_document->renderer()->mltRemoveClip(m_document->tracksCount() - info.track, info.startPos) == false) {
1743                             // error, clip cannot be removed from playlist
1744                             emit displayMessage(i18n("Error removing clip at %1 on track %2", m_document->timecode().getTimecodeFromFrames(info.startPos.frames(m_document->fps())), info.track), ErrorMessage);
1745                         } else {
1746                             clipsToMove.append(info);
1747                         }
1748                     } else {
1749                         transitionsToMove.append(info);
1750                         Transition *tr = static_cast <Transition*>(item);
1751                         m_document->renderer()->mltDeleteTransition(tr->transitionTag(), tr->transitionEndTrack(), m_document->tracksCount() - info.track, info.startPos, info.endPos, tr->toXML());
1752                     }
1753                 }
1754
1755                 for (int i = 0; i < items.count(); i++) {
1756                     // re-add items in correct place
1757                     AbstractClipItem *item = static_cast <AbstractClipItem *>(items.at(i));
1758                     item->updateItem();
1759                     ItemInfo info = item->info();
1760                     if (item->type() == AVWIDGET) {
1761                         ClipItem *clip = static_cast <ClipItem*>(item);
1762                         info.track = m_document->tracksCount() - info.track;
1763                         m_document->renderer()->mltInsertClip(info, clip->xml(), clip->baseClip()->producer(info.track));
1764                     } else {
1765                         Transition *tr = static_cast <Transition*>(item);
1766                         int newTrack = tr->transitionEndTrack();
1767                         if (!tr->forcedTrack()) {
1768                             newTrack += trackOffset;
1769                             if (newTrack < 0 || newTrack > m_document->tracksCount()) newTrack = getPreviousVideoTrack(info.track);
1770                         }
1771                         tr->updateTransitionEndTrack(newTrack);
1772                         m_document->renderer()->mltAddTransition(tr->transitionTag(), newTrack, m_document->tracksCount() - info.track, info.startPos, info.endPos, tr->toXML());
1773                     }
1774                 }
1775
1776                 new MoveGroupCommand(this, clipsToMove, transitionsToMove, timeOffset, trackOffset, false, moveClips);
1777                 m_commandStack->push(moveClips);
1778
1779                 QPointF top = m_selectionGroup->sceneBoundingRect().topLeft();
1780                 //QPointF oldpos = m_selectionGroup->scenePos();
1781                 //kDebug()<<"SELECTION GRP POS: "<<m_selectionGroup->scenePos()<<", TOP: "<<top;
1782                 m_selectionGroup->setPos(top);
1783                 m_selectionGroupInfo.startPos = GenTime(m_selectionGroup->scenePos().x(), m_document->fps());
1784                 m_selectionGroupInfo.track = m_selectionGroup->track();
1785             }
1786         }
1787
1788     } else if (m_operationMode == RESIZESTART && m_dragItem->startPos() != m_dragItemInfo.startPos) {
1789         // resize start
1790         if (m_dragItem->type() == AVWIDGET) {
1791             ItemInfo resizeinfo = m_dragItemInfo;
1792             resizeinfo.track = m_document->tracksCount() - resizeinfo.track;
1793             bool success = m_document->renderer()->mltResizeClipStart(resizeinfo, m_dragItem->startPos() - m_dragItemInfo.startPos);
1794             if (success) {
1795                 QUndoCommand *resizeCommand = new QUndoCommand();
1796                 resizeCommand->setText(i18n("Resize clip"));
1797
1798                 // Check if there is an automatic transition on that clip (lower track)
1799                 Transition *transition = getTransitionItemAtStart(m_dragItemInfo.startPos, m_dragItemInfo.track);
1800                 if (transition && transition->isAutomatic()) {
1801                     ItemInfo trInfo = transition->info();
1802                     ItemInfo newTrInfo = trInfo;
1803                     newTrInfo.startPos = m_dragItem->startPos();
1804                     new MoveTransitionCommand(this, trInfo, newTrInfo, true, resizeCommand);
1805                 }
1806                 // Check if there is an automatic transition on that clip (upper track)
1807                 transition = getTransitionItemAtStart(m_dragItemInfo.startPos, m_dragItemInfo.track - 1);
1808                 if (transition && transition->isAutomatic() && (m_document->tracksCount() - transition->transitionEndTrack()) == m_dragItemInfo.track) {
1809                     ItemInfo trInfo = transition->info();
1810                     ItemInfo newTrInfo = trInfo;
1811                     newTrInfo.startPos = m_dragItem->startPos();
1812                     new MoveTransitionCommand(this, trInfo, newTrInfo, true, resizeCommand);
1813                 }
1814                 updateClipFade(static_cast <ClipItem *>(m_dragItem));
1815                 new ResizeClipCommand(this, m_dragItemInfo, info, false, resizeCommand);
1816                 m_commandStack->push(resizeCommand);
1817             } else {
1818                 m_dragItem->resizeStart((int) m_dragItemInfo.startPos.frames(m_document->fps()));
1819                 emit displayMessage(i18n("Error when resizing clip"), ErrorMessage);
1820             }
1821         } else if (m_dragItem->type() == TRANSITIONWIDGET) {
1822             MoveTransitionCommand *command = new MoveTransitionCommand(this, m_dragItemInfo, info, false);
1823             m_commandStack->push(command);
1824             Transition *transition = static_cast <Transition *>(m_dragItem);
1825             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);
1826         }
1827
1828         //m_document->renderer()->doRefresh();
1829     } else if (m_operationMode == RESIZEEND && m_dragItem->endPos() != m_dragItemInfo.endPos) {
1830         // resize end
1831         if (m_dragItem->type() == AVWIDGET) {
1832             ItemInfo resizeinfo = info;
1833             resizeinfo.track = m_document->tracksCount() - resizeinfo.track;
1834             bool success = m_document->renderer()->mltResizeClipEnd(resizeinfo, resizeinfo.endPos - resizeinfo.startPos);
1835             if (success) {
1836                 QUndoCommand *resizeCommand = new QUndoCommand();
1837                 resizeCommand->setText(i18n("Resize clip"));
1838
1839                 // Check if there is an automatic transition on that clip (lower track)
1840                 Transition *tr = getTransitionItemAtEnd(m_dragItemInfo.endPos, m_dragItemInfo.track);
1841                 if (tr && tr->isAutomatic()) {
1842                     ItemInfo trInfo = tr->info();
1843                     ItemInfo newTrInfo = trInfo;
1844                     newTrInfo.endPos = m_dragItem->endPos();
1845                     if (!static_cast<ClipItem*>(m_dragItem)->baseClip()->isTransparent() && !getClipItemAtStart(trInfo.startPos, m_document->tracksCount() - tr->transitionEndTrack())) {
1846                         // transition start should be moved
1847                         newTrInfo.startPos = newTrInfo.startPos + (newTrInfo.endPos - trInfo.endPos);
1848                     }
1849                     new MoveTransitionCommand(this, trInfo, newTrInfo, true, resizeCommand);
1850                 }
1851
1852                 // Check if there is an automatic transition on that clip (upper track)
1853                 tr = getTransitionItemAtEnd(m_dragItemInfo.endPos, m_dragItemInfo.track - 1);
1854                 if (tr) kDebug() << "TRANS TRK: " << tr->transitionEndTrack() << ", CLP TRK:" << m_dragItemInfo.track << ", CALC: " << m_document->tracksCount() - tr->transitionEndTrack();
1855                 if (tr && tr->isAutomatic() && (m_document->tracksCount() - tr->transitionEndTrack()) == m_dragItemInfo.track) {
1856                     kDebug() << ".............. GOT TRANSITION";
1857                     ItemInfo trInfo = tr->info();
1858                     ItemInfo newTrInfo = trInfo;
1859                     newTrInfo.endPos = m_dragItem->endPos();
1860                     if (!static_cast<ClipItem*>(m_dragItem)->baseClip()->isTransparent() && !getClipItemAtStart(trInfo.startPos, trInfo.track)) {
1861                         // transition start should be moved
1862                         newTrInfo.startPos = newTrInfo.startPos + (newTrInfo.endPos - trInfo.endPos);
1863                     }
1864                     new MoveTransitionCommand(this, trInfo, newTrInfo, true, resizeCommand);
1865                 }
1866
1867                 new ResizeClipCommand(this, m_dragItemInfo, info, false, resizeCommand);
1868                 m_commandStack->push(resizeCommand);
1869                 updateClipFade(static_cast <ClipItem *>(m_dragItem), true);
1870             } else {
1871                 m_dragItem->resizeEnd((int) m_dragItemInfo.endPos.frames(m_document->fps()));
1872                 emit displayMessage(i18n("Error when resizing clip"), ErrorMessage);
1873             }
1874         } else if (m_dragItem->type() == TRANSITIONWIDGET) {
1875             MoveTransitionCommand *command = new MoveTransitionCommand(this, m_dragItemInfo, info, false);
1876             m_commandStack->push(command);
1877             Transition *transition = static_cast <Transition *>(m_dragItem);
1878             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);
1879         }
1880         //m_document->renderer()->doRefresh();
1881     } else if (m_operationMode == FADEIN) {
1882         // resize fade in effect
1883         ClipItem * item = (ClipItem *) m_dragItem;
1884         int ix = item->hasEffect("volume", "fadein");
1885         if (ix != -1) {
1886             QDomElement oldeffect = item->effectAt(ix);
1887             int start = item->cropStart().frames(m_document->fps());
1888             int end = item->fadeIn();
1889             if (end == 0) {
1890                 slotDeleteEffect(item, oldeffect);
1891             } else {
1892                 end += start;
1893                 QDomElement effect = oldeffect.cloneNode().toElement();
1894                 EffectsList::setParameter(oldeffect, "in", QString::number(start));
1895                 EffectsList::setParameter(oldeffect, "out", QString::number(end));
1896                 slotUpdateClipEffect(item, effect, oldeffect, ix);
1897                 emit clipItemSelected(item, ix);
1898             }
1899         } else if (item->fadeIn() != 0) {
1900             QDomElement effect = MainWindow::audioEffects.getEffectByTag("volume", "fadein").cloneNode().toElement();
1901             EffectsList::setParameter(effect, "out", QString::number(item->fadeIn()));
1902             slotAddEffect(effect, m_dragItem->startPos(), m_dragItem->track());
1903         }
1904     } else if (m_operationMode == FADEOUT) {
1905         // resize fade in effect
1906         ClipItem * item = (ClipItem *) m_dragItem;
1907         int ix = item->hasEffect("volume", "fadeout");
1908         if (ix != -1) {
1909             QDomElement oldeffect = item->effectAt(ix);
1910             int end = (item->duration() + item->cropStart()).frames(m_document->fps());
1911             int start = item->fadeOut();
1912             if (start == 0) {
1913                 slotDeleteEffect(item, oldeffect);
1914             } else {
1915                 start = end - start;
1916                 QDomElement effect = oldeffect.cloneNode().toElement();
1917                 EffectsList::setParameter(oldeffect, "in", QString::number(start));
1918                 EffectsList::setParameter(oldeffect, "out", QString::number(end));
1919                 slotUpdateClipEffect(item, effect, oldeffect, ix);
1920                 emit clipItemSelected(item, ix);
1921             }
1922         } else if (item->fadeOut() != 0) {
1923             QDomElement effect = MainWindow::audioEffects.getEffectByTag("volume", "fadeout").cloneNode().toElement();
1924             EffectsList::setParameter(effect, "out", QString::number(item->fadeOut()));
1925             slotAddEffect(effect, m_dragItem->startPos(), m_dragItem->track());
1926         }
1927     } else if (m_operationMode == KEYFRAME) {
1928         // update the MLT effect
1929         ClipItem * item = (ClipItem *) m_dragItem;
1930         QString previous = item->keyframes(item->selectedEffectIndex());
1931         item->updateKeyframeEffect();
1932         QString next = item->keyframes(item->selectedEffectIndex());
1933         EditKeyFrameCommand *command = new EditKeyFrameCommand(this, item->track(), item->startPos(), item->selectedEffectIndex(), previous, next, false);
1934         m_commandStack->push(command);
1935         updateEffect(m_document->tracksCount() - item->track(), item->startPos(), item->selectedEffect(), item->selectedEffectIndex());
1936     }
1937
1938     emit transitionItemSelected((m_dragItem && m_dragItem->type() == TRANSITIONWIDGET) ? static_cast <Transition *>(m_dragItem) : NULL);
1939     m_document->setModified(true);
1940     m_operationMode = NONE;
1941 }
1942
1943 void CustomTrackView::deleteClip(ItemInfo info) {
1944     ClipItem *item = getClipItemAt((int) info.startPos.frames(m_document->fps()) + 1, info.track);
1945
1946     if (!item || m_document->renderer()->mltRemoveClip(m_document->tracksCount() - info.track, info.startPos) == false) {
1947         emit displayMessage(i18n("Error removing clip at %1 on track %2", m_document->timecode().getTimecodeFromFrames(info.startPos.frames(m_document->fps())), info.track), ErrorMessage);
1948         return;
1949     }
1950     if (item->isSelected()) emit clipItemSelected(NULL);
1951     item->baseClip()->removeReference();
1952     m_document->updateClip(item->baseClip()->getId());
1953
1954     if (item->baseClip()->isTransparent()) {
1955         // also remove automatic transition
1956         Transition *tr = getTransitionItemAt((int) info.startPos.frames(m_document->fps()), info.track);
1957         if (tr && tr->isAutomatic()) {
1958             m_document->renderer()->mltDeleteTransition(tr->transitionTag(), tr->transitionEndTrack(), m_document->tracksCount() - info.track, info.startPos, info.endPos, tr->toXML());
1959             scene()->removeItem(tr);
1960             delete tr;
1961         }
1962     }
1963     scene()->removeItem(item);
1964     if (m_dragItem == item) m_dragItem = NULL;
1965     delete item;
1966     m_document->renderer()->doRefresh();
1967 }
1968
1969 void CustomTrackView::deleteSelectedClips() {
1970     QList<QGraphicsItem *> itemList = scene()->selectedItems();
1971     if (itemList.count() == 0) {
1972         emit displayMessage(i18n("Select clip to delete"), ErrorMessage);
1973         return;
1974     }
1975     QUndoCommand *deleteSelected = new QUndoCommand();
1976     deleteSelected->setText(i18n("Delete selected items"));
1977     for (int i = 0; i < itemList.count(); i++) {
1978         if (itemList.at(i)->type() == AVWIDGET) {
1979             ClipItem *item = static_cast <ClipItem *>(itemList.at(i));
1980             new AddTimelineClipCommand(this, item->xml(), item->clipProducer(), item->info(), item->effectList(), true, true, deleteSelected);
1981         } else if (itemList.at(i)->type() == TRANSITIONWIDGET) {
1982             Transition *item = static_cast <Transition *>(itemList.at(i));
1983             ItemInfo info;
1984             info.startPos = item->startPos();
1985             info.endPos = item->endPos();
1986             info.track = item->track();
1987             new AddTransitionCommand(this, info, item->transitionEndTrack(), item->toXML(), true, true, deleteSelected);
1988         }
1989     }
1990     m_commandStack->push(deleteSelected);
1991 }
1992
1993 void CustomTrackView::changeClipSpeed() {
1994     QList<QGraphicsItem *> itemList = scene()->selectedItems();
1995     if (itemList.count() == 0) {
1996         emit displayMessage(i18n("Select clip to change speed"), ErrorMessage);
1997         return;
1998     }
1999     QUndoCommand *changeSelected = new QUndoCommand();
2000     changeSelected->setText("Edit clip speed");
2001     for (int i = 0; i < itemList.count(); i++) {
2002         if (itemList.at(i)->type() == AVWIDGET) {
2003             ClipItem *item = static_cast <ClipItem *>(itemList.at(i));
2004             ItemInfo info = item->info();
2005             int percent = QInputDialog::getInteger(this, i18n("Edit Clip Speed"), i18n("New speed (percents)"), item->speed() * 100, 1, 300);
2006             double speed = (double) percent / 100.0;
2007             if (item->speed() != speed)
2008                 new ChangeSpeedCommand(this, info, item->speed(), speed, item->clipProducer(), true, changeSelected);
2009         }
2010     }
2011     m_commandStack->push(changeSelected);
2012 }
2013
2014 void CustomTrackView::doChangeClipSpeed(ItemInfo info, const double speed, const double oldspeed, const QString &id) {
2015     DocClipBase *baseclip = m_document->clipManager()->getClipById(id);
2016     ClipItem *item = getClipItemAt((int) info.startPos.frames(m_document->fps()) + 1, info.track);
2017     info.track = m_document->tracksCount() - item->track();
2018     int endPos = m_document->renderer()->mltChangeClipSpeed(info, speed, oldspeed, baseclip->producer());
2019     //kDebug() << "//CH CLIP SPEED: " << speed << "x" << oldspeed << ", END POS: " << endPos;
2020     item->setSpeed(speed);
2021     item->updateRectGeometry();
2022     if (item->cropDuration().frames(m_document->fps()) > endPos)
2023         item->AbstractClipItem::resizeEnd(info.startPos.frames(m_document->fps()) + endPos, speed);
2024     m_document->setModified(true);
2025 }
2026
2027 void CustomTrackView::cutSelectedClips() {
2028     QList<QGraphicsItem *> itemList = scene()->selectedItems();
2029     GenTime currentPos = GenTime(m_cursorPos, m_document->fps());
2030     for (int i = 0; i < itemList.count(); i++) {
2031         if (itemList.at(i)->type() == AVWIDGET) {
2032             ClipItem *item = static_cast <ClipItem *>(itemList.at(i));
2033             if (currentPos > item->startPos() && currentPos <  item->endPos()) {
2034                 RazorClipCommand *command = new RazorClipCommand(this, item->info(), currentPos, true);
2035                 m_commandStack->push(command);
2036             }
2037         }
2038     }
2039 }
2040
2041 void CustomTrackView::addClip(QDomElement xml, const QString &clipId, ItemInfo info, EffectsList effects) {
2042     DocClipBase *baseclip = m_document->clipManager()->getClipById(clipId);
2043     if (baseclip == NULL) {
2044         emit displayMessage(i18n("No clip copied"), ErrorMessage);
2045         return;
2046     }
2047     ClipItem *item = new ClipItem(baseclip, info, m_document->fps());
2048     item->setEffectList(effects);
2049     scene()->addItem(item);
2050     if (item->baseClip()->isTransparent()) {
2051         // add transparency transition
2052         int endTrack = getPreviousVideoTrack(info.track);
2053         Transition *tr = new Transition(info, endTrack, m_document->fps(), MainWindow::transitions.getEffectByTag("composite", "alphatransparency"), true);
2054         scene()->addItem(tr);
2055         m_document->renderer()->mltAddTransition(tr->transitionTag(), endTrack, m_document->tracksCount() - info.track, info.startPos, info.endPos, tr->toXML());
2056     }
2057
2058     baseclip->addReference();
2059     m_document->updateClip(baseclip->getId());
2060     info.track = m_document->tracksCount() - info.track;
2061     m_document->renderer()->mltInsertClip(info, xml, baseclip->producer(info.track));
2062     for (int i = 0; i < item->effectsCount(); i++) {
2063         m_document->renderer()->mltAddEffect(info.track, info.startPos, item->getEffectArgs(item->effectAt(i)), false);
2064     }
2065     m_document->renderer()->doRefresh();
2066 }
2067
2068 void CustomTrackView::slotUpdateClip(const QString &clipId) {
2069     QList<QGraphicsItem *> list = scene()->items();
2070     ClipItem *clip = NULL;
2071     for (int i = 0; i < list.size(); ++i) {
2072         if (list.at(i)->type() == AVWIDGET) {
2073             clip = static_cast <ClipItem *>(list.at(i));
2074             if (clip->clipProducer() == clipId) {
2075                 clip->refreshClip();
2076                 ItemInfo info = clip->info();
2077                 info.track = m_document->tracksCount() - clip->track();
2078                 m_document->renderer()->mltUpdateClip(info, clip->xml(), clip->baseClip()->producer());
2079             }
2080         }
2081     }
2082 }
2083
2084 ClipItem *CustomTrackView::getClipItemAtEnd(GenTime pos, int track) {
2085     QList<QGraphicsItem *> list = scene()->items(QPointF(pos.frames(m_document->fps()) - 1, track * m_tracksHeight + m_tracksHeight / 2));
2086     ClipItem *clip = NULL;
2087     for (int i = 0; i < list.size(); ++i) {
2088         if (list.at(i)->type() == AVWIDGET) {
2089             ClipItem *test = static_cast <ClipItem *>(list.at(i));
2090             if (test->endPos() == pos) clip = test;
2091             break;
2092         }
2093     }
2094     return clip;
2095 }
2096
2097 ClipItem *CustomTrackView::getClipItemAtStart(GenTime pos, int track) {
2098     QList<QGraphicsItem *> list = scene()->items(QPointF(pos.frames(m_document->fps()), track * m_tracksHeight + m_tracksHeight / 2));
2099     ClipItem *clip = NULL;
2100     for (int i = 0; i < list.size(); ++i) {
2101         if (list.at(i)->type() == AVWIDGET) {
2102             ClipItem *test = static_cast <ClipItem *>(list.at(i));
2103             if (test->startPos() == pos) clip = test;
2104             break;
2105         }
2106     }
2107     return clip;
2108 }
2109
2110 ClipItem *CustomTrackView::getClipItemAt(int pos, int track) {
2111     QList<QGraphicsItem *> list = scene()->items(QPointF(pos , track * m_tracksHeight + m_tracksHeight / 2));
2112     ClipItem *clip = NULL;
2113     for (int i = 0; i < list.size(); ++i) {
2114         if (list.at(i)->type() == AVWIDGET) {
2115             clip = static_cast <ClipItem *>(list.at(i));
2116             break;
2117         }
2118     }
2119     return clip;
2120 }
2121
2122 ClipItem *CustomTrackView::getClipItemAt(GenTime pos, int track) {
2123     int framepos = (int)(pos.frames(m_document->fps()));
2124     return getClipItemAt(framepos, track);
2125 }
2126
2127 Transition *CustomTrackView::getTransitionItemAt(int pos, int track) {
2128     QList<QGraphicsItem *> list = scene()->items(QPointF(pos, (track + 1) * m_tracksHeight));
2129     Transition *clip = NULL;
2130     for (int i = 0; i < list.size(); ++i) {
2131         if (list.at(i)->type() == TRANSITIONWIDGET) {
2132             clip = static_cast <Transition *>(list.at(i));
2133             break;
2134         }
2135     }
2136     return clip;
2137 }
2138
2139 Transition *CustomTrackView::getTransitionItemAt(GenTime pos, int track) {
2140     int framepos = (int)(pos.frames(m_document->fps()));
2141     return getTransitionItemAt(framepos, track);
2142 }
2143
2144 Transition *CustomTrackView::getTransitionItemAtEnd(GenTime pos, int track) {
2145     int framepos = (int)(pos.frames(m_document->fps()));
2146     QList<QGraphicsItem *> list = scene()->items(QPointF(framepos - 1, (track + 1) * m_tracksHeight));
2147     Transition *clip = NULL;
2148     for (int i = 0; i < list.size(); ++i) {
2149         if (list.at(i)->type() == TRANSITIONWIDGET) {
2150             Transition *test = static_cast <Transition *>(list.at(i));
2151             if (test->endPos() == pos) clip = test;
2152             break;
2153         }
2154     }
2155     return clip;
2156 }
2157
2158 Transition *CustomTrackView::getTransitionItemAtStart(GenTime pos, int track) {
2159     QList<QGraphicsItem *> list = scene()->items(QPointF(pos.frames(m_document->fps()), (track + 1) * m_tracksHeight));
2160     Transition *clip = NULL;
2161     for (int i = 0; i < list.size(); ++i) {
2162         if (list.at(i)->type() == TRANSITIONWIDGET) {
2163             Transition *test = static_cast <Transition *>(list.at(i));
2164             if (test->startPos() == pos) clip = test;
2165             break;
2166         }
2167     }
2168     return clip;
2169 }
2170
2171 void CustomTrackView::moveClip(const ItemInfo start, const ItemInfo end) {
2172     if (m_selectionGroup) resetSelectionGroup(false);
2173     ClipItem *item = getClipItemAt((int) start.startPos.frames(m_document->fps()) + 1, start.track);
2174     if (!item) {
2175         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);
2176         kDebug() << "----------------  ERROR, CANNOT find clip to move at.. ";
2177         return;
2178     }
2179     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));
2180     if (success) {
2181         item->setPos((int) end.startPos.frames(m_document->fps()), (int)(end.track * m_tracksHeight + 1));
2182         m_scene->clearSelection();
2183         item->setSelected(true);
2184         if (item->baseClip()->isTransparent()) {
2185             // Also move automatic transition
2186             Transition *tr = getTransitionItemAt((int) start.startPos.frames(m_document->fps()), start.track);
2187             if (tr && tr->isAutomatic()) {
2188                 tr->updateTransitionEndTrack(getPreviousVideoTrack(end.track));
2189                 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);
2190                 tr->setPos((int) end.startPos.frames(m_document->fps()), (int)(end.track * m_tracksHeight + 1));
2191             }
2192         }
2193     } else {
2194         // undo last move and emit error message
2195         emit displayMessage(i18n("Cannot move clip to position %1", m_document->timecode().getTimecodeFromFrames(end.startPos.frames(m_document->fps()))), ErrorMessage);
2196     }
2197     kDebug() << " // MOVED CLIP TO: " << end.startPos.frames(25) << ", ITEM START: " << item->startPos().frames(25);
2198 }
2199
2200 void CustomTrackView::moveGroup(QList <ItemInfo> startClip, QList <ItemInfo> startTransition, const GenTime offset, const int trackOffset, bool reverseMove) {
2201     // Group Items
2202     kDebug() << "// GROUP MOVE; OFFSET: " << offset.frames(25) << ", TK OFF: " << trackOffset;
2203     resetSelectionGroup();
2204     m_scene->clearSelection();
2205     for (int i = 0; i < startClip.count(); i++) {
2206         if (reverseMove) {
2207             startClip[i].startPos = startClip.at(i).startPos - offset;
2208             startClip[i].track = startClip.at(i).track - trackOffset;
2209         }
2210         ClipItem *clip = getClipItemAt(startClip.at(i).startPos, startClip.at(i).track);
2211         if (clip) {
2212             clip->setSelected(true);
2213             m_document->renderer()->mltRemoveClip(m_document->tracksCount() - startClip.at(i).track, startClip.at(i).startPos);
2214         }
2215     }
2216     for (int i = 0; i < startTransition.count(); i++) {
2217         if (reverseMove) {
2218             startTransition[i].startPos = startTransition.at(i).startPos - offset;
2219             startTransition[i].track = startTransition.at(i).track - trackOffset;
2220         }
2221         Transition *tr = getTransitionItemAt(startTransition.at(i).startPos, startTransition.at(i).track);
2222         if (tr) {
2223             tr->setSelected(true);
2224             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());
2225         }
2226     }
2227     groupSelectedItems();
2228     if (m_selectionGroup) {
2229         QPointF pos = m_selectionGroup->pos();
2230         qreal posx = pos.x() + offset.frames(m_document->fps());
2231         qreal posy = pos.y() + trackOffset * (qreal) m_tracksHeight;
2232         m_selectionGroup->setPos(posx, posy);
2233
2234         QPointF top = m_selectionGroup->sceneBoundingRect().topLeft();
2235         m_selectionGroup->setPos(top);
2236         m_selectionGroupInfo.startPos = GenTime(m_selectionGroup->scenePos().x(), m_document->fps());
2237         m_selectionGroupInfo.track = m_selectionGroup->track();
2238
2239         QList<QGraphicsItem *> children = m_selectionGroup->childItems();
2240         for (int i = 0; i < children.count(); i++) {
2241             // re-add items in correct place
2242             AbstractClipItem *item = static_cast <AbstractClipItem *>(children.at(i));
2243             item->updateItem();
2244             ItemInfo info = item->info();
2245             if (item->type() == AVWIDGET) {
2246                 ClipItem *clip = static_cast <ClipItem*>(item);
2247                 info.track = m_document->tracksCount() - info.track;
2248                 m_document->renderer()->mltInsertClip(info, clip->xml(), clip->baseClip()->producer(info.track));
2249             } else {
2250                 Transition *tr = static_cast <Transition*>(item);
2251                 int newTrack = tr->transitionEndTrack();
2252                 kDebug() << "/// TRANSITION CURR TRK: " << newTrack;
2253                 if (!tr->forcedTrack()) {
2254                     newTrack += trackOffset;
2255                     if (newTrack < 0 || newTrack > m_document->tracksCount()) newTrack = getPreviousVideoTrack(info.track);
2256                 }
2257                 tr->updateTransitionEndTrack(newTrack);
2258                 kDebug() << "/// TRANSITION UPDATED TRK: " << newTrack;
2259                 m_document->renderer()->mltAddTransition(tr->transitionTag(), newTrack, m_document->tracksCount() - info.track, info.startPos, info.endPos, tr->toXML());
2260             }
2261         }
2262     }
2263
2264 }
2265
2266 void CustomTrackView::moveTransition(const ItemInfo start, const ItemInfo end) {
2267     Transition *item = getTransitionItemAt((int)start.startPos.frames(m_document->fps()), start.track);
2268     if (!item) {
2269         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);
2270         kDebug() << "----------------  ERROR, CANNOT find transition to move... ";// << startPos.x() * m_scale * FRAME_SIZE + 1 << ", " << startPos.y() * m_tracksHeight + m_tracksHeight / 2;
2271         return;
2272     }
2273     //kDebug() << "----------------  Move TRANSITION FROM: " << startPos.x() << ", END:" << endPos.x() << ",TRACKS: " << oldtrack << " TO " << newtrack;
2274
2275     //kDebug()<<"///  RESIZE TRANS START: ("<< startPos.x()<<"x"<< startPos.y()<<") / ("<<endPos.x()<<"x"<< endPos.y()<<")";
2276     if (end.endPos - end.startPos == start.endPos - start.startPos) {
2277         // Transition was moved
2278         item->setPos((int) end.startPos.frames(m_document->fps()), (end.track) * m_tracksHeight + 1);
2279     } else if (end.endPos == start.endPos) {
2280         // Transition start resize
2281         item->resizeStart((int) end.startPos.frames(m_document->fps()));
2282     } else if (end.startPos == start.startPos) {
2283         // Transition end resize;
2284         item->resizeEnd((int) end.endPos.frames(m_document->fps()));
2285     } else {
2286         // Move & resize
2287         item->setPos((int) end.startPos.frames(m_document->fps()), (end.track) * m_tracksHeight + 1);
2288         item->resizeStart((int) end.startPos.frames(m_document->fps()));
2289         item->resizeEnd((int) end.endPos.frames(m_document->fps()));
2290     }
2291     //item->moveTransition(GenTime((int) (endPos.x() - startPos.x()), m_document->fps()));
2292     item->updateTransitionEndTrack(getPreviousVideoTrack(end.track));
2293     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);
2294 }
2295
2296 void CustomTrackView::resizeClip(const ItemInfo start, const ItemInfo end) {
2297     int offset = 0;
2298     bool resizeClipStart = true;
2299     if (start.startPos == end.startPos) resizeClipStart = false;
2300     /*if (resizeClipStart) offset = 1;
2301     else offset = -1;*/
2302     ClipItem *item = getClipItemAt((int)(start.startPos.frames(m_document->fps()) + offset), start.track);
2303     if (!item) {
2304         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);
2305         kDebug() << "----------------  ERROR, CANNOT find clip to resize at... "; // << startPos;
2306         return;
2307     }
2308     if (resizeClipStart) {
2309         ItemInfo clipinfo = item->info();
2310         clipinfo.track = m_document->tracksCount() - clipinfo.track;
2311         bool success = m_document->renderer()->mltResizeClipStart(clipinfo, end.startPos - item->startPos());
2312         if (success) {
2313             item->resizeStart((int) end.startPos.frames(m_document->fps()));
2314             updateClipFade(item);
2315         } else emit displayMessage(i18n("Error when resizing clip"), ErrorMessage);
2316     } else {
2317         ItemInfo clipinfo = item->info();
2318         clipinfo.track = m_document->tracksCount() - clipinfo.track;
2319         bool success = m_document->renderer()->mltResizeClipEnd(clipinfo, end.endPos - clipinfo.startPos);
2320         if (success) {
2321             item->resizeEnd((int) end.endPos.frames(m_document->fps()));
2322             updateClipFade(item, true);
2323         } else emit displayMessage(i18n("Error when resizing clip"), ErrorMessage);
2324     }
2325     m_document->renderer()->doRefresh();
2326 }
2327
2328 void CustomTrackView::updateClipFade(ClipItem * item, bool updateFadeOut) {
2329     if (!updateFadeOut) {
2330         int end = item->fadeIn();
2331         if (end != 0) {
2332             // there is a fade in effect
2333             int effectPos = item->hasEffect("volume", "fadein");
2334             if (effectPos == -1) return;
2335             QDomElement oldeffect = item->effectAt(effectPos);
2336             int start = item->cropStart().frames(m_document->fps());
2337             int max = item->cropDuration().frames(m_document->fps());
2338             if (end > max) {
2339                 item->setFadeIn(max);
2340                 end = item->fadeIn();
2341             }
2342             end += start;
2343             EffectsList::setParameter(oldeffect, "in", QString::number(start));
2344             EffectsList::setParameter(oldeffect, "out", QString::number(end));
2345             QHash <QString, QString> effectParams = item->getEffectArgs(oldeffect);
2346             if (!m_document->renderer()->mltEditEffect(m_document->tracksCount() - item->track(), item->startPos(), effectParams))
2347                 emit displayMessage(i18n("Problem editing effect"), ErrorMessage);
2348             // if fade effect is displayed, update the effect edit widget with new clip duration
2349             if (item->isSelected() && effectPos == item->selectedEffectIndex()) emit clipItemSelected(item, effectPos);
2350         }
2351     } else {
2352         int start = item->fadeOut();
2353         if (start != 0) {
2354             // there is a fade in effect
2355             int effectPos = item->hasEffect("volume", "fadeout");
2356             if (effectPos == -1) return;
2357             QDomElement oldeffect = item->effectAt(effectPos);
2358             int end = (item->duration() - item->cropStart()).frames(m_document->fps());
2359             int max = item->cropDuration().frames(m_document->fps());
2360             if (end > max) {
2361                 item->setFadeOut(max);
2362                 start = item->fadeOut();
2363             }
2364             start = end - start;
2365             EffectsList::setParameter(oldeffect, "in", QString::number(start));
2366             EffectsList::setParameter(oldeffect, "out", QString::number(end));
2367             QHash <QString, QString> effectParams = item->getEffectArgs(oldeffect);
2368             if (!m_document->renderer()->mltEditEffect(m_document->tracksCount() - item->track(), item->startPos(), effectParams))
2369                 emit displayMessage(i18n("Problem editing effect"), ErrorMessage);
2370             // if fade effect is displayed, update the effect edit widget with new clip duration
2371             if (item->isSelected() && effectPos == item->selectedEffectIndex()) emit clipItemSelected(item, effectPos);
2372         }
2373     }
2374 }
2375
2376 double CustomTrackView::getSnapPointForPos(double pos) {
2377     return m_scene->getSnapPointForPos(pos, KdenliveSettings::snaptopoints());
2378 }
2379
2380 void CustomTrackView::updateSnapPoints(AbstractClipItem *selected) {
2381     QList <GenTime> snaps;
2382     GenTime offset;
2383     if (selected) offset = selected->duration();
2384     QList<QGraphicsItem *> itemList = items();
2385     for (int i = 0; i < itemList.count(); i++) {
2386         if (itemList.at(i)->type() == AVWIDGET && itemList.at(i) != selected) {
2387             ClipItem *item = static_cast <ClipItem *>(itemList.at(i));
2388             GenTime start = item->startPos();
2389             GenTime end = item->endPos();
2390             snaps.append(start);
2391             snaps.append(end);
2392             QList < GenTime > markers = item->snapMarkers();
2393             for (int i = 0; i < markers.size(); ++i) {
2394                 GenTime t = markers.at(i);
2395                 snaps.append(t);
2396                 if (t > offset) snaps.append(t - offset);
2397             }
2398             if (offset != GenTime()) {
2399                 if (start > offset) snaps.append(start - offset);
2400                 if (end > offset) snaps.append(end - offset);
2401             }
2402         } else if (itemList.at(i)->type() == TRANSITIONWIDGET) {
2403             Transition *transition = static_cast <Transition*>(itemList.at(i));
2404             GenTime start = transition->startPos();
2405             GenTime end = transition->endPos();
2406             snaps.append(start);
2407             snaps.append(end);
2408             if (offset != GenTime()) {
2409                 if (start > offset) snaps.append(start - offset);
2410                 if (end > offset) snaps.append(end - offset);
2411             }
2412         }
2413     }
2414
2415     // add cursor position
2416     GenTime pos = GenTime(m_cursorPos, m_document->fps());
2417     snaps.append(pos);
2418     if (offset != GenTime()) snaps.append(pos - offset);
2419
2420     // add guides
2421     for (int i = 0; i < m_guides.count(); i++) {
2422         snaps.append(m_guides.at(i)->position());
2423         if (offset != GenTime()) snaps.append(m_guides.at(i)->position() - offset);
2424     }
2425
2426     qSort(snaps);
2427     m_scene->setSnapList(snaps);
2428     //for (int i = 0; i < m_snapPoints.size(); ++i)
2429     //    kDebug() << "SNAP POINT: " << m_snapPoints.at(i).frames(25);
2430 }
2431
2432 void CustomTrackView::slotSeekToPreviousSnap() {
2433     updateSnapPoints(NULL);
2434     GenTime res = m_scene->previousSnapPoint(GenTime(m_cursorPos, m_document->fps()));
2435     setCursorPos((int) res.frames(m_document->fps()));
2436     checkScrolling();
2437 }
2438
2439 void CustomTrackView::slotSeekToNextSnap() {
2440     updateSnapPoints(NULL);
2441     GenTime res = m_scene->nextSnapPoint(GenTime(m_cursorPos, m_document->fps()));
2442     setCursorPos((int) res.frames(m_document->fps()));
2443     checkScrolling();
2444 }
2445
2446 void CustomTrackView::clipStart() {
2447     ClipItem *item = getMainActiveClip();
2448     if (item != NULL) {
2449         setCursorPos((int) item->startPos().frames(m_document->fps()));
2450         checkScrolling();
2451     }
2452 }
2453
2454 void CustomTrackView::clipEnd() {
2455     ClipItem *item = getMainActiveClip();
2456     if (item != NULL) {
2457         setCursorPos((int) item->endPos().frames(m_document->fps()));
2458         checkScrolling();
2459     }
2460 }
2461
2462 void CustomTrackView::slotAddClipMarker(const QString &id, GenTime t, QString c) {
2463     QString oldcomment = m_document->clipManager()->getClipById(id)->markerComment(t);
2464     AddMarkerCommand *command = new AddMarkerCommand(this, oldcomment, c, id, t, true);
2465     m_commandStack->push(command);
2466 }
2467
2468 void CustomTrackView::slotDeleteClipMarker(const QString &comment, const QString &id, const GenTime &position) {
2469     AddMarkerCommand *command = new AddMarkerCommand(this, comment, QString(), id, position, true);
2470     m_commandStack->push(command);
2471 }
2472
2473 void CustomTrackView::slotDeleteAllClipMarkers(const QString &id) {
2474     DocClipBase *base = m_document->clipManager()->getClipById(id);
2475     QList <CommentedTime> markers = base->commentedSnapMarkers();
2476
2477     if (markers.isEmpty()) {
2478         emit displayMessage(i18n("Clip has no markers"), ErrorMessage);
2479         return;
2480     }
2481     QUndoCommand *deleteMarkers = new QUndoCommand();
2482     deleteMarkers->setText("Delete clip markers");
2483
2484     for (int i = 0; i < markers.size(); i++) {
2485         new AddMarkerCommand(this, markers.at(i).comment(), QString(), id, markers.at(i).time(), true, deleteMarkers);
2486     }
2487     m_commandStack->push(deleteMarkers);
2488 }
2489
2490 void CustomTrackView::addMarker(const QString &id, const GenTime &pos, const QString comment) {
2491     DocClipBase *base = m_document->clipManager()->getClipById(id);
2492     if (!comment.isEmpty()) base->addSnapMarker(pos, comment);
2493     else base->deleteSnapMarker(pos);
2494     m_document->setModified(true);
2495     viewport()->update();
2496 }
2497
2498 bool sortGuidesList(const Guide *g1 , const Guide *g2) {
2499     return (*g1).position() < (*g2).position();
2500 }
2501
2502 void CustomTrackView::editGuide(const GenTime oldPos, const GenTime pos, const QString &comment) {
2503     if (oldPos > GenTime() && pos > GenTime()) {
2504         // move guide
2505         for (int i = 0; i < m_guides.count(); i++) {
2506             if (m_guides.at(i)->position() == oldPos) {
2507                 Guide *item = m_guides.at(i);
2508                 item->updateGuide(pos, comment);
2509                 break;
2510             }
2511         }
2512     } else if (pos > GenTime()) addGuide(pos, comment);
2513     else {
2514         // remove guide
2515         bool found = false;
2516         for (int i = 0; i < m_guides.count(); i++) {
2517             if (m_guides.at(i)->position() == oldPos) {
2518                 Guide *item = m_guides.takeAt(i);
2519                 delete item;
2520                 found = true;
2521                 break;
2522             }
2523         }
2524         if (!found) emit displayMessage(i18n("No guide at cursor time"), ErrorMessage);
2525     }
2526     qSort(m_guides.begin(), m_guides.end(), sortGuidesList);
2527     m_document->syncGuides(m_guides);
2528 }
2529
2530 bool CustomTrackView::addGuide(const GenTime pos, const QString &comment) {
2531     for (int i = 0; i < m_guides.count(); i++) {
2532         if (m_guides.at(i)->position() == pos) {
2533             emit displayMessage(i18n("A guide already exists at position %1", m_document->timecode().getTimecodeFromFrames(pos.frames(m_document->fps()))), ErrorMessage);
2534             return false;
2535         }
2536     }
2537     Guide *g = new Guide(this, pos, comment, m_document->fps(), m_tracksHeight * m_document->tracksCount());
2538     scene()->addItem(g);
2539     m_guides.append(g);
2540     qSort(m_guides.begin(), m_guides.end(), sortGuidesList);
2541     m_document->syncGuides(m_guides);
2542     return true;
2543 }
2544
2545 void CustomTrackView::slotAddGuide() {
2546     CommentedTime marker(GenTime(m_cursorPos, m_document->fps()), i18n("Guide"));
2547     MarkerDialog d(NULL, marker, m_document->timecode(), i18n("Add Guide"), this);
2548     if (d.exec() != QDialog::Accepted) return;
2549     if (addGuide(d.newMarker().time(), d.newMarker().comment())) {
2550         EditGuideCommand *command = new EditGuideCommand(this, GenTime(), QString(), d.newMarker().time(), d.newMarker().comment(), false);
2551         m_commandStack->push(command);
2552     }
2553 }
2554
2555 void CustomTrackView::slotEditGuide() {
2556     GenTime pos = GenTime(m_cursorPos, m_document->fps());
2557     bool found = false;
2558     for (int i = 0; i < m_guides.count(); i++) {
2559         if (m_guides.at(i)->position() == pos) {
2560             slotEditGuide(m_guides.at(i)->info());
2561             found = true;
2562             break;
2563         }
2564     }
2565     if (!found) emit displayMessage(i18n("No guide at cursor time"), ErrorMessage);
2566 }
2567
2568 void CustomTrackView::slotEditGuide(CommentedTime guide) {
2569     MarkerDialog d(NULL, guide, m_document->timecode(), i18n("Edit Guide"), this);
2570     if (d.exec() == QDialog::Accepted) {
2571         EditGuideCommand *command = new EditGuideCommand(this, guide.time(), guide.comment(), d.newMarker().time(), d.newMarker().comment(), true);
2572         m_commandStack->push(command);
2573     }
2574 }
2575
2576
2577 void CustomTrackView::slotDeleteGuide() {
2578     GenTime pos = GenTime(m_cursorPos, m_document->fps());
2579     bool found = false;
2580     for (int i = 0; i < m_guides.count(); i++) {
2581         if (m_guides.at(i)->position() == pos) {
2582             EditGuideCommand *command = new EditGuideCommand(this, m_guides.at(i)->position(), m_guides.at(i)->label(), GenTime(), QString(), true);
2583             m_commandStack->push(command);
2584             found = true;
2585             break;
2586         }
2587     }
2588     if (!found) emit displayMessage(i18n("No guide at cursor time"), ErrorMessage);
2589 }
2590
2591 void CustomTrackView::slotDeleteAllGuides() {
2592     QUndoCommand *deleteAll = new QUndoCommand();
2593     deleteAll->setText("Delete all guides");
2594     for (int i = 0; i < m_guides.count(); i++) {
2595         EditGuideCommand *command = new EditGuideCommand(this, m_guides.at(i)->position(), m_guides.at(i)->label(), GenTime(), QString(), true, deleteAll);
2596     }
2597     m_commandStack->push(deleteAll);
2598 }
2599
2600 void CustomTrackView::setTool(PROJECTTOOL tool) {
2601     m_tool = tool;
2602 }
2603
2604 void CustomTrackView::setScale(double scaleFactor) {
2605     QMatrix matrix;
2606     matrix = matrix.scale(scaleFactor, 1);
2607     m_scene->setScale(scaleFactor);
2608     //scale(scaleFactor, 1);
2609     m_animationTimer->stop();
2610     if (m_visualTip) {
2611         delete m_visualTip;
2612         m_visualTip = NULL;
2613     }
2614     if (m_animation) {
2615         delete m_animation;
2616         m_animation = NULL;
2617     }
2618     /*double pos = cursorPos() / m_scale;
2619     m_scale = scaleFactor;
2620     m_scene->setScale(m_scale);
2621     int vert = verticalScrollBar()->value();
2622     kDebug() << " HHHHHHHH  SCALING: " << m_scale;
2623     QList<QGraphicsItem *> itemList = items();
2624     for (int i = 0; i < itemList.count(); i++) {
2625         if (itemList.at(i)->type() == AVWIDGET || itemList.at(i)->type() == TRANSITIONWIDGET) {
2626             AbstractClipItem *clip = (AbstractClipItem *)itemList.at(i);
2627             clip->setRect(0, 0, (qreal) clip->duration().frames(m_document->fps()) * m_scale - .5, clip->rect().height());
2628             clip->setPos((qreal) clip->startPos().frames(m_document->fps()) * m_scale, clip->pos().y());
2629         }
2630     }
2631
2632     for (int i = 0; i < m_guides.count(); i++) {
2633         m_guides.at(i)->updatePosition(m_scale);
2634     }
2635
2636     setSceneRect(0, 0, (m_projectDuration + 100) * m_scale, sceneRect().height());
2637     updateCursorPos();*/
2638     setMatrix(matrix);
2639     centerOn(QPointF(cursorPos(), m_tracksHeight));
2640     //verticalScrollBar()->setValue(vert);*/
2641 }
2642
2643 void CustomTrackView::slotRefreshGuides() {
2644     if (KdenliveSettings::showmarkers()) {
2645         kDebug() << "// refresh GUIDES";
2646         for (int i = 0; i < m_guides.count(); i++) {
2647             m_guides.at(i)->update();
2648         }
2649     }
2650 }
2651
2652 void CustomTrackView::drawBackground(QPainter * painter, const QRectF & rect) {
2653     QColor base = palette().button().color();
2654     QRectF r = rect;
2655     r.setWidth(r.width() + 1);
2656     painter->setClipRect(r);
2657     painter->drawLine(r.left(), 0, r.right(), 0);
2658     uint max = m_document->tracksCount();
2659     for (uint i = 0; i < max;i++) {
2660         /*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)));
2661                else*/
2662         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)));
2663         painter->drawLine(r.left(), m_tracksHeight * (i + 1), r.right(), m_tracksHeight * (i + 1));
2664     }
2665     int lowerLimit = m_tracksHeight * m_document->tracksCount() + 1;
2666     if (height() > lowerLimit)
2667         painter->fillRect(QRectF(r.left(), lowerLimit, r.width(), height() - lowerLimit), QBrush(base));
2668 }
2669
2670 bool CustomTrackView::findString(const QString &text) {
2671     QString marker;
2672     for (int i = 0; i < m_searchPoints.size(); ++i) {
2673         marker = m_searchPoints.at(i).comment();
2674         if (marker.contains(text, Qt::CaseInsensitive)) {
2675             setCursorPos(m_searchPoints.at(i).time().frames(m_document->fps()), true);
2676             int vert = verticalScrollBar()->value();
2677             int hor = cursorPos();
2678             ensureVisible(hor, vert + 10, 2, 2, 50, 0);
2679             m_findIndex = i;
2680             return true;
2681         }
2682     }
2683     return false;
2684 }
2685
2686 bool CustomTrackView::findNextString(const QString &text) {
2687     QString marker;
2688     for (int i = m_findIndex + 1; i < m_searchPoints.size(); ++i) {
2689         marker = m_searchPoints.at(i).comment();
2690         if (marker.contains(text, Qt::CaseInsensitive)) {
2691             setCursorPos(m_searchPoints.at(i).time().frames(m_document->fps()), true);
2692             int vert = verticalScrollBar()->value();
2693             int hor = cursorPos();
2694             ensureVisible(hor, vert + 10, 2, 2, 50, 0);
2695             m_findIndex = i;
2696             return true;
2697         }
2698     }
2699     m_findIndex = -1;
2700     return false;
2701 }
2702
2703 void CustomTrackView::initSearchStrings() {
2704     m_searchPoints.clear();
2705     QList<QGraphicsItem *> itemList = items();
2706     for (int i = 0; i < itemList.count(); i++) {
2707         // parse all clip names
2708         if (itemList.at(i)->type() == AVWIDGET) {
2709             ClipItem *item = static_cast <ClipItem *>(itemList.at(i));
2710             GenTime start = item->startPos();
2711             CommentedTime t(start, item->clipName());
2712             m_searchPoints.append(t);
2713             // add all clip markers
2714             QList < CommentedTime > markers = item->commentedSnapMarkers();
2715             m_searchPoints += markers;
2716         }
2717     }
2718
2719     // add guides
2720     for (int i = 0; i < m_guides.count(); i++) {
2721         m_searchPoints.append(m_guides.at(i)->info());
2722     }
2723
2724     qSort(m_searchPoints);
2725 }
2726
2727 void CustomTrackView::clearSearchStrings() {
2728     m_searchPoints.clear();
2729     m_findIndex = 0;
2730 }
2731
2732 void CustomTrackView::copyClip() {
2733     while (m_copiedItems.count() > 0) {
2734         delete m_copiedItems.takeFirst();
2735     }
2736     QList<QGraphicsItem *> itemList = scene()->selectedItems();
2737     if (itemList.count() == 0) {
2738         emit displayMessage(i18n("Select a clip before copying"), ErrorMessage);
2739         return;
2740     }
2741     for (int i = 0; i < itemList.count(); i++) {
2742         if (itemList.at(i)->type() == AVWIDGET) {
2743             ClipItem *dup = static_cast <ClipItem *>(itemList.at(i));
2744             m_copiedItems.append(dup->clone(dup->info()));
2745         } else if (itemList.at(i)->type() == TRANSITIONWIDGET) {
2746             Transition *dup = static_cast <Transition *>(itemList.at(i));
2747             m_copiedItems.append(dup->clone());
2748         }
2749     }
2750 }
2751
2752 bool CustomTrackView::canBePastedTo(ItemInfo info, int type) const {
2753     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));
2754     QList<QGraphicsItem *> collisions = scene()->items(rect, Qt::IntersectsItemBoundingRect);
2755     for (int i = 0; i < collisions.count(); i++) {
2756         if (collisions.at(i)->type() == type) return false;
2757     }
2758     return true;
2759 }
2760
2761 bool CustomTrackView::canBePasted(QList<AbstractClipItem *> items, GenTime offset, int trackOffset) const {
2762     for (int i = 0; i < items.count(); i++) {
2763         ItemInfo info = items.at(i)->info();
2764         info.startPos += offset;
2765         info.endPos += offset;
2766         info.track += trackOffset;
2767         if (!canBePastedTo(info, items.at(i)->type())) return false;
2768     }
2769     return true;
2770 }
2771
2772 bool CustomTrackView::canBeMoved(QList<AbstractClipItem *> items, GenTime offset, int trackOffset) const {
2773     QPainterPath movePath;
2774     movePath.moveTo(0, 0);
2775
2776     for (int i = 0; i < items.count(); i++) {
2777         ItemInfo info = items.at(i)->info();
2778         info.startPos = info.startPos + offset;
2779         info.endPos = info.endPos + offset;
2780         info.track = info.track + trackOffset;
2781         if (info.startPos < GenTime()) {
2782             // No clip should go below 0
2783             return false;
2784         }
2785         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));
2786         movePath.addRect(rect);
2787     }
2788     QList<QGraphicsItem *> collisions = scene()->items(movePath, Qt::IntersectsItemBoundingRect);
2789     for (int i = 0; i < collisions.count(); i++) {
2790         if ((collisions.at(i)->type() == AVWIDGET || collisions.at(i)->type() == TRANSITIONWIDGET) && !items.contains(static_cast <AbstractClipItem *>(collisions.at(i)))) {
2791             kDebug() << "  ////////////   CLIP COLLISION, MOVE NOT ALLOWED";
2792             return false;
2793         }
2794     }
2795     return true;
2796 }
2797
2798 void CustomTrackView::pasteClip() {
2799     if (m_copiedItems.count() == 0) {
2800         emit displayMessage(i18n("No clip copied"), ErrorMessage);
2801         return;
2802     }
2803     QPoint position;
2804     if (m_menuPosition.isNull()) position = mapFromGlobal(QCursor::pos());
2805     else position = m_menuPosition;
2806     GenTime pos = GenTime((int)(mapToScene(position).x()), m_document->fps());
2807     int track = (int)(position.y() / m_tracksHeight);
2808     ItemInfo first = m_copiedItems.at(0)->info();
2809
2810     GenTime offset = pos - first.startPos;
2811     int trackOffset = track - first.track;
2812
2813     if (!canBePasted(m_copiedItems, offset, trackOffset)) {
2814         emit displayMessage(i18n("Cannot paste selected clips"), ErrorMessage);
2815         return;
2816     }
2817     QUndoCommand *pasteClips = new QUndoCommand();
2818     pasteClips->setText("Paste clips");
2819
2820     for (int i = 0; i < m_copiedItems.count(); i++) {
2821         // parse all clip names
2822         if (m_copiedItems.at(i) && m_copiedItems.at(i)->type() == AVWIDGET) {
2823             ClipItem *clip = static_cast <ClipItem *>(m_copiedItems.at(i));
2824             ItemInfo info;
2825             info.startPos = clip->startPos() + offset;
2826             info.endPos = clip->endPos() + offset;
2827             info.cropStart = clip->cropStart();
2828             info.track = clip->track() + trackOffset;
2829             if (canBePastedTo(info, AVWIDGET)) {
2830                 new AddTimelineClipCommand(this, clip->xml(), clip->clipProducer(), info, clip->effectList(), true, false, pasteClips);
2831             } else emit displayMessage(i18n("Cannot paste clip to selected place"), ErrorMessage);
2832         } else if (m_copiedItems.at(i) && m_copiedItems.at(i)->type() == TRANSITIONWIDGET) {
2833             Transition *tr = static_cast <Transition *>(m_copiedItems.at(i));
2834             ItemInfo info;
2835             info.startPos = tr->startPos() + offset;
2836             info.endPos = tr->endPos() + offset;
2837             info.track = tr->track() + trackOffset;
2838             if (canBePastedTo(info, TRANSITIONWIDGET)) {
2839                 new AddTransitionCommand(this, info, tr->transitionEndTrack() + trackOffset, tr->toXML(), false, true, pasteClips);
2840             } else emit displayMessage(i18n("Cannot paste transition to selected place"), ErrorMessage);
2841         }
2842     }
2843     m_commandStack->push(pasteClips);
2844 }
2845
2846 void CustomTrackView::pasteClipEffects() {
2847     if (m_copiedItems.count() != 1 || m_copiedItems.at(0)->type() != AVWIDGET) {
2848         emit displayMessage(i18n("You must copy exactly one clip before pasting effects"), ErrorMessage);
2849         return;
2850     }
2851     ClipItem *clip = static_cast < ClipItem *>(m_copiedItems.at(0));
2852     EffectsList effects = clip->effectList();
2853
2854     QUndoCommand *paste = new QUndoCommand();
2855     paste->setText("Paste effects");
2856
2857     QList<QGraphicsItem *> clips = scene()->selectedItems();
2858     for (int i = 0; i < clips.count(); ++i) {
2859         if (clips.at(i)->type() == AVWIDGET) {
2860             ClipItem *item = static_cast < ClipItem *>(clips.at(i));
2861             for (int i = 0; i < clip->effectsCount(); i++) {
2862                 new AddEffectCommand(this, m_document->tracksCount() - item->track(), item->startPos(), clip->effectAt(i), true, paste);
2863             }
2864         }
2865     }
2866     m_commandStack->push(paste);
2867 }
2868
2869
2870 ClipItem *CustomTrackView::getClipUnderCursor() const {
2871     QRectF rect((double) m_cursorPos, 0.0, 1.0, (double)(m_tracksHeight * m_document->tracksCount()));
2872     QList<QGraphicsItem *> collisions = scene()->items(rect, Qt::IntersectsItemBoundingRect);
2873     for (int i = 0; i < collisions.count(); i++) {
2874         if (collisions.at(i)->type() == AVWIDGET) {
2875             return static_cast < ClipItem *>(collisions.at(i));
2876         }
2877     }
2878     return NULL;
2879 }
2880
2881 ClipItem *CustomTrackView::getMainActiveClip() const {
2882     QList<QGraphicsItem *> clips = scene()->selectedItems();
2883     if (clips.isEmpty()) {
2884         return getClipUnderCursor();
2885     } else {
2886         ClipItem *item = NULL;
2887         for (int i = 0; i < clips.count(); ++i) {
2888             if (clips.at(i)->type() == AVWIDGET)
2889                 item = static_cast < ClipItem *>(clips.at(i));
2890             if (item->startPos().frames(m_document->fps()) <= m_cursorPos && item->endPos().frames(m_document->fps()) >= m_cursorPos) break;
2891         }
2892         if (item) return item;
2893     }
2894     return NULL;
2895 }
2896
2897 ClipItem *CustomTrackView::getActiveClipUnderCursor(bool allowOutsideCursor) const {
2898     QList<QGraphicsItem *> clips = scene()->selectedItems();
2899     if (clips.isEmpty()) {
2900         return getClipUnderCursor();
2901     } else {
2902         ClipItem *item;
2903         // remove all items in the list that are not clips
2904         for (int i = 0; i < clips.count();) {
2905             if (clips.at(i)->type() != AVWIDGET) clips.removeAt(i);
2906             else i++;
2907         }
2908         if (clips.count() == 1 && allowOutsideCursor) return static_cast < ClipItem *>(clips.at(0));
2909         for (int i = 0; i < clips.count(); ++i) {
2910             if (clips.at(i)->type() == AVWIDGET)
2911                 item = static_cast < ClipItem *>(clips.at(i));
2912             if (item->startPos().frames(m_document->fps()) <= m_cursorPos && item->endPos().frames(m_document->fps()) >= m_cursorPos) return item;
2913         }
2914     }
2915     return NULL;
2916 }
2917
2918 void CustomTrackView::setInPoint() {
2919     ClipItem *clip = getActiveClipUnderCursor(true);
2920     if (clip == NULL) {
2921         emit displayMessage(i18n("You must select one clip for this action"), ErrorMessage);
2922         return;
2923     }
2924     ItemInfo startInfo = clip->info();
2925     ItemInfo endInfo = clip->info();
2926     endInfo.startPos = GenTime(m_cursorPos, m_document->fps());
2927     ResizeClipCommand *command = new ResizeClipCommand(this, startInfo, endInfo, true);
2928     m_commandStack->push(command);
2929 }
2930
2931 void CustomTrackView::setOutPoint() {
2932     ClipItem *clip = getActiveClipUnderCursor(true);
2933     if (clip == NULL) {
2934         emit displayMessage(i18n("You must select one clip for this action"), ErrorMessage);
2935         return;
2936     }
2937     ItemInfo startInfo = clip->info();
2938     ItemInfo endInfo = clip->info();
2939     endInfo.endPos = GenTime(m_cursorPos, m_document->fps());
2940     ResizeClipCommand *command = new ResizeClipCommand(this, startInfo, endInfo, true);
2941     m_commandStack->push(command);
2942 }
2943
2944 void CustomTrackView::slotUpdateAllThumbs() {
2945     QList<QGraphicsItem *> itemList = items();
2946     //if (itemList.isEmpty()) return;
2947     ClipItem *item;
2948     QString thumbBase = m_document->projectFolder().path() + "/thumbs/";
2949     for (int i = 0; i < itemList.count(); i++) {
2950         if (itemList.at(i)->type() == AVWIDGET) {
2951             item = static_cast <ClipItem *>(itemList.at(i));
2952             if (item->clipType() != COLOR) {
2953                 // Check if we have a cached thumbnail
2954                 if (item->clipType() == IMAGE || item->clipType() == TEXT || item->clipType() == AUDIO) {
2955                     QString thumb = thumbBase + item->baseClip()->getClipHash() + "_0.png";
2956                     if (QFile::exists(thumb)) {
2957                         QPixmap pix(thumb);
2958                         item->slotSetStartThumb(pix);
2959                         item->slotSetEndThumb(pix);
2960                     }
2961                 } else {
2962                     QString startThumb = thumbBase + item->baseClip()->getClipHash() + '_';
2963                     QString endThumb = startThumb;
2964                     startThumb.append(QString::number(item->cropStart().frames(m_document->fps())) + ".png");
2965                     endThumb.append(QString::number((item->cropStart() + item->cropDuration()).frames(m_document->fps()) - 1) + ".png");
2966                     if (QFile::exists(startThumb)) {
2967                         QPixmap pix(startThumb);
2968                         item->slotSetStartThumb(pix);
2969                     }
2970                     if (QFile::exists(endThumb)) {
2971                         QPixmap pix(endThumb);
2972                         item->slotSetEndThumb(pix);
2973                     }
2974                 }
2975             }
2976             item->refreshClip();
2977             qApp->processEvents();
2978         }
2979     }
2980     viewport()->update();
2981 }
2982
2983 void CustomTrackView::saveThumbnails() {
2984     QList<QGraphicsItem *> itemList = items();
2985     ClipItem *item;
2986     QString thumbBase = m_document->projectFolder().path() + "/thumbs/";
2987     for (int i = 0; i < itemList.count(); i++) {
2988         if (itemList.at(i)->type() == AVWIDGET) {
2989             item = static_cast <ClipItem *>(itemList.at(i));
2990             if (item->clipType() != COLOR) {
2991                 // Check if we have a cached thumbnail
2992                 if (item->clipType() == IMAGE || item->clipType() == TEXT || item->clipType() == AUDIO) {
2993                     QString thumb = thumbBase + item->baseClip()->getClipHash() + "_0.png";
2994                     if (!QFile::exists(thumb)) {
2995                         QPixmap pix(item->startThumb());
2996                         pix.save(thumb);
2997                     }
2998                 } else {
2999                     QString startThumb = thumbBase + item->baseClip()->getClipHash() + '_';
3000                     QString endThumb = startThumb;
3001                     startThumb.append(QString::number(item->cropStart().frames(m_document->fps())) + ".png");
3002                     endThumb.append(QString::number((item->cropStart() + item->cropDuration()).frames(m_document->fps()) - 1) + ".png");
3003                     if (!QFile::exists(startThumb)) {
3004                         QPixmap pix(item->startThumb());
3005                         pix.save(startThumb);
3006                     }
3007                     if (!QFile::exists(endThumb)) {
3008                         QPixmap pix(item->endThumb());
3009                         pix.save(endThumb);
3010                     }
3011                 }
3012             }
3013         }
3014     }
3015 }
3016
3017
3018 void CustomTrackView::slotInsertTrack(int ix) {
3019     kDebug() << "// INSERTING TRK: " << ix;
3020     QDialog d(parentWidget());
3021     Ui::AddTrack_UI view;
3022     view.setupUi(&d);
3023     view.track_nb->setMaximum(m_document->tracksCount() - 1);
3024     view.track_nb->setValue(ix);
3025     d.setWindowTitle(i18n("Insert Track"));
3026
3027     if (d.exec() == QDialog::Accepted) {
3028         if (view.before_select->currentIndex() == 1) {
3029             ix++;
3030         }
3031         TrackInfo info;
3032         if (view.video_track->isChecked()) {
3033             info.type = VIDEOTRACK;
3034             info.isMute = false;
3035             info.isBlind = false;
3036         } else {
3037             info.type = AUDIOTRACK;
3038             info.isMute = false;
3039             info.isBlind = true;
3040         }
3041         AddTrackCommand *addTrack = new AddTrackCommand(this, ix, info, true, true);
3042         m_commandStack->push(addTrack);
3043         m_document->setModified(true);
3044     }
3045 }
3046
3047 void CustomTrackView::slotDeleteTrack(int ix) {
3048     bool ok;
3049     ix = QInputDialog::getInteger(this, i18n("Remove Track"), i18n("Track"), ix, 0, m_document->tracksCount() - 1, 1, &ok);
3050     if (ok) {
3051         TrackInfo info = m_document->trackInfoAt(m_document->tracksCount() - ix - 1);
3052         deleteTimelineTrack(ix, info);
3053         m_document->setModified(true);
3054         /*AddTrackCommand* command = new AddTrackCommand(this, ix, info, false, true);
3055         m_commandStack->push(command);*/
3056     }
3057 }
3058
3059 void CustomTrackView::slotChangeTrack(int ix) {
3060     QDialog d(parentWidget());
3061     Ui::AddTrack_UI view;
3062     view.setupUi(&d);
3063     view.label->setText(i18n("Change track"));
3064     view.before_select->setHidden(true);
3065     view.track_nb->setMaximum(m_document->tracksCount() - 1);
3066     view.track_nb->setValue(ix);
3067     d.setWindowTitle(i18n("Change Track Type"));
3068
3069     if (d.exec() == QDialog::Accepted) {
3070         TrackInfo info;
3071         if (view.video_track->isChecked()) {
3072             info.type = VIDEOTRACK;
3073             info.isMute = false;
3074             info.isBlind = false;
3075         } else {
3076             info.type = AUDIOTRACK;
3077             info.isMute = false;
3078             info.isBlind = true;
3079         }
3080         changeTimelineTrack(ix, info);
3081         m_document->setModified(true);
3082     }
3083 }
3084
3085
3086 void CustomTrackView::deleteTimelineTrack(int ix, TrackInfo trackinfo) {
3087     double startY = ix * m_tracksHeight + 1 + m_tracksHeight / 2;
3088     QRectF r(0, startY, sceneRect().width(), m_tracksHeight / 2 - 1);
3089     QList<QGraphicsItem *> selection = m_scene->items(r);
3090     QUndoCommand *deleteTrack = new QUndoCommand();
3091     deleteTrack->setText("Delete track");
3092
3093     // Delete all clips in selected track
3094     for (int i = 0; i < selection.count(); i++) {
3095         if (selection.at(i)->type() == AVWIDGET) {
3096             ClipItem *item =  static_cast <ClipItem *>(selection.at(i));
3097             new AddTimelineClipCommand(this, item->xml(), item->clipProducer(), item->info(), item->effectList(), false, true, deleteTrack);
3098             m_scene->removeItem(item);
3099             delete item;
3100             item = NULL;
3101         } else if (selection.at(i)->type() == TRANSITIONWIDGET) {
3102             Transition *item =  static_cast <Transition *>(selection.at(i));
3103             new AddTransitionCommand(this, item->info(), item->transitionEndTrack(), item->toXML(), true, false, deleteTrack);
3104             m_scene->removeItem(item);
3105             delete item;
3106             item = NULL;
3107         }
3108     }
3109
3110     new AddTrackCommand(this, ix, trackinfo, false, true, deleteTrack);
3111     m_commandStack->push(deleteTrack);
3112 }
3113
3114 void CustomTrackView::changeTimelineTrack(int ix, TrackInfo trackinfo) {
3115     TrackInfo oldinfo = m_document->trackInfoAt(m_document->tracksCount() - ix);
3116     ChangeTrackCommand *changeTrack = new ChangeTrackCommand(this, ix, oldinfo, trackinfo, true);
3117     m_commandStack->push(changeTrack);
3118 }
3119
3120 void CustomTrackView::autoTransition() {
3121     QList<QGraphicsItem *> itemList = scene()->selectedItems();
3122     if (itemList.count() != 1 || itemList.at(0)->type() != TRANSITIONWIDGET) {
3123         emit displayMessage(i18n("You must select one transition for this action"), ErrorMessage);
3124         return;
3125     }
3126     Transition *tr = static_cast <Transition*>(itemList.at(0));
3127     tr->setAutomatic(!tr->isAutomatic());
3128     QDomElement transition = tr->toXML();
3129     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);
3130 }
3131
3132 #include "customtrackview.moc"