ACF $AcfVersion:0$
Classes | Public Types | Public Member Functions | Protected Types | Protected Member Functions | List of all members
idoc::CSerializedUndoManagerComp Class Reference

Implements multi-level UNDO mechanism based on storing complete object state at each step using serialization. More...

#include <CSerializedUndoManagerComp.h>

Inheritance diagram for idoc::CSerializedUndoManagerComp:
icomp::CComponentBase imod::TSingleModelObserverBase< iser::ISerializable > idoc::IUndoManager icomp::IComponent imod::CSingleModelObserverBase idoc::IDocumentStateComparator istd::IPolymorphic imod::IObserver istd::IChangeable istd::IPolymorphic istd::IPolymorphic

Classes

struct  UndoStepInfo
 

Public Types

typedef icomp::CComponentBase BaseClass
 
typedef imod::TSingleModelObserverBase< iser::ISerializableBaseClass2
 
- Public Types inherited from imod::TSingleModelObserverBase< iser::ISerializable >
typedef CSingleModelObserverBase BaseClass
 
typedef iser::ISerializable ModelType
 
- Public Types inherited from imod::CSingleModelObserverBase
typedef imod::IModel ModelType
 
- Public Types inherited from idoc::IDocumentStateComparator
enum  DocumentChangeFlag { DCF_UNKNOWN , DCF_EQUAL , DCF_DIFFERENT }
 Flag indicating the relationship between current and stored document state. More...
 
- Public Types inherited from istd::IChangeable
enum  ChangeFlags {
  CF_ACF_INTERNAL = 0 , CF_ALL_DATA , CF_ANY , CF_DESTROYING ,
  CF_DELEGATED , CF_NO_UNDO
}
 Data model change notification flags. More...
 
enum  SupportedOperations {
  SO_NONE = 0 , SO_OBSERVE = 1 << 0 , SO_COPY = 1 << 1 , SO_CLONE = 1 << 2 ,
  SO_COMPARE = 1 << 3 , SO_RESET = 1 << 4
}
 Flags for supported operations. More...
 
enum  CompatibilityMode { CM_STRICT , CM_WITHOUT_REFS , CM_WITH_REFS , CM_CONVERT }
 Control how relationship betweeen objects are interpreted. More...
 
typedef QMultiMap< QByteArray, QVariant > ChangeInfoMap
 

Public Member Functions

 CSerializedUndoManagerComp ()
 
virtual int GetAvailableUndoSteps () const override
 Get number of available UNDO levels.
 
virtual int GetAvailableRedoSteps () const override
 Get number of available REDO levels.
 
virtual QString GetUndoLevelDescription (int stepIndex) const override
 Get description of single UNDO level.
 
virtual QString GetRedoLevelDescription (int stepIndex) const override
 Get description of single REDO level.
 
virtual void ResetUndo () override
 Reset all UNDO and REDO steps.
 
virtual bool DoUndo (int steps=1) override
 Process UNDO steps.
 
virtual bool DoRedo (int steps=1) override
 Process REDO steps.
 
virtual bool OnModelAttached (imod::IModel *modelPtr, istd::IChangeable::ChangeSet &changeMask) override
 Callback invoked when an observable model is about to be attached to this observer.
 
virtual bool OnModelDetached (imod::IModel *modelPtr) override
 Callback invoked when an observable model is about to be detached from this observer.
 
- Public Member Functions inherited from icomp::CComponentBase
 CComponentBase ()
 Create component and assign it to specific context.
 
virtual const icomp::IComponentGetParentComponent (bool ownerOnly=false) const override
 Get parent of this component.
 
virtual void * GetInterface (const istd::CClassInfo &interfaceType, const QByteArray &subId="") override
 Get access to specified component interface.
 
virtual IComponentContextSharedPtr GetComponentContext () const override
 Get access to component context describing all application-specified component information loaded from components registry.
 
virtual void SetComponentContext (const IComponentContextSharedPtr &contextPtr, const icomp::IComponent *parentPtr, bool isParentOwner) override
 Set component context of this component.
 
- Public Member Functions inherited from istd::IPolymorphic
virtual ~IPolymorphic ()
 
- Public Member Functions inherited from imod::TSingleModelObserverBase< iser::ISerializable >
 TSingleModelObserverBase ()
 
iser::ISerializableGetObservedObject () const
 Get instance of observed object.
 
iser::ISerializableGetObjectPtr () const
 Get instance of observed object.
 
bool AttachOrSetObject (iser::ISerializable *objectPtr)
 Attach to model of object or set object pointer, if no connection is possible.
 
