+ EM_SETTEXTEX 3.0 (unicode only, no rich text insertion handling, proper style?)
- EM_SETTEXTMODE 2.0
- EM_SETTYPOGRAPHYOPTIONS 3.0
- - EM_SETUNDOLIMIT 2.0
+ + EM_SETUNDOLIMIT 2.0
+ EM_SETWORDBREAKPROC (used only for word movement at the moment)
- EM_SETWORDBREAKPROCEX
- EM_SETWORDWRAPMODE 1.0asian
#include "imm.h"
#include "textserv.h"
#include "rtf.h"
+
+#define STACK_SIZE_DEFAULT 100
+#define STACK_SIZE_MAX 1000
WINE_DEFAULT_DEBUG_CHANNEL(richedit);
ed->bCaretAtEnd = FALSE;
ed->nEventMask = 0;
ed->nModifyStep = 0;
- ed->pUndoStack = ed->pRedoStack = NULL;
+ ed->pUndoStack = ed->pRedoStack = ed->pUndoStackBottom = NULL;
+ ed->nUndoStackSize = 0;
+ ed->nUndoLimit = STACK_SIZE_DEFAULT;
ed->nUndoMode = umAddToUndo;
ed->nParagraphs = 1;
ed->nLastSelStart = ed->nLastSelEnd = 0;
UNSUPPORTED_MSG(EM_SETTABSTOPS)
UNSUPPORTED_MSG(EM_SETTARGETDEVICE)
UNSUPPORTED_MSG(EM_SETTYPOGRAPHYOPTIONS)
- UNSUPPORTED_MSG(EM_SETUNDOLIMIT)
UNSUPPORTED_MSG(EM_SETWORDBREAKPROCEX)
UNSUPPORTED_MSG(EM_SHOWSCROLLBAR)
UNSUPPORTED_MSG(WM_SETFONT)
TRACE("EM_EXGETSEL = (%ld,%ld)\n", pRange->cpMin, pRange->cpMax);
return 0;
}
+ case EM_SETUNDOLIMIT:
+ {
+ if ((int)wParam < 0)
+ editor->nUndoLimit = STACK_SIZE_DEFAULT;
+ else
+ editor->nUndoLimit = min(wParam, STACK_SIZE_MAX);
+ /* Setting a max stack size keeps wine from getting killed
+ for hogging memory. Windows allocates all this memory at once, so
+ no program would realisticly set a value above our maxiumum. */
+ return editor->nUndoLimit;
+ }
case EM_CANUNDO:
return editor->pUndoStack != NULL;
case EM_CANREDO:
DestroyWindow(hwndRichEdit);
}
+static void test_EM_SETUNDOLIMIT()
+{
+ /* cases we test for:
+ * default behaviour - limiting at 100 undo's
+ * undo disabled - setting a limit of 0
+ * undo limited - undo limit set to some to some number, like 2
+ * bad input - sending a negative number should default to 100 undo's */
+
+ HWND hwndRichEdit = new_richedit(NULL);
+ CHARRANGE cr;
+ int i;
+ int result;
+
+ SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) "x");
+ cr.cpMin = 0;
+ cr.cpMax = 1;
+ SendMessage(hwndRichEdit, WM_COPY, 0, 0);
+ /*Load "x" into the clipboard. Paste is an easy, undo'able operation.
+ also, multiple pastes don't combine like WM_CHAR would */
+ SendMessage(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM) &cr);
+
+ /* first case - check the default */
+ SendMessage(hwndRichEdit,EM_EMPTYUNDOBUFFER, 0,0);
+ for (i=0; i<101; i++) /* Put 101 undo's on the stack */
+ SendMessage(hwndRichEdit, WM_PASTE, 0, 0);
+ for (i=0; i<100; i++) /* Undo 100 of them */
+ SendMessage(hwndRichEdit, WM_UNDO, 0, 0);
+ ok(!SendMessage(hwndRichEdit, EM_CANUNDO, 0, 0),
+ "EM_SETUNDOLIMIT allowed more than a hundred undo's by default.\n");
+
+ /* second case - cannot undo */
+ SendMessage(hwndRichEdit,EM_EMPTYUNDOBUFFER, 0, 0);
+ SendMessage(hwndRichEdit, EM_SETUNDOLIMIT, 0, 0);
+ SendMessage(hwndRichEdit,
+ WM_PASTE, 0, 0); /* Try to put something in the undo stack */
+ ok(!SendMessage(hwndRichEdit, EM_CANUNDO, 0, 0),
+ "EM_SETUNDOLIMIT allowed undo with UNDOLIMIT set to 0\n");
+
+ /* third case - set it to an arbitrary number */
+ SendMessage(hwndRichEdit,EM_EMPTYUNDOBUFFER, 0, 0);
+ SendMessage(hwndRichEdit, EM_SETUNDOLIMIT, 2, 0);
+ SendMessage(hwndRichEdit, WM_PASTE, 0, 0);
+ SendMessage(hwndRichEdit, WM_PASTE, 0, 0);
+ SendMessage(hwndRichEdit, WM_PASTE, 0, 0);
+ /* If SETUNDOLIMIT is working, there should only be two undo's after this */
+ ok(SendMessage(hwndRichEdit, EM_CANUNDO, 0,0),
+ "EM_SETUNDOLIMIT didn't allow the first undo with UNDOLIMIT set to 2\n");
+ SendMessage(hwndRichEdit, WM_UNDO, 0, 0);
+ ok(SendMessage(hwndRichEdit, EM_CANUNDO, 0, 0),
+ "EM_SETUNDOLIMIT didn't allow a second undo with UNDOLIMIT set to 2\n");
+ SendMessage(hwndRichEdit, WM_UNDO, 0, 0);
+ ok(!SendMessage(hwndRichEdit, EM_CANUNDO, 0, 0),
+ "EM_SETUNDOLIMIT allowed a third undo with UNDOLIMIT set to 2\n");
+
+ /* fourth case - setting negative numbers should default to 100 undos */
+ SendMessage(hwndRichEdit,EM_EMPTYUNDOBUFFER, 0,0);
+ result = SendMessage(hwndRichEdit, EM_SETUNDOLIMIT, -1, 0);
+ ok (result == 100,
+ "EM_SETUNDOLIMIT returned %d when set to -1, instead of 100",result);
+
+ DestroyWindow(hwndRichEdit);
+}
+
+
START_TEST( editor )
{
MSG msg;
test_EM_SETOPTIONS();
test_WM_GETTEXT();
test_EM_AUTOURLDETECT();
+ test_EM_SETUNDOLIMIT();
/* Set the environment variable WINETEST_RICHED20 to keep windows
* responsive and open for 30 seconds. This is useful for debugging.
TRACE("Emptying undo stack\n");
p = editor->pUndoStack;
- editor->pUndoStack = NULL;
+ editor->pUndoStack = editor->pUndoStackBottom = NULL;
+ editor->nUndoStackSize = 0;
while(p) {
pNext = p->next;
ME_DestroyDisplayItem(p);
ME_UndoItem *ME_AddUndoItem(ME_TextEditor *editor, ME_DIType type, ME_DisplayItem *pdi) {
if (editor->nUndoMode == umIgnore)
return NULL;
+ else if (editor->nUndoLimit == 0)
+ return NULL;
else
{
ME_DisplayItem *pItem = (ME_DisplayItem *)ALLOC_OBJ(ME_UndoItem);
TRACE("Pushing id=%s to undo stack, deleting redo stack\n", ME_GetDITypeName(type));
else
TRACE("Pushing id=%s to undo stack\n", ME_GetDITypeName(type));
+
pItem->next = editor->pUndoStack;
+ if (type == diUndoEndTransaction)
+ editor->nUndoStackSize++;
if (editor->pUndoStack)
editor->pUndoStack->prev = pItem;
+ else
+ editor->pUndoStackBottom = pItem;
editor->pUndoStack = pItem;
+
+ if (editor->nUndoStackSize > editor->nUndoLimit)
+ { /* remove oldest undo from stack */
+ ME_DisplayItem *p = editor->pUndoStackBottom;
+ while (p->type !=diUndoEndTransaction)
+ p = p->prev; /*find new stack bottom */
+ editor->pUndoStackBottom = p->prev;
+ editor->pUndoStackBottom->next = NULL;
+ do
+ {
+ ME_DisplayItem *pp = p->next;
+ ME_DestroyDisplayItem(p);
+ p = pp;
+ } while (p);
+ editor->nUndoStackSize--;
+ }
/* any new operation (not redo) clears the redo stack */
if (editor->nUndoMode == umAddToUndo) {
ME_DisplayItem *p = editor->pRedoStack;
} while(p && p->type != diUndoEndTransaction);
ME_AddUndoItem(editor, diUndoEndTransaction, NULL);
editor->pUndoStack = p;
+ editor->nUndoStackSize--;
if (p)
p->prev = NULL;
editor->nUndoMode = nMode;