aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJean-Baptiste Mardelle <[email protected]>2015-12-06 12:40:05 +0100
committerJean-Baptiste Mardelle <[email protected]>2015-12-06 12:40:05 +0100
commit0d5e32ad224d399425b098db0a27e7caa7e0f27b (patch)
tree2ff291efbb785b5b2a2c074f7b0a5666ebbfbc47
parent47af589bc9f14269331b7d3078565c50f8cf0d10 (diff)
Fix crash on delete track with grouped clips, and another track deletion crash
-rw-r--r--src/doc/kdenlivedoc.cpp1
-rw-r--r--src/project/clipmanager.cpp5
-rw-r--r--src/project/clipmanager.h5
-rw-r--r--src/timeline/customtrackview.cpp114
-rw-r--r--src/timeline/headertrack.cpp6
-rw-r--r--src/timeline/headertrack.h2
-rw-r--r--src/timeline/timeline.cpp29
-rw-r--r--src/timeline/track.cpp12
-rw-r--r--src/timeline/track.h2
9 files changed, 94 insertions, 82 deletions
diff --git a/src/doc/kdenlivedoc.cpp b/src/doc/kdenlivedoc.cpp
index 56e9c9f..bb51d18 100644
--- a/src/doc/kdenlivedoc.cpp
+++ b/src/doc/kdenlivedoc.cpp
@@ -145,7 +145,6 @@ KdenliveDoc::KdenliveDoc(const QUrl &url, const QUrl &projectFolder, QUndoGroup
}
*openBackup = false;
-
if (url.isValid()) {
QFile file(url.toLocalFile());
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
diff --git a/src/project/clipmanager.cpp b/src/project/clipmanager.cpp
index 7fd25ce..1e6e35a 100644
--- a/src/project/clipmanager.cpp
+++ b/src/project/clipmanager.cpp
@@ -343,6 +343,11 @@ void ClipManager::removeGroup(AbstractGroupItem *group)
m_groupsList.removeAll(group);
}
+void ClipManager::resetGroups()
+{
+ m_groupsList.clear();
+}
+
QString ClipManager::groupsXml() const
{
QDomDocument doc;
diff --git a/src/project/clipmanager.h b/src/project/clipmanager.h
index d633864..bf9143a 100644
--- a/src/project/clipmanager.h
+++ b/src/project/clipmanager.h
@@ -82,6 +82,8 @@ Q_OBJECT public:
void clearCache();
AbstractGroupItem *createGroup();
void removeGroup(AbstractGroupItem *group);
+ /** @brief Delete groups list, prepare for a reload. */
+ void resetGroups();
QString groupsXml() const;
/** @brief remove a clip id from the queue list. */
void stopThumbs(const QString &id);
@@ -98,8 +100,7 @@ private slots:
void slotAddCopiedClip(KIO::Job*, const QUrl&, const QUrl &dst);
private: // Private attributes
- /** the list of clips in the document */
- /** the list of groups in the document */
+ /** @brief the list of groups in the document */
QList <AbstractGroupItem *> m_groupsList;
QMap <QString, QString> m_folderList;
QList <QString> m_audioThumbsQueue;
diff --git a/src/timeline/customtrackview.cpp b/src/timeline/customtrackview.cpp
index 8fd4d29..9d72813 100644
--- a/src/timeline/customtrackview.cpp
+++ b/src/timeline/customtrackview.cpp
@@ -3140,6 +3140,30 @@ void CustomTrackView::addTrack(const TrackInfo &type, int ix)
ix = m_timeline->tracksCount() + 1;
}
+ // Prepare groups for reload
+ QDomDocument doc;
+ doc.setContent(m_document->groupsXml());
+ QDomNodeList groups;
+ if (!doc.isNull()) {
+ groups = doc.documentElement().elementsByTagName("group");
+ for (int nodeindex = 0; nodeindex < groups.count(); ++nodeindex) {
+ QDomNode grp = groups.item(nodeindex);
+ QDomNodeList nodes = grp.childNodes();
+ for (int itemindex = 0; itemindex < nodes.count(); ++itemindex) {
+ QDomElement elem = nodes.item(itemindex).toElement();
+ if (!elem.hasAttribute("track")) continue;
+ int track = elem.attribute("track").toInt();
+ if (track <= ix) {
+ // No change
+ continue;
+ }
+ else {
+ elem.setAttribute("track", track + 1);
+ }
+ }
+ }
+ }
+
// insert track in MLT's playlist
transitionInfos = m_document->renderer()->mltInsertTrack(ix, type.trackName, type.type == VideoTrack);
Mlt::Tractor *tractor = m_document->renderer()->lockService();
@@ -3156,6 +3180,7 @@ void CustomTrackView::addTrack(const TrackInfo &type, int ix)
m_document->renderer()->unlockService(tractor);
// Reload timeline and m_tracks structure from MLT's playlist
reloadTimeline();
+ loadGroups(groups);
}
void CustomTrackView::checkCompositeTransitions(Mlt::Tractor *tractor)
@@ -3235,67 +3260,41 @@ void CustomTrackView::removeTrack(int ix)
field->disconnect_service(*mixTr.data());
}
}
+ // Prepare groups for reload
+ QDomDocument doc;
+ doc.setContent(m_document->groupsXml());
+ QDomNodeList groups;
+ if (!doc.isNull()) {
+ groups = doc.documentElement().elementsByTagName("group");
+ for (int nodeindex = 0; nodeindex < groups.count(); ++nodeindex) {
+ QDomNode grp = groups.item(nodeindex);
+ QDomNodeList nodes = grp.childNodes();
+ for (int itemindex = 0; itemindex < nodes.count(); ++itemindex) {
+ QDomElement elem = nodes.item(itemindex).toElement();
+ if (!elem.hasAttribute("track")) continue;
+ int track = elem.attribute("track").toInt();
+ if (track < ix) {
+ // No change
+ continue;
+ }
+ else if (track > ix) {
+ elem.setAttribute("track", track - 1);
+ }
+ else {
+ // track == ix
+ // A grouped item was on deleted track, remove it from group
+ elem.setAttribute("track", -1);
+ }
+ }
+ }
+ }
+
// Delete track in MLT playlist
tractor->remove_track(ix);
checkCompositeTransitions(tractor);
m_document->renderer()->unlockService(tractor);
reloadTimeline();
- /*
- double startY = ix * (m_tracksHeight + 1) + m_tracksHeight / 2;
- QRectF r(0, startY, sceneRect().width(), sceneRect().height() - startY);
- QList<QGraphicsItem *> selection = m_scene->items(r);
- m_selectionMutex.lock();
- m_selectionGroup = new AbstractGroupItem(m_document->fps());
- scene()->addItem(m_selectionGroup);
- for (int i = 0; i < selection.count(); ++i) {
- if ((selection.at(i) && !selection.at(i)->parentItem() && selection.at(i)->isEnabled()) && (selection.at(i)->type() == AVWidget || selection.at(i)->type() == TransitionWidget || selection.at(i)->type() == GroupWidget)) {
- m_selectionGroup->addItem(selection.at(i));
- }
- }
- // Move graphic items
- qreal ydiff = 0 - (int) m_tracksHeight;
- m_selectionGroup->setTransform(QTransform::fromTranslate(0, ydiff), true);
- Mlt::Tractor *tractor = m_document->renderer()->lockService();
-
- // adjust track number
- QList<QGraphicsItem *> children = m_selectionGroup->childItems();
- ////qDebug() << "// FOUND CLIPS TO MOVE: " << children.count();
- for (int i = 0; i < children.count(); ++i) {
- if (children.at(i)->type() == GroupWidget) {
- AbstractGroupItem *grp = static_cast<AbstractGroupItem*>(children.at(i));
- children << grp->childItems();
- continue;
- }
- if (children.at(i)->type() == AVWidget) {
- ClipItem *clip = static_cast <ClipItem *>(children.at(i));
- clip->updateItem();
- } else if (children.at(i)->type() == TransitionWidget) {
- Transition *tr = static_cast <Transition *>(children.at(i));
- tr->updateItem();
- int track = tr->transitionEndTrack();
- if (track >= ix) {
- ItemInfo clipinfo = tr->info();
- tr->updateTransitionEndTrack(getPreviousVideoTrack(clipinfo.track));
- }
- }
- }
- m_selectionMutex.unlock();
- resetSelectionGroup(false);
- m_document->renderer()->unlockService(tractor);
-
- int maxHeight = m_tracksHeight * m_timeline->tracksCount() * matrix().m22();
- for (int i = 0; i < m_guides.count(); ++i) {
- m_guides.at(i)->setLine(0, 0, 0, maxHeight - 1);
- }
- m_cursorLine->setLine(0, 0, 0, maxHeight - 1);
- setSceneRect(0, 0, sceneRect().width(), m_tracksHeight * m_timeline->tracksCount());
-
- m_selectedTrack = qMin(m_selectedTrack, m_timeline->tracksCount() - 1);
- viewport()->update();
-
- updateTrackNames(ix, false);
- //QTimer::singleShot(500, this, SIGNAL(()));
- */
+ loadGroups(groups);
}
void CustomTrackView::configTracks(const QList < TrackInfo > &trackInfos)
@@ -6687,6 +6686,7 @@ void CustomTrackView::getTransitionAvailableSpace(AbstractClipItem *item, GenTim
void CustomTrackView::loadGroups(const QDomNodeList &groups)
{
+ m_document->clipManager()->resetGroups();
for (int i = 0; i < groups.count(); ++i) {
QDomNodeList children = groups.at(i).childNodes();
scene()->clearSelection();
@@ -6695,6 +6695,8 @@ void CustomTrackView::loadGroups(const QDomNodeList &groups)
QDomElement elem = children.item(nodeindex).toElement();
int pos = elem.attribute("position").toInt();
int track = elem.attribute("track").toInt();
+ // Ignore items removed after track deletion
+ if (track == -1) continue;
if (elem.tagName() == "clipitem") {
ClipItem *clip = getClipItemAtStart(GenTime(pos, m_document->fps()), track);
if (clip) list.append(clip);//clip->setSelected(true);
diff --git a/src/timeline/headertrack.cpp b/src/timeline/headertrack.cpp
index 14f1246..42342fa 100644
--- a/src/timeline/headertrack.cpp
+++ b/src/timeline/headertrack.cpp
@@ -36,8 +36,8 @@
#include <QDomDocument>
#include <QMimeData>
-HeaderTrack::HeaderTrack(TrackInfo info, const QList <QAction *> &actions, Track *parent) :
- QWidget(0),
+HeaderTrack::HeaderTrack(TrackInfo info, const QList <QAction *> &actions, Track *parent, QWidget *parentWidget) :
+ QWidget(parentWidget),
m_type(info.type),
m_parentTrack(parent),
m_isSelected(false),
@@ -107,7 +107,7 @@ HeaderTrack::HeaderTrack(TrackInfo info, const QList <QAction *> &actions, Track
HeaderTrack::~HeaderTrack()
{
- //qDebug()<<" - --DEL: "<<m_name;
+ //qDebug()<<" - --DEL TK HEAD: "<<m_name;
}
bool HeaderTrack::eventFilter(QObject *obj, QEvent *event)
diff --git a/src/timeline/headertrack.h b/src/timeline/headertrack.h
index d6f0313..cb27283 100644
--- a/src/timeline/headertrack.h
+++ b/src/timeline/headertrack.h
@@ -34,7 +34,7 @@ class HeaderTrack : public QWidget, public Ui::TrackHeader_UI
Q_OBJECT
public:
- HeaderTrack(TrackInfo info, const QList <QAction *>& actions, Track *parent);
+ HeaderTrack(TrackInfo info, const QList <QAction *>& actions, Track *parent, QWidget *parentWidget);
virtual ~HeaderTrack();
void setTrackHeight(int height);
void setLock(bool lock);
diff --git a/src/timeline/timeline.cpp b/src/timeline/timeline.cpp
index 8c53a10..76764f4 100644
--- a/src/timeline/timeline.cpp
+++ b/src/timeline/timeline.cpp
@@ -225,13 +225,7 @@ int Timeline::getTracks() {
QVBoxLayout *headerLayout = qobject_cast< QVBoxLayout* >(headers_container->layout());
QLayoutItem *child;
while ((child = headerLayout->takeAt(0)) != 0) {
- QWidget *wid = child->widget();
delete child;
- if (wid) {
- // We need to change parent or the headers are still here when processing getTransitions()
- wid->setParent(0);
- wid->deleteLater();
- }
}
int clipsCount = 0;
for (int i = 0; i < m_tractor->count(); ++i) {
@@ -250,6 +244,7 @@ int Timeline::getTracks() {
QScopedPointer<Mlt::Producer> track(m_tractor->track(i));
QString playlist_name = track->get("id");
if (playlist_name == "playlistmain") continue;
+ bool isBackgroundBlackTrack = playlist_name == "black_track";
// check track effects
Mlt::Playlist playlist(*track);
int trackduration;
@@ -260,16 +255,16 @@ int Timeline::getTracks() {
frame->setFrameStyle(QFrame::HLine);
frame->setFixedHeight(1);
headerLayout->insertWidget(0, frame);
- Track *tk = new Track(i, m_trackActions, playlist, audio == 1 ? AudioTrack : VideoTrack, m_doc->fps());
+ Track *tk = new Track(i, m_trackActions, playlist, audio == 1 ? AudioTrack : VideoTrack, m_doc->fps(), this);
m_tracks.append(tk);
- if (audio == 0) {
+ if (audio == 0 && !isBackgroundBlackTrack) {
// Check if we have a composite transition for this track
QScopedPointer<Mlt::Transition> transition(transitionHandler->getTransition(KdenliveSettings::gpu_accel() ? "movit.overlay" : "frei0r.cairoblend", i, -1, true));
if (!transition) {
tk->trackHeader->disableComposite();
}
}
- if (playlist_name != "black_track") {
+ if (!isBackgroundBlackTrack) {
tk->trackHeader->setTrackHeight(height);
int currentWidth = tk->trackHeader->minimumWidth();
if (currentWidth > headerWidth) headerWidth = currentWidth;
@@ -284,13 +279,13 @@ int Timeline::getTracks() {
connect(tk->trackHeader, SIGNAL(renameTrack(int,QString)), this, SLOT(slotRenameTrack(int,QString)));
connect(tk->trackHeader, SIGNAL(configTrack()), this, SIGNAL(configTrack()));
connect(tk->trackHeader, SIGNAL(addTrackEffect(QDomElement,int)), m_trackview, SLOT(slotAddTrackEffect(QDomElement,int)));
+ if (playlist.filter_count()) {
+ getEffects(playlist, NULL, i);
+ slotUpdateTrackEffectState(i);
+ }
+ connect(tk, &Track::newTrackDuration, this, &Timeline::checkDuration);
+ connect(tk, SIGNAL(storeSlowMotion(QString,Mlt::Producer *)), m_doc->renderer(), SLOT(storeSlowmotionProducer(QString,Mlt::Producer *)));
}
- if (playlist.filter_count()) {
- getEffects(playlist, NULL, i);
- slotUpdateTrackEffectState(i);
- }
- connect(tk, &Track::newTrackDuration, this, &Timeline::checkDuration);
- connect(tk, SIGNAL(storeSlowMotion(QString,Mlt::Producer *)), m_doc->renderer(), SLOT(storeSlowmotionProducer(QString,Mlt::Producer *)));
}
headers_container->setFixedWidth(headerWidth);
updatePalette();
@@ -697,7 +692,7 @@ void Timeline::switchTrackVideo(int ix, bool hide)
void Timeline::slotSwitchTrackComposite(int trackIndex, bool enable)
{
- if (trackIndex < 0 || trackIndex > m_tracks.count()) return;
+ if (trackIndex < 1 || trackIndex > m_tracks.count()) return;
QScopedPointer<Mlt::Transition> transition(transitionHandler->getTransition(KdenliveSettings::gpu_accel() ? "movit.overlay" : "frei0r.cairoblend", trackIndex, -1, true));
if (transition) {
transition->set("disable", enable);
@@ -1138,6 +1133,7 @@ void Timeline::slotRenameTrack(int ix, const QString &name)
void Timeline::renameTrack(int ix, const QString &name)
{
+ if (ix < 1) return;
Track *tk = track(ix);
if (!tk) return;
tk->setProperty("kdenlive:track_name", name);
@@ -1165,6 +1161,7 @@ void Timeline::slotShowTrackEffects(int ix)
void Timeline::slotUpdateTrackEffectState(int ix)
{
+ if (ix < 1) return;
Track *tk = track(ix);
if (!tk) return;
tk->trackHeader->updateEffectLabel(tk->effectsList.effectNames());
diff --git a/src/timeline/track.cpp b/src/timeline/track.cpp
index c1e21ed..93851e3 100644
--- a/src/timeline/track.cpp
+++ b/src/timeline/track.cpp
@@ -28,18 +28,24 @@
#include <QDebug>
#include <math.h>
-Track::Track(int index, const QList<QAction *> &actions, Mlt::Playlist &playlist, TrackType type, qreal fps) :
+Track::Track(int index, const QList<QAction *> &actions, Mlt::Playlist &playlist, TrackType type, qreal fps, QWidget *parent) :
effectsList(EffectsList(true)),
type(type),
+ trackHeader(NULL),
m_index(index),
m_playlist(playlist),
m_fps(fps)
{
- trackHeader = new HeaderTrack(info(), actions, this);
+ QString playlist_name = playlist.get("id");
+ if (playlist_name != "black_track") {
+ trackHeader = new HeaderTrack(info(), actions, this, parent);
+ }
}
Track::~Track()
{
+ //qDebug()<<"// DELETING TRAK: "<<m_playlist.get("id");
+ trackHeader->deleteLater();
}
// members access
@@ -267,6 +273,7 @@ bool Track::needsDuplicate(const QString &service) const
void Track::lockTrack(bool locked)
{
+ if (!trackHeader) return;
setProperty("kdenlive:locked_track", locked ? 1 : 0);
trackHeader->setLock(locked);
}
@@ -531,6 +538,7 @@ TrackInfo Track::info()
void Track::setInfo(TrackInfo info)
{
+ if (!trackHeader) return;
m_playlist.set("kdenlive:track_name", info.trackName.toUtf8().constData());
m_playlist.set("kdenlive:locked_track", info.isLocked ? 1 : 0);
m_playlist.set("kdenlive:composite", info.composite ? 1 : 0);
diff --git a/src/timeline/track.h b/src/timeline/track.h
index 547229a..8dbe707 100644
--- a/src/timeline/track.h
+++ b/src/timeline/track.h
@@ -53,7 +53,7 @@ public:
/** @brief Track constructor
* @param playlist is the MLT object used for monitor/render
* @param fps is the read speed (frames per seconds) */
- explicit Track(int index, const QList<QAction *> &actions, Mlt::Playlist &playlist, TrackType type, qreal fps);
+ explicit Track(int index, const QList<QAction *> &actions, Mlt::Playlist &playlist, TrackType type, qreal fps, QWidget *parent = 0);
~Track();
/// Property access function