- Public Member Functions inherited from imod::CSingleModelObserverBase
 CSingleModelObserverBase ()
 
virtual ~CSingleModelObserverBase ()
 
imod::IModelGetObservedModel () const
 Get access to observed model.
 
imod::IModelGetModelPtr () const
 Get access to observed model.
 
void EnsureModelDetached ()
 Make sure this observer is detached.
 
void SetObservedIds (const istd::IChangeable::ChangeSet &changeMask)
 Set list of ID's beeing observed.
 
virtual bool IsModelAttached (const imod::IModel *modelPtr=NULL) const override
 Checks if the specified model is currently attached to this observer.
 
- Public Member Functions inherited from istd::IChangeable
virtual int GetSupportedOperations () const
 Get set of flags for supported operations.
 
virtual bool CopyFrom (const IChangeable &object, CompatibilityMode mode=CM_WITHOUT_REFS)
 Copy this object from another one.
 
virtual bool IsEqual (const IChangeable &object) const
 Compare this object with another object.
 
virtual istd::TUniqueInterfacePtr< istd::IChangeableCloneMe (CompatibilityMode mode=CM_WITHOUT_REFS) const
 Make a copy of this object.
 
virtual bool ResetData (CompatibilityMode mode=CM_WITHOUT_REFS)
 Reset data to its default state.
 
virtual void BeginChanges (const ChangeSet &changeSet)
 Starts the change transaction.
 
virtual void EndChanges (const ChangeSet &changeSet)
 Ends the change transaction.
 
virtual void BeginChangeGroup (const ChangeSet &changeSet)
 Starts group of changes.
 
virtual void EndChangeGroup (const ChangeSet &changeSet)
 Ends group of changes.
 

Protected Types

typedef istd::TDelPtr< iser::CMemoryWriteArchiveUndoArchivePtr
 
typedef QList< UndoStepInfoUndoList
 

Protected Member Functions

bool DoListShift (int steps, UndoList &fromList, UndoList &toList)
 
virtual iser::ISerializableCastFromModel (imod::IModel *modelPtr) const override
 
virtual void BeforeUpdate (imod::IModel *modelPtr) override
 Callback invoked before an update of the observer's content occurs.
 
virtual void AfterUpdate (imod::IModel *modelPtr, const istd::IChangeable::ChangeSet &changeSet) override
 Callback invoked after an update of the observer's content occurs.
 
virtual bool HasStoredDocumentState () const override
 Check if there is stored document state available.
 
virtual bool StoreDocumentState () override
 Store state of the document.
 
virtual bool RestoreDocumentState () override
 Restore last stored document state.
 
virtual DocumentChangeFlag GetDocumentChangeFlag () const override
 Check if document state is the same as stored state.
 
virtual void OnComponentDestroyed () override
 
- Protected Member Functions inherited from icomp::CComponentBase
bool IsComponentActive () const
 Check if component is active.
 
virtual void OnComponentCreated ()
 
virtual const icomp::IRealComponentStaticInfoGetComponentStaticInfo () const =0
 Get access to static info of this component.
 
- Protected Member Functions inherited from imod::CSingleModelObserverBase
void SetModelPtr (imod::IModel *modelPtr)
 Set internal model pointer to specified value.
 
virtual void OnUpdate (const istd::IChangeable::ChangeSet &changeSet)
 Called on update of observed model.
 
- Protected Member Functions inherited from istd::IChangeable
virtual void OnBeginChanges ()
 Callback function for begin change event.
 
virtual void OnEndChanges (const ChangeSet &changeSet)
 Callback function for end change event.
 

Additional Inherited Members

- Static Public Member Functions inherited from istd::IChangeable
static const ChangeSetGetNoChanges ()
 Get empty set of changes.
 
static const ChangeSetGetAnyChange ()
 Get anonymous change set.
 
static const ChangeSetGetAllChanges ()
 Get anonymous change set.
 
static const ChangeSetGetDelegatedChanges ()
 Get delegated change set.
 
- Static Protected Member Functions inherited from icomp::CComponentBase
static const icomp::IRealComponentStaticInfoInitStaticInfo (IComponent *componentPtr)
 
static QByteArray GetComponentId (const icomp::IComponentContext *componentContextPtr, const QByteArray &contextId=QByteArray())
 
- Static Protected Attributes inherited from imod::CSingleModelObserverBase
static const istd::IChangeable::ChangeSet s_undoChanges
 

Detailed Description

Implements multi-level UNDO mechanism based on storing complete object state at each step using serialization.

