Commit a057a3a9 authored by Nicolas Carion's avatar Nicolas Carion

Reapply fix for incorrect grouping prevention

parent 27d09c51
......@@ -97,12 +97,14 @@ int GroupsModel::groupItems(const std::unordered_set<int> &ids, Fun &undo, Fun &
QWriteLocker locker(&m_lock);
Q_ASSERT(type != GroupType::Leaf);
Q_ASSERT(!ids.empty());
if (ids.size() == 1 && !force) {
std::unordered_set<int> roots;
std::transform(ids.begin(), ids.end(), std::inserter(roots, roots.begin()), [&](int id) { return getRootId(id); });
if (roots.size() == 1 && !force) {
// We do not create a group with only one element. Instead, we return the id of that element
return *(ids.begin());
return *(roots.begin());
}
int gid = TimelineModel::getNextId();
auto operation = groupItems_lambda(gid, ids, type);
auto operation = groupItems_lambda(gid, roots, type);
if (operation()) {
auto reverse = destructGroupItem_lambda(gid);
UPDATE_UNDO_REDO(operation, reverse, undo, redo);
......@@ -399,8 +401,8 @@ bool GroupsModel::mergeSingleGroups(int id, Fun &undo, Fun &redo)
}
return true;
};
Fun reverse = [this, old_parents, parent_changer]() { return parent_changer(old_parents); };
Fun operation = [this, new_parents, parent_changer]() { return parent_changer(new_parents); };
Fun reverse = [old_parents, parent_changer]() { return parent_changer(old_parents); };
Fun operation = [new_parents, parent_changer]() { return parent_changer(new_parents); };
bool res = operation();
if (!res) {
bool undone = reverse();
......@@ -595,7 +597,7 @@ bool GroupsModel::createGroupAtSameLevel(int id, std::unordered_set<int> to_add,
Q_ASSERT(m_upLink.count(g) > 0);
old_parents[g] = m_upLink[g];
}
Fun operation = [this, id, gid, type, to_add, parent = m_upLink.at(id)]() {
Fun operation = [this, gid, type, to_add, parent = m_upLink.at(id)]() {
createGroupItem(gid);
setGroup(gid, parent);
for (const auto &g : to_add) {
......@@ -604,7 +606,7 @@ bool GroupsModel::createGroupAtSameLevel(int id, std::unordered_set<int> to_add,
setType(gid, type);
return true;
};
Fun reverse = [this, id, old_parents, gid]() {
Fun reverse = [this, old_parents, gid]() {
for (const auto &g : old_parents) {
setGroup(g.first, g.second);
}
......
......@@ -43,7 +43,7 @@ struct TimelineFunctions
Returns true on success
@param timeline : ptr to the timeline model
@param clipId: Id of the clip to split
@param position: position (in frames) where to cut
@param position: position (in frames from the beginning of the timeline) where to cut
*/
static bool requestClipCut(std::shared_ptr<TimelineItemModel> timeline, int clipId, int position);
/* This is the same function, except that it accumulates undo/redo */
......
......@@ -1642,11 +1642,11 @@ int TimelineModel::requestClipsGroup(const std::unordered_set<int> &ids, Fun &un
return -1;
}
}
int groupId = m_groups->groupItems(ids, undo, redo, type);
if (type == GroupType::Selection && *(ids.begin()) == groupId) {
if (type == GroupType::Selection && ids.size() == 1) {
// only one element selected, no group created
return -1;
}
int groupId = m_groups->groupItems(ids, undo, redo, type);
return groupId;
}
......
......@@ -413,3 +413,141 @@ TEST_CASE("Regression 4")
timeline->requestClipMove(12,9 ,521, true, true );
}
*/
TEST_CASE("FuzzBug1")
{
auto binModel = pCore->projectItemModel();
std::shared_ptr<DocUndoStack> undoStack = std::make_shared<DocUndoStack>(nullptr);
std::shared_ptr<MarkerListModel> guideModel = std::make_shared<MarkerListModel>(undoStack);
TimelineModel::next_id = 0;
{
Mock<ProjectManager> pmMock;
When(Method(pmMock, undoStack)).AlwaysReturn(undoStack);
ProjectManager &mocked = pmMock.get();
pCore->m_projectManager = &mocked;
TimelineItemModel tim_0(&reg_profile, undoStack);
Mock<TimelineItemModel> timMock_0(tim_0);
auto timeline_0 = std::shared_ptr<TimelineItemModel>(&timMock_0.get(), [](...) {});
TimelineItemModel::finishConstruct(timeline_0, guideModel);
Fake(Method(timMock_0, adjustAssetRange));
REQUIRE(timeline_0->checkConsistency());
undoStack->undo();
REQUIRE(timeline_0->checkConsistency());
undoStack->redo();
REQUIRE(timeline_0->checkConsistency());
TrackModel::construct(timeline_0, -1, -1, "", false);
REQUIRE(timeline_0->checkConsistency());
undoStack->undo();
REQUIRE(timeline_0->checkConsistency());
undoStack->redo();
REQUIRE(timeline_0->checkConsistency());
TrackModel::construct(timeline_0, -1, -1, "$$$", false);
REQUIRE(timeline_0->checkConsistency());
undoStack->undo();
REQUIRE(timeline_0->checkConsistency());
undoStack->redo();
REQUIRE(timeline_0->checkConsistency());
{
bool res = timeline_0->requestTrackDeletion(2);
REQUIRE(res == true);
}
REQUIRE(timeline_0->checkConsistency());
undoStack->undo();
REQUIRE(timeline_0->checkConsistency());
undoStack->redo();
REQUIRE(timeline_0->checkConsistency());
{
bool res = timeline_0->requestTrackDeletion(1);
REQUIRE(res == true);
}
REQUIRE(timeline_0->checkConsistency());
undoStack->undo();
REQUIRE(timeline_0->checkConsistency());
undoStack->redo();
REQUIRE(timeline_0->checkConsistency());
{
int dummy_1;
bool res = timeline_0->requestTrackInsertion(-1, dummy_1, "", false);
REQUIRE(res == true);
}
REQUIRE(timeline_0->checkConsistency());
undoStack->undo();
REQUIRE(timeline_0->checkConsistency());
undoStack->redo();
REQUIRE(timeline_0->checkConsistency());
{
int dummy_1;
bool res = timeline_0->requestTrackInsertion(-1, dummy_1, "", false);
REQUIRE(res == true);
}
REQUIRE(timeline_0->checkConsistency());
undoStack->undo();
REQUIRE(timeline_0->checkConsistency());
undoStack->redo();
REQUIRE(timeline_0->checkConsistency());
createProducer(reg_profile, "red", binModel, 20, true);
REQUIRE(timeline_0->checkConsistency());
undoStack->undo();
REQUIRE(timeline_0->checkConsistency());
undoStack->redo();
REQUIRE(timeline_0->checkConsistency());
{
int dummy_3;
bool res = timeline_0->requestClipInsertion("2", 3, 0, dummy_3, true, false, true);
REQUIRE(res == true);
}
REQUIRE(timeline_0->checkConsistency());
undoStack->undo();
REQUIRE(timeline_0->checkConsistency());
undoStack->redo();
REQUIRE(timeline_0->checkConsistency());
{
int dummy_3;
bool res = timeline_0->requestClipInsertion("2", 3, 20, dummy_3, true, false, true);
REQUIRE(res == true);
}
REQUIRE(timeline_0->checkConsistency());
undoStack->undo();
REQUIRE(timeline_0->checkConsistency());
undoStack->redo();
REQUIRE(timeline_0->checkConsistency());
{
int dummy_3;
bool res = timeline_0->requestClipInsertion("2", 3, 40, dummy_3, true, false, true);
REQUIRE(res == true);
}
REQUIRE(timeline_0->checkConsistency());
undoStack->undo();
REQUIRE(timeline_0->checkConsistency());
undoStack->redo();
REQUIRE(timeline_0->checkConsistency());
{
int res = timeline_0->requestClipsGroup({5, 7}, true, GroupType::Normal);
REQUIRE(res == 8);
}
REQUIRE(timeline_0->checkConsistency());
undoStack->undo();
REQUIRE(timeline_0->checkConsistency());
undoStack->redo();
REQUIRE(timeline_0->checkConsistency());
{
int res = timeline_0->requestClipsGroup({6, 7}, true, GroupType::Normal);
REQUIRE(res == 9);
}
REQUIRE(timeline_0->checkConsistency());
undoStack->undo();
REQUIRE(timeline_0->checkConsistency());
undoStack->redo();
REQUIRE(timeline_0->checkConsistency());
{
int res = timeline_0->requestClipsGroup({6, 7}, false, GroupType::Normal);
REQUIRE(res == 9);
}
REQUIRE(timeline_0->checkConsistency());
undoStack->undo();
REQUIRE(timeline_0->checkConsistency());
undoStack->redo();
REQUIRE(timeline_0->checkConsistency());
}
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