ole32: Remove 'recursive registry key delete' function.
[wine] / dlls / mshtml / olecmd.c
1 /*
2  * Copyright 2005-2007 Jacek Caban for CodeWeavers
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
17  */
18
19 #include "config.h"
20
21 #include <stdarg.h>
22 #include <stdio.h>
23
24 #define COBJMACROS
25
26 #include "windef.h"
27 #include "winbase.h"
28 #include "winuser.h"
29 #include "winnls.h"
30 #include "ole2.h"
31 #include "shlguid.h"
32 #include "mshtmdid.h"
33 #include "idispids.h"
34 #include "mshtmcid.h"
35
36 #include "wine/debug.h"
37 #include "wine/unicode.h"
38
39 #include "mshtml_private.h"
40 #include "resource.h"
41
42 WINE_DEFAULT_DEBUG_CHANNEL(mshtml);
43
44 #define NSCMD_BOLD "cmd_bold"
45 #define NSCMD_ITALIC "cmd_italic"
46 #define NSCMD_UNDERLINE "cmd_underline"
47 #define NSCMD_ALIGN "cmd_align"
48 #define NSCMD_INDENT "cmd_indent"
49 #define NSCMD_OUTDENT "cmd_outdent"
50 #define NSCMD_INSERTHR "cmd_insertHR"
51 #define NSCMD_UL "cmd_ul"
52 #define NSCMD_OL "cmd_ol"
53
54 #define NSSTATE_ATTRIBUTE "state_attribute"
55
56 #define NSALIGN_CENTER "center"
57 #define NSALIGN_LEFT   "left"
58 #define NSALIGN_RIGHT  "right"
59
60 /**********************************************************
61  * IOleCommandTarget implementation
62  */
63
64 #define CMDTARGET_THIS(iface) DEFINE_THIS(HTMLDocument, OleCommandTarget, iface)
65
66 static HRESULT exec_open(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
67 {
68     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
69     return E_NOTIMPL;
70 }
71
72 static HRESULT exec_new(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
73 {
74     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
75     return E_NOTIMPL;
76 }
77
78 static HRESULT exec_save(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
79 {
80     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
81     return E_NOTIMPL;
82 }
83
84 static HRESULT exec_save_as(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
85 {
86     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
87     return E_NOTIMPL;
88 }
89
90 static HRESULT exec_save_copy_as(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
91 {
92     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
93     return E_NOTIMPL;
94 }
95
96 static nsresult set_head_text(nsIPrintSettings *settings, LPCWSTR template, BOOL head, int pos)
97 {
98     if(head) {
99         switch(pos) {
100         case 0:
101             return nsIPrintSettings_SetHeaderStrLeft(settings, template);
102         case 1:
103             return nsIPrintSettings_SetHeaderStrRight(settings, template);
104         case 2:
105             return nsIPrintSettings_SetHeaderStrCenter(settings, template);
106         }
107     }else {
108         switch(pos) {
109         case 0:
110             return nsIPrintSettings_SetFooterStrLeft(settings, template);
111         case 1:
112             return nsIPrintSettings_SetFooterStrRight(settings, template);
113         case 2:
114             return nsIPrintSettings_SetFooterStrCenter(settings, template);
115         }
116     }
117
118     return NS_OK;
119 }
120
121 static void set_print_template(nsIPrintSettings *settings, LPCWSTR template, BOOL head)
122 {
123     PRUnichar nstemplate[200]; /* FIXME: Use dynamic allocation */
124     PRUnichar *p = nstemplate;
125     LPCWSTR ptr=template;
126     int pos=0;
127
128     while(*ptr) {
129         if(*ptr != '&') {
130             *p++ = *ptr++;
131             continue;
132         }
133
134         switch(*++ptr) {
135         case '&':
136             *p++ = '&';
137             *p++ = '&';
138             ptr++;
139             break;
140         case 'b': /* change align */
141             ptr++;
142             *p = 0;
143             set_head_text(settings, nstemplate, head, pos);
144             p = nstemplate;
145             pos++;
146             break;
147         case 'd': { /* short date */
148             SYSTEMTIME systime;
149             GetLocalTime(&systime);
150             GetDateFormatW(LOCALE_SYSTEM_DEFAULT, 0, &systime, NULL, p,
151                     sizeof(nstemplate)-(p-nstemplate)*sizeof(WCHAR));
152             p += strlenW(p);
153             ptr++;
154             break;
155         }
156         case 'p': /* page number */
157             *p++ = '&';
158             *p++ = 'P';
159             ptr++;
160             break;
161         case 'P': /* page count */
162             *p++ = '?'; /* FIXME */
163             ptr++;
164             break;
165         case 'u':
166             *p++ = '&';
167             *p++ = 'U';
168             ptr++;
169             break;
170         case 'w':
171             /* FIXME: set window title */
172             ptr++;
173             break;
174         default:
175             *p++ = '&';
176             *p++ = *ptr++;
177         }
178     }
179
180     *p = 0;
181     set_head_text(settings, nstemplate, head, pos);
182
183     while(++pos < 3)
184         set_head_text(settings, p, head, pos);
185 }
186
187 static void set_default_templates(nsIPrintSettings *settings)
188 {
189     WCHAR buf[64];
190
191     static const PRUnichar empty[] = {0};
192
193     nsIPrintSettings_SetHeaderStrLeft(settings, empty);
194     nsIPrintSettings_SetHeaderStrRight(settings, empty);
195     nsIPrintSettings_SetHeaderStrCenter(settings, empty);
196     nsIPrintSettings_SetFooterStrLeft(settings, empty);
197     nsIPrintSettings_SetFooterStrRight(settings, empty);
198     nsIPrintSettings_SetFooterStrCenter(settings, empty);
199
200     if(LoadStringW(get_shdoclc(), IDS_PRINT_HEADER_TEMPLATE, buf,
201                    sizeof(buf)/sizeof(WCHAR)))
202         set_print_template(settings, buf, TRUE);
203
204
205     if(LoadStringW(get_shdoclc(), IDS_PRINT_FOOTER_TEMPLATE, buf,
206                    sizeof(buf)/sizeof(WCHAR)))
207         set_print_template(settings, buf, FALSE);
208
209 }
210
211 static HRESULT exec_print(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
212 {
213     nsIInterfaceRequestor *iface_req;
214     nsIWebBrowserPrint *nsprint;
215     nsIPrintSettings *settings;
216     nsresult nsres;
217
218     TRACE("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
219
220     if(pvaOut)
221         FIXME("unsupported pvaOut\n");
222
223     if(!This->nscontainer)
224         return S_OK;
225
226     nsres = nsIWebBrowser_QueryInterface(This->nscontainer->webbrowser,
227             &IID_nsIInterfaceRequestor, (void**)&iface_req);
228     if(NS_FAILED(nsres)) {
229         ERR("Could not get nsIInterfaceRequestor: %08x\n", nsres);
230         return S_OK;
231     }
232
233     nsres = nsIInterfaceRequestor_GetInterface(iface_req, &IID_nsIWebBrowserPrint,
234             (void**)&nsprint);
235     nsIInterfaceRequestor_Release(iface_req);
236     if(NS_FAILED(nsres)) {
237         ERR("Could not get nsIWebBrowserPrint: %08x\n", nsres);
238         return S_OK;
239     }
240
241     nsres = nsIWebBrowserPrint_GetGlobalPrintSettings(nsprint, &settings);
242     if(NS_FAILED(nsres))
243         ERR("GetCurrentPrintSettings failed: %08x\n", nsres);
244
245     set_default_templates(settings);
246
247     if(pvaIn) {
248         switch(V_VT(pvaIn)) {
249         case VT_BYREF|VT_ARRAY: {
250             VARIANT *opts;
251             DWORD opts_cnt;
252
253             if(V_ARRAY(pvaIn)->cDims != 1)
254                 WARN("cDims = %d\n", V_ARRAY(pvaIn)->cDims);
255
256             SafeArrayAccessData(V_ARRAY(pvaIn), (void**)&opts);
257             opts_cnt = V_ARRAY(pvaIn)->rgsabound[0].cElements;
258
259             if(opts_cnt >= 1) {
260                 switch(V_VT(opts)) {
261                 case VT_BSTR:
262                     TRACE("setting footer %s\n", debugstr_w(V_BSTR(opts)));
263                     set_print_template(settings, V_BSTR(opts), TRUE);
264                     break;
265                 case VT_NULL:
266                     break;
267                 default:
268                     WARN("V_VT(opts) = %d\n", V_VT(opts));
269                 }
270             }
271
272             if(opts_cnt >= 2) {
273                 switch(V_VT(opts+1)) {
274                 case VT_BSTR:
275                     TRACE("setting footer %s\n", debugstr_w(V_BSTR(opts+1)));
276                     set_print_template(settings, V_BSTR(opts+1), FALSE);
277                     break;
278                 case VT_NULL:
279                     break;
280                 default:
281                     WARN("V_VT(opts) = %d\n", V_VT(opts+1));
282                 }
283             }
284
285             if(opts_cnt >= 3)
286                 FIXME("Unsupported opts_cnt %d\n", opts_cnt);
287
288             SafeArrayUnaccessData(V_ARRAY(pvaIn));
289             break;
290         }
291         default:
292             FIXME("unsupported vt %x\n", V_VT(pvaIn));
293         }
294     }
295
296     nsres = nsIWebBrowserPrint_Print(nsprint, settings, NULL);
297     if(NS_FAILED(nsres))
298         ERR("Print failed: %08x\n", nsres);
299
300     nsIWebBrowserPrint_Release(nsprint);
301
302     return S_OK;
303 }
304
305 static HRESULT exec_print_preview(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
306 {
307     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
308     return E_NOTIMPL;
309 }
310
311 static HRESULT exec_page_setup(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
312 {
313     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
314     return E_NOTIMPL;
315 }
316
317 static HRESULT exec_spell(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
318 {
319     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
320     return E_NOTIMPL;
321 }
322
323 static HRESULT exec_properties(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
324 {
325     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
326     return E_NOTIMPL;
327 }
328
329 static HRESULT exec_cut(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
330 {
331     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
332     return E_NOTIMPL;
333 }
334
335 static HRESULT exec_copy(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
336 {
337     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
338     return E_NOTIMPL;
339 }
340
341 static HRESULT exec_paste(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
342 {
343     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
344     return E_NOTIMPL;
345 }
346
347 static HRESULT exec_paste_special(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
348 {
349     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
350     return E_NOTIMPL;
351 }
352
353 static HRESULT exec_undo(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
354 {
355     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
356     return E_NOTIMPL;
357 }
358
359 static HRESULT exec_rendo(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
360 {
361     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
362     return E_NOTIMPL;
363 }
364
365 static HRESULT exec_select_all(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
366 {
367     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
368     return E_NOTIMPL;
369 }
370
371 static HRESULT exec_clear_selection(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
372 {
373     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
374     return E_NOTIMPL;
375 }
376
377 static HRESULT exec_zoom(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
378 {
379     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
380     return E_NOTIMPL;
381 }
382
383 static HRESULT exec_get_zoom_range(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
384 {
385     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
386     return E_NOTIMPL;
387 }
388
389 static HRESULT exec_refresh(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
390 {
391     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
392     return E_NOTIMPL;
393 }
394
395 static HRESULT exec_stop(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
396 {
397     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
398     return E_NOTIMPL;
399 }
400
401 static HRESULT exec_stop_download(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
402 {
403     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
404     return E_NOTIMPL;
405 }
406
407 static HRESULT exec_delete(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
408 {
409     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
410     return E_NOTIMPL;
411 }
412
413 static HRESULT exec_enable_interaction(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
414 {
415     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
416     return E_NOTIMPL;
417 }
418
419 static HRESULT exec_on_unload(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
420 {
421     TRACE("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
422
423     /* Tests show that we have nothing more to do here */
424
425     if(pvaOut) {
426         V_VT(pvaOut) = VT_BOOL;
427         V_BOOL(pvaOut) = VARIANT_TRUE;
428     }
429
430     return S_OK;
431 }
432
433 static HRESULT exec_show_page_setup(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
434 {
435     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
436     return E_NOTIMPL;
437 }
438
439 static HRESULT exec_show_print(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
440 {
441     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
442     return E_NOTIMPL;
443 }
444
445 static HRESULT exec_close(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
446 {
447     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
448     return E_NOTIMPL;
449 }
450
451 static HRESULT exec_set_print_template(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
452 {
453     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
454     return E_NOTIMPL;
455 }
456
457 static HRESULT exec_get_print_template(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
458 {
459     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
460     return E_NOTIMPL;
461 }
462
463 static HRESULT query_mshtml_copy(HTMLDocument *This, OLECMD *cmd)
464 {
465     FIXME("(%p)\n", This);
466     cmd->cmdf = OLECMDF_SUPPORTED|OLECMDF_ENABLED;
467     return S_OK;
468 }
469
470 static HRESULT exec_mshtml_copy(HTMLDocument *This, DWORD cmdexecopt, VARIANT *in, VARIANT *out)
471 {
472     TRACE("(%p)->(%08x %p %p)\n", This, cmdexecopt, in, out);
473
474     if(This->usermode == EDITMODE)
475         return editor_exec_copy(This, cmdexecopt, in, out);
476
477     FIXME("Unimplemented in browse mode\n");
478     return E_NOTIMPL;
479 }
480
481 static HRESULT query_mshtml_cut(HTMLDocument *This, OLECMD *cmd)
482 {
483     FIXME("(%p)\n", This);
484     cmd->cmdf = OLECMDF_SUPPORTED|OLECMDF_ENABLED;
485     return S_OK;
486 }
487
488 static HRESULT exec_mshtml_cut(HTMLDocument *This, DWORD cmdexecopt, VARIANT *in, VARIANT *out)
489 {
490     TRACE("(%p)->(%08x %p %p)\n", This, cmdexecopt, in, out);
491
492     if(This->usermode == EDITMODE)
493         return editor_exec_cut(This, cmdexecopt, in, out);
494
495     FIXME("Unimplemented in browse mode\n");
496     return E_NOTIMPL;
497 }
498
499 static HRESULT query_mshtml_paste(HTMLDocument *This, OLECMD *cmd)
500 {
501     FIXME("(%p)\n", This);
502     cmd->cmdf = OLECMDF_SUPPORTED|OLECMDF_ENABLED;
503     return S_OK;
504 }
505
506 static HRESULT exec_mshtml_paste(HTMLDocument *This, DWORD cmdexecopt, VARIANT *in, VARIANT *out)
507 {
508     TRACE("(%p)->(%08x %p %p)\n", This, cmdexecopt, in, out);
509
510     if(This->usermode == EDITMODE)
511         return editor_exec_paste(This, cmdexecopt, in, out);
512
513     FIXME("Unimplemented in browse mode\n");
514     return E_NOTIMPL;
515 }
516
517 static HRESULT exec_browsemode(HTMLDocument *This, DWORD cmdexecopt, VARIANT *in, VARIANT *out)
518 {
519     WARN("(%p)->(%08x %p %p)\n", This, cmdexecopt, in, out);
520
521     if(in || out)
522         FIXME("unsupported args\n");
523
524     This->usermode = BROWSEMODE;
525
526     return S_OK;
527 }
528
529 static HRESULT exec_editmode(HTMLDocument *This, DWORD cmdexecopt, VARIANT *in, VARIANT *out)
530 {
531     IMoniker *mon;
532     HRESULT hres;
533
534     static const WCHAR wszAboutBlank[] = {'a','b','o','u','t',':','b','l','a','n','k',0};
535
536     TRACE("(%p)->(%08x %p %p)\n", This, cmdexecopt, in, out);
537
538     if(in || out)
539         FIXME("unsupported args\n");
540
541     if(This->usermode == EDITMODE)
542         return S_OK;
543
544     This->usermode = EDITMODE;
545
546     if(This->frame)
547         IOleInPlaceFrame_SetStatusText(This->frame, NULL);
548
549     if(This->client) {
550         IOleCommandTarget *cmdtrg;
551
552         hres = IOleClientSite_QueryInterface(This->client, &IID_IOleCommandTarget,
553                 (void**)&cmdtrg);
554         if(SUCCEEDED(hres)) {
555             VARIANT var;
556
557             V_VT(&var) = VT_I4;
558             V_I4(&var) = 0;
559             IOleCommandTarget_Exec(cmdtrg, &CGID_ShellDocView, 37, 0, &var, NULL);
560
561             IOleCommandTarget_Release(cmdtrg);
562         }
563     }
564
565     if(This->hostui) {
566         DOCHOSTUIINFO hostinfo;
567
568         memset(&hostinfo, 0, sizeof(DOCHOSTUIINFO));
569         hostinfo.cbSize = sizeof(DOCHOSTUIINFO);
570         hres = IDocHostUIHandler_GetHostInfo(This->hostui, &hostinfo);
571         if(SUCCEEDED(hres))
572             /* FIXME: use hostinfo */
573             TRACE("hostinfo = {%u %08x %08x %s %s}\n",
574                     hostinfo.cbSize, hostinfo.dwFlags, hostinfo.dwDoubleClick,
575                     debugstr_w(hostinfo.pchHostCss), debugstr_w(hostinfo.pchHostNS));
576     }
577
578     if(This->nscontainer)
579         set_ns_editmode(This->nscontainer);
580
581     hres = CreateURLMoniker(NULL, wszAboutBlank, &mon);
582     if(FAILED(hres)) {
583         FIXME("CreateURLMoniker failed: %08x\n", hres);
584         return hres;
585     }
586
587     update_doc(This, UPDATE_UI);
588
589     return IPersistMoniker_Load(PERSISTMON(This), TRUE, mon, NULL, 0);
590 }
591
592 static HRESULT exec_htmleditmode(HTMLDocument *This, DWORD cmdexecopt, VARIANT *in, VARIANT *out)
593 {
594     FIXME("(%p)->(%08x %p %p)\n", This, cmdexecopt, in, out);
595     return S_OK;
596 }
597
598 static HRESULT exec_setdirty(HTMLDocument *This, DWORD cmdexecopt, VARIANT *in, VARIANT *out)
599 {
600     FIXME("(%p)->(%08x %p %p)\n", This, cmdexecopt, in, out);
601     return E_NOTIMPL;
602 }
603
604 static HRESULT exec_baselinefont3(HTMLDocument *This, DWORD cmdexecopt, VARIANT *in, VARIANT *out)
605 {
606     FIXME("(%p)->(%08x %p %p)\n", This, cmdexecopt, in, out);
607     return S_OK;
608 }
609
610 static HRESULT exec_respectvisibility_indesign(HTMLDocument *This, DWORD cmdexecopt,
611         VARIANT *in, VARIANT *out)
612 {
613     FIXME("(%p)->(%08x %p %p)\n", This, cmdexecopt, in, out);
614     return E_NOTIMPL;
615 }
616
617 static HRESULT query_enabled_stub(HTMLDocument *This, OLECMD *cmd)
618 {
619     switch(cmd->cmdID) {
620     case IDM_PRINT:
621         FIXME("CGID_MSHTML: IDM_PRINT\n");
622         cmd->cmdf = OLECMDF_SUPPORTED|OLECMDF_ENABLED;
623         break;
624     case IDM_BLOCKDIRLTR:
625         FIXME("CGID_MSHTML: IDM_BLOCKDIRLTR\n");
626         cmd->cmdf = OLECMDF_SUPPORTED|OLECMDF_ENABLED;
627         break;
628     case IDM_BLOCKDIRRTL:
629         FIXME("CGID_MSHTML: IDM_BLOCKDIRRTL\n");
630         cmd->cmdf = OLECMDF_SUPPORTED|OLECMDF_ENABLED;
631         break;
632     }
633
634     return S_OK;
635 }
636
637 static const struct {
638     OLECMDF cmdf;
639     HRESULT (*func)(HTMLDocument*,DWORD,VARIANT*,VARIANT*);
640 } exec_table[OLECMDID_GETPRINTTEMPLATE+1] = {
641     {0},
642     { OLECMDF_SUPPORTED,                  exec_open                 }, /* OLECMDID_OPEN */
643     { OLECMDF_SUPPORTED,                  exec_new                  }, /* OLECMDID_NEW */
644     { OLECMDF_SUPPORTED,                  exec_save                 }, /* OLECMDID_SAVE */
645     { OLECMDF_SUPPORTED|OLECMDF_ENABLED,  exec_save_as              }, /* OLECMDID_SAVEAS */
646     { OLECMDF_SUPPORTED,                  exec_save_copy_as         }, /* OLECMDID_SAVECOPYAS */
647     { OLECMDF_SUPPORTED|OLECMDF_ENABLED,  exec_print                }, /* OLECMDID_PRINT */
648     { OLECMDF_SUPPORTED|OLECMDF_ENABLED,  exec_print_preview        }, /* OLECMDID_PRINTPREVIEW */
649     { OLECMDF_SUPPORTED|OLECMDF_ENABLED,  exec_page_setup           }, /* OLECMDID_PAGESETUP */
650     { OLECMDF_SUPPORTED,                  exec_spell                }, /* OLECMDID_SPELL */
651     { OLECMDF_SUPPORTED|OLECMDF_ENABLED,  exec_properties           }, /* OLECMDID_PROPERTIES */
652     { OLECMDF_SUPPORTED,                  exec_cut                  }, /* OLECMDID_CUT */
653     { OLECMDF_SUPPORTED,                  exec_copy                 }, /* OLECMDID_COPY */
654     { OLECMDF_SUPPORTED,                  exec_paste                }, /* OLECMDID_PASTE */
655     { OLECMDF_SUPPORTED,                  exec_paste_special        }, /* OLECMDID_PASTESPECIAL */
656     { OLECMDF_SUPPORTED,                  exec_undo                 }, /* OLECMDID_UNDO */
657     { OLECMDF_SUPPORTED,                  exec_rendo                }, /* OLECMDID_REDO */
658     { OLECMDF_SUPPORTED|OLECMDF_ENABLED,  exec_select_all           }, /* OLECMDID_SELECTALL */
659     { OLECMDF_SUPPORTED,                  exec_clear_selection      }, /* OLECMDID_CLEARSELECTION */
660     { OLECMDF_SUPPORTED,                  exec_zoom                 }, /* OLECMDID_ZOOM */
661     { OLECMDF_SUPPORTED,                  exec_get_zoom_range       }, /* OLECMDID_GETZOOMRANGE */
662     {0},
663     { OLECMDF_SUPPORTED|OLECMDF_ENABLED,  exec_refresh              }, /* OLECMDID_REFRESH */
664     { OLECMDF_SUPPORTED|OLECMDF_ENABLED,  exec_stop                 }, /* OLECMDID_STOP */
665     {0},{0},{0},{0},{0},{0},
666     { OLECMDF_SUPPORTED,                  exec_stop_download        }, /* OLECMDID_STOPDOWNLOAD */
667     {0},{0},
668     { OLECMDF_SUPPORTED,                  exec_delete               }, /* OLECMDID_DELETE */
669     {0},{0},
670     { OLECMDF_SUPPORTED,                  exec_enable_interaction   }, /* OLECMDID_ENABLE_INTERACTION */
671     { OLECMDF_SUPPORTED,                  exec_on_unload            }, /* OLECMDID_ONUNLOAD */
672     {0},{0},{0},{0},{0},
673     { OLECMDF_SUPPORTED,                  exec_show_page_setup      }, /* OLECMDID_SHOWPAGESETUP */
674     { OLECMDF_SUPPORTED,                  exec_show_print           }, /* OLECMDID_SHOWPRINT */
675     {0},{0},
676     { OLECMDF_SUPPORTED,                  exec_close                }, /* OLECMDID_CLOSE */
677     {0},{0},{0},
678     { OLECMDF_SUPPORTED,                  exec_set_print_template   }, /* OLECMDID_SETPRINTTEMPLATE */
679     { OLECMDF_SUPPORTED,                  exec_get_print_template   }  /* OLECMDID_GETPRINTTEMPLATE */
680 };
681
682 static const cmdtable_t base_cmds[] = {
683     {IDM_COPY,             query_mshtml_copy,     exec_mshtml_copy},
684     {IDM_PASTE,            query_mshtml_paste,    exec_mshtml_paste},
685     {IDM_CUT,              query_mshtml_cut,      exec_mshtml_cut},
686     {IDM_BROWSEMODE,       NULL,                  exec_browsemode},
687     {IDM_EDITMODE,         NULL,                  exec_editmode},
688     {IDM_PRINT,            query_enabled_stub,    exec_print},
689     {IDM_SETDIRTY,         NULL,                  exec_setdirty},
690     {IDM_HTMLEDITMODE,     NULL,                  exec_htmleditmode},
691     {IDM_BASELINEFONT3,    NULL,                  exec_baselinefont3},
692     {IDM_BLOCKDIRLTR,      query_enabled_stub,    NULL},
693     {IDM_BLOCKDIRRTL,      query_enabled_stub,    NULL},
694     {IDM_RESPECTVISIBILITY_INDESIGN, NULL,        exec_respectvisibility_indesign},
695     {0,NULL,NULL}
696 };
697
698 static HRESULT WINAPI OleCommandTarget_QueryInterface(IOleCommandTarget *iface, REFIID riid, void **ppv)
699 {
700     HTMLDocument *This = CMDTARGET_THIS(iface);
701     return IHTMLDocument2_QueryInterface(HTMLDOC(This), riid, ppv);
702 }
703
704 static ULONG WINAPI OleCommandTarget_AddRef(IOleCommandTarget *iface)
705 {
706     HTMLDocument *This = CMDTARGET_THIS(iface);
707     return IHTMLDocument2_AddRef(HTMLDOC(This));
708 }
709
710 static ULONG WINAPI OleCommandTarget_Release(IOleCommandTarget *iface)
711 {
712     HTMLDocument *This = CMDTARGET_THIS(iface);
713     return IHTMLDocument_Release(HTMLDOC(This));
714 }
715
716 static HRESULT query_from_table(HTMLDocument *This, const cmdtable_t *cmdtable, OLECMD *cmd)
717 {
718     const cmdtable_t *iter = cmdtable;
719
720     cmd->cmdf = 0;
721
722     while(iter->id && iter->id != cmd->cmdID)
723         iter++;
724
725     if(!iter->id || !iter->query)
726         return OLECMDERR_E_NOTSUPPORTED;
727
728     return iter->query(This, cmd);
729 }
730
731 static HRESULT WINAPI OleCommandTarget_QueryStatus(IOleCommandTarget *iface, const GUID *pguidCmdGroup,
732         ULONG cCmds, OLECMD prgCmds[], OLECMDTEXT *pCmdText)
733 {
734     HTMLDocument *This = CMDTARGET_THIS(iface);
735     HRESULT hres = S_OK, hr;
736
737     TRACE("(%p)->(%s %d %p %p)\n", This, debugstr_guid(pguidCmdGroup), cCmds, prgCmds, pCmdText);
738
739     if(!pguidCmdGroup) {
740         ULONG i;
741
742         for(i=0; i<cCmds; i++) {
743             if(prgCmds[i].cmdID<OLECMDID_OPEN || prgCmds[i].cmdID>OLECMDID_GETPRINTTEMPLATE) {
744                 WARN("Unsupported cmdID = %d\n", prgCmds[i].cmdID);
745                 prgCmds[i].cmdf = 0;
746                 hres = OLECMDERR_E_NOTSUPPORTED;
747             }else {
748                 if(prgCmds[i].cmdID == OLECMDID_OPEN || prgCmds[i].cmdID == OLECMDID_NEW) {
749                     IOleCommandTarget *cmdtrg = NULL;
750                     OLECMD olecmd;
751
752                     prgCmds[i].cmdf = OLECMDF_SUPPORTED;
753                     if(This->client) {
754                         hr = IOleClientSite_QueryInterface(This->client, &IID_IOleCommandTarget,
755                                 (void**)&cmdtrg);
756                         if(SUCCEEDED(hr)) {
757                             olecmd.cmdID = prgCmds[i].cmdID;
758                             olecmd.cmdf = 0;
759
760                             hr = IOleCommandTarget_QueryStatus(cmdtrg, NULL, 1, &olecmd, NULL);
761                             if(SUCCEEDED(hr) && olecmd.cmdf)
762                                 prgCmds[i].cmdf = olecmd.cmdf;
763                         }
764                     }else {
765                         ERR("This->client == NULL, native would crash\n");
766                     }
767                 }else {
768                     prgCmds[i].cmdf = exec_table[prgCmds[i].cmdID].cmdf;
769                     TRACE("cmdID = %d  returning %x\n", prgCmds[i].cmdID, prgCmds[i].cmdf);
770                 }
771                 hres = S_OK;
772             }
773         }
774
775         if(pCmdText)
776             FIXME("Set pCmdText\n");
777     }else if(IsEqualGUID(&CGID_MSHTML, pguidCmdGroup)) {
778         ULONG i;
779
780         for(i=0; i<cCmds; i++) {
781             HRESULT hres = query_from_table(This, base_cmds, prgCmds+i);
782             if(hres == OLECMDERR_E_NOTSUPPORTED)
783                 hres = query_from_table(This, editmode_cmds, prgCmds+i);
784             if(hres == OLECMDERR_E_NOTSUPPORTED)
785                 FIXME("CGID_MSHTML: unsupported cmdID %d\n", prgCmds[i].cmdID);
786         }
787
788         hres = prgCmds[i-1].cmdf ? S_OK : OLECMDERR_E_NOTSUPPORTED;
789
790         if(pCmdText)
791             FIXME("Set pCmdText\n");
792     }else {
793         FIXME("Unsupported pguidCmdGroup %s\n", debugstr_guid(pguidCmdGroup));
794         hres = OLECMDERR_E_UNKNOWNGROUP;
795     }
796
797     return hres;
798 }
799
800 static HRESULT exec_from_table(HTMLDocument *This, const cmdtable_t *cmdtable, DWORD cmdid,
801                                DWORD cmdexecopt, VARIANT *in, VARIANT *out)
802 {
803     const cmdtable_t *iter = cmdtable;
804
805     while(iter->id && iter->id != cmdid)
806         iter++;
807
808     if(!iter->id || !iter->exec)
809         return OLECMDERR_E_NOTSUPPORTED;
810
811     return iter->exec(This, cmdexecopt, in, out);
812 }
813
814 static HRESULT WINAPI OleCommandTarget_Exec(IOleCommandTarget *iface, const GUID *pguidCmdGroup,
815         DWORD nCmdID, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
816 {
817     HTMLDocument *This = CMDTARGET_THIS(iface);
818
819     if(!pguidCmdGroup) {
820         if(nCmdID<OLECMDID_OPEN || nCmdID>OLECMDID_GETPRINTTEMPLATE || !exec_table[nCmdID].func) {
821             WARN("Unsupported cmdID = %d\n", nCmdID);
822             return OLECMDERR_E_NOTSUPPORTED;
823         }
824
825         return exec_table[nCmdID].func(This, nCmdexecopt, pvaIn, pvaOut);
826     }else if(IsEqualGUID(&CGID_Explorer, pguidCmdGroup)) {
827         FIXME("unsupported nCmdID %d of CGID_Explorer group\n", nCmdID);
828         TRACE("%p %p\n", pvaIn, pvaOut);
829         return OLECMDERR_E_NOTSUPPORTED;
830     }else if(IsEqualGUID(&CGID_ShellDocView, pguidCmdGroup)) {
831         FIXME("unsupported nCmdID %d of CGID_ShellDocView group\n", nCmdID);
832         return OLECMDERR_E_NOTSUPPORTED;
833     }else if(IsEqualGUID(&CGID_MSHTML, pguidCmdGroup)) {
834         HRESULT hres = exec_from_table(This, base_cmds, nCmdID, nCmdexecopt, pvaIn, pvaOut);
835         if(hres == OLECMDERR_E_NOTSUPPORTED)
836             hres = exec_from_table(This, editmode_cmds, nCmdID,
837                                    nCmdexecopt, pvaIn, pvaOut);
838         if(hres == OLECMDERR_E_NOTSUPPORTED)
839             FIXME("unsupported nCmdID %d of CGID_MSHTML group\n", nCmdID);
840
841         return hres;
842     }
843
844     FIXME("Unsupported pguidCmdGroup %s\n", debugstr_guid(pguidCmdGroup));
845     return OLECMDERR_E_UNKNOWNGROUP;
846 }
847
848 #undef CMDTARGET_THIS
849
850 static const IOleCommandTargetVtbl OleCommandTargetVtbl = {
851     OleCommandTarget_QueryInterface,
852     OleCommandTarget_AddRef,
853     OleCommandTarget_Release,
854     OleCommandTarget_QueryStatus,
855     OleCommandTarget_Exec
856 };
857
858 void show_context_menu(HTMLDocument *This, DWORD dwID, POINT *ppt)
859 {
860     HMENU menu_res, menu;
861     DWORD cmdid;
862     HRESULT hres;
863
864     hres = IDocHostUIHandler_ShowContextMenu(This->hostui, dwID, ppt,
865             (IUnknown*)CMDTARGET(This), (IDispatch*)HTMLDOC(This));
866     if(hres == S_OK)
867         return;
868
869     menu_res = LoadMenuW(get_shdoclc(), MAKEINTRESOURCEW(IDR_BROWSE_CONTEXT_MENU));
870     menu = GetSubMenu(menu_res, dwID);
871
872     cmdid = TrackPopupMenu(menu, TPM_LEFTALIGN | TPM_RIGHTBUTTON | TPM_RETURNCMD,
873             ppt->x, ppt->y, 0, This->hwnd, NULL);
874     DestroyMenu(menu_res);
875
876     IOleCommandTarget_Exec(CMDTARGET(This), &CGID_MSHTML, cmdid, 0, NULL, NULL);
877 }
878
879 void HTMLDocument_OleCmd_Init(HTMLDocument *This)
880 {
881     This->lpOleCommandTargetVtbl = &OleCommandTargetVtbl;
882 }