]> git.sesse.net Git - kdenlive/blob - src/customtrackview.cpp
Fix possible crash on clip deletion, fetch thumbs sequentially when adding several...
[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)) continue;
1339             } else if (effect.hasAttribute("type") == false) {
1340                 // Don't add video effect on audio clips
1341                 if (item->isAudioOnly() || item->clipType() == AUDIO) continue;
1342             }
1343             if (item->hasEffect(effect.attribute("tag"), effect.attribute("id")) != -1 && effect.attribute("unique", "0") != "0") {
1344                 emit displayMessage(i18n("Effect already present in clip"), ErrorMessage);
1345                 continue;
1346             }
1347             if (item->isItemLocked()) {
1348                 continue;
1349             }
1350             item->initEffect(effect);
1351             if (effect.attribute("tag") == "ladspa") {
1352                 QString ladpsaFile = m_document->getLadspaFile();
1353                 initEffects::ladspaEffectFile(ladpsaFile, effect.attribute("ladspaid").toInt(), getLadspaParams(effect));
1354                 effect.setAttribute("src", ladpsaFile);
1355             }
1356             new AddEffectCommand(this, m_document->tracksCount() - item->track(), item->startPos(), effect, true, effectCommand);
1357             count++;
1358         }
1359     }
1360     if (count > 0) {
1361         m_commandStack->push(effectCommand);
1362         m_document->setModified(true);
1363     } else delete effectCommand;
1364 }
1365
1366 void CustomTrackView::slotDeleteEffect(ClipItem *clip, QDomElement effect)
1367 {
1368     AddEffectCommand *command = new AddEffectCommand(this, m_document->tracksCount() - clip->track(), clip->startPos(), effect, false);
1369     m_commandStack->push(command);
1370     m_document->setModified(true);
1371 }
1372
1373 void CustomTrackView::updateEffect(int track, GenTime pos, QDomElement effect, int ix, bool triggeredByUser)
1374 {
1375     ClipItem *clip = getClipItemAt((int)pos.frames(m_document->fps()) + 1, m_document->tracksCount() - track);
1376     if (clip) {
1377         EffectsParameterList effectParams = clip->getEffectArgs(effect);
1378         if (effect.attribute("tag") == "ladspa") {
1379             // Update the ladspa affect file
1380             initEffects::ladspaEffectFile(effect.attribute("src"), effect.attribute("ladspaid").toInt(), getLadspaParams(effect));
1381         }
1382         // check if we are trying to reset a keyframe effect
1383         if (effectParams.hasParam("keyframes") && effectParams.paramValue("keyframes").isEmpty()) {
1384             clip->initEffect(effect);
1385             clip->setEffectAt(ix, effect);
1386             effectParams = clip->getEffectArgs(effect);
1387         }
1388         if (effectParams.paramValue("disabled") == "1") {
1389             if (m_document->renderer()->mltRemoveEffect(track, pos, effectParams.paramValue("kdenlive_ix"), false)) {
1390                 kDebug() << "//////  DISABLING EFFECT: " << ix << ", CURRENTLA: " << clip->selectedEffectIndex();
1391             } else emit displayMessage(i18n("Problem deleting effect"), ErrorMessage);
1392         } else if (!m_document->renderer()->mltEditEffect(m_document->tracksCount() - clip->track(), clip->startPos(), effectParams))
1393             emit displayMessage(i18n("Problem editing effect"), ErrorMessage);
1394
1395         clip->setEffectAt(ix, effect);
1396         if (ix == clip->selectedEffectIndex()) {
1397             clip->setSelectedEffect(ix);
1398             if (!triggeredByUser) emit clipItemSelected(clip, ix);
1399         }
1400         if (effect.attribute("tag") == "volume" || effect.attribute("tag") == "brightness") {
1401             // A fade effect was modified, update the clip
1402             if (effect.attribute("id") == "fadein" || effect.attribute("id") == "fade_from_black") {
1403                 int pos = effectParams.paramValue("out").toInt() - effectParams.paramValue("in").toInt();
1404                 clip->setFadeIn(pos);
1405             }
1406             if (effect.attribute("id") == "fadeout" || effect.attribute("id") == "fade_to_black") {
1407                 int pos = effectParams.paramValue("out").toInt() - effectParams.paramValue("in").toInt();
1408                 clip->setFadeOut(pos);
1409             }
1410         }
1411     }
1412     m_document->setModified(true);
1413 }
1414
1415 void CustomTrackView::moveEffect(int track, GenTime pos, int oldPos, int newPos)
1416 {
1417     ClipItem *clip = getClipItemAt((int)pos.frames(m_document->fps()) + 1, m_document->tracksCount() - track);
1418     if (clip) {
1419         m_document->renderer()->mltMoveEffect(track, pos, oldPos, newPos);
1420         QDomElement act = clip->effectAt(newPos - 1).cloneNode().toElement();
1421         QDomElement before = clip->effectAt(oldPos - 1).cloneNode().toElement();
1422         clip->setEffectAt(oldPos - 1, act);
1423         clip->setEffectAt(newPos - 1, before);
1424         emit clipItemSelected(clip, newPos - 1);
1425     }
1426     m_document->setModified(true);
1427 }
1428
1429 void CustomTrackView::slotChangeEffectState(ClipItem *clip, int effectPos, bool disable)
1430 {
1431     QDomElement effect = clip->effectAt(effectPos);
1432     QDomElement oldEffect = effect.cloneNode().toElement();
1433     effect.setAttribute("disabled", disable);
1434     EditEffectCommand *command = new EditEffectCommand(this, m_document->tracksCount() - clip->track(), clip->startPos(), oldEffect, effect, effectPos, true);
1435     m_commandStack->push(command);
1436     m_document->setModified(true);
1437 }
1438
1439 void CustomTrackView::slotChangeEffectPosition(ClipItem *clip, int currentPos, int newPos)
1440 {
1441     MoveEffectCommand *command = new MoveEffectCommand(this, m_document->tracksCount() - clip->track(), clip->startPos(), currentPos, newPos);
1442     m_commandStack->push(command);
1443     m_document->setModified(true);
1444 }
1445
1446 void CustomTrackView::slotUpdateClipEffect(ClipItem *clip, QDomElement oldeffect, QDomElement effect, int ix)
1447 {
1448     EditEffectCommand *command = new EditEffectCommand(this, m_document->tracksCount() - clip->track(), clip->startPos(), oldeffect, effect, ix, true);
1449     m_commandStack->push(command);
1450 }
1451
1452 void CustomTrackView::cutClip(ItemInfo info, GenTime cutTime, bool cut)
1453 {
1454     if (cut) {
1455         // cut clip
1456         ClipItem *item = getClipItemAt((int) info.startPos.frames(m_document->fps()) + 1, info.track);
1457         if (!item || cutTime >= item->endPos() || cutTime <= item->startPos()) {
1458             emit displayMessage(i18n("Cannot find clip to cut"), ErrorMessage);
1459             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);
1460             m_blockRefresh = false;
1461             return;
1462         }
1463         if (item->parentItem()) {
1464             // Item is part of a group, reset group
1465             resetSelectionGroup();
1466         }
1467         kDebug() << "/////////  CUTTING CLIP : (" << item->startPos().frames(25) << "-" << item->endPos().frames(25) << "), INFO: (" << info.startPos.frames(25) << "-" << info.endPos.frames(25) << ")" << ", CUT: " << cutTime.frames(25);
1468
1469         m_document->renderer()->mltCutClip(m_document->tracksCount() - info.track, cutTime);
1470         int cutPos = (int) cutTime.frames(m_document->fps());
1471         ItemInfo newPos;
1472         double speed = item->speed();
1473         newPos.startPos = cutTime;
1474         newPos.endPos = info.endPos;
1475         if (speed == 1) newPos.cropStart = item->info().cropStart + (cutTime - info.startPos);
1476         else newPos.cropStart = item->info().cropStart + (cutTime - info.startPos) * speed;
1477         newPos.track = info.track;
1478         ClipItem *dup = item->clone(newPos);
1479         // remove unwanted effects (fade in) from 2nd part of cutted clip
1480         int ix = dup->hasEffect(QString(), "fadein");
1481         if (ix != -1) {
1482             QDomElement oldeffect = item->effectAt(ix);
1483             dup->deleteEffect(oldeffect.attribute("kdenlive_ix"));
1484         }
1485         ix = dup->hasEffect(QString(), "fade_from_black");
1486         if (ix != -1) {
1487             QDomElement oldeffect = item->effectAt(ix);
1488             dup->deleteEffect(oldeffect.attribute("kdenlive_ix"));
1489         }
1490         item->resizeEnd(cutPos, false);
1491         scene()->addItem(dup);
1492         if (item->checkKeyFrames()) slotRefreshEffects(item);
1493         if (dup->checkKeyFrames()) slotRefreshEffects(dup);
1494         item->baseClip()->addReference();
1495         m_document->updateClip(item->baseClip()->getId());
1496         m_document->setModified(true);
1497         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);
1498         kDebug() << "//  CUTTING CLIP dONE";
1499     } else {
1500         // uncut clip
1501
1502         ClipItem *item = getClipItemAt((int) info.startPos.frames(m_document->fps()), info.track);
1503         ClipItem *dup = getClipItemAt((int) cutTime.frames(m_document->fps()) + 1, info.track);
1504         if (!item || !dup || item == dup) {
1505             emit displayMessage(i18n("Cannot find clip to uncut"), ErrorMessage);
1506             m_blockRefresh = false;
1507             return;
1508         }
1509         if (m_document->renderer()->mltRemoveClip(m_document->tracksCount() - info.track, cutTime) == false) {
1510             emit displayMessage(i18n("Error removing clip at %1 on track %2", m_document->timecode().getTimecodeFromFrames(cutTime.frames(m_document->fps())), info.track), ErrorMessage);
1511             return;
1512         }
1513
1514         kDebug() << "// UNCUTTING CLIPS: ITEM 1 (" << item->startPos().frames(25) << "x" << item->endPos().frames(25) << ")";
1515         kDebug() << "// UNCUTTING CLIPS: ITEM 2 (" << dup->startPos().frames(25) << "x" << dup->endPos().frames(25) << ")";
1516         kDebug() << "// UNCUTTING CLIPS, INFO (" << info.startPos.frames(25) << "x" << info.endPos.frames(25) << ") , CUT: " << cutTime.frames(25);;
1517         //deleteClip(dup->info());
1518
1519
1520         if (dup->isSelected()) emit clipItemSelected(NULL);
1521         dup->baseClip()->removeReference();
1522         m_document->updateClip(dup->baseClip()->getId());
1523         scene()->removeItem(dup);
1524         delete dup;
1525
1526         ItemInfo clipinfo = item->info();
1527         clipinfo.track = m_document->tracksCount() - clipinfo.track;
1528         bool success = m_document->renderer()->mltResizeClipEnd(clipinfo, info.endPos - info.startPos);
1529         if (success) {
1530             item->resizeEnd((int) info.endPos.frames(m_document->fps()));
1531             m_document->setModified(true);
1532         } else
1533             emit displayMessage(i18n("Error when resizing clip"), ErrorMessage);
1534
1535     }
1536     QTimer::singleShot(3000, this, SLOT(slotEnableRefresh()));
1537 }
1538
1539 void CustomTrackView::slotEnableRefresh()
1540 {
1541     m_blockRefresh = false;
1542 }
1543
1544 void CustomTrackView::slotAddTransitionToSelectedClips(QDomElement transition)
1545 {
1546     QList<QGraphicsItem *> itemList = scene()->selectedItems();
1547     if (itemList.count() == 1) {
1548         if (itemList.at(0)->type() == AVWIDGET) {
1549             ClipItem *item = (ClipItem *) itemList.at(0);
1550             ItemInfo info;
1551             info.track = item->track();
1552             ClipItem *transitionClip = NULL;
1553             const int transitiontrack = getPreviousVideoTrack(info.track);
1554             GenTime pos = GenTime((int)(mapToScene(m_menuPosition).x()), m_document->fps());
1555             if (pos < item->startPos() + item->duration() / 2) {
1556                 // add transition to clip start
1557                 info.startPos = item->startPos();
1558                 if (transitiontrack != 0) transitionClip = getClipItemAt((int) info.startPos.frames(m_document->fps()), m_document->tracksCount() - transitiontrack);
1559                 if (transitionClip && transitionClip->endPos() < item->endPos()) {
1560                     info.endPos = transitionClip->endPos();
1561                 } else info.endPos = info.startPos + GenTime(65, m_document->fps());
1562                 // Check there is no other transition at that place
1563                 double startY = info.track * m_tracksHeight + 1 + m_tracksHeight / 2;
1564                 QRectF r(info.startPos.frames(m_document->fps()), startY, (info.endPos - info.startPos).frames(m_document->fps()), m_tracksHeight / 2);
1565                 QList<QGraphicsItem *> selection = m_scene->items(r);
1566                 bool transitionAccepted = true;
1567                 for (int i = 0; i < selection.count(); i++) {
1568                     if (selection.at(i)->type() == TRANSITIONWIDGET) {
1569                         Transition *tr = static_cast <Transition *>(selection.at(i));
1570                         if (tr->startPos() - info.startPos > GenTime(5, m_document->fps())) {
1571                             if (tr->startPos() < info.endPos) info.endPos = tr->startPos();
1572                         } else transitionAccepted = false;
1573                     }
1574                 }
1575                 if (transitionAccepted) slotAddTransition(item, info, transitiontrack, transition);
1576                 else emit displayMessage(i18n("Cannot add transition"), ErrorMessage);
1577
1578             } else {
1579                 // add transition to clip  end
1580                 info.endPos = item->endPos();
1581                 if (transitiontrack != 0) transitionClip = getClipItemAt((int) info.endPos.frames(m_document->fps()), m_document->tracksCount() - transitiontrack);
1582                 if (transitionClip && transitionClip->startPos() > item->startPos()) {
1583                     info.startPos = transitionClip->startPos();
1584                 } else info.startPos = info.endPos - GenTime(65, m_document->fps());
1585                 if (transition.attribute("tag") == "luma") EffectsList::setParameter(transition, "reverse", "1");
1586                 else if (transition.attribute("id") == "slide") EffectsList::setParameter(transition, "invert", "1");
1587
1588                 // Check there is no other transition at that place
1589                 double startY = info.track * m_tracksHeight + 1 + m_tracksHeight / 2;
1590                 QRectF r(info.startPos.frames(m_document->fps()), startY, (info.endPos - info.startPos).frames(m_document->fps()), m_tracksHeight / 2);
1591                 QList<QGraphicsItem *> selection = m_scene->items(r);
1592                 bool transitionAccepted = true;
1593                 for (int i = 0; i < selection.count(); i++) {
1594                     if (selection.at(i)->type() == TRANSITIONWIDGET) {
1595                         Transition *tr = static_cast <Transition *>(selection.at(i));
1596                         if (info.endPos - tr->endPos() > GenTime(5, m_document->fps())) {
1597                             if (tr->endPos() > info.startPos) info.startPos = tr->endPos();
1598                         } else transitionAccepted = false;
1599                     }
1600                 }
1601                 if (transitionAccepted) slotAddTransition(item, info, transitiontrack, transition);
1602                 else emit displayMessage(i18n("Cannot add transition"), ErrorMessage);
1603             }
1604         }
1605     } else for (int i = 0; i < itemList.count(); i++) {
1606             if (itemList.at(i)->type() == AVWIDGET) {
1607                 ClipItem *item = (ClipItem *) itemList.at(i);
1608                 ItemInfo info;
1609                 info.startPos = item->startPos();
1610                 info.endPos = info.startPos + GenTime(65, m_document->fps());
1611                 info.track = item->track();
1612
1613                 // Check there is no other transition at that place
1614                 double startY = info.track * m_tracksHeight + 1 + m_tracksHeight / 2;
1615                 QRectF r(info.startPos.frames(m_document->fps()), startY, (info.endPos - info.startPos).frames(m_document->fps()), m_tracksHeight / 2);
1616                 QList<QGraphicsItem *> selection = m_scene->items(r);
1617                 bool transitionAccepted = true;
1618                 for (int i = 0; i < selection.count(); i++) {
1619                     if (selection.at(i)->type() == TRANSITIONWIDGET) {
1620                         Transition *tr = static_cast <Transition *>(selection.at(i));
1621                         if (tr->startPos() - info.startPos > GenTime(5, m_document->fps())) {
1622                             if (tr->startPos() < info.endPos) info.endPos = tr->startPos();
1623                         } else transitionAccepted = false;
1624                     }
1625                 }
1626                 int transitiontrack = getPreviousVideoTrack(info.track);
1627                 if (transitionAccepted) slotAddTransition(item, info, transitiontrack, transition);
1628                 else emit displayMessage(i18n("Cannot add transition"), ErrorMessage);
1629             }
1630         }
1631 }
1632
1633 void CustomTrackView::slotAddTransition(ClipItem* /*clip*/, ItemInfo transitionInfo, int endTrack, QDomElement transition)
1634 {
1635     if (transitionInfo.startPos >= transitionInfo.endPos) {
1636         emit displayMessage(i18n("Invalid transition"), ErrorMessage);
1637         return;
1638     }
1639     AddTransitionCommand* command = new AddTransitionCommand(this, transitionInfo, endTrack, transition, false, true);
1640     m_commandStack->push(command);
1641     m_document->setModified(true);
1642 }
1643
1644 void CustomTrackView::addTransition(ItemInfo transitionInfo, int endTrack, QDomElement params)
1645 {
1646     Transition *tr = new Transition(transitionInfo, endTrack, m_document->fps(), params, true);
1647     //kDebug() << "---- ADDING transition " << params.attribute("value");
1648     if (m_document->renderer()->mltAddTransition(tr->transitionTag(), endTrack, m_document->tracksCount() - transitionInfo.track, transitionInfo.startPos, transitionInfo.endPos, tr->toXML())) {
1649         scene()->addItem(tr);
1650         m_document->setModified(true);
1651     } else {
1652         emit displayMessage(i18n("Cannot add transition"), ErrorMessage);
1653         delete tr;
1654     }
1655 }
1656
1657 void CustomTrackView::deleteTransition(ItemInfo transitionInfo, int endTrack, QDomElement /*params*/)
1658 {
1659     Transition *item = getTransitionItemAt(transitionInfo.startPos, transitionInfo.track);
1660     if (!item) {
1661         emit displayMessage(i18n("Select clip to delete"), ErrorMessage);
1662         return;
1663     }
1664     m_document->renderer()->mltDeleteTransition(item->transitionTag(), endTrack, m_document->tracksCount() - transitionInfo.track, transitionInfo.startPos, transitionInfo.endPos, item->toXML());
1665     if (m_dragItem == item) m_dragItem = NULL;
1666     delete item;
1667     emit transitionItemSelected(NULL);
1668     m_document->setModified(true);
1669 }
1670
1671 void CustomTrackView::slotTransitionUpdated(Transition *tr, QDomElement old)
1672 {
1673     kDebug() << "TRANS UPDATE, TRACKS: " << old.attribute("transition_btrack") << ", NEW: " << tr->toXML().attribute("transition_btrack");
1674     EditTransitionCommand *command = new EditTransitionCommand(this, tr->track(), tr->startPos(), old, tr->toXML(), false);
1675     m_commandStack->push(command);
1676     m_document->setModified(true);
1677 }
1678
1679 void CustomTrackView::updateTransition(int track, GenTime pos, QDomElement oldTransition, QDomElement transition, bool updateTransitionWidget)
1680 {
1681     Transition *item = getTransitionItemAt(pos, track);
1682     if (!item) {
1683         kWarning() << "Unable to find transition at pos :" << pos.frames(m_document->fps()) << ", ON track: " << track;
1684         return;
1685     }
1686     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);
1687     //kDebug() << "ORIGINAL TRACK: "<< oldTransition.attribute("transition_btrack") << ", NEW TRACK: "<<transition.attribute("transition_btrack");
1688     item->setTransitionParameters(transition);
1689     if (updateTransitionWidget) {
1690         ItemInfo info = item->info();
1691         QPoint p;
1692         ClipItem *transitionClip = getClipItemAt(info.startPos, info.track);
1693         if (transitionClip && transitionClip->baseClip()) {
1694             QString size = transitionClip->baseClip()->getProperty("frame_size");
1695             p.setX(size.section('x', 0, 0).toInt());
1696             p.setY(size.section('x', 1, 1).toInt());
1697         }
1698         emit transitionItemSelected(item, getPreviousVideoTrack(info.track), p, true);
1699     }
1700     m_document->setModified(true);
1701 }
1702
1703 void CustomTrackView::dragMoveEvent(QDragMoveEvent * event)
1704 {
1705     event->setDropAction(Qt::IgnoreAction);
1706     const QPointF pos = mapToScene(event->pos());
1707     if (m_selectionGroup && m_clipDrag) {
1708         m_selectionGroup->setPos(pos.x(), pos.y());
1709         emit mousePosition((int)(m_selectionGroup->scenePos().x() + 0.5));
1710         event->setDropAction(Qt::MoveAction);
1711         event->acceptProposedAction();
1712     } else {
1713         QGraphicsView::dragMoveEvent(event);
1714     }
1715 }
1716
1717 void CustomTrackView::dragLeaveEvent(QDragLeaveEvent * event)
1718 {
1719     if (m_selectionGroup && m_clipDrag) {
1720         m_thumbsTimer.stop();
1721         m_waitingThumbs.clear();
1722         QList<QGraphicsItem *> items = m_selectionGroup->childItems();
1723         qDeleteAll(items);
1724         scene()->destroyItemGroup(m_selectionGroup);
1725         m_selectionGroup = NULL;
1726     } else QGraphicsView::dragLeaveEvent(event);
1727 }
1728
1729 void CustomTrackView::dropEvent(QDropEvent * event)
1730 {
1731     if (m_selectionGroup && m_clipDrag) {
1732         QList<QGraphicsItem *> items = m_selectionGroup->childItems();
1733         resetSelectionGroup();
1734         m_scene->clearSelection();
1735         bool hasVideoClip = false;
1736         QUndoCommand *addCommand = new QUndoCommand();
1737         addCommand->setText(i18n("Add timeline clip"));
1738
1739         for (int i = 0; i < items.count(); i++) {
1740             ClipItem *item = static_cast <ClipItem *>(items.at(i));
1741             if (!hasVideoClip && (item->clipType() == AV || item->clipType() == VIDEO)) hasVideoClip = true;
1742             if (items.count() == 1) {
1743                 updateClipTypeActions(item);
1744             } else {
1745                 updateClipTypeActions(NULL);
1746             }
1747
1748             new AddTimelineClipCommand(this, item->xml(), item->clipProducer(), item->info(), item->effectList(), false, false, addCommand);
1749             item->baseClip()->addReference();
1750             m_document->updateClip(item->baseClip()->getId());
1751             ItemInfo info = item->info();
1752
1753             int tracknumber = m_document->tracksCount() - info.track - 1;
1754             bool isLocked = m_document->trackInfoAt(tracknumber).isLocked;
1755             if (isLocked) item->setItemLocked(true);
1756
1757             if (item->baseClip()->isTransparent() && getTransitionItemAtStart(info.startPos, info.track) == NULL) {
1758                 // add transparency transition
1759                 new AddTransitionCommand(this, info, getPreviousVideoTrack(info.track), MainWindow::transitions.getEffectByTag("composite", "composite"), false, true, addCommand);
1760             }
1761             info.track = m_document->tracksCount() - item->track();
1762             m_document->renderer()->mltInsertClip(info, item->xml(), item->baseClip()->producer(item->track()));
1763             item->setSelected(true);
1764         }
1765         m_commandStack->push(addCommand);
1766         m_document->setModified(true);
1767         m_changeSpeedAction->setEnabled(hasVideoClip);
1768         m_pasteEffectsAction->setEnabled(m_copiedItems.count() == 1);
1769         if (items.count() > 1) groupSelectedItems(true);
1770     } else QGraphicsView::dropEvent(event);
1771     setFocus();
1772 }
1773
1774
1775 QStringList CustomTrackView::mimeTypes() const
1776 {
1777     QStringList qstrList;
1778     // list of accepted mime types for drop
1779     qstrList.append("text/plain");
1780     qstrList.append("kdenlive/producerslist");
1781     qstrList.append("kdenlive/clip");
1782     return qstrList;
1783 }
1784
1785 Qt::DropActions CustomTrackView::supportedDropActions() const
1786 {
1787     // returns what actions are supported when dropping
1788     return Qt::MoveAction;
1789 }
1790
1791 void CustomTrackView::setDuration(int duration)
1792 {
1793     int diff = qAbs(duration - sceneRect().width());
1794     if (diff * matrix().m11() > -50) {
1795         if (matrix().m11() < 0.4) setSceneRect(0, 0, (duration + 100 / matrix().m11()), sceneRect().height());
1796         else setSceneRect(0, 0, (duration + 300), sceneRect().height());
1797     }
1798     m_projectDuration = duration;
1799 }
1800
1801 int CustomTrackView::duration() const
1802 {
1803     return m_projectDuration;
1804 }
1805
1806 void CustomTrackView::addTrack(TrackInfo type, int ix)
1807 {
1808     if (ix == -1 || ix == m_document->tracksCount()) {
1809         m_document->insertTrack(ix, type);
1810         m_document->renderer()->mltInsertTrack(1, type.type == VIDEOTRACK);
1811     } else {
1812         m_document->insertTrack(m_document->tracksCount() - ix, type);
1813         // insert track in MLT playlist
1814         m_document->renderer()->mltInsertTrack(m_document->tracksCount() - ix, type.type == VIDEOTRACK);
1815
1816         double startY = ix * m_tracksHeight + 1 + m_tracksHeight / 2;
1817         QRectF r(0, startY, sceneRect().width(), sceneRect().height() - startY);
1818         QList<QGraphicsItem *> selection = m_scene->items(r);
1819         resetSelectionGroup();
1820
1821         m_selectionGroup = new AbstractGroupItem(m_document->fps());
1822         scene()->addItem(m_selectionGroup);
1823         for (int i = 0; i < selection.count(); i++) {
1824             if (selection.at(i)->type() == AVWIDGET || selection.at(i)->type() == TRANSITIONWIDGET)
1825                 m_selectionGroup->addToGroup(selection.at(i));
1826             selection.at(i)->setFlags(QGraphicsItem::ItemIsSelectable);
1827         }
1828         // Move graphic items
1829         m_selectionGroup->translate(0, m_tracksHeight);
1830
1831         // adjust track number
1832         QList<QGraphicsItem *> children = m_selectionGroup->childItems();
1833         for (int i = 0; i < children.count(); i++) {
1834             AbstractClipItem *item = static_cast <AbstractClipItem *>(children.at(i));
1835             item->updateItem();
1836             ItemInfo clipinfo = item->info();
1837             if (item->type() == AVWIDGET) {
1838                 ClipItem *clip = static_cast <ClipItem *>(item);
1839                 // We add a move clip command so that we get the correct producer for new track number
1840                 if (clip->clipType() == AV || clip->clipType() == AUDIO) {
1841                     Mlt::Producer *prod;
1842                     if (clip->isAudioOnly()) prod = clip->baseClip()->audioProducer(clipinfo.track);
1843                     else if (clip->isVideoOnly()) prod = clip->baseClip()->videoProducer();
1844                     else prod = clip->baseClip()->producer(clipinfo.track);
1845                     m_document->renderer()->mltUpdateClipProducer((int)(m_document->tracksCount() - clipinfo.track), clipinfo.startPos.frames(m_document->fps()), prod);
1846                     kDebug() << "// UPDATING CLIP TO TRACK PROD: " << clipinfo.track;
1847                 }
1848             } else if (item->type() == TRANSITIONWIDGET) {
1849                 Transition *tr = static_cast <Transition *>(item);
1850                 int track = tr->transitionEndTrack();
1851                 if (track >= ix) {
1852                     tr->updateTransitionEndTrack(getPreviousVideoTrack(clipinfo.track));
1853                 }
1854             }
1855         }
1856         resetSelectionGroup(false);
1857
1858     }
1859     int maxHeight = m_tracksHeight * m_document->tracksCount();
1860     for (int i = 0; i < m_guides.count(); i++) {
1861         QLineF l = m_guides.at(i)->line();
1862         l.setP2(QPointF(l.x2(), maxHeight));
1863         m_guides.at(i)->setLine(l);
1864     }
1865     m_cursorLine->setLine(m_cursorLine->line().x1(), 0, m_cursorLine->line().x1(), maxHeight);
1866     setSceneRect(0, 0, sceneRect().width(), maxHeight);
1867     QTimer::singleShot(300, this, SIGNAL(trackHeightChanged()));
1868     viewport()->update();
1869     //setFixedHeight(50 * m_tracksCount);
1870 }
1871
1872 void CustomTrackView::removeTrack(int ix)
1873 {
1874     // Delete track in MLT playlist
1875     m_document->renderer()->mltDeleteTrack(m_document->tracksCount() - ix);
1876     m_document->deleteTrack(m_document->tracksCount() - ix - 1);
1877
1878     double startY = ix * (m_tracksHeight + 1) + m_tracksHeight / 2;
1879     QRectF r(0, startY, sceneRect().width(), sceneRect().height() - startY);
1880     QList<QGraphicsItem *> selection = m_scene->items(r);
1881
1882     resetSelectionGroup();
1883
1884     m_selectionGroup = new AbstractGroupItem(m_document->fps());
1885     scene()->addItem(m_selectionGroup);
1886     for (int i = 0; i < selection.count(); i++) {
1887         if (selection.at(i)->type() == AVWIDGET || selection.at(i)->type() == TRANSITIONWIDGET) {
1888             m_selectionGroup->addToGroup(selection.at(i));
1889             selection.at(i)->setFlags(QGraphicsItem::ItemIsSelectable);
1890         }
1891     }
1892     // Move graphic items
1893     qreal ydiff = 0 - (int) m_tracksHeight;
1894     m_selectionGroup->translate(0, ydiff);
1895
1896     // adjust track number
1897     QList<QGraphicsItem *> children = m_selectionGroup->childItems();
1898     //kDebug() << "// FOUND CLIPS TO MOVE: " << children.count();
1899     for (int i = 0; i < children.count(); i++) {
1900         if (children.at(i)->type() == AVWIDGET) {
1901             ClipItem *clip = static_cast <ClipItem *>(children.at(i));
1902             clip->updateItem();
1903             ItemInfo clipinfo = clip->info();
1904             // We add a move clip command so that we get the correct producer for new track number
1905             if (clip->clipType() == AV || clip->clipType() == AUDIO) {
1906                 Mlt::Producer *prod;
1907                 if (clip->isAudioOnly()) prod = clip->baseClip()->audioProducer(clipinfo.track);
1908                 else if (clip->isVideoOnly()) prod = clip->baseClip()->videoProducer();
1909                 else prod = clip->baseClip()->producer(clipinfo.track);
1910                 m_document->renderer()->mltUpdateClipProducer((int)(m_document->tracksCount() - clipinfo.track), clipinfo.startPos.frames(m_document->fps()), prod);
1911             }
1912         } else if (children.at(i)->type() == TRANSITIONWIDGET) {
1913             Transition *tr = static_cast <Transition *>(children.at(i));
1914             tr->updateItem();
1915             int track = tr->transitionEndTrack();
1916             if (track >= ix) {
1917                 ItemInfo clipinfo = tr->info();
1918                 tr->updateTransitionEndTrack(getPreviousVideoTrack(clipinfo.track));
1919             }
1920         }
1921     }
1922     resetSelectionGroup(false);
1923
1924     int maxHeight = m_tracksHeight * m_document->tracksCount();
1925     for (int i = 0; i < m_guides.count(); i++) {
1926         QLineF l = m_guides.at(i)->line();
1927         l.setP2(QPointF(l.x2(), maxHeight));
1928         m_guides.at(i)->setLine(l);
1929     }
1930     m_cursorLine->setLine(m_cursorLine->line().x1(), 0, m_cursorLine->line().x1(), maxHeight);
1931     setSceneRect(0, 0, sceneRect().width(), maxHeight);
1932     QTimer::singleShot(300, this, SIGNAL(trackHeightChanged()));
1933     viewport()->update();
1934 }
1935
1936 void CustomTrackView::changeTrack(int ix, TrackInfo type)
1937 {
1938     int tracknumber = m_document->tracksCount() - ix;
1939     m_document->setTrackType(tracknumber - 1, type);
1940     m_document->renderer()->mltChangeTrackState(tracknumber, m_document->trackInfoAt(tracknumber - 1).isMute, m_document->trackInfoAt(tracknumber - 1).isBlind);
1941     QTimer::singleShot(300, this, SIGNAL(trackHeightChanged()));
1942     viewport()->update();
1943 }
1944
1945
1946 void CustomTrackView::slotSwitchTrackAudio(int ix)
1947 {
1948     /*for (int i = 0; i < m_document->tracksCount(); i++)
1949         kDebug() << "TRK " << i << " STATE: " << m_document->trackInfoAt(i).isMute << m_document->trackInfoAt(i).isBlind;*/
1950     int tracknumber = m_document->tracksCount() - ix - 1;
1951     m_document->switchTrackAudio(tracknumber, !m_document->trackInfoAt(tracknumber).isMute);
1952     kDebug() << "NEXT TRK STATE: " << m_document->trackInfoAt(tracknumber).isMute << m_document->trackInfoAt(tracknumber).isBlind;
1953     m_document->renderer()->mltChangeTrackState(tracknumber + 1, m_document->trackInfoAt(tracknumber).isMute, m_document->trackInfoAt(tracknumber).isBlind);
1954     m_document->setModified(true);
1955 }
1956
1957 void CustomTrackView::slotSwitchTrackLock(int ix)
1958 {
1959     int tracknumber = m_document->tracksCount() - ix - 1;
1960     LockTrackCommand *command = new LockTrackCommand(this, ix, !m_document->trackInfoAt(tracknumber).isLocked);
1961     m_commandStack->push(command);
1962 }
1963
1964
1965 void CustomTrackView::lockTrack(int ix, bool lock)
1966 {
1967     int tracknumber = m_document->tracksCount() - ix - 1;
1968     m_document->switchTrackLock(tracknumber, lock);
1969     emit doTrackLock(ix, lock);
1970     QList<QGraphicsItem *> selection = m_scene->items(0, ix * m_tracksHeight + m_tracksHeight / 2, sceneRect().width(), m_tracksHeight / 2 - 2);
1971
1972     for (int i = 0; i < selection.count(); i++) {
1973         if (selection.at(i)->type() != AVWIDGET && selection.at(i)->type() != TRANSITIONWIDGET) continue;
1974         if (selection.at(i)->isSelected()) {
1975             if (selection.at(i)->type() == AVWIDGET) emit clipItemSelected(NULL);
1976             else emit transitionItemSelected(NULL);
1977         }
1978         static_cast <AbstractClipItem *>(selection.at(i))->setItemLocked(lock);
1979     }
1980     kDebug() << "NEXT TRK STATE: " << m_document->trackInfoAt(tracknumber).isLocked;
1981     viewport()->update();
1982     m_document->setModified(true);
1983 }
1984
1985 void CustomTrackView::slotSwitchTrackVideo(int ix)
1986 {
1987     int tracknumber = m_document->tracksCount() - ix;
1988     m_document->switchTrackVideo(tracknumber - 1, !m_document->trackInfoAt(tracknumber - 1).isBlind);
1989     m_document->renderer()->mltChangeTrackState(tracknumber, m_document->trackInfoAt(tracknumber - 1).isMute, m_document->trackInfoAt(tracknumber - 1).isBlind);
1990     m_document->setModified(true);
1991 }
1992
1993 void CustomTrackView::slotRemoveSpace()
1994 {
1995     GenTime pos;
1996     int track = 0;
1997     if (m_menuPosition.isNull()) {
1998         pos = GenTime(cursorPos(), m_document->fps());
1999         bool ok;
2000         track = QInputDialog::getInteger(this, i18n("Remove Space"), i18n("Track"), 0, 0, m_document->tracksCount() - 1, 1, &ok);
2001         if (!ok) return;
2002     } else {
2003         pos = GenTime((int)(mapToScene(m_menuPosition).x()), m_document->fps());
2004         track = (int)(mapToScene(m_menuPosition).y() / m_tracksHeight);
2005     }
2006     ClipItem *item = getClipItemAt(pos, track);
2007     if (item) {
2008         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);
2009         return;
2010     }
2011     int length = m_document->renderer()->mltGetSpaceLength(pos, m_document->tracksCount() - track, true);
2012     //kDebug() << "// GOT LENGT; " << length;
2013     if (length <= 0) {
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
2018     QRectF r(pos.frames(m_document->fps()), track * m_tracksHeight + m_tracksHeight / 2, sceneRect().width() - pos.frames(m_document->fps()), m_tracksHeight / 2 - 1);
2019     QList<QGraphicsItem *> items = m_scene->items(r);
2020
2021     QList<ItemInfo> clipsToMove;
2022     QList<ItemInfo> transitionsToMove;
2023
2024     for (int i = 0; i < items.count(); i++) {
2025         if (items.at(i)->type() == AVWIDGET || items.at(i)->type() == TRANSITIONWIDGET) {
2026             AbstractClipItem *item = static_cast <AbstractClipItem *>(items.at(i));
2027             ItemInfo info = item->info();
2028             if (item->type() == AVWIDGET) {
2029                 clipsToMove.append(info);
2030             } else if (item->type() == TRANSITIONWIDGET) {
2031                 transitionsToMove.append(info);
2032             }
2033         }
2034     }
2035
2036     InsertSpaceCommand *command = new InsertSpaceCommand(this, clipsToMove, transitionsToMove, track, GenTime(-length, m_document->fps()), true);
2037     m_commandStack->push(command);
2038 }
2039
2040 void CustomTrackView::slotInsertSpace()
2041 {
2042     GenTime pos;
2043     int track = 0;
2044     if (m_menuPosition.isNull()) {
2045         pos = GenTime(cursorPos(), m_document->fps());
2046     } else {
2047         pos = GenTime((int)(mapToScene(m_menuPosition).x()), m_document->fps());
2048         track = (int)(mapToScene(m_menuPosition).y() / m_tracksHeight) + 1;
2049     }
2050     SpacerDialog d(GenTime(65, m_document->fps()), m_document->timecode(), track, m_document->tracksCount(), this);
2051     if (d.exec() != QDialog::Accepted) return;
2052     GenTime spaceDuration = d.selectedDuration();
2053     track = d.selectedTrack();
2054     ClipItem *item = getClipItemAt(pos, track);
2055     if (item) pos = item->startPos();
2056
2057     int minh = 0;
2058     int maxh = sceneRect().height();
2059     if (track != -1) {
2060         minh = track * m_tracksHeight + m_tracksHeight / 2;
2061         maxh = m_tracksHeight / 2 - 1;
2062     }
2063
2064     QRectF r(pos.frames(m_document->fps()), minh, sceneRect().width() - pos.frames(m_document->fps()), maxh);
2065     QList<QGraphicsItem *> items = m_scene->items(r);
2066
2067     QList<ItemInfo> clipsToMove;
2068     QList<ItemInfo> transitionsToMove;
2069
2070     for (int i = 0; i < items.count(); i++) {
2071         if (items.at(i)->type() == AVWIDGET || items.at(i)->type() == TRANSITIONWIDGET) {
2072             AbstractClipItem *item = static_cast <AbstractClipItem *>(items.at(i));
2073             ItemInfo info = item->info();
2074             if (item->type() == AVWIDGET) {
2075                 clipsToMove.append(info);
2076             } else if (item->type() == TRANSITIONWIDGET) {
2077                 transitionsToMove.append(info);
2078             }
2079         }
2080     }
2081
2082     InsertSpaceCommand *command = new InsertSpaceCommand(this, clipsToMove, transitionsToMove, track, spaceDuration, true);
2083     m_commandStack->push(command);
2084 }
2085
2086 void CustomTrackView::insertSpace(QList<ItemInfo> clipsToMove, QList<ItemInfo> transToMove, int track, const GenTime duration, const GenTime offset)
2087 {
2088     int diff = duration.frames(m_document->fps());
2089     resetSelectionGroup();
2090     m_selectionGroup = new AbstractGroupItem(m_document->fps());
2091     scene()->addItem(m_selectionGroup);
2092     ClipItem *clip;
2093     Transition *transition;
2094
2095     // Create lists with start pos for each track
2096     QMap <int, int> trackClipStartList;
2097     QMap <int, int> trackTransitionStartList;
2098
2099     for (int i = 1; i < m_document->tracksCount() + 1; i++) {
2100         trackClipStartList[i] = -1;
2101         trackTransitionStartList[i] = -1;
2102     }
2103
2104     if (!clipsToMove.isEmpty()) for (int i = 0; i < clipsToMove.count(); i++) {
2105             clip = getClipItemAtStart(clipsToMove.at(i).startPos + offset, clipsToMove.at(i).track);
2106             if (clip) {
2107                 if (clip->parentItem()) {
2108                     m_selectionGroup->addToGroup(clip->parentItem());
2109                     clip->parentItem()->setFlags(QGraphicsItem::ItemIsSelectable);
2110                 } else {
2111                     m_selectionGroup->addToGroup(clip);
2112                     clip->setFlags(QGraphicsItem::ItemIsSelectable);
2113                 }
2114                 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))
2115                     trackClipStartList[m_document->tracksCount() - clipsToMove.at(i).track] = clipsToMove.at(i).startPos.frames(m_document->fps());
2116             } 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);
2117         }
2118     if (!transToMove.isEmpty()) for (int i = 0; i < transToMove.count(); i++) {
2119             transition = getTransitionItemAtStart(transToMove.at(i).startPos + offset, transToMove.at(i).track);
2120             if (transition) {
2121                 if (transition->parentItem()) m_selectionGroup->addToGroup(transition->parentItem());
2122                 m_selectionGroup->addToGroup(transition);
2123                 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))
2124                     trackTransitionStartList[m_document->tracksCount() - transToMove.at(i).track] = transToMove.at(i).startPos.frames(m_document->fps());
2125                 transition->setFlags(QGraphicsItem::ItemIsSelectable);
2126             } 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);
2127         }
2128     m_selectionGroup->translate(diff, 0);
2129
2130     // update items coordinates
2131     QList<QGraphicsItem *> itemList = scene()->selectedItems();
2132     for (int i = 0; i < itemList.count(); i++) {
2133         if (itemList.at(i)->type() == AVWIDGET || itemList.at(i)->type() == TRANSITIONWIDGET) {
2134             static_cast < AbstractClipItem *>(itemList.at(i))->updateItem();
2135         } else if (itemList.at(i)->type() == GROUPWIDGET) {
2136             QList<QGraphicsItem *> children = itemList.at(i)->childItems();
2137             for (int j = 0; j < children.count(); j++) {
2138                 static_cast < AbstractClipItem *>(children.at(j))->updateItem();
2139             }
2140         }
2141     }
2142     resetSelectionGroup(false);
2143     if (track != -1) track = m_document->tracksCount() - track;
2144     m_document->renderer()->mltInsertSpace(trackClipStartList, trackTransitionStartList, track, duration, offset);
2145 }
2146
2147 void CustomTrackView::deleteClip(const QString &clipId)
2148 {
2149     resetSelectionGroup();
2150     QList<QGraphicsItem *> itemList = items();
2151     QUndoCommand *deleteCommand = new QUndoCommand();
2152     deleteCommand->setText(i18n("Delete timeline clips"));
2153     int count = 0;
2154     for (int i = 0; i < itemList.count(); i++) {
2155         if (itemList.at(i)->type() == AVWIDGET) {
2156             ClipItem *item = (ClipItem *)itemList.at(i);
2157             if (item->clipProducer() == clipId) {
2158                 count++;
2159                 if (item->parentItem()) {
2160                     // Clip is in a group, destroy the group
2161                     new GroupClipsCommand(this, QList<ItemInfo>() << item->info(), QList<ItemInfo>(), false, deleteCommand);
2162                 }
2163                 new AddTimelineClipCommand(this, item->xml(), item->clipProducer(), item->info(), item->effectList(), true, true, deleteCommand);
2164             }
2165         }
2166     }
2167     if (count == 0) delete deleteCommand;
2168     else m_commandStack->push(deleteCommand);
2169 }
2170
2171 void CustomTrackView::setCursorPos(int pos, bool seek)
2172 {
2173     if (pos == m_cursorPos) return;
2174     emit cursorMoved((int)(m_cursorPos), (int)(pos));
2175     m_cursorPos = pos;
2176     if (seek) m_document->renderer()->seek(GenTime(m_cursorPos, m_document->fps()));
2177     else if (m_autoScroll) checkScrolling();
2178     m_cursorLine->setPos(m_cursorPos, 0);
2179 }
2180
2181 void CustomTrackView::updateCursorPos()
2182 {
2183     m_cursorLine->setPos(m_cursorPos, 0);
2184 }
2185
2186 int CustomTrackView::cursorPos()
2187 {
2188     return (int)(m_cursorPos);
2189 }
2190
2191 void CustomTrackView::moveCursorPos(int delta)
2192 {
2193     if (m_cursorPos + delta < 0) delta = 0 - m_cursorPos;
2194     emit cursorMoved((int)(m_cursorPos), (int)((m_cursorPos + delta)));
2195     m_cursorPos += delta;
2196     m_cursorLine->setPos(m_cursorPos, 0);
2197     m_document->renderer()->seek(GenTime(m_cursorPos, m_document->fps()));
2198 }
2199
2200 void CustomTrackView::initCursorPos(int pos)
2201 {
2202     emit cursorMoved((int)(m_cursorPos), (int)(pos));
2203     m_cursorPos = pos;
2204     m_cursorLine->setPos(pos, 0);
2205     checkScrolling();
2206 }
2207
2208 void CustomTrackView::checkScrolling()
2209 {
2210     ensureVisible(m_cursorPos, verticalScrollBar()->value() + 10, 2, 2, 50, 0);
2211 }
2212
2213 void CustomTrackView::mouseReleaseEvent(QMouseEvent * event)
2214 {
2215     if (m_moveOpMode == SEEK) m_moveOpMode = NONE;
2216     QGraphicsView::mouseReleaseEvent(event);
2217     if (m_scrollTimer.isActive()) m_scrollTimer.stop();
2218     if (event->button() == Qt::MidButton) {
2219         return;
2220     }
2221     setDragMode(QGraphicsView::NoDrag);
2222     if (m_operationMode == MOVEGUIDE) {
2223         setCursor(Qt::ArrowCursor);
2224         m_operationMode = NONE;
2225         m_dragGuide->setFlag(QGraphicsItem::ItemIsMovable, false);
2226         GenTime newPos = GenTime(m_dragGuide->pos().x(), m_document->fps());
2227         if (newPos != m_dragGuide->position()) {
2228             EditGuideCommand *command = new EditGuideCommand(this, m_dragGuide->position(), m_dragGuide->label(), newPos, m_dragGuide->label(), false);
2229             m_commandStack->push(command);
2230             m_dragGuide->updateGuide(GenTime(m_dragGuide->pos().x(), m_document->fps()));
2231             m_document->syncGuides(m_guides);
2232         }
2233         m_dragGuide = NULL;
2234         m_dragItem = NULL;
2235         return;
2236     } else if (m_operationMode == SPACER) {
2237         int track;
2238         if (event->modifiers() != Qt::ControlModifier) {
2239             // We are moving all tracks
2240             track = -1;
2241         } else track = (int)(mapToScene(m_clickEvent).y() / m_tracksHeight);
2242         GenTime timeOffset = GenTime(m_selectionGroup->scenePos().x(), m_document->fps()) - m_selectionGroupInfo.startPos;
2243         if (timeOffset != GenTime()) {
2244             QList<QGraphicsItem *> items = m_selectionGroup->childItems();
2245
2246             QList<ItemInfo> clipsToMove;
2247             QList<ItemInfo> transitionsToMove;
2248
2249             // Create lists with start pos for each track
2250             QMap <int, int> trackClipStartList;
2251             QMap <int, int> trackTransitionStartList;
2252
2253             for (int i = 1; i < m_document->tracksCount() + 1; i++) {
2254                 trackClipStartList[i] = -1;
2255                 trackTransitionStartList[i] = -1;
2256             }
2257
2258             int max = items.count();
2259             for (int i = 0; i < max; i++) {
2260                 if (items.at(i)->type() == GROUPWIDGET)
2261                     items += static_cast <QGraphicsItemGroup *>(items.at(i))->childItems();
2262             }
2263
2264             for (int i = 0; i < items.count(); i++) {
2265                 if (items.at(i)->type() == AVWIDGET) {
2266                     AbstractClipItem *item = static_cast <AbstractClipItem *>(items.at(i));
2267                     ItemInfo info = item->info();
2268                     clipsToMove.append(info);
2269                     item->updateItem();
2270                     if (trackClipStartList.value(m_document->tracksCount() - info.track) == -1 || info.startPos.frames(m_document->fps()) < trackClipStartList.value(m_document->tracksCount() - info.track))
2271                         trackClipStartList[m_document->tracksCount() - info.track] = info.startPos.frames(m_document->fps());
2272                 } else if (items.at(i)->type() == TRANSITIONWIDGET) {
2273                     AbstractClipItem *item = static_cast <AbstractClipItem *>(items.at(i));
2274                     ItemInfo info = item->info();
2275                     transitionsToMove.append(info);
2276                     item->updateItem();
2277                     if (trackTransitionStartList.value(m_document->tracksCount() - info.track) == -1 || info.startPos.frames(m_document->fps()) < trackTransitionStartList.value(m_document->tracksCount() - info.track))
2278                         trackTransitionStartList[m_document->tracksCount() - info.track] = info.startPos.frames(m_document->fps());
2279                 }
2280             }
2281
2282             InsertSpaceCommand *command = new InsertSpaceCommand(this, clipsToMove, transitionsToMove, track, timeOffset, false);
2283             m_commandStack->push(command);
2284             if (track != -1) track = m_document->tracksCount() - track;
2285             kDebug() << "SPACER TRACK:" << track;
2286             m_document->renderer()->mltInsertSpace(trackClipStartList, trackTransitionStartList, track, timeOffset, GenTime());
2287         }
2288         resetSelectionGroup(false);
2289         m_operationMode = NONE;
2290     } else if (m_operationMode == RUBBERSELECTION) {
2291         kDebug() << "// END RUBBER SELECT";
2292         resetSelectionGroup();
2293         groupSelectedItems();
2294         m_operationMode = NONE;
2295     }
2296
2297     if (m_dragItem == NULL && m_selectionGroup == NULL) {
2298         emit transitionItemSelected(NULL);
2299         return;
2300     }
2301     ItemInfo info;
2302     if (m_dragItem) info = m_dragItem->info();
2303
2304     if (m_operationMode == MOVE) {
2305         setCursor(Qt::OpenHandCursor);
2306
2307         if (m_dragItem->parentItem() == 0) {
2308             // we are moving one clip, easy
2309             if (m_dragItem->type() == AVWIDGET && (m_dragItemInfo.startPos != info.startPos || m_dragItemInfo.track != info.track)) {
2310                 ClipItem *item = static_cast <ClipItem *>(m_dragItem);
2311                 Mlt::Producer *prod;
2312                 if (item->isAudioOnly()) prod = item->baseClip()->audioProducer(m_dragItemInfo.track);
2313                 else if (item->isVideoOnly()) prod = item->baseClip()->videoProducer();
2314                 else prod = item->baseClip()->producer(m_dragItemInfo.track);
2315                 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);
2316                 if (success) {
2317                     kDebug() << "// get trans info";
2318                     int tracknumber = m_document->tracksCount() - item->track() - 1;
2319                     bool isLocked = m_document->trackInfoAt(tracknumber).isLocked;
2320                     if (isLocked) item->setItemLocked(true);
2321
2322                     QUndoCommand *moveCommand = new QUndoCommand();
2323                     moveCommand->setText(i18n("Move clip"));
2324                     new MoveClipCommand(this, m_dragItemInfo, info, false, moveCommand);
2325                     // Also move automatic transitions (on lower track)
2326                     Transition *tr = getTransitionItemAtStart(m_dragItemInfo.startPos, m_dragItemInfo.track);
2327                     kDebug() << "// get trans info2";
2328                     if (tr && tr->isAutomatic()) {
2329                         ItemInfo trInfo = tr->info();
2330                         ItemInfo newTrInfo = trInfo;
2331                         newTrInfo.track = info.track;
2332                         newTrInfo.startPos = m_dragItem->startPos();
2333                         if (m_dragItemInfo.track == info.track && !item->baseClip()->isTransparent() && getClipItemAtEnd(newTrInfo.endPos, m_document->tracksCount() - tr->transitionEndTrack())) {
2334                             // transition end should stay the same
2335                         } else {
2336                             // transition end should be adjusted to clip
2337                             newTrInfo.endPos = newTrInfo.endPos + (newTrInfo.startPos - trInfo.startPos);
2338                         }
2339                         if (newTrInfo.startPos < newTrInfo.endPos) new MoveTransitionCommand(this, trInfo, newTrInfo, true, moveCommand);
2340                     }
2341                     if (tr == NULL || tr->endPos() < m_dragItemInfo.endPos) {
2342                         // Check if there is a transition at clip end
2343                         tr = getTransitionItemAtEnd(m_dragItemInfo.endPos, m_dragItemInfo.track);
2344                         if (tr && tr->isAutomatic()) {
2345                             ItemInfo trInfo = tr->info();
2346                             ItemInfo newTrInfo = trInfo;
2347                             newTrInfo.track = info.track;
2348                             newTrInfo.endPos = m_dragItem->endPos();
2349                             if (m_dragItemInfo.track == info.track && !item->baseClip()->isTransparent() && getClipItemAtStart(trInfo.startPos, m_document->tracksCount() - tr->transitionEndTrack())) {
2350                                 // transition start should stay the same
2351                             } else {
2352                                 // transition start should be moved
2353                                 newTrInfo.startPos = newTrInfo.startPos + (newTrInfo.endPos - trInfo.endPos);
2354                             }
2355                             if (newTrInfo.startPos < newTrInfo.endPos)
2356                                 new MoveTransitionCommand(this, trInfo, newTrInfo, true, moveCommand);
2357                         }
2358                     }
2359                     // Also move automatic transitions (on upper track)
2360                     tr = getTransitionItemAtStart(m_dragItemInfo.startPos, m_dragItemInfo.track - 1);
2361                     if (m_dragItemInfo.track == info.track && tr && tr->isAutomatic() && (m_document->tracksCount() - tr->transitionEndTrack()) == m_dragItemInfo.track) {
2362                         ItemInfo trInfo = tr->info();
2363                         ItemInfo newTrInfo = trInfo;
2364                         newTrInfo.startPos = m_dragItem->startPos();
2365                         ClipItem * upperClip = getClipItemAt(m_dragItemInfo.startPos, m_dragItemInfo.track - 1);
2366                         if (!upperClip || !upperClip->baseClip()->isTransparent()) {
2367                             if (!getClipItemAtEnd(newTrInfo.endPos, tr->track())) {
2368                                 // transition end should be adjusted to clip on upper track
2369                                 newTrInfo.endPos = newTrInfo.endPos + (newTrInfo.startPos - trInfo.startPos);
2370                             }
2371                             if (newTrInfo.startPos < newTrInfo.endPos) new MoveTransitionCommand(this, trInfo, newTrInfo, true, moveCommand);
2372                         }
2373                     }
2374                     if (m_dragItemInfo.track == info.track && (tr == NULL || tr->endPos() < m_dragItemInfo.endPos)) {
2375                         // Check if there is a transition at clip end
2376                         tr = getTransitionItemAtEnd(m_dragItemInfo.endPos, m_dragItemInfo.track - 1);
2377                         if (tr && tr->isAutomatic() && (m_document->tracksCount() - tr->transitionEndTrack()) == m_dragItemInfo.track) {
2378                             ItemInfo trInfo = tr->info();
2379                             ItemInfo newTrInfo = trInfo;
2380                             newTrInfo.endPos = m_dragItem->endPos();
2381                             ClipItem * upperClip = getClipItemAt(m_dragItemInfo.startPos, m_dragItemInfo.track - 1);
2382                             if (!upperClip || !upperClip->baseClip()->isTransparent()) {
2383                                 if (!getClipItemAtStart(trInfo.startPos, tr->track())) {
2384                                     // transition start should be moved
2385                                     newTrInfo.startPos = newTrInfo.startPos + (newTrInfo.endPos - trInfo.endPos);
2386                                 }
2387                                 if (newTrInfo.startPos < newTrInfo.endPos) new MoveTransitionCommand(this, trInfo, newTrInfo, true, moveCommand);
2388                             }
2389                         }
2390                     }
2391                     m_commandStack->push(moveCommand);
2392                 } else {
2393                     // undo last move and emit error message
2394                     bool snap = KdenliveSettings::snaptopoints();
2395                     KdenliveSettings::setSnaptopoints(false);
2396                     item->setPos((int) m_dragItemInfo.startPos.frames(m_document->fps()), (int)(m_dragItemInfo.track * m_tracksHeight + 1));
2397                     KdenliveSettings::setSnaptopoints(snap);
2398                     emit displayMessage(i18n("Cannot move clip to position %1", m_document->timecode().getTimecodeFromFrames(m_dragItemInfo.startPos.frames(m_document->fps()))), ErrorMessage);
2399                 }
2400                 m_document->setModified(true);
2401             }
2402             if (m_dragItem->type() == TRANSITIONWIDGET && (m_dragItemInfo.startPos != info.startPos || m_dragItemInfo.track != info.track)) {
2403                 Transition *transition = static_cast <Transition *>(m_dragItem);
2404                 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)) {
2405                     // Moving transition failed, revert to previous position
2406                     emit displayMessage(i18n("Cannot move transition"), ErrorMessage);
2407                     transition->setPos((int) m_dragItemInfo.startPos.frames(m_document->fps()), (m_dragItemInfo.track) * m_tracksHeight + 1);
2408                 } else {
2409                     MoveTransitionCommand *command = new MoveTransitionCommand(this, m_dragItemInfo, info, false);
2410                     m_commandStack->push(command);
2411                     transition->updateTransitionEndTrack(getPreviousVideoTrack(m_dragItem->track()));
2412                 }
2413             }
2414         } else {
2415             // Moving several clips. We need to delete them and readd them to new position,
2416             // or they might overlap each other during the move
2417             QGraphicsItemGroup *group = static_cast <QGraphicsItemGroup *>(m_dragItem->parentItem());
2418             QList<QGraphicsItem *> items = group->childItems();
2419
2420             QList<ItemInfo> clipsToMove;
2421             QList<ItemInfo> transitionsToMove;
2422
2423             GenTime timeOffset = GenTime(m_dragItem->scenePos().x(), m_document->fps()) - m_dragItemInfo.startPos;
2424             const int trackOffset = (int)(m_dragItem->scenePos().y() / m_tracksHeight) - m_dragItemInfo.track;
2425             //kDebug() << "// MOVED SEVERAL CLIPS" << timeOffset.frames(25);
2426             if (timeOffset != GenTime() || trackOffset != 0) {
2427                 // remove items in MLT playlist
2428
2429                 // Expand groups
2430                 int max = items.count();
2431                 for (int i = 0; i < max; i++) {
2432                     if (items.at(i)->type() == GROUPWIDGET) {
2433                         items += items.at(i)->childItems();
2434                     }
2435                 }
2436
2437                 for (int i = 0; i < items.count(); i++) {
2438                     if (items.at(i)->type() != AVWIDGET && items.at(i)->type() != TRANSITIONWIDGET) continue;
2439                     AbstractClipItem *item = static_cast <AbstractClipItem *>(items.at(i));
2440                     ItemInfo info = item->info();
2441                     if (item->type() == AVWIDGET) {
2442                         if (m_document->renderer()->mltRemoveClip(m_document->tracksCount() - info.track, info.startPos) == false) {
2443                             // error, clip cannot be removed from playlist
2444                             emit displayMessage(i18n("Error removing clip at %1 on track %2", m_document->timecode().getTimecodeFromFrames(info.startPos.frames(m_document->fps())), info.track), ErrorMessage);
2445                         } else {
2446                             clipsToMove.append(info);
2447                         }
2448                     } else {
2449                         transitionsToMove.append(info);
2450                         Transition *tr = static_cast <Transition*>(item);
2451                         m_document->renderer()->mltDeleteTransition(tr->transitionTag(), tr->transitionEndTrack(), m_document->tracksCount() - info.track, info.startPos, info.endPos, tr->toXML());
2452                     }
2453                 }
2454
2455                 for (int i = 0; i < items.count(); i++) {
2456                     // re-add items in correct place
2457                     if (items.at(i)->type() != AVWIDGET && items.at(i)->type() != TRANSITIONWIDGET) continue;
2458                     AbstractClipItem *item = static_cast <AbstractClipItem *>(items.at(i));
2459                     item->updateItem();
2460                     ItemInfo info = item->info();
2461                     int tracknumber = m_document->tracksCount() - info.track - 1;
2462                     bool isLocked = m_document->trackInfoAt(tracknumber).isLocked;
2463                     if (isLocked) {
2464                         group->removeFromGroup(item);
2465                         item->setItemLocked(true);
2466                     }
2467
2468                     if (item->type() == AVWIDGET) {
2469                         ClipItem *clip = static_cast <ClipItem*>(item);
2470                         info.track = m_document->tracksCount() - info.track;
2471                         Mlt::Producer *prod;
2472                         if (clip->isAudioOnly()) prod = clip->baseClip()->audioProducer(info.track);
2473                         else if (clip->isVideoOnly()) prod = clip->baseClip()->videoProducer();
2474                         else prod = clip->baseClip()->producer(info.track);
2475                         m_document->renderer()->mltInsertClip(info, clip->xml(), prod);
2476                         for (int i = 0; i < clip->effectsCount(); i++) {
2477                             m_document->renderer()->mltAddEffect(info.track, info.startPos, clip->getEffectArgs(clip->effectAt(i)), false);
2478                         }
2479                     } else {
2480                         Transition *tr = static_cast <Transition*>(item);
2481                         int newTrack = tr->transitionEndTrack();
2482                         if (!tr->forcedTrack()) {
2483                             newTrack = getPreviousVideoTrack(info.track);
2484                         }
2485                         tr->updateTransitionEndTrack(newTrack);
2486                         m_document->renderer()->mltAddTransition(tr->transitionTag(), newTrack, m_document->tracksCount() - info.track, info.startPos, info.endPos, tr->toXML());
2487                     }
2488                 }
2489
2490                 MoveGroupCommand *move = new MoveGroupCommand(this, clipsToMove, transitionsToMove, timeOffset, trackOffset, false);
2491                 m_commandStack->push(move);
2492
2493                 //QPointF top = group->sceneBoundingRect().topLeft();
2494                 //QPointF oldpos = m_selectionGroup->scenePos();
2495                 //kDebug()<<"SELECTION GRP POS: "<<m_selectionGroup->scenePos()<<", TOP: "<<top;
2496                 //group->setPos(top);
2497                 //TODO: get rid of the 3 lines below
2498                 if (m_selectionGroup) {
2499                     m_selectionGroupInfo.startPos = GenTime(m_selectionGroup->scenePos().x(), m_document->fps());
2500                     m_selectionGroupInfo.track = m_selectionGroup->track();
2501                 }
2502                 m_document->setModified(true);
2503             }
2504         }
2505
2506     } else if (m_operationMode == RESIZESTART && m_dragItem->startPos() != m_dragItemInfo.startPos) {
2507         // resize start
2508         if (m_dragItem->type() == AVWIDGET) {
2509             ItemInfo resizeinfo = m_dragItemInfo;
2510             resizeinfo.track = m_document->tracksCount() - resizeinfo.track;
2511             bool success = m_document->renderer()->mltResizeClipStart(resizeinfo, m_dragItem->startPos() - m_dragItemInfo.startPos);
2512             if (success) {
2513                 QUndoCommand *resizeCommand = new QUndoCommand();
2514                 resizeCommand->setText(i18n("Resize clip"));
2515
2516                 // Check if there is an automatic transition on that clip (lower track)
2517                 Transition *transition = getTransitionItemAtStart(m_dragItemInfo.startPos, m_dragItemInfo.track);
2518                 if (transition && transition->isAutomatic()) {
2519                     ItemInfo trInfo = transition->info();
2520                     ItemInfo newTrInfo = trInfo;
2521                     newTrInfo.startPos = m_dragItem->startPos();
2522                     if (newTrInfo.startPos < newTrInfo.endPos)
2523                         new MoveTransitionCommand(this, trInfo, newTrInfo, true, resizeCommand);
2524                 }
2525                 // Check if there is an automatic transition on that clip (upper track)
2526                 transition = getTransitionItemAtStart(m_dragItemInfo.startPos, m_dragItemInfo.track - 1);
2527                 if (transition && transition->isAutomatic() && (m_document->tracksCount() - transition->transitionEndTrack()) == m_dragItemInfo.track) {
2528                     ItemInfo trInfo = transition->info();
2529                     ItemInfo newTrInfo = trInfo;
2530                     newTrInfo.startPos = m_dragItem->startPos();
2531                     ClipItem * upperClip = getClipItemAt(m_dragItemInfo.startPos, m_dragItemInfo.track - 1);
2532                     if ((!upperClip || !upperClip->baseClip()->isTransparent()) && newTrInfo.startPos < newTrInfo.endPos) {
2533                         new MoveTransitionCommand(this, trInfo, newTrInfo, true, resizeCommand);
2534                     }
2535                 }
2536                 updateClipFade(static_cast <ClipItem *>(m_dragItem));
2537                 new ResizeClipCommand(this, m_dragItemInfo, info, false, resizeCommand);
2538                 m_commandStack->push(resizeCommand);
2539             } else {
2540                 m_dragItem->resizeStart((int) m_dragItemInfo.startPos.frames(m_document->fps()));
2541                 emit displayMessage(i18n("Error when resizing clip"), ErrorMessage);
2542             }
2543         } else if (m_dragItem->type() == TRANSITIONWIDGET) {
2544             Transition *transition = static_cast <Transition *>(m_dragItem);
2545             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)) {
2546                 // Cannot resize transition
2547                 transition->resizeStart((int) m_dragItemInfo.startPos.frames(m_document->fps()));
2548                 emit displayMessage(i18n("Cannot resize transition"), ErrorMessage);
2549             } else {
2550                 MoveTransitionCommand *command = new MoveTransitionCommand(this, m_dragItemInfo, info, false);
2551                 m_commandStack->push(command);
2552             }
2553
2554         }
2555         if (m_dragItem->parentItem() && m_dragItem->parentItem() != m_selectionGroup) {
2556             // Item was resized, rebuild group;
2557             AbstractGroupItem *group = static_cast <AbstractGroupItem *>(m_dragItem->parentItem());
2558             QList <QGraphicsItem *> children = group->childItems();
2559             m_document->clipManager()->removeGroup(group);
2560             scene()->destroyItemGroup(group);
2561             for (int i = 0; i < children.count(); i++) {
2562                 children.at(i)->setSelected(true);
2563             }
2564             groupSelectedItems(false, true);
2565         }
2566         //m_document->renderer()->doRefresh();
2567     } else if (m_operationMode == RESIZEEND && m_dragItem->endPos() != m_dragItemInfo.endPos) {
2568         // resize end
2569         if (m_dragItem->type() == AVWIDGET) {
2570             ItemInfo resizeinfo = info;
2571             resizeinfo.track = m_document->tracksCount() - resizeinfo.track;
2572             bool success = m_document->renderer()->mltResizeClipEnd(resizeinfo, resizeinfo.endPos - resizeinfo.startPos);
2573             if (success) {
2574                 QUndoCommand *resizeCommand = new QUndoCommand();
2575                 resizeCommand->setText(i18n("Resize clip"));
2576
2577                 // Check if there is an automatic transition on that clip (lower track)
2578                 Transition *tr = getTransitionItemAtEnd(m_dragItemInfo.endPos, m_dragItemInfo.track);
2579                 if (tr && tr->isAutomatic()) {
2580                     ItemInfo trInfo = tr->info();
2581                     ItemInfo newTrInfo = trInfo;
2582                     newTrInfo.endPos = m_dragItem->endPos();
2583                     if (newTrInfo.endPos > newTrInfo.startPos) new MoveTransitionCommand(this, trInfo, newTrInfo, true, resizeCommand);
2584                 }
2585
2586                 // Check if there is an automatic transition on that clip (upper track)
2587                 tr = getTransitionItemAtEnd(m_dragItemInfo.endPos, m_dragItemInfo.track - 1);
2588                 if (tr && tr->isAutomatic() && (m_document->tracksCount() - tr->transitionEndTrack()) == m_dragItemInfo.track) {
2589                     ItemInfo trInfo = tr->info();
2590                     ItemInfo newTrInfo = trInfo;
2591                     newTrInfo.endPos = m_dragItem->endPos();
2592                     ClipItem * upperClip = getClipItemAtEnd(m_dragItemInfo.endPos, m_dragItemInfo.track - 1);
2593                     if ((!upperClip || !upperClip->baseClip()->isTransparent()) && newTrInfo.endPos > newTrInfo.startPos) {
2594                         new MoveTransitionCommand(this, trInfo, newTrInfo, true, resizeCommand);
2595                     }
2596                 }
2597
2598                 new ResizeClipCommand(this, m_dragItemInfo, info, false, resizeCommand);
2599                 m_commandStack->push(resizeCommand);
2600                 updateClipFade(static_cast <ClipItem *>(m_dragItem), true);
2601             } else {
2602                 m_dragItem->resizeEnd((int) m_dragItemInfo.endPos.frames(m_document->fps()));
2603                 emit displayMessage(i18n("Error when resizing clip"), ErrorMessage);
2604             }
2605         } else if (m_dragItem->type() == TRANSITIONWIDGET) {
2606             Transition *transition = static_cast <Transition *>(m_dragItem);
2607             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)) {
2608                 // Cannot resize transition
2609                 transition->resizeEnd((int) m_dragItemInfo.endPos.frames(m_document->fps()));
2610                 emit displayMessage(i18n("Cannot resize transition"), ErrorMessage);
2611             } else {
2612                 MoveTransitionCommand *command = new MoveTransitionCommand(this, m_dragItemInfo, info, false);
2613                 m_commandStack->push(command);
2614             }
2615         }
2616         if (m_dragItem->parentItem() && m_dragItem->parentItem() != m_selectionGroup) {
2617             // Item was resized, rebuild group;
2618             AbstractGroupItem *group = static_cast <AbstractGroupItem *>(m_dragItem->parentItem());
2619             QList <QGraphicsItem *> children = group->childItems();
2620             m_document->clipManager()->removeGroup(group);
2621             scene()->destroyItemGroup(group);
2622             for (int i = 0; i < children.count(); i++) {
2623                 children.at(i)->setSelected(true);
2624             }
2625             groupSelectedItems(false, true);
2626         }
2627         //m_document->renderer()->doRefresh();
2628     } else if (m_operationMode == FADEIN) {
2629         // resize fade in effect
2630         ClipItem * item = (ClipItem *) m_dragItem;
2631         int ix = item->hasEffect("volume", "fadein");
2632         if (ix != -1) {
2633             QDomElement oldeffect = item->effectAt(ix);
2634             int start = item->cropStart().frames(m_document->fps());
2635             int end = item->fadeIn();
2636             if (end == 0) {
2637                 slotDeleteEffect(item, oldeffect);
2638             } else {
2639                 end += start;
2640                 QDomElement effect = oldeffect.cloneNode().toElement();
2641                 EffectsList::setParameter(oldeffect, "in", QString::number(start));
2642                 EffectsList::setParameter(oldeffect, "out", QString::number(end));
2643                 slotUpdateClipEffect(item, effect, oldeffect, ix);
2644                 emit clipItemSelected(item, ix);
2645             }
2646         } else if (item->fadeIn() != 0 && item->hasEffect("", "fade_from_black") == -1) {
2647             QDomElement effect = MainWindow::audioEffects.getEffectByTag("volume", "fadein").cloneNode().toElement();
2648             EffectsList::setParameter(effect, "out", QString::number(item->fadeIn()));
2649             slotAddEffect(effect, m_dragItem->startPos(), m_dragItem->track());
2650         }
2651         ix = item->hasEffect("volume", "fade_from_black");
2652         if (ix != -1) {
2653             QDomElement oldeffect = item->effectAt(ix);
2654             int start = item->cropStart().frames(m_document->fps());
2655             int end = item->fadeIn();
2656             if (end == 0) {
2657                 slotDeleteEffect(item, oldeffect);
2658             } else {
2659                 end += start;
2660                 QDomElement effect = oldeffect.cloneNode().toElement();
2661                 EffectsList::setParameter(oldeffect, "in", QString::number(start));
2662                 EffectsList::setParameter(oldeffect, "out", QString::number(end));
2663                 slotUpdateClipEffect(item, effect, oldeffect, ix);
2664                 emit clipItemSelected(item, ix);
2665             }
2666         }
2667     } else if (m_operationMode == FADEOUT) {
2668         // resize fade in effect
2669         ClipItem * item = (ClipItem *) m_dragItem;
2670         int ix = item->hasEffect("volume", "fadeout");
2671         if (ix != -1) {
2672             QDomElement oldeffect = item->effectAt(ix);
2673             int end = (item->duration() + item->cropStart()).frames(m_document->fps());
2674             int start = item->fadeOut();
2675             if (start == 0) {
2676                 slotDeleteEffect(item, oldeffect);
2677             } else {
2678                 start = end - start;
2679                 QDomElement effect = oldeffect.cloneNode().toElement();
2680                 EffectsList::setParameter(oldeffect, "in", QString::number(start));
2681                 EffectsList::setParameter(oldeffect, "out", QString::number(end));
2682                 // kDebug()<<"EDIT FADE OUT : "<<start<<"x"<<end;
2683                 slotUpdateClipEffect(item, effect, oldeffect, ix);
2684                 emit clipItemSelected(item, ix);
2685             }
2686         } else if (item->fadeOut() != 0 && item->hasEffect("", "fade_to_black") == -1) {
2687             QDomElement effect = MainWindow::audioEffects.getEffectByTag("volume", "fadeout").cloneNode().toElement();
2688             EffectsList::setParameter(effect, "in", QString::number(item->fadeOut()));
2689             EffectsList::setParameter(effect, "out", QString::number(0));
2690             slotAddEffect(effect, m_dragItem->startPos(), m_dragItem->track());
2691         }
2692         ix = item->hasEffect("brightness", "fade_to_black");
2693         if (ix != -1) {
2694             QDomElement oldeffect = item->effectAt(ix);
2695             int end = (item->duration() + item->cropStart()).frames(m_document->fps());
2696             int start = item->fadeOut();
2697             if (start == 0) {
2698                 slotDeleteEffect(item, oldeffect);
2699             } else {
2700                 start = end - start;
2701                 QDomElement effect = oldeffect.cloneNode().toElement();
2702                 EffectsList::setParameter(oldeffect, "in", QString::number(start));
2703                 EffectsList::setParameter(oldeffect, "out", QString::number(end));
2704                 // kDebug()<<"EDIT FADE OUT : "<<start<<"x"<<end;
2705                 slotUpdateClipEffect(item, effect, oldeffect, ix);
2706                 emit clipItemSelected(item, ix);
2707             }
2708         }
2709     } else if (m_operationMode == KEYFRAME) {
2710         // update the MLT effect
2711         ClipItem * item = (ClipItem *) m_dragItem;
2712         QString previous = item->keyframes(item->selectedEffectIndex());
2713         item->updateKeyframeEffect();
2714         QString next = item->keyframes(item->selectedEffectIndex());
2715         EditKeyFrameCommand *command = new EditKeyFrameCommand(this, item->track(), item->startPos(), item->selectedEffectIndex(), previous, next, false);
2716         m_commandStack->push(command);
2717         updateEffect(m_document->tracksCount() - item->track(), item->startPos(), item->selectedEffect(), item->selectedEffectIndex());
2718     }
2719     if (m_dragItem && m_dragItem->type() == TRANSITIONWIDGET && m_dragItem->isSelected()) {
2720         // A transition is selected
2721         QPoint p;
2722         ClipItem *transitionClip = getClipItemAt(m_dragItemInfo.startPos, m_dragItemInfo.track);
2723         if (transitionClip && transitionClip->baseClip()) {
2724             QString size = transitionClip->baseClip()->getProperty("frame_size");
2725             p.setX(size.section('x', 0, 0).toInt());
2726             p.setY(size.section('x', 1, 1).toInt());
2727         }
2728         emit transitionItemSelected(static_cast <Transition *>(m_dragItem), getPreviousVideoTrack(m_dragItem->track()), p);
2729     } else emit transitionItemSelected(NULL);
2730     if (m_operationMode != NONE && m_operationMode != MOVE) m_document->setModified(true);
2731     m_operationMode = NONE;
2732 }
2733
2734 void CustomTrackView::deleteClip(ItemInfo info)
2735 {
2736     ClipItem *item = getClipItemAt((int) info.startPos.frames(m_document->fps()) + 1, info.track);
2737
2738     if (!item || m_document->renderer()->mltRemoveClip(m_document->tracksCount() - info.track, info.startPos) == false) {
2739         emit displayMessage(i18n("Error removing clip at %1 on track %2", m_document->timecode().getTimecodeFromFrames(info.startPos.frames(m_document->fps())), info.track), ErrorMessage);
2740         return;
2741     }
2742     if (item->isSelected()) emit clipItemSelected(NULL);
2743     item->baseClip()->removeReference();
2744     m_document->updateClip(item->baseClip()->getId());
2745
2746     /*if (item->baseClip()->isTransparent()) {
2747         // also remove automatic transition
2748         Transition *tr = getTransitionItemAt(info.startPos, info.track);
2749         if (tr && tr->isAutomatic()) {
2750             m_document->renderer()->mltDeleteTransition(tr->transitionTag(), tr->transitionEndTrack(), m_document->tracksCount() - info.track, info.startPos, info.endPos, tr->toXML());
2751             scene()->removeItem(tr);
2752             delete tr;
2753         }
2754     }*/
2755     scene()->removeItem(item);
2756     m_waitingThumbs.removeAll(item);
2757     if (m_dragItem == item) m_dragItem = NULL;
2758     delete item;
2759     item = NULL;
2760     m_document->setModified(true);
2761     m_document->renderer()->doRefresh();
2762 }
2763
2764 void CustomTrackView::deleteSelectedClips()
2765 {
2766     resetSelectionGroup();
2767     QList<QGraphicsItem *> itemList = scene()->selectedItems();
2768     if (itemList.count() == 0) {
2769         emit displayMessage(i18n("Select clip to delete"), ErrorMessage);
2770         return;
2771     }
2772     scene()->clearSelection();
2773     QUndoCommand *deleteSelected = new QUndoCommand();
2774     deleteSelected->setText(i18n("Delete selected items"));
2775     bool resetGroup = false;
2776
2777     // expand & destroy groups
2778     for (int i = 0; i < itemList.count(); i++) {
2779         if (itemList.at(i)->type() == GROUPWIDGET) {
2780             QList<QGraphicsItem *> children = itemList.at(i)->childItems();
2781             itemList += children;
2782             QList <ItemInfo> clipInfos;
2783             QList <ItemInfo> transitionInfos;
2784             GenTime currentPos = GenTime(m_cursorPos, m_document->fps());
2785             for (int j = 0; j < children.count(); j++) {
2786                 if (children.at(j)->type() == AVWIDGET) {
2787                     AbstractClipItem *clip = static_cast <AbstractClipItem *>(children.at(j));
2788                     if (!clip->isItemLocked()) clipInfos.append(clip->info());
2789                 } else if (children.at(j)->type() == TRANSITIONWIDGET) {
2790                     AbstractClipItem *clip = static_cast <AbstractClipItem *>(children.at(j));
2791                     if (!clip->isItemLocked()) transitionInfos.append(clip->info());
2792                 }
2793             }
2794             if (clipInfos.count() > 0) {
2795                 new GroupClipsCommand(this, clipInfos, transitionInfos, false, deleteSelected);
2796             }
2797         }
2798     }
2799
2800     for (int i = 0; i < itemList.count(); i++) {
2801         if (itemList.at(i)->type() == AVWIDGET) {
2802             ClipItem *item = static_cast <ClipItem *>(itemList.at(i));
2803             if (item->parentItem()) resetGroup = true;
2804             new AddTimelineClipCommand(this, item->xml(), item->clipProducer(), item->info(), item->effectList(), true, true, deleteSelected);
2805             emit clipItemSelected(NULL);
2806         } else if (itemList.at(i)->type() == TRANSITIONWIDGET) {
2807             Transition *item = static_cast <Transition *>(itemList.at(i));
2808             if (item->parentItem()) resetGroup = true;
2809             new AddTransitionCommand(this, item->info(), item->transitionEndTrack(), item->toXML(), true, true, deleteSelected);
2810             emit transitionItemSelected(NULL);
2811         }
2812     }
2813
2814     m_commandStack->push(deleteSelected);
2815 }
2816
2817 void CustomTrackView::changeClipSpeed()
2818 {
2819     QList<QGraphicsItem *> itemList = scene()->selectedItems();
2820     if (itemList.count() == 0) {
2821         emit displayMessage(i18n("Select clip to change speed"), ErrorMessage);
2822         return;
2823     }
2824     QUndoCommand *changeSelected = new QUndoCommand();
2825     changeSelected->setText("Edit clip speed");
2826     int count = 0;
2827     int percent = -1;
2828     bool ok;
2829     for (int i = 0; i < itemList.count(); i++) {
2830         if (itemList.at(i)->type() == AVWIDGET) {
2831             ClipItem *item = static_cast <ClipItem *>(itemList.at(i));
2832             ItemInfo info = item->info();
2833             if (percent == -1) percent = QInputDialog::getInteger(this, i18n("Edit Clip Speed"), i18n("New speed (percents)"), item->speed() * 100, 1, 10000, 1, &ok);
2834             if (!ok) break;
2835             double speed = (double) percent / 100.0;
2836             if (item->speed() != speed && (item->clipType() == VIDEO || item->clipType() == AV)) {
2837                 count++;
2838                 new ChangeSpeedCommand(this, info, item->speed(), speed, item->clipProducer(), changeSelected);
2839             }
2840         }
2841     }
2842     if (count > 0) m_commandStack->push(changeSelected);
2843     else delete changeSelected;
2844 }
2845
2846 void CustomTrackView::doChangeClipSpeed(ItemInfo info, const double speed, const double oldspeed, const QString &id)
2847 {
2848     DocClipBase *baseclip = m_document->clipManager()->getClipById(id);
2849     ClipItem *item = getClipItemAt((int) info.startPos.frames(m_document->fps()) + 1, info.track);
2850     if (!item) {
2851         kDebug() << "ERROR: Cannot find clip for speed change";
2852         emit displayMessage(i18n("Cannot find clip for speed change"), ErrorMessage);
2853         return;
2854     }
2855     info.track = m_document->tracksCount() - item->track();
2856     int endPos = m_document->renderer()->mltChangeClipSpeed(info, speed, oldspeed, baseclip->producer());
2857     if (endPos >= 0) {
2858         item->setSpeed(speed);
2859         item->updateRectGeometry();
2860         if (item->cropDuration().frames(m_document->fps()) > endPos)
2861             item->AbstractClipItem::resizeEnd(info.startPos.frames(m_document->fps()) + endPos, speed);
2862         m_document->setModified(true);
2863     } else emit displayMessage(i18n("Invalid clip"), ErrorMessage);
2864 }
2865
2866 void CustomTrackView::cutSelectedClips()
2867 {
2868     QList<QGraphicsItem *> itemList = scene()->selectedItems();
2869     GenTime currentPos = GenTime(m_cursorPos, m_document->fps());
2870     for (int i = 0; i < itemList.count(); i++) {
2871         if (itemList.at(i)->type() == AVWIDGET) {
2872             ClipItem *item = static_cast <ClipItem *>(itemList.at(i));
2873             if (item->parentItem() && item->parentItem() != m_selectionGroup) {
2874                 emit displayMessage(i18n("Cannot cut a clip in a group"), ErrorMessage);
2875             } else if (currentPos > item->startPos() && currentPos <  item->endPos()) {
2876                 RazorClipCommand *command = new RazorClipCommand(this, item->info(), currentPos);
2877                 m_commandStack->push(command);
2878             }
2879         }
2880     }
2881 }
2882
2883 void CustomTrackView::groupClips(bool group)
2884 {
2885     QList<QGraphicsItem *> itemList = scene()->selectedItems();
2886     QList <ItemInfo> clipInfos;
2887     QList <ItemInfo> transitionInfos;
2888     GenTime currentPos = GenTime(m_cursorPos, m_document->fps());
2889
2890     // Expand groups
2891     int max = itemList.count();
2892     for (int i = 0; i < max; i++) {
2893         if (itemList.at(i)->type() == GROUPWIDGET) {
2894             itemList += itemList.at(i)->childItems();
2895         }
2896     }
2897
2898     for (int i = 0; i < itemList.count(); i++) {
2899         if (itemList.at(i)->type() == AVWIDGET) {
2900             AbstractClipItem *clip = static_cast <AbstractClipItem *>(itemList.at(i));
2901             if (!clip->isItemLocked()) clipInfos.append(clip->info());
2902         } else if (itemList.at(i)->type() == TRANSITIONWIDGET) {
2903             AbstractClipItem *clip = static_cast <AbstractClipItem *>(itemList.at(i));
2904             if (!clip->isItemLocked()) transitionInfos.append(clip->info());
2905         }
2906     }
2907     if (clipInfos.count() > 0) {
2908         GroupClipsCommand *command = new GroupClipsCommand(this, clipInfos, transitionInfos, group);
2909         m_commandStack->push(command);
2910     }
2911 }
2912
2913 void CustomTrackView::doGroupClips(QList <ItemInfo> clipInfos, QList <ItemInfo> transitionInfos, bool group)
2914 {
2915     resetSelectionGroup();
2916     m_scene->clearSelection();
2917     if (!group) {
2918         for (int i = 0; i < clipInfos.count(); i++) {
2919             ClipItem *clip = getClipItemAt(clipInfos.at(i).startPos, clipInfos.at(i).track);
2920             if (clip == NULL) continue;
2921             if (clip->parentItem() && clip->parentItem()->type() == GROUPWIDGET) {
2922                 AbstractGroupItem *grp = static_cast <AbstractGroupItem *>(clip->parentItem());
2923                 m_document->clipManager()->removeGroup(grp);
2924                 scene()->destroyItemGroup(grp);
2925             }
2926             clip->setFlags(QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemIsSelectable);
2927         }
2928         for (int i = 0; i < transitionInfos.count(); i++) {
2929             Transition *tr = getTransitionItemAt(transitionInfos.at(i).startPos, transitionInfos.at(i).track);
2930             if (tr == NULL) continue;
2931             if (tr->parentItem() && tr->parentItem()->type() == GROUPWIDGET) {
2932                 AbstractGroupItem *grp = static_cast <AbstractGroupItem *>(tr->parentItem());
2933                 m_document->clipManager()->removeGroup(grp);
2934                 scene()->destroyItemGroup(grp);
2935             }
2936             tr->setFlags(QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemIsSelectable);
2937         }
2938         m_document->setModified(true);
2939         return;
2940     }
2941
2942     QList <QGraphicsItemGroup *> groups;
2943     for (int i = 0; i < clipInfos.count(); i++) {
2944         ClipItem *clip = getClipItemAt(clipInfos.at(i).startPos, clipInfos.at(i).track);
2945         if (clip) {
2946             clip->setSelected(true);
2947         }
2948     }
2949     for (int i = 0; i < transitionInfos.count(); i++) {
2950         Transition *clip = getTransitionItemAt(transitionInfos.at(i).startPos, transitionInfos.at(i).track);
2951         if (clip) {
2952             clip->setSelected(true);
2953         }
2954     }
2955
2956     groupSelectedItems(false, true);
2957     m_document->setModified(true);
2958 }
2959
2960 void CustomTrackView::addClip(QDomElement xml, const QString &clipId, ItemInfo info, EffectsList effects)
2961 {
2962     DocClipBase *baseclip = m_document->clipManager()->getClipById(clipId);
2963     if (baseclip == NULL) {
2964         emit displayMessage(i18n("No clip copied"), ErrorMessage);
2965         return;
2966     }
2967     ClipItem *item = new ClipItem(baseclip, info, m_document->fps(), xml.attribute("speed", "1").toDouble());
2968     item->setEffectList(effects);
2969     if (xml.hasAttribute("audio_only")) item->setAudioOnly(true);
2970     else if (xml.hasAttribute("video_only")) item->setVideoOnly(true);
2971     scene()->addItem(item);
2972
2973     int tracknumber = m_document->tracksCount() - info.track - 1;
2974     bool isLocked = m_document->trackInfoAt(tracknumber).isLocked;
2975     if (isLocked) item->setItemLocked(true);
2976
2977     baseclip->addReference();
2978     m_document->updateClip(baseclip->getId());
2979     info.track = m_document->tracksCount() - info.track;
2980     Mlt::Producer *prod;
2981     if (item->isAudioOnly()) prod = baseclip->audioProducer(info.track);
2982     else if (item->isVideoOnly()) prod = baseclip->videoProducer();
2983     else prod = baseclip->producer(info.track);
2984     m_document->renderer()->mltInsertClip(info, xml, prod);
2985     for (int i = 0; i < item->effectsCount(); i++) {
2986         m_document->renderer()->mltAddEffect(info.track, info.startPos, item->getEffectArgs(item->effectAt(i)), false);
2987     }
2988     m_document->setModified(true);
2989     m_document->renderer()->doRefresh();
2990 }
2991
2992 void CustomTrackView::slotUpdateClip(const QString &clipId)
2993 {
2994     QList<QGraphicsItem *> list = scene()->items();
2995     ClipItem *clip = NULL;
2996     for (int i = 0; i < list.size(); ++i) {
2997         if (list.at(i)->type() == AVWIDGET) {
2998             clip = static_cast <ClipItem *>(list.at(i));
2999             if (clip->clipProducer() == clipId) {
3000                 ItemInfo info = clip->info();
3001                 info.track = m_document->tracksCount() - clip->track();
3002                 m_document->renderer()->mltUpdateClip(info, clip->xml(), clip->baseClip()->producer());
3003                 clip->refreshClip(true);
3004                 clip->update();
3005             }
3006         }
3007     }
3008 }
3009
3010 ClipItem *CustomTrackView::getClipItemAtEnd(GenTime pos, int track)
3011 {
3012     int framepos = (int)(pos.frames(m_document->fps()));
3013     QList<QGraphicsItem *> list = scene()->items(QPointF(framepos - 1, track * m_tracksHeight + m_tracksHeight / 2));
3014     ClipItem *clip = NULL;
3015     for (int i = 0; i < list.size(); i++) {
3016         if (list.at(i)->type() == AVWIDGET) {
3017             ClipItem *test = static_cast <ClipItem *>(list.at(i));
3018             if (test->endPos() == pos) clip = test;
3019             break;
3020         }
3021     }
3022     return clip;
3023 }
3024
3025 ClipItem *CustomTrackView::getClipItemAtStart(GenTime pos, int track)
3026 {
3027     QList<QGraphicsItem *> list = scene()->items(QPointF(pos.frames(m_document->fps()), track * m_tracksHeight + m_tracksHeight / 2));
3028     ClipItem *clip = NULL;
3029     for (int i = 0; i < list.size(); i++) {
3030         if (list.at(i)->type() == AVWIDGET) {
3031             ClipItem *test = static_cast <ClipItem *>(list.at(i));
3032             if (test->startPos() == pos) clip = test;
3033             break;
3034         }
3035     }
3036     return clip;
3037 }
3038
3039 ClipItem *CustomTrackView::getClipItemAt(int pos, int track)
3040 {
3041     QList<QGraphicsItem *> list = scene()->items(QPointF(pos, track * m_tracksHeight + m_tracksHeight / 2));
3042     ClipItem *clip = NULL;
3043     for (int i = 0; i < list.size(); i++) {
3044         if (list.at(i)->type() == AVWIDGET) {
3045             clip = static_cast <ClipItem *>(list.at(i));
3046             break;
3047         }
3048     }
3049     return clip;
3050 }
3051
3052 ClipItem *CustomTrackView::getClipItemAt(GenTime pos, int track)
3053 {
3054     int framepos = (int)(pos.frames(m_document->fps()));
3055     return getClipItemAt(framepos, track);
3056 }
3057
3058 Transition *CustomTrackView::getTransitionItemAt(int pos, int track)
3059 {
3060     QList<QGraphicsItem *> list = scene()->items(QPointF(pos, (track + 1) * m_tracksHeight));
3061     Transition *clip = NULL;
3062     for (int i = 0; i < list.size(); i++) {
3063         if (list.at(i)->type() == TRANSITIONWIDGET) {
3064             clip = static_cast <Transition *>(list.at(i));
3065             break;
3066         }
3067     }
3068     return clip;
3069 }
3070
3071 Transition *CustomTrackView::getTransitionItemAt(GenTime pos, int track)
3072 {
3073     return getTransitionItemAt(pos.frames(m_document->fps()), track);
3074 }
3075
3076 Transition *CustomTrackView::getTransitionItemAtEnd(GenTime pos, int track)
3077 {
3078     int framepos = (int)(pos.frames(m_document->fps()));
3079     QList<QGraphicsItem *> list = scene()->items(QPointF(framepos - 1, (track + 1) * m_tracksHeight));
3080     Transition *clip = NULL;
3081     for (int i = 0; i < list.size(); i++) {
3082         if (list.at(i)->type() == TRANSITIONWIDGET) {
3083             Transition *test = static_cast <Transition *>(list.at(i));
3084             if (test->endPos() == pos) clip = test;
3085             break;
3086         }
3087     }
3088     return clip;
3089 }
3090
3091 Transition *CustomTrackView::getTransitionItemAtStart(GenTime pos, int track)
3092 {
3093     QList<QGraphicsItem *> list = scene()->items(QPointF(pos.frames(m_document->fps()), (track + 1) * m_tracksHeight));
3094     Transition *clip = NULL;
3095     for (int i = 0; i < list.size(); ++i) {
3096         if (list.at(i)->type() == TRANSITIONWIDGET) {
3097             Transition *test = static_cast <Transition *>(list.at(i));
3098             if (test->startPos() == pos) clip = test;
3099             break;
3100         }
3101     }
3102     return clip;
3103 }
3104
3105 void CustomTrackView::moveClip(const ItemInfo start, const ItemInfo end)
3106 {
3107     if (m_selectionGroup) resetSelectionGroup(false);
3108     ClipItem *item = getClipItemAt((int) start.startPos.frames(m_document->fps()) + 1, start.track);
3109     if (!item) {
3110         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);
3111         kDebug() << "----------------  ERROR, CANNOT find clip to move at.. ";
3112         return;
3113     }
3114     Mlt::Producer *prod;
3115     if (item->isAudioOnly()) prod = item->baseClip()->audioProducer(end.track);
3116     else if (item->isVideoOnly()) prod = item->baseClip()->videoProducer();
3117     else prod = item->baseClip()->producer(end.track);
3118
3119     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);
3120     if (success) {
3121         bool snap = KdenliveSettings::snaptopoints();
3122         KdenliveSettings::setSnaptopoints(false);
3123         item->setPos((int) end.startPos.frames(m_document->fps()), (int)(end.track * m_tracksHeight + 1));
3124
3125         int tracknumber = m_document->tracksCount() - end.track - 1;
3126         bool isLocked = m_document->trackInfoAt(tracknumber).isLocked;
3127         m_scene->clearSelection();
3128         if (isLocked) item->setItemLocked(true);
3129         else {
3130             if (item->isItemLocked()) item->setItemLocked(false);
3131             item->setSelected(true);
3132         }
3133         if (item->baseClip()->isTransparent()) {
3134             // Also move automatic transition
3135             Transition *tr = getTransitionItemAt(start.startPos, start.track);
3136             if (tr && tr->isAutomatic()) {
3137                 tr->updateTransitionEndTrack(getPreviousVideoTrack(end.track));
3138                 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);
3139                 tr->setPos((int) end.startPos.frames(m_document->fps()), (int)(end.track * m_tracksHeight + 1));
3140             }
3141         }
3142         KdenliveSettings::setSnaptopoints(snap);
3143         m_document->setModified(true);
3144     } else {
3145         // undo last move and emit error message
3146         emit displayMessage(i18n("Cannot move clip to position %1", m_document->timecode().getTimecodeFromFrames(end.startPos.frames(m_document->fps()))), ErrorMessage);
3147     }
3148     kDebug() << " // MOVED CLIP TO: " << end.startPos.frames(25) << ", ITEM START: " << item->startPos().frames(25);
3149 }
3150
3151 void CustomTrackView::moveGroup(QList <ItemInfo> startClip, QList <ItemInfo> startTransition, const GenTime offset, const int trackOffset, bool reverseMove)
3152 {
3153     // Group Items
3154     /*kDebug() << "//GRP MOVE, REVERS:" << reverseMove;
3155     kDebug() << "// GROUP MOV; OFFSET: " << offset.frames(25) << ", TK OFF: " << trackOffset;*/
3156     resetSelectionGroup();
3157     m_scene->clearSelection();
3158
3159     for (int i = 0; i < startClip.count(); i++) {
3160         if (reverseMove) {
3161             startClip[i].startPos = startClip.at(i).startPos - offset;
3162             startClip[i].track = startClip.at(i).track - trackOffset;
3163         }
3164         //kDebug()<<"//LKING FR CLIP AT:"<<startClip.at(i).startPos.frames(25)<<", TK:"<<startClip.at(i).track;
3165         ClipItem *clip = getClipItemAt(startClip.at(i).startPos, startClip.at(i).track);
3166         if (clip) {
3167             clip->setItemLocked(false);
3168             if (clip->parentItem()) clip->parentItem()->setSelected(true);
3169             else clip->setSelected(true);
3170             m_document->renderer()->mltRemoveClip(m_document->tracksCount() - startClip.at(i).track, startClip.at(i).startPos);
3171         } else kDebug() << "//MISSING CLIP AT: " << startClip.at(i).startPos.frames(25);
3172     }
3173     for (int i = 0; i < startTransition.count(); i++) {
3174         if (reverseMove) {
3175             startTransition[i].startPos = startTransition.at(i).startPos - offset;
3176             startTransition[i].track = startTransition.at(i).track - trackOffset;
3177         }
3178         Transition *tr = getTransitionItemAt(startTransition.at(i).startPos, startTransition.at(i).track);
3179         if (tr) {
3180             tr->setItemLocked(false);
3181             if (tr->parentItem()) tr->parentItem()->setSelected(true);
3182             else tr->setSelected(true);
3183             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());
3184         } else kDebug() << "//MISSING TRANSITION AT: " << startTransition.at(i).startPos.frames(25);
3185     }
3186     groupSelectedItems(true);
3187     if (m_selectionGroup) {
3188         bool snap = KdenliveSettings::snaptopoints();
3189         KdenliveSettings::setSnaptopoints(false);
3190
3191         m_selectionGroup->moveBy(offset.frames(m_document->fps()), trackOffset * (qreal) m_tracksHeight);
3192
3193         kDebug() << "%% GRP NEW POS: " << m_selectionGroup->scenePos().x();
3194
3195         QList<QGraphicsItem *> children = m_selectionGroup->childItems();
3196         // Expand groups
3197         int max = children.count();
3198         for (int i = 0; i < max; i++) {
3199             if (children.at(i)->type() == GROUPWIDGET) {
3200                 children += children.at(i)->childItems();
3201             }
3202         }
3203         kDebug() << "// GRP MOVE; FOUND CHILDREN:" << children.count();
3204
3205         for (int i = 0; i < children.count(); i++) {
3206             // re-add items in correct place
3207             if (children.at(i)->type() != AVWIDGET && children.at(i)->type() != TRANSITIONWIDGET) continue;
3208             AbstractClipItem *item = static_cast <AbstractClipItem *>(children.at(i));
3209             item->updateItem();
3210             ItemInfo info = item->info();
3211             int tracknumber = m_document->tracksCount() - info.track - 1;
3212             bool isLocked = m_document->trackInfoAt(tracknumber).isLocked;
3213             if (isLocked) item->setItemLocked(true);
3214             else if (item->isItemLocked()) item->setItemLocked(false);
3215
3216             if (item->type() == AVWIDGET) {
3217                 ClipItem *clip = static_cast <ClipItem*>(item);
3218                 info.track = m_document->tracksCount() - info.track;
3219                 Mlt::Producer *prod;
3220                 if (clip->isAudioOnly()) prod = clip->baseClip()->audioProducer(info.track);
3221                 else if (clip->isVideoOnly()) prod = clip->baseClip()->videoProducer();
3222                 else prod = clip->baseClip()->producer(info.track);
3223                 m_document->renderer()->mltInsertClip(info, clip->xml(), prod);
3224                 kDebug() << "// inserting new clp: " << info.startPos.frames(25);
3225             } else if (item->type() == TRANSITIONWIDGET) {
3226                 Transition *tr = static_cast <Transition*>(item);
3227                 int newTrack = tr->transitionEndTrack();
3228                 kDebug() << "/// TRANSITION CURR TRK: " << newTrack;
3229                 if (!tr->forcedTrack()) {
3230                     newTrack += trackOffset;
3231                     if (newTrack < 0 || newTrack > m_document->tracksCount()) newTrack = getPreviousVideoTrack(info.track);
3232                 }
3233                 tr->updateTransitionEndTrack(newTrack);
3234                 kDebug() << "/// TRANSITION UPDATED TRK: " << newTrack;
3235                 m_document->renderer()->mltAddTransition(tr->transitionTag(), newTrack, m_document->tracksCount() - info.track, info.startPos, info.endPos, tr->toXML());
3236             }
3237         }
3238         KdenliveSettings::setSnaptopoints(snap);
3239     } else kDebug() << "///////// WARNING; NO GROUP TO MOVE";
3240 }
3241
3242 void CustomTrackView::moveTransition(const ItemInfo start, const ItemInfo end)
3243 {
3244     Transition *item = getTransitionItemAt(start.startPos, start.track);
3245     if (!item) {
3246         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);
3247         kDebug() << "----------------  ERROR, CANNOT find transition to move... ";// << startPos.x() * m_scale * FRAME_SIZE + 1 << ", " << startPos.y() * m_tracksHeight + m_tracksHeight / 2;
3248         return;
3249     }
3250     //kDebug() << "----------------  Move TRANSITION FROM: " << startPos.x() << ", END:" << endPos.x() << ",TRACKS: " << oldtrack << " TO " << newtrack;
3251     bool snap = KdenliveSettings::snaptopoints();
3252     KdenliveSettings::setSnaptopoints(false);
3253     //kDebug()<<"///  RESIZE TRANS START: ("<< startPos.x()<<"x"<< startPos.y()<<") / ("<<endPos.x()<<"x"<< endPos.y()<<")";
3254     if (end.endPos - end.startPos == start.endPos - start.startPos) {
3255         // Transition was moved
3256         item->setPos((int) end.startPos.frames(m_document->fps()), (end.track) * m_tracksHeight + 1);
3257     } else if (end.endPos == start.endPos) {
3258         // Transition start resize
3259         item->resizeStart((int) end.startPos.frames(m_document->fps()));
3260     } else if (end.startPos == start.startPos) {
3261         // Transition end resize;
3262         item->resizeEnd((int) end.endPos.frames(m_document->fps()));
3263     } else {
3264         // Move & resize
3265         item->setPos((int) end.startPos.frames(m_document->fps()), (end.track) * m_tracksHeight + 1);
3266         item->resizeStart((int) end.startPos.frames(m_document->fps()));
3267         item->resizeEnd((int) end.endPos.frames(m_document->fps()));
3268     }
3269     //item->moveTransition(GenTime((int) (endPos.x() - startPos.x()), m_document->fps()));
3270     KdenliveSettings::setSnaptopoints(snap);
3271     item->updateTransitionEndTrack(getPreviousVideoTrack(end.track));
3272     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);
3273     if (m_dragItem && m_dragItem == item) {
3274         QPoint p;
3275         ClipItem *transitionClip = getClipItemAt(item->startPos(), item->track());
3276         if (transitionClip && transitionClip->baseClip()) {
3277             QString size = transitionClip->baseClip()->getProperty("frame_size");
3278             p.setX(size.section('x', 0, 0).toInt());
3279             p.setY(size.section('x', 1, 1).toInt());
3280         }
3281         emit transitionItemSelected(item, getPreviousVideoTrack(item->track()), p);
3282     }
3283 }
3284
3285 void CustomTrackView::resizeClip(const ItemInfo start, const ItemInfo end)
3286 {
3287     bool resizeClipStart = true;
3288     if (start.startPos == end.startPos) resizeClipStart = false;
3289     /*if (resizeClipStart) offset = 1;
3290     else offset = -1;*/
3291     ClipItem *item = getClipItemAt((int)(start.startPos.frames(m_document->fps())), start.track);
3292     if (!item) {
3293         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);
3294         kDebug() << "----------------  ERROR, CANNOT find clip to resize at... "; // << startPos;
3295         return;
3296     }
3297     if (item->parentItem()) {
3298         // Item is part of a group, reset group
3299         resetSelectionGroup();
3300     }
3301     bool snap = KdenliveSettings::snaptopoints();
3302     KdenliveSettings::setSnaptopoints(false);
3303     if (resizeClipStart && start.startPos != end.startPos) {
3304         ItemInfo clipinfo = item->info();
3305         clipinfo.track = m_document->tracksCount() - clipinfo.track;
3306         bool success = m_document->renderer()->mltResizeClipStart(clipinfo, end.startPos - item->startPos());
3307         if (success) {
3308             kDebug() << "RESIZE CLP STRAT TO:" << end.startPos.frames(m_document->fps()) << ", OLD ST: " << start.startPos.frames(25);
3309             item->resizeStart((int) end.startPos.frames(m_document->fps()));
3310             updateClipFade(item);
3311         } else emit displayMessage(i18n("Error when resizing clip"), ErrorMessage);
3312     } else if (!resizeClipStart) {
3313         ItemInfo clipinfo = item->info();
3314         clipinfo.track = m_document->tracksCount() - clipinfo.track;
3315         bool success = m_document->renderer()->mltResizeClipEnd(clipinfo, end.endPos - clipinfo.startPos);
3316         if (success) {
3317             item->resizeEnd((int) end.endPos.frames(m_document->fps()));
3318             updateClipFade(item, true);
3319         } else emit displayMessage(i18n("Error when resizing clip"), ErrorMessage);
3320     }
3321     if (end.cropStart != start.cropStart) {
3322         kDebug() << "// RESIZE CROP, DIFF: " << (end.cropStart - start.cropStart).frames(25);
3323         ItemInfo clipinfo = end;
3324         clipinfo.track = m_document->tracksCount() - end.track;
3325         bool success = m_document->renderer()->mltResizeClipCrop(clipinfo, end.cropStart - start.cropStart);
3326         if (success) {
3327             item->setCropStart(end.cropStart);
3328             item->resetThumbs();
3329         }
3330     }
3331     m_document->renderer()->doRefresh();
3332     KdenliveSettings::setSnaptopoints(snap);
3333 }
3334
3335 void CustomTrackView::updateClipFade(ClipItem * item, bool updateFadeOut)
3336 {
3337     if (!updateFadeOut) {
3338         int end = item->fadeIn();
3339         if (end != 0) {
3340             // there is a fade in effect
3341             int effectPos = item->hasEffect("volume", "fadein");
3342             if (effectPos != -1) {
3343                 QDomElement oldeffect = item->effectAt(effectPos);
3344                 int start = item->cropStart().frames(m_document->fps());
3345                 int max = item->cropDuration().frames(m_document->fps());
3346                 if (end > max) {
3347                     item->setFadeIn(max);
3348                     end = item->fadeIn();
3349                 }
3350                 end += start;
3351                 EffectsList::setParameter(oldeffect, "in", QString::number(start));
3352                 EffectsList::setParameter(oldeffect, "out", QString::number(end));
3353                 if (!m_document->renderer()->mltEditEffect(m_document->tracksCount() - item->track(), item->startPos(), item->getEffectArgs(oldeffect)))
3354                     emit displayMessage(i18n("Problem editing effect"), ErrorMessage);
3355                 // if fade effect is displayed, update the effect edit widget with new clip duration
3356                 if (item->isSelected() && effectPos == item->selectedEffectIndex()) emit clipItemSelected(item, effectPos);
3357             }
3358             effectPos = item->hasEffect("brightness", "fade_from_black");
3359             if (effectPos != -1) {
3360                 QDomElement oldeffect = item->effectAt(effectPos);
3361                 int start = item->cropStart().frames(m_document->fps());
3362                 int max = item->cropDuration().frames(m_document->fps());
3363                 if (end > max) {
3364                     item->setFadeIn(max);
3365                     end = item->fadeIn();
3366                 }
3367                 end += start;
3368                 EffectsList::setParameter(oldeffect, "in", QString::number(start));
3369                 EffectsList::setParameter(oldeffect, "out", QString::number(end));
3370                 if (!m_document->renderer()->mltEditEffect(m_document->tracksCount() - item->track(), item->startPos(), item->getEffectArgs(oldeffect)))
3371                     emit displayMessage(i18n("Problem editing effect"), ErrorMessage);
3372                 // if fade effect is displayed, update the effect edit widget with new clip duration
3373                 if (item->isSelected() && effectPos == item->selectedEffectIndex()) emit clipItemSelected(item, effectPos);
3374             }
3375         }
3376     } else {
3377         int start = item->fadeOut();
3378         if (start != 0) {
3379             // there is a fade in effect
3380             int effectPos = item->hasEffect("volume", "fadeout");
3381             if (effectPos != -1) {
3382                 QDomElement oldeffect = item->effectAt(effectPos);
3383                 int end = (item->duration() - item->cropStart()).frames(m_document->fps());
3384                 int max = item->cropDuration().frames(m_document->fps());
3385                 if (end > max) {
3386                     item->setFadeOut(max);
3387                     start = item->fadeOut();
3388                 }
3389                 start = end - start;
3390                 EffectsList::setParameter(oldeffect, "in", QString::number(start));
3391                 EffectsList::setParameter(oldeffect, "out", QString::number(end));
3392                 if (!m_document->renderer()->mltEditEffect(m_document->tracksCount() - item->track(), item->startPos(), item->getEffectArgs(oldeffect)))
3393                     emit displayMessage(i18n("Problem editing effect"), ErrorMessage);
3394                 // if fade effect is displayed, update the effect edit widget with new clip duration
3395                 if (item->isSelected() && effectPos == item->selectedEffectIndex()) emit clipItemSelected(item, effectPos);
3396             }
3397             effectPos = item->hasEffect("brightness", "fade_to_black");
3398             if (effectPos != -1) {
3399                 QDomElement oldeffect = item->effectAt(effectPos);
3400                 int end = (item->duration() - item->cropStart()).frames(m_document->fps());
3401                 int max = item->cropDuration().frames(m_document->fps());
3402                 if (end > max) {
3403                     item->setFadeOut(max);
3404                     start = item->fadeOut();
3405                 }
3406                 start = end - start;
3407                 EffectsList::setParameter(oldeffect, "in", QString::number(start));
3408                 EffectsList::setParameter(oldeffect, "out", QString::number(end));
3409                 if (!m_document->renderer()->mltEditEffect(m_document->tracksCount() - item->track(), item->startPos(), item->getEffectArgs(oldeffect)))
3410                     emit displayMessage(i18n("Problem editing effect"), ErrorMessage);
3411                 // if fade effect is displayed, update the effect edit widget with new clip duration
3412                 if (item->isSelected() && effectPos == item->selectedEffectIndex()) emit clipItemSelected(item, effectPos);
3413             }
3414         }
3415     }
3416 }
3417
3418 double CustomTrackView::getSnapPointForPos(double pos)
3419 {
3420     return m_scene->getSnapPointForPos(pos, KdenliveSettings::snaptopoints());
3421 }
3422
3423 void CustomTrackView::updateSnapPoints(AbstractClipItem *selected, QList <GenTime> offsetList, bool skipSelectedItems)
3424 {
3425     QList <GenTime> snaps;
3426     if (selected && offsetList.isEmpty()) offsetList.append(selected->duration());
3427     QList<QGraphicsItem *> itemList = items();
3428     for (int i = 0; i < itemList.count(); i++) {
3429         if (itemList.at(i) == selected) continue;
3430         if (skipSelectedItems && itemList.at(i)->isSelected()) continue;
3431         if (itemList.at(i)->type() == AVWIDGET) {
3432             ClipItem *item = static_cast <ClipItem *>(itemList.at(i));
3433             GenTime start = item->startPos();
3434             GenTime end = item->endPos();
3435             snaps.append(start);
3436             snaps.append(end);
3437             if (!offsetList.isEmpty()) {
3438                 for (int j = 0; j < offsetList.size(); j++) {
3439                     if (start > offsetList.at(j)) snaps.append(start - offsetList.at(j));
3440                     if (end > offsetList.at(j)) snaps.append(end - offsetList.at(j));
3441                 }
3442             }
3443             // Add clip markers
3444             QList < GenTime > markers = item->snapMarkers();
3445             for (int j = 0; j < markers.size(); ++j) {
3446                 GenTime t = markers.at(j);
3447                 snaps.append(t);
3448                 if (!offsetList.isEmpty()) {
3449                     for (int k = 0; k < offsetList.size(); k++) {
3450                         if (t > offsetList.at(k)) snaps.append(t - offsetList.at(k));
3451                     }
3452                 }
3453             }
3454         } else if (itemList.at(i)->type() == TRANSITIONWIDGET) {
3455             Transition *transition = static_cast <Transition*>(itemList.at(i));
3456             GenTime start = transition->startPos();
3457             GenTime end = transition->endPos();
3458             snaps.append(start);
3459             snaps.append(end);
3460             if (!offsetList.isEmpty()) {
3461                 for (int j = 0; j < offsetList.size(); j++) {
3462                     if (start > offsetList.at(j)) snaps.append(start - offsetList.at(j));
3463                     if (end > offsetList.at(j)) snaps.append(end - offsetList.at(j));
3464                 }
3465             }
3466         }
3467     }
3468
3469     // add cursor position
3470     GenTime pos = GenTime(m_cursorPos, m_document->fps());
3471     snaps.append(pos);
3472     if (!offsetList.isEmpty()) {
3473         for (int j = 0; j < offsetList.size(); j++) {
3474             snaps.append(pos - offsetList.at(j));
3475         }
3476     }
3477
3478     // add guides
3479     for (int i = 0; i < m_guides.count(); i++) {
3480         snaps.append(m_guides.at(i)->position());
3481         if (!offsetList.isEmpty()) {
3482             for (int j = 0; j < offsetList.size(); j++) {
3483                 snaps.append(m_guides.at(i)->position() - offsetList.at(j));
3484             }
3485         }
3486     }
3487
3488     qSort(snaps);
3489     m_scene->setSnapList(snaps);
3490     //for (int i = 0; i < m_snapPoints.size(); ++i)
3491     //    kDebug() << "SNAP POINT: " << m_snapPoints.at(i).frames(25);
3492 }
3493
3494 void CustomTrackView::slotSeekToPreviousSnap()
3495 {
3496     updateSnapPoints(NULL);
3497     GenTime res = m_scene->previousSnapPoint(GenTime(m_cursorPos, m_document->fps()));
3498     setCursorPos((int) res.frames(m_document->fps()));
3499     checkScrolling();
3500 }
3501
3502 void CustomTrackView::slotSeekToNextSnap()
3503 {
3504     updateSnapPoints(NULL);
3505     GenTime res = m_scene->nextSnapPoint(GenTime(m_cursorPos, m_document->fps()));
3506     setCursorPos((int) res.frames(m_document->fps()));
3507     checkScrolling();
3508 }
3509
3510 void CustomTrackView::clipStart()
3511 {
3512     ClipItem *item = getMainActiveClip();
3513     if (item != NULL) {
3514         setCursorPos((int) item->startPos().frames(m_document->fps()));
3515         checkScrolling();
3516     }
3517 }
3518
3519 void CustomTrackView::clipEnd()
3520 {
3521     ClipItem *item = getMainActiveClip();
3522     if (item != NULL) {
3523         setCursorPos((int) item->endPos().frames(m_document->fps()) - 1);
3524         checkScrolling();
3525     }
3526 }
3527
3528 void CustomTrackView::slotAddClipMarker(const QString &id, GenTime t, QString c)
3529 {
3530     QString oldcomment = m_document->clipManager()->getClipById(id)->markerComment(t);
3531     AddMarkerCommand *command = new AddMarkerCommand(this, oldcomment, c, id, t);
3532     m_commandStack->push(command);
3533 }
3534
3535 void CustomTrackView::slotDeleteClipMarker(const QString &comment, const QString &id, const GenTime &position)
3536 {
3537     AddMarkerCommand *command = new AddMarkerCommand(this, comment, QString(), id, position);
3538     m_commandStack->push(command);
3539 }
3540
3541 void CustomTrackView::slotDeleteAllClipMarkers(const QString &id)
3542 {
3543     DocClipBase *base = m_document->clipManager()->getClipById(id);
3544     QList <CommentedTime> markers = base->commentedSnapMarkers();
3545
3546     if (markers.isEmpty()) {
3547         emit displayMessage(i18n("Clip has no markers"), ErrorMessage);
3548         return;
3549     }
3550     QUndoCommand *deleteMarkers = new QUndoCommand();
3551     deleteMarkers->setText("Delete clip markers");
3552
3553     for (int i = 0; i < markers.size(); i++) {
3554         new AddMarkerCommand(this, markers.at(i).comment(), QString(), id, markers.at(i).time(), deleteMarkers);
3555     }
3556     m_commandStack->push(deleteMarkers);
3557 }
3558
3559 void CustomTrackView::addMarker(const QString &id, const GenTime &pos, const QString comment)
3560 {
3561     DocClipBase *base = m_document->clipManager()->getClipById(id);
3562     if (!comment.isEmpty()) base->addSnapMarker(pos, comment);
3563     else base->deleteSnapMarker(pos);
3564     m_document->setModified(true);
3565     viewport()->update();
3566 }
3567
3568 bool sortGuidesList(const Guide *g1 , const Guide *g2)
3569 {
3570     return (*g1).position() < (*g2).position();
3571 }
3572
3573 int CustomTrackView::hasGuide(int pos, int offset)
3574 {
3575     for (int i = 0; i < m_guides.count(); i++) {
3576         int guidePos = m_guides.at(i)->position().frames(m_document->fps());
3577         if (qAbs(guidePos - pos) <= offset) return guidePos;
3578         else if (guidePos > pos) return -1;
3579     }
3580     return -1;
3581 }
3582
3583 void CustomTrackView::editGuide(const GenTime oldPos, const GenTime pos, const QString &comment)
3584 {
3585     if (oldPos > GenTime() && pos > GenTime()) {
3586         // move guide
3587         for (int i = 0; i < m_guides.count(); i++) {
3588             if (m_guides.at(i)->position() == oldPos) {
3589                 Guide *item = m_guides.at(i);
3590                 item->updateGuide(pos, comment);
3591                 break;
3592             }
3593         }
3594     } else if (pos > GenTime()) addGuide(pos, comment);
3595     else {
3596         // remove guide
3597         bool found = false;
3598         for (int i = 0; i < m_guides.count(); i++) {
3599             if (m_guides.at(i)->position() == oldPos) {
3600                 delete m_guides.takeAt(i);
3601                 found = true;
3602                 break;
3603             }
3604         }
3605         if (!found) emit displayMessage(i18n("No guide at cursor time"), ErrorMessage);
3606     }
3607     qSort(m_guides.begin(), m_guides.end(), sortGuidesList);
3608     m_document->syncGuides(m_guides);
3609 }
3610
3611 bool CustomTrackView::addGuide(const GenTime pos, const QString &comment)
3612 {
3613     for (int i = 0; i < m_guides.count(); i++) {
3614         if (m_guides.at(i)->position() == pos) {
3615             emit displayMessage(i18n("A guide already exists at position %1", m_document->timecode().getTimecodeFromFrames(pos.frames(m_document->fps()))), ErrorMessage);
3616             return false;
3617         }
3618     }
3619     Guide *g = new Guide(this, pos, comment, m_document->fps(), m_tracksHeight * m_document->tracksCount());
3620     scene()->addItem(g);
3621     m_guides.append(g);
3622     qSort(m_guides.begin(), m_guides.end(), sortGuidesList);
3623     m_document->syncGuides(m_guides);
3624     return true;
3625 }
3626
3627 void CustomTrackView::slotAddGuide()
3628 {
3629     CommentedTime marker(GenTime(m_cursorPos, m_document->fps()), i18n("Guide"));
3630     MarkerDialog d(NULL, marker, m_document->timecode(), i18n("Add Guide"), this);
3631     if (d.exec() != QDialog::Accepted) return;
3632     if (addGuide(d.newMarker().time(), d.newMarker().comment())) {
3633         EditGuideCommand *command = new EditGuideCommand(this, GenTime(), QString(), d.newMarker().time(), d.newMarker().comment(), false);
3634         m_commandStack->push(command);
3635     }
3636 }
3637
3638 void CustomTrackView::slotEditGuide(int guidePos)
3639 {
3640     GenTime pos;
3641     if (guidePos == -1) pos = GenTime(m_cursorPos, m_document->fps());
3642     else pos = GenTime(guidePos, m_document->fps());
3643     bool found = false;
3644     for (int i = 0; i < m_guides.count(); i++) {
3645         if (m_guides.at(i)->position() == pos) {
3646             slotEditGuide(m_guides.at(i)->info());
3647             found = true;
3648             break;
3649         }
3650     }
3651     if (!found) emit displayMessage(i18n("No guide at cursor time"), ErrorMessage);
3652 }
3653
3654 void CustomTrackView::slotEditGuide(CommentedTime guide)
3655 {
3656     MarkerDialog d(NULL, guide, m_document->timecode(), i18n("Edit Guide"), this);
3657     if (d.exec() == QDialog::Accepted) {
3658         EditGuideCommand *command = new EditGuideCommand(this, guide.time(), guide.comment(), d.newMarker().time(), d.newMarker().comment(), true);
3659         m_commandStack->push(command);
3660     }
3661 }
3662
3663
3664 void CustomTrackView::slotEditTimeLineGuide()
3665 {
3666     if (m_dragGuide == NULL) return;
3667     CommentedTime guide = m_dragGuide->info();
3668     MarkerDialog d(NULL, guide, m_document->timecode(), i18n("Edit Guide"), this);
3669     if (d.exec() == QDialog::Accepted) {
3670         EditGuideCommand *command = new EditGuideCommand(this, guide.time(), guide.comment(), d.newMarker().time(), d.newMarker().comment(), true);
3671         m_commandStack->push(command);
3672     }
3673 }
3674
3675 void CustomTrackView::slotDeleteGuide(int guidePos)
3676 {
3677     GenTime pos;
3678     if (guidePos == -1) pos = GenTime(m_cursorPos, m_document->fps());
3679     else pos = GenTime(guidePos, m_document->fps());
3680     bool found = false;
3681     for (int i = 0; i < m_guides.count(); i++) {
3682         if (m_guides.at(i)->position() == pos) {
3683             EditGuideCommand *command = new EditGuideCommand(this, m_guides.at(i)->position(), m_guides.at(i)->label(), GenTime(), QString(), true);
3684             m_commandStack->push(command);
3685             found = true;
3686             break;
3687         }
3688     }
3689     if (!found) emit displayMessage(i18n("No guide at cursor time"), ErrorMessage);
3690 }
3691
3692
3693 void CustomTrackView::slotDeleteTimeLineGuide()
3694 {
3695     if (m_dragGuide == NULL) return;
3696     EditGuideCommand *command = new EditGuideCommand(this, m_dragGuide->position(), m_dragGuide->label(), GenTime(), QString(), true);
3697     m_commandStack->push(command);
3698 }
3699
3700
3701 void CustomTrackView::slotDeleteAllGuides()
3702 {
3703     QUndoCommand *deleteAll = new QUndoCommand();
3704     deleteAll->setText("Delete all guides");
3705     for (int i = 0; i < m_guides.count(); i++) {
3706         new EditGuideCommand(this, m_guides.at(i)->position(), m_guides.at(i)->label(), GenTime(), QString(), true, deleteAll);
3707     }
3708     m_commandStack->push(deleteAll);
3709 }
3710
3711 void CustomTrackView::setTool(PROJECTTOOL tool)
3712 {
3713     m_tool = tool;
3714 }
3715
3716 void CustomTrackView::setScale(double scaleFactor)
3717 {
3718     QMatrix matrix;
3719     matrix = matrix.scale(scaleFactor, 1);
3720     m_scene->setScale(scaleFactor);
3721     //scale(scaleFactor, 1);
3722     m_animationTimer->stop();
3723     delete m_visualTip;
3724     m_visualTip = NULL;
3725     delete m_animation;
3726     m_animation = NULL;
3727
3728     //setSceneRect(0, 0, m_projectDuration + 100 * scaleFactor, sceneRect().height());
3729     setMatrix(matrix);
3730     int diff = sceneRect().width() - m_projectDuration;
3731     if (diff * matrix.m11() < 50) {
3732         if (matrix.m11() < 0.4) setSceneRect(0, 0, (m_projectDuration + 100 / matrix.m11()), sceneRect().height());
3733         else setSceneRect(0, 0, (m_projectDuration + 300), sceneRect().height());
3734     }
3735
3736     centerOn(QPointF(cursorPos(), m_tracksHeight));
3737     //verticalScrollBar()->setValue(vert);*/
3738 }
3739
3740 void CustomTrackView::slotRefreshGuides()
3741 {
3742     if (KdenliveSettings::showmarkers()) {
3743         kDebug() << "// refresh GUIDES";
3744         for (int i = 0; i < m_guides.count(); i++) {
3745             m_guides.at(i)->update();
3746         }
3747     }
3748 }
3749
3750 void CustomTrackView::drawBackground(QPainter * painter, const QRectF & rect)
3751 {
3752     QRectF r = rect;
3753     r.setWidth(r.width() + 1);
3754     painter->setClipRect(r);
3755     painter->drawLine(r.left(), 0, r.right(), 0);
3756     uint max = m_document->tracksCount();
3757     KColorScheme scheme(palette().currentColorGroup(), KColorScheme::Window);
3758     QColor lockedColor = scheme.background(KColorScheme::NegativeBackground).color();
3759     QColor audioColor = palette().alternateBase().color();
3760     QColor base = scheme.background(KColorScheme::NormalBackground).color();
3761     for (uint i = 0; i < max;i++) {
3762         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));
3763         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));
3764         painter->drawLine(r.left(), m_tracksHeight * (i + 1), r.right(), m_tracksHeight * (i + 1));
3765     }
3766     int lowerLimit = m_tracksHeight * m_document->tracksCount() + 1;
3767     if (height() > lowerLimit)
3768         painter->fillRect(QRectF(r.left(), lowerLimit, r.width(), height() - lowerLimit), QBrush(base));
3769 }
3770
3771 bool CustomTrackView::findString(const QString &text)
3772 {
3773     QString marker;
3774     for (int i = 0; i < m_searchPoints.size(); ++i) {
3775         marker = m_searchPoints.at(i).comment();
3776         if (marker.contains(text, Qt::CaseInsensitive)) {
3777             setCursorPos(m_searchPoints.at(i).time().frames(m_document->fps()), true);
3778             int vert = verticalScrollBar()->value();
3779             int hor = cursorPos();
3780             ensureVisible(hor, vert + 10, 2, 2, 50, 0);
3781             m_findIndex = i;
3782             return true;
3783         }
3784     }
3785     return false;
3786 }
3787
3788 bool CustomTrackView::findNextString(const QString &text)
3789 {
3790     QString marker;
3791     for (int i = m_findIndex + 1; i < m_searchPoints.size(); ++i) {
3792         marker = m_searchPoints.at(i).comment();
3793         if (marker.contains(text, Qt::CaseInsensitive)) {
3794             setCursorPos(m_searchPoints.at(i).time().frames(m_document->fps()), true);
3795             int vert = verticalScrollBar()->value();
3796             int hor = cursorPos();
3797             ensureVisible(hor, vert + 10, 2, 2, 50, 0);
3798             m_findIndex = i;
3799             return true;
3800         }
3801     }
3802     m_findIndex = -1;
3803     return false;
3804 }
3805
3806 void CustomTrackView::initSearchStrings()
3807 {
3808     m_searchPoints.clear();
3809     QList<QGraphicsItem *> itemList = items();
3810     for (int i = 0; i < itemList.count(); i++) {
3811         // parse all clip names
3812         if (itemList.at(i)->type() == AVWIDGET) {
3813             ClipItem *item = static_cast <ClipItem *>(itemList.at(i));
3814             GenTime start = item->startPos();
3815             CommentedTime t(start, item->clipName());
3816             m_searchPoints.append(t);
3817             // add all clip markers
3818             QList < CommentedTime > markers = item->commentedSnapMarkers();
3819             m_searchPoints += markers;
3820         }
3821     }
3822
3823     // add guides
3824     for (int i = 0; i < m_guides.count(); i++) {
3825         m_searchPoints.append(m_guides.at(i)->info());
3826     }
3827
3828     qSort(m_searchPoints);
3829 }
3830
3831 void CustomTrackView::clearSearchStrings()
3832 {
3833     m_searchPoints.clear();
3834     m_findIndex = 0;
3835 }
3836
3837 void CustomTrackView::copyClip()
3838 {
3839     qDeleteAll(m_copiedItems);
3840     m_copiedItems.clear();
3841     QList<QGraphicsItem *> itemList = scene()->selectedItems();
3842     if (itemList.count() == 0) {
3843         emit displayMessage(i18n("Select a clip before copying"), ErrorMessage);
3844         return;
3845     }
3846     for (int i = 0; i < itemList.count(); i++) {
3847         if (itemList.at(i)->type() == AVWIDGET) {
3848             ClipItem *dup = static_cast <ClipItem *>(itemList.at(i));
3849             m_copiedItems.append(dup->clone(dup->info()));
3850         } else if (itemList.at(i)->type() == TRANSITIONWIDGET) {
3851             Transition *dup = static_cast <Transition *>(itemList.at(i));
3852             m_copiedItems.append(dup->clone());
3853         }
3854     }
3855 }
3856
3857 bool CustomTrackView::canBePastedTo(ItemInfo info, int type) const
3858 {
3859     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));
3860     QList<QGraphicsItem *> collisions = scene()->items(rect, Qt::IntersectsItemBoundingRect);
3861     for (int i = 0; i < collisions.count(); i++) {
3862         if (collisions.at(i)->type() == type) return false;
3863     }
3864     return true;
3865 }
3866
3867 bool CustomTrackView::canBePasted(QList<AbstractClipItem *> items, GenTime offset, int trackOffset) const
3868 {
3869     for (int i = 0; i < items.count(); i++) {
3870         ItemInfo info = items.at(i)->info();
3871         info.startPos += offset;
3872         info.endPos += offset;
3873         info.track += trackOffset;
3874         if (!canBePastedTo(info, items.at(i)->type())) return false;
3875     }
3876     return true;
3877 }
3878
3879 bool CustomTrackView::canBeMoved(QList<AbstractClipItem *> items, GenTime offset, int trackOffset) const
3880 {
3881     QPainterPath movePath;
3882     movePath.moveTo(0, 0);
3883
3884     for (int i = 0; i < items.count(); i++) {
3885         ItemInfo info = items.at(i)->info();
3886         info.startPos = info.startPos + offset;
3887         info.endPos = info.endPos + offset;
3888         info.track = info.track + trackOffset;
3889         if (info.startPos < GenTime()) {
3890             // No clip should go below 0
3891             return false;
3892         }
3893         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));
3894         movePath.addRect(rect);
3895     }
3896     QList<QGraphicsItem *> collisions = scene()->items(movePath, Qt::IntersectsItemBoundingRect);
3897     for (int i = 0; i < collisions.count(); i++) {
3898         if ((collisions.at(i)->type() == AVWIDGET || collisions.at(i)->type() == TRANSITIONWIDGET) && !items.contains(static_cast <AbstractClipItem *>(collisions.at(i)))) {
3899             kDebug() << "  ////////////   CLIP COLLISION, MOVE NOT ALLOWED";
3900             return false;
3901         }
3902     }
3903     return true;
3904 }
3905
3906 void CustomTrackView::pasteClip()
3907 {
3908     if (m_copiedItems.count() == 0) {
3909         emit displayMessage(i18n("No clip copied"), ErrorMessage);
3910         return;
3911     }
3912     QPoint position;
3913     if (m_menuPosition.isNull()) {
3914         position = mapFromGlobal(QCursor::pos());
3915         if (!underMouse() || position.y() > m_tracksHeight * m_document->tracksCount()) {
3916             emit displayMessage(i18n("Cannot paste selected clips"), ErrorMessage);
3917             return;
3918         }
3919     } else position = m_menuPosition;
3920     GenTime pos = GenTime((int)(mapToScene(position).x()), m_document->fps());
3921     int track = (int)(position.y() / m_tracksHeight);
3922     ItemInfo first = m_copiedItems.at(0)->info();
3923
3924     GenTime offset = pos - first.startPos;
3925     int trackOffset = track - first.track;
3926
3927     if (!canBePasted(m_copiedItems, offset, trackOffset)) {
3928         emit displayMessage(i18n("Cannot paste selected clips"), ErrorMessage);
3929         return;
3930     }
3931     QUndoCommand *pasteClips = new QUndoCommand();
3932     pasteClips->setText("Paste clips");
3933
3934     for (int i = 0; i < m_copiedItems.count(); i++) {
3935         // parse all clip names
3936         if (m_copiedItems.at(i) && m_copiedItems.at(i)->type() == AVWIDGET) {
3937             ClipItem *clip = static_cast <ClipItem *>(m_copiedItems.at(i));
3938             ItemInfo info;
3939             info.startPos = clip->startPos() + offset;
3940             info.endPos = clip->endPos() + offset;
3941             info.cropStart = clip->cropStart();
3942             info.track = clip->track() + trackOffset;
3943             if (canBePastedTo(info, AVWIDGET)) {
3944                 new AddTimelineClipCommand(this, clip->xml(), clip->clipProducer(), info, clip->effectList(), true, false, pasteClips);
3945             } else emit displayMessage(i18n("Cannot paste clip to selected place"), ErrorMessage);
3946         } else if (m_copiedItems.at(i) && m_copiedItems.at(i)->type() == TRANSITIONWIDGET) {
3947             Transition *tr = static_cast <Transition *>(m_copiedItems.at(i));
3948             ItemInfo info;
3949             info.startPos = tr->startPos() + offset;
3950             info.endPos = tr->endPos() + offset;
3951             info.track = tr->track() + trackOffset;
3952             if (canBePastedTo(info, TRANSITIONWIDGET)) {
3953                 if (info.startPos >= info.endPos) {
3954                     emit displayMessage(i18n("Invalid transition"), ErrorMessage);
3955                 } else new AddTransitionCommand(this, info, tr->transitionEndTrack() + trackOffset, tr->toXML(), false, true, pasteClips);
3956             } else emit displayMessage(i18n("Cannot paste transition to selected place"), ErrorMessage);
3957         }
3958     }
3959     m_commandStack->push(pasteClips);
3960 }
3961
3962 void CustomTrackView::pasteClipEffects()
3963 {
3964     if (m_copiedItems.count() != 1 || m_copiedItems.at(0)->type() != AVWIDGET) {
3965         emit displayMessage(i18n("You must copy exactly one clip before pasting effects"), ErrorMessage);
3966         return;
3967     }
3968     ClipItem *clip = static_cast < ClipItem *>(m_copiedItems.at(0));
3969     EffectsList effects = clip->effectList();
3970
3971     QUndoCommand *paste = new QUndoCommand();
3972     paste->setText("Paste effects");
3973
3974     QList<QGraphicsItem *> clips = scene()->selectedItems();
3975     for (int i = 0; i < clips.count(); ++i) {
3976         if (clips.at(i)->type() == AVWIDGET) {
3977             ClipItem *item = static_cast < ClipItem *>(clips.at(i));
3978             for (int i = 0; i < clip->effectsCount(); i++) {
3979                 new AddEffectCommand(this, m_document->tracksCount() - item->track(), item->startPos(), clip->effectAt(i), true, paste);
3980             }
3981         }
3982     }
3983     m_commandStack->push(paste);
3984 }
3985
3986
3987 ClipItem *CustomTrackView::getClipUnderCursor() const
3988 {
3989     QRectF rect((double) m_cursorPos, 0.0, 1.0, (double)(m_tracksHeight * m_document->tracksCount()));
3990     QList<QGraphicsItem *> collisions = scene()->items(rect, Qt::IntersectsItemBoundingRect);
3991     for (int i = 0; i < collisions.count(); i++) {
3992         if (collisions.at(i)->type() == AVWIDGET) {
3993             return static_cast < ClipItem *>(collisions.at(i));
3994         }
3995     }
3996     return NULL;
3997 }
3998
3999 ClipItem *CustomTrackView::getMainActiveClip() const
4000 {
4001     QList<QGraphicsItem *> clips = scene()->selectedItems();
4002     if (clips.isEmpty()) {
4003         return getClipUnderCursor();
4004     } else {
4005         ClipItem *item = NULL;
4006         for (int i = 0; i < clips.count(); ++i) {
4007             if (clips.at(i)->type() == AVWIDGET)
4008                 item = static_cast < ClipItem *>(clips.at(i));
4009             if (item->startPos().frames(m_document->fps()) <= m_cursorPos && item->endPos().frames(m_document->fps()) >= m_cursorPos) break;
4010         }
4011         if (item) return item;
4012     }
4013     return NULL;
4014 }
4015
4016 ClipItem *CustomTrackView::getActiveClipUnderCursor(bool allowOutsideCursor) const
4017 {
4018     QList<QGraphicsItem *> clips = scene()->selectedItems();
4019     if (clips.isEmpty()) {
4020         return getClipUnderCursor();
4021     } else {
4022         ClipItem *item;
4023         // remove all items in the list that are not clips
4024         for (int i = 0; i < clips.count();) {
4025             if (clips.at(i)->type() != AVWIDGET) clips.removeAt(i);
4026             else i++;
4027         }
4028         if (clips.count() == 1 && allowOutsideCursor) return static_cast < ClipItem *>(clips.at(0));
4029         for (int i = 0; i < clips.count(); ++i) {
4030             if (clips.at(i)->type() == AVWIDGET) {
4031                 item = static_cast < ClipItem *>(clips.at(i));
4032                 if (item->startPos().frames(m_document->fps()) <= m_cursorPos && item->endPos().frames(m_document->fps()) >= m_cursorPos)
4033                     return item;
4034             }
4035         }
4036     }
4037     return NULL;
4038 }
4039
4040 void CustomTrackView::setInPoint()
4041 {
4042     ClipItem *clip = getActiveClipUnderCursor(true);
4043     if (clip == NULL) {
4044         emit displayMessage(i18n("You must select one clip for this action"), ErrorMessage);
4045         return;
4046     }
4047     ItemInfo startInfo = clip->info();
4048     ItemInfo endInfo = startInfo;
4049     endInfo.startPos = GenTime(m_cursorPos, m_document->fps());
4050     if (endInfo.startPos >= startInfo.endPos) {
4051         // Check for invalid resize
4052         emit displayMessage(i18n("Invalid action"), ErrorMessage);
4053         return;
4054     } else if (endInfo.startPos < startInfo.startPos) {
4055         int length = m_document->renderer()->mltGetSpaceLength(endInfo.startPos, m_document->tracksCount() - startInfo.track, false);
4056         if (length < (startInfo.startPos - endInfo.startPos).frames(m_document->fps())) {
4057             emit displayMessage(i18n("Invalid action"), ErrorMessage);
4058             return;
4059         }
4060     }
4061     ResizeClipCommand *command = new ResizeClipCommand(this, startInfo, endInfo, true);
4062     m_commandStack->push(command);
4063 }
4064
4065 void CustomTrackView::setOutPoint()
4066 {
4067     ClipItem *clip = getActiveClipUnderCursor(true);
4068     if (clip == NULL) {
4069         emit displayMessage(i18n("You must select one clip for this action"), ErrorMessage);
4070         return;
4071     }
4072     ItemInfo startInfo = clip->info();
4073     ItemInfo endInfo = clip->info();
4074     endInfo.endPos = GenTime(m_cursorPos, m_document->fps());
4075     if (endInfo.endPos <= startInfo.startPos) {
4076         // Check for invalid resize
4077         emit displayMessage(i18n("Invalid action"), ErrorMessage);
4078         return;
4079     } else if (endInfo.endPos > startInfo.endPos) {
4080         int length = m_document->renderer()->mltGetSpaceLength(endInfo.endPos, m_document->tracksCount() - startInfo.track, false);
4081         if (length < (endInfo.endPos - startInfo.endPos).frames(m_document->fps())) {
4082             emit displayMessage(i18n("Invalid action"), ErrorMessage);
4083             return;
4084         }
4085     }
4086
4087
4088
4089     ResizeClipCommand *command = new ResizeClipCommand(this, startInfo, endInfo, true);
4090     m_commandStack->push(command);
4091 }
4092
4093 void CustomTrackView::slotUpdateAllThumbs()
4094 {
4095     QList<QGraphicsItem *> itemList = items();
4096     //if (itemList.isEmpty()) return;
4097     ClipItem *item;
4098     const QString thumbBase = m_document->projectFolder().path() + "/thumbs/";
4099     for (int i = 0; i < itemList.count(); i++) {
4100         if (itemList.at(i)->type() == AVWIDGET) {
4101             item = static_cast <ClipItem *>(itemList.at(i));
4102             if (item->clipType() != COLOR) {
4103                 // Check if we have a cached thumbnail
4104                 if (item->clipType() == IMAGE || item->clipType() == TEXT || item->clipType() == AUDIO) {
4105                     QString thumb = thumbBase + item->baseClip()->getClipHash() + "_0.png";
4106                     if (QFile::exists(thumb)) {
4107                         QPixmap pix(thumb);
4108                         item->slotSetStartThumb(pix);
4109                         item->slotSetEndThumb(pix);
4110                     }
4111                 } else {
4112                     QString startThumb = thumbBase + item->baseClip()->getClipHash() + '_';
4113                     QString endThumb = startThumb;
4114                     startThumb.append(QString::number(item->cropStart().frames(m_document->fps())) + ".png");
4115                     endThumb.append(QString::number((item->cropStart() + item->cropDuration()).frames(m_document->fps()) - 1) + ".png");
4116                     if (QFile::exists(startThumb)) {
4117                         QPixmap pix(startThumb);
4118                         item->slotSetStartThumb(pix);
4119                     }
4120                     if (QFile::exists(endThumb)) {
4121                         QPixmap pix(endThumb);
4122                         item->slotSetEndThumb(pix);
4123                     }
4124                 }
4125             }
4126             item->refreshClip(false);
4127             qApp->processEvents();
4128         }
4129     }
4130     viewport()->update();
4131 }
4132
4133 void CustomTrackView::saveThumbnails()
4134 {
4135     QList<QGraphicsItem *> itemList = items();
4136     ClipItem *item;
4137     QString thumbBase = m_document->projectFolder().path() + "/thumbs/";
4138     for (int i = 0; i < itemList.count(); i++) {
4139         if (itemList.at(i)->type() == AVWIDGET) {
4140             item = static_cast <ClipItem *>(itemList.at(i));
4141             if (item->clipType() != COLOR) {
4142                 // Check if we have a cached thumbnail
4143                 if (item->clipType() == IMAGE || item->clipType() == TEXT || item->clipType() == AUDIO) {
4144                     QString thumb = thumbBase + item->baseClip()->getClipHash() + "_0.png";
4145                     if (!QFile::exists(thumb)) {
4146                         QPixmap pix(item->startThumb());
4147                         pix.save(thumb);
4148                     }
4149                 } else {
4150                     QString startThumb = thumbBase + item->baseClip()->getClipHash() + '_';
4151                     QString endThumb = startThumb;
4152                     startThumb.append(QString::number(item->cropStart().frames(m_document->fps())) + ".png");
4153                     endThumb.append(QString::number((item->cropStart() + item->cropDuration()).frames(m_document->fps()) - 1) + ".png");
4154                     if (!QFile::exists(startThumb)) {
4155                         QPixmap pix(item->startThumb());
4156                         pix.save(startThumb);
4157                     }
4158                     if (!QFile::exists(endThumb)) {
4159                         QPixmap pix(item->endThumb());
4160                         pix.save(endThumb);
4161                     }
4162                 }
4163             }
4164         }
4165     }
4166 }
4167
4168
4169 void CustomTrackView::slotInsertTrack(int ix)
4170 {
4171     kDebug() << "// INSERTING TRK: " << ix;
4172     QDialog d(parentWidget());
4173     Ui::AddTrack_UI view;
4174     view.setupUi(&d);
4175     view.track_nb->setMaximum(m_document->tracksCount() - 1);
4176     view.track_nb->setValue(ix);
4177     d.setWindowTitle(i18n("Insert Track"));
4178
4179     if (d.exec() == QDialog::Accepted) {
4180         ix = view.track_nb->value();
4181         if (view.before_select->currentIndex() == 1) {
4182             ix++;
4183         }
4184         TrackInfo info;
4185         if (view.video_track->isChecked()) {
4186             info.type = VIDEOTRACK;
4187             info.isMute = false;
4188             info.isBlind = false;
4189             info.isLocked = false;
4190         } else {
4191             info.type = AUDIOTRACK;
4192             info.isMute = false;
4193             info.isBlind = true;
4194             info.isLocked = false;
4195         }
4196         AddTrackCommand *addTrack = new AddTrackCommand(this, ix, info, true);
4197         m_commandStack->push(addTrack);
4198         m_document->setModified(true);
4199     }
4200 }
4201
4202 void CustomTrackView::slotDeleteTrack(int ix)
4203 {
4204     bool ok;
4205     ix = QInputDialog::getInteger(this, i18n("Remove Track"), i18n("Track"), ix, 0, m_document->tracksCount() - 1, 1, &ok);
4206     if (ok) {
4207         TrackInfo info = m_document->trackInfoAt(m_document->tracksCount() - ix - 1);
4208         deleteTimelineTrack(ix, info);
4209         m_document->setModified(true);
4210         /*AddTrackCommand* command = new AddTrackCommand(this, ix, info, false);
4211         m_commandStack->push(command);*/
4212     }
4213 }
4214
4215 void CustomTrackView::slotChangeTrack(int ix)
4216 {
4217     QDialog d(parentWidget());
4218     Ui::AddTrack_UI view;
4219     view.setupUi(&d);
4220     view.label->setText(i18n("Change track"));
4221     view.before_select->setHidden(true);
4222     view.track_nb->setMaximum(m_document->tracksCount() - 1);
4223     view.track_nb->setValue(ix);
4224     d.setWindowTitle(i18n("Change Track Type"));
4225
4226     if (m_document->trackInfoAt(m_document->tracksCount() - ix - 1).type == VIDEOTRACK)
4227         view.video_track->setChecked(true);
4228     else
4229         view.audio_track->setChecked(true);
4230
4231     if (d.exec() == QDialog::Accepted) {
4232         TrackInfo info;
4233         info.isLocked = false;
4234         info.isMute = false;
4235         ix = view.track_nb->value();
4236
4237         if (view.video_track->isChecked()) {
4238             info.type = VIDEOTRACK;
4239             info.isBlind = false;
4240         } else {
4241             info.type = AUDIOTRACK;
4242             info.isBlind = true;
4243         }
4244         changeTimelineTrack(ix, info);
4245         m_document->setModified(true);
4246     }
4247 }
4248
4249
4250 void CustomTrackView::deleteTimelineTrack(int ix, TrackInfo trackinfo)
4251 {
4252     double startY = ix * m_tracksHeight + 1 + m_tracksHeight / 2;
4253     QRectF r(0, startY, sceneRect().width(), m_tracksHeight / 2 - 1);
4254     QList<QGraphicsItem *> selection = m_scene->items(r);
4255     QUndoCommand *deleteTrack = new QUndoCommand();
4256     deleteTrack->setText("Delete track");
4257
4258     // Delete all clips in selected track
4259     for (int i = 0; i < selection.count(); i++) {
4260         if (selection.at(i)->type() == AVWIDGET) {
4261             ClipItem *item =  static_cast <ClipItem *>(selection.at(i));
4262             new AddTimelineClipCommand(this, item->xml(), item->clipProducer(), item->info(), item->effectList(), false, true, deleteTrack);
4263             m_scene->removeItem(item);
4264             delete item;
4265             item = NULL;
4266         } else if (selection.at(i)->type() == TRANSITIONWIDGET) {
4267             Transition *item =  static_cast <Transition *>(selection.at(i));
4268             new AddTransitionCommand(this, item->info(), item->transitionEndTrack(), item->toXML(), true, false, deleteTrack);
4269             m_scene->removeItem(item);
4270             delete item;
4271             item = NULL;
4272         }
4273     }
4274
4275     selection = m_scene->items();
4276     new AddTrackCommand(this, ix, trackinfo, false, deleteTrack);
4277     m_commandStack->push(deleteTrack);
4278 }
4279
4280 void CustomTrackView::changeTimelineTrack(int ix, TrackInfo trackinfo)
4281 {
4282     TrackInfo oldinfo = m_document->trackInfoAt(m_document->tracksCount() - ix - 1);
4283     ChangeTrackCommand *changeTrack = new ChangeTrackCommand(this, ix, oldinfo, trackinfo);
4284     m_commandStack->push(changeTrack);
4285 }
4286
4287 void CustomTrackView::autoTransition()
4288 {
4289     QList<QGraphicsItem *> itemList = scene()->selectedItems();
4290     if (itemList.count() != 1 || itemList.at(0)->type() != TRANSITIONWIDGET) {
4291         emit displayMessage(i18n("You must select one transition for this action"), ErrorMessage);
4292         return;
4293     }
4294     Transition *tr = static_cast <Transition*>(itemList.at(0));
4295     tr->setAutomatic(!tr->isAutomatic());
4296     QDomElement transition = tr->toXML();
4297     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);
4298 }
4299
4300
4301 QStringList CustomTrackView::getLadspaParams(QDomElement effect) const
4302 {
4303     QStringList result;
4304     QDomNodeList params = effect.elementsByTagName("parameter");
4305     for (int i = 0; i < params.count(); i++) {
4306         QDomElement e = params.item(i).toElement();
4307         if (!e.isNull() && e.attribute("type") == "constant") {
4308             if (e.hasAttribute("factor")) {
4309                 double factor = e.attribute("factor").toDouble();
4310                 double value = e.attribute("value").toDouble();
4311                 value = value / factor;
4312                 result.append(QString::number(value));
4313             } else result.append(e.attribute("value"));
4314         }
4315     }
4316     return result;
4317 }
4318
4319 void CustomTrackView::clipNameChanged(const QString id, const QString name)
4320 {
4321     QList<QGraphicsItem *> list = scene()->items();
4322     ClipItem *clip = NULL;
4323     for (int i = 0; i < list.size(); ++i) {
4324         if (list.at(i)->type() == AVWIDGET) {
4325             clip = static_cast <ClipItem *>(list.at(i));
4326             if (clip->clipProducer() == id) {
4327                 clip->setClipName(name);
4328             }
4329         }
4330     }
4331     viewport()->update();
4332 }
4333
4334 void CustomTrackView::getClipAvailableSpace(AbstractClipItem *item, GenTime &minimum, GenTime &maximum)
4335 {
4336     minimum = GenTime();
4337     maximum = GenTime();
4338     QList<QGraphicsItem *> selection;
4339     selection = m_scene->items(0, item->track() * m_tracksHeight + m_tracksHeight / 2, sceneRect().width(), 2);
4340     selection.removeAll(item);
4341     for (int i = 0; i < selection.count(); i++) {
4342         AbstractClipItem *clip = static_cast <AbstractClipItem *>(selection.at(i));
4343         if (clip && clip->type() == AVWIDGET) {
4344             if (clip->endPos() <= item->startPos() && clip->endPos() > minimum) minimum = clip->endPos();
4345             if (clip->startPos() > item->startPos() && (clip->startPos() < maximum || maximum == GenTime())) maximum = clip->startPos();
4346         }
4347     }
4348 }
4349
4350 void CustomTrackView::getTransitionAvailableSpace(AbstractClipItem *item, GenTime &minimum, GenTime &maximum)
4351 {
4352     minimum = GenTime();
4353     maximum = GenTime();
4354     QList<QGraphicsItem *> selection;
4355     selection = m_scene->items(0, (item->track() + 1) * m_tracksHeight, sceneRect().width(), 2);
4356     selection.removeAll(item);
4357     for (int i = 0; i < selection.count(); i++) {
4358         AbstractClipItem *clip = static_cast <AbstractClipItem *>(selection.at(i));
4359         if (clip && clip->type() == TRANSITIONWIDGET) {
4360             if (clip->endPos() <= item->startPos() && clip->endPos() > minimum) minimum = clip->endPos();
4361             if (clip->startPos() > item->startPos() && (clip->startPos() < maximum || maximum == GenTime())) maximum = clip->startPos();
4362         }
4363     }
4364 }
4365
4366
4367 void CustomTrackView::loadGroups(const QDomNodeList groups)
4368 {
4369     for (int i = 0; i < groups.count(); i++) {
4370         QDomNodeList children = groups.at(i).childNodes();
4371         scene()->clearSelection();
4372         for (int nodeindex = 0; nodeindex < children.count(); nodeindex++) {
4373             QDomNode n = children.item(nodeindex);
4374             QDomElement elem = n.toElement();
4375             int pos = elem.attribute("position").toInt();
4376             int track = elem.attribute("track").toInt();
4377             if (elem.tagName() == "clipitem") {
4378                 ClipItem *clip = getClipItemAt(pos, track); //m_document->tracksCount() - transitiontrack);
4379                 if (clip) clip->setSelected(true);
4380             } else {
4381                 Transition *clip = getTransitionItemAt(pos, track); //m_document->tracksCount() - transitiontrack);
4382                 if (clip) clip->setSelected(true);
4383             }
4384         }
4385         groupSelectedItems(false, true);
4386     }
4387 }
4388
4389 void CustomTrackView::splitAudio()
4390 {
4391     resetSelectionGroup();
4392     QList<QGraphicsItem *> selection = scene()->selectedItems();
4393     if (selection.isEmpty()) {
4394         emit displayMessage(i18n("You must select one clip for this action"), ErrorMessage);
4395         return;
4396     }
4397     QUndoCommand *splitCommand = new QUndoCommand();
4398     splitCommand->setText(i18n("Split audio"));
4399     for (int i = 0; i < selection.count(); i++) {
4400         if (selection.at(i)->type() == AVWIDGET) {
4401             ClipItem *clip = static_cast <ClipItem *>(selection.at(i));
4402             if (clip->clipType() == AV || clip->clipType() == PLAYLIST) {
4403                 if (clip->parentItem()) {
4404                     emit displayMessage(i18n("Cannot split audio of grouped clips"), ErrorMessage);
4405                 } else {
4406                     new SplitAudioCommand(this, clip->track(), clip->startPos(), splitCommand);
4407                 }
4408             }
4409         }
4410     }
4411     m_commandStack->push(splitCommand);
4412 }
4413
4414 void CustomTrackView::doSplitAudio(const GenTime &pos, int track, bool split)
4415 {
4416     ClipItem *clip = getClipItemAt(pos, track);
4417     if (clip == NULL) {
4418         kDebug() << "// Cannot find clip to split!!!";
4419         return;
4420     }
4421     if (split) {
4422         int start = pos.frames(m_document->fps());
4423         int freetrack = m_document->tracksCount() - track - 1;
4424         for (; freetrack > 0; freetrack--) {
4425             kDebug() << "// CHK DOC TRK:" << freetrack << ", DUR:" << m_document->renderer()->mltTrackDuration(freetrack);
4426             if (m_document->trackInfoAt(freetrack - 1).type == AUDIOTRACK) {
4427                 kDebug() << "// CHK DOC TRK:" << freetrack << ", DUR:" << m_document->renderer()->mltTrackDuration(freetrack);
4428                 if (m_document->renderer()->mltTrackDuration(freetrack) < start || m_document->renderer()->mltGetSpaceLength(pos, freetrack, false) >= clip->duration().frames(m_document->fps())) {
4429                     kDebug() << "FOUND SPACE ON TRK: " << freetrack;
4430                     break;
4431                 }
4432             }
4433         }
4434         kDebug() << "GOT TRK: " << track;
4435         if (freetrack == 0) {
4436             emit displayMessage(i18n("No empty space to put clip audio"), ErrorMessage);
4437         } else {
4438             ItemInfo info;
4439             info.startPos = clip->startPos();
4440             info.endPos = clip->endPos();
4441             info.cropStart = clip->cropStart();
4442             info.track = m_document->tracksCount() - freetrack;
4443             addClip(clip->xml(), clip->clipProducer(), info, clip->effectList());
4444             scene()->clearSelection();
4445             clip->setSelected(true);
4446             ClipItem *audioClip = getClipItemAt(start, info.track);
4447             if (audioClip) {
4448                 clip->setVideoOnly(true);
4449                 m_document->renderer()->mltUpdateClipProducer(m_document->tracksCount() - track, start, clip->baseClip()->videoProducer());
4450                 m_document->renderer()->mltUpdateClipProducer(m_document->tracksCount() - info.track, start, clip->baseClip()->audioProducer(info.track));
4451                 audioClip->setSelected(true);
4452                 audioClip->setAudioOnly(true);
4453                 groupSelectedItems(false, true);
4454             }
4455         }
4456     } else {
4457         // unsplit clip: remove audio part and change video part to normal clip
4458         if (clip->parentItem() == NULL || clip->parentItem()->type() != GROUPWIDGET) {
4459             kDebug() << "//CANNOT FIND CLP GRP";
4460             return;
4461         }
4462         AbstractGroupItem *grp = static_cast <AbstractGroupItem *>(clip->parentItem());
4463         QList<QGraphicsItem *> children = grp->childItems();
4464         if (children.count() != 2) {
4465             kDebug() << "//SOMETHING IS WRONG WITH CLP GRP";
4466             return;
4467         }
4468         for (int i = 0; i < children.count(); i++) {
4469             if (children.at(i) != clip) {
4470                 ClipItem *clp = static_cast <ClipItem *>(children.at(i));
4471                 ItemInfo info = clip->info();
4472                 deleteClip(clp->info());
4473                 clip->setVideoOnly(false);
4474                 m_document->renderer()->mltUpdateClipProducer(m_document->tracksCount() - info.track, info.startPos.frames(m_document->fps()), clip->baseClip()->producer(info.track));
4475                 break;
4476             }
4477         }
4478         clip->setFlags(QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemIsSelectable);
4479         m_document->clipManager()->removeGroup(grp);
4480         scene()->destroyItemGroup(grp);
4481     }
4482 }
4483
4484 void CustomTrackView::setVideoOnly()
4485 {
4486     resetSelectionGroup();
4487     QList<QGraphicsItem *> selection = scene()->selectedItems();
4488     if (selection.isEmpty()) {
4489         emit displayMessage(i18n("You must select one clip for this action"), ErrorMessage);
4490         return;
4491     }
4492     QUndoCommand *videoCommand = new QUndoCommand();
4493     videoCommand->setText(i18n("Video only"));
4494     for (int i = 0; i < selection.count(); i++) {
4495         if (selection.at(i)->type() == AVWIDGET) {
4496             ClipItem *clip = static_cast <ClipItem *>(selection.at(i));
4497             if (clip->clipType() == AV || clip->clipType() == PLAYLIST) {
4498                 if (clip->parentItem()) {
4499                     emit displayMessage(i18n("Cannot change grouped clips"), ErrorMessage);
4500                 } else {
4501                     new ChangeClipTypeCommand(this, clip->track(), clip->startPos(), true, false, clip->isVideoOnly(), clip->isAudioOnly(), videoCommand);
4502                 }
4503             }
4504         }
4505     }
4506     m_commandStack->push(videoCommand);
4507 }
4508
4509 void CustomTrackView::setAudioOnly()
4510 {
4511     resetSelectionGroup();
4512     QList<QGraphicsItem *> selection = scene()->selectedItems();
4513     if (selection.isEmpty()) {
4514         emit displayMessage(i18n("You must select one clip for this action"), ErrorMessage);
4515         return;
4516     }
4517     QUndoCommand *videoCommand = new QUndoCommand();
4518     videoCommand->setText(i18n("Audio only"));
4519     for (int i = 0; i < selection.count(); i++) {
4520         if (selection.at(i)->type() == AVWIDGET) {
4521             ClipItem *clip = static_cast <ClipItem *>(selection.at(i));
4522             if (clip->clipType() == AV || clip->clipType() == PLAYLIST) {
4523                 if (clip->parentItem()) {
4524                     emit displayMessage(i18n("Cannot change grouped clips"), ErrorMessage);
4525                 } else {
4526                     new ChangeClipTypeCommand(this, clip->track(), clip->startPos(), false, true, clip->isVideoOnly(), clip->isAudioOnly(), videoCommand);
4527                 }
4528             }
4529         }
4530     }
4531     m_commandStack->push(videoCommand);
4532 }
4533
4534 void CustomTrackView::setAudioAndVideo()
4535 {
4536     resetSelectionGroup();
4537     QList<QGraphicsItem *> selection = scene()->selectedItems();
4538     if (selection.isEmpty()) {
4539         emit displayMessage(i18n("You must select one clip for this action"), ErrorMessage);
4540         return;
4541     }
4542     QUndoCommand *videoCommand = new QUndoCommand();
4543     videoCommand->setText(i18n("Audio and Video"));
4544     for (int i = 0; i < selection.count(); i++) {
4545         if (selection.at(i)->type() == AVWIDGET) {
4546             ClipItem *clip = static_cast <ClipItem *>(selection.at(i));
4547             if (clip->clipType() == AV || clip->clipType() == PLAYLIST) {
4548                 if (clip->parentItem()) {
4549                     emit displayMessage(i18n("Cannot change grouped clips"), ErrorMessage);
4550                 } else {
4551                     new ChangeClipTypeCommand(this, clip->track(), clip->startPos(), false, false, clip->isVideoOnly(), clip->isAudioOnly(), videoCommand);
4552                 }
4553             }
4554         }
4555     }
4556     m_commandStack->push(videoCommand);
4557 }
4558
4559 void CustomTrackView::doChangeClipType(const GenTime &pos, int track, bool videoOnly, bool audioOnly)
4560 {
4561     ClipItem *clip = getClipItemAt(pos, track);
4562     if (clip == NULL) {
4563         kDebug() << "// Cannot find clip to split!!!";
4564         return;
4565     }
4566     if (videoOnly) {
4567         int start = pos.frames(m_document->fps());
4568         clip->setVideoOnly(true);
4569         clip->setAudioOnly(false);
4570         m_document->renderer()->mltUpdateClipProducer(m_document->tracksCount() - track, start, clip->baseClip()->videoProducer());
4571     } else if (audioOnly) {
4572         int start = pos.frames(m_document->fps());
4573         clip->setAudioOnly(true);
4574         clip->setVideoOnly(false);
4575         m_document->renderer()->mltUpdateClipProducer(m_document->tracksCount() - track, start, clip->baseClip()->audioProducer(track));
4576     } else {
4577         int start = pos.frames(m_document->fps());
4578         clip->setAudioOnly(false);
4579         clip->setVideoOnly(false);
4580         m_document->renderer()->mltUpdateClipProducer(m_document->tracksCount() - track, start, clip->baseClip()->producer(track));
4581     }
4582     clip->update();
4583     m_document->setModified(true);
4584 }
4585
4586 void CustomTrackView::updateClipTypeActions(ClipItem *clip)
4587 {
4588     if (clip == NULL || (clip->clipType() != AV && clip->clipType() != PLAYLIST)) {
4589         m_clipTypeGroup->setEnabled(false);
4590     } else {
4591         m_clipTypeGroup->setEnabled(true);
4592         QList <QAction *> actions = m_clipTypeGroup->actions();
4593         QString lookup;
4594         if (clip->isAudioOnly()) lookup = "clip_audio_only";
4595         else if (clip->isVideoOnly()) lookup = "clip_video_only";
4596         else  lookup = "clip_audio_and_video";
4597         for (int i = 0; i < actions.count(); i++) {
4598             if (actions.at(i)->data().toString() == lookup) {
4599                 actions.at(i)->setChecked(true);
4600                 break;
4601             }
4602         }
4603     }
4604 }
4605
4606 void CustomTrackView::reloadTransitionLumas()
4607 {
4608     QString lumaNames;
4609     QString lumaFiles;
4610     QDomElement lumaTransition = MainWindow::transitions.getEffectByTag("luma", "luma");
4611     QDomNodeList params = lumaTransition.elementsByTagName("parameter");
4612     for (int i = 0; i < params.count(); i++) {
4613         QDomElement e = params.item(i).toElement();
4614         if (e.attribute("tag") == "resource") {
4615             lumaNames = e.attribute("paramlistdisplay");
4616             lumaFiles = e.attribute("paramlist");
4617             break;
4618         }
4619     }
4620
4621     QList<QGraphicsItem *> itemList = items();
4622     Transition *transitionitem;
4623     QDomElement transitionXml;
4624     for (int i = 0; i < itemList.count(); i++) {
4625         if (itemList.at(i)->type() == TRANSITIONWIDGET) {
4626             transitionitem = static_cast <Transition*>(itemList.at(i));
4627             transitionXml = transitionitem->toXML();
4628             if (transitionXml.attribute("id") == "luma" && transitionXml.attribute("tag") == "luma") {
4629                 QDomNodeList params = transitionXml.elementsByTagName("parameter");
4630                 for (int i = 0; i < params.count(); i++) {
4631                     QDomElement e = params.item(i).toElement();
4632                     if (e.attribute("tag") == "resource") {
4633                         e.setAttribute("paramlistdisplay", lumaNames);
4634                         e.setAttribute("paramlist", lumaFiles);
4635                         break;
4636                     }
4637                 }
4638             }
4639             if (transitionXml.attribute("id") == "composite" && transitionXml.attribute("tag") == "composite") {
4640                 QDomNodeList params = transitionXml.elementsByTagName("parameter");
4641                 for (int i = 0; i < params.count(); i++) {
4642                     QDomElement e = params.item(i).toElement();
4643                     if (e.attribute("tag") == "luma") {
4644                         e.setAttribute("paramlistdisplay", lumaNames);
4645                         e.setAttribute("paramlist", lumaFiles);
4646                         break;
4647                     }
4648                 }
4649             }
4650         }
4651     }
4652     emit transitionItemSelected(NULL);
4653 }
4654
4655 #include "customtrackview.moc"