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