mshtml: Code clean up.
[wine] / dlls / mshtml / olecmd.c
1 /*
2  * Copyright 2005-2006 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
38 #include "mshtml_private.h"
39
40 WINE_DEFAULT_DEBUG_CHANNEL(mshtml);
41
42 #define NSCMD_BOLD "cmd_bold"
43 #define NSCMD_ITALIC "cmd_italic"
44 #define NSCMD_UNDERLINE "cmd_underline"
45 #define NSCMD_FONTCOLOR "cmd_fontColor"
46 #define NSCMD_ALIGN "cmd_align"
47 #define NSCMD_FONTFACE "cmd_fontFace"
48
49 #define NSSTATE_ATTRIBUTE "state_attribute"
50 #define NSSTATE_ALL "state_all"
51
52 /**********************************************************
53  * IOleCommandTarget implementation
54  */
55
56 #define CMDTARGET_THIS(iface) DEFINE_THIS(HTMLDocument, OleCommandTarget, iface)
57
58 static HRESULT exec_open(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
59 {
60     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
61     return E_NOTIMPL;
62 }
63
64 static HRESULT exec_new(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
65 {
66     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
67     return E_NOTIMPL;
68 }
69
70 static HRESULT exec_save(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
71 {
72     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
73     return E_NOTIMPL;
74 }
75
76 static HRESULT exec_save_as(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
77 {
78     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
79     return E_NOTIMPL;
80 }
81
82 static HRESULT exec_save_copy_as(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
83 {
84     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
85     return E_NOTIMPL;
86 }
87
88 static HRESULT exec_print(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
89 {
90     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
91     return E_NOTIMPL;
92 }
93
94 static HRESULT exec_print_preview(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
95 {
96     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
97     return E_NOTIMPL;
98 }
99
100 static HRESULT exec_page_setup(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
101 {
102     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
103     return E_NOTIMPL;
104 }
105
106 static HRESULT exec_spell(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
107 {
108     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
109     return E_NOTIMPL;
110 }
111
112 static HRESULT exec_properties(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
113 {
114     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
115     return E_NOTIMPL;
116 }
117
118 static HRESULT exec_cut(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
119 {
120     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
121     return E_NOTIMPL;
122 }
123
124 static HRESULT exec_copy(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
125 {
126     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
127     return E_NOTIMPL;
128 }
129
130 static HRESULT exec_paste(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
131 {
132     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
133     return E_NOTIMPL;
134 }
135
136 static HRESULT exec_paste_special(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
137 {
138     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
139     return E_NOTIMPL;
140 }
141
142 static HRESULT exec_undo(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
143 {
144     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
145     return E_NOTIMPL;
146 }
147
148 static HRESULT exec_rendo(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
149 {
150     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
151     return E_NOTIMPL;
152 }
153
154 static HRESULT exec_select_all(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
155 {
156     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
157     return E_NOTIMPL;
158 }
159
160 static HRESULT exec_clear_selection(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
161 {
162     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
163     return E_NOTIMPL;
164 }
165
166 static HRESULT exec_zoom(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
167 {
168     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
169     return E_NOTIMPL;
170 }
171
172 static HRESULT exec_get_zoom_range(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
173 {
174     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
175     return E_NOTIMPL;
176 }
177
178 static HRESULT exec_refresh(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
179 {
180     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
181     return E_NOTIMPL;
182 }
183
184 static HRESULT exec_stop(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
185 {
186     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
187     return E_NOTIMPL;
188 }
189
190 static HRESULT exec_stop_download(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
191 {
192     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
193     return E_NOTIMPL;
194 }
195
196 static HRESULT exec_delete(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
197 {
198     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
199     return E_NOTIMPL;
200 }
201
202 static HRESULT exec_enable_interaction(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
203 {
204     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
205     return E_NOTIMPL;
206 }
207
208 static HRESULT exec_on_unload(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
209 {
210     TRACE("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
211
212     /* Tests show that we have nothing more to do here */
213
214     if(pvaOut) {
215         V_VT(pvaOut) = VT_BOOL;
216         V_BOOL(pvaOut) = VARIANT_TRUE;
217     }
218
219     return S_OK;
220 }
221
222 static HRESULT exec_show_page_setup(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
223 {
224     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
225     return E_NOTIMPL;
226 }
227
228 static HRESULT exec_show_print(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
229 {
230     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
231     return E_NOTIMPL;
232 }
233
234 static HRESULT exec_close(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
235 {
236     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
237     return E_NOTIMPL;
238 }
239
240 static HRESULT exec_set_print_template(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
241 {
242     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
243     return E_NOTIMPL;
244 }
245
246 static HRESULT exec_get_print_template(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
247 {
248     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
249     return E_NOTIMPL;
250 }
251
252 static void do_ns_command(NSContainer *This, const char *cmd, nsICommandParams *nsparam)
253 {
254     nsICommandManager *cmdmgr;
255     nsIInterfaceRequestor *iface_req;
256     nsresult nsres;
257
258     TRACE("(%p)\n", This);
259
260     nsres = nsIWebBrowser_QueryInterface(This->webbrowser,
261             &IID_nsIInterfaceRequestor, (void**)&iface_req);
262     if(NS_FAILED(nsres)) {
263         ERR("Could not get nsIInterfaceRequestor: %08x\n", nsres);
264         return;
265     }
266
267     nsres = nsIInterfaceRequestor_GetInterface(iface_req, &IID_nsICommandManager,
268                                                (void**)&cmdmgr);
269     nsIInterfaceRequestor_Release(iface_req);
270     if(NS_FAILED(nsres)) {
271         ERR("Could not get nsICommandManager: %08x\n", nsres);
272         return;
273     }
274
275     nsres = nsICommandManager_DoCommand(cmdmgr, cmd, nsparam, NULL);
276     if(NS_FAILED(nsres))
277         ERR("DoCommand(%s) failed: %08x\n", debugstr_a(cmd), nsres);
278
279     nsICommandManager_Release(cmdmgr);
280 }
281
282 static nsresult get_ns_command_state(NSContainer *This, const char *cmd, nsICommandParams *nsparam)
283 {
284     nsICommandManager *cmdmgr;
285     nsIInterfaceRequestor *iface_req;
286     nsresult nsres;
287
288     nsres = nsIWebBrowser_QueryInterface(This->webbrowser,
289             &IID_nsIInterfaceRequestor, (void**)&iface_req);
290     if(NS_FAILED(nsres)) {
291         ERR("Could not get nsIInterfaceRequestor: %08x\n", nsres);
292         return nsres;
293     }
294
295     nsres = nsIInterfaceRequestor_GetInterface(iface_req, &IID_nsICommandManager,
296                                                (void**)&cmdmgr);
297     nsIInterfaceRequestor_Release(iface_req);
298     if(NS_FAILED(nsres)) {
299         ERR("Could not get nsICommandManager: %08x\n", nsres);
300         return nsres;
301     }
302
303     nsres = nsICommandManager_GetCommandState(cmdmgr, cmd, NULL, nsparam);
304     if(NS_FAILED(nsres))
305         ERR("GetCommandState(%s) failed: %08x\n", debugstr_a(cmd), nsres);
306
307     nsICommandManager_Release(cmdmgr);
308     return nsres;
309 }
310
311 static DWORD query_edit_status(HTMLDocument *This, const char *nscmd)
312 {
313     nsICommandParams *nsparam;
314     PRBool b = FALSE;
315
316     if(This->usermode != EDITMODE || This->readystate < READYSTATE_INTERACTIVE)
317         return OLECMDF_SUPPORTED;
318
319     if(This->nscontainer && nscmd) {
320         nsparam = create_nscommand_params();
321         get_ns_command_state(This->nscontainer, nscmd, nsparam);
322
323         nsICommandParams_GetBooleanValue(nsparam, NSSTATE_ALL, &b);
324     }
325
326     return OLECMDF_SUPPORTED | OLECMDF_ENABLED | (b ? OLECMDF_LATCHED : 0);
327 }
328
329 static void set_ns_align(HTMLDocument *This, const char *align_str)
330 {
331     nsICommandParams *nsparam;
332
333     if(!This->nscontainer)
334         return;
335
336     nsparam = create_nscommand_params();
337     nsICommandParams_SetCStringValue(nsparam, NSSTATE_ATTRIBUTE, align_str);
338
339     do_ns_command(This->nscontainer, NSCMD_ALIGN, nsparam);
340
341     nsICommandParams_Release(nsparam);
342 }
343
344 static HRESULT exec_fontname(HTMLDocument *This, VARIANT *in, VARIANT *out)
345 {
346     TRACE("(%p)->(%p %p)\n", This, in, out);
347
348     if(!This->nscontainer)
349         return E_FAIL;
350
351     if(in) {
352         nsICommandParams *nsparam = create_nscommand_params();
353         char *stra;
354         DWORD len;
355
356         if(V_VT(in) != VT_BSTR) {
357             FIXME("Unsupported vt=%d\n", V_VT(out));
358             return E_INVALIDARG;
359         }
360
361         len = WideCharToMultiByte(CP_ACP, 0, V_BSTR(in), -1, NULL, 0, NULL, NULL);
362         stra = mshtml_alloc(len);
363         WideCharToMultiByte(CP_ACP, 0, V_BSTR(in), -1, stra, -1, NULL, NULL);
364         nsICommandParams_SetCStringValue(nsparam, NSSTATE_ATTRIBUTE, stra);
365         mshtml_free(stra);
366
367         do_ns_command(This->nscontainer, NSCMD_FONTFACE, nsparam);
368
369         nsICommandParams_Release(nsparam);
370     }
371
372     if(out) {
373         nsICommandParams *nsparam;
374         LPWSTR strw;
375         char *stra;
376         DWORD len;
377         nsresult nsres;
378
379         if(V_VT(out) != VT_BSTR) {
380             FIXME("Unsupported vt=%d\n", V_VT(out));
381             return E_INVALIDARG;
382         }
383
384         nsparam = create_nscommand_params();
385
386         nsres = get_ns_command_state(This->nscontainer, NSCMD_FONTFACE, nsparam);
387         if(NS_FAILED(nsres))
388             return S_OK;
389
390         nsICommandParams_GetCStringValue(nsparam, NSSTATE_ATTRIBUTE, &stra);
391         nsICommandParams_Release(nsparam);
392
393         len = MultiByteToWideChar(CP_ACP, 0, stra, -1, NULL, 0);
394         strw = mshtml_alloc(len*sizeof(WCHAR));
395         MultiByteToWideChar(CP_ACP, 0, stra, -1, strw, -1);
396         nsfree(stra);
397
398         V_BSTR(out) = SysAllocString(strw);
399         mshtml_free(strw);
400     }
401
402     return S_OK;
403 }
404
405 static HRESULT exec_forecolor(HTMLDocument *This, VARIANT *in, VARIANT *out)
406 {
407     TRACE("(%p)->(%p %p)\n", This, in, out);
408
409     if(in) {
410         if(V_VT(in) == VT_I4) {
411             nsICommandParams *nsparam = create_nscommand_params();
412             char color_str[10];
413
414             sprintf(color_str, "#%02x%02x%02x",
415                     V_I4(in)&0xff, (V_I4(in)>>8)&0xff, (V_I4(in)>>16)&0xff);
416
417             nsICommandParams_SetCStringValue(nsparam, NSSTATE_ATTRIBUTE, color_str);
418             do_ns_command(This->nscontainer, NSCMD_FONTCOLOR, nsparam);
419
420             nsICommandParams_Release(nsparam);
421         }else {
422             FIXME("unsupported in vt=%d\n", V_VT(in));
423         }
424     }
425
426     if(out) {
427         FIXME("unsupported out\n");
428         return E_NOTIMPL;
429     }
430
431     return S_OK;
432 }
433
434 static HRESULT exec_fontsize(HTMLDocument *This, VARIANT *in, VARIANT *out)
435 {
436     FIXME("(%p)->(%p %p)\n", This, in, out);
437     return E_NOTIMPL;
438 }
439
440 static HRESULT exec_bold(HTMLDocument *This)
441 {
442     TRACE("(%p)\n", This);
443
444     if(This->nscontainer)
445         do_ns_command(This->nscontainer, NSCMD_BOLD, NULL);
446
447     return S_OK;
448 }
449
450 static HRESULT exec_italic(HTMLDocument *This)
451 {
452     TRACE("(%p)\n", This);
453
454     if(This->nscontainer)
455         do_ns_command(This->nscontainer, NSCMD_ITALIC, NULL);
456
457     return S_OK;
458 }
459
460 static HRESULT exec_justifycenter(HTMLDocument *This)
461 {
462     TRACE("(%p)\n", This);
463     set_ns_align(This, "center");
464     return S_OK;
465 }
466
467 static HRESULT exec_justifyleft(HTMLDocument *This)
468 {
469     TRACE("(%p)\n", This);
470     set_ns_align(This, "left");
471     return S_OK;
472 }
473
474 static HRESULT exec_justifyright(HTMLDocument *This)
475 {
476     TRACE("(%p)\n", This);
477     set_ns_align(This, "right");
478     return S_OK;
479 }
480
481 static HRESULT exec_underline(HTMLDocument *This)
482 {
483     TRACE("(%p)\n", This);
484
485     if(This->nscontainer)
486         do_ns_command(This->nscontainer, NSCMD_UNDERLINE, NULL);
487
488     return S_OK;
489 }
490
491 static HRESULT exec_browsemode(HTMLDocument *This)
492 {
493     WARN("(%p)\n", This);
494
495     This->usermode = BROWSEMODE;
496
497     return S_OK;
498 }
499
500 static void setup_ns_editing(NSContainer *This)
501 {
502     nsIInterfaceRequestor *iface_req;
503     nsIEditingSession *editing_session = NULL;
504     nsIURIContentListener *listener = NULL;
505     nsIDOMWindow *dom_window = NULL;
506     nsresult nsres;
507
508     nsres = nsIWebBrowser_QueryInterface(This->webbrowser,
509             &IID_nsIInterfaceRequestor, (void**)&iface_req);
510     if(NS_FAILED(nsres)) {
511         ERR("Could not get nsIInterfaceRequestor: %08x\n", nsres);
512         return;
513     }
514
515     nsres = nsIInterfaceRequestor_GetInterface(iface_req, &IID_nsIEditingSession,
516                                                (void**)&editing_session);
517     nsIInterfaceRequestor_Release(iface_req);
518     if(NS_FAILED(nsres)) {
519         ERR("Could not get nsIEditingSession: %08x\n", nsres);
520         return;
521     }
522
523     nsres = nsIWebBrowser_GetContentDOMWindow(This->webbrowser, &dom_window);
524     if(NS_FAILED(nsres)) {
525         ERR("Could not get content DOM window: %08x\n", nsres);
526         nsIEditingSession_Release(editing_session);
527         return;
528     }
529
530     nsres = nsIEditingSession_MakeWindowEditable(editing_session, dom_window, NULL, FALSE);
531     nsIEditingSession_Release(editing_session);
532     nsIDOMWindow_Release(dom_window);
533     if(NS_FAILED(nsres)) {
534         ERR("MakeWindowEditable failed: %08x\n", nsres);
535         return;
536     }
537
538     /* MakeWindowEditable changes WebBrowser's parent URI content listener.
539      * It seams to be a bug in Gecko. To workaround it we set our content
540      * listener again and Gecko's one as its parent.
541      */
542     nsIWebBrowser_GetParentURIContentListener(This->webbrowser, &listener);
543     nsIURIContentListener_SetParentContentListener(NSURICL(This), listener);
544     nsIURIContentListener_Release(listener);
545     nsIWebBrowser_SetParentURIContentListener(This->webbrowser, NSURICL(This));
546 }
547
548 static HRESULT exec_editmode(HTMLDocument *This)
549 {
550     IMoniker *mon;
551     HRESULT hres;
552
553     static const WCHAR wszAboutBlank[] = {'a','b','o','u','t',':','b','l','a','n','k',0};
554
555     TRACE("(%p)\n", This);
556
557     This->usermode = EDITMODE;
558
559     if(This->frame)
560         IOleInPlaceFrame_SetStatusText(This->frame, NULL);
561
562     if(This->hostui) {
563         DOCHOSTUIINFO hostinfo;
564
565         memset(&hostinfo, 0, sizeof(DOCHOSTUIINFO));
566         hostinfo.cbSize = sizeof(DOCHOSTUIINFO);
567         hres = IDocHostUIHandler_GetHostInfo(This->hostui, &hostinfo);
568         if(SUCCEEDED(hres))
569             /* FIXME: use hostinfo */
570             TRACE("hostinfo = {%u %08x %08x %s %s}\n",
571                     hostinfo.cbSize, hostinfo.dwFlags, hostinfo.dwDoubleClick,
572                     debugstr_w(hostinfo.pchHostCss), debugstr_w(hostinfo.pchHostNS));
573     }
574
575     if(This->nscontainer)
576         setup_ns_editing(This->nscontainer);
577
578     hres = CreateURLMoniker(NULL, wszAboutBlank, &mon);
579     if(FAILED(hres)) {
580         FIXME("CreateURLMoniker failed: %08x\n", hres);
581         return hres;
582     }
583
584     return IPersistMoniker_Load(PERSISTMON(This), TRUE, mon, NULL, 0);
585 }
586
587 static HRESULT exec_baselinefont3(HTMLDocument *This)
588 {
589     FIXME("(%p)\n", This);
590     return S_OK;
591 }
592
593 static const struct {
594     OLECMDF cmdf;
595     HRESULT (*func)(HTMLDocument*,DWORD,VARIANT*,VARIANT*);
596 } exec_table[OLECMDID_GETPRINTTEMPLATE+1] = {
597     {0},
598     { OLECMDF_SUPPORTED,                  exec_open                 }, /* OLECMDID_OPEN */
599     { OLECMDF_SUPPORTED,                  exec_new                  }, /* OLECMDID_NEW */
600     { OLECMDF_SUPPORTED,                  exec_save                 }, /* OLECMDID_SAVE */
601     { OLECMDF_SUPPORTED|OLECMDF_ENABLED,  exec_save_as              }, /* OLECMDID_SAVEAS */
602     { OLECMDF_SUPPORTED,                  exec_save_copy_as         }, /* OLECMDID_SAVECOPYAS */
603     { OLECMDF_SUPPORTED|OLECMDF_ENABLED,  exec_print                }, /* OLECMDID_PRINT */
604     { OLECMDF_SUPPORTED|OLECMDF_ENABLED,  exec_print_preview        }, /* OLECMDID_PRINTPREVIEW */
605     { OLECMDF_SUPPORTED|OLECMDF_ENABLED,  exec_page_setup           }, /* OLECMDID_PAGESETUP */
606     { OLECMDF_SUPPORTED,                  exec_spell                }, /* OLECMDID_SPELL */
607     { OLECMDF_SUPPORTED|OLECMDF_ENABLED,  exec_properties           }, /* OLECMDID_PROPERTIES */
608     { OLECMDF_SUPPORTED,                  exec_cut                  }, /* OLECMDID_CUT */
609     { OLECMDF_SUPPORTED,                  exec_copy                 }, /* OLECMDID_COPY */
610     { OLECMDF_SUPPORTED,                  exec_paste                }, /* OLECMDID_PASTE */
611     { OLECMDF_SUPPORTED,                  exec_paste_special        }, /* OLECMDID_PASTESPECIAL */
612     { OLECMDF_SUPPORTED,                  exec_undo                 }, /* OLECMDID_UNDO */
613     { OLECMDF_SUPPORTED,                  exec_rendo                }, /* OLECMDID_REDO */
614     { OLECMDF_SUPPORTED|OLECMDF_ENABLED,  exec_select_all           }, /* OLECMDID_SELECTALL */
615     { OLECMDF_SUPPORTED,                  exec_clear_selection      }, /* OLECMDID_CLEARSELECTION */
616     { OLECMDF_SUPPORTED,                  exec_zoom                 }, /* OLECMDID_ZOOM */
617     { OLECMDF_SUPPORTED,                  exec_get_zoom_range       }, /* OLECMDID_GETZOOMRANGE */
618     {0},
619     { OLECMDF_SUPPORTED|OLECMDF_ENABLED,  exec_refresh              }, /* OLECMDID_REFRESH */
620     { OLECMDF_SUPPORTED|OLECMDF_ENABLED,  exec_stop                 }, /* OLECMDID_STOP */
621     {0},{0},{0},{0},{0},{0},
622     { OLECMDF_SUPPORTED,                  exec_stop_download        }, /* OLECMDID_STOPDOWNLOAD */
623     {0},{0},
624     { OLECMDF_SUPPORTED,                  exec_delete               }, /* OLECMDID_DELETE */
625     {0},{0},
626     { OLECMDF_SUPPORTED,                  exec_enable_interaction   }, /* OLECMDID_ENABLE_INTERACTION */
627     { OLECMDF_SUPPORTED,                  exec_on_unload            }, /* OLECMDID_ONUNLOAD */
628     {0},{0},{0},{0},{0},
629     { OLECMDF_SUPPORTED,                  exec_show_page_setup      }, /* OLECMDID_SHOWPAGESETUP */
630     { OLECMDF_SUPPORTED,                  exec_show_print           }, /* OLECMDID_SHOWPRINT */
631     {0},{0},
632     { OLECMDF_SUPPORTED,                  exec_close                }, /* OLECMDID_CLOSE */
633     {0},{0},{0},
634     { OLECMDF_SUPPORTED,                  exec_set_print_template   }, /* OLECMDID_SETPRINTTEMPLATE */
635     { OLECMDF_SUPPORTED,                  exec_get_print_template   }  /* OLECMDID_GETPRINTTEMPLATE */
636 };
637
638 static HRESULT WINAPI OleCommandTarget_QueryInterface(IOleCommandTarget *iface, REFIID riid, void **ppv)
639 {
640     HTMLDocument *This = CMDTARGET_THIS(iface);
641     return IHTMLDocument2_QueryInterface(HTMLDOC(This), riid, ppv);
642 }
643
644 static ULONG WINAPI OleCommandTarget_AddRef(IOleCommandTarget *iface)
645 {
646     HTMLDocument *This = CMDTARGET_THIS(iface);
647     return IHTMLDocument2_AddRef(HTMLDOC(This));
648 }
649
650 static ULONG WINAPI OleCommandTarget_Release(IOleCommandTarget *iface)
651 {
652     HTMLDocument *This = CMDTARGET_THIS(iface);
653     return IHTMLDocument_Release(HTMLDOC(This));
654 }
655
656 static HRESULT WINAPI OleCommandTarget_QueryStatus(IOleCommandTarget *iface, const GUID *pguidCmdGroup,
657         ULONG cCmds, OLECMD prgCmds[], OLECMDTEXT *pCmdText)
658 {
659     HTMLDocument *This = CMDTARGET_THIS(iface);
660     HRESULT hres = S_OK, hr;
661
662     TRACE("(%p)->(%s %d %p %p)\n", This, debugstr_guid(pguidCmdGroup), cCmds, prgCmds, pCmdText);
663
664     if(!pguidCmdGroup) {
665         ULONG i;
666
667         for(i=0; i<cCmds; i++) {
668             if(prgCmds[i].cmdID<OLECMDID_OPEN || prgCmds[i].cmdID>OLECMDID_GETPRINTTEMPLATE) {
669                 WARN("Unsupported cmdID = %d\n", prgCmds[i].cmdID);
670                 prgCmds[i].cmdf = 0;
671                 hres = OLECMDERR_E_NOTSUPPORTED;
672             }else {
673                 if(prgCmds[i].cmdID == OLECMDID_OPEN || prgCmds[i].cmdID == OLECMDID_NEW) {
674                     IOleCommandTarget *cmdtrg = NULL;
675                     OLECMD olecmd;
676
677                     prgCmds[i].cmdf = OLECMDF_SUPPORTED;
678                     if(This->client) {
679                         hr = IOleClientSite_QueryInterface(This->client, &IID_IOleCommandTarget,
680                                 (void**)&cmdtrg);
681                         if(SUCCEEDED(hr)) {
682                             olecmd.cmdID = prgCmds[i].cmdID;
683                             olecmd.cmdf = 0;
684
685                             hr = IOleCommandTarget_QueryStatus(cmdtrg, NULL, 1, &olecmd, NULL);
686                             if(SUCCEEDED(hr) && olecmd.cmdf)
687                                 prgCmds[i].cmdf = olecmd.cmdf;
688                         }
689                     }else {
690                         ERR("This->client == NULL, native would crash\n");
691                     }
692                 }else {
693                     prgCmds[i].cmdf = exec_table[prgCmds[i].cmdID].cmdf;
694                     TRACE("cmdID = %d  returning %x\n", prgCmds[i].cmdID, prgCmds[i].cmdf);
695                 }
696                 hres = S_OK;
697             }
698         }
699
700         if(pCmdText)
701             FIXME("Set pCmdText\n");
702     }else if(IsEqualGUID(&CGID_MSHTML, pguidCmdGroup)) {
703         ULONG i;
704
705         for(i=0; i<cCmds; i++) {
706             switch(prgCmds[i].cmdID) {
707             case IDM_COPY:
708                 FIXME("CGID_MSHTML: IDM_COPY\n");
709                 prgCmds[i].cmdf = OLECMDF_SUPPORTED|OLECMDF_ENABLED;
710                 break;
711             case IDM_CUT:
712                 FIXME("CGID_MSHTML: IDM_CUT\n");
713                 prgCmds[i].cmdf = OLECMDF_SUPPORTED|OLECMDF_ENABLED;
714                 break;
715             case IDM_FONTNAME:
716                 TRACE("CGID_MSHTML: IDM_FONTNAME\n");
717                 prgCmds[i].cmdf = query_edit_status(This, NULL);
718                 break;
719             case IDM_FONTSIZE:
720                 TRACE("CGID_MSHTML: IDM_FONTSIZE\n");
721                 prgCmds[i].cmdf = query_edit_status(This, NULL);
722                 break;
723             case IDM_PASTE:
724                 FIXME("CGID_MSHTML: IDM_PASTE\n");
725                 prgCmds[i].cmdf = OLECMDF_SUPPORTED|OLECMDF_ENABLED;
726                 break;
727             case IDM_BOLD:
728                 TRACE("CGID_MSHTML: IDM_BOLD\n");
729                 prgCmds[i].cmdf = query_edit_status(This, NSCMD_BOLD);
730                 break;
731             case IDM_FORECOLOR:
732                 TRACE("CGID_MSHTML: IDM_FORECOLOR\n");
733                 prgCmds[i].cmdf = query_edit_status(This, NULL);
734                 break;
735             case IDM_ITALIC:
736                 TRACE("CGID_MSHTML: IDM_ITALIC\n");
737                 prgCmds[i].cmdf = query_edit_status(This, NSCMD_ITALIC);
738                 break;
739             case IDM_JUSTIFYCENTER:
740                 FIXME("CGID_MSHTML: IDM_JUSTIFYCENTER\n");
741                 prgCmds[i].cmdf = OLECMDF_SUPPORTED|OLECMDF_ENABLED;
742                 break;
743             case IDM_JUSTIFYLEFT:
744                 FIXME("CGID_MSHTML: IDM_JUSTIFYLEFT\n");
745                 prgCmds[i].cmdf = OLECMDF_SUPPORTED|OLECMDF_ENABLED;
746                 break;
747             case IDM_JUSTIFYRIGHT:
748                 FIXME("CGID_MSHTML: IDM_JUSTIFYRIGHT\n");
749                 prgCmds[i].cmdf = OLECMDF_SUPPORTED|OLECMDF_ENABLED;
750                 break;
751             case IDM_UNDERLINE:
752                 TRACE("CGID_MSHTML: IDM_UNDERLINE\n");
753                 prgCmds[i].cmdf = query_edit_status(This, NSCMD_UNDERLINE);
754                 break;
755             case IDM_HORIZONTALLINE:
756                 FIXME("CGID_MSHTML: IDM_HORIZONTALLINE\n");
757                 prgCmds[i].cmdf = OLECMDF_SUPPORTED|OLECMDF_ENABLED;
758                 break;
759             case IDM_ORDERLIST:
760                 FIXME("CGID_MSHTML: IDM_ORDERLIST\n");
761                 prgCmds[i].cmdf = OLECMDF_SUPPORTED|OLECMDF_ENABLED;
762                 break;
763             case IDM_UNORDERLIST:
764                 FIXME("CGID_MSHTML: IDM_UNORDERLIST\n");
765                 prgCmds[i].cmdf = OLECMDF_SUPPORTED|OLECMDF_ENABLED;
766                 break;
767             case IDM_INDENT:
768                 FIXME("CGID_MSHTML: IDM_INDENT\n");
769                 prgCmds[i].cmdf = OLECMDF_SUPPORTED|OLECMDF_ENABLED;
770                 break;
771             case IDM_OUTDENT:
772                 FIXME("CGID_MSHTML: IDM_OUTDENT\n");
773                 prgCmds[i].cmdf = OLECMDF_SUPPORTED|OLECMDF_ENABLED;
774                 break;
775             case IDM_BLOCKDIRLTR:
776                 FIXME("CGID_MSHTML: IDM_BLOCKDIRLTR\n");
777                 prgCmds[i].cmdf = OLECMDF_SUPPORTED|OLECMDF_ENABLED;
778                 break;
779             case IDM_BLOCKDIRRTL:
780                 FIXME("CGID_MSHTML: IDM_BLOCKDIRRTL\n");
781                 prgCmds[i].cmdf = OLECMDF_SUPPORTED|OLECMDF_ENABLED;
782                 break;
783             default:
784                 FIXME("CGID_MSHTML: unsupported cmdID %d\n", prgCmds[i].cmdID);
785                 prgCmds[i].cmdf = 0;
786             }
787         }
788
789         hres = prgCmds[i-1].cmdf ? S_OK : OLECMDERR_E_NOTSUPPORTED;
790
791         if(pCmdText)
792             FIXME("Set pCmdText\n");
793     }else {
794         FIXME("Unsupported pguidCmdGroup %s\n", debugstr_guid(pguidCmdGroup));
795         hres = OLECMDERR_E_UNKNOWNGROUP;
796     }
797
798     return hres;
799 }
800
801 static HRESULT WINAPI OleCommandTarget_Exec(IOleCommandTarget *iface, const GUID *pguidCmdGroup,
802         DWORD nCmdID, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
803 {
804     HTMLDocument *This = CMDTARGET_THIS(iface);
805
806     if(!pguidCmdGroup) {
807         if(nCmdID<OLECMDID_OPEN || nCmdID>OLECMDID_GETPRINTTEMPLATE || !exec_table[nCmdID].func) {
808             WARN("Unsupported cmdID = %d\n", nCmdID);
809             return OLECMDERR_E_NOTSUPPORTED;
810         }
811
812         return exec_table[nCmdID].func(This, nCmdexecopt, pvaIn, pvaOut);
813     }else if(IsEqualGUID(&CGID_Explorer, pguidCmdGroup)) {
814         FIXME("unsupported nCmdID %d of CGID_Explorer group\n", nCmdID);
815         TRACE("%p %p\n", pvaIn, pvaOut);
816         return OLECMDERR_E_NOTSUPPORTED;
817     }else if(IsEqualGUID(&CGID_ShellDocView, pguidCmdGroup)) {
818         FIXME("unsupported nCmdID %d of CGID_ShellDocView group\n", nCmdID);
819         return OLECMDERR_E_NOTSUPPORTED;
820     }else if(IsEqualGUID(&CGID_MSHTML, pguidCmdGroup)) {
821         switch(nCmdID) {
822         case IDM_FONTNAME:
823             return exec_fontname(This, pvaIn, pvaOut);
824         case IDM_FONTSIZE:
825             return exec_fontsize(This, pvaIn, pvaOut);
826         case IDM_BOLD:
827             if(pvaIn || pvaOut)
828                 FIXME("unsupported arguments\n");
829             return exec_bold(This);
830         case IDM_FORECOLOR:
831             return exec_forecolor(This, pvaIn, pvaOut);
832         case IDM_ITALIC:
833             if(pvaIn || pvaOut)
834                 FIXME("unsupported arguments\n");
835             return exec_italic(This);
836         case IDM_JUSTIFYCENTER:
837             if(pvaIn || pvaOut)
838                 FIXME("unsupported arguments\n");
839             return exec_justifycenter(This);
840         case IDM_JUSTIFYLEFT:
841             if(pvaIn || pvaOut)
842                 FIXME("unsupported arguments\n");
843             return exec_justifyleft(This);
844         case IDM_JUSTIFYRIGHT:
845             if(pvaIn || pvaOut)
846                 FIXME("unsupported arguments\n");
847             return exec_justifyright(This);
848         case IDM_UNDERLINE:
849             if(pvaIn || pvaOut)
850                 FIXME("unsupported arguments\n");
851             return exec_underline(This);
852         case IDM_BROWSEMODE:
853             if(pvaIn || pvaOut)
854                 FIXME("unsupported arguments\n");
855             return exec_browsemode(This);
856         case IDM_EDITMODE:
857             if(pvaIn || pvaOut)
858                 FIXME("unsupported arguments\n");
859             return exec_editmode(This);
860         case IDM_BASELINEFONT3:
861             return exec_baselinefont3(This);
862         default:
863             FIXME("unsupported nCmdID %d of CGID_MSHTML group\n", nCmdID);
864             return OLECMDERR_E_NOTSUPPORTED;
865         }
866     }
867
868     FIXME("Unsupported pguidCmdGroup %s\n", debugstr_guid(pguidCmdGroup));
869     return OLECMDERR_E_UNKNOWNGROUP;
870 }
871
872 #undef CMDTARGET_THIS
873
874 static const IOleCommandTargetVtbl OleCommandTargetVtbl = {
875     OleCommandTarget_QueryInterface,
876     OleCommandTarget_AddRef,
877     OleCommandTarget_Release,
878     OleCommandTarget_QueryStatus,
879     OleCommandTarget_Exec
880 };
881
882 void HTMLDocument_OleCmd_Init(HTMLDocument *This)
883 {
884     This->lpOleCommandTargetVtbl = &OleCommandTargetVtbl;
885 }