oledlg: Minimal 'As Icon' handling. Just disable for now.
[wine/hacks.git] / dlls / oledlg / pastespl.c
blob26f91e85b0ce95a0a9ef55f49a94605de3d69be9
1 /*
2 * OleUIPasteSpecial implementation
4 * Copyright 2006 Huw Davies
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #define COM_NO_WINDOWS_H
22 #define COBJMACROS
24 #include <stdarg.h>
26 #include "windef.h"
27 #include "winbase.h"
28 #include "winerror.h"
29 #include "wingdi.h"
30 #include "winuser.h"
31 #include "winnls.h"
32 #include "oledlg.h"
34 #include "oledlg_private.h"
35 #include "resource.h"
37 #include "wine/debug.h"
38 #include "wine/unicode.h"
40 WINE_DEFAULT_DEBUG_CHANNEL(ole);
42 typedef struct
44 OLEUIPASTESPECIALW *ps;
45 DWORD flags;
46 } ps_struct_t;
48 static const struct ps_flag
50 DWORD flag;
51 const char *name;
52 } ps_flags[] = {
53 #define PS_FLAG_ENTRY(p) {p, #p}
54 PS_FLAG_ENTRY(PSF_SHOWHELP),
55 PS_FLAG_ENTRY(PSF_SELECTPASTE),
56 PS_FLAG_ENTRY(PSF_SELECTPASTELINK),
57 PS_FLAG_ENTRY(PSF_CHECKDISPLAYASICON),
58 PS_FLAG_ENTRY(PSF_DISABLEDISPLAYASICON),
59 PS_FLAG_ENTRY(PSF_HIDECHANGEICON),
60 PS_FLAG_ENTRY(PSF_STAYONCLIPBOARDCHANGE),
61 PS_FLAG_ENTRY(PSF_NOREFRESHDATAOBJECT),
62 {-1, NULL}
63 #undef PS_FLAG_ENTRY
66 static void dump_ps_flags(DWORD flags)
68 char flagstr[1000] = "";
70 const struct ps_flag *flag = ps_flags;
71 for( ; flag->name; flag++) {
72 if(flags & flag->flag) {
73 strcat(flagstr, flag->name);
74 strcat(flagstr, "|");
77 TRACE("flags %08x %s\n", flags, flagstr);
80 static void dump_pastespecial(LPOLEUIPASTESPECIALW ps)
82 UINT i;
83 dump_ps_flags(ps->dwFlags);
84 TRACE("hwnd %p caption %s hook %p custdata %lx\n",
85 ps->hWndOwner, debugstr_w(ps->lpszCaption), ps->lpfnHook, ps->lCustData);
86 if(IS_INTRESOURCE(ps->lpszTemplate))
87 TRACE("hinst %p template %04x hresource %p\n", ps->hInstance, (WORD)(ULONG_PTR)ps->lpszTemplate, ps->hResource);
88 else
89 TRACE("hinst %p template %s hresource %p\n", ps->hInstance, debugstr_w(ps->lpszTemplate), ps->hResource);
90 TRACE("dataobj %p arrpasteent %p cpasteent %d arrlinktype %p clinktype %d\n",
91 ps->lpSrcDataObj, ps->arrPasteEntries, ps->cPasteEntries,
92 ps->arrLinkTypes, ps->cLinkTypes);
93 TRACE("cclsidex %d lpclsidex %p nselect %d flink %d hmetapict %p size(%d,%d)\n",
94 ps->cClsidExclude, ps->lpClsidExclude, ps->nSelectedIndex, ps->fLink,
95 ps->hMetaPict, ps->sizel.cx, ps->sizel.cy);
96 for(i = 0; i < ps->cPasteEntries; i++)
98 TRACE("arrPasteEntries[%d]: cFormat %08x pTargetDevice %p dwAspect %d lindex %d tymed %d\n",
99 i, ps->arrPasteEntries[i].fmtetc.cfFormat, ps->arrPasteEntries[i].fmtetc.ptd,
100 ps->arrPasteEntries[i].fmtetc.dwAspect, ps->arrPasteEntries[i].fmtetc.lindex,
101 ps->arrPasteEntries[i].fmtetc.tymed);
102 TRACE("\tformat name %s result text %s flags %04x\n", debugstr_w(ps->arrPasteEntries[i].lpstrFormatName),
103 debugstr_w(ps->arrPasteEntries[i].lpstrResultText), ps->arrPasteEntries[i].dwFlags);
105 for(i = 0; i < ps->cLinkTypes; i++)
106 TRACE("arrLinkTypes[%d] %08x\n", i, ps->arrLinkTypes[i]);
107 for(i = 0; i < ps->cClsidExclude; i++)
108 TRACE("lpClsidExclude[%d] %s\n", i, debugstr_guid(&ps->lpClsidExclude[i]));
112 static inline WCHAR *strdupAtoW(const char *str)
114 DWORD len;
115 WCHAR *ret;
116 if(!str) return NULL;
117 len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
118 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
119 MultiByteToWideChar(CP_ACP, 0, str, -1, ret, len);
120 return ret;
123 static BOOL add_entry_to_lb(HWND hdlg, UINT id, OLEUIPASTEENTRYW *pe)
125 HWND hwnd = GetDlgItem(hdlg, id);
126 BOOL ret = FALSE;
128 /* FIXME %s handling */
130 /* Note that this suffers from the same bug as native, in that if a new string
131 is a substring of an already added string, then the FINDSTRING will succeed
132 this is probably not what we want */
133 if(SendMessageW(hwnd, LB_FINDSTRING, 0, (LPARAM)pe->lpstrFormatName) == -1)
135 LRESULT pos = SendMessageW(hwnd, LB_ADDSTRING, 0, (LPARAM)pe->lpstrFormatName);
136 SendMessageW(hwnd, LB_SETITEMDATA, pos, (LPARAM)pe);
137 ret = TRUE;
139 return ret;
142 static DWORD init_pastelist(HWND hdlg, OLEUIPASTESPECIALW *ps)
144 IEnumFORMATETC *penum;
145 HRESULT hr;
146 FORMATETC fmts[20];
147 DWORD fetched, items_added = 0;
149 hr = IDataObject_EnumFormatEtc(ps->lpSrcDataObj, DATADIR_GET, &penum);
150 if(FAILED(hr))
152 WARN("Unable to create IEnumFORMATETC\n");
153 return 0;
156 /* The native version grabs only the first 20 fmts and we do the same */
157 hr = IEnumFORMATETC_Next(penum, sizeof(fmts)/sizeof(fmts[0]), fmts, &fetched);
158 TRACE("got %d formats hr %08x\n", fetched, hr);
160 if(SUCCEEDED(hr))
162 DWORD src_fmt, req_fmt;
163 for(req_fmt = 0; req_fmt < ps->cPasteEntries; req_fmt++)
165 /* This is used by update_struct() to set nSelectedIndex on exit */
166 ps->arrPasteEntries[req_fmt].dwScratchSpace = req_fmt;
167 TRACE("req_fmt %x\n", ps->arrPasteEntries[req_fmt].fmtetc.cfFormat);
168 for(src_fmt = 0; src_fmt < fetched; src_fmt++)
170 TRACE("\tenum'ed fmt %x\n", fmts[src_fmt].cfFormat);
171 if(ps->arrPasteEntries[req_fmt].fmtetc.cfFormat == fmts[src_fmt].cfFormat)
173 add_entry_to_lb(hdlg, IDC_PS_PASTELIST, ps->arrPasteEntries + req_fmt);
174 items_added++;
175 break;
181 IEnumFORMATETC_Release(penum);
182 EnableWindow(GetDlgItem(hdlg, IDC_PS_PASTE), items_added ? TRUE : FALSE);
183 return items_added;
186 static DWORD init_linklist(HWND hdlg, OLEUIPASTESPECIALW *ps)
188 HRESULT hr;
189 DWORD supported_mask = 0;
190 DWORD items_added = 0;
191 int link, req_fmt;
192 FORMATETC fmt = {0, NULL, DVASPECT_CONTENT, -1, -1};
194 for(link = 0; link < ps->cLinkTypes && link < PS_MAXLINKTYPES; link++)
196 fmt.cfFormat = ps->arrLinkTypes[link];
197 hr = IDataObject_QueryGetData(ps->lpSrcDataObj, &fmt);
198 if(hr == S_OK)
199 supported_mask |= 1 << link;
201 TRACE("supported_mask %02x\n", supported_mask);
202 for(req_fmt = 0; req_fmt < ps->cPasteEntries; req_fmt++)
204 DWORD linktypes;
205 if(ps->arrPasteEntries[req_fmt].dwFlags & OLEUIPASTE_LINKANYTYPE)
206 linktypes = 0xff;
207 else
208 linktypes = ps->arrPasteEntries[req_fmt].dwFlags & 0xff;
210 if(linktypes & supported_mask)
212 add_entry_to_lb(hdlg, IDC_PS_PASTELINKLIST, ps->arrPasteEntries + req_fmt);
213 items_added++;
217 EnableWindow(GetDlgItem(hdlg, IDC_PS_PASTELINK), items_added ? TRUE : FALSE);
218 return items_added;
221 /* copies src_list_id into the display list */
222 static void update_display_list(HWND hdlg, UINT src_list_id)
224 LONG count, i, old_pos;
225 WCHAR txt[256];
226 LONG item_data;
227 HWND display_list = GetDlgItem(hdlg, IDC_PS_DISPLAYLIST);
228 HWND list = GetDlgItem(hdlg, src_list_id);
230 old_pos = SendMessageW(display_list, LB_GETCURSEL, 0, 0);
231 if(old_pos == -1) old_pos = 0;
233 SendMessageW(display_list, WM_SETREDRAW, 0, 0);
234 SendMessageW(display_list, LB_RESETCONTENT, 0, 0);
235 count = SendMessageW(list, LB_GETCOUNT, 0, 0);
236 for(i = 0; i < count; i++)
238 SendMessageW(list, LB_GETTEXT, i, (LPARAM)txt);
239 item_data = SendMessageW(list, LB_GETITEMDATA, i, 0);
240 SendMessageW(display_list, LB_INSERTSTRING, i, (LPARAM)txt);
241 SendMessageW(display_list, LB_SETITEMDATA, i, item_data);
243 old_pos = max(old_pos, count);
244 SendMessageW(display_list, LB_SETCURSEL, 0, 0);
245 SendMessageW(display_list, WM_SETREDRAW, 1, 0);
246 if(GetForegroundWindow() == hdlg)
247 SetFocus(display_list);
250 static void init_lists(HWND hdlg, ps_struct_t *ps_struct)
252 DWORD pastes_added = init_pastelist(hdlg, ps_struct->ps);
253 DWORD links_added = init_linklist(hdlg, ps_struct->ps);
254 UINT check_id, list_id;
256 if((ps_struct->flags & (PSF_SELECTPASTE | PSF_SELECTPASTELINK)) == 0)
257 ps_struct->flags |= PSF_SELECTPASTE;
259 if(!pastes_added && !links_added)
260 ps_struct->flags &= ~(PSF_SELECTPASTE | PSF_SELECTPASTELINK);
261 else if(!pastes_added && (ps_struct->flags & PSF_SELECTPASTE))
263 ps_struct->flags &= ~PSF_SELECTPASTE;
264 ps_struct->flags |= PSF_SELECTPASTELINK;
266 else if(!links_added && (ps_struct->flags & PSF_SELECTPASTELINK))
268 ps_struct->flags &= ~PSF_SELECTPASTELINK;
269 ps_struct->flags |= PSF_SELECTPASTE;
272 check_id = 0;
273 list_id = 0;
274 if(ps_struct->flags & PSF_SELECTPASTE)
276 check_id = IDC_PS_PASTE;
277 list_id = IDC_PS_PASTELIST;
279 else if(ps_struct->flags & PSF_SELECTPASTELINK)
281 check_id = IDC_PS_PASTELINK;
282 list_id = IDC_PS_PASTELINKLIST;
285 CheckRadioButton(hdlg, IDC_PS_PASTE, IDC_PS_PASTELINK, check_id);
287 if(list_id)
288 update_display_list(hdlg, list_id);
289 else
290 EnableWindow(GetDlgItem(hdlg, IDOK), 0);
293 static void update_as_icon(HWND hdlg, ps_struct_t *ps_struct)
295 HWND icon_display = GetDlgItem(hdlg, IDC_PS_ICONDISPLAY);
296 HWND display_as_icon = GetDlgItem(hdlg, IDC_PS_DISPLAYASICON);
297 HWND change_icon = GetDlgItem(hdlg, IDC_PS_CHANGEICON);
299 /* FIXME. No as icon handling */
300 ps_struct->flags &= ~PSF_CHECKDISPLAYASICON;
302 CheckDlgButton(hdlg, IDC_PS_DISPLAYASICON, ps_struct->flags & PSF_CHECKDISPLAYASICON);
303 EnableWindow(display_as_icon, 0);
304 ShowWindow(icon_display, SW_HIDE);
305 EnableWindow(icon_display, 0);
306 ShowWindow(change_icon, SW_HIDE);
307 EnableWindow(change_icon, 0);
310 static void update_result_text(HWND hdlg, ps_struct_t *ps_struct)
312 WCHAR resource_txt[200];
313 UINT res_id;
314 OLEUIPASTEENTRYW *pent;
315 LONG cur_sel;
316 static const WCHAR percent_s[] = {'%','s',0};
317 WCHAR *result_txt, *ptr;
319 cur_sel = SendMessageW(GetDlgItem(hdlg, IDC_PS_DISPLAYLIST), LB_GETCURSEL, 0, 0);
320 if(cur_sel == -1) return;
321 pent = (OLEUIPASTEENTRYW*)SendMessageW(GetDlgItem(hdlg, IDC_PS_DISPLAYLIST), LB_GETITEMDATA, cur_sel, 0);
323 if(ps_struct->flags & PSF_SELECTPASTE)
325 if(ps_struct->flags & PSF_CHECKDISPLAYASICON)
326 res_id = IDS_PS_PASTE_OBJECT_AS_ICON;
327 else
328 res_id = IDS_PS_PASTE_DATA;
330 else
332 if(ps_struct->flags & PSF_CHECKDISPLAYASICON)
333 res_id = IDS_PS_PASTE_LINK_OBJECT_AS_ICON;
334 else
335 res_id = IDS_PS_PASTE_LINK_DATA;
338 LoadStringW(OLEDLG_hInstance, res_id, resource_txt, sizeof(resource_txt)/sizeof(WCHAR));
339 if((ptr = strstrW(resource_txt, percent_s)))
341 /* FIXME handle %s in ResultText. Sub appname if IDS_PS_PASTE_OBJECT{_AS_ICON}. Else sub appropiate type name */
342 size_t result_txt_len = strlenW(pent->lpstrResultText);
343 ptrdiff_t offs = (char*)ptr - (char*)resource_txt;
344 result_txt = HeapAlloc(GetProcessHeap(), 0, (strlenW(resource_txt) + result_txt_len - 1) * sizeof(WCHAR));
345 memcpy(result_txt, resource_txt, offs);
346 memcpy((char*)result_txt + offs, pent->lpstrResultText, result_txt_len * sizeof(WCHAR));
347 memcpy((char*)result_txt + offs + result_txt_len * sizeof(WCHAR), ptr + 2, (strlenW(ptr + 2) + 1) * sizeof(WCHAR));
349 else
350 result_txt = resource_txt;
352 SetDlgItemTextW(hdlg, IDC_PS_RESULTTEXT, result_txt);
354 if(result_txt != resource_txt)
355 HeapFree(GetProcessHeap(), 0, result_txt);
359 static void selection_change(HWND hdlg, ps_struct_t *ps_struct)
361 update_as_icon(hdlg, ps_struct);
362 update_result_text(hdlg, ps_struct);
365 static void post_help_msg(HWND hdlg, ps_struct_t *ps_struct)
367 PostMessageW(ps_struct->ps->hWndOwner, oleui_msg_help, (WPARAM)hdlg, IDD_PASTESPECIAL);
370 static void send_end_dialog_msg(HWND hdlg, ps_struct_t *ps_struct, UINT id)
372 SendMessageW(hdlg, oleui_msg_enddialog, id, 0);
375 static void update_structure(HWND hdlg, ps_struct_t *ps_struct)
377 ps_struct->ps->dwFlags = ps_struct->flags;
378 ps_struct->ps->fLink = (ps_struct->flags & PSF_SELECTPASTELINK) ? TRUE : FALSE;
381 static void free_structure(ps_struct_t *ps_struct)
383 HeapFree(GetProcessHeap(), 0, ps_struct);
386 static INT_PTR CALLBACK ps_dlg_proc(HWND hdlg, UINT msg, WPARAM wp, LPARAM lp)
388 /* native uses prop name "Structure", but we're not compatible
389 with that so we'll prepend "Wine_". */
390 static const WCHAR prop_name[] = {'W','i','n','e','_','S','t','r','u','c','t','u','r','e',0};
391 ps_struct_t *ps_struct;
393 TRACE("(%p, %04x, %08x, %08lx)\n", hdlg, msg, wp, lp);
395 ps_struct = GetPropW(hdlg, prop_name);
397 if(msg != WM_INITDIALOG)
399 if(!ps_struct)
400 return 0;
403 switch(msg)
405 case WM_INITDIALOG:
407 ps_struct = HeapAlloc(GetProcessHeap(), 0, sizeof(*ps_struct));
408 ps_struct->ps = (OLEUIPASTESPECIALW*)lp;
409 ps_struct->flags = ps_struct->ps->dwFlags;
411 SetPropW(hdlg, prop_name, ps_struct);
413 if(!(ps_struct->ps->dwFlags & PSF_SHOWHELP))
415 ShowWindow(GetDlgItem(hdlg, IDC_OLEUIHELP), SW_HIDE);
416 EnableWindow(GetDlgItem(hdlg, IDC_OLEUIHELP), 0);
419 if(ps_struct->ps->lpszCaption)
420 SetWindowTextW(hdlg, ps_struct->ps->lpszCaption);
422 init_lists(hdlg, ps_struct);
424 selection_change(hdlg, ps_struct);
426 return TRUE; /* use default focus */
428 case WM_COMMAND:
429 switch(LOWORD(wp))
431 case IDC_PS_DISPLAYLIST:
432 switch(HIWORD(wp))
434 case LBN_SELCHANGE:
435 selection_change(hdlg, ps_struct);
436 return FALSE;
437 default:
438 return FALSE;
440 case IDC_OLEUIHELP:
441 switch(HIWORD(wp))
443 case BN_CLICKED:
444 post_help_msg(hdlg, ps_struct);
445 return FALSE;
446 default:
447 return FALSE;
449 case IDOK:
450 case IDCANCEL:
451 send_end_dialog_msg(hdlg, ps_struct, LOWORD(wp));
452 return FALSE;
454 return FALSE;
455 default:
456 if(msg == oleui_msg_enddialog)
458 if(wp == IDOK)
459 update_structure(hdlg, ps_struct);
460 EndDialog(hdlg, wp);
461 free_structure(ps_struct);
462 return TRUE;
464 return FALSE;
469 /***********************************************************************
470 * OleUIPasteSpecialA (OLEDLG.4)
472 UINT WINAPI OleUIPasteSpecialA(LPOLEUIPASTESPECIALA psA)
474 OLEUIPASTESPECIALW ps;
475 UINT ret;
476 TRACE("(%p)\n", psA);
478 memcpy(&ps, psA, psA->cbStruct);
480 ps.lpszCaption = strdupAtoW(psA->lpszCaption);
481 if(!IS_INTRESOURCE(ps.lpszTemplate))
482 ps.lpszTemplate = strdupAtoW(psA->lpszTemplate);
484 if(psA->cPasteEntries > 0)
486 DWORD size = psA->cPasteEntries * sizeof(ps.arrPasteEntries[0]);
487 UINT i;
489 ps.arrPasteEntries = HeapAlloc(GetProcessHeap(), 0, size);
490 memcpy(ps.arrPasteEntries, psA->arrPasteEntries, size);
491 for(i = 0; i < psA->cPasteEntries; i++)
493 ps.arrPasteEntries[i].lpstrFormatName =
494 strdupAtoW(psA->arrPasteEntries[i].lpstrFormatName);
495 ps.arrPasteEntries[i].lpstrResultText =
496 strdupAtoW(psA->arrPasteEntries[i].lpstrResultText);
500 ret = OleUIPasteSpecialW(&ps);
502 if(psA->cPasteEntries > 0)
504 UINT i;
505 for(i = 0; i < psA->cPasteEntries; i++)
507 HeapFree(GetProcessHeap(), 0, (WCHAR*)ps.arrPasteEntries[i].lpstrFormatName);
508 HeapFree(GetProcessHeap(), 0, (WCHAR*)ps.arrPasteEntries[i].lpstrResultText);
510 HeapFree(GetProcessHeap(), 0, ps.arrPasteEntries);
512 if(!IS_INTRESOURCE(ps.lpszTemplate))
513 HeapFree(GetProcessHeap(), 0, (WCHAR*)ps.lpszTemplate);
514 HeapFree(GetProcessHeap(), 0, (WCHAR*)ps.lpszCaption);
516 /* Copy back the output fields */
517 psA->dwFlags = ps.dwFlags;
518 psA->lpSrcDataObj = ps.lpSrcDataObj;
519 psA->nSelectedIndex = ps.nSelectedIndex;
520 psA->fLink = ps.fLink;
521 psA->hMetaPict = ps.hMetaPict;
522 psA->sizel = ps.sizel;
524 return ret;
527 /***********************************************************************
528 * OleUIPasteSpecialW (OLEDLG.22)
530 UINT WINAPI OleUIPasteSpecialW(LPOLEUIPASTESPECIALW ps)
532 LPCDLGTEMPLATEW dlg_templ = (LPCDLGTEMPLATEW)ps->hResource;
534 TRACE("(%p)\n", ps);
536 if(TRACE_ON(ole)) dump_pastespecial(ps);
538 if(!ps->lpSrcDataObj)
539 OleGetClipboard(&ps->lpSrcDataObj);
541 if(ps->hInstance || !ps->hResource)
543 HINSTANCE hInst = ps->hInstance ? ps->hInstance : OLEDLG_hInstance;
544 const WCHAR *name = ps->hInstance ? ps->lpszTemplate : MAKEINTRESOURCEW(IDD_PASTESPECIAL4);
545 HRSRC hrsrc;
547 if(name == NULL) return OLEUI_ERR_LPSZTEMPLATEINVALID;
548 hrsrc = FindResourceW(hInst, name, MAKEINTRESOURCEW(RT_DIALOG));
549 if(!hrsrc) return OLEUI_ERR_FINDTEMPLATEFAILURE;
550 dlg_templ = LoadResource(hInst, hrsrc);
551 if(!dlg_templ) return OLEUI_ERR_LOADTEMPLATEFAILURE;
554 DialogBoxIndirectParamW(OLEDLG_hInstance, dlg_templ, ps->hWndOwner, ps_dlg_proc, (LPARAM)ps);
556 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
557 return OLEUI_FALSE;