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