File indexing completed on 2024-12-01 04:29:47
0001 /* 0002 SPDX-FileCopyrightText: 2020-2022 Jean-Baptiste Mardelle <jb@kdenlive.org> 0003 SPDX-FileCopyrightText: 2021 Julius Künzel <jk.kdedev@smartlab.uber.space> 0004 SPDX-FileCopyrightText: 2017-2019 Nicolas Carion <french.ebook.lover@gmail.com> 0005 SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL 0006 */ 0007 #include "test_utils.hpp" 0008 // test specific headers 0009 #include "doc/kdenlivedoc.h" 0010 #include "timeline2/model/timelinefunctions.hpp" 0011 0012 using namespace fakeit; 0013 0014 TEST_CASE("Simple trimming operations", "[Trimming]") 0015 { 0016 auto binModel = pCore->projectItemModel(); 0017 binModel->clean(); 0018 std::shared_ptr<DocUndoStack> undoStack = std::make_shared<DocUndoStack>(nullptr); 0019 0020 // Here we do some trickery to enable testing. 0021 KdenliveDoc document(undoStack, {1, 3}); 0022 pCore->projectManager()->m_project = &document; 0023 QDateTime documentDate = QDateTime::currentDateTime(); 0024 pCore->projectManager()->updateTimeline(false, QString(), QString(), documentDate, 0); 0025 auto timeline = document.getTimeline(document.uuid()); 0026 pCore->projectManager()->m_activeTimelineModel = timeline; 0027 pCore->projectManager()->testSetActiveDocument(&document, timeline); 0028 0029 QString binId = createProducer(pCore->getProjectProfile(), "red", binModel); 0030 QString binId2 = createProducer(pCore->getProjectProfile(), "blue", binModel); 0031 QString binId3 = createProducerWithSound(pCore->getProjectProfile(), binModel); 0032 0033 int cid1 = ClipModel::construct(timeline, binId, -1, PlaylistState::VideoOnly); 0034 int tid1 = timeline->getTrackIndexFromPosition(3); 0035 int tid2 = timeline->getTrackIndexFromPosition(2); 0036 int tid3 = timeline->getTrackIndexFromPosition(1); 0037 0038 // Add an audio track 0039 int tid4 = timeline->getTrackIndexFromPosition(0); 0040 int cid2 = ClipModel::construct(timeline, binId2, -1, PlaylistState::VideoOnly); 0041 int cid3 = ClipModel::construct(timeline, binId, -1, PlaylistState::VideoOnly); 0042 int cid4 = ClipModel::construct(timeline, binId, -1, PlaylistState::VideoOnly); 0043 int cid5 = ClipModel::construct(timeline, binId, -1, PlaylistState::VideoOnly); 0044 int cid6 = ClipModel::construct(timeline, binId, -1, PlaylistState::VideoOnly); 0045 int cid7 = ClipModel::construct(timeline, binId, -1, PlaylistState::VideoOnly); 0046 0047 int audio1 = ClipModel::construct(timeline, binId3, -1, PlaylistState::VideoOnly); 0048 int audio2 = ClipModel::construct(timeline, binId3, -1, PlaylistState::VideoOnly); 0049 int audio3 = ClipModel::construct(timeline, binId3, -1, PlaylistState::VideoOnly); 0050 0051 timeline->m_allClips[cid1]->m_endlessResize = false; 0052 timeline->m_allClips[cid2]->m_endlessResize = false; 0053 timeline->m_allClips[cid3]->m_endlessResize = false; 0054 timeline->m_allClips[cid4]->m_endlessResize = false; 0055 timeline->m_allClips[cid5]->m_endlessResize = false; 0056 timeline->m_allClips[cid6]->m_endlessResize = false; 0057 timeline->m_allClips[cid7]->m_endlessResize = false; 0058 0059 SECTION("Clip cutting") 0060 { 0061 // Trivial split 0062 REQUIRE(timeline->requestClipMove(cid1, tid1, 0)); 0063 int l = timeline->getClipPlaytime(cid2); 0064 REQUIRE(timeline->requestItemResize(cid2, l - 3, true) == l - 3); 0065 REQUIRE(timeline->requestItemResize(cid2, l - 5, false) == l - 5); 0066 REQUIRE(timeline->requestClipMove(cid2, tid1, l)); 0067 REQUIRE(timeline->requestClipMove(cid3, tid1, l + l - 5)); 0068 auto state = [&]() { 0069 REQUIRE(timeline->checkConsistency()); 0070 REQUIRE(timeline->getClipPlaytime(cid1) == l); 0071 REQUIRE(timeline->getClipPlaytime(cid2) == l - 5); 0072 REQUIRE(timeline->getClipPlaytime(cid3) == l); 0073 REQUIRE(timeline->getClipPosition(cid1) == 0); 0074 REQUIRE(timeline->getClipPosition(cid2) == l); 0075 REQUIRE(timeline->getClipPosition(cid3) == l + l - 5); 0076 REQUIRE(timeline->getClipPtr(cid2)->getIn() == 2); 0077 REQUIRE(timeline->getClipPtr(cid2)->getOut() == l - 4); 0078 }; 0079 state(); 0080 0081 // require cut position outside the clip. Should return true and nothing is done 0082 REQUIRE(TimelineFunctions::requestClipCut(timeline, cid2, 0)); 0083 state(); 0084 REQUIRE(TimelineFunctions::requestClipCut(timeline, cid2, 5 * l)); 0085 state(); 0086 // cut on edges doesn't do anything either 0087 REQUIRE(TimelineFunctions::requestClipCut(timeline, cid2, l)); 0088 state(); 0089 REQUIRE(TimelineFunctions::requestClipCut(timeline, cid2, l + l - 5)); 0090 state(); 0091 0092 REQUIRE(TimelineFunctions::requestClipCut(timeline, cid2, l + 4)); 0093 int splitted = timeline->getClipByPosition(tid1, l + 5); 0094 auto state2 = [&]() { 0095 REQUIRE(timeline->checkConsistency()); 0096 REQUIRE(timeline->getClipPlaytime(cid1) == l); 0097 REQUIRE(timeline->getClipPlaytime(cid2) == 4); 0098 REQUIRE(timeline->getClipPlaytime(splitted) == l - 9); 0099 REQUIRE(timeline->getClipPlaytime(cid3) == l); 0100 REQUIRE(timeline->getClipPosition(cid1) == 0); 0101 REQUIRE(timeline->getClipPosition(cid2) == l); 0102 REQUIRE(timeline->getClipPosition(splitted) == l + 4); 0103 REQUIRE(timeline->getClipPosition(cid3) == l + l - 5); 0104 REQUIRE(timeline->getClipPtr(cid2)->getIn() == 2); 0105 REQUIRE(timeline->getClipPtr(cid2)->getOut() == 5); 0106 REQUIRE(timeline->getClipPtr(splitted)->getIn() == 6); 0107 REQUIRE(timeline->getClipPtr(splitted)->getOut() == l - 4); 0108 }; 0109 state2(); 0110 0111 undoStack->undo(); 0112 state(); 0113 0114 undoStack->redo(); 0115 state2(); 0116 } 0117 0118 SECTION("Cut and resize") 0119 { 0120 REQUIRE(timeline->requestClipMove(cid1, tid1, 5)); 0121 int l = timeline->getClipPlaytime(cid1); 0122 timeline->m_allClips[cid1]->m_endlessResize = false; 0123 0124 auto state = [&]() { 0125 REQUIRE(timeline->checkConsistency()); 0126 REQUIRE(timeline->getClipTrackId(cid1) == tid1); 0127 REQUIRE(timeline->getClipPlaytime(cid1) == l); 0128 REQUIRE(timeline->getClipPosition(cid1) == 5); 0129 }; 0130 state(); 0131 0132 REQUIRE(TimelineFunctions::requestClipCut(timeline, cid1, 9)); 0133 int splitted = timeline->getClipByPosition(tid1, 10); 0134 timeline->m_allClips[splitted]->m_endlessResize = false; 0135 auto state2 = [&]() { 0136 REQUIRE(timeline->checkConsistency()); 0137 REQUIRE(timeline->getClipTrackId(cid1) == tid1); 0138 REQUIRE(timeline->getClipTrackId(splitted) == tid1); 0139 REQUIRE(timeline->getClipPlaytime(cid1) == 4); 0140 REQUIRE(timeline->getClipPlaytime(splitted) == l - 4); 0141 REQUIRE(timeline->getClipPosition(cid1) == 5); 0142 REQUIRE(timeline->getClipPosition(splitted) == 9); 0143 }; 0144 state2(); 0145 0146 REQUIRE(timeline->requestClipMove(splitted, tid2, 9, true, true)); 0147 REQUIRE(timeline->requestItemResize(splitted, l - 3, true, true) == -1); 0148 REQUIRE(timeline->requestItemResize(splitted, l, false, true) == l); 0149 REQUIRE(timeline->requestItemResize(cid1, 5, false, true) == -1); 0150 REQUIRE(timeline->requestItemResize(cid1, l, true, true) == l); 0151 auto state3 = [&]() { 0152 REQUIRE(timeline->checkConsistency()); 0153 REQUIRE(timeline->getClipTrackId(cid1) == tid1); 0154 REQUIRE(timeline->getClipTrackId(splitted) == tid2); 0155 REQUIRE(timeline->getClipPlaytime(cid1) == l); 0156 REQUIRE(timeline->getClipPlaytime(splitted) == l); 0157 REQUIRE(timeline->getClipPosition(cid1) == 5); 0158 REQUIRE(timeline->getClipPosition(splitted) == 5); 0159 }; 0160 state3(); 0161 0162 undoStack->undo(); 0163 undoStack->undo(); 0164 undoStack->undo(); 0165 state2(); 0166 undoStack->undo(); 0167 state(); 0168 undoStack->redo(); 0169 state2(); 0170 undoStack->redo(); 0171 undoStack->redo(); 0172 undoStack->redo(); 0173 state3(); 0174 } 0175 0176 SECTION("Clip cutting 2") 0177 { 0178 // More complex group structure split split 0179 int l = timeline->getClipPlaytime(cid2); 0180 REQUIRE(timeline->requestClipMove(cid1, tid1, 0)); 0181 REQUIRE(timeline->requestClipMove(cid2, tid1, l)); 0182 REQUIRE(timeline->requestClipMove(cid3, tid1, 2 * l)); 0183 REQUIRE(timeline->requestClipMove(cid4, tid2, 0)); 0184 REQUIRE(timeline->requestClipMove(cid5, tid2, l)); 0185 REQUIRE(timeline->requestClipMove(cid6, tid2, 2 * l)); 0186 REQUIRE(timeline->requestClipMove(cid7, tid1, 200)); 0187 int gid1 = timeline->requestClipsGroup(std::unordered_set<int>({cid1, cid4}), true, GroupType::Normal); 0188 int gid2 = timeline->requestClipsGroup(std::unordered_set<int>({cid2, cid5}), true, GroupType::Normal); 0189 int gid3 = timeline->requestClipsGroup(std::unordered_set<int>({cid3, cid6}), true, GroupType::Normal); 0190 int gid4 = timeline->requestClipsGroup(std::unordered_set<int>({cid1, cid2, cid3, cid4, cid5, cid6, cid7}), true, GroupType::Normal); 0191 auto state = [&]() { 0192 REQUIRE(timeline->checkConsistency()); 0193 int p = 0; 0194 for (int c : std::vector<int>({cid1, cid2, cid3})) { 0195 REQUIRE(timeline->getClipPlaytime(c) == l); 0196 REQUIRE(timeline->getClipTrackId(c) == tid1); 0197 REQUIRE(timeline->getClipPosition(c) == p); 0198 p += l; 0199 } 0200 p = 0; 0201 for (int c : std::vector<int>({cid4, cid5, cid6})) { 0202 REQUIRE(timeline->getClipPlaytime(c) == l); 0203 REQUIRE(timeline->getClipTrackId(c) == tid2); 0204 REQUIRE(timeline->getClipPosition(c) == p); 0205 p += l; 0206 } 0207 REQUIRE(timeline->getClipPosition(cid7) == 200); 0208 REQUIRE(timeline->getClipTrackId(cid7) == tid1); 0209 REQUIRE(timeline->m_groups->getDirectChildren(gid1) == std::unordered_set<int>({cid1, cid4})); 0210 REQUIRE(timeline->m_groups->getDirectChildren(gid2) == std::unordered_set<int>({cid2, cid5})); 0211 REQUIRE(timeline->m_groups->getDirectChildren(gid3) == std::unordered_set<int>({cid3, cid6})); 0212 REQUIRE(timeline->m_groups->getDirectChildren(gid4) == std::unordered_set<int>({gid1, gid2, gid3, cid7})); 0213 REQUIRE(timeline->getGroupElements(cid1) == std::unordered_set<int>({cid1, cid2, cid3, cid4, cid5, cid6, cid7})); 0214 }; 0215 state(); 0216 0217 // These functions will return true but do nothing 0218 REQUIRE(TimelineFunctions::requestClipCut(timeline, cid2, 0)); 0219 REQUIRE(TimelineFunctions::requestClipCut(timeline, cid2, 5 * l)); 0220 REQUIRE(TimelineFunctions::requestClipCut(timeline, cid2, l)); 0221 REQUIRE(TimelineFunctions::requestClipCut(timeline, cid2, 2 * l)); 0222 state(); 0223 0224 REQUIRE(TimelineFunctions::requestClipCut(timeline, cid2, l + 4)); 0225 int splitted = timeline->getClipByPosition(tid1, l + 5); 0226 int splitted2 = timeline->getClipByPosition(tid2, l + 5); 0227 REQUIRE(splitted != splitted2); 0228 auto check_groups = [&]() { 0229 REQUIRE(timeline->m_groups->getDirectChildren(gid2) == std::unordered_set<int>({splitted, splitted2})); 0230 REQUIRE(timeline->m_groups->getDirectChildren(gid3) == std::unordered_set<int>({cid3, cid6})); 0231 REQUIRE(timeline->m_groups->getDirectChildren(gid4) == std::unordered_set<int>({gid2, gid3, cid7})); 0232 REQUIRE(timeline->getGroupElements(cid3) == std::unordered_set<int>({splitted, splitted2, cid3, cid6, cid7})); 0233 0234 int g1b = timeline->m_groups->m_upLink[cid1]; 0235 int g2b = timeline->m_groups->m_upLink[cid2]; 0236 int g4b = timeline->m_groups->getRootId(cid1); 0237 REQUIRE(timeline->m_groups->getDirectChildren(g1b) == std::unordered_set<int>({cid1, cid4})); 0238 REQUIRE(timeline->m_groups->getDirectChildren(g2b) == std::unordered_set<int>({cid2, cid5})); 0239 REQUIRE(timeline->m_groups->getDirectChildren(g4b) == std::unordered_set<int>({g1b, g2b})); 0240 REQUIRE(timeline->getGroupElements(cid1) == std::unordered_set<int>({cid1, cid2, cid4, cid5})); 0241 }; 0242 auto state2 = [&]() { 0243 REQUIRE(timeline->checkConsistency()); 0244 int p = 0; 0245 for (int c : std::vector<int>({cid1, cid2, cid3})) { 0246 REQUIRE(timeline->getClipPlaytime(c) == (c == cid2 ? 4 : l)); 0247 REQUIRE(timeline->getClipTrackId(c) == tid1); 0248 REQUIRE(timeline->getClipPosition(c) == p); 0249 p += l; 0250 } 0251 p = 0; 0252 for (int c : std::vector<int>({cid4, cid5, cid6})) { 0253 REQUIRE(timeline->getClipPlaytime(c) == (c == cid5 ? 4 : l)); 0254 REQUIRE(timeline->getClipTrackId(c) == tid2); 0255 REQUIRE(timeline->getClipPosition(c) == p); 0256 p += l; 0257 } 0258 REQUIRE(timeline->getClipPosition(cid7) == 200); 0259 REQUIRE(timeline->getClipTrackId(cid7) == tid1); 0260 REQUIRE(timeline->getClipPosition(splitted) == l + 4); 0261 REQUIRE(timeline->getClipPlaytime(splitted) == l - 4); 0262 REQUIRE(timeline->getClipTrackId(splitted) == tid1); 0263 REQUIRE(timeline->getClipPosition(splitted2) == l + 4); 0264 REQUIRE(timeline->getClipPlaytime(splitted2) == l - 4); 0265 REQUIRE(timeline->getClipTrackId(splitted2) == tid2); 0266 check_groups(); 0267 }; 0268 state2(); 0269 0270 REQUIRE(timeline->requestClipMove(splitted, tid1, l + 4 + 10, true, true)); 0271 REQUIRE(timeline->requestClipMove(cid1, tid2, 10, true, true)); 0272 auto state3 = [&]() { 0273 REQUIRE(timeline->checkConsistency()); 0274 int p = 0; 0275 for (int c : std::vector<int>({cid1, cid2, cid3})) { 0276 REQUIRE(timeline->getClipPlaytime(c) == (c == cid2 ? 4 : l)); 0277 REQUIRE(timeline->getClipTrackId(c) == (c == cid3 ? tid1 : tid2)); 0278 REQUIRE(timeline->getClipPosition(c) == p + 10); 0279 p += l; 0280 } 0281 p = 0; 0282 for (int c : std::vector<int>({cid4, cid5, cid6})) { 0283 REQUIRE(timeline->getClipPlaytime(c) == (c == cid5 ? 4 : l)); 0284 REQUIRE(timeline->getClipTrackId(c) == (c == cid6 ? tid2 : tid3)); 0285 REQUIRE(timeline->getClipPosition(c) == p + 10); 0286 p += l; 0287 } 0288 REQUIRE(timeline->getClipPosition(cid7) == 210); 0289 REQUIRE(timeline->getClipTrackId(cid7) == tid1); 0290 REQUIRE(timeline->getClipPosition(splitted) == l + 4 + 10); 0291 REQUIRE(timeline->getClipPlaytime(splitted) == l - 4); 0292 REQUIRE(timeline->getClipTrackId(splitted) == tid1); 0293 REQUIRE(timeline->getClipPosition(splitted2) == l + 4 + 10); 0294 REQUIRE(timeline->getClipPlaytime(splitted2) == l - 4); 0295 REQUIRE(timeline->getClipTrackId(splitted2) == tid2); 0296 check_groups(); 0297 }; 0298 state3(); 0299 0300 undoStack->undo(); 0301 undoStack->undo(); 0302 state2(); 0303 undoStack->undo(); 0304 state(); 0305 undoStack->redo(); 0306 state2(); 0307 undoStack->redo(); 0308 undoStack->redo(); 0309 state3(); 0310 } 0311 0312 SECTION("Simple audio split") 0313 { 0314 int l = timeline->getClipPlaytime(audio1); 0315 REQUIRE(timeline->requestClipMove(audio1, tid1, 3)); 0316 0317 auto state = [&]() { 0318 REQUIRE(timeline->checkConsistency()); 0319 REQUIRE(timeline->getClipPlaytime(audio1) == l); 0320 REQUIRE(timeline->getClipPosition(audio1) == 3); 0321 REQUIRE(timeline->getClipTrackId(audio1) == tid1); 0322 REQUIRE(timeline->getTrackClipsCount(tid1) == 1); 0323 REQUIRE(timeline->getTrackClipsCount(tid2) == 0); 0324 0325 REQUIRE(timeline->getGroupElements(audio1) == std::unordered_set<int>({audio1})); 0326 }; 0327 state(); 0328 0329 REQUIRE(TimelineFunctions::requestSplitAudio(timeline, audio1, tid4)); 0330 int splitted1 = timeline->getClipByPosition(tid4, 3); 0331 auto state2 = [&]() { 0332 REQUIRE(timeline->checkConsistency()); 0333 REQUIRE(timeline->getClipPlaytime(audio1) == l); 0334 REQUIRE(timeline->getClipPosition(audio1) == 3); 0335 REQUIRE(timeline->getClipPlaytime(splitted1) == l); 0336 REQUIRE(timeline->getClipPosition(splitted1) == 3); 0337 REQUIRE(timeline->getClipTrackId(audio1) == tid1); 0338 REQUIRE(timeline->getClipTrackId(splitted1) == tid4); 0339 REQUIRE(timeline->getTrackClipsCount(tid1) == 1); 0340 REQUIRE(timeline->getTrackClipsCount(tid4) == 1); 0341 0342 REQUIRE(timeline->getGroupElements(audio1) == std::unordered_set<int>({audio1, splitted1})); 0343 0344 int g1 = timeline->m_groups->getDirectAncestor(audio1); 0345 REQUIRE(timeline->m_groups->getDirectChildren(g1) == std::unordered_set<int>({audio1, splitted1})); 0346 REQUIRE(timeline->m_groups->getType(g1) == GroupType::AVSplit); 0347 }; 0348 state2(); 0349 0350 undoStack->undo(); 0351 state(); 0352 undoStack->redo(); 0353 state2(); 0354 undoStack->undo(); 0355 state(); 0356 undoStack->redo(); 0357 state2(); 0358 0359 // We also make sure that clips that are audio only cannot be further splitted 0360 REQUIRE(timeline->requestClipMove(cid1, tid1, l + 30)); 0361 // This is a color clip, shouldn't be splittable 0362 REQUIRE_FALSE(TimelineFunctions::requestSplitAudio(timeline, cid1, tid2)); 0363 // Check we cannot split audio on a video track 0364 REQUIRE_FALSE(TimelineFunctions::requestSplitAudio(timeline, audio1, tid2)); 0365 } 0366 SECTION("Split audio on a selection") 0367 { 0368 0369 int l = timeline->getClipPlaytime(audio2); 0370 REQUIRE(timeline->requestClipMove(audio1, tid1, 0)); 0371 REQUIRE(timeline->requestClipMove(audio2, tid1, l)); 0372 REQUIRE(timeline->requestClipMove(audio3, tid1, 2 * l)); 0373 0374 std::unordered_set<int> selection{audio1, audio3, audio2}; 0375 timeline->requestSetSelection(selection); 0376 0377 auto state = [&]() { 0378 REQUIRE(timeline->checkConsistency()); 0379 REQUIRE(timeline->getClipPlaytime(audio1) == l); 0380 REQUIRE(timeline->getClipPlaytime(audio2) == l); 0381 REQUIRE(timeline->getClipPlaytime(audio3) == l); 0382 REQUIRE(timeline->getClipPosition(audio1) == 0); 0383 REQUIRE(timeline->getClipPosition(audio2) == l); 0384 REQUIRE(timeline->getClipPosition(audio3) == l + l); 0385 REQUIRE(timeline->getClipTrackId(audio1) == tid1); 0386 REQUIRE(timeline->getClipTrackId(audio2) == tid1); 0387 REQUIRE(timeline->getClipTrackId(audio3) == tid1); 0388 REQUIRE(timeline->getTrackClipsCount(tid1) == 3); 0389 REQUIRE(timeline->getTrackClipsCount(tid2) == 0); 0390 0391 REQUIRE(timeline->getGroupElements(audio1) == std::unordered_set<int>({audio1, audio2, audio3})); 0392 0393 REQUIRE(timeline->getCurrentSelection() == std::unordered_set<int>({audio1, audio3, audio2})); 0394 }; 0395 state(); 0396 0397 REQUIRE(TimelineFunctions::requestSplitAudio(timeline, audio1, tid4)); 0398 int splitted1 = timeline->getClipByPosition(tid4, 0); 0399 int splitted2 = timeline->getClipByPosition(tid4, l); 0400 int splitted3 = timeline->getClipByPosition(tid4, 2 * l); 0401 auto state2 = [&]() { 0402 REQUIRE(timeline->checkConsistency()); 0403 REQUIRE(timeline->getClipPlaytime(audio1) == l); 0404 REQUIRE(timeline->getClipPlaytime(audio2) == l); 0405 REQUIRE(timeline->getClipPlaytime(audio3) == l); 0406 REQUIRE(timeline->getClipPosition(audio1) == 0); 0407 REQUIRE(timeline->getClipPosition(audio2) == l); 0408 REQUIRE(timeline->getClipPosition(audio3) == l + l); 0409 REQUIRE(timeline->getClipPlaytime(splitted1) == l); 0410 REQUIRE(timeline->getClipPlaytime(splitted2) == l); 0411 REQUIRE(timeline->getClipPlaytime(splitted3) == l); 0412 REQUIRE(timeline->getClipPosition(splitted1) == 0); 0413 REQUIRE(timeline->getClipPosition(splitted2) == l); 0414 REQUIRE(timeline->getClipPosition(splitted3) == l + l); 0415 REQUIRE(timeline->getClipTrackId(audio1) == tid1); 0416 REQUIRE(timeline->getClipTrackId(audio2) == tid1); 0417 REQUIRE(timeline->getClipTrackId(audio3) == tid1); 0418 REQUIRE(timeline->getClipTrackId(splitted1) == tid4); 0419 REQUIRE(timeline->getClipTrackId(splitted2) == tid4); 0420 REQUIRE(timeline->getClipTrackId(splitted3) == tid4); 0421 REQUIRE(timeline->getTrackClipsCount(tid1) == 3); 0422 REQUIRE(timeline->getTrackClipsCount(tid4) == 3); 0423 0424 REQUIRE(timeline->getGroupElements(audio1) == std::unordered_set<int>({audio1, splitted1, audio2, audio3, splitted2, splitted3})); 0425 REQUIRE(timeline->getCurrentSelection() == std::unordered_set<int>({audio1, splitted1, audio2, audio3, splitted2, splitted3})); 0426 0427 int g1 = timeline->m_groups->getDirectAncestor(audio1); 0428 int g2 = timeline->m_groups->getDirectAncestor(audio2); 0429 int g3 = timeline->m_groups->getDirectAncestor(audio3); 0430 REQUIRE(timeline->m_groups->getDirectChildren(g1) == std::unordered_set<int>({audio1, splitted1})); 0431 REQUIRE(timeline->m_groups->getDirectChildren(g2) == std::unordered_set<int>({audio2, splitted2})); 0432 REQUIRE(timeline->m_groups->getDirectChildren(g3) == std::unordered_set<int>({audio3, splitted3})); 0433 REQUIRE(timeline->m_groups->getType(g1) == GroupType::AVSplit); 0434 REQUIRE(timeline->m_groups->getType(g2) == GroupType::AVSplit); 0435 REQUIRE(timeline->m_groups->getType(g3) == GroupType::AVSplit); 0436 }; 0437 state2(); 0438 0439 undoStack->undo(); 0440 state(); 0441 undoStack->redo(); 0442 state2(); 0443 } 0444 SECTION("Cut should preserve AV groups") 0445 { 0446 QString binId3 = createProducerWithSound(pCore->getProjectProfile(), binModel); 0447 0448 int tid6 = TrackModel::construct(timeline, -1, -1, QString(), true); 0449 int tid5 = TrackModel::construct(timeline); 0450 0451 // Setup timeline audio drop info 0452 QMap<int, QString> audioInfo; 0453 audioInfo.insert(1, QStringLiteral("stream1")); 0454 timeline->m_binAudioTargets = audioInfo; 0455 timeline->m_videoTarget = tid5; 0456 0457 int cid6 = -1; 0458 int pos = 3; 0459 REQUIRE(timeline->requestClipInsertion(binId3, tid5, pos, cid6, true, true, false)); 0460 int cid7 = timeline->m_groups->getSplitPartner(cid6); 0461 int l = timeline->getClipPlaytime(cid6); 0462 REQUIRE(l >= 10); 0463 0464 auto state = [&]() { 0465 REQUIRE(timeline->checkConsistency()); 0466 REQUIRE(timeline->getTrackClipsCount(tid5) == 1); 0467 REQUIRE(timeline->getTrackClipsCount(tid6) == 1); 0468 REQUIRE(timeline->getClipTrackId(cid6) == tid5); 0469 REQUIRE(timeline->getClipTrackId(cid7) == tid6); 0470 REQUIRE(timeline->getClipPosition(cid6) == pos); 0471 REQUIRE(timeline->getClipPosition(cid7) == pos); 0472 REQUIRE(timeline->getClipPtr(cid6)->clipState() == PlaylistState::VideoOnly); 0473 REQUIRE(timeline->getClipPtr(cid7)->clipState() == PlaylistState::AudioOnly); 0474 0475 // we check that the av group was correctly created 0476 REQUIRE(timeline->getGroupElements(cid6) == std::unordered_set<int>({cid6, cid7})); 0477 int g1 = timeline->m_groups->getDirectAncestor(cid6); 0478 REQUIRE(timeline->m_groups->getDirectChildren(g1) == std::unordered_set<int>({cid6, cid7})); 0479 REQUIRE(timeline->m_groups->getType(g1) == GroupType::AVSplit); 0480 }; 0481 state(); 0482 0483 REQUIRE(TimelineFunctions::requestClipCut(timeline, cid6, pos + 4)); 0484 0485 int cid8 = timeline->getClipByPosition(tid5, pos + 5); 0486 int cid9 = timeline->getClipByPosition(tid6, pos + 5); 0487 REQUIRE(cid8 >= 0); 0488 REQUIRE(cid9 >= 0); 0489 0490 auto state2 = [&]() { 0491 REQUIRE(timeline->checkConsistency()); 0492 REQUIRE(timeline->getTrackClipsCount(tid5) == 2); 0493 REQUIRE(timeline->getTrackClipsCount(tid6) == 2); 0494 REQUIRE(timeline->getClipTrackId(cid6) == tid5); 0495 REQUIRE(timeline->getClipTrackId(cid7) == tid6); 0496 REQUIRE(timeline->getClipTrackId(cid8) == tid5); 0497 REQUIRE(timeline->getClipTrackId(cid9) == tid6); 0498 0499 REQUIRE(timeline->getClipPosition(cid6) == pos); 0500 REQUIRE(timeline->getClipPosition(cid7) == pos); 0501 REQUIRE(timeline->getClipPosition(cid8) == pos + 4); 0502 REQUIRE(timeline->getClipPosition(cid9) == pos + 4); 0503 0504 REQUIRE(timeline->getClipPtr(cid6)->clipState() == PlaylistState::VideoOnly); 0505 REQUIRE(timeline->getClipPtr(cid7)->clipState() == PlaylistState::AudioOnly); 0506 REQUIRE(timeline->getClipPtr(cid8)->clipState() == PlaylistState::VideoOnly); 0507 REQUIRE(timeline->getClipPtr(cid9)->clipState() == PlaylistState::AudioOnly); 0508 0509 // original AV group 0510 REQUIRE(timeline->getGroupElements(cid6) == std::unordered_set<int>({cid6, cid7})); 0511 int g1 = timeline->m_groups->getDirectAncestor(cid6); 0512 REQUIRE(timeline->m_groups->getDirectChildren(g1) == std::unordered_set<int>({cid6, cid7})); 0513 REQUIRE(timeline->m_groups->getType(g1) == GroupType::AVSplit); 0514 0515 // new AV group 0516 REQUIRE(timeline->getGroupElements(cid8) == std::unordered_set<int>({cid8, cid9})); 0517 int g2 = timeline->m_groups->getDirectAncestor(cid8); 0518 REQUIRE(timeline->m_groups->getDirectChildren(g2) == std::unordered_set<int>({cid8, cid9})); 0519 REQUIRE(timeline->m_groups->getType(g2) == GroupType::AVSplit); 0520 }; 0521 state2(); 0522 0523 undoStack->undo(); 0524 state(); 0525 undoStack->redo(); 0526 state2(); 0527 } 0528 0529 pCore->projectManager()->closeCurrentDocument(false, false); 0530 } 0531 0532 TEST_CASE("Spacer operations", "[Spacer]") 0533 { 0534 auto binModel = pCore->projectItemModel(); 0535 binModel->clean(); 0536 std::shared_ptr<DocUndoStack> undoStack = std::make_shared<DocUndoStack>(nullptr); 0537 KdenliveDoc document(undoStack, {0, 1}); 0538 pCore->projectManager()->m_project = &document; 0539 QDateTime documentDate = QDateTime::currentDateTime(); 0540 pCore->projectManager()->updateTimeline(false, QString(), QString(), documentDate, 0); 0541 auto timeline = document.getTimeline(document.uuid()); 0542 pCore->projectManager()->m_activeTimelineModel = timeline; 0543 pCore->projectManager()->testSetActiveDocument(&document, timeline); 0544 0545 std::shared_ptr<MarkerListModel> guideModel = document.getGuideModel(document.uuid()); 0546 0547 QString binId = createProducer(pCore->getProjectProfile(), "red", binModel); 0548 QString binId2 = createProducer(pCore->getProjectProfile(), "blue", binModel); 0549 QString binId3 = createProducerWithSound(pCore->getProjectProfile(), binModel); 0550 0551 int cid1 = ClipModel::construct(timeline, binId, -1, PlaylistState::VideoOnly); 0552 int tid1 = timeline->getTrackIndexFromPosition(0); 0553 0554 // Add an audio track 0555 // int tid4 = TrackModel::construct(timeline, -1, -1, QString(), true); 0556 int cid2 = ClipModel::construct(timeline, binId2, -1, PlaylistState::VideoOnly); 0557 int cid3 = ClipModel::construct(timeline, binId, -1, PlaylistState::VideoOnly); 0558 0559 // int audio1 = ClipModel::construct(timeline, binId3, -1, PlaylistState::VideoOnly); 0560 0561 timeline->m_allClips[cid1]->m_endlessResize = false; 0562 timeline->m_allClips[cid2]->m_endlessResize = false; 0563 timeline->m_allClips[cid3]->m_endlessResize = false; 0564 0565 SECTION("Simple one track space insertion") 0566 { 0567 REQUIRE(timeline->requestClipMove(cid1, tid1, 0)); 0568 int l = timeline->getClipPlaytime(cid1); 0569 int p2 = l + 10; 0570 REQUIRE(timeline->requestClipMove(cid2, tid1, p2)); 0571 int p3 = l + l + 20; 0572 REQUIRE(timeline->requestClipMove(cid3, tid1, p3)); 0573 auto state = [&]() { 0574 REQUIRE(timeline->checkConsistency(guideModel->getSnapPoints())); 0575 REQUIRE(timeline->getClipPlaytime(cid1) == l); 0576 REQUIRE(timeline->getClipPlaytime(cid2) == l); 0577 REQUIRE(timeline->getClipPlaytime(cid3) == l); 0578 REQUIRE(timeline->getClipPosition(cid1) == 0); 0579 REQUIRE(timeline->getClipPosition(cid2) == p2); 0580 REQUIRE(timeline->getClipPosition(cid3) == p3); 0581 0582 REQUIRE(timeline->getClipPtr(cid1)->getIn() == 0); 0583 REQUIRE(timeline->getClipPtr(cid1)->getOut() == l - 1); 0584 REQUIRE(timeline->getClipPtr(cid2)->getIn() == 0); 0585 REQUIRE(timeline->getClipPtr(cid2)->getOut() == l - 1); 0586 REQUIRE(timeline->getClipPtr(cid3)->getIn() == 0); 0587 REQUIRE(timeline->getClipPtr(cid3)->getOut() == l - 1); 0588 }; 0589 state(); 0590 0591 int spacerIid = TimelineFunctions::requestSpacerStartOperation(timeline, tid1, l + 5).first; 0592 REQUIRE(spacerIid > -1); 0593 std::function<bool(void)> undo = []() { return true; }; 0594 std::function<bool(void)> redo = []() { return true; }; 0595 int itemPos = timeline->getItemPosition(spacerIid); 0596 int space = 18; 0597 REQUIRE(TimelineFunctions::requestSpacerEndOperation(timeline, spacerIid, itemPos, itemPos + space, tid1, -1, undo, redo)); 0598 auto state1 = [&]() { 0599 REQUIRE(timeline->checkConsistency(guideModel->getSnapPoints())); 0600 REQUIRE(timeline->getClipPlaytime(cid1) == l); 0601 REQUIRE(timeline->getClipPlaytime(cid2) == l); 0602 REQUIRE(timeline->getClipPlaytime(cid3) == l); 0603 REQUIRE(timeline->getClipPosition(cid1) == 0); 0604 REQUIRE(timeline->getClipPosition(cid2) == p2 + space); 0605 REQUIRE(timeline->getClipPosition(cid3) == p3 + space); 0606 REQUIRE(timeline->getClipPtr(cid1)->getIn() == 0); 0607 REQUIRE(timeline->getClipPtr(cid1)->getOut() == l - 1); 0608 REQUIRE(timeline->getClipPtr(cid2)->getIn() == 0); 0609 REQUIRE(timeline->getClipPtr(cid2)->getOut() == l - 1); 0610 REQUIRE(timeline->getClipPtr(cid3)->getIn() == 0); 0611 REQUIRE(timeline->getClipPtr(cid3)->getOut() == l - 1); 0612 }; 0613 state1(); 0614 0615 int startPos = timeline->getClipPosition(cid3) + l / 2; 0616 spacerIid = TimelineFunctions::requestSpacerStartOperation(timeline, tid1, startPos).first; 0617 REQUIRE(spacerIid > -1); 0618 undo = []() { return true; }; 0619 redo = []() { return true; }; 0620 itemPos = timeline->getItemPosition(spacerIid); 0621 int space2 = 3; 0622 REQUIRE(TimelineFunctions::requestSpacerEndOperation(timeline, spacerIid, itemPos, itemPos + space2, tid1, -1, undo, redo)); 0623 auto state2 = [&]() { 0624 REQUIRE(timeline->checkConsistency(guideModel->getSnapPoints())); 0625 REQUIRE(timeline->getClipPlaytime(cid1) == l); 0626 REQUIRE(timeline->getClipPlaytime(cid2) == l); 0627 REQUIRE(timeline->getClipPlaytime(cid3) == l); 0628 REQUIRE(timeline->getClipPosition(cid1) == 0); 0629 REQUIRE(timeline->getClipPosition(cid2) == p2 + space); 0630 REQUIRE(timeline->getClipPosition(cid3) == p3 + space + space2); 0631 REQUIRE(timeline->getClipPtr(cid1)->getIn() == 0); 0632 REQUIRE(timeline->getClipPtr(cid1)->getOut() == l - 1); 0633 REQUIRE(timeline->getClipPtr(cid2)->getIn() == 0); 0634 REQUIRE(timeline->getClipPtr(cid2)->getOut() == l - 1); 0635 REQUIRE(timeline->getClipPtr(cid3)->getIn() == 0); 0636 REQUIRE(timeline->getClipPtr(cid3)->getOut() == l - 1); 0637 }; 0638 state2(); 0639 0640 undoStack->undo(); 0641 state1(); 0642 undoStack->undo(); 0643 state(); 0644 0645 undoStack->redo(); 0646 state1(); 0647 undoStack->redo(); 0648 state2(); 0649 } 0650 0651 SECTION("Simple one track space insertion with guides") 0652 { 0653 pCore->projectManager()->m_activeTimelineModel = timeline; 0654 REQUIRE(timeline->requestClipMove(cid1, tid1, 0)); 0655 int l = timeline->getClipPlaytime(cid1); 0656 int p2 = l + 10; 0657 REQUIRE(timeline->requestClipMove(cid2, tid1, p2)); 0658 int p3 = l + l + 20; 0659 REQUIRE(timeline->requestClipMove(cid3, tid1, p3)); 0660 double fps = pCore->getProjectProfile().fps(); 0661 guideModel->addMarker(GenTime(l / 2, fps), "guide1"); 0662 guideModel->addMarker(GenTime(l + 2, fps), "guide2"); 0663 guideModel->addMarker(GenTime(l + 7, fps), "guide3"); 0664 guideModel->addMarker(GenTime(p2 + l / 2, fps), "guide4"); 0665 guideModel->addMarker(GenTime(p3, fps), "guide5"); 0666 auto state = [&]() { 0667 REQUIRE(timeline->checkConsistency(guideModel->getSnapPoints())); 0668 REQUIRE(timeline->getClipPlaytime(cid1) == l); 0669 REQUIRE(timeline->getClipPlaytime(cid2) == l); 0670 REQUIRE(timeline->getClipPlaytime(cid3) == l); 0671 REQUIRE(timeline->getClipPosition(cid1) == 0); 0672 REQUIRE(timeline->getClipPosition(cid2) == p2); 0673 REQUIRE(timeline->getClipPosition(cid3) == p3); 0674 0675 REQUIRE(timeline->getClipPtr(cid1)->getIn() == 0); 0676 REQUIRE(timeline->getClipPtr(cid1)->getOut() == l - 1); 0677 REQUIRE(timeline->getClipPtr(cid2)->getIn() == 0); 0678 REQUIRE(timeline->getClipPtr(cid2)->getOut() == l - 1); 0679 REQUIRE(timeline->getClipPtr(cid3)->getIn() == 0); 0680 REQUIRE(timeline->getClipPtr(cid3)->getOut() == l - 1); 0681 }; 0682 state(); 0683 0684 int spacerIid = TimelineFunctions::requestSpacerStartOperation(timeline, tid1, l + 5).first; 0685 REQUIRE(spacerIid > -1); 0686 std::function<bool(void)> undo = []() { return true; }; 0687 std::function<bool(void)> redo = []() { return true; }; 0688 int itemPos = timeline->getItemPosition(spacerIid); 0689 int space = 18; 0690 REQUIRE(TimelineFunctions::requestSpacerEndOperation(timeline, spacerIid, itemPos, itemPos + space, tid1, l + 5, undo, redo)); 0691 auto state1 = [&]() { 0692 REQUIRE(guideModel->getSnapPoints() == std::vector<int>{l / 2, l + 2, l + 7 + space, p2 + l / 2 + space, p3 + space}); 0693 REQUIRE(timeline->checkConsistency(guideModel->getSnapPoints())); 0694 REQUIRE(timeline->getClipPlaytime(cid1) == l); 0695 REQUIRE(timeline->getClipPlaytime(cid2) == l); 0696 REQUIRE(timeline->getClipPlaytime(cid3) == l); 0697 REQUIRE(timeline->getClipPosition(cid1) == 0); 0698 REQUIRE(timeline->getClipPosition(cid2) == p2 + space); 0699 REQUIRE(timeline->getClipPosition(cid3) == p3 + space); 0700 REQUIRE(timeline->getClipPtr(cid1)->getIn() == 0); 0701 REQUIRE(timeline->getClipPtr(cid1)->getOut() == l - 1); 0702 REQUIRE(timeline->getClipPtr(cid2)->getIn() == 0); 0703 REQUIRE(timeline->getClipPtr(cid2)->getOut() == l - 1); 0704 REQUIRE(timeline->getClipPtr(cid3)->getIn() == 0); 0705 REQUIRE(timeline->getClipPtr(cid3)->getOut() == l - 1); 0706 }; 0707 state1(); 0708 0709 int startPos = timeline->getClipPosition(cid3) + l / 2; 0710 spacerIid = TimelineFunctions::requestSpacerStartOperation(timeline, tid1, startPos).first; 0711 REQUIRE(spacerIid > -1); 0712 undo = []() { return true; }; 0713 redo = []() { return true; }; 0714 itemPos = timeline->getItemPosition(spacerIid); 0715 int space2 = 3; 0716 REQUIRE(TimelineFunctions::requestSpacerEndOperation(timeline, spacerIid, itemPos, itemPos + space2, tid1, startPos, undo, redo)); 0717 auto state2 = [&]() { 0718 REQUIRE(guideModel->getSnapPoints() == std::vector<int>{l / 2, l + 2, l + 7 + space, p2 + l / 2 + space, p3 + space + space2}); 0719 REQUIRE(timeline->checkConsistency(guideModel->getSnapPoints())); 0720 REQUIRE(timeline->getClipPlaytime(cid1) == l); 0721 REQUIRE(timeline->getClipPlaytime(cid2) == l); 0722 REQUIRE(timeline->getClipPlaytime(cid3) == l); 0723 REQUIRE(timeline->getClipPosition(cid1) == 0); 0724 REQUIRE(timeline->getClipPosition(cid2) == p2 + space); 0725 REQUIRE(timeline->getClipPosition(cid3) == p3 + space + space2); 0726 REQUIRE(timeline->getClipPtr(cid1)->getIn() == 0); 0727 REQUIRE(timeline->getClipPtr(cid1)->getOut() == l - 1); 0728 REQUIRE(timeline->getClipPtr(cid2)->getIn() == 0); 0729 REQUIRE(timeline->getClipPtr(cid2)->getOut() == l - 1); 0730 REQUIRE(timeline->getClipPtr(cid3)->getIn() == 0); 0731 REQUIRE(timeline->getClipPtr(cid3)->getOut() == l - 1); 0732 }; 0733 state2(); 0734 0735 undoStack->undo(); 0736 state1(); 0737 undoStack->undo(); 0738 state(); 0739 0740 undoStack->redo(); 0741 state1(); 0742 undoStack->redo(); 0743 state2(); 0744 } 0745 0746 SECTION("Simple one track space deletion") 0747 { 0748 REQUIRE(timeline->requestClipMove(cid1, tid1, 0)); 0749 int l = timeline->getClipPlaytime(cid1); 0750 int p2 = l + 10; 0751 REQUIRE(timeline->requestClipMove(cid2, tid1, p2)); 0752 int p3 = l + l + 10; 0753 REQUIRE(timeline->requestClipMove(cid3, tid1, p3)); 0754 auto state = [&]() { 0755 REQUIRE(timeline->checkConsistency(guideModel->getSnapPoints())); 0756 REQUIRE(timeline->getClipPlaytime(cid1) == l); 0757 REQUIRE(timeline->getClipPlaytime(cid2) == l); 0758 REQUIRE(timeline->getClipPlaytime(cid3) == l); 0759 REQUIRE(timeline->getClipPosition(cid1) == 0); 0760 REQUIRE(timeline->getClipPosition(cid2) == p2); 0761 REQUIRE(timeline->getClipPosition(cid3) == p3); 0762 0763 REQUIRE(timeline->getClipPtr(cid1)->getIn() == 0); 0764 REQUIRE(timeline->getClipPtr(cid1)->getOut() == l - 1); 0765 REQUIRE(timeline->getClipPtr(cid2)->getIn() == 0); 0766 REQUIRE(timeline->getClipPtr(cid2)->getOut() == l - 1); 0767 REQUIRE(timeline->getClipPtr(cid3)->getIn() == 0); 0768 REQUIRE(timeline->getClipPtr(cid3)->getOut() == l - 1); 0769 }; 0770 state(); 0771 0772 int spacerIid = TimelineFunctions::requestSpacerStartOperation(timeline, tid1, l + 5).first; 0773 REQUIRE(spacerIid > -1); 0774 std::function<bool(void)> undo = []() { return true; }; 0775 std::function<bool(void)> redo = []() { return true; }; 0776 int itemPos = timeline->getItemPosition(spacerIid); 0777 // space to remove is larger than possible (at the end only 10 frames should be removed) 0778 int space = 18; 0779 REQUIRE(TimelineFunctions::requestSpacerEndOperation(timeline, spacerIid, itemPos, itemPos - space, tid1, -1, undo, redo)); 0780 auto state1 = [&]() { 0781 REQUIRE(timeline->checkConsistency(guideModel->getSnapPoints())); 0782 REQUIRE(timeline->getClipPlaytime(cid1) == l); 0783 REQUIRE(timeline->getClipPlaytime(cid2) == l); 0784 REQUIRE(timeline->getClipPlaytime(cid3) == l); 0785 REQUIRE(timeline->getClipPosition(cid1) == 0); 0786 REQUIRE(timeline->getClipPosition(cid2) == p2 - 10); 0787 REQUIRE(timeline->getClipPosition(cid3) == p3 - 10); 0788 REQUIRE(timeline->getClipPtr(cid1)->getIn() == 0); 0789 REQUIRE(timeline->getClipPtr(cid1)->getOut() == l - 1); 0790 REQUIRE(timeline->getClipPtr(cid2)->getIn() == 0); 0791 REQUIRE(timeline->getClipPtr(cid2)->getOut() == l - 1); 0792 REQUIRE(timeline->getClipPtr(cid3)->getIn() == 0); 0793 REQUIRE(timeline->getClipPtr(cid3)->getOut() == l - 1); 0794 }; 0795 state1(); 0796 0797 int startPos = timeline->getClipPosition(cid3) + l / 2; 0798 spacerIid = TimelineFunctions::requestSpacerStartOperation(timeline, tid1, startPos).first; 0799 REQUIRE(spacerIid > -1); 0800 undo = []() { return true; }; 0801 redo = []() { return true; }; 0802 itemPos = timeline->getItemPosition(spacerIid); 0803 int space2 = 3; 0804 REQUIRE(!TimelineFunctions::requestSpacerEndOperation(timeline, spacerIid, itemPos, itemPos - space2, tid1, -1, undo, redo)); 0805 state1(); 0806 0807 undoStack->undo(); 0808 state(); 0809 0810 undoStack->redo(); 0811 state1(); 0812 } 0813 0814 pCore->projectManager()->closeCurrentDocument(false, false); 0815 } 0816 0817 TEST_CASE("Insert/delete", "[Trimming2]") 0818 { 0819 auto binModel = pCore->projectItemModel(); 0820 binModel->clean(); 0821 std::shared_ptr<DocUndoStack> undoStack = std::make_shared<DocUndoStack>(nullptr); 0822 0823 // Here we do some trickery to enable testing. 0824 KdenliveDoc document(undoStack); 0825 pCore->projectManager()->m_project = &document; 0826 QDateTime documentDate = QDateTime::currentDateTime(); 0827 pCore->projectManager()->updateTimeline(false, QString(), QString(), documentDate, 0); 0828 auto timeline = document.getTimeline(document.uuid()); 0829 pCore->projectManager()->m_activeTimelineModel = timeline; 0830 pCore->projectManager()->testSetActiveDocument(&document, timeline); 0831 0832 QString binId = createProducerWithSound(pCore->getProjectProfile(), binModel); 0833 int tid2 = timeline->getTrackIndexFromPosition(1); 0834 int tid1 = timeline->getTrackIndexFromPosition(2); 0835 0836 // Setup timeline audio drop info 0837 QMap<int, QString> audioInfo; 0838 audioInfo.insert(1, QStringLiteral("stream1")); 0839 timeline->m_binAudioTargets = audioInfo; 0840 timeline->m_videoTarget = tid1; 0841 0842 SECTION("Remove Space should preserve groups") 0843 { 0844 0845 int cid1 = -1; 0846 REQUIRE(timeline->requestClipInsertion(binId, tid1, 3, cid1, true, true, false)); 0847 int cid2 = timeline->m_groups->getSplitPartner(cid1); 0848 0849 auto state = [&](int pos) { 0850 REQUIRE(timeline->checkConsistency()); 0851 REQUIRE(timeline->getTrackClipsCount(tid1) == 1); 0852 REQUIRE(timeline->getTrackClipsCount(tid2) == 1); 0853 REQUIRE(timeline->getClipTrackId(cid1) == tid1); 0854 REQUIRE(timeline->getClipTrackId(cid2) == tid2); 0855 REQUIRE(timeline->getClipPosition(cid1) == pos); 0856 REQUIRE(timeline->getClipPosition(cid2) == pos); 0857 REQUIRE(timeline->getClipPtr(cid1)->clipState() == PlaylistState::VideoOnly); 0858 REQUIRE(timeline->getClipPtr(cid2)->clipState() == PlaylistState::AudioOnly); 0859 // we check that the av group was correctly created 0860 REQUIRE(timeline->getGroupElements(cid1) == std::unordered_set<int>({cid1, cid2})); 0861 int g1 = timeline->m_groups->getDirectAncestor(cid1); 0862 REQUIRE(timeline->m_groups->getDirectChildren(g1) == std::unordered_set<int>({cid1, cid2})); 0863 REQUIRE(timeline->m_groups->getType(g1) == GroupType::AVSplit); 0864 }; 0865 state(3); 0866 0867 REQUIRE(TimelineFunctions::requestDeleteBlankAt(timeline, tid1, 1, true)); 0868 state(0); 0869 0870 undoStack->undo(); 0871 state(3); 0872 undoStack->redo(); 0873 state(0); 0874 } 0875 0876 SECTION("Insert zone should preserve groups") 0877 { 0878 int cid1 = -1; 0879 REQUIRE(timeline->requestClipInsertion(binId, tid1, 3, cid1, true, true, false)); 0880 int cid2 = timeline->m_groups->getSplitPartner(cid1); 0881 0882 int l = timeline->getClipPlaytime(cid2); 0883 auto state = [&]() { 0884 REQUIRE(timeline->checkConsistency()); 0885 REQUIRE(timeline->getTrackClipsCount(tid1) == 1); 0886 REQUIRE(timeline->getTrackClipsCount(tid2) == 1); 0887 REQUIRE(timeline->getClipTrackId(cid1) == tid1); 0888 REQUIRE(timeline->getClipTrackId(cid2) == tid2); 0889 REQUIRE(timeline->getClipPosition(cid1) == 3); 0890 REQUIRE(timeline->getClipPosition(cid2) == 3); 0891 REQUIRE(timeline->getClipPtr(cid1)->clipState() == PlaylistState::VideoOnly); 0892 REQUIRE(timeline->getClipPtr(cid2)->clipState() == PlaylistState::AudioOnly); 0893 // we check that the av group was correctly created 0894 REQUIRE(timeline->getGroupElements(cid1) == std::unordered_set<int>({cid1, cid2})); 0895 int g1 = timeline->m_groups->getDirectAncestor(cid1); 0896 REQUIRE(timeline->m_groups->getDirectChildren(g1) == std::unordered_set<int>({cid1, cid2})); 0897 REQUIRE(timeline->m_groups->getType(g1) == GroupType::AVSplit); 0898 }; 0899 state(); 0900 0901 timeline->m_audioTarget.insert(tid2, 0); 0902 timeline->m_videoTarget = tid1; 0903 // Make tracks active 0904 timeline->setTrackProperty(tid1, QStringLiteral("kdenlive:timeline_active"), QStringLiteral("1")); 0905 timeline->setTrackProperty(tid2, QStringLiteral("kdenlive:timeline_active"), QStringLiteral("1")); 0906 REQUIRE(TimelineFunctions::insertZone(timeline, {tid1, tid2}, binId, 3 + 2, {l / 4, 3 * l / 4}, false)); 0907 timeline->m_audioTarget.clear(); 0908 timeline->m_videoTarget = -1; 0909 int small_length = 3 * l / 4 - l / 4; 0910 int cid3 = timeline->getClipByPosition(tid1, 3 + 2); 0911 int cid4 = timeline->getClipByPosition(tid2, 3 + 2); 0912 int cid5 = timeline->getClipByPosition(tid1, 3 + 2 + small_length); 0913 int cid6 = timeline->getClipByPosition(tid2, 3 + 2 + small_length); 0914 0915 auto state2 = [&]() { 0916 REQUIRE(timeline->checkConsistency()); 0917 REQUIRE(timeline->getTrackClipsCount(tid1) == 3); 0918 REQUIRE(timeline->getTrackClipsCount(tid2) == 3); 0919 REQUIRE(timeline->getClipTrackId(cid1) == tid1); 0920 REQUIRE(timeline->getClipTrackId(cid2) == tid2); 0921 REQUIRE(timeline->getClipTrackId(cid3) == tid1); 0922 REQUIRE(timeline->getClipTrackId(cid4) == tid2); 0923 REQUIRE(timeline->getClipTrackId(cid5) == tid1); 0924 REQUIRE(timeline->getClipTrackId(cid6) == tid2); 0925 REQUIRE(timeline->getClipPosition(cid1) == 3); 0926 REQUIRE(timeline->getClipPosition(cid2) == 3); 0927 REQUIRE(timeline->getClipPosition(cid3) == 3 + 2); 0928 REQUIRE(timeline->getClipPosition(cid4) == 3 + 2); 0929 REQUIRE(timeline->getClipPosition(cid5) == 3 + 2 + small_length); 0930 REQUIRE(timeline->getClipPosition(cid6) == 3 + 2 + small_length); 0931 REQUIRE(timeline->getClipPlaytime(cid1) + timeline->getClipPlaytime(cid5) == l); 0932 REQUIRE(timeline->getClipPlaytime(cid1) == 2); 0933 REQUIRE(timeline->getClipPlaytime(cid3) == small_length); 0934 REQUIRE(timeline->getClipPtr(cid1)->clipState() == PlaylistState::VideoOnly); 0935 REQUIRE(timeline->getClipPtr(cid2)->clipState() == PlaylistState::AudioOnly); 0936 REQUIRE(timeline->getClipPtr(cid3)->clipState() == PlaylistState::VideoOnly); 0937 REQUIRE(timeline->getClipPtr(cid4)->clipState() == PlaylistState::AudioOnly); 0938 REQUIRE(timeline->getClipPtr(cid5)->clipState() == PlaylistState::VideoOnly); 0939 REQUIRE(timeline->getClipPtr(cid6)->clipState() == PlaylistState::AudioOnly); 0940 // we check that the av group was correctly created 0941 REQUIRE(timeline->getGroupElements(cid1) == std::unordered_set<int>({cid1, cid2})); 0942 int g1 = timeline->m_groups->getDirectAncestor(cid1); 0943 REQUIRE(timeline->m_groups->getDirectChildren(g1) == std::unordered_set<int>({cid1, cid2})); 0944 REQUIRE(timeline->m_groups->getType(g1) == GroupType::AVSplit); 0945 0946 REQUIRE(timeline->getGroupElements(cid3) == std::unordered_set<int>({cid3, cid4})); 0947 int g2 = timeline->m_groups->getDirectAncestor(cid3); 0948 REQUIRE(timeline->m_groups->getDirectChildren(g2) == std::unordered_set<int>({cid3, cid4})); 0949 REQUIRE(timeline->m_groups->getType(g2) == GroupType::AVSplit); 0950 0951 int g3 = timeline->m_groups->getDirectAncestor(cid5); 0952 REQUIRE(timeline->m_groups->getDirectChildren(g3) == std::unordered_set<int>({cid5, cid6})); 0953 REQUIRE(timeline->m_groups->getType(g3) == GroupType::AVSplit); 0954 }; 0955 state2(); 0956 undoStack->undo(); 0957 state(); 0958 undoStack->redo(); 0959 state2(); 0960 } 0961 0962 pCore->projectManager()->closeCurrentDocument(false, false); 0963 } 0964 0965 TEST_CASE("Copy/paste", "[CP]") 0966 { 0967 auto binModel = pCore->projectItemModel(); 0968 binModel->clean(); 0969 std::shared_ptr<DocUndoStack> undoStack = std::make_shared<DocUndoStack>(nullptr); 0970 0971 KdenliveDoc document(undoStack); 0972 pCore->projectManager()->m_project = &document; 0973 QDateTime documentDate = QDateTime::currentDateTime(); 0974 pCore->projectManager()->updateTimeline(false, QString(), QString(), documentDate, 0); 0975 auto timeline = document.getTimeline(document.uuid()); 0976 pCore->projectManager()->m_activeTimelineModel = timeline; 0977 pCore->projectManager()->testSetActiveDocument(&document, timeline); 0978 0979 QString binId = createProducerWithSound(pCore->getProjectProfile(), binModel); 0980 QString binId2 = createProducer(pCore->getProjectProfile(), "red", binModel); 0981 0982 int tid2b = timeline->getTrackIndexFromPosition(0); 0983 int tid2 = timeline->getTrackIndexFromPosition(1); 0984 int tid1 = timeline->getTrackIndexFromPosition(2); 0985 int tid1b = timeline->getTrackIndexFromPosition(3); 0986 0987 // Setup timeline audio drop info 0988 QMap<int, QString> audioInfo; 0989 audioInfo.insert(1, QStringLiteral("stream1")); 0990 timeline->m_binAudioTargets = audioInfo; 0991 timeline->m_videoTarget = tid1; 0992 0993 SECTION("Simple copy paste of one clip") 0994 { 0995 0996 int cid1 = -1; 0997 REQUIRE(timeline->requestClipInsertion(binId2, tid1, 3, cid1, true, true, false)); 0998 int l = timeline->getClipPlaytime(cid1); 0999 int cid2 = -1; 1000 REQUIRE(timeline->requestClipInsertion(binId2, tid1, 3 + l, cid2, true, true, false)); 1001 1002 auto state = [&]() { 1003 REQUIRE(timeline->checkConsistency()); 1004 REQUIRE(timeline->getTrackClipsCount(tid1) == 2); 1005 REQUIRE(timeline->getClipTrackId(cid1) == tid1); 1006 REQUIRE(timeline->getClipTrackId(cid2) == tid1); 1007 REQUIRE(timeline->getClipPosition(cid1) == 3); 1008 REQUIRE(timeline->getClipPosition(cid2) == 3 + l); 1009 }; 1010 state(); 1011 1012 QString cpy_str = TimelineFunctions::copyClips(timeline, {cid1}); 1013 1014 // Try to paste in invalid positions 1015 REQUIRE_FALSE(TimelineFunctions::pasteClips(timeline, cpy_str, tid1, 0)); 1016 state(); 1017 REQUIRE_FALSE(TimelineFunctions::pasteClips(timeline, cpy_str, tid1, 4)); 1018 state(); 1019 REQUIRE_FALSE(TimelineFunctions::pasteClips(timeline, cpy_str, tid1, 4 + l)); 1020 state(); 1021 // Paste in audio track 1022 REQUIRE_FALSE(TimelineFunctions::pasteClips(timeline, cpy_str, tid2, 0)); 1023 state(); 1024 REQUIRE_FALSE(TimelineFunctions::pasteClips(timeline, cpy_str, tid2b, 0)); 1025 state(); 1026 1027 // Paste after the last clip 1028 REQUIRE(TimelineFunctions::pasteClips(timeline, cpy_str, tid1, 3 + 2 * l)); 1029 int cid3 = timeline->getTrackById(tid1)->getClipByPosition(3 + 2 * l + 1); 1030 REQUIRE(cid3 != -1); 1031 auto state2 = [&]() { 1032 REQUIRE(timeline->checkConsistency()); 1033 REQUIRE(timeline->getTrackClipsCount(tid1) == 3); 1034 REQUIRE(timeline->getClipTrackId(cid1) == tid1); 1035 REQUIRE(timeline->getClipTrackId(cid2) == tid1); 1036 REQUIRE(timeline->getClipTrackId(cid3) == tid1); 1037 REQUIRE(timeline->getClipPosition(cid1) == 3); 1038 REQUIRE(timeline->getClipPosition(cid2) == 3 + l); 1039 REQUIRE(timeline->getClipPosition(cid3) == 3 + 2 * l); 1040 }; 1041 state2(); 1042 1043 undoStack->undo(); 1044 state(); 1045 undoStack->redo(); 1046 state2(); 1047 1048 // Paste in different track 1049 REQUIRE(TimelineFunctions::pasteClips(timeline, cpy_str, tid1b, 0)); 1050 int cid4 = timeline->getTrackById(tid1b)->getClipByPosition(0); 1051 REQUIRE(cid4 != -1); 1052 auto state3 = [&]() { 1053 state2(); 1054 REQUIRE(timeline->getTrackClipsCount(tid1b) == 1); 1055 REQUIRE(timeline->getClipTrackId(cid4) == tid1b); 1056 REQUIRE(timeline->getClipPosition(cid4) == 0); 1057 }; 1058 state3(); 1059 1060 undoStack->undo(); 1061 state2(); 1062 undoStack->undo(); 1063 state(); 1064 undoStack->redo(); 1065 state2(); 1066 undoStack->redo(); 1067 state3(); 1068 } 1069 1070 SECTION("Copy paste groups") 1071 { 1072 1073 auto state0 = [&]() { 1074 REQUIRE(timeline->checkConsistency()); 1075 REQUIRE(timeline->getTrackClipsCount(tid1) == 0); 1076 REQUIRE(timeline->getTrackClipsCount(tid2) == 0); 1077 REQUIRE(timeline->getTrackClipsCount(tid1b) == 0); 1078 REQUIRE(timeline->getTrackClipsCount(tid2b) == 0); 1079 }; 1080 state0(); 1081 int cid1 = -1; 1082 REQUIRE(timeline->requestClipInsertion(binId, tid1, 3, cid1, true, true, false)); 1083 int l = timeline->getClipPlaytime(cid1); 1084 int cid2 = timeline->m_groups->getSplitPartner(cid1); 1085 1086 auto state = [&](int count1, int count2) { 1087 REQUIRE(timeline->checkConsistency()); 1088 REQUIRE(timeline->getTrackClipsCount(tid1) == count1); 1089 REQUIRE(timeline->getTrackClipsCount(tid2) == count1); 1090 REQUIRE(timeline->getTrackClipsCount(tid1b) == count2); 1091 REQUIRE(timeline->getTrackClipsCount(tid2b) == count2); 1092 REQUIRE(timeline->getClipTrackId(cid1) == tid1); 1093 REQUIRE(timeline->getClipTrackId(cid2) == tid2); 1094 REQUIRE(timeline->getClipPosition(cid1) == 3); 1095 REQUIRE(timeline->getClipPosition(cid2) == 3); 1096 REQUIRE(timeline->getClipPtr(cid1)->clipState() == PlaylistState::VideoOnly); 1097 REQUIRE(timeline->getClipPtr(cid2)->clipState() == PlaylistState::AudioOnly); 1098 // we check that the av group was correctly created 1099 REQUIRE(timeline->getGroupElements(cid1) == std::unordered_set<int>({cid1, cid2})); 1100 int g1 = timeline->m_groups->getDirectAncestor(cid1); 1101 REQUIRE(timeline->m_groups->getDirectChildren(g1) == std::unordered_set<int>({cid1, cid2})); 1102 REQUIRE(timeline->m_groups->getType(g1) == GroupType::AVSplit); 1103 }; 1104 state(1, 0); 1105 1106 QString cpy_str = TimelineFunctions::copyClips(timeline, {cid1}); 1107 1108 REQUIRE_FALSE(TimelineFunctions::pasteClips(timeline, cpy_str, tid1, 0)); 1109 state(1, 0); 1110 REQUIRE_FALSE(TimelineFunctions::pasteClips(timeline, cpy_str, tid1, 4)); 1111 state(1, 0); 1112 1113 // potentially annoying selection 1114 REQUIRE(timeline->requestSetSelection({cid1})); 1115 REQUIRE(timeline->getCurrentSelection() == std::unordered_set<int>{cid1, cid2}); 1116 1117 // paste on same track, after clip 1118 REQUIRE(TimelineFunctions::pasteClips(timeline, cpy_str, tid1, 3 + 2 * l)); 1119 int cid3 = timeline->getTrackById(tid1)->getClipByPosition(3 + 2 * l + 1); 1120 REQUIRE(cid3 != -1); 1121 int cid4 = timeline->m_groups->getSplitPartner(cid3); 1122 auto state2 = [&](int count1, int count2) { 1123 state(count1, count2); 1124 REQUIRE(timeline->getClipTrackId(cid3) == tid1); 1125 REQUIRE(timeline->getClipTrackId(cid4) == tid2); 1126 REQUIRE(timeline->getClipPosition(cid3) == 3 + 2 * l); 1127 REQUIRE(timeline->getClipPosition(cid4) == 3 + 2 * l); 1128 REQUIRE(timeline->getClipPtr(cid3)->clipState() == PlaylistState::VideoOnly); 1129 REQUIRE(timeline->getClipPtr(cid4)->clipState() == PlaylistState::AudioOnly); 1130 // we check that the av group was correctly created 1131 REQUIRE(timeline->getGroupElements(cid3) == std::unordered_set<int>({cid3, cid4})); 1132 int g1 = timeline->m_groups->getDirectAncestor(cid3); 1133 REQUIRE(timeline->m_groups->getDirectChildren(g1) == std::unordered_set<int>({cid3, cid4})); 1134 REQUIRE(timeline->m_groups->getType(g1) == GroupType::AVSplit); 1135 }; 1136 state2(2, 0); 1137 1138 // potentially annoying selection 1139 REQUIRE(timeline->requestSetSelection({cid1})); 1140 REQUIRE(timeline->getCurrentSelection() == std::unordered_set<int>{cid1, cid2}); 1141 undoStack->undo(); 1142 REQUIRE(timeline->requestClearSelection()); 1143 state(1, 0); 1144 1145 // potentially annoying selection 1146 REQUIRE(timeline->requestSetSelection({cid1})); 1147 REQUIRE(timeline->getCurrentSelection() == std::unordered_set<int>{cid1, cid2}); 1148 undoStack->redo(); 1149 REQUIRE(timeline->requestClearSelection()); 1150 state2(2, 0); 1151 1152 // another potentially annoying selection 1153 REQUIRE(timeline->requestSetSelection({cid1, cid3})); 1154 REQUIRE(timeline->getCurrentSelection() == std::unordered_set<int>{cid1, cid2, cid3, cid4}); 1155 undoStack->undo(); 1156 REQUIRE(timeline->requestClearSelection()); 1157 state(1, 0); 1158 REQUIRE(timeline->requestSetSelection({cid1})); 1159 REQUIRE(timeline->getCurrentSelection() == std::unordered_set<int>{cid1, cid2}); 1160 undoStack->redo(); 1161 REQUIRE(timeline->requestClearSelection()); 1162 state2(2, 0); 1163 1164 // now, we copy the old clips as well as those we just pasted. Let's do it using a selection 1165 REQUIRE(timeline->requestSetSelection({cid1, cid3})); 1166 REQUIRE(timeline->getCurrentSelection() == std::unordered_set<int>{cid1, cid2, cid3, cid4}); 1167 // since everything is selected, everything should be copied here 1168 cpy_str = TimelineFunctions::copyClips(timeline, {cid1}); 1169 1170 REQUIRE_FALSE(TimelineFunctions::pasteClips(timeline, cpy_str, tid1, 0)); 1171 state2(2, 0); 1172 1173 // parasitic selection 1174 REQUIRE(timeline->requestSetSelection({cid1, cid3})); 1175 REQUIRE(timeline->getCurrentSelection() == std::unordered_set<int>{cid1, cid2, cid3, cid4}); 1176 1177 // We paste on the other track 1178 REQUIRE(TimelineFunctions::pasteClips(timeline, cpy_str, tid1b, 0)); 1179 qDebug() << "track tid1 count" << timeline->getTrackClipsCount(tid1); 1180 qDebug() << "track tid2 count" << timeline->getTrackClipsCount(tid2); 1181 qDebug() << "track tid1b count" << timeline->getTrackClipsCount(tid1b); 1182 qDebug() << "track tid2b count" << timeline->getTrackClipsCount(tid2b); 1183 int cid5 = timeline->getTrackById(tid1b)->getClipByPosition(0); 1184 REQUIRE(cid5 != -1); 1185 int cid6 = timeline->m_groups->getSplitPartner(cid5); 1186 REQUIRE(cid6 != -1); 1187 int cid7 = timeline->getTrackById(tid1b)->getClipByPosition(2 * l + 1); 1188 REQUIRE(cid7 != -1); 1189 int cid8 = timeline->m_groups->getSplitPartner(cid7); 1190 REQUIRE(cid8 != -1); 1191 auto state3 = [&](int count1, int count2) { 1192 state2(count1, count2); 1193 REQUIRE(timeline->getClipTrackId(cid5) == tid1b); 1194 REQUIRE(timeline->getClipTrackId(cid7) == tid1b); 1195 REQUIRE(timeline->getClipTrackId(cid6) == tid2b); 1196 REQUIRE(timeline->getClipTrackId(cid8) == tid2b); 1197 REQUIRE(timeline->getClipPosition(cid5) == 0); 1198 REQUIRE(timeline->getClipPosition(cid6) == 0); 1199 REQUIRE(timeline->getClipPosition(cid7) == 2 * l); 1200 REQUIRE(timeline->getClipPosition(cid8) == 2 * l); 1201 REQUIRE(timeline->getClipPtr(cid5)->clipState() == PlaylistState::VideoOnly); 1202 REQUIRE(timeline->getClipPtr(cid6)->clipState() == PlaylistState::AudioOnly); 1203 REQUIRE(timeline->getClipPtr(cid7)->clipState() == PlaylistState::VideoOnly); 1204 REQUIRE(timeline->getClipPtr(cid8)->clipState() == PlaylistState::AudioOnly); 1205 // we check that the av group was correctly created 1206 REQUIRE(timeline->getGroupElements(cid5) == std::unordered_set<int>({cid5, cid6})); 1207 int g1 = timeline->m_groups->getDirectAncestor(cid5); 1208 REQUIRE(timeline->m_groups->getDirectChildren(g1) == std::unordered_set<int>({cid5, cid6})); 1209 REQUIRE(timeline->m_groups->getType(g1) == GroupType::AVSplit); 1210 1211 REQUIRE(timeline->getGroupElements(cid7) == std::unordered_set<int>({cid7, cid8})); 1212 int g2 = timeline->m_groups->getDirectAncestor(cid7); 1213 REQUIRE(timeline->m_groups->getDirectChildren(g2) == std::unordered_set<int>({cid7, cid8})); 1214 REQUIRE(timeline->m_groups->getType(g2) == GroupType::AVSplit); 1215 }; 1216 state3(2, 2); 1217 1218 // parasitic selection 1219 REQUIRE(timeline->requestSetSelection({cid1, cid3})); 1220 REQUIRE(timeline->getCurrentSelection() == std::unordered_set<int>{cid1, cid2, cid3, cid4}); 1221 undoStack->undo(); 1222 REQUIRE(timeline->requestClearSelection()); 1223 state2(2, 0); 1224 REQUIRE(timeline->requestSetSelection({cid1, cid3})); 1225 REQUIRE(timeline->getCurrentSelection() == std::unordered_set<int>{cid1, cid2, cid3, cid4}); 1226 undoStack->redo(); 1227 REQUIRE(timeline->requestClearSelection()); 1228 state3(2, 2); 1229 } 1230 1231 SECTION("Paste when tracks get deleted") 1232 { 1233 auto state0 = [&]() { 1234 REQUIRE(timeline->checkConsistency()); 1235 REQUIRE(timeline->getTrackClipsCount(tid1) == 0); 1236 REQUIRE(timeline->getTrackClipsCount(tid2) == 0); 1237 REQUIRE(timeline->getTrackClipsCount(tid1b) == 0); 1238 REQUIRE(timeline->getTrackClipsCount(tid2b) == 0); 1239 }; 1240 state0(); 1241 int cid1 = -1; 1242 REQUIRE(timeline->requestClipInsertion(binId, tid1, 3, cid1, true, true, false)); 1243 timeline->getClipPlaytime(cid1); 1244 int cid2 = timeline->m_groups->getSplitPartner(cid1); 1245 1246 auto state = [&]() { 1247 REQUIRE(timeline->checkConsistency()); 1248 REQUIRE(timeline->getTrackClipsCount(tid1) == 1); 1249 REQUIRE(timeline->getTrackClipsCount(tid2) == 1); 1250 REQUIRE(timeline->getTrackClipsCount(tid1b) == 0); 1251 REQUIRE(timeline->getTrackClipsCount(tid2b) == 0); 1252 REQUIRE(timeline->getClipTrackId(cid1) == tid1); 1253 REQUIRE(timeline->getClipTrackId(cid2) == tid2); 1254 REQUIRE(timeline->getClipPosition(cid1) == 3); 1255 REQUIRE(timeline->getClipPosition(cid2) == 3); 1256 REQUIRE(timeline->getClipPtr(cid1)->clipState() == PlaylistState::VideoOnly); 1257 REQUIRE(timeline->getClipPtr(cid2)->clipState() == PlaylistState::AudioOnly); 1258 // we check that the av group was correctly created 1259 REQUIRE(timeline->getGroupElements(cid1) == std::unordered_set<int>({cid1, cid2})); 1260 int g1 = timeline->m_groups->getDirectAncestor(cid1); 1261 REQUIRE(timeline->m_groups->getDirectChildren(g1) == std::unordered_set<int>({cid1, cid2})); 1262 REQUIRE(timeline->m_groups->getType(g1) == GroupType::AVSplit); 1263 }; 1264 state(); 1265 1266 QString cpy_str = TimelineFunctions::copyClips(timeline, {cid1}); 1267 1268 // we delete origin of the copy, paste should still be possible 1269 REQUIRE(timeline->requestItemDeletion(cid1)); 1270 state0(); 1271 1272 REQUIRE(TimelineFunctions::pasteClips(timeline, cpy_str, tid1, 0)); 1273 int cid3 = timeline->getTrackById(tid1)->getClipByPosition(0); 1274 REQUIRE(cid3 != -1); 1275 int cid4 = timeline->m_groups->getSplitPartner(cid3); 1276 auto state2 = [&](int audio) { 1277 REQUIRE(timeline->checkConsistency()); 1278 REQUIRE(timeline->getTrackClipsCount(tid1) == 1); 1279 REQUIRE(timeline->getTrackClipsCount(audio) == 1); 1280 REQUIRE(timeline->getTrackClipsCount(tid1b) == 0); 1281 REQUIRE(timeline->getClipTrackId(cid3) == tid1); 1282 REQUIRE(timeline->getClipTrackId(cid4) == audio); 1283 REQUIRE(timeline->getClipPosition(cid3) == 0); 1284 REQUIRE(timeline->getClipPosition(cid4) == 0); 1285 REQUIRE(timeline->getClipPtr(cid3)->clipState() == PlaylistState::VideoOnly); 1286 REQUIRE(timeline->getClipPtr(cid4)->clipState() == PlaylistState::AudioOnly); 1287 // we check that the av group was correctly created 1288 REQUIRE(timeline->getGroupElements(cid3) == std::unordered_set<int>({cid3, cid4})); 1289 int g1 = timeline->m_groups->getDirectAncestor(cid3); 1290 REQUIRE(timeline->m_groups->getDirectChildren(g1) == std::unordered_set<int>({cid3, cid4})); 1291 REQUIRE(timeline->m_groups->getType(g1) == GroupType::AVSplit); 1292 }; 1293 state2(tid2); 1294 1295 undoStack->undo(); 1296 state0(); 1297 undoStack->redo(); 1298 state2(tid2); 1299 undoStack->undo(); 1300 state0(); 1301 1302 // now, we remove all audio tracks, making paste impossible 1303 REQUIRE(timeline->requestTrackDeletion(tid2)); 1304 REQUIRE(timeline->requestTrackDeletion(tid2b)); 1305 REQUIRE_FALSE(TimelineFunctions::pasteClips(timeline, cpy_str, tid1, 0)); 1306 1307 // undo one deletion 1308 undoStack->undo(); 1309 // now, tid2b should be a valid audio track 1310 REQUIRE(TimelineFunctions::pasteClips(timeline, cpy_str, tid1, 0)); 1311 cid3 = timeline->getTrackById(tid1)->getClipByPosition(0); 1312 REQUIRE(cid3 != -1); 1313 cid4 = timeline->m_groups->getSplitPartner(cid3); 1314 state2(tid2b); 1315 } 1316 pCore->projectManager()->closeCurrentDocument(false, false); 1317 } 1318 1319 TEST_CASE("Advanced trimming operations: Slip", "[TrimmingSlip]") 1320 { 1321 auto binModel = pCore->projectItemModel(); 1322 binModel->clean(); 1323 std::shared_ptr<DocUndoStack> undoStack = std::make_shared<DocUndoStack>(nullptr); 1324 1325 // Here we do some trickery to enable testing. 1326 KdenliveDoc document(undoStack, {0, 2}); 1327 pCore->projectManager()->m_project = &document; 1328 QDateTime documentDate = QDateTime::currentDateTime(); 1329 pCore->projectManager()->updateTimeline(false, QString(), QString(), documentDate, 0); 1330 auto timeline = document.getTimeline(document.uuid()); 1331 pCore->projectManager()->m_activeTimelineModel = timeline; 1332 pCore->projectManager()->testSetActiveDocument(&document, timeline); 1333 1334 QString binId = createProducer(pCore->getProjectProfile(), "red", binModel); 1335 QString binId2 = createProducer(pCore->getProjectProfile(), "blue", binModel); 1336 1337 int tid1 = timeline->getTrackIndexFromPosition(0); 1338 int tid2 = timeline->getTrackIndexFromPosition(1); 1339 1340 int cid1 = ClipModel::construct(timeline, binId, -1, PlaylistState::VideoOnly); 1341 int cid2 = ClipModel::construct(timeline, binId2, -1, PlaylistState::VideoOnly); 1342 int cid3 = ClipModel::construct(timeline, binId, -1, PlaylistState::VideoOnly); 1343 int cid4 = ClipModel::construct(timeline, binId, -1, PlaylistState::VideoOnly); 1344 int cid5 = ClipModel::construct(timeline, binId, -1, PlaylistState::VideoOnly); 1345 1346 timeline->m_allClips[cid1]->m_endlessResize = false; 1347 timeline->m_allClips[cid2]->m_endlessResize = false; 1348 timeline->m_allClips[cid3]->m_endlessResize = false; 1349 timeline->m_allClips[cid4]->m_endlessResize = false; 1350 timeline->m_allClips[cid5]->m_endlessResize = false; 1351 1352 // sliping a fullsized clips should not to anything 1353 SECTION("Slip single fullsized clip") 1354 { 1355 REQUIRE(timeline->requestClipMove(cid1, tid1, 5)); 1356 int l = timeline->getClipPlaytime(cid1); 1357 auto state = [&]() { 1358 REQUIRE(timeline->checkConsistency()); 1359 REQUIRE(timeline->getClipPlaytime(cid1) == l); 1360 REQUIRE(timeline->getClipPosition(cid1) == 5); 1361 REQUIRE(timeline->getClipPtr(cid1)->getIn() == 0); 1362 REQUIRE(timeline->getClipPtr(cid1)->getOut() == l - 1); 1363 }; 1364 state(); 1365 1366 REQUIRE(timeline->requestClipSlip(cid1, 3) == 3); 1367 state(); 1368 1369 REQUIRE(timeline->requestClipSlip(cid1, -3) == -3); 1370 state(); 1371 1372 undoStack->undo(); 1373 state(); 1374 undoStack->undo(); 1375 state(); 1376 1377 undoStack->redo(); 1378 state(); 1379 undoStack->redo(); 1380 state(); 1381 } 1382 1383 // slipping a downsized clip should only change the in and out point 1384 SECTION("Slip single cutted clip") 1385 { 1386 REQUIRE(timeline->requestClipMove(cid1, tid1, 5)); 1387 int l = timeline->getClipPlaytime(cid1); 1388 REQUIRE(timeline->requestItemResize(cid1, l - 5, true) == l - 5); 1389 REQUIRE(timeline->requestItemResize(cid1, l - 11, false) == l - 11); 1390 1391 auto state = [&]() { 1392 REQUIRE(timeline->checkConsistency()); 1393 REQUIRE(timeline->getClipPlaytime(cid1) == l - 11); 1394 REQUIRE(timeline->getClipPosition(cid1) == 5 + 6); 1395 REQUIRE(timeline->getClipPtr(cid1)->getIn() == 6); 1396 REQUIRE(timeline->getClipPtr(cid1)->getOut() == l - 6); 1397 }; 1398 state(); 1399 1400 REQUIRE(timeline->requestClipSlip(cid1, 3) == 3); 1401 auto state2 = [&]() { 1402 REQUIRE(timeline->checkConsistency()); 1403 REQUIRE(timeline->getClipPlaytime(cid1) == l - 11); 1404 REQUIRE(timeline->getClipPosition(cid1) == 5 + 6); 1405 REQUIRE(timeline->getClipPtr(cid1)->getIn() == 3); 1406 REQUIRE(timeline->getClipPtr(cid1)->getOut() == l - 9); 1407 }; 1408 state2(); 1409 1410 REQUIRE(timeline->requestClipSlip(cid1, -3) == -3); 1411 state(); 1412 1413 undoStack->undo(); 1414 state2(); 1415 undoStack->undo(); 1416 state(); 1417 1418 undoStack->redo(); 1419 state2(); 1420 undoStack->redo(); 1421 state(); 1422 } 1423 1424 // if offset is bigger than the borders use the biggest possible offset without going beyond the borders 1425 SECTION("Slip beyond borders") 1426 { 1427 REQUIRE(timeline->requestClipMove(cid1, tid1, 5)); 1428 int l = timeline->getClipPlaytime(cid1); 1429 1430 REQUIRE(timeline->getClipPlaytime(cid1) == l); 1431 REQUIRE(timeline->requestItemResize(cid1, l - 5, true) == l - 5); 1432 REQUIRE(timeline->requestItemResize(cid1, l - 11, false) == l - 11); 1433 REQUIRE(timeline->getClipPtr(cid1)->getOut() == l - 6); 1434 1435 auto state = [&]() { 1436 REQUIRE(timeline->checkConsistency()); 1437 REQUIRE(timeline->getClipPlaytime(cid1) == l - 11); 1438 REQUIRE(timeline->getClipPosition(cid1) == 5 + 6); 1439 REQUIRE(timeline->getClipPtr(cid1)->getIn() == 6); 1440 REQUIRE(timeline->getClipPtr(cid1)->getOut() == l - 6); 1441 }; 1442 state(); 1443 1444 // left border 1445 REQUIRE(timeline->requestClipSlip(cid1, 30) == 30); 1446 auto state2 = [&]() { 1447 REQUIRE(timeline->checkConsistency()); 1448 REQUIRE(timeline->getClipPlaytime(cid1) == l - 11); 1449 REQUIRE(timeline->getClipPosition(cid1) == 5 + 6); 1450 REQUIRE(timeline->getClipPtr(cid1)->getIn() == 0); 1451 REQUIRE(timeline->getClipPtr(cid1)->getOut() == l - 12); 1452 }; 1453 state2(); 1454 1455 // right border 1456 REQUIRE(timeline->requestClipSlip(cid1, -30) == -30); 1457 auto state3 = [&]() { 1458 REQUIRE(timeline->checkConsistency()); 1459 REQUIRE(timeline->getClipPlaytime(cid1) == l - 11); 1460 REQUIRE(timeline->getClipPosition(cid1) == 5 + 6); 1461 REQUIRE(timeline->getClipPtr(cid1)->getIn() == 11); 1462 REQUIRE(timeline->getClipPtr(cid1)->getOut() == l - 1); 1463 }; 1464 state3(); 1465 1466 undoStack->undo(); 1467 state2(); 1468 undoStack->undo(); 1469 state(); 1470 1471 undoStack->redo(); 1472 state2(); 1473 undoStack->redo(); 1474 state3(); 1475 } 1476 1477 // slipping one clip of a group should slip all members 1478 SECTION("Slip group") 1479 { 1480 REQUIRE(timeline->requestClipMove(cid1, tid1, 5)); 1481 int l1 = timeline->getClipPlaytime(cid1); 1482 REQUIRE(timeline->requestItemResize(cid1, l1 - 5, true) == l1 - 5); 1483 REQUIRE(timeline->requestItemResize(cid1, l1 - 11, false) == l1 - 11); 1484 1485 REQUIRE(timeline->requestClipMove(cid2, tid1, 50)); 1486 int l2 = timeline->getClipPlaytime(cid2); 1487 REQUIRE(timeline->requestItemResize(cid2, l2 - 11, false) == l2 - 11); 1488 1489 REQUIRE(timeline->requestClipMove(cid3, tid2, 25)); 1490 int l3 = timeline->getClipPlaytime(cid3); 1491 REQUIRE(timeline->requestItemResize(cid3, l3 - 5, true) == l3 - 5); 1492 1493 REQUIRE(timeline->requestClipMove(cid4, tid2, 0)); 1494 int l4 = timeline->getClipPlaytime(cid4); 1495 REQUIRE(timeline->requestItemResize(cid4, l4 - 9, true) == l4 - 9); 1496 REQUIRE(timeline->requestItemResize(cid4, l4 - 17, false) == l4 - 17); 1497 1498 REQUIRE(timeline->requestClipMove(cid5, tid2, 60)); 1499 int l5 = timeline->getClipPlaytime(cid5); 1500 int gid1 = timeline->requestClipsGroup(std::unordered_set<int>({cid1, cid2, cid3, cid4, cid5}), true, GroupType::Normal); 1501 REQUIRE(gid1 > -1); 1502 1503 auto state = [&]() { 1504 REQUIRE(timeline->checkConsistency()); 1505 REQUIRE(timeline->getClipPlaytime(cid1) == l1 - 11); 1506 REQUIRE(timeline->getClipPosition(cid1) == 5 + 6); 1507 REQUIRE(timeline->getClipPtr(cid1)->getIn() == 6); 1508 REQUIRE(timeline->getClipPtr(cid1)->getOut() == l1 - 6); 1509 REQUIRE(timeline->getClipTrackId(cid1) == tid1); 1510 1511 REQUIRE(timeline->getClipPlaytime(cid2) == l2 - 11); 1512 REQUIRE(timeline->getClipPosition(cid2) == 50 + 11); 1513 REQUIRE(timeline->getClipPtr(cid2)->getIn() == 11); 1514 REQUIRE(timeline->getClipPtr(cid2)->getOut() == l2 - 1); 1515 REQUIRE(timeline->getClipTrackId(cid2) == tid1); 1516 1517 REQUIRE(timeline->getClipPlaytime(cid3) == l3 - 5); 1518 REQUIRE(timeline->getClipPosition(cid3) == 25); 1519 REQUIRE(timeline->getClipPtr(cid3)->getIn() == 0); 1520 REQUIRE(timeline->getClipPtr(cid3)->getOut() == l3 - 6); 1521 REQUIRE(timeline->getClipTrackId(cid3) == tid2); 1522 1523 REQUIRE(timeline->getClipPlaytime(cid4) == l4 - 17); 1524 REQUIRE(timeline->getClipPosition(cid4) == 8); 1525 REQUIRE(timeline->getClipPtr(cid4)->getIn() == 8); 1526 REQUIRE(timeline->getClipPtr(cid4)->getOut() == l4 - 10); 1527 REQUIRE(timeline->getClipTrackId(cid4) == tid2); 1528 1529 REQUIRE(timeline->getClipPlaytime(cid5) == l5); 1530 REQUIRE(timeline->getClipPosition(cid5) == 60); 1531 REQUIRE(timeline->getClipPtr(cid5)->getIn() == 0); 1532 REQUIRE(timeline->getClipPtr(cid5)->getOut() == l5 - 1); 1533 REQUIRE(timeline->getClipTrackId(cid5) == tid2); 1534 1535 REQUIRE(timeline->m_groups->getLeaves(gid1) == std::unordered_set<int>({cid1, cid2, cid3, cid4, cid5})); 1536 }; 1537 state(); 1538 1539 REQUIRE(timeline->requestClipSlip(cid1, 3) == 3); 1540 1541 auto state2 = [&]() { 1542 REQUIRE(timeline->checkConsistency()); 1543 REQUIRE(timeline->getClipPlaytime(cid1) == l1 - 11); 1544 REQUIRE(timeline->getClipPosition(cid1) == 5 + 6); 1545 REQUIRE(timeline->getClipPtr(cid1)->getIn() == 3); 1546 REQUIRE(timeline->getClipPtr(cid1)->getOut() == l1 - 9); 1547 REQUIRE(timeline->getClipTrackId(cid1) == tid1); 1548 1549 REQUIRE(timeline->getClipPlaytime(cid2) == l2 - 11); 1550 REQUIRE(timeline->getClipPosition(cid2) == 50 + 11); 1551 REQUIRE(timeline->getClipPtr(cid2)->getIn() == 8); 1552 REQUIRE(timeline->getClipPtr(cid2)->getOut() == l2 - 4); 1553 REQUIRE(timeline->getClipTrackId(cid2) == tid1); 1554 1555 REQUIRE(timeline->getClipPlaytime(cid3) == l3 - 5); 1556 REQUIRE(timeline->getClipPosition(cid3) == 25); 1557 REQUIRE(timeline->getClipPtr(cid3)->getIn() == 0); 1558 REQUIRE(timeline->getClipPtr(cid3)->getOut() == l3 - 6); 1559 REQUIRE(timeline->getClipTrackId(cid3) == tid2); 1560 1561 REQUIRE(timeline->getClipPlaytime(cid4) == l4 - 17); 1562 REQUIRE(timeline->getClipPosition(cid4) == 8); 1563 REQUIRE(timeline->getClipPtr(cid4)->getIn() == 5); 1564 REQUIRE(timeline->getClipPtr(cid4)->getOut() == l4 - 13); 1565 REQUIRE(timeline->getClipTrackId(cid4) == tid2); 1566 1567 REQUIRE(timeline->getClipPlaytime(cid5) == l5); 1568 REQUIRE(timeline->getClipPosition(cid5) == 60); 1569 REQUIRE(timeline->getClipPtr(cid5)->getIn() == 0); 1570 REQUIRE(timeline->getClipPtr(cid5)->getOut() == l5 - 1); 1571 REQUIRE(timeline->getClipTrackId(cid5) == tid2); 1572 1573 REQUIRE(timeline->m_groups->getLeaves(gid1) == std::unordered_set<int>({cid1, cid2, cid3, cid4, cid5})); 1574 }; 1575 state2(); 1576 1577 REQUIRE(timeline->requestClipSlip(cid4, 30) == 30); 1578 1579 auto state3 = [&]() { 1580 REQUIRE(timeline->checkConsistency()); 1581 REQUIRE(timeline->getClipPlaytime(cid1) == l1 - 11); 1582 REQUIRE(timeline->getClipPosition(cid1) == 5 + 6); 1583 REQUIRE(timeline->getClipPtr(cid1)->getIn() == 0); 1584 REQUIRE(timeline->getClipPtr(cid1)->getOut() == l1 - 12); 1585 REQUIRE(timeline->getClipTrackId(cid1) == tid1); 1586 1587 REQUIRE(timeline->getClipPlaytime(cid2) == l2 - 11); 1588 REQUIRE(timeline->getClipPosition(cid2) == 50 + 11); 1589 REQUIRE(timeline->getClipPtr(cid2)->getIn() == 0); 1590 REQUIRE(timeline->getClipPtr(cid2)->getOut() == l2 - 12); 1591 REQUIRE(timeline->getClipTrackId(cid2) == tid1); 1592 1593 REQUIRE(timeline->getClipPlaytime(cid3) == l3 - 5); 1594 REQUIRE(timeline->getClipPosition(cid3) == 25); 1595 REQUIRE(timeline->getClipPtr(cid3)->getIn() == 0); 1596 REQUIRE(timeline->getClipPtr(cid3)->getOut() == l3 - 6); 1597 REQUIRE(timeline->getClipTrackId(cid3) == tid2); 1598 1599 REQUIRE(timeline->getClipPlaytime(cid4) == l4 - 17); 1600 REQUIRE(timeline->getClipPosition(cid4) == 8); 1601 REQUIRE(timeline->getClipPtr(cid4)->getIn() == 0); 1602 REQUIRE(timeline->getClipPtr(cid4)->getOut() == l4 - 18); 1603 REQUIRE(timeline->getClipTrackId(cid4) == tid2); 1604 1605 REQUIRE(timeline->getClipPlaytime(cid5) == l5); 1606 REQUIRE(timeline->getClipPosition(cid5) == 60); 1607 REQUIRE(timeline->getClipPtr(cid5)->getIn() == 0); 1608 REQUIRE(timeline->getClipPtr(cid5)->getOut() == l5 - 1); 1609 REQUIRE(timeline->getClipTrackId(cid5) == tid2); 1610 1611 REQUIRE(timeline->m_groups->getLeaves(gid1) == std::unordered_set<int>({cid1, cid2, cid3, cid4, cid5})); 1612 }; 1613 state3(); 1614 1615 undoStack->undo(); 1616 state2(); 1617 undoStack->undo(); 1618 state(); 1619 1620 undoStack->redo(); 1621 state2(); 1622 undoStack->redo(); 1623 state3(); 1624 } 1625 1626 pCore->projectManager()->closeCurrentDocument(false, false); 1627 } 1628 1629 TEST_CASE("Advanced trimming operations: Ripple", "[TrimmingRipple]") 1630 { 1631 auto binModel = pCore->projectItemModel(); 1632 binModel->clean(); 1633 std::shared_ptr<DocUndoStack> undoStack = std::make_shared<DocUndoStack>(nullptr); 1634 1635 // Here we do some trickery to enable testing. 1636 KdenliveDoc document(undoStack, {0, 2}); 1637 pCore->projectManager()->m_project = &document; 1638 QDateTime documentDate = QDateTime::currentDateTime(); 1639 pCore->projectManager()->updateTimeline(false, QString(), QString(), documentDate, 0); 1640 auto timeline = document.getTimeline(document.uuid()); 1641 pCore->projectManager()->m_activeTimelineModel = timeline; 1642 pCore->projectManager()->testSetActiveDocument(&document, timeline); 1643 1644 QString binId = createProducer(pCore->getProjectProfile(), "red", binModel); 1645 QString binId2 = createProducer(pCore->getProjectProfile(), "blue", binModel); 1646 1647 int tid1 = timeline->getTrackIndexFromPosition(0); 1648 int tid2 = timeline->getTrackIndexFromPosition(1); 1649 1650 int cid1 = ClipModel::construct(timeline, binId, -1, PlaylistState::VideoOnly); 1651 int cid2 = ClipModel::construct(timeline, binId2, -1, PlaylistState::VideoOnly); 1652 int cid3 = ClipModel::construct(timeline, binId, -1, PlaylistState::VideoOnly); 1653 int cid4 = ClipModel::construct(timeline, binId, -1, PlaylistState::VideoOnly); 1654 int cid5 = ClipModel::construct(timeline, binId, -1, PlaylistState::VideoOnly); 1655 int cid6 = ClipModel::construct(timeline, binId, -1, PlaylistState::VideoOnly); 1656 1657 timeline->m_allClips[cid1]->m_endlessResize = false; 1658 timeline->m_allClips[cid2]->m_endlessResize = false; 1659 timeline->m_allClips[cid3]->m_endlessResize = false; 1660 timeline->m_allClips[cid4]->m_endlessResize = false; 1661 timeline->m_allClips[cid5]->m_endlessResize = false; 1662 1663 // ripple resize a fullsized clip longer should not to anything 1664 SECTION("Ripple resize single fullsized clip (longer)") 1665 { 1666 REQUIRE(timeline->requestClipMove(cid1, tid1, 5)); 1667 int l1 = timeline->getClipPlaytime(cid1); 1668 1669 REQUIRE(timeline->requestClipMove(cid2, tid1, 50)); 1670 int l2 = timeline->getClipPlaytime(cid2); 1671 1672 REQUIRE(timeline->requestClipMove(cid3, tid1, 80)); 1673 int l3 = timeline->getClipPlaytime(cid3); 1674 1675 auto state = [&]() { 1676 REQUIRE(timeline->checkConsistency()); 1677 REQUIRE(timeline->getClipPlaytime(cid1) == l1); 1678 REQUIRE(timeline->getClipPosition(cid1) == 5); 1679 REQUIRE(timeline->getClipPtr(cid1)->getIn() == 0); 1680 REQUIRE(timeline->getClipPtr(cid1)->getOut() == l1 - 1); 1681 REQUIRE(timeline->getClipPlaytime(cid2) == l2); 1682 REQUIRE(timeline->getClipPosition(cid2) == 50); 1683 REQUIRE(timeline->getClipPtr(cid2)->getIn() == 0); 1684 REQUIRE(timeline->getClipPtr(cid2)->getOut() == l2 - 1); 1685 REQUIRE(timeline->getClipPlaytime(cid3) == l3); 1686 REQUIRE(timeline->getClipPosition(cid3) == 80); 1687 REQUIRE(timeline->getClipPtr(cid3)->getIn() == 0); 1688 REQUIRE(timeline->getClipPtr(cid3)->getOut() == l3 - 1); 1689 }; 1690 state(); 1691 1692 REQUIRE(timeline->requestItemRippleResize(timeline, cid1, l1 + 5, true)); 1693 state(); 1694 1695 REQUIRE(timeline->requestItemRippleResize(timeline, cid1, l1 + 5, false)); 1696 state(); 1697 1698 REQUIRE(timeline->requestItemRippleResize(timeline, cid2, l2 + 5, true)); 1699 REQUIRE(timeline->requestItemRippleResize(timeline, cid1, l2 + 5, false)); 1700 state(); 1701 1702 REQUIRE(timeline->requestItemRippleResize(timeline, cid3, l3 + 5, true)); 1703 REQUIRE(timeline->requestItemRippleResize(timeline, cid3, l3 + 5, false)); 1704 state(); 1705 1706 undoStack->undo(); 1707 state(); 1708 undoStack->undo(); 1709 state(); 1710 1711 undoStack->redo(); 1712 state(); 1713 undoStack->redo(); 1714 state(); 1715 } 1716 1717 // ripple resize a fullsized clip shorter should resize the clip and move following clips 1718 SECTION("Ripple resize single fullsized clip (shorter)") 1719 { 1720 REQUIRE(timeline->requestClipMove(cid1, tid1, 5)); 1721 int l1 = timeline->getClipPlaytime(cid1); 1722 1723 REQUIRE(timeline->requestClipMove(cid2, tid1, 50)); 1724 int l2 = timeline->getClipPlaytime(cid2); 1725 1726 REQUIRE(timeline->requestClipMove(cid3, tid1, 80)); 1727 int l3 = timeline->getClipPlaytime(cid3); 1728 1729 auto stateA1 = [&]() { 1730 REQUIRE(timeline->checkConsistency()); 1731 REQUIRE(timeline->getClipPlaytime(cid1) == l1); 1732 REQUIRE(timeline->getClipPosition(cid1) == 5); 1733 REQUIRE(timeline->getClipPtr(cid1)->getIn() == 0); 1734 REQUIRE(timeline->getClipPtr(cid1)->getOut() == l1 - 1); 1735 }; 1736 auto stateA2 = [&]() { 1737 REQUIRE(timeline->checkConsistency()); 1738 REQUIRE(timeline->getClipPlaytime(cid2) == l2); 1739 REQUIRE(timeline->getClipPosition(cid2) == 50); 1740 REQUIRE(timeline->getClipPtr(cid2)->getIn() == 0); 1741 REQUIRE(timeline->getClipPtr(cid2)->getOut() == l2 - 1); 1742 1743 REQUIRE(timeline->checkConsistency()); 1744 REQUIRE(timeline->getClipPlaytime(cid3) == l3); 1745 REQUIRE(timeline->getClipPosition(cid3) == 80); 1746 REQUIRE(timeline->getClipPtr(cid3)->getIn() == 0); 1747 REQUIRE(timeline->getClipPtr(cid3)->getOut() == l3 - 1); 1748 }; 1749 stateA1(); 1750 stateA2(); 1751 1752 auto stateB = [&]() { 1753 REQUIRE(timeline->checkConsistency()); 1754 REQUIRE(timeline->getClipPlaytime(cid2) == l2 - 5); 1755 REQUIRE(timeline->getClipPosition(cid2) == 50); 1756 REQUIRE(timeline->getClipPtr(cid2)->getIn() == 0); 1757 REQUIRE(timeline->getClipPtr(cid2)->getOut() == l2 - 6); 1758 1759 REQUIRE(timeline->getClipPlaytime(cid3) == l3); 1760 REQUIRE(timeline->getClipPosition(cid3) == 75); 1761 REQUIRE(timeline->getClipPtr(cid3)->getIn() == 0); 1762 REQUIRE(timeline->getClipPtr(cid3)->getOut() == l3 - 1); 1763 }; 1764 REQUIRE(timeline->requestItemRippleResize(timeline, cid2, l2 - 5, true) == l2 - 5); 1765 stateA1(); 1766 stateB(); 1767 1768 auto stateC = [&]() { 1769 REQUIRE(timeline->checkConsistency()); 1770 REQUIRE(timeline->getClipPlaytime(cid2) == l2 - 8); 1771 REQUIRE(timeline->getClipPosition(cid2) == 50); 1772 REQUIRE(timeline->getClipPtr(cid2)->getIn() == 3); 1773 REQUIRE(timeline->getClipPtr(cid2)->getOut() == l2 - 6); 1774 1775 REQUIRE(timeline->getClipPlaytime(cid3) == l3); 1776 REQUIRE(timeline->getClipPosition(cid3) == 72); 1777 REQUIRE(timeline->getClipPtr(cid3)->getIn() == 0); 1778 REQUIRE(timeline->getClipPtr(cid3)->getOut() == l3 - 1); 1779 }; 1780 1781 REQUIRE(timeline->requestItemRippleResize(timeline, cid2, l2 - 8, false)); 1782 stateA1(); 1783 stateC(); 1784 1785 undoStack->undo(); 1786 stateA1(); 1787 stateB(); 1788 1789 undoStack->undo(); 1790 stateA1(); 1791 stateA2(); 1792 1793 undoStack->redo(); 1794 stateA1(); 1795 stateB(); 1796 1797 undoStack->redo(); 1798 stateA1(); 1799 stateC(); 1800 } 1801 1802 // ripple resize a grouped clip should move the affect all group partners on other tracks with same position as well 1803 SECTION("Ripple resize fullsized multitrack group (shorter)") 1804 { 1805 REQUIRE(timeline->requestClipMove(cid1, tid1, 5)); 1806 int l1 = timeline->getClipPlaytime(cid1); 1807 1808 REQUIRE(timeline->requestClipMove(cid2, tid1, 50)); 1809 int l2 = timeline->getClipPlaytime(cid2); 1810 1811 REQUIRE(timeline->requestClipMove(cid3, tid1, 80)); 1812 int l3 = timeline->getClipPlaytime(cid3); 1813 1814 REQUIRE(timeline->requestClipMove(cid4, tid2, 5)); 1815 int l4 = timeline->getClipPlaytime(cid4); 1816 REQUIRE(l4 == l1); 1817 timeline->requestClipsGroup(std::unordered_set<int>({cid1, cid4}), true, GroupType::Normal); 1818 1819 REQUIRE(timeline->requestClipMove(cid5, tid2, 50)); 1820 int l5 = timeline->getClipPlaytime(cid5); 1821 REQUIRE(l5 == l2); 1822 timeline->requestClipsGroup(std::unordered_set<int>({cid2, cid5}), true, GroupType::Normal); 1823 1824 REQUIRE(timeline->requestClipMove(cid6, tid2, 80)); 1825 int l6 = timeline->getClipPlaytime(cid6); 1826 REQUIRE(l6 == l3); 1827 timeline->requestClipsGroup(std::unordered_set<int>({cid3, cid6}), true, GroupType::Normal); 1828 1829 auto stateA1 = [&]() { 1830 REQUIRE(timeline->checkConsistency()); 1831 REQUIRE(timeline->getClipPlaytime(cid1) == l1); 1832 REQUIRE(timeline->getClipPosition(cid1) == 5); 1833 REQUIRE(timeline->getClipPtr(cid1)->getIn() == 0); 1834 REQUIRE(timeline->getClipPtr(cid1)->getOut() == l1 - 1); 1835 1836 REQUIRE(timeline->checkConsistency()); 1837 REQUIRE(timeline->getClipPlaytime(cid4) == timeline->getClipPlaytime(cid1)); 1838 REQUIRE(timeline->getClipPosition(cid4) == timeline->getClipPosition(cid1)); 1839 REQUIRE(timeline->getClipPtr(cid4)->getIn() == timeline->getClipPtr(cid1)->getIn()); 1840 REQUIRE(timeline->getClipPtr(cid4)->getOut() == timeline->getClipPtr(cid1)->getOut()); 1841 }; 1842 auto stateA2 = [&]() { 1843 REQUIRE(timeline->checkConsistency()); 1844 REQUIRE(timeline->getClipPlaytime(cid2) == l2); 1845 REQUIRE(timeline->getClipPosition(cid2) == 50); 1846 REQUIRE(timeline->getClipPtr(cid2)->getIn() == 0); 1847 REQUIRE(timeline->getClipPtr(cid2)->getOut() == l2 - 1); 1848 1849 REQUIRE(timeline->checkConsistency()); 1850 REQUIRE(timeline->getClipPlaytime(cid3) == l3); 1851 REQUIRE(timeline->getClipPosition(cid3) == 80); 1852 REQUIRE(timeline->getClipPtr(cid3)->getIn() == 0); 1853 REQUIRE(timeline->getClipPtr(cid3)->getOut() == l3 - 1); 1854 1855 REQUIRE(timeline->checkConsistency()); 1856 REQUIRE(timeline->getClipPlaytime(cid5) == timeline->getClipPlaytime(cid2)); 1857 REQUIRE(timeline->getClipPosition(cid5) == timeline->getClipPosition(cid2)); 1858 REQUIRE(timeline->getClipPtr(cid5)->getIn() == timeline->getClipPtr(cid2)->getIn()); 1859 REQUIRE(timeline->getClipPtr(cid5)->getOut() == timeline->getClipPtr(cid2)->getOut()); 1860 1861 REQUIRE(timeline->checkConsistency()); 1862 REQUIRE(timeline->getClipPlaytime(cid6) == timeline->getClipPlaytime(cid3)); 1863 REQUIRE(timeline->getClipPosition(cid6) == timeline->getClipPosition(cid3)); 1864 REQUIRE(timeline->getClipPtr(cid6)->getIn() == timeline->getClipPtr(cid3)->getIn()); 1865 REQUIRE(timeline->getClipPtr(cid6)->getOut() == timeline->getClipPtr(cid3)->getOut()); 1866 }; 1867 stateA1(); 1868 stateA2(); 1869 1870 auto stateB = [&]() { 1871 REQUIRE(timeline->checkConsistency()); 1872 REQUIRE(timeline->getClipPlaytime(cid2) == l2 - 5); 1873 REQUIRE(timeline->getClipPosition(cid2) == 50); 1874 REQUIRE(timeline->getClipPtr(cid2)->getIn() == 0); 1875 REQUIRE(timeline->getClipPtr(cid2)->getOut() == l2 - 6); 1876 1877 REQUIRE(timeline->getClipPlaytime(cid3) == l3); 1878 REQUIRE(timeline->getClipPosition(cid3) == 75); 1879 REQUIRE(timeline->getClipPtr(cid3)->getIn() == 0); 1880 REQUIRE(timeline->getClipPtr(cid3)->getOut() == l3 - 1); 1881 1882 REQUIRE(timeline->checkConsistency()); 1883 REQUIRE(timeline->getClipPlaytime(cid5) == timeline->getClipPlaytime(cid2)); 1884 REQUIRE(timeline->getClipPosition(cid5) == timeline->getClipPosition(cid2)); 1885 REQUIRE(timeline->getClipPtr(cid5)->getIn() == timeline->getClipPtr(cid2)->getIn()); 1886 REQUIRE(timeline->getClipPtr(cid5)->getOut() == timeline->getClipPtr(cid2)->getOut()); 1887 1888 REQUIRE(timeline->checkConsistency()); 1889 REQUIRE(timeline->getClipPlaytime(cid6) == timeline->getClipPlaytime(cid3)); 1890 REQUIRE(timeline->getClipPosition(cid6) == timeline->getClipPosition(cid3)); 1891 REQUIRE(timeline->getClipPtr(cid6)->getIn() == timeline->getClipPtr(cid3)->getIn()); 1892 REQUIRE(timeline->getClipPtr(cid6)->getOut() == timeline->getClipPtr(cid3)->getOut()); 1893 }; 1894 REQUIRE(timeline->requestItemRippleResize(timeline, cid2, l2 - 5, true) == l2 - 5); 1895 stateA1(); 1896 stateB(); 1897 1898 auto stateC = [&]() { 1899 REQUIRE(timeline->checkConsistency()); 1900 REQUIRE(timeline->getClipPlaytime(cid2) == l2 - 8); 1901 REQUIRE(timeline->getClipPosition(cid2) == 50); 1902 REQUIRE(timeline->getClipPtr(cid2)->getIn() == 3); 1903 REQUIRE(timeline->getClipPtr(cid2)->getOut() == l2 - 6); 1904 1905 REQUIRE(timeline->getClipPlaytime(cid3) == l3); 1906 REQUIRE(timeline->getClipPosition(cid3) == 72); 1907 REQUIRE(timeline->getClipPtr(cid3)->getIn() == 0); 1908 REQUIRE(timeline->getClipPtr(cid3)->getOut() == l3 - 1); 1909 1910 REQUIRE(timeline->checkConsistency()); 1911 REQUIRE(timeline->getClipPlaytime(cid5) == timeline->getClipPlaytime(cid2)); 1912 REQUIRE(timeline->getClipPosition(cid5) == timeline->getClipPosition(cid2)); 1913 REQUIRE(timeline->getClipPtr(cid5)->getIn() == timeline->getClipPtr(cid2)->getIn()); 1914 REQUIRE(timeline->getClipPtr(cid5)->getOut() == timeline->getClipPtr(cid2)->getOut()); 1915 1916 REQUIRE(timeline->checkConsistency()); 1917 REQUIRE(timeline->getClipPlaytime(cid6) == timeline->getClipPlaytime(cid3)); 1918 REQUIRE(timeline->getClipPosition(cid6) == timeline->getClipPosition(cid3)); 1919 REQUIRE(timeline->getClipPtr(cid6)->getIn() == timeline->getClipPtr(cid3)->getIn()); 1920 REQUIRE(timeline->getClipPtr(cid6)->getOut() == timeline->getClipPtr(cid3)->getOut()); 1921 }; 1922 1923 REQUIRE(timeline->requestItemRippleResize(timeline, cid2, l2 - 8, false)); 1924 stateA1(); 1925 stateC(); 1926 1927 undoStack->undo(); 1928 stateA1(); 1929 stateB(); 1930 1931 undoStack->undo(); 1932 stateA1(); 1933 stateA2(); 1934 1935 undoStack->redo(); 1936 stateA1(); 1937 stateB(); 1938 1939 undoStack->redo(); 1940 stateA1(); 1941 stateC(); 1942 } 1943 1944 SECTION("Ripple resize fullsized single track group (shorter)") 1945 { 1946 REQUIRE(timeline->requestClipMove(cid1, tid1, 5)); 1947 int l1 = timeline->getClipPlaytime(cid1); 1948 1949 REQUIRE(timeline->requestClipMove(cid2, tid1, 50)); 1950 int l2 = timeline->getClipPlaytime(cid2); 1951 1952 REQUIRE(timeline->requestClipMove(cid3, tid1, 80)); 1953 int l3 = timeline->getClipPlaytime(cid3); 1954 1955 int gid1 = timeline->requestClipsGroup(std::unordered_set<int>({cid1, cid2, cid3}), true, GroupType::Normal); 1956 1957 auto stateA1 = [&]() { 1958 REQUIRE(timeline->checkConsistency()); 1959 REQUIRE(timeline->getClipPlaytime(cid1) == l1); 1960 REQUIRE(timeline->getClipPosition(cid1) == 5); 1961 REQUIRE(timeline->getClipPtr(cid1)->getIn() == 0); 1962 REQUIRE(timeline->getClipPtr(cid1)->getOut() == l1 - 1); 1963 1964 REQUIRE(timeline->m_groups->getLeaves(gid1) == std::unordered_set<int>({cid1, cid2, cid3})); 1965 }; 1966 auto stateA2 = [&]() { 1967 REQUIRE(timeline->checkConsistency()); 1968 REQUIRE(timeline->getClipPlaytime(cid2) == l2); 1969 REQUIRE(timeline->getClipPosition(cid2) == 50); 1970 REQUIRE(timeline->getClipPtr(cid2)->getIn() == 0); 1971 REQUIRE(timeline->getClipPtr(cid2)->getOut() == l2 - 1); 1972 1973 REQUIRE(timeline->checkConsistency()); 1974 REQUIRE(timeline->getClipPlaytime(cid3) == l3); 1975 REQUIRE(timeline->getClipPosition(cid3) == 80); 1976 REQUIRE(timeline->getClipPtr(cid3)->getIn() == 0); 1977 REQUIRE(timeline->getClipPtr(cid3)->getOut() == l3 - 1); 1978 1979 REQUIRE(timeline->m_groups->getLeaves(gid1) == std::unordered_set<int>({cid1, cid2, cid3})); 1980 }; 1981 stateA1(); 1982 stateA2(); 1983 1984 auto stateB = [&]() { 1985 REQUIRE(timeline->checkConsistency()); 1986 REQUIRE(timeline->getClipPlaytime(cid2) == l2 - 5); 1987 REQUIRE(timeline->getClipPosition(cid2) == 50); 1988 REQUIRE(timeline->getClipPtr(cid2)->getIn() == 0); 1989 REQUIRE(timeline->getClipPtr(cid2)->getOut() == l2 - 6); 1990 1991 REQUIRE(timeline->getClipPlaytime(cid3) == l3); 1992 REQUIRE(timeline->getClipPosition(cid3) == 75); 1993 REQUIRE(timeline->getClipPtr(cid3)->getIn() == 0); 1994 REQUIRE(timeline->getClipPtr(cid3)->getOut() == l3 - 1); 1995 1996 REQUIRE(timeline->m_groups->getLeaves(gid1) == std::unordered_set<int>({cid1, cid2, cid3})); 1997 }; 1998 REQUIRE(timeline->requestItemRippleResize(timeline, cid2, l2 - 5, true) == l2 - 5); 1999 stateA1(); 2000 stateB(); 2001 2002 auto stateC = [&]() { 2003 REQUIRE(timeline->checkConsistency()); 2004 REQUIRE(timeline->getClipPlaytime(cid2) == l2 - 8); 2005 REQUIRE(timeline->getClipPosition(cid2) == 50); 2006 REQUIRE(timeline->getClipPtr(cid2)->getIn() == 3); 2007 REQUIRE(timeline->getClipPtr(cid2)->getOut() == l2 - 6); 2008 2009 REQUIRE(timeline->getClipPlaytime(cid3) == l3); 2010 REQUIRE(timeline->getClipPosition(cid3) == 72); 2011 REQUIRE(timeline->getClipPtr(cid3)->getIn() == 0); 2012 REQUIRE(timeline->getClipPtr(cid3)->getOut() == l3 - 1); 2013 2014 REQUIRE(timeline->m_groups->getLeaves(gid1) == std::unordered_set<int>({cid1, cid2, cid3})); 2015 }; 2016 2017 REQUIRE(timeline->requestItemRippleResize(timeline, cid2, l2 - 8, false)); 2018 stateA1(); 2019 stateC(); 2020 2021 undoStack->undo(); 2022 stateA1(); 2023 stateB(); 2024 2025 undoStack->undo(); 2026 stateA1(); 2027 stateA2(); 2028 2029 undoStack->redo(); 2030 stateA1(); 2031 stateB(); 2032 2033 undoStack->redo(); 2034 stateA1(); 2035 stateC(); 2036 } 2037 2038 pCore->projectManager()->closeCurrentDocument(false, false); 2039 }