Subject: Implementation of TIP #446 - Introspect Undo/Redo Stack

From: fvogel <[email-masked]>
Date: Thu, 12 May 2016 20:26:20 +0000

---
 generic/tkText.c | 34 +++++++++++++++++++++++---
 generic/tkUndo.c | 72 +++++++++++++++++++++++++++++++++++++++++++++++++++++---
 generic/tkUndo.h |  4 +++-
 3 files changed, 103 insertions(+), 7 deletions(-)

diff --git a/generic/tkText.c b/generic/tkText.c
index 3e8d625..4a352b2 100644
--- a/generic/tkText.c
+++ b/generic/tkText.c
@@ -2093,7 +2093,7 @@ ConfigureText(
     textPtr->sharedTextPtr->maxUndo = textPtr->maxUndo;
     textPtr->sharedTextPtr->autoSeparators = textPtr->autoSeparators;
 
-    TkUndoSetDepth(textPtr->sharedTextPtr->undoStack,
+    TkUndoSetMaxDepth(textPtr->sharedTextPtr->undoStack,
 	    textPtr->sharedTextPtr->maxUndo);
 
     /*
@@ -5156,10 +5156,12 @@ TextEditCmd(
 {
     int index, setModified, oldModified;
     static const char *const editOptionStrings[] = {
-	"modified", "redo", "reset", "separator", "undo", NULL
+	"canundo", "canredo", "modified", "redo", "reset", "separator",
+        "undo", NULL
     };
     enum editOptions {
-	EDIT_MODIFIED, EDIT_REDO, EDIT_RESET, EDIT_SEPARATOR, EDIT_UNDO
+	EDIT_CANUNDO, EDIT_CANREDO, EDIT_MODIFIED, EDIT_REDO, EDIT_RESET,
+	EDIT_SEPARATOR, EDIT_UNDO
     };
 
     if (objc < 3) {
@@ -5173,6 +5175,32 @@ TextEditCmd(
     }
 
     switch ((enum editOptions) index) {
+    case EDIT_CANREDO: {
+        int canRedo = 0;
+
+        if (objc != 3) {
+            Tcl_WrongNumArgs(interp, 3, objv, NULL);
+             return TCL_ERROR;
+        }
+        if (textPtr->sharedTextPtr->undo) {
+            canRedo = TkUndoCanRedo(textPtr->sharedTextPtr->undoStack);
+        }
+        Tcl_SetObjResult(interp, Tcl_NewBooleanObj(canRedo));
+        break;
+    }
+    case EDIT_CANUNDO: {
+        int canUndo = 0;
+
+        if (objc != 3) {
+            Tcl_WrongNumArgs(interp, 3, objv, NULL);
+             return TCL_ERROR;
+        }
+        if (textPtr->sharedTextPtr->undo) {
+            canUndo = TkUndoCanUndo(textPtr->sharedTextPtr->undoStack);
+        }
+        Tcl_SetObjResult(interp, Tcl_NewBooleanObj(canUndo));
+        break;
+    }
     case EDIT_MODIFIED:
 	if (objc == 3) {
 	    Tcl_SetObjResult(interp,
diff --git a/generic/tkUndo.c b/generic/tkUndo.c
index 8359e0a..5934154 100644
--- a/generic/tkUndo.c
+++ b/generic/tkUndo.c
@@ -353,7 +353,7 @@ TkUndoInitStack(
 /*
  *----------------------------------------------------------------------
  *
- * TkUndoSetDepth --
+ * TkUndoSetMaxDepth --
  *
  *	Set the maximum depth of stack.
  *
@@ -368,7 +368,7 @@ TkUndoInitStack(
  */
 
 void
-TkUndoSetDepth(
+TkUndoSetMaxDepth(
     TkUndoRedoStack *stack,	/* An Undo/Redo stack */
     int maxdepth)		/* The maximum stack depth */
 {
@@ -478,6 +478,72 @@ TkUndoFreeStack(
 /*
  *----------------------------------------------------------------------
  *
+ * 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 */
+{
+    int canRedo = 0;
+    TkUndoAtom *elem = stack->redoStack;
+
+    while (elem != NULL) {
+        if (elem->type != TK_UNDO_SEPARATOR) {
+            canRedo = 1;
+            break;
+        }
+        elem = elem->next;
+    }
+    return canRedo;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * 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 */
+{
+    int canUndo = 0;
+    TkUndoAtom *elem = stack->undoStack;
+
+    while (elem != NULL) {
+        if (elem->type != TK_UNDO_SEPARATOR) {
+            canUndo = 1;
+            break;
+        }
+        elem = elem->next;
+    }
+    return canUndo;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
  * TkUndoInsertUndoSeparator --
  *
  *	Insert a separator on the undo stack, indicating a border for an
@@ -498,7 +564,7 @@ TkUndoInsertUndoSeparator(
 {
     if (TkUndoInsertSeparator(&stack->undoStack)) {
 	stack->depth++;
-	TkUndoSetDepth(stack, stack->maxdepth);
+	TkUndoSetMaxDepth(stack, stack->maxdepth);
     }
 }
 
diff --git a/generic/tkUndo.h b/generic/tkUndo.h
index e63aac4..490ede9 100644
--- a/generic/tkUndo.h
+++ b/generic/tkUndo.h
@@ -96,9 +96,11 @@ MODULE_SCOPE void	TkUndoClearStack(TkUndoAtom **stack);
  */
 
 MODULE_SCOPE TkUndoRedoStack *TkUndoInitStack(Tcl_Interp *interp, int maxdepth);
-MODULE_SCOPE void	TkUndoSetDepth(TkUndoRedoStack *stack, int maxdepth);
+MODULE_SCOPE void	TkUndoSetMaxDepth(TkUndoRedoStack *stack, int maxdepth);
 MODULE_SCOPE void	TkUndoClearStacks(TkUndoRedoStack *stack);
 MODULE_SCOPE void	TkUndoFreeStack(TkUndoRedoStack *stack);
+MODULE_SCOPE int	TkUndoCanRedo(TkUndoRedoStack *stack);
+MODULE_SCOPE int	TkUndoCanUndo(TkUndoRedoStack *stack);
 MODULE_SCOPE void	TkUndoInsertUndoSeparator(TkUndoRedoStack *stack);
 MODULE_SCOPE TkUndoSubAtom *TkUndoMakeCmdSubAtom(Tcl_Command command,
 			    Tcl_Obj *actionScript, TkUndoSubAtom *subAtomList);
-- 
cgit v0.12