This component provides a complete undo/redo implementation by serializing the entire document state before each change. It maintains separate undo and redo stacks and automatically manages memory usage by limiting the buffer size.

The undo manager observes the document model and automatically captures state snapshots when changes occur. It integrates with the ACF model/observer pattern to track when undo/redo availability changes.

Component Attributes
  • MaxBufferSize - Maximum memory size for undo buffer in megabytes (default: 100 MB)
Registered Interfaces
Configuration Example
MaxBufferSize = 50 // Limit undo buffer to 50 MB
}
Implements multi-level UNDO mechanism based on storing complete object state at each step using seria...
Usage with Document Template
DocumentTypeId = "TextDocument"
DocumentFactory = CTextDocumentComp
MaxBufferSize = 100
}
}
Document template component supporting only one type of the provided document.
Simple implementation of a text document model.
How It Works
The undo manager:
  1. Attaches to a serializable document as an observer
  2. Before each document change, serializes current state to memory
  3. Stores serialized state in undo stack with a description
  4. On undo, deserializes previous state from stack
  5. Manages memory by removing oldest undo steps when buffer is full
Usage Example
// Get undo manager for document
idoc::IUndoManager* undoMgr = GetUndoManager();
// Make changes to document
document->SetText("New text");
// Undo manager automatically captured state before change
if (undoMgr->GetAvailableUndoSteps() > 0) {
QString desc = undoMgr->GetUndoLevelDescription(0);
qDebug() << "Can undo:" << desc;
undoMgr->DoUndo();
}
// After undo, redo becomes available
if (undoMgr->GetAvailableRedoSteps() > 0) {
undoMgr->DoRedo();
}
// Clear all undo history
undoMgr->ResetUndo();
// Check if document has unsaved changes
// Document has been modified
}
virtual DocumentChangeFlag GetDocumentChangeFlag() const =0
Check if document state is the same as stored state.
DocumentChangeFlag
Flag indicating the relationship between current and stored document state.
@ DCF_DIFFERENT
Current document state differs from the stored one (has changes).
Interface providing UNDO/REDO functionality.
virtual int GetAvailableRedoSteps() const =0
Get number of available REDO levels.
virtual bool DoRedo(int steps=1)=0
Process REDO steps.
virtual bool DoUndo(int steps=1)=0
Process UNDO steps.
virtual void ResetUndo()=0
Reset all UNDO and REDO steps.
virtual QString GetUndoLevelDescription(int stepIndex) const =0
Get description of single UNDO level.
virtual int GetAvailableUndoSteps() const =0
Get number of available UNDO levels.
Note
The document must implement iser::ISerializable for this undo manager to work.
Memory usage is automatically managed based on MaxBufferSize setting.
Each undo step stores the complete document state, so large documents may use significant memory.
See also
IUndoManager, IDocumentStateComparator

Definition at line 104 of file CSerializedUndoManagerComp.h.

Member Typedef Documentation

◆ BaseClass

Definition at line 110 of file CSerializedUndoManagerComp.h.

◆ BaseClass2

Definition at line 111 of file CSerializedUndoManagerComp.h.

◆ UndoArchivePtr

Definition at line 136 of file CSerializedUndoManagerComp.h.

◆ UndoList

Definition at line 142 of file CSerializedUndoManagerComp.h.

Constructor & Destructor Documentation

◆ CSerializedUndoManagerComp()

idoc::CSerializedUndoManagerComp::CSerializedUndoManagerComp ( )

Member Function Documentation

◆ AfterUpdate()

virtual void idoc::CSerializedUndoManagerComp::AfterUpdate ( imod::IModel modelPtr,
const istd::IChangeable::ChangeSet changeSet 
)
overrideprotectedvirtual

Callback invoked after an update of the observer's content occurs.

This is the primary notification method where observers react to model changes. It's called after the model has finished updating its state. The implementation should examine the changeSet to determine what changed and update accordingly.

