@@ -182,11 +182,17 @@ class AddChildAction : public UndoableAction
182182
183183 if (state == UndoableActionState::Redo)
184184 {
185- // Remove from previous parent if any
186- if (auto oldParentObj = childTree.object ->parent .lock ())
185+ // Capture the child's current parent ( if any) for undo
186+ if (auto currentParent = childTree.object ->parent .lock ())
187187 {
188- DataTree oldParent (oldParentObj);
189- oldParent.removeChild (childTree);
188+ previousParent = DataTree (currentParent);
189+ previousIndex = previousParent.indexOf (childTree);
190+ previousParent.removeChild (childTree);
191+ }
192+ else
193+ {
194+ previousParent = DataTree (); // No previous parent
195+ previousIndex = -1 ;
190196 }
191197
192198 const int numChildren = static_cast <int > (parentTree.object ->children .size ());
@@ -203,8 +209,24 @@ class AddChildAction : public UndoableAction
203209 if (childIndex >= 0 )
204210 {
205211 parentTree.object ->children .erase (parentTree.object ->children .begin () + childIndex);
206- childTree.object ->parent .reset ();
207212 parentTree.object ->sendChildRemovedMessage (childTree, childIndex);
213+
214+ // Restore previous parent
215+ if (previousParent.isValid ())
216+ {
217+ // Restore to previous parent at previous index
218+ const int numChildren = static_cast <int > (previousParent.object ->children .size ());
219+ const int actualIndex = (previousIndex < 0 || previousIndex > numChildren) ? numChildren : previousIndex;
220+
221+ previousParent.object ->children .insert (previousParent.object ->children .begin () + actualIndex, childTree);
222+ childTree.object ->parent = previousParent.object ;
223+ previousParent.object ->sendChildAddedMessage (childTree);
224+ }
225+ else
226+ {
227+ // No previous parent - clear parent reference
228+ childTree.object ->parent .reset ();
229+ }
208230 }
209231 }
210232
@@ -215,6 +237,8 @@ class AddChildAction : public UndoableAction
215237 DataTree parentTree;
216238 DataTree childTree;
217239 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
218242};
219243
220244class RemoveChildAction : public UndoableAction
@@ -367,17 +391,21 @@ class MoveChildAction : public UndoableAction
367391
368392// ==============================================================================
369393
370- class TransactionAction : public UndoableAction
394+ class SimpleTransactionAction : public UndoableAction
371395{
372396public:
373- TransactionAction (DataTree tree, const String& desc, const NamedValueSet& origProps, const std::vector<DataTree>& origChildren, const std::vector<DataTree::Transaction::PropertyChange>& propChanges, const std::vector<DataTree::Transaction::ChildChange>& childChanges )
397+ SimpleTransactionAction (DataTree tree, const String& desc, const NamedValueSet& origProps, const std::vector<DataTree>& origChildren)
374398 : dataTree (tree)
375399 , description (desc)
376400 , originalProperties (origProps)
377401 , originalChildren (origChildren)
378- , propertyChanges (propChanges)
379- , childChangeList (childChanges)
380402 {
403+ // Capture current state as the "after" state
404+ if (dataTree.object != nullptr )
405+ {
406+ currentProperties = dataTree.object ->properties ;
407+ currentChildren = dataTree.object ->children ;
408+ }
381409 }
382410
383411 bool isValid () const override
@@ -392,62 +420,63 @@ class TransactionAction : public UndoableAction
392420
393421 if (state == UndoableActionState::Redo)
394422 {
395- // Reapply all the changes
396- applyChangesToTree ();
397- return true ;
423+ // Restore "after" state (current/new state)
424+ restoreState (currentProperties, currentChildren);
398425 }
399426 else // Undo
400427 {
401- // Restore original state
402- dataTree.object ->properties = originalProperties;
403- dataTree.object ->children = originalChildren;
404-
405- // Update parent pointers for children
406- for (auto & child : dataTree.object ->children )
407- {
408- if (child.object != nullptr )
409- child.object ->parent = dataTree.object ;
410- }
411-
412- // Send notifications for all properties
413- for (int i = 0 ; i < originalProperties.size (); ++i)
414- dataTree.object ->sendPropertyChangeMessage (originalProperties.getName (i));
415-
416- // Send notifications for children
417- for (size_t i = 0 ; i < originalChildren.size (); ++i)
418- dataTree.object ->sendChildAddedMessage (originalChildren[i]);
419-
420- return true ;
428+ // Restore "before" state (original state)
429+ restoreState (originalProperties, originalChildren);
421430 }
431+
432+ return true ;
422433 }
423434
424435private:
425- void applyChangesToTree ( )
436+ void restoreState ( const NamedValueSet& props, const std::vector<DataTree>& children )
426437 {
427- if (dataTree.object == nullptr )
428- return ;
429-
430- // Start with original state
431- dataTree.object ->properties = originalProperties;
432- dataTree.object ->children = originalChildren;
438+ // Clear parent references for children that will be removed
439+ for (const auto & currentChild : dataTree.object ->children )
440+ {
441+ bool willBeKept = false ;
442+ for (const auto & newChild : children)
443+ {
444+ if (currentChild.object == newChild.object )
445+ {
446+ willBeKept = true ;
447+ break ;
448+ }
449+ }
450+
451+ if (!willBeKept && currentChild.object != nullptr )
452+ {
453+ currentChild.object ->parent .reset ();
454+ }
455+ }
456+
457+ // Restore properties and children
458+ dataTree.object ->properties = props;
459+ dataTree.object ->children = children;
433460
434- // Update parent pointers for original children
435- for (auto & child : dataTree.object ->children )
461+ // Set parent references for restored children
462+ for (const auto & child : dataTree.object ->children )
436463 {
437464 if (child.object != nullptr )
438465 child.object ->parent = dataTree.object ;
439466 }
440467
441- // Apply all changes using the shared implementation
442- DataTree::Transaction::applyChangesToTree (dataTree, originalProperties, originalChildren, propertyChanges, childChangeList);
468+ // Send notifications
469+ for (int i = 0 ; i < props.size (); ++i)
470+ dataTree.object ->sendPropertyChangeMessage (props.getName (i));
471+
472+ for (size_t i = 0 ; i < children.size (); ++i)
473+ dataTree.object ->sendChildAddedMessage (children[i]);
443474 }
444475
445476 DataTree dataTree;
446477 String description;
447- NamedValueSet originalProperties;
448- std::vector<DataTree> originalChildren;
449- std::vector<DataTree::Transaction::PropertyChange> propertyChanges;
450- std::vector<DataTree::Transaction::ChildChange> childChangeList;
478+ NamedValueSet originalProperties, currentProperties;
479+ std::vector<DataTree> originalChildren, currentChildren;
451480};
452481
453482// ==============================================================================
@@ -523,6 +552,40 @@ DataTree::DataTree (const Identifier& type)
523552{
524553}
525554
555+ DataTree::DataTree (const Identifier& type,
556+ const std::initializer_list<std::pair<Identifier, var>>& properties)
557+ : DataTree (type)
558+ {
559+ auto transaction = beginTransaction ();
560+
561+ for (const auto & [key, value] : properties)
562+ transaction.setProperty (key, value);
563+ }
564+
565+ DataTree::DataTree (const Identifier& type,
566+ const std::initializer_list<DataTree>& children)
567+ : DataTree (type)
568+ {
569+ auto transaction = beginTransaction ();
570+
571+ for (const auto & child : children)
572+ transaction.addChild (child);
573+ }
574+
575+ DataTree::DataTree (const Identifier& type,
576+ const std::initializer_list<std::pair<Identifier, var>>& properties,
577+ const std::initializer_list<DataTree>& children)
578+ : DataTree (type)
579+ {
580+ auto transaction = beginTransaction ();
581+
582+ for (const auto & [key, value] : properties)
583+ transaction.setProperty (key, value);
584+
585+ for (const auto & child : children)
586+ transaction.addChild (child);
587+ }
588+
526589DataTree::DataTree (const DataTree& other) noexcept
527590 : object (other.object)
528591{
@@ -1240,8 +1303,11 @@ void DataTree::Transaction::commit()
12401303
12411304 if (undoManager != nullptr && (! propertyChanges.empty () || ! childChanges.empty ()))
12421305 {
1243- // Use undo manager to perform the transaction action
1244- undoManager->perform (new TransactionAction (dataTree, description, originalProperties, originalChildren, propertyChanges, childChanges));
1306+ // Apply changes first to get final state, then create undo action with before/after states
1307+ applyChangesToTree (dataTree, originalProperties, originalChildren, propertyChanges, childChanges);
1308+
1309+ // Create a simple action that can restore the original state
1310+ undoManager->perform (new SimpleTransactionAction (dataTree, description, originalProperties, originalChildren));
12451311 }
12461312 else
12471313 {
0 commit comments