summaryrefslogtreecommitdiffstats
path: root/tk8.6/generic/tkUndo.c
diff options
context:
space:
mode:
Diffstat (limited to 'tk8.6/generic/tkUndo.c')
-rw-r--r--tk8.6/generic/tkUndo.c736
1 files changed, 0 insertions, 736 deletions
diff --git a/tk8.6/generic/tkUndo.c b/tk8.6/generic/tkUndo.c
deleted file mode 100644
index c66905d..0000000
--- a/tk8.6/generic/tkUndo.c
+++ /dev/null
@@ -1,736 +0,0 @@
-/*
- * tkUndo.c --
- *
- * This module provides the implementation of an undo stack.
- *
- * Copyright (c) 2002 by Ludwig Callewaert.
- * Copyright (c) 2003-2004 by Vincent Darley.
- *
- * See the file "license.terms" for information on usage and redistribution of
- * this file, and for a DISCLAIMER OF ALL WARRANTIES.
- */
-
-#include "tkInt.h"
-#include "tkUndo.h"
-
-static int EvaluateActionList(Tcl_Interp *interp,
- TkUndoSubAtom *action);
-
-/*
- *----------------------------------------------------------------------
- *
- * TkUndoPushStack --
- *
- * Push elem on the stack identified by stack.
- *
- * Results:
- * None.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
-
-void
-TkUndoPushStack(
- TkUndoAtom **stack,
- TkUndoAtom *elem)
-{
- elem->next = *stack;
- *stack = elem;
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * TkUndoPopStack --
- *
- * Remove and return the top element from the stack identified by stack.
- *
- * Results:
- * None.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
-
-TkUndoAtom *
-TkUndoPopStack(
- TkUndoAtom **stack)
-{
- TkUndoAtom *elem = NULL;
-
- if (*stack != NULL) {
- elem = *stack;
- *stack = elem->next;
- }
- return elem;
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * TkUndoInsertSeparator --
- *
- * Insert a separator on the stack, indicating a border for an undo/redo
- * chunk.
- *
- * Results:
- * None.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
-
-int
-TkUndoInsertSeparator(
- TkUndoAtom **stack)
-{
- TkUndoAtom *separator;
-
- if (*stack!=NULL && (*stack)->type!=TK_UNDO_SEPARATOR) {
- separator = ckalloc(sizeof(TkUndoAtom));
- separator->type = TK_UNDO_SEPARATOR;
- TkUndoPushStack(stack,separator);
- return 1;
- }
- return 0;
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * TkUndoClearStack --
- *
- * Clear an entire undo or redo stack and destroy all elements in it.
- *
- * Results:
- * None.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
-
-void
-TkUndoClearStack(
- TkUndoAtom **stack) /* An Undo or Redo stack */
-{
- TkUndoAtom *elem;
-
- while ((elem = TkUndoPopStack(stack)) != NULL) {
- if (elem->type != TK_UNDO_SEPARATOR) {
- TkUndoSubAtom *sub;
-
- sub = elem->apply;
- while (sub != NULL) {
- TkUndoSubAtom *next = sub->next;
-
- if (sub->action != NULL) {
- Tcl_DecrRefCount(sub->action);
- }
- ckfree(sub);
- sub = next;
- }
-
- sub = elem->revert;
- while (sub != NULL) {
- TkUndoSubAtom *next = sub->next;
-
- if (sub->action != NULL) {
- Tcl_DecrRefCount(sub->action);
- }
- ckfree(sub);
- sub = next;
- }
- }
- ckfree(elem);
- }
- *stack = NULL;
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * TkUndoPushAction --
- *
- * Push a new elem on the stack identified by stack. Action and revert
- * are given through Tcl_Obj's to which we will retain a reference. (So
- * they can be passed in with a zero refCount if desired).
- *
- * Results:
- * None.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
-
-void
-TkUndoPushAction(
- TkUndoRedoStack *stack, /* An Undo or Redo stack */
- TkUndoSubAtom *apply,
- TkUndoSubAtom *revert)
-{
- TkUndoAtom *atom;
-
- atom = ckalloc(sizeof(TkUndoAtom));
- atom->type = TK_UNDO_ACTION;
- atom->apply = apply;
- atom->revert = revert;
-
- TkUndoPushStack(&stack->undoStack, atom);
- TkUndoClearStack(&stack->redoStack);
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * TkUndoMakeCmdSubAtom --
- *
- * Create a new undo/redo step which must later be place into an undo
- * stack with TkUndoPushAction. This sub-atom, if evaluated, will take
- * the given command (if non-NULL), find its full Tcl command string, and
- * then evaluate that command with the list elements of 'actionScript'
- * appended.
- *
- * If 'subAtomList' is non-NULL, the newly created sub-atom is added onto
- * the end of the linked list of which 'subAtomList' is a part. This
- * makes it easy to build up a sequence of actions which will be pushed
- * in one step.
- *
- * Note: if the undo stack can persist for longer than the Tcl_Command
- * provided, the stack will cause crashes when actions are evaluated. In
- * this case the 'command' argument should not be used. This is the case
- * with peer text widgets, for example.
- *
- * Results:
- * The newly created subAtom is returned. It must be passed to
- * TkUndoPushAction otherwise a memory leak will result.
- *
- * Side effects:
- * A refCount is retained on 'actionScript'.
- *
- *----------------------------------------------------------------------
- */
-
-TkUndoSubAtom *
-TkUndoMakeCmdSubAtom(
- Tcl_Command command, /* Tcl command token for actions, may be NULL
- * if not needed. */
- Tcl_Obj *actionScript, /* The script to append to the command to
- * perform the action (may be NULL if the
- * command is not-null). */
- TkUndoSubAtom *subAtomList) /* Add to the end of this list of actions if
- * non-NULL */
-{
- TkUndoSubAtom *atom;
-
- if (command == NULL && actionScript == NULL) {
- Tcl_Panic("NULL command and actionScript in TkUndoMakeCmdSubAtom");
- }
-
- atom = ckalloc(sizeof(TkUndoSubAtom));
- atom->command = command;
- atom->funcPtr = NULL;
- atom->clientData = NULL;
- atom->next = NULL;
- atom->action = actionScript;
- if (atom->action != NULL) {
- Tcl_IncrRefCount(atom->action);
- }
-
- if (subAtomList != NULL) {
- while (subAtomList->next != NULL) {
- subAtomList = subAtomList->next;
- }
- subAtomList->next = atom;
- }
- return atom;
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * TkUndoMakeSubAtom --
- *
- * Create a new undo/redo step which must later be place into an undo
- * stack with TkUndoPushAction. This sub-atom, if evaluated, will take
- * the given C-funcPtr (which must be non-NULL), and call it with three
- * arguments: the undo stack's 'interp', the 'clientData' given and the
- * 'actionScript'. The callback should return a standard Tcl return code
- * (TCL_OK on success).
- *
- * If 'subAtomList' is non-NULL, the newly created sub-atom is added onto
- * the end of the linked list of which 'subAtomList' is a part. This
- * makes it easy to build up a sequence of actions which will be pushed
- * in one step.
- *
- * Results:
- * The newly created subAtom is returned. It must be passed to
- * TkUndoPushAction otherwise a memory leak will result.
- *
- * Side effects:
- * A refCount is retained on 'actionScript'.
- *
- *----------------------------------------------------------------------
- */
-
-TkUndoSubAtom *
-TkUndoMakeSubAtom(
- TkUndoProc *funcPtr, /* Callback function to perform the
- * undo/redo. */
- ClientData clientData, /* Data to pass to the callback function. */
- Tcl_Obj *actionScript, /* Additional Tcl data to pass to the callback
- * function (may be NULL). */
- TkUndoSubAtom *subAtomList) /* Add to the end of this list of actions if
- * non-NULL */
-{
- TkUndoSubAtom *atom;
-
- if (funcPtr == NULL) {
- Tcl_Panic("NULL funcPtr in TkUndoMakeSubAtom");
- }
-
- atom = ckalloc(sizeof(TkUndoSubAtom));
- atom->command = NULL;
- atom->funcPtr = funcPtr;
- atom->clientData = clientData;
- atom->next = NULL;
- atom->action = actionScript;
- if (atom->action != NULL) {
- Tcl_IncrRefCount(atom->action);
- }
-
- if (subAtomList != NULL) {
- while (subAtomList->next != NULL) {
- subAtomList = subAtomList->next;
- }
- subAtomList->next = atom;
- }
- return atom;
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * TkUndoInitStack --
- *
- * Initialize a new undo/redo stack.
- *
- * Results:
- * An Undo/Redo stack pointer.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
-
-TkUndoRedoStack *
-TkUndoInitStack(
- Tcl_Interp *interp, /* The interpreter */
- int maxdepth) /* The maximum stack depth */
-{
- TkUndoRedoStack *stack; /* An Undo/Redo stack */
-
- stack = ckalloc(sizeof(TkUndoRedoStack));
- stack->undoStack = NULL;
- stack->redoStack = NULL;
- stack->interp = interp;
- stack->maxdepth = maxdepth;
- stack->depth = 0;
- return stack;
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * TkUndoSetMaxDepth --
- *
- * Set the maximum depth of stack.
- *
- * Results:
- * None.
- *
- * Side effects:
- * May delete elements from the stack if the new maximum depth is smaller
- * than the number of elements previously in the stack.
- *
- *----------------------------------------------------------------------
- */
-
-void
-TkUndoSetMaxDepth(
- TkUndoRedoStack *stack, /* An Undo/Redo stack */
- int maxdepth) /* The maximum stack depth */
-{
- stack->maxdepth = maxdepth;
-
- if (stack->maxdepth>0 && stack->depth>stack->maxdepth) {
- TkUndoAtom *elem, *prevelem;
- int sepNumber = 0;
-
- /*
- * Maximum stack depth exceeded. We have to remove the last compound
- * elements on the stack.
- */
-
- elem = stack->undoStack;
- prevelem = NULL;
- while ((elem != NULL) && (sepNumber <= stack->maxdepth)) {
- if (elem->type == TK_UNDO_SEPARATOR) {
- sepNumber++;
- }
- prevelem = elem;
- elem = elem->next;
- }
- CLANG_ASSERT(prevelem);
- prevelem->next = NULL;
- while (elem != NULL) {
- prevelem = elem;
- if (elem->type != TK_UNDO_SEPARATOR) {
- TkUndoSubAtom *sub = elem->apply;
- while (sub != NULL) {
- TkUndoSubAtom *next = sub->next;
-
- if (sub->action != NULL) {
- Tcl_DecrRefCount(sub->action);
- }
- ckfree(sub);
- sub = next;
- }
- sub = elem->revert;
- while (sub != NULL) {
- TkUndoSubAtom *next = sub->next;
-
- if (sub->action != NULL) {
- Tcl_DecrRefCount(sub->action);
- }
- ckfree(sub);
- sub = next;
- }
- }
- elem = elem->next;
- ckfree(prevelem);
- }
- stack->depth = stack->maxdepth;
- }
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * TkUndoClearStacks --
- *
- * Clear both the undo and redo stack.
- *
- * Results:
- * None.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
-
-void
-TkUndoClearStacks(
- TkUndoRedoStack *stack) /* An Undo/Redo stack */
-{
- TkUndoClearStack(&stack->undoStack);
- TkUndoClearStack(&stack->redoStack);
- stack->depth = 0;
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * TkUndoFreeStack
- *
- * Clear both the undo and redo stack and free the memory allocated to
- * the u/r stack pointer.
- *
- * Results:
- * None.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
-
-void
-TkUndoFreeStack(
- TkUndoRedoStack *stack) /* An Undo/Redo stack */
-{
- TkUndoClearStacks(stack);
- ckfree(stack);
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * TkUndoCanRedo --
- *
- * Returns true if redo is possible, i.e. if the redo stack is not empty.
- *
- * Results:
- * A boolean.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
-
-int
-TkUndoCanRedo(
- TkUndoRedoStack *stack) /* An Undo/Redo stack */
-{
- return stack->redoStack != NULL;
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * TkUndoCanUndo --
- *
- * Returns true if undo is possible, i.e. if the undo stack is not empty.
- *
- * Results:
- * A boolean.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
-
-int
-TkUndoCanUndo(
- TkUndoRedoStack *stack) /* An Undo/Redo stack */
-{
- return stack->undoStack != NULL;
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * TkUndoInsertUndoSeparator --
- *
- * Insert a separator on the undo stack, indicating a border for an
- * undo/redo chunk.
- *
- * Results:
- * None.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
-
-void
-TkUndoInsertUndoSeparator(
- TkUndoRedoStack *stack)
-{
- if (TkUndoInsertSeparator(&stack->undoStack)) {
- stack->depth++;
- TkUndoSetMaxDepth(stack, stack->maxdepth);
- }
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * TkUndoRevert --
- *
- * Undo a compound action on the stack.
- *
- * Results:
- * A Tcl status code
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
-
-int
-TkUndoRevert(
- TkUndoRedoStack *stack)
-{
- TkUndoAtom *elem;
-
- /*
- * Insert a separator on the undo and the redo stack.
- */
-
- TkUndoInsertUndoSeparator(stack);
- TkUndoInsertSeparator(&stack->redoStack);
-
- /*
- * Pop and skip the first separator if there is one.
- */
-
- elem = TkUndoPopStack(&stack->undoStack);
- if (elem == NULL) {
- return TCL_ERROR;
- }
-
- if (elem->type == TK_UNDO_SEPARATOR) {
- ckfree(elem);
- elem = TkUndoPopStack(&stack->undoStack);
- }
-
- while (elem != NULL && elem->type != TK_UNDO_SEPARATOR) {
- /*
- * Note that we currently ignore errors thrown here.
- */
-
- EvaluateActionList(stack->interp, elem->revert);
-
- TkUndoPushStack(&stack->redoStack, elem);
- elem = TkUndoPopStack(&stack->undoStack);
- }
-
- /*
- * Insert a separator on the redo stack.
- */
-
- TkUndoInsertSeparator(&stack->redoStack);
- stack->depth--;
- return TCL_OK;
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * TkUndoApply --
- *
- * Redo a compound action on the stack.
- *
- * Results:
- * A Tcl status code
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
-
-int
-TkUndoApply(
- TkUndoRedoStack *stack)
-{
- TkUndoAtom *elem;
-
- /*
- * Insert a separator on the undo stack.
- */
-
- TkUndoInsertSeparator(&stack->undoStack);
-
- /*
- * Pop and skip the first separator if there is one.
- */
-
- elem = TkUndoPopStack(&stack->redoStack);
- if (elem == NULL) {
- return TCL_ERROR;
- }
-
- if (elem->type == TK_UNDO_SEPARATOR) {
- ckfree(elem);
- elem = TkUndoPopStack(&stack->redoStack);
- }
-
- while (elem != NULL && elem->type != TK_UNDO_SEPARATOR) {
- /*
- * Note that we currently ignore errors thrown here.
- */
-
- EvaluateActionList(stack->interp, elem->apply);
-
- TkUndoPushStack(&stack->undoStack, elem);
- elem = TkUndoPopStack(&stack->redoStack);
- }
-
- /*
- * Insert a separator on the undo stack.
- */
-
- TkUndoInsertSeparator(&stack->undoStack);
- stack->depth++;
- return TCL_OK;
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * EvaluateActionList --
- *
- * Execute a linked list of undo/redo sub-atoms. If any sub-atom returns
- * a non TCL_OK value, execution of subsequent sub-atoms is cancelled and
- * the error returned immediately.
- *
- * Results:
- * A Tcl status code
- *
- * Side effects:
- * The undo/redo subAtoms can perform arbitrary actions.
- *
- *----------------------------------------------------------------------
- */
-
-static int
-EvaluateActionList(
- Tcl_Interp *interp, /* Interpreter to evaluate the action in. */
- TkUndoSubAtom *action) /* Head of linked list of action steps to
- * perform. */
-{
- int result = TCL_OK;
-
- while (action != NULL) {
- if (action->funcPtr != NULL) {
- result = action->funcPtr(interp, action->clientData,
- action->action);
- } else if (action->command != NULL) {
- Tcl_Obj *cmdNameObj, *evalObj;
-
- cmdNameObj = Tcl_NewObj();
- evalObj = Tcl_NewObj();
- Tcl_IncrRefCount(evalObj);
- Tcl_GetCommandFullName(interp, action->command, cmdNameObj);
- Tcl_ListObjAppendElement(NULL, evalObj, cmdNameObj);
- if (action->action != NULL) {
- Tcl_ListObjAppendList(NULL, evalObj, action->action);
- }
- result = Tcl_EvalObjEx(interp, evalObj, TCL_EVAL_GLOBAL);
- Tcl_DecrRefCount(evalObj);
- } else {
- result = Tcl_EvalObjEx(interp, action->action, TCL_EVAL_GLOBAL);
- }
- if (result != TCL_OK) {
- return result;
- }
- action = action->next;
- }
- return result;
-}
-
-/*
- * Local Variables:
- * mode: c
- * c-basic-offset: 4
- * fill-column: 78
- * End:
- */