Parameters
modelPtrPointer to the model that has changed
changeSetContains information about what changed in the model. Use changeSet.Contains(changeId) to check for specific changes. The changeSet respects the mask specified in OnModelAttached().
Note
This is typically where you update your GUI, recalculate derived values, or trigger other dependent operations.
Keep this method fast - it's called frequently and may block the UI thread.
Use the changeSet to perform incremental updates rather than refreshing everything.
virtual void AfterUpdate(IModel* modelPtr,
const istd::IChangeable::ChangeSet& changeSet)
{
CMyModel* model = dynamic_cast<CMyModel*>(modelPtr);
if (!model) return;
// Selective update based on what changed
if (changeSet.Contains(CMyModel::CF_NAME_CHANGED)) {
m_nameLabel->setText(model->GetName());
}
if (changeSet.Contains(CMyModel::CF_VALUE_CHANGED)) {
m_valueSpinBox->setValue(model->GetValue());
RecalculateDependentValues();
}
// Re-enable signals if blocked in BeforeUpdate
if (m_widget) {
m_widget->blockSignals(false);
}
}
virtual void AfterUpdate(imod::IModel *modelPtr, const istd::IChangeable::ChangeSet &changeSet) override
Callback invoked after an update of the observer's content occurs.
Set of change flags (its IDs).
Definition IChangeable.h:36
bool Contains(int changeId) const
Check if there is specific change flag in the set.
See also
BeforeUpdate(), OnModelAttached()

Reimplemented from imod::CSingleModelObserverBase.

◆ BeforeUpdate()

virtual void idoc::CSerializedUndoManagerComp::BeforeUpdate ( imod::IModel modelPtr)
overrideprotectedvirtual

Callback invoked before an update of the observer's content occurs.

This method is called at the start of a model update cycle, before any data actually changes. It allows the observer to prepare for the update, such as saving current state for comparison or disabling UI updates temporarily.

Parameters
modelPtrPointer to the model that is about to change
Warning
In some error cases, this method may be called without a subsequent AfterUpdate() call. Don't rely on AfterUpdate() always being called.
Note
This method is optional to implement - if you don't need preparation logic, just provide an empty implementation.
virtual void BeforeUpdate(IModel* modelPtr)
{
// Example: Block signals to prevent multiple GUI updates
if (m_widget) {
m_widget->blockSignals(true);
}
// Example: Save state for delta comparison
m_previousValue = m_currentValue;
}
virtual void BeforeUpdate(imod::IModel *modelPtr) override
Callback invoked before an update of the observer's content occurs.
See also
AfterUpdate()

Reimplemented from imod::CSingleModelObserverBase.

◆ CastFromModel()

virtual iser::ISerializable * idoc::CSerializedUndoManagerComp::CastFromModel ( imod::IModel modelPtr) const
overrideprotectedvirtual

◆ DoListShift()

bool idoc::CSerializedUndoManagerComp::DoListShift ( int  steps,
UndoList fromList,
UndoList toList 
)
protected

◆ DoRedo()

virtual bool idoc::CSerializedUndoManagerComp::DoRedo ( int  steps = 1)
overridevirtual

Process REDO steps.

Parameters
stepsNumber of redo levels to execute (default is 1).
Returns
True if redo was successful, false otherwise.

Implements idoc::IUndoManager.

◆ DoUndo()

virtual bool idoc::CSerializedUndoManagerComp::DoUndo ( int  steps = 1)
overridevirtual

Process UNDO steps.

Parameters
stepsNumber of undo levels to execute (default is 1).
Returns
True if undo was successful, false otherwise.

Implements idoc::IUndoManager.

◆ GetAvailableRedoSteps()

virtual int idoc::CSerializedUndoManagerComp::GetAvailableRedoSteps ( ) const
overridevirtual

Get number of available REDO levels.

Returns
Number of REDO levels, or 0 if there is no REDO available.

REDO levels are created when undo operations are performed.

Implements idoc::IUndoManager.

◆ GetAvailableUndoSteps()

virtual int idoc::CSerializedUndoManagerComp::GetAvailableUndoSteps ( ) const
overridevirtual

Get number of available UNDO levels.

Returns
Number of UNDO levels, or 0 if there is no UNDO available.

Each level represents a separate change that can be undone.

Implements idoc::IUndoManager.

◆ GetDocumentChangeFlag()

virtual DocumentChangeFlag idoc::CSerializedUndoManagerComp::GetDocumentChangeFlag ( ) const
overrideprotectedvirtual

Check if document state is the same as stored state.

Returns
Flag indicating whether current state matches stored state.

Implements idoc::IDocumentStateComparator.

◆ GetRedoLevelDescription()

virtual QString idoc::CSerializedUndoManagerComp::GetRedoLevelDescription ( int  stepIndex) const
overridevirtual

Get description of single REDO level.

Parameters
stepIndexIndex of the redo step (0 = most recent).
Returns
Human-readable description of what will be redone.

Implements idoc::IUndoManager.

◆ GetUndoLevelDescription()

virtual QString idoc::CSerializedUndoManagerComp::GetUndoLevelDescription ( int  stepIndex) const
overridevirtual

Get description of single UNDO level.

Parameters
stepIndexIndex of the undo step (0 = most recent).
Returns
Human-readable description of what will be undone.

