riched20: Implement EM_SETUNDOLIMIT and its conformance tests.

This commit is contained in:
Matt Finnicum 2006-05-15 14:00:15 -04:00 committed by Alexandre Julliard
parent 24157e0f74
commit a379ac9ef5
4 changed files with 112 additions and 5 deletions

View File

@ -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 "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 hWnd, UINT msg, WPARAM wParam, LPARAM lP
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 hWnd, UINT msg, WPARAM wParam, LPARAM lP
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:

View File

@ -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;

View File

@ -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.

View File

@ -32,7 +32,8 @@ void ME_EmptyUndoStack(ME_TextEditor *editor)
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 *editor)
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_TextEditor *editor, ME_DIType type, ME_DisplayIte
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;