Commit 6d70e304 authored by Eric Jiang's avatar Eric Jiang Committed by Julius Künzel
Browse files

Select a valid activeTrack for new documents

When creating a new KdenliveDoc, the activeTrack property was set to be
the last audio track's position + 1. If a new document with 0 video
tracks is created, then activeTrack is out of range and causes a crash
later in TimelineController::documentProperties().

This fixes BUG: 442545
parent aaff3cad
Pipeline #199930 passed with stage
in 7 minutes and 15 seconds
......@@ -79,9 +79,15 @@ KdenliveDoc::KdenliveDoc(QString projectFolder, QUndoGroup *undoGroup, const QSt
// connect(m_commandStack, SIGNAL(cleanChanged(bool)), this, SLOT(setModified(bool)));
initializeProperties();
// video tracks are after audio tracks, and the UI shows them from highest position to lowest position
m_documentProperties[QStringLiteral("videoTarget")] = QString::number(tracks.second);
m_documentProperties[QStringLiteral("audioTarget")] = QString::number(tracks.second - 1);
m_documentProperties[QStringLiteral("activeTrack")] = QString::number(tracks.second);
// If there is at least one video track, set activeTrack to be the first
// video track (which comes after the audio tracks). Otherwise, set the
// activeTrack to be the last audio track (the top-most audio track in the
// UI).
const int activeTrack = tracks.first > 0 ? tracks.second : tracks.second - 1;
m_documentProperties[QStringLiteral("activeTrack")] = QString::number(activeTrack);
m_documentProperties[QStringLiteral("audioChannels")] = QString::number(audioChannels);
// Load properties
......
......@@ -81,7 +81,10 @@ class KdenliveDoc : public QObject
{
Q_OBJECT
public:
/** @brief Create a new empty Kdenlive project with the specified profile and requested number of tracks. */
/** @brief Create a new empty Kdenlive project with the specified profile and requested number of tracks.
*
* @param tracks The number of <video, audio> tracks to create in the project.
*/
KdenliveDoc(QString projectFolder, QUndoGroup *undoGroup, const QString &profileName, const QMap<QString, QString> &properties,
const QMap<QString, QString> &metadata, const QPair<int, int> &tracks, int audioChannels, MainWindow *parent = nullptr);
/** @brief Open an existing Kdenlive project, returning nothing if the project cannot be opened. */
......
......@@ -1074,11 +1074,17 @@ bool ProjectManager::updateTimeline(int pos, const QString &chunks, const QStrin
pCore->window()->getMainTimeline()->controller()->setZone(m_project->zone(), false);
pCore->window()->getMainTimeline()->controller()->setScrollPos(m_project->getDocumentProperty(QStringLiteral("scrollPos")).toInt());
int activeTrackPosition = m_project->getDocumentProperty(QStringLiteral("activeTrack"), QString::number(-1)).toInt();
if (activeTrackPosition > -1 && activeTrackPosition < m_mainTimelineModel->getTracksCount()) {
if (activeTrackPosition == -2) {
// Subtitle model track always has ID == -2
pCore->window()->getMainTimeline()->controller()->setActiveTrack(-2);
} else if (activeTrackPosition > -1 && activeTrackPosition < m_mainTimelineModel->getTracksCount()) {
// otherwise, convert the position to a track ID
pCore->window()->getMainTimeline()->controller()->setActiveTrack(m_mainTimelineModel->getTrackIndexFromPosition(activeTrackPosition));
} else {
// Subtitle model track was active
pCore->window()->getMainTimeline()->controller()->setActiveTrack(activeTrackPosition);
qWarning() << "[BUG] \"activeTrack\" property is" << activeTrackPosition <<
"but track count is only" << m_mainTimelineModel->getTracksCount();
// set it to some valid track instead
pCore->window()->getMainTimeline()->controller()->setActiveTrack(m_mainTimelineModel->getTrackIndexFromPosition(0));
}
m_mainTimelineModel->setUndoStack(m_project->commandStack());
......
#include "test_utils.hpp"
#include "doc/kdenlivedoc.h"
#include <QUndoGroup>
using namespace fakeit;
std::default_random_engine g(42);
......@@ -2148,3 +2151,60 @@ TEST_CASE("Operations under locked tracks", "[Locked]")
binModel->clean();
pCore->m_projectManager = nullptr;
}
TEST_CASE("New KdenliveDoc activeTrack", "KdenliveDoc")
{
auto binModel = pCore->projectItemModel();
binModel->clean();
std::shared_ptr<DocUndoStack> undoStack = std::make_shared<DocUndoStack>(nullptr);
QUndoGroup *undoGroup = new QUndoGroup();
undoGroup->addStack(undoStack.get());
std::shared_ptr<MarkerListModel> guideModel = std::make_shared<MarkerListModel>(undoStack);
const QMap<QString, QString> emptyMap{};
/*
* Bug 442545: KdenliveDoc created with 0 video tracks causes a crash at
* save time because the document's activeTrack was set to an out-of-range
* position.
*/
SECTION("0 video tracks")
{
// Create document
KdenliveDoc doc{QString(), undoGroup, QString(), emptyMap,
emptyMap, qMakePair<int, int>(0, 2), 2, nullptr};
// since there are only 2 tracks, the activeTrack position should be 0 or 1
CHECK(doc.getDocumentProperty("activeTrack").toInt() >= 0);
CHECK(doc.getDocumentProperty("activeTrack").toInt() < 2);
}
SECTION("both audio and video tracks")
{
KdenliveDoc doc{QString(), undoGroup, QString(), emptyMap,
emptyMap, qMakePair<int, int>(2, 2), 2, nullptr};
CHECK(doc.getDocumentProperty("activeTrack").toInt() >= 0);
CHECK(doc.getDocumentProperty("activeTrack").toInt() < 4);
// because video tracks come after audio tracks, videoTarget position
// should also be after the audio tracks
CHECK(doc.getDocumentProperty("videoTarget").toInt() > 1);
CHECK(doc.getDocumentProperty("videoTarget").toInt() < 4);
CHECK(doc.getDocumentProperty("audioTarget").toInt() >= 0);
CHECK(doc.getDocumentProperty("audioTarget").toInt() < 2);
}
SECTION("0 audio tracks")
{
KdenliveDoc doc{QString(), undoGroup, QString(), emptyMap,
emptyMap, qMakePair<int, int>(2, 0), 2, nullptr};
CHECK(doc.getDocumentProperty("activeTrack").toInt() >= 0);
CHECK(doc.getDocumentProperty("activeTrack").toInt() < 2);
CHECK(doc.getDocumentProperty("videoTarget").toInt() >= 0);
CHECK(doc.getDocumentProperty("videoTarget").toInt() < 2);
}
delete undoGroup;
binModel->clean();
pCore->m_projectManager = nullptr;
}
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