Main Page   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members

FXUndoList.h

Go to the documentation of this file.
00001 /********************************************************************************
00002 *                                                                               *
00003 *                  U n d o / R e d o - a b l e   C o m m a n d                  *
00004 *                                                                               *
00005 *********************************************************************************
00006 * Copyright (C) 2000,2009 by Jeroen van der Zijp.   All Rights Reserved.        *
00007 *********************************************************************************
00008 * This library is free software; you can redistribute it and/or modify          *
00009 * it under the terms of the GNU Lesser General Public License as published by   *
00010 * the Free Software Foundation; either version 3 of the License, or             *
00011 * (at your option) any later version.                                           *
00012 *                                                                               *
00013 * This library is distributed in the hope that it will be useful,               *
00014 * but WITHOUT ANY WARRANTY; without even the implied warranty of                *
00015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the                 *
00016 * GNU Lesser General Public License for more details.                           *
00017 *                                                                               *
00018 * You should have received a copy of the GNU Lesser General Public License      *
00019 * along with this program.  If not, see <http://www.gnu.org/licenses/>          *
00020 *********************************************************************************
00021 * $Id: FXUndoList.h,v 1.45 2009/01/06 13:07:29 fox Exp $                        *
00022 ********************************************************************************/
00023 #ifndef FXUNDOLIST_H
00024 #define FXUNDOLIST_H
00025 
00026 #ifndef FXOBJECT_H
00027 #include "FXObject.h"
00028 #endif
00029 
00030 namespace FX {
00031 
00032 
00033 class FXUndoList;
00034 class FXCommandGroup;
00035 
00036 
00037 /**
00038 * Base class for undoable commands.  Each undo records all the
00039 * information necessary to undo as well as redo a given operation.
00040 * Since commands are derived from FXObject, subclassed commands can
00041 * both send and receive messages (like ID_GETINTVALUE, for example).
00042 */
00043 class FXAPI FXCommand : public FXObject {
00044   FXDECLARE_ABSTRACT(FXCommand)
00045   friend class FXUndoList;
00046   friend class FXCommandGroup;
00047 private:
00048   FXCommand *next;
00049 private:
00050   FXCommand(const FXCommand&);
00051   FXCommand &operator=(const FXCommand&);
00052 protected:
00053   FXCommand():next(NULL){}
00054 public:
00055 
00056   /**
00057   * Undo this command; this should save the
00058   * information for a subsequent redo.
00059   */
00060   virtual void undo() = 0;
00061 
00062   /**
00063   * Redo this command; this should save the
00064   * information for a subsequent undo.
00065   */
00066   virtual void redo() = 0;
00067 
00068   /**
00069   * Return the size of the information in the undo record.
00070   * The undo list may be trimmed to limit memory usage to
00071   * a certain limit.  The value returned should include
00072   * the size of the command record itself as well as any
00073   * data linked from it.
00074   */
00075   virtual FXuint size() const;
00076 
00077   /**
00078   * Name of the undo command to be shown on a button;
00079   * for example, "Undo Delete".
00080   */
00081   virtual FXString undoName() const;
00082 
00083   /**
00084   * Name of the redo command to be shown on a button;
00085   * for example, "Redo Delete".
00086   */
00087   virtual FXString redoName() const;
00088 
00089   /**
00090   * Return true if this command can be merged with previous undo
00091   * commands.  This is useful to combine e.g. multiple consecutive
00092   * single-character text changes into a single block change.
00093   * The default implementation returns false.
00094   */
00095   virtual FXbool canMerge() const;
00096 
00097   /**
00098   * Called by the undo system to try and merge the new incoming command
00099   * with this command; should return true if merging was possible.
00100   * The default implementation returns false.
00101   */
00102   virtual FXbool mergeWith(FXCommand* command);
00103 
00104   /// Delete undo command
00105   virtual ~FXCommand(){}
00106   };
00107 
00108 
00109 
00110 /**
00111 * Group of undoable commands.  A group may comprise multiple
00112 * individual actions which together undo (or redo) a larger
00113 * operation.  Even larger operations may be built by nesting
00114 * multiple undo groups.
00115 */
00116 class FXAPI FXCommandGroup : public FXCommand {
00117   FXDECLARE(FXCommandGroup)
00118   friend class FXUndoList;
00119 private:
00120   FXCommand      *undolist;
00121   FXCommand      *redolist;
00122   FXCommandGroup *group;
00123 private:
00124   FXCommandGroup(const FXCommandGroup&);
00125   FXCommandGroup &operator=(const FXCommandGroup&);
00126 public:
00127 
00128   /// Construct initially empty undo command group
00129   FXCommandGroup():undolist(NULL),redolist(NULL),group(NULL){}
00130 
00131   /// Return true if empty
00132   FXbool empty(){ return !undolist; }
00133 
00134   /// Undo whole command group
00135   virtual void undo();
00136 
00137   /// Redo whole command group
00138   virtual void redo();
00139 
00140   /// Return the size of the command group
00141   virtual FXuint size() const;
00142 
00143   /// Delete undo command and sub-commands
00144   virtual ~FXCommandGroup();
00145   };
00146 
00147 
00148 
00149 /**
00150 * The Undo List class manages a list of undoable commands.
00151 */
00152 class FXAPI FXUndoList : public FXCommandGroup {
00153   FXDECLARE(FXUndoList)
00154 private:
00155   FXint      undocount;     // Number of undo records
00156   FXint      redocount;     // Number of redo records
00157   FXint      marker;        // Marker value
00158   FXuint     space;         // Space taken up by all the undo records
00159   FXbool     working;       // Currently busy with undo or redo
00160 private:
00161   FXUndoList(const FXUndoList&);
00162   FXUndoList &operator=(const FXUndoList&);
00163 public:
00164   long onCmdUndo(FXObject*,FXSelector,void*);
00165   long onUpdUndo(FXObject*,FXSelector,void*);
00166   long onCmdRedo(FXObject*,FXSelector,void*);
00167   long onUpdRedo(FXObject*,FXSelector,void*);
00168   long onCmdClear(FXObject*,FXSelector,void*);
00169   long onUpdClear(FXObject*,FXSelector,void*);
00170   long onCmdRevert(FXObject*,FXSelector,void*);
00171   long onUpdRevert(FXObject*,FXSelector,void*);
00172   long onCmdUndoAll(FXObject*,FXSelector,void*);
00173   long onCmdRedoAll(FXObject*,FXSelector,void*);
00174   long onUpdUndoCount(FXObject*,FXSelector,void*);
00175   long onUpdRedoCount(FXObject*,FXSelector,void*);
00176 public:
00177   enum{
00178     ID_CLEAR=FXWindow::ID_LAST,
00179     ID_REVERT,
00180     ID_UNDO,
00181     ID_REDO,
00182     ID_UNDO_ALL,
00183     ID_REDO_ALL,
00184     ID_UNDO_COUNT,
00185     ID_REDO_COUNT,
00186     ID_LAST
00187     };
00188 public:
00189 
00190   /**
00191   * Make new empty undo list, initially unmarked.
00192   */
00193   FXUndoList();
00194 
00195   /**
00196   * Cut the redo list.
00197   * This is automatically invoked when a new undo command is added.
00198   */
00199   void cut();
00200 
00201   /**
00202   * Add new command, executing it if desired. The new command will be merged
00203   * with the previous command if merge is true and we're not at a marked position
00204   * and the commands are mergeable.  Otherwise the new command will be appended
00205   * after the last undo command in the currently active undo group.
00206   * If the new command is successfully merged, it will be deleted.  Furthermore,
00207   * all redo commands will be deleted since it is no longer possible to redo
00208   * from this point.
00209   */
00210   void add(FXCommand* command,FXbool doit=false,FXbool merge=true);
00211 
00212   /**
00213   * Begin undo command sub-group. This begins a new group of commands that
00214   * are treated as a single command.  Must eventually be followed by a
00215   * matching end() after recording the sub-commands.  The new sub-group
00216   * will be appended to its parent group's undo list when end() is called.
00217   */
00218   void begin(FXCommandGroup *command);
00219 
00220   /**
00221   * End undo command sub-group.  If the sub-group is still empty, it will
00222   * be deleted; otherwise, the sub-group will be added as a new command
00223   * into parent group.
00224   * A matching begin() must have been called previously.
00225   */
00226   void end();
00227 
00228   /**
00229   * Abort the current command sub-group being compiled.  All commands
00230   * already added to the sub-groups undo list will be discarded.
00231   * Intermediate command groups will be left intact.
00232   */
00233   void abort();
00234 
00235   /**
00236   * Undo last command. This will move the command to the redo list.
00237   */
00238   virtual void undo();
00239 
00240   /**
00241   * Redo next command. This will move the command back to the undo list.
00242   */
00243   virtual void redo();
00244 
00245   /// Undo all commands
00246   void undoAll();
00247 
00248   /// Redo all commands
00249   void redoAll();
00250 
00251   /// Revert to marked
00252   void revert();
00253 
00254   /// Can we undo more commands
00255   FXbool canUndo() const;
00256 
00257   /// Can we redo more commands
00258   FXbool canRedo() const;
00259 
00260   /// Can revert to marked
00261   FXbool canRevert() const;
00262 
00263   /**
00264   * Return true if currently inside undo or redo operation; this
00265   * is useful to avoid generating another undo command while inside
00266   * an undo operation.
00267   */
00268   FXbool busy() const { return working; }
00269 
00270   /// Current top level undo command
00271   FXCommand* current() const { return undolist; }
00272 
00273   /**
00274   * Return name of the first undo command available; if no
00275   * undo command available this will return the empty string.
00276   */
00277   virtual FXString undoName() const;
00278 
00279   /**
00280   * Return name of the first redo command available; if no
00281   * Redo command available this will return the empty string.
00282   */
00283   virtual FXString redoName() const;
00284 
00285   /// Number of undo records
00286   FXint undoCount() const { return undocount; }
00287 
00288   /// Number of redo records
00289   FXint redoCount() const { return redocount; }
00290 
00291   /// Size of undo information
00292   virtual FXuint size() const;
00293 
00294   /**
00295   * Clear list, and unmark all states.
00296   * All undo and redo information will be destroyed.
00297   */
00298   void clear();
00299 
00300   /**
00301   * Trim undo list down to at most nc commands.
00302   * Call this periodically to prevent the undo-list from growing
00303   * beyond a certain number of records.
00304   */
00305   void trimCount(FXint nc);
00306 
00307   /**
00308   * Trim undo list down to at most size sz.
00309   * Call this periodically to prevent the undo-list from growing
00310   * beyond a certain amount of memory.
00311   */
00312   void trimSize(FXuint sz);
00313 
00314   /**
00315   * Mark the current state of the undo list, which is initially unmarked.
00316   * There can be only one active mark at any time.  Call mark() at any
00317   * time when you know the document to be "clean"; for example when you
00318   * save the document to disk.
00319   */
00320   void mark();
00321 
00322   /**
00323   * Unmark all states in the undo list.
00324   */
00325   void unmark();
00326 
00327   /**
00328   * Check if the current state was marked, if the application has returned
00329   * to the previously marked state.
00330   */
00331   FXbool marked() const;
00332   };
00333 
00334 
00335 }
00336 
00337 #endif

Copyright © 1997-2009 Jeroen van der Zijp