Implements idoc::IUndoManager.

◆ HasStoredDocumentState()

virtual bool idoc::CSerializedUndoManagerComp::HasStoredDocumentState ( ) const
overrideprotectedvirtual

Check if there is stored document state available.

Returns
True if a document state has been stored and is available for comparison.

Implements idoc::IDocumentStateComparator.

◆ OnComponentDestroyed()

virtual void idoc::CSerializedUndoManagerComp::OnComponentDestroyed ( )
overrideprotectedvirtual

Reimplemented from icomp::CComponentBase.

◆ OnModelAttached()

virtual bool idoc::CSerializedUndoManagerComp::OnModelAttached ( imod::IModel modelPtr,
istd::IChangeable::ChangeSet changeMask 
)
overridevirtual

Callback invoked when an observable model is about to be attached to this observer.

This method is called by the model when attempting to establish an observer relationship. The implementation should:

  1. Validate that the model is of an acceptable type
  2. Set the changeMask to specify which changes to monitor
  3. Return true to accept the attachment, or false to reject it
Parameters
modelPtrPointer to the model object being attached. Never nullptr.
changeMaskOutput parameter where the observer specifies which change types it wants to be notified about. Set the appropriate change flags using changeMask.Set(changeId). An empty mask means the observer wants all changes.
Returns
true if the model is accepted and attachment succeeds, false to reject the attachment (e.g., if the model is of incompatible type).
Note
After successful attachment, the observer should initialize its state based on the current model data.
The changeMask allows filtering notifications for better performance. Only changes matching the mask will trigger AfterUpdate() calls.
virtual bool OnModelAttached(IModel* modelPtr,
{
// Type check
CMyModel* model = dynamic_cast<CMyModel*>(modelPtr);
if (!model) return false;
// Set up change filtering
changeMask.Set(CMyModel::CF_DATA_CHANGED);
changeMask.Set(CMyModel::CF_STATUS_CHANGED);
// Don't set CF_INTERNAL_CHANGED - we don't care about those
// Initialize view from current model state
UpdateViewFromModel(model);
return true;
}
virtual bool OnModelAttached(imod::IModel *modelPtr, istd::IChangeable::ChangeSet &changeMask) override
Callback invoked when an observable model is about to be attached to this observer.
See also
OnModelDetached(), IsModelAttached(), AfterUpdate()

Reimplemented from imod::TSingleModelObserverBase< iser::ISerializable >.

◆ OnModelDetached()

virtual bool idoc::CSerializedUndoManagerComp::OnModelDetached ( imod::IModel modelPtr)
overridevirtual

Callback invoked when an observable model is about to be detached from this observer.

This method is called when the observer-model relationship is being terminated, either explicitly or because the model is being destroyed. The implementation should clean up any state or resources related to this model.

Parameters
modelPtrPointer to the model object being detached
Returns
true if the detachment was handled successfully, false otherwise
Note
After this call, the observer should not access the model pointer anymore.
This method may be called even if OnModelAttached() previously returned false.
Clean up any cached data or references to this model.
virtual bool OnModelDetached(IModel* modelPtr)
{
if (m_currentModel == modelPtr) {
// Clear any cached data
m_cachedData.clear();
m_currentModel = nullptr;
// Update UI to show no model is attached
ClearDisplay();
return true;
}
return false;
}
virtual bool OnModelDetached(imod::IModel *modelPtr) override
Callback invoked when an observable model is about to be detached from this observer.
See also
OnModelAttached(), IsModelAttached()

Reimplemented from imod::TSingleModelObserverBase< iser::ISerializable >.

◆ ResetUndo()

virtual void idoc::CSerializedUndoManagerComp::ResetUndo ( )
overridevirtual

Reset all UNDO and REDO steps.

This clears the entire undo/redo history. Use with caution.

Implements idoc::IUndoManager.

◆ RestoreDocumentState()

virtual bool idoc::CSerializedUndoManagerComp::RestoreDocumentState ( )
overrideprotectedvirtual

Restore last stored document state.

Returns
True if state was successfully restored, false otherwise.

This reverts the document to the last stored state, effectively undoing all changes made since the state was stored.

Implements idoc::IDocumentStateComparator.

◆ StoreDocumentState()

virtual bool idoc::CSerializedUndoManagerComp::StoreDocumentState ( )
overrideprotectedvirtual

Store state of the document.

Returns
True if state was successfully stored, false otherwise.

This creates a snapshot of the current document state that can be used for comparison or restoration later.

Implements idoc::IDocumentStateComparator.


The documentation for this class was generated from the following file: