riched20: Fix one more memory leak.
[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
46 /**********************************************************
47  * IOleCommandTarget implementation
48  */
49
50 #define CMDTARGET_THIS(iface) DEFINE_THIS(HTMLDocument, OleCommandTarget, iface)
51
52 static HRESULT exec_open(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
53 {
54     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
55     return E_NOTIMPL;
56 }
57
58 static HRESULT exec_new(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_save(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_as(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_copy_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_print(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_preview(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_page_setup(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_spell(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_properties(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_cut(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_copy(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_paste(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_special(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_undo(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_rendo(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_select_all(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_clear_selection(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_zoom(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_get_zoom_range(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_refresh(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_stop(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_download(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_delete(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_enable_interaction(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_on_unload(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
203 {
204     TRACE("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
205
206     /* Tests show that we have nothing more to do here */
207
208     if(pvaOut) {
209         V_VT(pvaOut) = VT_BOOL;
210         V_BOOL(pvaOut) = VARIANT_TRUE;
211     }
212
213     return S_OK;
214 }
215
216 static HRESULT exec_show_page_setup(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
217 {
218     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
219     return E_NOTIMPL;
220 }
221
222 static HRESULT exec_show_print(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_close(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_set_print_template(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_get_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 void do_ns_command(NSContainer *This, const char *cmd, nsICommandParams *nsparam)
247 {
248     nsICommandManager *cmdmgr;
249     nsIInterfaceRequestor *iface_req;
250     nsresult nsres;
251
252     TRACE("(%p)\n", This);
253
254     nsres = nsIWebBrowser_QueryInterface(This->webbrowser,
255             &IID_nsIInterfaceRequestor, (void**)&iface_req);
256     if(NS_FAILED(nsres)) {
257         ERR("Could not get nsIInterfaceRequestor: %08x\n", nsres);
258         return;
259     }
260
261     nsres = nsIInterfaceRequestor_GetInterface(iface_req, &IID_nsICommandManager,
262                                                (void**)&cmdmgr);
263     nsIInterfaceRequestor_Release(iface_req);
264     if(NS_FAILED(nsres)) {
265         ERR("Could not get nsICommandManager: %08x\n", nsres);
266         return;
267     }
268
269     nsres = nsICommandManager_DoCommand(cmdmgr, cmd, nsparam, NULL);
270     if(NS_FAILED(nsres))
271         ERR("DoCommand(%s) failed: %08x\n", debugstr_a(cmd), nsres);
272
273     nsICommandManager_Release(cmdmgr);
274 }
275
276 static nsresult get_ns_command_state(NSContainer *This, const char *cmd, nsICommandParams *nsparam)
277 {
278     nsICommandManager *cmdmgr;
279     nsIInterfaceRequestor *iface_req;
280     nsresult nsres;
281
282     nsres = nsIWebBrowser_QueryInterface(This->webbrowser,
283             &IID_nsIInterfaceRequestor, (void**)&iface_req);
284     if(NS_FAILED(nsres)) {
285         ERR("Could not get nsIInterfaceRequestor: %08x\n", nsres);
286         return nsres;
287     }
288
289     nsres = nsIInterfaceRequestor_GetInterface(iface_req, &IID_nsICommandManager,
290                                                (void**)&cmdmgr);
291     nsIInterfaceRequestor_Release(iface_req);
292     if(NS_FAILED(nsres)) {
293         ERR("Could not get nsICommandManager: %08x\n", nsres);
294         return nsres;
295     }
296
297     nsres = nsICommandManager_GetCommandState(cmdmgr, cmd, NULL, nsparam);
298     if(NS_FAILED(nsres))
299         ERR("GetCommandState(%s) failed: %08x\n", debugstr_a(cmd), nsres);
300
301     nsICommandManager_Release(cmdmgr);
302     return nsres;
303 }
304
305 static DWORD query_edit_status(HTMLDocument *This, const char *nscmd)
306 {
307     nsICommandParams *nsparam;
308     PRBool b = FALSE;
309
310     if(!This->nscontainer) {
311         FIXME("dummy not implemented\n");
312         return OLECMDF_SUPPORTED;
313     }
314
315     if(This->usermode != EDITMODE || This->readystate < READYSTATE_INTERACTIVE)
316         return OLECMDF_SUPPORTED;
317
318     nsparam = create_nscommand_params();
319     get_ns_command_state(This->nscontainer, nscmd, nsparam);
320
321     nsICommandParams_GetBooleanValue(nsparam, "state_enabled", &b);
322
323     return OLECMDF_SUPPORTED | OLECMDF_ENABLED | (b ? OLECMDF_LATCHED : 0);
324 }
325
326 static HRESULT exec_fontname(HTMLDocument *This, VARIANT *in, VARIANT *out)
327 {
328     TRACE("(%p)->(%p %p)\n", This, in, out);
329
330     if(!This->nscontainer)
331         return E_FAIL;
332
333     if(in) {
334         nsICommandParams *nsparam = create_nscommand_params();
335         char *stra;
336         DWORD len;
337
338         if(V_VT(in) != VT_BSTR) {
339             FIXME("Unsupported vt=%d\n", V_VT(out));
340             return E_INVALIDARG;
341         }
342
343         len = WideCharToMultiByte(CP_ACP, 0, V_BSTR(in), -1, NULL, 0, NULL, NULL);
344         stra = mshtml_alloc(len);
345         WideCharToMultiByte(CP_ACP, 0, V_BSTR(in), -1, stra, -1, NULL, NULL);
346         nsICommandParams_SetCStringValue(nsparam, "state_attribute", stra);
347         mshtml_free(stra);
348
349         do_ns_command(This->nscontainer, "cmd_fontFace", nsparam);
350
351         nsICommandParams_Release(nsparam);
352     }
353
354     if(out) {
355         nsICommandParams *nsparam;
356         LPWSTR strw;
357         char *stra;
358         DWORD len;
359         nsresult nsres;
360
361         if(V_VT(out) != VT_BSTR) {
362             FIXME("Unsupported vt=%d\n", V_VT(out));
363             return E_INVALIDARG;
364         }
365
366         nsparam = create_nscommand_params();
367
368         nsres = get_ns_command_state(This->nscontainer, "cmd_fontFace", nsparam);
369         if(NS_FAILED(nsres))
370             return S_OK;
371
372         nsICommandParams_GetCStringValue(nsparam, "state_attribute", &stra);
373         nsICommandParams_Release(nsparam);
374
375         len = MultiByteToWideChar(CP_ACP, 0, stra, -1, NULL, 0);
376         strw = mshtml_alloc(len*sizeof(WCHAR));
377         MultiByteToWideChar(CP_ACP, 0, stra, -1, strw, -1);
378         nsfree(stra);
379
380         V_BSTR(out) = SysAllocString(strw);
381         mshtml_free(strw);
382     }
383
384     return S_OK;
385 }
386
387 static HRESULT exec_bold(HTMLDocument *This)
388 {
389     TRACE("(%p)\n", This);
390
391     if(This->nscontainer)
392         do_ns_command(This->nscontainer, NSCMD_BOLD, NULL);
393
394     return S_OK;
395 }
396
397 static HRESULT exec_italic(HTMLDocument *This)
398 {
399     TRACE("(%p)\n", This);
400
401     if(This->nscontainer)
402         do_ns_command(This->nscontainer, NSCMD_ITALIC, NULL);
403
404     return S_OK;
405 }
406
407 static HRESULT exec_underline(HTMLDocument *This)
408 {
409     TRACE("(%p)\n", This);
410
411     if(This->nscontainer)
412         do_ns_command(This->nscontainer, NSCMD_UNDERLINE, NULL);
413
414     return S_OK;
415 }
416
417 static HRESULT exec_browsemode(HTMLDocument *This)
418 {
419     WARN("(%p)\n", This);
420
421     This->usermode = BROWSEMODE;
422
423     return S_OK;
424 }
425
426 static void setup_ns_editing(NSContainer *This)
427 {
428     nsIInterfaceRequestor *iface_req;
429     nsIEditingSession *editing_session = NULL;
430     nsIURIContentListener *listener = NULL;
431     nsIDOMWindow *dom_window = NULL;
432     nsresult nsres;
433
434     nsres = nsIWebBrowser_QueryInterface(This->webbrowser,
435             &IID_nsIInterfaceRequestor, (void**)&iface_req);
436     if(NS_FAILED(nsres)) {
437         ERR("Could not get nsIInterfaceRequestor: %08x\n", nsres);
438         return;
439     }
440
441     nsres = nsIInterfaceRequestor_GetInterface(iface_req, &IID_nsIEditingSession,
442                                                (void**)&editing_session);
443     nsIInterfaceRequestor_Release(iface_req);
444     if(NS_FAILED(nsres)) {
445         ERR("Could not get nsIEditingSession: %08x\n", nsres);
446         return;
447     }
448
449     nsres = nsIWebBrowser_GetContentDOMWindow(This->webbrowser, &dom_window);
450     if(NS_FAILED(nsres)) {
451         ERR("Could not get content DOM window: %08x\n", nsres);
452         nsIEditingSession_Release(editing_session);
453         return;
454     }
455
456     nsres = nsIEditingSession_MakeWindowEditable(editing_session, dom_window, NULL, FALSE);
457     nsIEditingSession_Release(editing_session);
458     nsIDOMWindow_Release(dom_window);
459     if(NS_FAILED(nsres)) {
460         ERR("MakeWindowEditable failed: %08x\n", nsres);
461         return;
462     }
463
464     /* MakeWindowEditable changes WebBrowser's parent URI content listener.
465      * It seams to be a bug in Gecko. To workaround it we set our content
466      * listener again and Gecko's one as its parent.
467      */
468     nsIWebBrowser_GetParentURIContentListener(This->webbrowser, &listener);
469     nsIURIContentListener_SetParentContentListener(NSURICL(This), listener);
470     nsIURIContentListener_Release(listener);
471     nsIWebBrowser_SetParentURIContentListener(This->webbrowser, NSURICL(This));
472 }
473
474 static HRESULT exec_editmode(HTMLDocument *This)
475 {
476     IMoniker *mon;
477     HRESULT hres;
478
479     static const WCHAR wszAboutBlank[] = {'a','b','o','u','t',':','b','l','a','n','k',0};
480
481     TRACE("(%p)\n", This);
482
483     This->usermode = EDITMODE;
484
485     if(This->frame)
486         IOleInPlaceFrame_SetStatusText(This->frame, NULL);
487
488     if(This->hostui) {
489         DOCHOSTUIINFO hostinfo;
490
491         memset(&hostinfo, 0, sizeof(DOCHOSTUIINFO));
492         hostinfo.cbSize = sizeof(DOCHOSTUIINFO);
493         hres = IDocHostUIHandler_GetHostInfo(This->hostui, &hostinfo);
494         if(SUCCEEDED(hres))
495             /* FIXME: use hostinfo */
496             TRACE("hostinfo = {%u %08x %08x %s %s}\n",
497                     hostinfo.cbSize, hostinfo.dwFlags, hostinfo.dwDoubleClick,
498                     debugstr_w(hostinfo.pchHostCss), debugstr_w(hostinfo.pchHostNS));
499     }
500
501     if(This->nscontainer)
502         setup_ns_editing(This->nscontainer);
503
504     hres = CreateURLMoniker(NULL, wszAboutBlank, &mon);
505     if(FAILED(hres)) {
506         FIXME("CreateURLMoniker failed: %08x\n", hres);
507         return hres;
508     }
509
510     return IPersistMoniker_Load(PERSISTMON(This), TRUE, mon, NULL, 0);
511 }
512
513 static HRESULT exec_baselinefont3(HTMLDocument *This)
514 {
515     FIXME("(%p)\n", This);
516     return S_OK;
517 }
518
519 static const struct {
520     OLECMDF cmdf;
521     HRESULT (*func)(HTMLDocument*,DWORD,VARIANT*,VARIANT*);
522 } exec_table[OLECMDID_GETPRINTTEMPLATE+1] = {
523     {0},
524     { OLECMDF_SUPPORTED,                  exec_open                 }, /* OLECMDID_OPEN */
525     { OLECMDF_SUPPORTED,                  exec_new                  }, /* OLECMDID_NEW */
526     { OLECMDF_SUPPORTED,                  exec_save                 }, /* OLECMDID_SAVE */
527     { OLECMDF_SUPPORTED|OLECMDF_ENABLED,  exec_save_as              }, /* OLECMDID_SAVEAS */
528     { OLECMDF_SUPPORTED,                  exec_save_copy_as         }, /* OLECMDID_SAVECOPYAS */
529     { OLECMDF_SUPPORTED|OLECMDF_ENABLED,  exec_print                }, /* OLECMDID_PRINT */
530     { OLECMDF_SUPPORTED|OLECMDF_ENABLED,  exec_print_preview        }, /* OLECMDID_PRINTPREVIEW */
531     { OLECMDF_SUPPORTED|OLECMDF_ENABLED,  exec_page_setup           }, /* OLECMDID_PAGESETUP */
532     { OLECMDF_SUPPORTED,                  exec_spell                }, /* OLECMDID_SPELL */
533     { OLECMDF_SUPPORTED|OLECMDF_ENABLED,  exec_properties           }, /* OLECMDID_PROPERTIES */
534     { OLECMDF_SUPPORTED,                  exec_cut                  }, /* OLECMDID_CUT */
535     { OLECMDF_SUPPORTED,                  exec_copy                 }, /* OLECMDID_COPY */
536     { OLECMDF_SUPPORTED,                  exec_paste                }, /* OLECMDID_PASTE */
537     { OLECMDF_SUPPORTED,                  exec_paste_special        }, /* OLECMDID_PASTESPECIAL */
538     { OLECMDF_SUPPORTED,                  exec_undo                 }, /* OLECMDID_UNDO */
539     { OLECMDF_SUPPORTED,                  exec_rendo                }, /* OLECMDID_REDO */
540     { OLECMDF_SUPPORTED|OLECMDF_ENABLED,  exec_select_all           }, /* OLECMDID_SELECTALL */
541     { OLECMDF_SUPPORTED,                  exec_clear_selection      }, /* OLECMDID_CLEARSELECTION */
542     { OLECMDF_SUPPORTED,                  exec_zoom                 }, /* OLECMDID_ZOOM */
543     { OLECMDF_SUPPORTED,                  exec_get_zoom_range       }, /* OLECMDID_GETZOOMRANGE */
544     {0},
545     { OLECMDF_SUPPORTED|OLECMDF_ENABLED,  exec_refresh              }, /* OLECMDID_REFRESH */
546     { OLECMDF_SUPPORTED|OLECMDF_ENABLED,  exec_stop                 }, /* OLECMDID_STOP */
547     {0},{0},{0},{0},{0},{0},
548     { OLECMDF_SUPPORTED,                  exec_stop_download        }, /* OLECMDID_STOPDOWNLOAD */
549     {0},{0},
550     { OLECMDF_SUPPORTED,                  exec_delete               }, /* OLECMDID_DELETE */
551     {0},{0},
552     { OLECMDF_SUPPORTED,                  exec_enable_interaction   }, /* OLECMDID_ENABLE_INTERACTION */
553     { OLECMDF_SUPPORTED,                  exec_on_unload            }, /* OLECMDID_ONUNLOAD */
554     {0},{0},{0},{0},{0},
555     { OLECMDF_SUPPORTED,                  exec_show_page_setup      }, /* OLECMDID_SHOWPAGESETUP */
556     { OLECMDF_SUPPORTED,                  exec_show_print           }, /* OLECMDID_SHOWPRINT */
557     {0},{0},
558     { OLECMDF_SUPPORTED,                  exec_close                }, /* OLECMDID_CLOSE */
559     {0},{0},{0},
560     { OLECMDF_SUPPORTED,                  exec_set_print_template   }, /* OLECMDID_SETPRINTTEMPLATE */
561     { OLECMDF_SUPPORTED,                  exec_get_print_template   }  /* OLECMDID_GETPRINTTEMPLATE */
562 };
563
564 static HRESULT WINAPI OleCommandTarget_QueryInterface(IOleCommandTarget *iface, REFIID riid, void **ppv)
565 {
566     HTMLDocument *This = CMDTARGET_THIS(iface);
567     return IHTMLDocument2_QueryInterface(HTMLDOC(This), riid, ppv);
568 }
569
570 static ULONG WINAPI OleCommandTarget_AddRef(IOleCommandTarget *iface)
571 {
572     HTMLDocument *This = CMDTARGET_THIS(iface);
573     return IHTMLDocument2_AddRef(HTMLDOC(This));
574 }
575
576 static ULONG WINAPI OleCommandTarget_Release(IOleCommandTarget *iface)
577 {
578     HTMLDocument *This = CMDTARGET_THIS(iface);
579     return IHTMLDocument_Release(HTMLDOC(This));
580 }
581
582 static HRESULT WINAPI OleCommandTarget_QueryStatus(IOleCommandTarget *iface, const GUID *pguidCmdGroup,
583         ULONG cCmds, OLECMD prgCmds[], OLECMDTEXT *pCmdText)
584 {
585     HTMLDocument *This = CMDTARGET_THIS(iface);
586     HRESULT hres = S_OK, hr;
587
588     TRACE("(%p)->(%s %d %p %p)\n", This, debugstr_guid(pguidCmdGroup), cCmds, prgCmds, pCmdText);
589
590     if(!pguidCmdGroup) {
591         ULONG i;
592
593         for(i=0; i<cCmds; i++) {
594             if(prgCmds[i].cmdID<OLECMDID_OPEN || prgCmds[i].cmdID>OLECMDID_GETPRINTTEMPLATE) {
595                 WARN("Unsupported cmdID = %d\n", prgCmds[i].cmdID);
596                 prgCmds[i].cmdf = 0;
597                 hres = OLECMDERR_E_NOTSUPPORTED;
598             }else {
599                 if(prgCmds[i].cmdID == OLECMDID_OPEN || prgCmds[i].cmdID == OLECMDID_NEW) {
600                     IOleCommandTarget *cmdtrg = NULL;
601                     OLECMD olecmd;
602
603                     prgCmds[i].cmdf = OLECMDF_SUPPORTED;
604                     if(This->client) {
605                         hr = IOleClientSite_QueryInterface(This->client, &IID_IOleCommandTarget,
606                                 (void**)&cmdtrg);
607                         if(SUCCEEDED(hr)) {
608                             olecmd.cmdID = prgCmds[i].cmdID;
609                             olecmd.cmdf = 0;
610
611                             hr = IOleCommandTarget_QueryStatus(cmdtrg, NULL, 1, &olecmd, NULL);
612                             if(SUCCEEDED(hr) && olecmd.cmdf)
613                                 prgCmds[i].cmdf = olecmd.cmdf;
614                         }
615                     }else {
616                         ERR("This->client == NULL, native would crash\n");
617                     }
618                 }else {
619                     prgCmds[i].cmdf = exec_table[prgCmds[i].cmdID].cmdf;
620                     TRACE("cmdID = %d  returning %x\n", prgCmds[i].cmdID, prgCmds[i].cmdf);
621                 }
622                 hres = S_OK;
623             }
624         }
625
626         if(pCmdText)
627             FIXME("Set pCmdText\n");
628     }else if(IsEqualGUID(&CGID_MSHTML, pguidCmdGroup)) {
629         ULONG i;
630
631         for(i=0; i<cCmds; i++) {
632             switch(prgCmds[i].cmdID) {
633             case IDM_COPY:
634                 FIXME("CGID_MSHTML: IDM_COPY\n");
635                 prgCmds[i].cmdf = OLECMDF_SUPPORTED|OLECMDF_ENABLED;
636                 break;
637             case IDM_CUT:
638                 FIXME("CGID_MSHTML: IDM_CUT\n");
639                 prgCmds[i].cmdf = OLECMDF_SUPPORTED|OLECMDF_ENABLED;
640                 break;
641             case IDM_FONTNAME:
642                 FIXME("CGID_MSHTML: IDM_FONTNAME\n");
643                 prgCmds[i].cmdf = OLECMDF_SUPPORTED|OLECMDF_ENABLED;
644                 break;
645             case IDM_FONTSIZE:
646                 FIXME("CGID_MSHTML: IDM_FONTSIZE\n");
647                 prgCmds[i].cmdf = OLECMDF_SUPPORTED|OLECMDF_ENABLED;
648                 break;
649             case IDM_PASTE:
650                 FIXME("CGID_MSHTML: IDM_PASTE\n");
651                 prgCmds[i].cmdf = OLECMDF_SUPPORTED|OLECMDF_ENABLED;
652                 break;
653             case IDM_BOLD:
654                 TRACE("CGID_MSHTML: IDM_BOLD\n");
655                 prgCmds[i].cmdf = query_edit_status(This, NSCMD_BOLD);
656                 break;
657             case IDM_FORECOLOR:
658                 FIXME("CGID_MSHTML: IDM_FORECOLOR\n");
659                 prgCmds[i].cmdf = OLECMDF_SUPPORTED|OLECMDF_ENABLED;
660                 break;
661             case IDM_ITALIC:
662                 TRACE("CGID_MSHTML: IDM_ITALIC\n");
663                 prgCmds[i].cmdf = query_edit_status(This, NSCMD_ITALIC);
664                 break;
665             case IDM_JUSTIFYCENTER:
666                 FIXME("CGID_MSHTML: IDM_JUSTIFYCENTER\n");
667                 prgCmds[i].cmdf = OLECMDF_SUPPORTED|OLECMDF_ENABLED;
668                 break;
669             case IDM_JUSTIFYLEFT:
670                 FIXME("CGID_MSHTML: IDM_JUSTIFYLEFT\n");
671                 prgCmds[i].cmdf = OLECMDF_SUPPORTED|OLECMDF_ENABLED;
672                 break;
673             case IDM_JUSTIFYRIGHT:
674                 FIXME("CGID_MSHTML: IDM_JUSTIFYRIGHT\n");
675                 prgCmds[i].cmdf = OLECMDF_SUPPORTED|OLECMDF_ENABLED;
676                 break;
677             case IDM_UNDERLINE:
678                 TRACE("CGID_MSHTML: IDM_UNDERLINE\n");
679                 prgCmds[i].cmdf = query_edit_status(This, NSCMD_UNDERLINE);
680                 break;
681             case IDM_HORIZONTALLINE:
682                 FIXME("CGID_MSHTML: IDM_HORIZONTALLINE\n");
683                 prgCmds[i].cmdf = OLECMDF_SUPPORTED|OLECMDF_ENABLED;
684                 break;
685             case IDM_ORDERLIST:
686                 FIXME("CGID_MSHTML: IDM_ORDERLIST\n");
687                 prgCmds[i].cmdf = OLECMDF_SUPPORTED|OLECMDF_ENABLED;
688                 break;
689             case IDM_UNORDERLIST:
690                 FIXME("CGID_MSHTML: IDM_UNORDERLIST\n");
691                 prgCmds[i].cmdf = OLECMDF_SUPPORTED|OLECMDF_ENABLED;
692                 break;
693             case IDM_INDENT:
694                 FIXME("CGID_MSHTML: IDM_INDENT\n");
695                 prgCmds[i].cmdf = OLECMDF_SUPPORTED|OLECMDF_ENABLED;
696                 break;
697             case IDM_OUTDENT:
698                 FIXME("CGID_MSHTML: IDM_OUTDENT\n");
699                 prgCmds[i].cmdf = OLECMDF_SUPPORTED|OLECMDF_ENABLED;
700                 break;
701             case IDM_BLOCKDIRLTR:
702                 FIXME("CGID_MSHTML: IDM_BLOCKDIRLTR\n");
703                 prgCmds[i].cmdf = OLECMDF_SUPPORTED|OLECMDF_ENABLED;
704                 break;
705             case IDM_BLOCKDIRRTL:
706                 FIXME("CGID_MSHTML: IDM_BLOCKDIRRTL\n");
707                 prgCmds[i].cmdf = OLECMDF_SUPPORTED|OLECMDF_ENABLED;
708                 break;
709             default:
710                 FIXME("CGID_MSHTML: unsupported cmdID %d\n", prgCmds[i].cmdID);
711                 prgCmds[i].cmdf = 0;
712             }
713         }
714
715         hres = prgCmds[i-1].cmdf ? S_OK : OLECMDERR_E_NOTSUPPORTED;
716
717         if(pCmdText)
718             FIXME("Set pCmdText\n");
719     }else {
720         FIXME("Unsupported pguidCmdGroup %s\n", debugstr_guid(pguidCmdGroup));
721         hres = OLECMDERR_E_UNKNOWNGROUP;
722     }
723
724     return hres;
725 }
726
727 static HRESULT WINAPI OleCommandTarget_Exec(IOleCommandTarget *iface, const GUID *pguidCmdGroup,
728         DWORD nCmdID, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
729 {
730     HTMLDocument *This = CMDTARGET_THIS(iface);
731
732     if(!pguidCmdGroup) {
733         if(nCmdID<OLECMDID_OPEN || nCmdID>OLECMDID_GETPRINTTEMPLATE || !exec_table[nCmdID].func) {
734             WARN("Unsupported cmdID = %d\n", nCmdID);
735             return OLECMDERR_E_NOTSUPPORTED;
736         }
737
738         return exec_table[nCmdID].func(This, nCmdexecopt, pvaIn, pvaOut);
739     }else if(IsEqualGUID(&CGID_Explorer, pguidCmdGroup)) {
740         FIXME("unsupported nCmdID %d of CGID_Explorer group\n", nCmdID);
741         TRACE("%p %p\n", pvaIn, pvaOut);
742         return OLECMDERR_E_NOTSUPPORTED;
743     }else if(IsEqualGUID(&CGID_ShellDocView, pguidCmdGroup)) {
744         FIXME("unsupported nCmdID %d of CGID_ShellDocView group\n", nCmdID);
745         return OLECMDERR_E_NOTSUPPORTED;
746     }else if(IsEqualGUID(&CGID_MSHTML, pguidCmdGroup)) {
747         switch(nCmdID) {
748         case IDM_FONTNAME:
749             return exec_fontname(This, pvaIn, pvaOut);
750         case IDM_BOLD:
751             if(pvaIn || pvaOut)
752                 FIXME("unsupported arguments\n");
753             return exec_bold(This);
754         case IDM_ITALIC:
755             if(pvaIn || pvaOut)
756                 FIXME("unsupported arguments\n");
757             return exec_italic(This);
758         case IDM_UNDERLINE:
759             if(pvaIn || pvaOut)
760                 FIXME("unsupported arguments\n");
761             return exec_underline(This);
762         case IDM_BROWSEMODE:
763             if(pvaIn || pvaOut)
764                 FIXME("unsupported arguments\n");
765             return exec_browsemode(This);
766         case IDM_EDITMODE:
767             if(pvaIn || pvaOut)
768                 FIXME("unsupported arguments\n");
769             return exec_editmode(This);
770         case IDM_BASELINEFONT3:
771             return exec_baselinefont3(This);
772         default:
773             FIXME("unsupported nCmdID %d of CGID_MSHTML group\n", nCmdID);
774             return OLECMDERR_E_NOTSUPPORTED;
775         }
776     }
777
778     FIXME("Unsupported pguidCmdGroup %s\n", debugstr_guid(pguidCmdGroup));
779     return OLECMDERR_E_UNKNOWNGROUP;
780 }
781
782 #undef CMDTARGET_THIS
783
784 static const IOleCommandTargetVtbl OleCommandTargetVtbl = {
785     OleCommandTarget_QueryInterface,
786     OleCommandTarget_AddRef,
787     OleCommandTarget_Release,
788     OleCommandTarget_QueryStatus,
789     OleCommandTarget_Exec
790 };
791
792 void HTMLDocument_OleCmd_Init(HTMLDocument *This)
793 {
794     This->lpOleCommandTargetVtbl = &OleCommandTargetVtbl;
795 }