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