Module: wine Branch: refs/heads/master Commit: a379ac9ef5b987d7071593daf0a63af31c89499c URL: http://source.winehq.org/git/?p=wine.git;a=commit;h=a379ac9ef5b987d7071593da...
Author: Matt Finnicum mattfinn@gmail.com Date: Mon May 15 14:00:15 2006 -0400
riched20: Implement EM_SETUNDOLIMIT and its conformance tests.
---
dlls/riched20/editor.c | 21 ++++++++++++-- dlls/riched20/editstr.h | 4 ++- dlls/riched20/tests/editor.c | 65 ++++++++++++++++++++++++++++++++++++++++++ dlls/riched20/undo.c | 27 +++++++++++++++++ 4 files changed, 112 insertions(+), 5 deletions(-)
diff --git a/dlls/riched20/editor.c b/dlls/riched20/editor.c index d73690c..3e8c834 100644 --- a/dlls/riched20/editor.c +++ b/dlls/riched20/editor.c @@ -117,7 +117,7 @@ + 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 @@ -229,6 +229,9 @@ #include "shlwapi.h" #include "imm.h" #include "textserv.h" #include "rtf.h" + +#define STACK_SIZE_DEFAULT 100 +#define STACK_SIZE_MAX 1000
WINE_DEFAULT_DEBUG_CHANNEL(richedit);
@@ -1119,7 +1122,9 @@ ME_TextEditor *ME_MakeEditor(HWND hWnd) 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; @@ -1426,7 +1431,6 @@ LRESULT WINAPI RichEditANSIWndProc(HWND 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) @@ -1477,6 +1481,17 @@ LRESULT WINAPI RichEditANSIWndProc(HWND 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: diff --git a/dlls/riched20/editstr.h b/dlls/riched20/editstr.h index 0911e90..bb151fa 100644 --- a/dlls/riched20/editstr.h +++ b/dlls/riched20/editstr.h @@ -298,7 +298,9 @@ typedef struct tagME_TextEditor BOOL bCaretAtEnd; int nEventMask; int nModifyStep; - ME_DisplayItem *pUndoStack, *pRedoStack; + ME_DisplayItem *pUndoStack, *pRedoStack, *pUndoStackBottom; + int nUndoStackSize; + int nUndoLimit; ME_UndoMode nUndoMode; int nParagraphs; int nLastSelStart, nLastSelEnd; diff --git a/dlls/riched20/tests/editor.c b/dlls/riched20/tests/editor.c index 6b80903..837fb15 100644 --- a/dlls/riched20/tests/editor.c +++ b/dlls/riched20/tests/editor.c @@ -747,6 +747,70 @@ static void test_EM_SCROLL() 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; @@ -764,6 +828,7 @@ START_TEST( editor ) 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. diff --git a/dlls/riched20/undo.c b/dlls/riched20/undo.c index 916dcb3..f8895cb 100644 --- a/dlls/riched20/undo.c +++ b/dlls/riched20/undo.c @@ -32,7 +32,8 @@ void ME_EmptyUndoStack(ME_TextEditor *ed 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); @@ -50,6 +51,8 @@ void ME_EmptyUndoStack(ME_TextEditor *ed 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); @@ -93,10 +96,31 @@ ME_UndoItem *ME_AddUndoItem(ME_TextEdito 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; @@ -233,6 +257,7 @@ void ME_Undo(ME_TextEditor *editor) { } while(p && p->type != diUndoEndTransaction); ME_AddUndoItem(editor, diUndoEndTransaction, NULL); editor->pUndoStack = p; + editor->nUndoStackSize--; if (p) p->prev = NULL; editor->nUndoMode = nMode;