diff --git a/dlls/riched20/editor.c b/dlls/riched20/editor.c index 9b1904dbc46..783e91d1aeb 100644 --- a/dlls/riched20/editor.c +++ b/dlls/riched20/editor.c @@ -597,7 +597,7 @@ static LRESULT ME_StreamIn(ME_TextEditor *editor, DWORD format, EDITSTREAM *stre { RTF_Info parser; ME_Style *style; - int from, to, to2; + int from, to, to2, nUndoMode; int nEventMask = editor->nEventMask; ME_InStream inStream; @@ -619,7 +619,15 @@ static LRESULT ME_StreamIn(ME_TextEditor *editor, DWORD format, EDITSTREAM *stre ME_ClearTempStyle(editor); /* FIXME restore default paragraph formatting ! */ } - + + + /* Back up undo mode to a local variable */ + nUndoMode = editor->nUndoMode; + + /* Only create an undo if SFF_SELECTION is set */ + if (!(format & SFF_SELECTION)) + editor->nUndoMode = umIgnore; + inStream.editstream = stream; inStream.editstream->dwError = 0; inStream.dwSize = 0; @@ -671,17 +679,17 @@ static LRESULT ME_StreamIn(ME_TextEditor *editor, DWORD format, EDITSTREAM *stre SendMessageA(editor->hWnd, EM_SETSEL, 0, 0); } - if (format & SFF_SELECTION) - { - /* even if we didn't add an undo, we need to commit the ones added earlier */ - ME_CommitUndo(editor); - } - else - { - ME_EmptyUndoStack(editor); - } + /* Restore saved undo mode */ + editor->nUndoMode = nUndoMode; - ME_ReleaseStyle(style); + /* even if we didn't add an undo, we need to commit anything on the stack */ + ME_CommitUndo(editor); + + /* If SFF_SELECTION isn't set, delete any undos from before we started too */ + if (!(format & SFF_SELECTION)) + ME_EmptyUndoStack(editor); + + ME_ReleaseStyle(style); editor->nEventMask = nEventMask; if (editor->bRedraw) { diff --git a/dlls/riched20/tests/editor.c b/dlls/riched20/tests/editor.c index f86ca5a7f18..60ab7ab8fdd 100644 --- a/dlls/riched20/tests/editor.c +++ b/dlls/riched20/tests/editor.c @@ -1462,6 +1462,106 @@ static void test_WM_PASTE(void) DestroyWindow(hwndRichEdit); } +static int nCallbackCount = 0; + +static DWORD CALLBACK EditStreamCallback(DWORD_PTR dwCookie, LPBYTE pbBuff, + LONG cb, LONG* pcb) +{ + const char text[] = {'t','e','s','t'}; + + if (sizeof(text) <= cb) + { + if ((int)dwCookie != nCallbackCount) + { + *pcb = 0; + return 0; + } + + memcpy (pbBuff, text, sizeof(text)); + *pcb = sizeof(text); + + nCallbackCount++; + + return 0; + } + else + return 1; /* indicates callback failed */ +} + +static void test_EM_StreamIn_Undo(void) +{ + /* The purpose of this test is to determine when a EM_StreamIn should be + * undoable. This is important because WM_PASTE currently uses StreamIn and + * pasting should always be undoable but streaming isn't always. + * + * cases to test: + * StreamIn plain text without SFF_SELECTION. + * StreamIn plain text with SFF_SELECTION set but a zero-length selection + * StreamIn plain text with SFF_SELECTION and a valid, normal selection + * StreamIn plain text with SFF_SELECTION and a backwards-selection (from>to) + * Feel free to add tests for other text modes or StreamIn things. + */ + + + HWND hwndRichEdit = new_richedit(NULL); + LRESULT result; + EDITSTREAM es; + char buffer[1024] = {0}; + const char randomtext[] = "Some text"; + + es.pfnCallback = (EDITSTREAMCALLBACK) EditStreamCallback; + + /* StreamIn, no SFF_SELECTION */ + es.dwCookie = nCallbackCount; + SendMessage(hwndRichEdit,EM_EMPTYUNDOBUFFER, 0,0); + SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) randomtext); + SendMessage(hwndRichEdit, EM_SETSEL,0,0); + SendMessage(hwndRichEdit, EM_STREAMIN, (WPARAM)SF_TEXT, (LPARAM)&es); + SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer); + result = strcmp (buffer,"test"); + ok (result == 0, + "EM_STREAMIN: Test 1 set wrong text: Result: %s\n",buffer); + + result = SendMessage(hwndRichEdit, EM_CANUNDO, 0, 0); + ok (result == FALSE, + "EM_STREAMIN without SFF_SELECTION wrongly allows undo\n"); + + /* StreamIn, SFF_SELECTION, but nothing selected */ + es.dwCookie = nCallbackCount; + SendMessage(hwndRichEdit,EM_EMPTYUNDOBUFFER, 0,0); + SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) randomtext); + SendMessage(hwndRichEdit, EM_SETSEL,0,0); + SendMessage(hwndRichEdit, EM_STREAMIN, + (WPARAM)(SF_TEXT|SFF_SELECTION), (LPARAM)&es); + SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer); + result = strcmp (buffer,"testSome text"); + ok (result == 0, + "EM_STREAMIN: Test 2 set wrong text: Result: %s\n",buffer); + + result = SendMessage(hwndRichEdit, EM_CANUNDO, 0, 0); + ok (result == TRUE, + "EM_STREAMIN with SFF_SELECTION but no selection set " + "should create an undo\n"); + + /* StreamIn, SFF_SELECTION, with a selection */ + es.dwCookie = nCallbackCount; + SendMessage(hwndRichEdit,EM_EMPTYUNDOBUFFER, 0,0); + SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) randomtext); + SendMessage(hwndRichEdit, EM_SETSEL,4,5); + SendMessage(hwndRichEdit, EM_STREAMIN, + (WPARAM)(SF_TEXT|SFF_SELECTION), (LPARAM)&es); + SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer); + result = strcmp (buffer,"Sometesttext"); + ok (result == 0, + "EM_STREAMIN: Test 2 set wrong text: Result: %s\n",buffer); + + result = SendMessage(hwndRichEdit, EM_CANUNDO, 0, 0); + ok (result == TRUE, + "EM_STREAMIN with SFF_SELECTION and selection set " + "should create an undo\n"); + +} + START_TEST( editor ) { MSG msg; @@ -1490,6 +1590,7 @@ START_TEST( editor ) test_EM_GETMODIFY(); test_EM_EXSETSEL(); test_WM_PASTE(); + test_EM_StreamIn_Undo(); /* Set the environment variable WINETEST_RICHED20 to keep windows * responsive and open for 30 seconds. This is useful for debugging.