Commit d9d5d95a authored by Jean-Baptiste Mardelle's avatar Jean-Baptiste Mardelle
Browse files

Add new timeline action: Remove space from all tracks that works if there are grouped clips

CCBUG: 369123
parent a0ee357c
<!DOCTYPE kpartgui SYSTEM "kpartgui.dtd">
<kpartgui name="kdenlive" version="147" translationDomain="kdenlive">
<kpartgui name="kdenlive" version="148" translationDomain="kdenlive">
<MenuBar>
<Menu name="file" >
<Action name="dvd_wizard" />
......@@ -129,6 +129,7 @@
<Menu name="space_menu" ><text>Space</text>
<Action name="insert_space" />
<Action name="delete_space" />
<Action name="delete_space_all_tracks" />
</Menu>
<Action name="group_clip" />
<Action name="ungroup_clip" />
......
......@@ -525,6 +525,7 @@ MainWindow::MainWindow(const QString &MltPath, const QUrl &Url, const QString &
m_timelineContextMenu->addAction(actionCollection()->action(QStringLiteral("insert_space")));
m_timelineContextMenu->addAction(actionCollection()->action(QStringLiteral("delete_space")));
m_timelineContextMenu->addAction(actionCollection()->action(QStringLiteral("delete_space_all_tracks")));
m_timelineContextMenu->addAction(actionCollection()->action(KStandardAction::name(KStandardAction::Paste)));
m_timelineContextClipMenu->addAction(actionCollection()->action(QStringLiteral("clip_in_project_tree")));
......@@ -1380,6 +1381,7 @@ void MainWindow::setupActions()
addAction(QStringLiteral("insert_space"), i18n("Insert Space"), this, SLOT(slotInsertSpace()));
addAction(QStringLiteral("delete_space"), i18n("Remove Space"), this, SLOT(slotRemoveSpace()));
addAction(QStringLiteral("delete_space_all_tracks"), i18n("Remove Space In All Tracks"), this, SLOT(slotRemoveAllSpace()));
KActionCategory *timelineActions = new KActionCategory(i18n("Tracks"), actionCollection());
QAction *insertTrack = new QAction(QIcon(), i18n("Insert Track"), this);
......@@ -2314,6 +2316,12 @@ void MainWindow::slotRemoveSpace()
pCore->projectManager()->currentTimeline()->projectView()->slotRemoveSpace();
}
void MainWindow::slotRemoveAllSpace()
{
if (pCore->projectManager()->currentTimeline())
pCore->projectManager()->currentTimeline()->projectView()->slotRemoveSpace(true);
}
void MainWindow::slotInsertTrack()
{
pCore->monitorManager()->activateMonitor(Kdenlive::ProjectMonitor);
......
......@@ -359,6 +359,7 @@ private slots:
void slotInsertSpace();
void slotRemoveSpace();
void slotRemoveAllSpace();
void slotAddGuide();
void slotEditGuide(int pos = -1, QString text = QString());
void slotDeleteGuide();
......
......@@ -727,14 +727,19 @@ QList<QGraphicsItem *> CustomTrackView::selectAllItemsToTheRight(int x)
return m_scene->items(r);
}
int CustomTrackView::spaceToolSelectTrackOnly(int track, QList<QGraphicsItem *> &selection)
int CustomTrackView::spaceToolSelectTrackOnly(int track, QList<QGraphicsItem *> &selection, GenTime pos)
{
if (m_timeline->getTrackInfo(track).isLocked) {
// Cannot use spacer on locked track
emit displayMessage(i18n("Cannot use spacer in a locked track"), ErrorMessage);
return -1;
}
QRectF rect(mapToScene(m_clickEvent).x(), getPositionFromTrack(track) + m_tracksHeight / 2, sceneRect().width() - mapToScene(m_clickEvent).x(), m_tracksHeight / 2 - 2);
QRectF rect;
if (pos > GenTime()) {
rect = QRectF(pos.frames(m_document->fps()), getPositionFromTrack(track) + m_tracksHeight / 2, sceneRect().width() - pos.frames(m_document->fps()), m_tracksHeight / 2 - 2);
} else {
rect = QRectF(mapToScene(m_clickEvent).x(), getPositionFromTrack(track) + m_tracksHeight / 2, sceneRect().width() - mapToScene(m_clickEvent).x(), m_tracksHeight / 2 - 2);
}
bool isOk;
selection = checkForGroups(rect, &isOk);
if (!isOk) {
......@@ -3788,7 +3793,7 @@ QList<QGraphicsItem *> CustomTrackView::checkForGroups(const QRectF &rect, bool
return selection;
}
void CustomTrackView::slotRemoveSpace()
void CustomTrackView::slotRemoveSpace(bool multiTrack)
{
GenTime pos;
int track = 0;
......@@ -3832,69 +3837,29 @@ void CustomTrackView::slotRemoveSpace()
return;
}
// Make sure there is no group in the way
QRectF rect(pos.frames(m_document->fps()), getPositionFromTrack(track) + m_tracksHeight / 2, sceneRect().width() - pos.frames(m_document->fps()), m_tracksHeight / 2 - 2);
bool isOk;
QList<QGraphicsItem *> items = checkForGroups(rect, &isOk);
if (!isOk) {
// groups found on track, do not allow the move
emit displayMessage(i18n("Cannot remove space in a track with a group"), ErrorMessage);
return;
}
QList<ItemInfo> clipsToMove;
QList<ItemInfo> transitionsToMove;
for (int i = 0; i < items.count(); ++i) {
if (items.at(i)->type() == AVWidget || items.at(i)->type() == TransitionWidget) {
AbstractClipItem *item = static_cast <AbstractClipItem *>(items.at(i));
ItemInfo info = item->info();
if (item->type() == AVWidget) {
clipsToMove.append(info);
} else if (item->type() == TransitionWidget) {
transitionsToMove.append(info);
}
QList<QGraphicsItem *> selection;
if (multiTrack) {
selection = selectAllItemsToTheRight(pos.frames(m_document->fps()));
} else {
if (spaceToolSelectTrackOnly(track, selection, pos) == -1) {
return;
}
}
if (!transitionsToMove.isEmpty()) {
// Make sure that by moving the items, we don't get a transition collision
// Find first transition
ItemInfo info = transitionsToMove.at(0);
for (int i = 1; i < transitionsToMove.count(); ++i)
if (transitionsToMove.at(i).startPos < info.startPos) info = transitionsToMove.at(i);
// make sure there are no transitions on the way
QRectF rect(info.startPos.frames(m_document->fps()) - length, getPositionFromTrack(track) + m_tracksHeight / 2, length - 1, m_tracksHeight / 2 - 2);
items = scene()->items(rect);
int transitionCorrection = -1;
for (int i = 0; i < items.count(); ++i) {
if (items.at(i)->type() == TransitionWidget) {
// There is a transition on the way
AbstractClipItem *item = static_cast <AbstractClipItem *>(items.at(i));
int transitionEnd = item->endPos().frames(m_document->fps());
if (transitionEnd > transitionCorrection) transitionCorrection = transitionEnd;
}
}
if (transitionCorrection > 0) {
// We need to fix the move length
length = info.startPos.frames(m_document->fps()) - transitionCorrection;
}
// Make sure we don't send transition before 0
if (info.startPos.frames(m_document->fps()) < length) {
// reduce length to maximum possible
length = info.startPos.frames(m_document->fps());
}
createGroupForSelectedItems(selection);
QList <AbstractClipItem *> items;
foreach(QGraphicsItem *item, selection) {
if (item->type() == AVWidget || item->type() == TransitionWidget)
items << (AbstractClipItem *) item;
}
GenTime timeOffset(-length, m_document->fps());
if (canBePasted(items, timeOffset, 0)) {
completeSpaceOperation(multiTrack ? -1 : track, timeOffset, true);
} else {
// Conflict, cannot move clips
emit displayMessage(i18n("Clip collision, cannot perform operation"), ErrorMessage);
clearSelection();
m_operationMode = None;
}
QUndoCommand *command = new QUndoCommand;
command->setText(length > 0 ? i18n("Remove space") : i18n("Insert space"));
breakLockedGroups(clipsToMove, transitionsToMove, command);
new InsertSpaceCommand(this, clipsToMove, transitionsToMove, track, GenTime(-length, m_document->fps()), true, command);
updateTrackDuration(track, command);
m_commandStack->push(command);
}
void CustomTrackView::slotInsertSpace()
......@@ -3927,41 +3892,14 @@ void CustomTrackView::slotInsertSpace()
ClipItem *item = getClipItemAtMiddlePoint(pos, track);
if (item) pos = item->startPos().frames(m_document->fps());
// Make sure there is no group in the way
QRectF rect(pos, getPositionFromTrack(track) + m_tracksHeight / 2, sceneRect().width() - pos, m_tracksHeight / 2 - 2);
bool isOk;
items = checkForGroups(rect, &isOk);
if (!isOk) {
// groups found on track, do not allow the move
emit displayMessage(i18n("Cannot insert space in a track with a group"), ErrorMessage);
if (spaceToolSelectTrackOnly(track, items, GenTime(pos, m_document->fps())) == -1) {
return;
}
} else {
QRectF rect(pos, 0, sceneRect().width() - pos, m_timeline->visibleTracksCount() * m_tracksHeight);
items = scene()->items(rect);
}
QList<ItemInfo> clipsToMove;
QList<ItemInfo> transitionsToMove;
for (int i = 0; i < items.count(); ++i) {
if (items.at(i)->type() == AVWidget || items.at(i)->type() == TransitionWidget) {
AbstractClipItem *item = static_cast <AbstractClipItem *>(items.at(i));
ItemInfo info = item->info();
if (item->type() == AVWidget)
clipsToMove.append(info);
else if (item->type() == TransitionWidget)
transitionsToMove.append(info);
}
}
if (!clipsToMove.isEmpty() || !transitionsToMove.isEmpty()) {
QUndoCommand *command = new QUndoCommand;
command->setText(spaceDuration < GenTime() ? i18n("Remove space") : i18n("Insert space"));
breakLockedGroups(clipsToMove, transitionsToMove, command);
new InsertSpaceCommand(this, clipsToMove, transitionsToMove, track, spaceDuration, true, command);
updateTrackDuration(track, command);
m_commandStack->push(command);
items = selectAllItemsToTheRight(pos);
}
createGroupForSelectedItems(items);
completeSpaceOperation(track, spaceDuration, true);
}
void CustomTrackView::insertTimelineSpace(GenTime startPos, GenTime duration, int track, QList <ItemInfo> excludeList)
......@@ -4189,7 +4127,7 @@ void CustomTrackView::scrollToStart()
horizontalScrollBar()->setValue(0);
}
void CustomTrackView::completeSpaceOperation(int track, GenTime &timeOffset)
void CustomTrackView::completeSpaceOperation(int track, GenTime &timeOffset, bool fromStart)
{
QList <AbstractGroupItem*> groups;
......@@ -4223,25 +4161,25 @@ void CustomTrackView::completeSpaceOperation(int track, GenTime &timeOffset)
{
if (items.at(i)->type() == AVWidget)
{
AbstractClipItem *item = static_cast <AbstractClipItem *>(items.at(i));
ItemInfo info = item->info();
clipsToMove.append(info);
AbstractClipItem *item = static_cast <AbstractClipItem *>(items.at(i));
ItemInfo info = item->info();
clipsToMove.append(info);
int realTrack = getTrackFromPos(item->scenePos().y());
item->updateItem(realTrack);
if (trackClipStartList.value(info.track) == -1 ||
info.startPos.frames(m_document->fps()) < trackClipStartList.value(info.track))
trackClipStartList[info.track] = info.startPos.frames(m_document->fps());
}
item->updateItem(realTrack);
if (trackClipStartList.value(info.track) == -1 ||
info.startPos.frames(m_document->fps()) < trackClipStartList.value(info.track))
trackClipStartList[info.track] = info.startPos.frames(m_document->fps());
}
else if (items.at(i)->type() == TransitionWidget)
{
AbstractClipItem *item = static_cast <AbstractClipItem *>(items.at(i));
ItemInfo info = item->info();
transitionsToMove.append(info);
AbstractClipItem *item = static_cast <AbstractClipItem *>(items.at(i));
ItemInfo info = item->info();
transitionsToMove.append(info);
int realTrack = getTrackFromPos(item->scenePos().y());
item->updateItem(realTrack);
if (trackTransitionStartList.value(info.track) == -1 ||
info.startPos.frames(m_document->fps()) < trackTransitionStartList.value(info.track))
trackTransitionStartList[info.track] = info.startPos.frames(m_document->fps());
item->updateItem(realTrack);
if (trackTransitionStartList.value(info.track) == -1 ||
info.startPos.frames(m_document->fps()) < trackTransitionStartList.value(info.track))
trackTransitionStartList[info.track] = info.startPos.frames(m_document->fps());
}
}
if (!clipsToMove.isEmpty() || !transitionsToMove.isEmpty())
......@@ -4249,15 +4187,16 @@ void CustomTrackView::completeSpaceOperation(int track, GenTime &timeOffset)
QUndoCommand *command = new QUndoCommand;
command->setText(timeOffset < GenTime() ? i18n("Remove space") : i18n("Insert space"));
//TODO: break groups upstream
breakLockedGroups(clipsToMove, transitionsToMove, command, false);
new InsertSpaceCommand(this, clipsToMove, transitionsToMove, track, timeOffset, false, command);
breakLockedGroups(clipsToMove, transitionsToMove, command, fromStart);
new InsertSpaceCommand(this, clipsToMove, transitionsToMove, track, timeOffset, fromStart, command);
updateTrackDuration(track, command);
m_commandStack->push(command);
m_document->renderer()->mltInsertSpace(trackClipStartList, trackTransitionStartList, track, timeOffset, GenTime());
if (!fromStart)
m_document->renderer()->mltInsertSpace(trackClipStartList, trackTransitionStartList, track, timeOffset, GenTime());
}
}
resetSelectionGroup();
for (int i = 0; i < groups.count(); ++i)
if (!fromStart) for (int i = 0; i < groups.count(); ++i)
{
rebuildGroup(groups.at(i));
}
......@@ -6324,7 +6263,7 @@ void CustomTrackView::copyClip()
pasteAction->setEnabled(!m_copiedItems.isEmpty());
}
bool CustomTrackView::canBePastedTo(ItemInfo info, int type) const
bool CustomTrackView::canBePastedTo(ItemInfo info, int type, QList<AbstractClipItem *>excluded) const
{
if (m_scene->editMode() != TimelineMode::NormalEdit) {
// If we are in overwrite mode, always allow the move
......@@ -6343,7 +6282,7 @@ bool CustomTrackView::canBePastedTo(ItemInfo info, int type) const
QRectF rect((double) info.startPos.frames(m_document->fps()), (double)(getPositionFromTrack(info.track) + 1 + offset), (double)(info.endPos - info.startPos).frames(m_document->fps()), (double) height);
QList<QGraphicsItem *> collisions = scene()->items(rect, Qt::IntersectsItemBoundingRect);
for (int i = 0; i < collisions.count(); ++i) {
if (collisions.at(i)->type() == type) {
if (collisions.at(i)->type() == type && !excluded.contains((AbstractClipItem *)collisions.at(i))) {
return false;
}
}
......@@ -6371,7 +6310,7 @@ bool CustomTrackView::canBePasted(QList<AbstractClipItem *> items, GenTime offse
info.startPos += offset;
info.endPos += offset;
info.track += trackOffset;
if (!canBePastedTo(info, items.at(i)->type())) return false;
if (!canBePastedTo(info, items.at(i)->type(), items)) return false;
}
return true;
}
......
......@@ -133,7 +133,7 @@ public:
* Shows a dialog to configure length and track. */
void slotInsertSpace();
/** @brief Prepares removing space. */
void slotRemoveSpace();
void slotRemoveSpace(bool multiTrack = false);
void insertSpace(QList<ItemInfo> clipsToMove, QList<ItemInfo> transToMove, int track, const GenTime &duration, const GenTime &offset);
ClipItem *getActiveClipUnderCursor(bool allowOutsideCursor = false) const;
void deleteTimelineTrack(int ix, TrackInfo trackinfo);
......@@ -181,7 +181,7 @@ public:
int selectedTrack() const;
QStringList selectedClips() const;
/** @brief Checks whether an item can be inserted (make sure it does not overlap another item) */
bool canBePastedTo(ItemInfo info, int type) const;
bool canBePastedTo(ItemInfo info, int type, QList<AbstractClipItem *>excluded = QList<AbstractClipItem *>()) const;
/** @brief Selects a clip.
* @param add Whether to select or deselect
......@@ -223,11 +223,11 @@ public:
/** @brief Returns frame number of current mouse position. */
int getMousePos() const;
void completeSpaceOperation(int track, GenTime &timeOffset);
/** @brief Insert space in timeline after clips were moved. if fromstart is true, we assume clips have not yet been moved manually. */
void completeSpaceOperation(int track, GenTime &timeOffset, bool fromStart = false);
void spaceToolMoveToSnapPos(double snappedPos);
void createRectangleSelection(Qt::KeyboardModifiers modifiers);
int spaceToolSelectTrackOnly(int track, QList<QGraphicsItem *> &selection);
int spaceToolSelectTrackOnly(int track, QList<QGraphicsItem *> &selection, GenTime pos = GenTime(-1));
QList<QGraphicsItem *> selectAllItemsToTheRight(int x);
GenTime createGroupForSelectedItems(QList<QGraphicsItem *> &selection);
void resetSelectionGroup(bool selectItems = true);
......@@ -527,7 +527,6 @@ private:
bool insertDropClips(const QMimeData *data, const QPoint &pos);
bool canBePastedTo(QList <ItemInfo> infoList, int type) const;
bool canBePasted(QList<AbstractClipItem *> items, GenTime offset, int trackOffset) const;
bool canBeMoved(QList<AbstractClipItem *> items, GenTime offset, int trackOffset) const;
ClipItem *getClipUnderCursor() const;
AbstractClipItem *getMainActiveClip() const;
/** Get available space for clip move (min and max free positions) */
......
......@@ -38,22 +38,13 @@ SpacerDialog::SpacerDialog(const GenTime &duration, const Timecode &tc, int trac
inputLayout->addWidget(&m_in);
m_in.setValue(duration);
/*QStringList trackItems;
trackItems << i18n("All tracks");
for (int i = tracks.count() - 1; i > 0; --i) {
if (!tracks.at(i).trackName.isEmpty())
trackItems << tracks.at(i).trackName;
else
trackItems << QString::number(i);
}
track_number->addItems(trackItems);*/
QIcon videoIcon = QIcon::fromTheme(QStringLiteral("kdenlive-show-video"));
QIcon audioIcon = QIcon::fromTheme(QStringLiteral("kdenlive-show-audio"));
track_number->addItem(i18n("All tracks"));
track_number->addItem(i18n("All tracks"), -1);
for (int i = tracks.count() - 1; i > 0 ; i--) {
TrackInfo info = tracks.at(i);
track_number->addItem(info.type == VideoTrack ? videoIcon : audioIcon,
info.trackName.isEmpty() ? QString::number(i) : info.trackName);
info.trackName.isEmpty() ? QString::number(i) : info.trackName, i);
}
track_number->setCurrentIndex(track == 0 ? 0 : tracks.count() - track);
......@@ -67,7 +58,7 @@ GenTime SpacerDialog::selectedDuration() const
int SpacerDialog::selectedTrack() const
{
return track_number->count() - track_number->currentIndex();
return track_number->currentData().toInt();
}
......
......@@ -6,14 +6,37 @@
<rect>
<x>0</x>
<y>0</y>
<width>184</width>
<height>94</height>
<width>226</width>
<height>174</height>
</rect>
</property>
<property name="windowTitle">
<string>Add space</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="2" column="0" colspan="2">
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item row="1" column="0">
<widget class="QLabel" name="clip_filesize_3">
<property name="text">
<string>Track:</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="KComboBox" name="track_number"/>
</item>
<item row="3" column="0" colspan="2">
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
......@@ -31,32 +54,9 @@
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="clip_filesize_3">
<property name="text">
<string>Track:</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="KComboBox" name="track_number"/>
</item>
<item row="0" column="1">
<layout class="QHBoxLayout" name="inputLayout"/>
</item>
<item row="2" column="0" colspan="2">
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<customwidgets>
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment