Commit aa1ef09f authored by Damjan Jovanovic's avatar Damjan Jovanovic Committed by Alexandre Julliard

riched20: Implement ITextRange/ITextSelection Copy and Cut.

parent a9a2a68b
...@@ -2333,52 +2333,70 @@ done: ...@@ -2333,52 +2333,70 @@ done:
return hr == S_OK; return hr == S_OK;
} }
static BOOL ME_Copy(ME_TextEditor *editor, const ME_Cursor *start, int nChars) static HRESULT editor_copy( ME_TextEditor *editor, ME_Cursor *start, int chars, IDataObject **data_out )
{ {
LPDATAOBJECT dataObj = NULL; IDataObject *data = NULL;
HRESULT hr = S_OK; HRESULT hr = S_OK;
if (editor->cPasswordMask) if (editor->lpOleCallback)
return FALSE; /* Copying or Cutting masked text isn't allowed */
if(editor->lpOleCallback)
{ {
CHARRANGE range; CHARRANGE range;
range.cpMin = ME_GetCursorOfs(start); range.cpMin = ME_GetCursorOfs( start );
range.cpMax = range.cpMin + nChars; range.cpMax = range.cpMin + chars;
hr = IRichEditOleCallback_GetClipboardData(editor->lpOleCallback, &range, RECO_COPY, &dataObj); hr = IRichEditOleCallback_GetClipboardData( editor->lpOleCallback, &range, RECO_COPY, &data );
}
if (FAILED( hr ) || !data)
hr = ME_GetDataObject( editor, start, chars, &data );
if (SUCCEEDED( hr ))
{
if (data_out)
*data_out = data;
else
{
hr = OleSetClipboard( data );
IDataObject_Release( data );
} }
if(FAILED(hr) || !dataObj)
hr = ME_GetDataObject(editor, start, nChars, &dataObj);
if(SUCCEEDED(hr)) {
hr = OleSetClipboard(dataObj);
IDataObject_Release(dataObj);
} }
return SUCCEEDED(hr);
return hr;
} }
static BOOL copy_or_cut(ME_TextEditor *editor, BOOL cut) HRESULT editor_copy_or_cut( ME_TextEditor *editor, BOOL cut, ME_Cursor *start, int count,
IDataObject **data_out )
{ {
BOOL result; HRESULT hr;
int offs, num_chars;
int start_cursor = ME_GetSelectionOfs(editor, &offs, &num_chars);
ME_Cursor *sel_start = &editor->pCursors[start_cursor];
if (cut && (editor->styleFlags & ES_READONLY)) if (cut && (editor->styleFlags & ES_READONLY))
{ {
MessageBeep(MB_ICONERROR); return E_ACCESSDENIED;
return FALSE;
} }
num_chars -= offs; hr = editor_copy( editor, start, count, data_out );
result = ME_Copy(editor, sel_start, num_chars); if (SUCCEEDED(hr) && cut)
if (result && cut)
{ {
ME_InternalDeleteText(editor, sel_start, num_chars, FALSE); ME_InternalDeleteText( editor, start, count, FALSE );
ME_CommitUndo(editor); ME_CommitUndo( editor );
ME_UpdateRepaint(editor, TRUE); ME_UpdateRepaint( editor, TRUE );
} }
return result; return hr;
}
static BOOL copy_or_cut( ME_TextEditor *editor, BOOL cut )
{
HRESULT hr;
int offs, count;
int start_cursor = ME_GetSelectionOfs( editor, &offs, &count );
ME_Cursor *sel_start = &editor->pCursors[start_cursor];
if (editor->cPasswordMask) return FALSE;
count -= offs;
hr = editor_copy_or_cut( editor, cut, sel_start, count, NULL );
if (FAILED( hr )) MessageBeep( MB_ICONERROR );
return SUCCEEDED( hr );
} }
/* helper to send a msg filter notification */ /* helper to send a msg filter notification */
......
...@@ -270,6 +270,8 @@ void ME_StreamInFill(ME_InStream *stream) DECLSPEC_HIDDEN; ...@@ -270,6 +270,8 @@ void ME_StreamInFill(ME_InStream *stream) DECLSPEC_HIDDEN;
extern BOOL me_debug DECLSPEC_HIDDEN; extern BOOL me_debug DECLSPEC_HIDDEN;
void ME_ReplaceSel(ME_TextEditor *editor, BOOL can_undo, const WCHAR *str, int len) DECLSPEC_HIDDEN; void ME_ReplaceSel(ME_TextEditor *editor, BOOL can_undo, const WCHAR *str, int len) DECLSPEC_HIDDEN;
int set_selection( ME_TextEditor *editor, int to, int from ) DECLSPEC_HIDDEN; int set_selection( ME_TextEditor *editor, int to, int from ) DECLSPEC_HIDDEN;
HRESULT editor_copy_or_cut( ME_TextEditor *editor, BOOL cut, ME_Cursor *start, int count,
IDataObject **data_out ) DECLSPEC_HIDDEN;
ME_Paragraph *editor_first_para( ME_TextEditor *editor ) DECLSPEC_HIDDEN; ME_Paragraph *editor_first_para( ME_TextEditor *editor ) DECLSPEC_HIDDEN;
/* table.c */ /* table.c */
......
...@@ -2594,28 +2594,53 @@ static HRESULT WINAPI ITextRange_fnDelete(ITextRange *me, LONG unit, LONG count, ...@@ -2594,28 +2594,53 @@ static HRESULT WINAPI ITextRange_fnDelete(ITextRange *me, LONG unit, LONG count,
return E_NOTIMPL; return E_NOTIMPL;
} }
static HRESULT textrange_copy_or_cut( ITextRange *range, ME_TextEditor *editor, BOOL cut, VARIANT *v )
{
LONG start, end;
ME_Cursor cursor;
IDataObject **data_out = NULL;
ITextRange_GetStart( range, &start );
ITextRange_GetEnd( range, &end );
if (start == end)
{
/* If the range is empty, all text is copied */
LONG prev_end = end;
ITextRange_SetEnd( range, MAXLONG );
start = 0;
ITextRange_GetEnd( range, &end );
ITextRange_SetEnd( range, prev_end );
}
cursor_from_char_ofs( editor, start, &cursor );
if (v && V_VT(v) == (VT_UNKNOWN | VT_BYREF) && V_UNKNOWNREF( v ))
data_out = (IDataObject **)V_UNKNOWNREF( v );
return editor_copy_or_cut( editor, cut, &cursor, end - start, data_out );
}
static HRESULT WINAPI ITextRange_fnCut(ITextRange *me, VARIANT *v) static HRESULT WINAPI ITextRange_fnCut(ITextRange *me, VARIANT *v)
{ {
ITextRangeImpl *This = impl_from_ITextRange(me); ITextRangeImpl *This = impl_from_ITextRange(me);
FIXME("(%p)->(%p): stub\n", This, v); TRACE("(%p)->(%p)\n", This, v);
if (!This->child.reole) if (!This->child.reole)
return CO_E_RELEASED; return CO_E_RELEASED;
return E_NOTIMPL; return textrange_copy_or_cut(me, This->child.reole->editor, TRUE, v);
} }
static HRESULT WINAPI ITextRange_fnCopy(ITextRange *me, VARIANT *v) static HRESULT WINAPI ITextRange_fnCopy(ITextRange *me, VARIANT *v)
{ {
ITextRangeImpl *This = impl_from_ITextRange(me); ITextRangeImpl *This = impl_from_ITextRange(me);
FIXME("(%p)->(%p): stub\n", This, v); TRACE("(%p)->(%p)\n", This, v);
if (!This->child.reole) if (!This->child.reole)
return CO_E_RELEASED; return CO_E_RELEASED;
return E_NOTIMPL; return textrange_copy_or_cut(me, This->child.reole->editor, FALSE, v);
} }
static HRESULT WINAPI ITextRange_fnPaste(ITextRange *me, VARIANT *v, LONG format) static HRESULT WINAPI ITextRange_fnPaste(ITextRange *me, VARIANT *v, LONG format)
...@@ -5365,25 +5390,35 @@ static HRESULT WINAPI ITextSelection_fnDelete(ITextSelection *me, LONG unit, LON ...@@ -5365,25 +5390,35 @@ static HRESULT WINAPI ITextSelection_fnDelete(ITextSelection *me, LONG unit, LON
static HRESULT WINAPI ITextSelection_fnCut(ITextSelection *me, VARIANT *v) static HRESULT WINAPI ITextSelection_fnCut(ITextSelection *me, VARIANT *v)
{ {
ITextSelectionImpl *This = impl_from_ITextSelection(me); ITextSelectionImpl *This = impl_from_ITextSelection(me);
ITextRange *range = NULL;
HRESULT hr;
FIXME("(%p)->(%p): stub\n", This, v); TRACE("(%p)->(%p): stub\n", This, v);
if (!This->reOle) if (!This->reOle)
return CO_E_RELEASED; return CO_E_RELEASED;
return E_NOTIMPL; ITextSelection_QueryInterface(me, &IID_ITextRange, (void**)&range);
hr = textrange_copy_or_cut(range, This->reOle->editor, TRUE, v);
ITextRange_Release(range);
return hr;
} }
static HRESULT WINAPI ITextSelection_fnCopy(ITextSelection *me, VARIANT *v) static HRESULT WINAPI ITextSelection_fnCopy(ITextSelection *me, VARIANT *v)
{ {
ITextSelectionImpl *This = impl_from_ITextSelection(me); ITextSelectionImpl *This = impl_from_ITextSelection(me);
ITextRange *range = NULL;
HRESULT hr;
FIXME("(%p)->(%p): stub\n", This, v); TRACE("(%p)->(%p)\n", This, v);
if (!This->reOle) if (!This->reOle)
return CO_E_RELEASED; return CO_E_RELEASED;
return E_NOTIMPL; ITextSelection_QueryInterface(me, &IID_ITextRange, (void**)&range);
hr = textrange_copy_or_cut(range, This->reOle->editor, FALSE, v);
ITextRange_Release(range);
return hr;
} }
static HRESULT WINAPI ITextSelection_fnPaste(ITextSelection *me, VARIANT *v, LONG format) static HRESULT WINAPI ITextSelection_fnPaste(ITextSelection *me, VARIANT *v, LONG format)
......
...@@ -4012,6 +4012,79 @@ static void test_character_movement(void) ...@@ -4012,6 +4012,79 @@ static void test_character_movement(void)
ITextRange_Release(range); ITextRange_Release(range);
} }
#define CLIPBOARD_RANGE_CONTAINS(range, start, end, expected) _clipboard_range_contains(range, start, end, expected, __LINE__, 0);
#define TODO_CLIPBOARD_RANGE_CONTAINS(range, start, end, expected) _clipboard_range_contains(range, start, end, expected, __LINE__, 1);
static void _clipboard_range_contains(ITextRange *range, LONG start, LONG end, const char *expected, int line, int todo)
{
HRESULT hr;
BOOL clipboard_open;
HGLOBAL global;
const char *clipboard_text;
hr = ITextRange_SetRange(range, start, end);
ok_(__FILE__,line)(SUCCEEDED(hr), "SetRange failed: 0x%08x\n", hr);
hr = ITextRange_Copy(range, NULL);
ok_(__FILE__,line)(hr == S_OK, "Copy failed: 0x%08x\n", hr);
clipboard_open = OpenClipboard(NULL);
ok_(__FILE__,line)(clipboard_open, "OpenClipboard failed: %d\n", GetLastError());
global = GetClipboardData(CF_TEXT);
ok_(__FILE__,line)(global != NULL, "GetClipboardData failed: %p\n", global);
clipboard_text = GlobalLock(global);
ok_(__FILE__,line)(clipboard_text != NULL, "GlobalLock failed: %p\n", clipboard_text);
todo_wine_if(todo) ok_(__FILE__,line)(!strcmp(expected, clipboard_text), "unexpected contents: %s\n", wine_dbgstr_a(clipboard_text));
GlobalUnlock(global);
CloseClipboard();
}
static void test_clipboard(void)
{
static const char text_in[] = "ab\n c";
IRichEditOle *reole = NULL;
ITextDocument *doc = NULL;
ITextRange *range;
ITextSelection *selection;
HRESULT hr;
HWND hwnd;
create_interfaces(&hwnd, &reole, &doc, &selection);
SendMessageA(hwnd, WM_SETTEXT, 0, (LPARAM)text_in);
hr = ITextDocument_Range(doc, 0, 0, &range);
ok(hr == S_OK, "got 0x%08x\n", hr);
CLIPBOARD_RANGE_CONTAINS(range, 0, 5, "ab\r\n c")
CLIPBOARD_RANGE_CONTAINS(range, 0, 0, "ab\r\n c")
CLIPBOARD_RANGE_CONTAINS(range, 1, 1, "ab\r\n c")
CLIPBOARD_RANGE_CONTAINS(range, 0, 1, "a")
CLIPBOARD_RANGE_CONTAINS(range, 5, 6, "")
/* Setting password char does not stop Copy */
SendMessageA(hwnd, EM_SETPASSWORDCHAR, '*', 0);
CLIPBOARD_RANGE_CONTAINS(range, 0, 1, "a")
/* Cut can be undone */
hr = ITextRange_SetRange(range, 0, 1);
ok(SUCCEEDED(hr), "SetRange failed: 0x%08x\n", hr);
hr = ITextRange_Cut(range, NULL);
ok(hr == S_OK, "Cut failed: 0x%08x\n", hr);
CLIPBOARD_RANGE_CONTAINS(range, 0, 4, "b\r\n c");
hr = ITextDocument_Undo(doc, 1, NULL);
todo_wine ok(hr == S_OK, "Undo failed: 0x%08x\n", hr);
TODO_CLIPBOARD_RANGE_CONTAINS(range, 0, 5, "ab\r\n c");
/* Cannot cut when read-only */
SendMessageA(hwnd, EM_SETREADONLY, TRUE, 0);
hr = ITextRange_SetRange(range, 0, 1);
ok(SUCCEEDED(hr), "SetRange failed: 0x%08x\n", hr);
hr = ITextRange_Cut(range, NULL);
ok(hr == E_ACCESSDENIED, "got 0x%08x\n", hr);
release_interfaces(&hwnd, &reole, &doc, NULL);
ITextSelection_Release(selection);
ITextRange_Release(range);
}
START_TEST(richole) START_TEST(richole)
{ {
/* Must explicitly LoadLibrary(). The test has no references to functions in /* Must explicitly LoadLibrary(). The test has no references to functions in
...@@ -4052,4 +4125,5 @@ START_TEST(richole) ...@@ -4052,4 +4125,5 @@ START_TEST(richole)
test_Expand(); test_Expand();
test_MoveEnd_story(); test_MoveEnd_story();
test_character_movement(); test_character_movement();
test_clipboard();
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment