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