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