Skip to content

Commit 8dd9507

Browse files
committed
More work in the right direction
1 parent 029fb4c commit 8dd9507

File tree

4 files changed

+526
-75
lines changed

4 files changed

+526
-75
lines changed

modules/yup_data_model/tree/yup_DataTree.cpp

Lines changed: 112 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,8 @@ class PropertySetAction : public UndoableAction
8282
var newValue, oldValue;
8383
};
8484

85+
//==============================================================================
86+
8587
class PropertyRemoveAction : public UndoableAction
8688
{
8789
public:
@@ -121,6 +123,8 @@ class PropertyRemoveAction : public UndoableAction
121123
var oldValue;
122124
};
123125

126+
//==============================================================================
127+
124128
class RemoveAllPropertiesAction : public UndoableAction
125129
{
126130
public:
@@ -141,13 +145,9 @@ class RemoveAllPropertiesAction : public UndoableAction
141145
return false;
142146

143147
if (state == UndoableActionState::Redo)
144-
{
145148
dataTree.object->properties.clear();
146-
}
147-
else // Undo
148-
{
149+
else
149150
dataTree.object->properties = oldProperties;
150-
}
151151

152152
for (int i = 0; i < oldProperties.size(); ++i)
153153
dataTree.object->sendPropertyChangeMessage (oldProperties.getName (i));
@@ -160,6 +160,8 @@ class RemoveAllPropertiesAction : public UndoableAction
160160
NamedValueSet oldProperties;
161161
};
162162

