Dia's Undo System
Dia's Undo system uses a stack of Change objects that each describe how to undo/redo an action and provide a way to free the object. These objects typically contain some state information about the action, such as a pointer to a deleted object, a text entered or a set of properties changed. Note that there may be required information both for undoing and for redoing.
The core of the undo system is defined in app/undo.c and app/undo.h. In particular, app/undo.h defines the following types:
typedef void (*UndoApplyFunc)(Change *change, Diagram *dia); typedef void (*UndoRevertFunc)(Change *change, Diagram *dia); typedef void (*UndoFreeFunc)(Change *change); struct _Change { /* If apply == transaction_point_pointer then this is a transaction point */ UndoApplyFunc apply; UndoRevertFunc revert; UndoFreeFunc free; /* Remove extra data. Then this object is freed */ Change *prev, *next; };
dia-types.h defines Change to be the same as struct _Change.
The prev and next pointers should never be used outside of app/undo.c.
Defining Change objects
Example
This is the undo definition for reordering objects (i.e. moving them up/down in the layer):
/******** Reorder object list: */ struct ReorderObjectsChange { Change change; Layer *layer; GList *changed_list; /* Owning reference when applied */ GList *original_objects; GList *reordered_objects; }; static void reorder_objects_apply(struct ReorderObjectsChange *change, Diagram *dia) { DEBUG_PRINTF(("reorder_objects_apply()\n")); layer_set_object_list(change->layer, g_list_copy(change->reordered_objects)); object_add_updates_list(change->changed_list, dia); } static void reorder_objects_revert(struct ReorderObjectsChange *change, Diagram *dia) { DEBUG_PRINTF(("reorder_objects_revert()\n")); layer_set_object_list(change->layer, g_list_copy(change->original_objects)); object_add_updates_list(change->changed_list, dia); } static void reorder_objects_free(struct ReorderObjectsChange *change) { DEBUG_PRINTF(("reorder_objects_free()\n")); g_list_free(change->changed_list); g_list_free(change->original_objects); g_list_free(change->reordered_objects); } Change * undo_reorder_objects(Diagram *dia, GList *changed_list, GList *orig_list) { struct ReorderObjectsChange *change; change = g_new0(struct ReorderObjectsChange, 1); change->change.apply = (UndoApplyFunc) reorder_objects_apply; change->change.revert = (UndoRevertFunc) reorder_objects_revert; change->change.free = (UndoFreeFunc) reorder_objects_free; change->layer = dia->data->active_layer; change->changed_list = changed_list; change->original_objects = orig_list; change->reordered_objects = g_list_copy(dia->data->active_layer->objects); DEBUG_PRINTF(("UNDO: Push new reorder objects at %d\n", depth(dia->undo))); undo_push_change(dia->undo, (Change *) change); return (Change *)change; }