mshtml: Use ifaces instead of vtbl pointers in HTMLDocumentNode.
[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 #include "wine/unicode.h"
34
35 #include "mshtml_private.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 %p %p)\n", This, nCmdexecopt, 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("V_VT(opts) = %d\n", V_VT(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("V_VT(opts) = %d\n", V_VT(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 vt %x\n", V_VT(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 static HRESULT exec_refresh(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
389 {
390     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
391     return E_NOTIMPL;
392 }
393
394 static HRESULT exec_stop(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
395 {
396     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
397     return E_NOTIMPL;
398 }
399
400 static HRESULT exec_stop_download(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
401 {
402     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
403     return E_NOTIMPL;
404 }
405
406 static HRESULT exec_find(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
407 {
408     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
409     return E_NOTIMPL;
410 }
411
412 static HRESULT exec_delete(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
413 {
414     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
415     return E_NOTIMPL;
416 }
417
418 static HRESULT exec_enable_interaction(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
419 {
420     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
421     return E_NOTIMPL;
422 }
423
424 static HRESULT exec_on_unload(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
425 {
426     TRACE("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
427
428     /* Tests show that we have nothing more to do here */
429
430     if(pvaOut) {
431         V_VT(pvaOut) = VT_BOOL;
432         V_BOOL(pvaOut) = VARIANT_TRUE;
433     }
434
435     return S_OK;
436 }
437
438 static HRESULT exec_show_page_setup(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
439 {
440     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
441     return E_NOTIMPL;
442 }
443
444 static HRESULT exec_show_print(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
445 {
446     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
447     return E_NOTIMPL;
448 }
449
450 static HRESULT exec_close(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
451 {
452     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
453     return E_NOTIMPL;
454 }
455
456 static HRESULT exec_set_print_template(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
457 {
458     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
459     return E_NOTIMPL;
460 }
461
462 static HRESULT exec_get_print_template(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
463 {
464     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
465     return E_NOTIMPL;
466 }
467
468 static HRESULT query_mshtml_copy(HTMLDocument *This, OLECMD *cmd)
469 {
470     FIXME("(%p)\n", This);
471     cmd->cmdf = OLECMDF_SUPPORTED|OLECMDF_ENABLED;
472     return S_OK;
473 }
474
475 static HRESULT exec_mshtml_copy(HTMLDocument *This, DWORD cmdexecopt, VARIANT *in, VARIANT *out)
476 {
477     TRACE("(%p)->(%08x %p %p)\n", This, cmdexecopt, in, out);
478
479     if(This->doc_obj->usermode == EDITMODE)
480         return editor_exec_copy(This, cmdexecopt, in, out);
481
482     do_ns_command(This, NSCMD_COPY, NULL);
483     return S_OK;
484 }
485
486 static HRESULT query_mshtml_cut(HTMLDocument *This, OLECMD *cmd)
487 {
488     FIXME("(%p)\n", This);
489     cmd->cmdf = OLECMDF_SUPPORTED|OLECMDF_ENABLED;
490     return S_OK;
491 }
492
493 static HRESULT exec_mshtml_cut(HTMLDocument *This, DWORD cmdexecopt, VARIANT *in, VARIANT *out)
494 {
495     TRACE("(%p)->(%08x %p %p)\n", This, cmdexecopt, in, out);
496
497     if(This->doc_obj->usermode == EDITMODE)
498         return editor_exec_cut(This, cmdexecopt, in, out);
499
500     FIXME("Unimplemented in browse mode\n");
501     return E_NOTIMPL;
502 }
503
504 static HRESULT query_mshtml_paste(HTMLDocument *This, OLECMD *cmd)
505 {
506     FIXME("(%p)\n", This);
507     cmd->cmdf = OLECMDF_SUPPORTED|OLECMDF_ENABLED;
508     return S_OK;
509 }
510
511 static HRESULT exec_mshtml_paste(HTMLDocument *This, DWORD cmdexecopt, VARIANT *in, VARIANT *out)
512 {
513     TRACE("(%p)->(%08x %p %p)\n", This, cmdexecopt, in, out);
514
515     if(This->doc_obj->usermode == EDITMODE)
516         return editor_exec_paste(This, cmdexecopt, in, out);
517
518     FIXME("Unimplemented in browse mode\n");
519     return E_NOTIMPL;
520 }
521
522 static HRESULT exec_browsemode(HTMLDocument *This, DWORD cmdexecopt, VARIANT *in, VARIANT *out)
523 {
524     WARN("(%p)->(%08x %p %p)\n", This, cmdexecopt, in, out);
525
526     if(in || out)
527         FIXME("unsupported args\n");
528
529     This->doc_obj->usermode = BROWSEMODE;
530
531     return S_OK;
532 }
533
534 static HRESULT exec_editmode(HTMLDocument *This, DWORD cmdexecopt, VARIANT *in, VARIANT *out)
535 {
536     IMoniker *mon;
537     HRESULT hres;
538
539     TRACE("(%p)->(%08x %p %p)\n", This, cmdexecopt, in, out);
540
541     if(in || out)
542         FIXME("unsupported args\n");
543
544     if(This->doc_obj->usermode == EDITMODE)
545         return S_OK;
546
547     This->doc_obj->usermode = EDITMODE;
548
549     if(This->window->mon) {
550         CLSID clsid = IID_NULL;
551         hres = IMoniker_GetClassID(This->window->mon, &clsid);
552         if(SUCCEEDED(hres)) {
553             /* We should use IMoniker::Save here */
554             FIXME("Use CLSID %s\n", debugstr_guid(&clsid));
555         }
556     }
557
558     if(This->doc_obj->frame)
559         IOleInPlaceFrame_SetStatusText(This->doc_obj->frame, NULL);
560
561     This->window->readystate = READYSTATE_UNINITIALIZED;
562
563     if(This->doc_obj->client) {
564         IOleCommandTarget *cmdtrg;
565
566         hres = IOleClientSite_QueryInterface(This->doc_obj->client, &IID_IOleCommandTarget,
567                 (void**)&cmdtrg);
568         if(SUCCEEDED(hres)) {
569             VARIANT var;
570
571             V_VT(&var) = VT_I4;
572             V_I4(&var) = 0;
573             IOleCommandTarget_Exec(cmdtrg, &CGID_ShellDocView, 37, 0, &var, NULL);
574
575             IOleCommandTarget_Release(cmdtrg);
576         }
577     }
578
579     if(This->doc_obj->hostui) {
580         DOCHOSTUIINFO hostinfo;
581
582         memset(&hostinfo, 0, sizeof(DOCHOSTUIINFO));
583         hostinfo.cbSize = sizeof(DOCHOSTUIINFO);
584         hres = IDocHostUIHandler_GetHostInfo(This->doc_obj->hostui, &hostinfo);
585         if(SUCCEEDED(hres))
586             /* FIXME: use hostinfo */
587             TRACE("hostinfo = {%u %08x %08x %s %s}\n",
588                     hostinfo.cbSize, hostinfo.dwFlags, hostinfo.dwDoubleClick,
589                     debugstr_w(hostinfo.pchHostCss), debugstr_w(hostinfo.pchHostNS));
590     }
591
592     update_doc(This, UPDATE_UI);
593
594     if(This->window->mon) {
595         /* FIXME: We should find nicer way to do this */
596         remove_target_tasks(This->task_magic);
597
598         mon = This->window->mon;
599         IMoniker_AddRef(mon);
600     }else {
601         static const WCHAR about_blankW[] = {'a','b','o','u','t',':','b','l','a','n','k',0};
602
603         hres = CreateURLMoniker(NULL, about_blankW, &mon);
604         if(FAILED(hres)) {
605             FIXME("CreateURLMoniker failed: %08x\n", hres);
606             return hres;
607         }
608     }
609
610     hres = IPersistMoniker_Load(&This->IPersistMoniker_iface, TRUE, mon, NULL, 0);
611     IMoniker_Release(mon);
612     if(FAILED(hres))
613         return hres;
614
615     if(This->doc_obj->ui_active) {
616         if(This->doc_obj->ip_window)
617             call_set_active_object(This->doc_obj->ip_window, NULL);
618         if(This->doc_obj->hostui)
619             IDocHostUIHandler_HideUI(This->doc_obj->hostui);
620     }
621
622     if(This->doc_obj->ui_active) {
623         RECT rcBorderWidths;
624
625         if(This->doc_obj->hostui)
626             IDocHostUIHandler_ShowUI(This->doc_obj->hostui, DOCHOSTUITYPE_AUTHOR,
627                     &This->IOleInPlaceActiveObject_iface, &This->IOleCommandTarget_iface,
628                     This->doc_obj->frame, This->doc_obj->ip_window);
629
630         if(This->doc_obj->ip_window)
631             call_set_active_object(This->doc_obj->ip_window, &This->IOleInPlaceActiveObject_iface);
632
633         memset(&rcBorderWidths, 0, sizeof(rcBorderWidths));
634         if(This->doc_obj->frame)
635             IOleInPlaceFrame_SetBorderSpace(This->doc_obj->frame, &rcBorderWidths);
636     }
637
638     return S_OK;
639 }
640
641 static HRESULT exec_htmleditmode(HTMLDocument *This, DWORD cmdexecopt, VARIANT *in, VARIANT *out)
642 {
643     FIXME("(%p)->(%08x %p %p)\n", This, cmdexecopt, in, out);
644     return S_OK;
645 }
646
647 static HRESULT exec_baselinefont3(HTMLDocument *This, DWORD cmdexecopt, VARIANT *in, VARIANT *out)
648 {
649     FIXME("(%p)->(%08x %p %p)\n", This, cmdexecopt, in, out);
650     return S_OK;
651 }
652
653 static HRESULT exec_respectvisibility_indesign(HTMLDocument *This, DWORD cmdexecopt,
654         VARIANT *in, VARIANT *out)
655 {
656     FIXME("(%p)->(%08x %p %p)\n", This, cmdexecopt, in, out);
657     return E_NOTIMPL;
658 }
659
660 static HRESULT query_enabled_stub(HTMLDocument *This, OLECMD *cmd)
661 {
662     switch(cmd->cmdID) {
663     case IDM_PRINT:
664         FIXME("CGID_MSHTML: IDM_PRINT\n");
665         cmd->cmdf = OLECMDF_SUPPORTED|OLECMDF_ENABLED;
666         break;
667     case IDM_BLOCKDIRLTR:
668         FIXME("CGID_MSHTML: IDM_BLOCKDIRLTR\n");
669         cmd->cmdf = OLECMDF_SUPPORTED|OLECMDF_ENABLED;
670         break;
671     case IDM_BLOCKDIRRTL:
672         FIXME("CGID_MSHTML: IDM_BLOCKDIRRTL\n");
673         cmd->cmdf = OLECMDF_SUPPORTED|OLECMDF_ENABLED;
674         break;
675     }
676
677     return S_OK;
678 }
679
680 static const struct {
681     OLECMDF cmdf;
682     HRESULT (*func)(HTMLDocument*,DWORD,VARIANT*,VARIANT*);
683 } exec_table[OLECMDID_GETPRINTTEMPLATE+1] = {
684     {0},
685     { OLECMDF_SUPPORTED,                  exec_open                 }, /* OLECMDID_OPEN */
686     { OLECMDF_SUPPORTED,                  exec_new                  }, /* OLECMDID_NEW */
687     { OLECMDF_SUPPORTED,                  exec_save                 }, /* OLECMDID_SAVE */
688     { OLECMDF_SUPPORTED|OLECMDF_ENABLED,  exec_save_as              }, /* OLECMDID_SAVEAS */
689     { OLECMDF_SUPPORTED,                  exec_save_copy_as         }, /* OLECMDID_SAVECOPYAS */
690     { OLECMDF_SUPPORTED|OLECMDF_ENABLED,  exec_print                }, /* OLECMDID_PRINT */
691     { OLECMDF_SUPPORTED|OLECMDF_ENABLED,  exec_print_preview        }, /* OLECMDID_PRINTPREVIEW */
692     { OLECMDF_SUPPORTED|OLECMDF_ENABLED,  exec_page_setup           }, /* OLECMDID_PAGESETUP */
693     { OLECMDF_SUPPORTED,                  exec_spell                }, /* OLECMDID_SPELL */
694     { OLECMDF_SUPPORTED|OLECMDF_ENABLED,  exec_properties           }, /* OLECMDID_PROPERTIES */
695     { OLECMDF_SUPPORTED,                  exec_cut                  }, /* OLECMDID_CUT */
696     { OLECMDF_SUPPORTED,                  exec_copy                 }, /* OLECMDID_COPY */
697     { OLECMDF_SUPPORTED,                  exec_paste                }, /* OLECMDID_PASTE */
698     { OLECMDF_SUPPORTED,                  exec_paste_special        }, /* OLECMDID_PASTESPECIAL */
699     { OLECMDF_SUPPORTED,                  exec_undo                 }, /* OLECMDID_UNDO */
700     { OLECMDF_SUPPORTED,                  exec_rendo                }, /* OLECMDID_REDO */
701     { OLECMDF_SUPPORTED|OLECMDF_ENABLED,  exec_select_all           }, /* OLECMDID_SELECTALL */
702     { OLECMDF_SUPPORTED,                  exec_clear_selection      }, /* OLECMDID_CLEARSELECTION */
703     { OLECMDF_SUPPORTED,                  exec_zoom                 }, /* OLECMDID_ZOOM */
704     { OLECMDF_SUPPORTED,                  exec_get_zoom_range       }, /* OLECMDID_GETZOOMRANGE */
705     {0},
706     { OLECMDF_SUPPORTED|OLECMDF_ENABLED,  exec_refresh              }, /* OLECMDID_REFRESH */
707     { OLECMDF_SUPPORTED|OLECMDF_ENABLED,  exec_stop                 }, /* OLECMDID_STOP */
708     {0},{0},{0},{0},{0},{0},
709     { OLECMDF_SUPPORTED,                  exec_stop_download        }, /* OLECMDID_STOPDOWNLOAD */
710     {0},
711     { OLECMDF_SUPPORTED|OLECMDF_ENABLED,  exec_find                 }, /* OLECMDID_FIND */
712     { OLECMDF_SUPPORTED,                  exec_delete               }, /* OLECMDID_DELETE */
713     {0},{0},
714     { OLECMDF_SUPPORTED,                  exec_enable_interaction   }, /* OLECMDID_ENABLE_INTERACTION */
715     { OLECMDF_SUPPORTED,                  exec_on_unload            }, /* OLECMDID_ONUNLOAD */
716     {0},{0},{0},{0},{0},
717     { OLECMDF_SUPPORTED,                  exec_show_page_setup      }, /* OLECMDID_SHOWPAGESETUP */
718     { OLECMDF_SUPPORTED,                  exec_show_print           }, /* OLECMDID_SHOWPRINT */
719     {0},{0},
720     { OLECMDF_SUPPORTED,                  exec_close                }, /* OLECMDID_CLOSE */
721     {0},{0},{0},
722     { OLECMDF_SUPPORTED,                  exec_set_print_template   }, /* OLECMDID_SETPRINTTEMPLATE */
723     { OLECMDF_SUPPORTED,                  exec_get_print_template   }  /* OLECMDID_GETPRINTTEMPLATE */
724 };
725
726 static const cmdtable_t base_cmds[] = {
727     {IDM_COPY,             query_mshtml_copy,     exec_mshtml_copy},
728     {IDM_PASTE,            query_mshtml_paste,    exec_mshtml_paste},
729     {IDM_CUT,              query_mshtml_cut,      exec_mshtml_cut},
730     {IDM_BROWSEMODE,       NULL,                  exec_browsemode},
731     {IDM_EDITMODE,         NULL,                  exec_editmode},
732     {IDM_PRINT,            query_enabled_stub,    exec_print},
733     {IDM_HTMLEDITMODE,     NULL,                  exec_htmleditmode},
734     {IDM_BASELINEFONT3,    NULL,                  exec_baselinefont3},
735     {IDM_BLOCKDIRLTR,      query_enabled_stub,    NULL},
736     {IDM_BLOCKDIRRTL,      query_enabled_stub,    NULL},
737     {IDM_RESPECTVISIBILITY_INDESIGN, NULL,        exec_respectvisibility_indesign},
738     {0,NULL,NULL}
739 };
740
741 static HRESULT WINAPI OleCommandTarget_QueryInterface(IOleCommandTarget *iface, REFIID riid, void **ppv)
742 {
743     HTMLDocument *This = impl_from_IOleCommandTarget(iface);
744     return htmldoc_query_interface(This, riid, ppv);
745 }
746
747 static ULONG WINAPI OleCommandTarget_AddRef(IOleCommandTarget *iface)
748 {
749     HTMLDocument *This = impl_from_IOleCommandTarget(iface);
750     return htmldoc_addref(This);
751 }
752
753 static ULONG WINAPI OleCommandTarget_Release(IOleCommandTarget *iface)
754 {
755     HTMLDocument *This = impl_from_IOleCommandTarget(iface);
756     return htmldoc_release(This);
757 }
758
759 static HRESULT query_from_table(HTMLDocument *This, const cmdtable_t *cmdtable, OLECMD *cmd)
760 {
761     const cmdtable_t *iter = cmdtable;
762
763     cmd->cmdf = 0;
764
765     while(iter->id && iter->id != cmd->cmdID)
766         iter++;
767
768     if(!iter->id || !iter->query)
769         return OLECMDERR_E_NOTSUPPORTED;
770
771     return iter->query(This, cmd);
772 }
773
774 static HRESULT WINAPI OleCommandTarget_QueryStatus(IOleCommandTarget *iface, const GUID *pguidCmdGroup,
775         ULONG cCmds, OLECMD prgCmds[], OLECMDTEXT *pCmdText)
776 {
777     HTMLDocument *This = impl_from_IOleCommandTarget(iface);
778     HRESULT hres = S_OK, hr;
779
780     TRACE("(%p)->(%s %d %p %p)\n", This, debugstr_guid(pguidCmdGroup), cCmds, prgCmds, pCmdText);
781
782     if(!pguidCmdGroup) {
783         ULONG i;
784
785         for(i=0; i<cCmds; i++) {
786             if(prgCmds[i].cmdID<OLECMDID_OPEN || prgCmds[i].cmdID>OLECMDID_GETPRINTTEMPLATE) {
787                 WARN("Unsupported cmdID = %d\n", prgCmds[i].cmdID);
788                 prgCmds[i].cmdf = 0;
789                 hres = OLECMDERR_E_NOTSUPPORTED;
790             }else {
791                 if(prgCmds[i].cmdID == OLECMDID_OPEN || prgCmds[i].cmdID == OLECMDID_NEW) {
792                     IOleCommandTarget *cmdtrg = NULL;
793                     OLECMD olecmd;
794
795                     prgCmds[i].cmdf = OLECMDF_SUPPORTED;
796                     if(This->doc_obj->client) {
797                         hr = IOleClientSite_QueryInterface(This->doc_obj->client, &IID_IOleCommandTarget,
798                                 (void**)&cmdtrg);
799                         if(SUCCEEDED(hr)) {
800                             olecmd.cmdID = prgCmds[i].cmdID;
801                             olecmd.cmdf = 0;
802
803                             hr = IOleCommandTarget_QueryStatus(cmdtrg, NULL, 1, &olecmd, NULL);
804                             if(SUCCEEDED(hr) && olecmd.cmdf)
805                                 prgCmds[i].cmdf = olecmd.cmdf;
806                         }
807                     }else {
808                         ERR("This->client == NULL, native would crash\n");
809                     }
810                 }else {
811                     prgCmds[i].cmdf = exec_table[prgCmds[i].cmdID].cmdf;
812                     TRACE("cmdID = %d  returning %x\n", prgCmds[i].cmdID, prgCmds[i].cmdf);
813                 }
814                 hres = S_OK;
815             }
816         }
817
818         if(pCmdText)
819             FIXME("Set pCmdText\n");
820     }else if(IsEqualGUID(&CGID_MSHTML, pguidCmdGroup)) {
821         ULONG i;
822
823         for(i=0; i<cCmds; i++) {
824             HRESULT hres = query_from_table(This, base_cmds, prgCmds+i);
825             if(hres == OLECMDERR_E_NOTSUPPORTED)
826                 hres = query_from_table(This, editmode_cmds, prgCmds+i);
827             if(hres == OLECMDERR_E_NOTSUPPORTED)
828                 FIXME("CGID_MSHTML: unsupported cmdID %d\n", prgCmds[i].cmdID);
829         }
830
831         hres = prgCmds[i-1].cmdf ? S_OK : OLECMDERR_E_NOTSUPPORTED;
832
833         if(pCmdText)
834             FIXME("Set pCmdText\n");
835     }else {
836         FIXME("Unsupported pguidCmdGroup %s\n", debugstr_guid(pguidCmdGroup));
837         hres = OLECMDERR_E_UNKNOWNGROUP;
838     }
839
840     return hres;
841 }
842
843 static HRESULT exec_from_table(HTMLDocument *This, const cmdtable_t *cmdtable, DWORD cmdid,
844                                DWORD cmdexecopt, VARIANT *in, VARIANT *out)
845 {
846     const cmdtable_t *iter = cmdtable;
847
848     while(iter->id && iter->id != cmdid)
849         iter++;
850
851     if(!iter->id || !iter->exec)
852         return OLECMDERR_E_NOTSUPPORTED;
853
854     return iter->exec(This, cmdexecopt, in, out);
855 }
856
857 static HRESULT WINAPI OleCommandTarget_Exec(IOleCommandTarget *iface, const GUID *pguidCmdGroup,
858         DWORD nCmdID, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
859 {
860     HTMLDocument *This = impl_from_IOleCommandTarget(iface);
861
862     if(!pguidCmdGroup) {
863         if(nCmdID<OLECMDID_OPEN || nCmdID>OLECMDID_GETPRINTTEMPLATE || !exec_table[nCmdID].func) {
864             WARN("Unsupported cmdID = %d\n", nCmdID);
865             return OLECMDERR_E_NOTSUPPORTED;
866         }
867
868         return exec_table[nCmdID].func(This, nCmdexecopt, pvaIn, pvaOut);
869     }else if(IsEqualGUID(&CGID_Explorer, pguidCmdGroup)) {
870         FIXME("unsupported nCmdID %d of CGID_Explorer group\n", nCmdID);
871         TRACE("%p %p\n", pvaIn, pvaOut);
872         return OLECMDERR_E_NOTSUPPORTED;
873     }else if(IsEqualGUID(&CGID_ShellDocView, pguidCmdGroup)) {
874         FIXME("unsupported nCmdID %d of CGID_ShellDocView group\n", nCmdID);
875         return OLECMDERR_E_NOTSUPPORTED;
876     }else if(IsEqualGUID(&CGID_MSHTML, pguidCmdGroup)) {
877         HRESULT hres = exec_from_table(This, base_cmds, nCmdID, nCmdexecopt, pvaIn, pvaOut);
878         if(hres == OLECMDERR_E_NOTSUPPORTED)
879             hres = exec_from_table(This, editmode_cmds, nCmdID,
880                                    nCmdexecopt, pvaIn, pvaOut);
881         if(hres == OLECMDERR_E_NOTSUPPORTED)
882             FIXME("unsupported nCmdID %d of CGID_MSHTML group\n", nCmdID);
883
884         return hres;
885     }
886
887     FIXME("Unsupported pguidCmdGroup %s\n", debugstr_guid(pguidCmdGroup));
888     return OLECMDERR_E_UNKNOWNGROUP;
889 }
890
891 #undef CMDTARGET_THIS
892
893 static const IOleCommandTargetVtbl OleCommandTargetVtbl = {
894     OleCommandTarget_QueryInterface,
895     OleCommandTarget_AddRef,
896     OleCommandTarget_Release,
897     OleCommandTarget_QueryStatus,
898     OleCommandTarget_Exec
899 };
900
901 void show_context_menu(HTMLDocumentObj *This, DWORD dwID, POINT *ppt, IDispatch *elem)
902 {
903     HMENU menu_res, menu;
904     DWORD cmdid;
905
906     if(This->hostui && S_OK == IDocHostUIHandler_ShowContextMenu(This->hostui,
907             dwID, ppt, (IUnknown*)&This->basedoc.IOleCommandTarget_iface, elem))
908         return;
909
910     menu_res = LoadMenuW(get_shdoclc(), MAKEINTRESOURCEW(IDR_BROWSE_CONTEXT_MENU));
911     menu = GetSubMenu(menu_res, dwID);
912
913     cmdid = TrackPopupMenu(menu, TPM_LEFTALIGN | TPM_RIGHTBUTTON | TPM_RETURNCMD,
914             ppt->x, ppt->y, 0, This->hwnd, NULL);
915     DestroyMenu(menu_res);
916
917     if(cmdid)
918         IOleCommandTarget_Exec(&This->basedoc.IOleCommandTarget_iface, &CGID_MSHTML, cmdid, 0,
919                 NULL, NULL);
920 }
921
922 void HTMLDocument_OleCmd_Init(HTMLDocument *This)
923 {
924     This->IOleCommandTarget_iface.lpVtbl = &OleCommandTargetVtbl;
925 }