Click here to Skip to main content
15,884,628 members
Articles / Programming Languages / C++

A Simple, Action Based, Undo/Redo Framework

Rate me:
Please Sign up or sign in to vote.
4.51/5 (38 votes)
16 Feb 2013CPOL5 min read 97.3K   1.9K   104  
How to use a simple, action based, undo/redo framework
/*
***************************************************************************

kis v 1

(c) 2002-2006, Florin DUMITRESCU

mailto: fdproxy@gmail.com

$Workfile: kis_Action.h $ 

***************************************************************************
*/


#ifndef _KIS_ACTION_H_
#define _KIS_ACTION_H_


KIS_BEG


//-------------------------------------------------------------------------
/** Shortcuts */
typedef C_SharedPtr< class C_Action > SP_Action;
typedef C_SharedPtr< class C_ActionExecutor > SP_ActionExecutor;


//-------------------------------------------------------------------------
/** A C_Action derived class encapsulates user requests.
    
An action cannot be directly executed/un-executed/re-executed. 
You can execute it through an action executor (see 
C_ActionExecutor). */ 
class KIS_API C_Action
{

public:

  /** The AddRef method increments the reference count.*/
  virtual unsigned long AddRef() = 0;

  /** The Release method decrements the reference count. If the 
  reference count falls to 0, the action is freed from memory. */
  virtual unsigned long Release() = 0;

protected:

  /** Protected destructor. */
  virtual ~C_Action() = 0 {}

  /** The Clone method creates a copy of the current action. The 
  reference counter is set to zero. The caller must call AddRef 
  on copy. */
  virtual SP_Action Clone() const = 0;

  /** The IsUnexecutable method returns true if the action can be 
  un-executed and re-executed. Certain actions cannot be 
  unexecuted (opening a file in Microsoft Word, for instance). 
  For most action classes this is a per class behavior, not 
  per object. If the action is not un-executable then it is not 
  re-executable also. */
  virtual bool IsUnexecutable() const = 0;

  /** The IsNull method returns true if executing the action 
  will produce no effect on target. For instance: changing the 
  selected text "abc", in an editor, to "abc". */
  virtual bool IsNull() const = 0;

  /** The HasInput method returns true if the data (parameters) 
  required to execute the action has been collected. The start 
  and end point of a segment, for instance. */
  virtual bool HasInput() const = 0;

  /** The AcquireInput collects data (parameters) required by the 
  action for execution. Returns false if the collecting process 
  was cancelled. */
  virtual bool AcquireInput() = 0;

  /** The Execute method executes the action. Returns false if 
  the action was canceled. Canceling an action is not an error. 
  Use exceptions for errors. */
  virtual bool Execute() = 0;

  /** The HasUnexecute method returns true if the un-execute 
  information was built. Un-execute information must be available 
  immediately after execution. Un-execute information may not 
  exists after execution (memory could not be allocated, for 
  instance). If the action IsUnexecutable but un-execute information 
  is not present after execution then the action is not stored in 
  the history memory. */
  virtual bool HasUnexecute() const = 0;

  /** The Unexecute method un-executes the action. Un-execute 
  should not be called before Execute (the un-execute information 
  was not built yet). */
  virtual void Unexecute() = 0;

  /** The HasReexecute method returns true if re-execute 
  information was built. Re-execute information ought to be 
  available immediately after un-execute. Execute information may 
  not exists after un-execution. */
  virtual bool HasReexecute() const = 0;

  /** The Reexecute method re-executes an un-executed action. The 
  action was executed and then un-executed. To get it back to after 
  execute state Reexecute must be called. */
  virtual void Reexecute() = 0;

  /** The GetName method returns the name of the action. The name 
  is truncated to a_MaxNameLen bytes. The name may depend on 
  current state of action. For instance the name returned by 
  GetName for an insert character action may be "Insert Character" 
  before execution and "Insert Character 'c' at Line 3, Column 5" 
  after the action has been executed. */
  virtual void GetName( unsigned char* a_Name, const unsigned char a_MaxNameLen ) const = 0;

  /** The GetBytesCount method returns the number of bytes used 
  by action object. This number might be, but it is not necessarily, 
  the result of sizeof operator; it should count the free store 
  allocated bytes too. The more accurate the result is the more 
  accurate the history memory usage will be estimated. */
  virtual unsigned int GetBytesCount() const = 0;

};


//-------------------------------------------------------------------------
/** An action cannot be directly executed. You can execute it 
thru an action executor. The main responsibility of the action 
executor is to manage the history memory. */ 
class KIS_API C_ActionExecutor
{

public:

  /** The AddRef method increments the reference count.*/
  virtual unsigned long AddRef() = 0;

  /** The Release method decrements the reference count. If the 
  reference count falls to 0, the action is freed from memory. */
  virtual unsigned long Release() = 0;

  /** The SetMaxBytesCount sets the maximum number of bytes the 
  history memory may use. If the maximum number of bytes is set 
  to zero then the history memory is disabled. */
  virtual void SetMaxBytesCount( unsigned int a_MaxBytesCount ) = 0;

  /** The GetMaxBytesCount method returns the maximum number of 
  bytes the history memory may use. Returns zero if the history 
  memory is disabled. */
  virtual unsigned int GetMaxBytesCount() const = 0;

  /** The Execute method executes the a_spAction action. */
  virtual void Execute( const SP_Action a_spAction ) = 0;

  /** The Unexecute method un-executes the last a_ActionsCount 
  executed actions. */
  virtual void Unexecute( const unsigned int a_ActionsCount ) = 0;

  /** The GetUnexecuteCount method returns the number of actions 
  stored in the un-execute memory. */
  virtual unsigned int GetUnexecuteCount() const = 0;

  /** The GetUnexecuteName method returns the name of the action 
  in the un-execute memory located at index a_Idx. The top most 
  action is located at index 0. */
  virtual void GetUnexecuteName( unsigned char* a_Name, const unsigned char a_MaxNameLen, const unsigned int a_Idx ) const = 0;

  /** The Reexecute method re-executes the last a_ActionsCount 
  un-executed actions. */
  virtual void Reexecute( const unsigned int a_ActionsCount ) = 0;

  /** The GetReexecuteCount method returns the number of actions 
  stored in the re-execute memory. */
  virtual unsigned int GetReexecuteCount() const = 0;

  /** The GetReexecuteName method returns the name of the action 
  in the re-execute memory located at index a_Idx. The top most 
  action is located at index 0. */
  virtual void GetReexecuteName( unsigned char* a_Name, const unsigned char a_MaxNameLen, const unsigned int a_Idx ) const = 0;

protected:

  /** Protected destructor. */
  virtual ~C_ActionExecutor() = 0 {}

};


//-------------------------------------------------------------------------
/** CreateActionExecutor_Default function creates a default 
action executor. */ 
KIS_API SP_ActionExecutor CreateActionExecutor_Default();


KIS_END


#endif _KIS_ACTION_H_

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
zdf
Romania Romania
Just a humble programmer.

Comments and Discussions