163+
//==============================================================================
164+
163165
class AddChildAction : public UndoableAction
164166
{
165167
public:
@@ -182,7 +184,6 @@ class AddChildAction : public UndoableAction
182184

183185
if (state == UndoableActionState::Redo)
184186
{
185-
// Capture the child's current parent (if any) for undo
186187
if (auto currentParent = childTree.object->parent.lock())
187188
{
188189
previousParent = DataTree (currentParent);
@@ -203,18 +204,16 @@ class AddChildAction : public UndoableAction
203204

204205
parentTree.object->sendChildAddedMessage (childTree);
205206
}
206-
else // Undo
207+
else
207208
{
208209
const int childIndex = parentTree.indexOf (childTree);
209210
if (childIndex >= 0)
210211
{
211212
parentTree.object->children.erase (parentTree.object->children.begin() + childIndex);
212213
parentTree.object->sendChildRemovedMessage (childTree, childIndex);
213-
214-
// Restore previous parent
214+
215215
if (previousParent.isValid())
216216
{
217-
// Restore to previous parent at previous index
218217
const int numChildren = static_cast<int> (previousParent.object->children.size());
219218
const int actualIndex = (previousIndex < 0 || previousIndex > numChildren) ? numChildren : previousIndex;
220219

@@ -224,7 +223,6 @@ class AddChildAction : public UndoableAction
224223
}
225224
else
226225
{
227-
// No previous parent - clear parent reference
228226
childTree.object->parent.reset();
229227
}
230228
}
@@ -237,10 +235,12 @@ class AddChildAction : public UndoableAction
237235
DataTree parentTree;
238236
DataTree childTree;
239237
int index;
240-
DataTree previousParent; // For undo: the child's parent before this action
241-
int previousIndex = -1; // For undo: the child's index in previous parent
238+
DataTree previousParent;
239+
int previousIndex = -1;
242240
};
243241

242+
//==============================================================================
243+
244244
class RemoveChildAction : public UndoableAction
245245
{
246246
public:
@@ -270,7 +270,7 @@ class RemoveChildAction : public UndoableAction
270270
childTree.object->parent.reset();
271271
parentTree.object->sendChildRemovedMessage (childTree, index);
272272
}
273-
else // Undo
273+
else
274274
{
275275
if (childTree.object == nullptr)
276276
return false;
@@ -292,6 +292,8 @@ class RemoveChildAction : public UndoableAction
292292
int index;
293293
};
294294

295+
//==============================================================================
296+
295297
class RemoveAllChildrenAction : public UndoableAction
296298
{
297299
public:
@@ -321,7 +323,7 @@ class RemoveAllChildrenAction : public UndoableAction
321323
parentTree.object->sendChildRemovedMessage (children[i], static_cast<int> (i));
322324
}
323325
}
324-
else // Undo
326+
else
325327
{
326328
parentTree.object->children = children;
327329

@@ -340,6 +342,8 @@ class RemoveAllChildrenAction : public UndoableAction
340342
std::vector<DataTree> children;
341343
};
342344

345+
//==============================================================================
346+
343347
class MoveChildAction : public UndoableAction
344348
{
345349
public:
@@ -372,7 +376,7 @@ class MoveChildAction : public UndoableAction
372376

373377
parentTree.object->sendChildMovedMessage (child, oldIndex, newIndex);
374378
}
375-
else // Undo
379+
else
376380
{
377381
auto child = parentTree.object->children[static_cast<size_t> (newIndex)];
378382
parentTree.object->children.erase (parentTree.object->children.begin() + newIndex);
@@ -389,27 +393,19 @@ class MoveChildAction : public UndoableAction
389393
int oldIndex, newIndex;
390394
};
391395

392-
//==============================================================================
393-
394-
class SimpleTransactionAction : public UndoableAction
396+
class CompoundAction : public UndoableAction
395397
{
396398
public:
397-
SimpleTransactionAction (DataTree tree, const String& desc, const NamedValueSet& origProps, const std::vector<DataTree>& origChildren)
399+
CompoundAction (DataTree tree, const String& desc, std::vector<UndoableAction::Ptr>&& actions)
398400
: dataTree (tree)
399401
, description (desc)
400-
, originalProperties (origProps)
401-
, originalChildren (origChildren)
402+
, individualActions (std::move (actions))
402403
{
403-
if (dataTree.object != nullptr)
404-
{
405-
currentProperties = dataTree.object->properties;
406-
currentChildren = dataTree.object->children;
407-
}
408404
}
409405

410406
bool isValid() const override
411407
{
412-
return dataTree.object != nullptr;
408+
return dataTree.object != nullptr && !individualActions.empty();
413409
}
414410

415411
bool perform (UndoableActionState state) override
@@ -418,52 +414,29 @@ class SimpleTransactionAction : public UndoableAction
418414
return false;
419415

420416
if (state == UndoableActionState::Redo)
421-
restoreState (currentProperties, currentChildren);
422-
else
423-
restoreState (originalProperties, originalChildren);
424-
425-
return true;
426-
}
427-
428-
private:
429-
void restoreState (const NamedValueSet& props, const std::vector<DataTree>& children)
430-
{
431-
for (const auto& currentChild : dataTree.object->children)
432417
{
433-
bool willBeKept = false;
434-
for (const auto& newChild : children)
418+
for (auto& action : individualActions)
435419
{
436-
if (currentChild.object == newChild.object)
437-
{
438-
willBeKept = true;
439-
break;
440-
}
420+
if (! action->perform (UndoableActionState::Redo))
421+
return false;
441422
}
442-
443-
if (! willBeKept && currentChild.object != nullptr)
444-
currentChild.object->parent.reset();
445423
}
446-
447-
dataTree.object->properties = props;
448-
dataTree.object->children = children;
449-
450-
for (const auto& child : dataTree.object->children)
424+
else
451425
{
452-
if (child.object != nullptr)
453-
child.object->parent = dataTree.object;
426+
for (auto it = individualActions.rbegin(); it != individualActions.rend(); ++it)
427+
{
428+
if (! (*it)->perform (UndoableActionState::Undo))
429+
return false;
430+
}
454431
}
455432

456-
for (int i = 0; i < props.size(); ++i)
457-
dataTree.object->sendPropertyChangeMessage (props.getName (i));
458-
459-
for (size_t i = 0; i < children.size(); ++i)
460-
dataTree.object->sendChildAddedMessage (children[i]);
433+
return true;
461434
}
462435

436+
private:
463437
DataTree dataTree;
464438
String description;
465-
NamedValueSet originalProperties, currentProperties;
466-
std::vector<DataTree> originalChildren, currentChildren;
439+
std::vector<UndoableAction::Ptr> individualActions;
467440
};
468441

469442
//==============================================================================
@@ -1198,7 +1171,6 @@ bool DataTree::isEquivalentTo (const DataTree& other) const
11981171
}
11991172

12001173
//==============================================================================
1201-
// Transaction Implementation
12021174

12031175
DataTree::Transaction::Transaction (DataTree& tree, const String& desc, UndoManager* manager)
12041176
: dataTree (tree)
@@ -1258,17 +1230,87 @@ void DataTree::Transaction::commit()
12581230
if (! active || dataTree.object == nullptr)
12591231
return;
12601232

1261-
if (undoManager != nullptr && (! propertyChanges.empty() || ! childChanges.empty()))
1233+
// Always build individual actions and execute them
1234+
std::vector<UndoableAction::Ptr> actions;
1235+
1236+
// Create property actions that capture current state
1237+
for (const auto& change : propertyChanges)
1238+
{
1239+
switch (change.type)
1240+
{
1241+
case PropertyChange::Set:
1242+
{
1243+
var oldValue = dataTree.hasProperty (change.name) ? dataTree.getProperty (change.name) : var::undefined();
1244+
actions.push_back (new PropertySetAction (dataTree, change.name, change.newValue, oldValue));
1245+
break;
1246+
}
1247+
case PropertyChange::Remove:
1248+
{
1249+
if (dataTree.hasProperty (change.name))
1250+
{
1251+
var oldValue = dataTree.getProperty (change.name);
1252+
actions.push_back (new PropertyRemoveAction (dataTree, change.name, oldValue));
1253+
}
1254+
break;
1255+
}
1256+
case PropertyChange::RemoveAll:
1257+
{
1258+
if (! dataTree.object->properties.isEmpty())
1259+
actions.push_back (new RemoveAllPropertiesAction (dataTree, dataTree.object->properties));
1260+
break;
1261+
}
1262+
}
1263+
}
1264+
1265+
// Create child actions that capture current state
1266+
for (const auto& change : childChanges)
12621267
{
1263-
// Apply changes first to get final state, then create undo action with before/after states
1264-
applyChangesToTree (dataTree, originalProperties, originalChildren, propertyChanges, childChanges);
1268+
switch (change.type)
1269+
{
1270+
case ChildChange::Add:
1271+
{
1272+
actions.push_back (new AddChildAction (dataTree, change.child, change.newIndex));
1273+
break;
1274+
}
1275+
1276+
case ChildChange::Remove:
1277+
{
1278+
int childIndex = dataTree.indexOf (change.child);
1279+
if (childIndex >= 0)
1280+
actions.push_back (new RemoveChildAction (dataTree, change.child, childIndex));
1281+
break;
1282+
}
1283+
1284+
case ChildChange::RemoveAll:
1285+
{
1286+
if (!dataTree.object->children.empty())
1287+
actions.push_back (new RemoveAllChildrenAction (dataTree, dataTree.object->children));
1288+
break;
1289+
}
12651290

1266-
// Create a simple action that can restore the original state
1267-
undoManager->perform (new SimpleTransactionAction (dataTree, description, originalProperties, originalChildren));
1291+
case ChildChange::Move:
1292+
{
1293+
const int numChildren = static_cast<int> (dataTree.object->children.size());
1294+
if (change.oldIndex >= 0 && change.oldIndex < numChildren &&
1295+
change.newIndex >= 0 && change.newIndex < numChildren &&
1296+
change.oldIndex != change.newIndex)
1297+
{
1298+
actions.push_back (new MoveChildAction (dataTree, change.oldIndex, change.newIndex));
1299+
}
1300+
break;
1301+
}
1302+
}
1303+
}
1304+
1305+
// If we have undo manager, use compound action for undo/redo
1306+
if (undoManager != nullptr && !actions.empty())
1307+
{
1308+
undoManager->perform (new CompoundAction (dataTree, description, std::move (actions)));
12681309
}
12691310
else
12701311
{
1271-
applyChangesToTree (dataTree, originalProperties, originalChildren, propertyChanges, childChanges);
1312+
for (auto& action : actions)
1313+
action->perform (UndoableActionState::Redo);
12721314
}
12731315

12741316
active = false;

modules/yup_data_model/tree/yup_DataTree.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1231,7 +1231,7 @@ class YUP_API DataTree
12311231
friend class RemoveChildAction;
12321232
friend class RemoveAllChildrenAction;
12331233
friend class MoveChildAction;
1234-
friend class SimpleTransactionAction;
1234+
friend class CompoundAction;
12351235

12361236
class DataObject : public std::enable_shared_from_this<DataObject>
12371237
{

0 commit comments

Comments
 (0)