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