tkUndo.c
上传用户:rrhhcc
上传日期:2015-12-11
资源大小:54129k
文件大小:8k
源码类别:

通讯编程

开发平台:

Visual C++

  1. /* 
  2.  * tkUndo.c --
  3.  *
  4.  * This module provides the implementation of an undo stack.
  5.  *
  6.  * Copyright (c) 2002 by Ludwig Callewaert.
  7.  *
  8.  * See the file "license.terms" for information on usage and redistribution
  9.  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  10.  *
  11.  * RCS: @(#) $Id: tkUndo.c,v 1.1.4.2 2006/03/20 22:16:34 dkf Exp $
  12.  */
  13. #include "tkUndo.h"
  14. /*
  15.  * TkUndoPushStack
  16.  *    Push elem on the stack identified by stack.
  17.  *
  18.  * Results:
  19.  *    None
  20.  *
  21.  * Side effects:
  22.  *    None.
  23.  */
  24.  
  25. void TkUndoPushStack ( stack, elem )
  26.     TkUndoAtom ** stack;
  27.     TkUndoAtom *  elem;
  28.     elem->next = *stack;
  29.     *stack = elem;
  30. }
  31. /*
  32.  * TkUndoPopStack --
  33.  *    Remove and return the top element from the stack identified by 
  34.  *      stack.
  35.  *
  36.  * Results:
  37.  *    None
  38.  *
  39.  * Side effects:
  40.  *    None.
  41.  */
  42.  
  43. TkUndoAtom * TkUndoPopStack ( stack )
  44.     TkUndoAtom ** stack ;
  45.     TkUndoAtom * elem = NULL;
  46.     if (*stack != NULL ) {
  47.         elem   = *stack;
  48.         *stack = elem->next;
  49.     }
  50.     return elem;
  51. }
  52. /*
  53.  * TkUndoInsertSeparator --
  54.  *    insert a separator on the stack, indicating a border for
  55.  *      an undo/redo chunk.
  56.  *
  57.  * Results:
  58.  *    None
  59.  *
  60.  * Side effects:
  61.  *    None.
  62.  */
  63.  
  64. int TkUndoInsertSeparator ( stack )
  65.     TkUndoAtom ** stack;
  66. {
  67.     TkUndoAtom * separator;
  68.     if ( *stack != NULL && (*stack)->type != TK_UNDO_SEPARATOR ) {
  69.         separator = (TkUndoAtom *) ckalloc(sizeof(TkUndoAtom));
  70.         separator->type = TK_UNDO_SEPARATOR;
  71.         TkUndoPushStack(stack,separator);
  72.         return 1;
  73.     } else {
  74.         return 0;
  75.     }
  76. }
  77. /*
  78.  * TkUndoClearStack --
  79.  *    Clear an entire undo or redo stack and destroy all elements in it.
  80.  *
  81.  * Results:
  82.  *    None
  83.  *
  84.  * Side effects:
  85.  *    None.
  86.  */
  87. void TkUndoClearStack ( stack )
  88.     TkUndoAtom ** stack;      /* An Undo or Redo stack */
  89. {
  90.     TkUndoAtom * elem;
  91.     while ( (elem = TkUndoPopStack(stack)) ) {
  92.         if ( elem->type != TK_UNDO_SEPARATOR ) {
  93.             Tcl_DecrRefCount(elem->apply);
  94.             Tcl_DecrRefCount(elem->revert);
  95.         }
  96.         ckfree((char *)elem);
  97.     }
  98.     *stack = NULL;
  99. }
  100. /*
  101.  * TkUndoPushAction
  102.  *    Push a new elem on the stack identified by stack.
  103.  *    action and revert are given through Tcl_DStrings
  104.  *
  105.  * Results:
  106.  *    None
  107.  *
  108.  * Side effects:
  109.  *    None.
  110.  */
  111.  
  112. void TkUndoPushAction ( stack, actionScript, revertScript )
  113.     TkUndoRedoStack * stack;      /* An Undo or Redo stack */
  114.     Tcl_DString * actionScript; /* The script to get the action (redo) */
  115.     Tcl_DString * revertScript; /* The script to revert the action (undo) */
  116.     TkUndoAtom * atom;
  117.     atom = (TkUndoAtom *) ckalloc(sizeof(TkUndoAtom));
  118.     atom->type = TK_UNDO_ACTION;
  119.     atom->apply = Tcl_NewStringObj(Tcl_DStringValue(actionScript),Tcl_DStringLength(actionScript));
  120.     Tcl_IncrRefCount(atom->apply);
  121.     atom->revert = Tcl_NewStringObj(Tcl_DStringValue(revertScript),Tcl_DStringLength(revertScript));
  122.     Tcl_IncrRefCount(atom->revert);
  123.     TkUndoPushStack(&(stack->undoStack), atom);
  124.     TkUndoClearStack(&(stack->redoStack));
  125. }
  126. /*
  127.  * TkUndoInitStack
  128.  *    Initialize a new undo/redo stack
  129.  *
  130.  * Results:
  131.  *    un Undo/Redo stack pointer
  132.  *
  133.  * Side effects:
  134.  *    None.
  135.  */
  136.  
  137. TkUndoRedoStack * TkUndoInitStack ( interp, maxdepth )
  138.     Tcl_Interp * interp;          /* The interpreter */
  139.     int          maxdepth;        /* The maximum stack depth */
  140.     TkUndoRedoStack * stack;      /* An Undo/Redo stack */
  141.     stack = (TkUndoRedoStack *) ckalloc(sizeof(TkUndoRedoStack));
  142.     stack->undoStack = NULL;
  143.     stack->redoStack = NULL;
  144.     stack->interp    = interp;
  145.     stack->maxdepth  = maxdepth; 
  146.     stack->depth     = 0;
  147.     return stack;
  148. }
  149. /*
  150.  * TkUndoInitStack
  151.  *    Initialize a new undo/redo stack
  152.  *
  153.  * Results:
  154.  *    un Undo/Redo stack pointer
  155.  *
  156.  * Side effects:
  157.  *    None.
  158.  */
  159.  
  160. void TkUndoSetDepth ( stack, maxdepth )
  161.     TkUndoRedoStack * stack;           /* An Undo/Redo stack */
  162.     int               maxdepth;        /* The maximum stack depth */
  163. {
  164.     TkUndoAtom * elem;
  165.     TkUndoAtom * prevelem;
  166.     int sepNumber = 0;
  167.     
  168.     stack->maxdepth = maxdepth;
  169.     if ((stack->maxdepth > 0) && (stack->depth > stack->maxdepth)) {
  170.         /*
  171.  * Maximum stack depth exceeded. We have to remove the last compound
  172.  * elements on the stack.
  173.  */
  174.         elem = stack->undoStack;
  175.         prevelem = NULL;
  176.         while (elem && (sepNumber <= stack->maxdepth)) {
  177.             if (elem->type == TK_UNDO_SEPARATOR) {
  178.                 sepNumber++;
  179.             }
  180.             prevelem = elem;
  181.             elem = elem->next;
  182.         }
  183.         prevelem->next = NULL;
  184.         while ( elem ) {
  185.            prevelem = elem;
  186.            elem = elem->next;
  187.            ckfree((char *) prevelem);
  188.         }
  189.         stack->depth = stack->maxdepth;
  190.     }
  191. }
  192. /*
  193.  * TkUndoClearStacks
  194.  *    Clear both the undo and redo stack
  195.  *
  196.  * Results:
  197.  *    None
  198.  *
  199.  * Side effects:
  200.  *    None.
  201.  */
  202.  
  203. void TkUndoClearStacks ( stack )
  204.     TkUndoRedoStack * stack;      /* An Undo/Redo stack */
  205.     TkUndoClearStack(&(stack->undoStack));
  206.     TkUndoClearStack(&(stack->redoStack));
  207.     stack->depth = 0;
  208. }
  209. /*
  210.  * TkUndoFreeStack
  211.  *    Clear both the undo and redo stack
  212.  *    also free the memory allocated to the u/r stack pointer
  213.  *
  214.  * Results:
  215.  *    None
  216.  *
  217.  * Side effects:
  218.  *    None.
  219.  */
  220.  
  221. void TkUndoFreeStack ( stack )
  222.     TkUndoRedoStack * stack;      /* An Undo/Redo stack */
  223.    TkUndoClearStacks(stack);
  224. /*   ckfree((TkUndoRedoStack *) stack); */
  225.    ckfree((char *) stack);
  226. }
  227. /*
  228.  * TkUndoInsertUndoSeparator --
  229.  *    insert a separator on the undo stack, indicating a border for
  230.  *      an undo/redo chunk.
  231.  *
  232.  * Results:
  233.  *    None
  234.  *
  235.  * Side effects:
  236.  *    None.
  237.  */
  238.  
  239. void TkUndoInsertUndoSeparator ( stack )
  240.     TkUndoRedoStack * stack;
  241. {
  242.     if ( TkUndoInsertSeparator(&(stack->undoStack)) ) {
  243.         ++(stack->depth);
  244.         TkUndoSetDepth(stack,stack->maxdepth);
  245.     }
  246. }
  247. /*
  248.  * TkUndoRevert --
  249.  *    Undo a compound action on the stack.
  250.  *
  251.  * Results:
  252.  *    A TCL status code
  253.  *
  254.  * Side effects:
  255.  *    None.
  256.  */
  257.  
  258. int TkUndoRevert ( stack )
  259.     TkUndoRedoStack * stack;
  260. {
  261.     TkUndoAtom * elem;
  262.     /* insert a separator on the undo and the redo stack */
  263.     TkUndoInsertUndoSeparator(stack);
  264.     TkUndoInsertSeparator(&(stack->redoStack));
  265.     /* Pop and skip the first separator if there is one*/
  266.     elem = TkUndoPopStack(&(stack->undoStack));
  267.     if ( elem == NULL ) {
  268.         return TCL_ERROR;
  269.     }
  270.     if ( ( elem != NULL ) && ( elem->type == TK_UNDO_SEPARATOR ) ) {
  271.         ckfree((char *) elem);
  272.         elem = TkUndoPopStack(&(stack->undoStack));
  273.     }
  274.     
  275.     while ( elem && (elem->type != TK_UNDO_SEPARATOR) ) {
  276.         Tcl_EvalObjEx(stack->interp,elem->revert,TCL_EVAL_GLOBAL);
  277.         
  278.         TkUndoPushStack(&(stack->redoStack),elem);
  279.         elem = TkUndoPopStack(&(stack->undoStack));
  280.     }
  281.     
  282.     /* insert a separator on the redo stack */
  283.     
  284.     TkUndoInsertSeparator(&(stack->redoStack));
  285.     
  286.     --(stack->depth);
  287.     
  288.     return TCL_OK;
  289. }
  290. /*
  291.  * TkUndoApply --
  292.  *    Redo a compound action on the stack.
  293.  *
  294.  * Results:
  295.  *    A TCL status code
  296.  *
  297.  * Side effects:
  298.  *    None.
  299.  */
  300.  
  301. int TkUndoApply ( stack )
  302.     TkUndoRedoStack * stack;
  303. {
  304.     TkUndoAtom *elem;
  305.     /* insert a separator on the undo stack */
  306.     TkUndoInsertSeparator(&(stack->undoStack));
  307.     /* Pop and skip the first separator if there is one*/
  308.     elem = TkUndoPopStack(&(stack->redoStack));
  309.     if ( elem == NULL ) {
  310.        return TCL_ERROR;
  311.     }
  312.     if ( ( elem != NULL ) && ( elem->type == TK_UNDO_SEPARATOR ) ) {
  313.         ckfree((char *) elem);
  314.         elem = TkUndoPopStack(&(stack->redoStack));
  315.     }
  316.     while ( elem && (elem->type != TK_UNDO_SEPARATOR) ) {
  317.         Tcl_EvalObjEx(stack->interp,elem->apply,TCL_EVAL_GLOBAL);
  318.         
  319.         TkUndoPushStack(&(stack->undoStack), elem);
  320.         elem = TkUndoPopStack(&(stack->redoStack));
  321.     }
  322.     /* insert a separator on the undo stack */
  323.     
  324.     TkUndoInsertSeparator(&(stack->undoStack));
  325.     ++(stack->depth);
  326.     
  327.     return TCL_OK;
  328. }