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