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

Merge branch 'master' of invent.kde.org:multimedia/kdenlive

parents 3dcf36a6 63a11481
Pipeline #175550 passed with stage
in 5 minutes and 49 seconds
......@@ -2726,7 +2726,7 @@ void MainWindow::slotNormalizeAudioChannel()
void MainWindow::slotInsertTrack()
{
pCore->monitorManager()->activateMonitor(Kdenlive::ProjectMonitor);
getCurrentTimeline()->controller()->addTrack(-1);
getCurrentTimeline()->controller()->beginAddTrack(-1);
}
void MainWindow::slotDeleteTrack()
......
......@@ -98,6 +98,48 @@ QModelIndex TimelineItemModel::index(int row, int column, const QModelIndex &par
return index(clipIndex, 0, index(trackIndex));
}*/
bool TimelineItemModel::addTracksAtPosition(int position, int tracksCount, QString &trackName, bool addAudioTrack, bool addAVTrack, bool addRecTrack)
{
Fun undo = []() { return true; };
Fun redo = []() { return true; };
bool result = true;
int insertionIndex = position;
for (int ix = 0; ix < tracksCount; ++ix) {
int newTid;
result = requestTrackInsertion(insertionIndex, newTid, trackName, addAudioTrack, undo, redo);
// bump up insertion index so that the next new track goes after this one
insertionIndex++;
if (result) {
if (addAVTrack) {
int newTid2;
int mirrorPos = 0;
int mirrorId = getMirrorAudioTrackId(newTid);
if (mirrorId > -1) {
mirrorPos = getTrackMltIndex(mirrorId);
}
result = requestTrackInsertion(mirrorPos, newTid2, trackName, true, undo, redo);
// because we also added an audio track, we need to put the next
// new track's index is 1 further
insertionIndex++;
}
if (addRecTrack) {
setTrackProperty(newTid, "kdenlive:audio_rec", QStringLiteral("1"));
}
} else {
break;
}
}
if (result) {
pCore->pushUndo(undo, redo, addAVTrack || tracksCount > 1 ? i18nc("@action", "Insert Tracks") : i18nc("@action", "Insert Track"));
return true;
} else {
undo();
return false;
}
}
QModelIndex TimelineItemModel::makeClipIndexFromID(int clipId) const
{
Q_ASSERT(m_allClips.count(clipId) > 0);
......
......@@ -54,6 +54,11 @@ public:
QHash<int, QByteArray> roleNames() const override;
QModelIndex index(int row, int column = 0, const QModelIndex &parent = QModelIndex()) const override;
// QModelIndex makeIndex(int trackIndex, int clipIndex) const;
/** @brief Add multiple tracks at a specific position (used by the Add Track
* dialog). Returns true if successful, false otherwise. */
bool addTracksAtPosition(int position, int tracksCount, QString &trackName, bool addAudioTrack, bool addAVTrack, bool addRecTrack);
/** @brief Creates an index based on the ID of the clip*/
QModelIndex makeClipIndexFromID(int clipId) const override;
/** @brief Creates an index based on the ID of the compoition*/
......
......@@ -688,44 +688,19 @@ bool TimelineController::showWaveforms() const
return KdenliveSettings::audiothumbnails();
}
void TimelineController::addTrack(int tid)
void TimelineController::beginAddTrack(int tid)
{
if (tid == -1) {
tid = m_activeTrack;
}
QPointer<TrackDialog> d = new TrackDialog(m_model, tid, qApp->activeWindow());
if (d->exec() == QDialog::Accepted) {
bool audioRecTrack = d->addRecTrack();
bool addAVTrack = d->addAVTrack();
int tracksCount = d->tracksCount();
Fun undo = []() { return true; };
Fun redo = []() { return true; };
bool result = true;
for (int ix = 0; ix < tracksCount; ++ix) {
int newTid;
result = m_model->requestTrackInsertion(d->selectedTrackPosition(), newTid, d->trackName(), d->addAudioTrack(), undo, redo);
if (result) {
if (addAVTrack) {
int newTid2;
int mirrorPos = 0;
int mirrorId = m_model->getMirrorAudioTrackId(newTid);
if (mirrorId > -1) {
mirrorPos = m_model->getTrackMltIndex(mirrorId);
}
result = m_model->requestTrackInsertion(mirrorPos, newTid2, d->trackName(), true, undo, redo);
}
if (audioRecTrack) {
m_model->setTrackProperty(newTid, "kdenlive:audio_rec", QStringLiteral("1"));
}
} else {
break;
}
}
if (result) {
pCore->pushUndo(undo, redo, addAVTrack || tracksCount > 1 ? i18nc("@action", "Insert Tracks") : i18nc("@action", "Insert Track"));
} else {
auto trackName = d->trackName();
bool result = m_model->addTracksAtPosition(d->selectedTrackPosition(),
d->tracksCount(), trackName,
d->addAudioTrack(), d->addAVTrack(), d->addRecTrack());
if (!result) {
pCore->displayMessage(i18n("Could not insert track"), ErrorMessage, 500);
undo();
}
}
}
......
......@@ -272,9 +272,9 @@ public:
/** @brief Do we want to display audio thumbnails
*/
Q_INVOKABLE bool showWaveforms() const;
/** @brief Insert a timeline track
/** @brief Invoke the GUI to add new timeline tracks
*/
Q_INVOKABLE void addTrack(int tid);
Q_INVOKABLE void beginAddTrack(int tid);
/** @brief Remove multiple(or single) timeline tracks
*/
Q_INVOKABLE void deleteMultipleTracks(int tid);
......
......@@ -115,6 +115,85 @@ TEST_CASE("Basic creation/deletion of a track", "[TrackModel]")
pCore->m_projectManager = nullptr;
}
TEST_CASE("Adding multiple A/V tracks", "[TrackModel]")
{
auto binModel = pCore->projectItemModel();
std::shared_ptr<DocUndoStack> undoStack = std::make_shared<DocUndoStack>(nullptr);
std::shared_ptr<MarkerListModel> guideModel = std::make_shared<MarkerListModel>(undoStack);
Mock<ProjectManager> pmMock;
When(Method(pmMock, undoStack)).AlwaysReturn(undoStack);
When(Method(pmMock, cacheDir)).AlwaysReturn(QDir(QStandardPaths::writableLocation(QStandardPaths::CacheLocation)));
ProjectManager &mocked = pmMock.get();
pCore->m_projectManager = &mocked;
TimelineItemModel tim(&profile_model, undoStack);
Mock<TimelineItemModel> timMock(tim);
auto timeline = std::shared_ptr<TimelineItemModel>(&timMock.get(), [](...) {});
TimelineItemModel::finishConstruct(timeline, guideModel);
SECTION("Check AV track ordering")
{
// start state:
// * V2 (position 3)
// * V1
// * A1
// * A2 (position 0)
int a1, a2, v1, v2;
REQUIRE(timeline->requestTrackInsertion(0, a2, QString(), true));
REQUIRE(timeline->requestTrackInsertion(1, a1, QString(), true));
REQUIRE(timeline->requestTrackInsertion(2, v1, QString(), false));
REQUIRE(timeline->requestTrackInsertion(3, v2, QString(), false));
// when we add 3 AV tracks above V1, we should have:
// * V5 (position 9)
// * V4
// * V3
// * V2
// * V1
// * A1
// * A2
// * A3
// * A4
// * A5 (position 0)
QString trackName("New track");
REQUIRE(timeline->addTracksAtPosition(3, 3, trackName, false, true, false));
// but if the new tracks keep getting added at the same position 3, then we'll get
// * V2
// * V3
// * V1
// * V4
// * A4
// * V5
// * A5
// * A1
// * A3
// * A2
// (numbering doesn't look like this in the GUI)
REQUIRE(timeline->getTracksCount() == 10);
// first 5 tracks should be audio, and last 5 tracks should be video
auto it = timeline->m_allTracks.cbegin();
int position = 0;
while (it != timeline->m_allTracks.cend()) {
if (position < 5) {
CHECK((*it)->isAudioTrack());
} else {
CHECK(!(*it)->isAudioTrack());
}
it++;
position++;
}
// V1 track should be at index 5 (i.e. we shouldn't have inserted any video
// tracks before it)
REQUIRE(timeline->getTrackIndexFromPosition(5) == v1);
}
binModel->clean();
pCore->m_projectManager = nullptr;
}
TEST_CASE("Basic creation/deletion of a clip", "[ClipModel]")
{
......@@ -2065,8 +2144,7 @@ TEST_CASE("Operations under locked tracks", "[Locked]")
REQUIRE(timeline->requestItemResize(compo, 17, true) == 17);
check(17);
}
binModel->clean();
pCore->m_projectManager = nullptr;
}
Markdown is supported
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