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