Close

Relief for ODA Team in Ukraine

Learn more
ODA Drawings SDK
Implementing Partial Undo

Sometimes it is necessary to implement partial undo functionality for a certain modification method of an object, for example, when the complete object state data is large and a modification method affects only a small part of this data. There are no strict rules for determining whether the amount of object state data is big or not and whether the part of the affected data is small or not; implemnetation of partial undo depends on whether the recorded undo data size savings benefit is worth the effort that is needed to implement it.

Below is a sample implementation of a method with partial object state recording using an example of the setName() method of the MyClass class.

To use partial undo for the modification method, first call the assertWriteEnabled() method with autoUndo parameter set to false.

From this point the modification method is responsible for recording undo data by itself because automatic recording is turned off.

Next the method tries to get the undo filer of the object by calling undoFiler(). If getting the undo filer is successful, the method starts saving data. Each record in the undo filer must contain the following fields:

  • Description of the object type
  • Description of the modification operation
  • Data set, representing the current object state
To save all these fields, use appropriate methods of the undo filer that is an instance of the OdDbUndoFiler class. After the current object state is recorded by the undo filer, the method can apply changes to the object's properties.

void MyClass::setName(const OdString& s)
{
  if (m_sName == s)
    return;                  // Nothing to do
  assertWriteEnabled(false); // Do not write automatic (complete) undo
  OdDbUndoFiler* pFiler = (OdDbUndoFiler*)undoFiler());
  if (pFiler)
  {                          // Undo recording enabled. Write partial undo
    pFiler->wrClass(desc());               // Write class identifier
    pFiler->wrInt16(OdUInt16(kPU_Rename)); // Write operation code
    pFiler->wrString(m_sName);             // Write old value
  }
  m_sName = s;                             // Set new value
}

If at least one modification method of an object uses partial undo, override the applyPartialUndo() method for this object so that restoring the object state is held correctly.

The applyPartialUndo() method first checks that the class type specified by the pClass parameter matches the class type of the object. If it does not, the method must call applyPartialUndo() of the parent class. If the class types match, the method must use the undo filer specified by the pFiler parameter to read the operation code (the class description was already read from the undo filer to determine which object must restore its state). When the operation is identified, the method must read the data from the undo filer and apply it to the object using its appropriate set() method.

Note: The applyPartialUndo() method is responsible for correctly reading data from the undo filer. It must know which types of fields to scan and must stop after reading what it needs.

void MyClass::applyPartialUndo(OdDbDwgFiler* pFiler, OdRxClass* pClass)
{
  if (pClass == desc())
  { // This is my class partial undo
    OdInt16 opCode = pFiler->rdInt16();
    switch (opCode)
    {
      case kPU_Rename:
        // Do not change data member directly
        // setName() will write partial undo for "redo" operation
        setName(pFiler->rdString());
        break;
      case :
        break;
		
      ...
	  
      default:
        ODA_ASSERT_ONCE(!L"Unknown partial undo operation code");
    }
  }
  else
  { // It's undo of parent class. Call parent's method
    MyClassParent::applyPartialUndo(pFiler, pClass);
  }
}

See Also

Implementing Undo and Redo Operations

Recording Object States

Restoring Object States

Copyright © 2002 – 2022. Open Design Alliance. All rights reserved.