UndoEngine

The UndoEngine allows you to install Multiple Undo in your Application. It is RAM-effective, because it saves only the items that really have changed. It is objectoriented, as it communicates directly with the objects of your application. And it is also an example on how to use Class Interfaces. As a plus, provides you a method to store your document in a file.

Download class and sample project
http://www.belle-nuit.com/download/undoengine.sit.hqx

UndoEngine works with REALBasic 2.1 or later. In conjunction with the Undoable Object Interface Class it is self-contained and works with both 68k and PowerPC. It should work on Windows, but it hasn't been tested for.

How it works

Install the UndoEngine class and the UndoableObject Class interface in your project.

Define every class you want to be able to undo as subclass of the UndoableObject Class Interface. (If you are not already working with subclasses of the windows controls, subclass them, so that you can make them subclasses of the Undoable Object Class Interface.)

Every class has to provide two methods:

Backup() as RAMstream

Write a function which collects the values of your object before they have changed. You may have to define and use oldvalue-properties on every changement because the user may have changed the value before you can call the undo-backup.

Look at the RAMstream-page to know more about RAMstream.

Restore(bak as RAMstream)

Write a method which reassigns the values from the RAMstream to the object.

Install an instance of the UndoEngine on the document window or in the application subclass.

Methods

UndoEngine(max as integer)

Defines the number of multiple undos. Max must not be 0 or negative.

Backup(label as string, obj as UndoableObject)

Undo

Redo

UndoLabel() as string

Returns the label which was provided when the Backup method was called. Is emty, if Undo is not available.

RedoLabel() as string

Returns the label which was provided when the Backup method was called. Is emty, if Redo is not available.

Reset

Resets the undo. You may choose this method when saving your document, if you want to prevent the user to undo.

Function About() as string

Returns an about-string of the class.

Function Methods() as string

Returns a string with the definitions of the methods.

Function Properties() as string

Returns a string with the definitions of the properties.

Function Version() as string

Returns the current version of the class.

Properties

This class does not have any property. Providing it as a class however frees you of problems of namespace in your application. If you need to access to it from the whole program, make it a property of your app-subclass. In a multiple-document Application, however, you may want to install the class on the document level.

Technical comments

This class uses RAMstreams for different reasons:

On demand, I could provide a class which works with strings or with memoryblocks.

The sample project shows also an example for undoing an editfield. If you are working on bigger texts, backup and restore the whole text of the editfield may not be the fastest solution. You may want to design a backup function which only saves the changes and a restore method which is able to reconstruct the editfield.

If you create and destroy instances dynamically, you may want to backup at the creation and destruction not the created object but the holder of the object. For example, if you have a drawing application with circles and rectangles, you may backup the circle when it changes its size and its color, but the window, when the circle is created or destroyed. Also, when the user changes multiple circles (a selection) at once, you may back up more the window than one circle at a time. Be aware also, that destroyed objects will not be destroyed immediately, because they have a reference, as long as they are undoable.

The sample application

For every class we use (or subclass of a generic rectcontrol) we implement the backup and restore methods. Also, we need a UndoEngine instance in the Window

Now the real work begins. Everytime, when an object is about to change, we are calling the UndoEngine for a backup. The problem is that we have to intercept before the parameters of the object have been changed. There are different cases

The Backup/Restore methods can be used for the document structure. On saving, a method collects all RAMstreams with backup and writes them to a binarystream. and on opening, a method distributes the RAMstreams and distributes them to the objects. The RAMstreams are saved as tagged records with the following structure

  1. A unique four caracter identifier of the object
  2. A long integer defining the length of the following RAMstream
  3. The RAMstream itself

This method gives you flexibility in further extensions of the document structure. File readers won't expect a particular order of the object being saved. Also, file readers can easily ignore the record if they can't handle the object.

Terms of use / Disclaimer

© Belle Nuit Montage / Matthias Bürcher April 2000. All rights reserved. Written in Switzerland.

This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA

Comments please to matti@belle-nuit.com

The latest version is available at http//www.belle-nuit.com/

History

8.6.00 Released as open source

6.5.00 Sample project updated with version 1.1 of RAMstream

22.4.00 Release UndoEngine 1.0