2 * Copyright 2006-2007 Jacek Caban for CodeWeavers
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.
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.
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
19 #include "mshtml_private.h"
21 #define NSCMD_ALIGN "cmd_align"
22 #define NSCMD_BEGINLINE "cmd_beginLine"
23 #define NSCMD_BOLD "cmd_bold"
24 #define NSCMD_CHARNEXT "cmd_charNext"
25 #define NSCMD_CHARPREVIOUS "cmd_charPrevious"
26 #define NSCMD_COPY "cmd_copy"
27 #define NSCMD_CUT "cmd_cut"
28 #define NSCMD_DELETECHARFORWARD "cmd_deleteCharForward"
29 #define NSCMD_DELETEWORDFORWARD "cmd_deleteWordForward"
30 #define NSCMD_ENDLINE "cmd_endLine"
31 #define NSCMD_FONTCOLOR "cmd_fontColor"
32 #define NSCMD_FONTFACE "cmd_fontFace"
33 #define NSCMD_INDENT "cmd_indent"
34 #define NSCMD_INSERTHR "cmd_insertHR"
35 #define NSCMD_INSERTLINKNOUI "cmd_insertLinkNoUI"
36 #define NSCMD_ITALIC "cmd_italic"
37 #define NSCMD_LINENEXT "cmd_lineNext"
38 #define NSCMD_LINEPREVIOUS "cmd_linePrevious"
39 #define NSCMD_MOVEBOTTOM "cmd_moveBottom"
40 #define NSCMD_MOVEPAGEDOWN "cmd_movePageDown"
41 #define NSCMD_MOVEPAGEUP "cmd_movePageUp"
42 #define NSCMD_MOVETOP "cmd_moveTop"
43 #define NSCMD_OL "cmd_ol"
44 #define NSCMD_OUTDENT "cmd_outdent"
45 #define NSCMD_PASTE "cmd_paste"
46 #define NSCMD_SELECTBEGINLINE "cmd_selectBeginLine"
47 #define NSCMD_SELECTBOTTOM "cmd_selectBottom"
48 #define NSCMD_SELECTCHARNEXT "cmd_selectCharNext"
49 #define NSCMD_SELECTCHARPREVIOUS "cmd_selectCharPrevious"
50 #define NSCMD_SELECTENDLINE "cmd_selectEndLine"
51 #define NSCMD_SELECTLINENEXT "cmd_selectLineNext"
52 #define NSCMD_SELECTLINEPREVIOUS "cmd_selectLinePrevious"
53 #define NSCMD_SELECTPAGEDOWN "cmd_selectPageDown"
54 #define NSCMD_SELECTPAGEUP "cmd_selectPageUp"
55 #define NSCMD_SELECTTOP "cmd_selectTop"
56 #define NSCMD_SELECTWORDNEXT "cmd_selectWordNext"
57 #define NSCMD_SELECTWORDPREVIOUS "cmd_selectWordPrevious"
58 #define NSCMD_UL "cmd_ul"
59 #define NSCMD_UNDERLINE "cmd_underline"
60 #define NSCMD_WORDNEXT "cmd_wordNext"
61 #define NSCMD_WORDPREVIOUS "cmd_wordPrevious"
63 #define NSSTATE_ATTRIBUTE "state_attribute"
64 #define NSSTATE_ALL "state_all"
66 #define NSALIGN_CENTER "center"
67 #define NSALIGN_LEFT "left"
68 #define NSALIGN_RIGHT "right"
70 #define DOM_VK_LEFT VK_LEFT
71 #define DOM_VK_UP VK_UP
72 #define DOM_VK_RIGHT VK_RIGHT
73 #define DOM_VK_DOWN VK_DOWN
74 #define DOM_VK_DELETE VK_DELETE
75 #define DOM_VK_HOME VK_HOME
76 #define DOM_VK_END VK_END
78 static const WCHAR fontW
[] = {'f','o','n','t',0};
79 static const WCHAR sizeW
[] = {'s','i','z','e',0};
81 void set_dirty(HTMLDocument
*This
, VARIANT_BOOL dirty
)
85 if(This
->doc_obj
->usermode
!= EDITMODE
|| !This
->doc_obj
->nscontainer
|| !This
->doc_obj
->nscontainer
->editor
)
89 nsres
= nsIEditor_IncrementModificationCount(This
->doc_obj
->nscontainer
->editor
, 1);
91 ERR("IncrementModificationCount failed: %08x\n", nsres
);
93 nsres
= nsIEditor_ResetModificationCount(This
->doc_obj
->nscontainer
->editor
);
95 ERR("ResetModificationCount failed: %08x\n", nsres
);
99 static void do_ns_editor_command(NSContainer
*This
, const char *cmd
)
103 if(!This
->editor_controller
)
106 nsres
= nsIController_DoCommand(This
->editor_controller
, cmd
);
108 ERR("DoCommand(%s) failed: %08x\n", debugstr_a(cmd
), nsres
);
111 static nsresult
get_ns_command_state(NSContainer
*This
, const char *cmd
, nsICommandParams
*nsparam
)
113 nsICommandManager
*cmdmgr
;
116 nsres
= get_nsinterface((nsISupports
*)This
->webbrowser
, &IID_nsICommandManager
, (void**)&cmdmgr
);
117 if(NS_FAILED(nsres
)) {
118 ERR("Could not get nsICommandManager: %08x\n", nsres
);
122 nsres
= nsICommandManager_GetCommandState(cmdmgr
, cmd
, This
->doc
->basedoc
.window
->nswindow
, nsparam
);
124 ERR("GetCommandState(%s) failed: %08x\n", debugstr_a(cmd
), nsres
);
126 nsICommandManager_Release(cmdmgr
);
130 static DWORD
query_ns_edit_status(HTMLDocument
*This
, const char *nscmd
)
132 nsICommandParams
*nsparam
;
135 if(This
->doc_obj
->usermode
!= EDITMODE
|| This
->window
->readystate
< READYSTATE_INTERACTIVE
)
136 return OLECMDF_SUPPORTED
;
138 if(This
->doc_obj
->nscontainer
&& nscmd
) {
139 nsparam
= create_nscommand_params();
140 get_ns_command_state(This
->doc_obj
->nscontainer
, nscmd
, nsparam
);
142 nsICommandParams_GetBooleanValue(nsparam
, NSSTATE_ALL
, &b
);
144 nsICommandParams_Release(nsparam
);
147 return OLECMDF_SUPPORTED
| OLECMDF_ENABLED
| (b
? OLECMDF_LATCHED
: 0);
150 static void set_ns_align(HTMLDocument
*This
, const char *align_str
)
152 nsICommandParams
*nsparam
;
154 if(!This
->doc_obj
->nscontainer
)
157 nsparam
= create_nscommand_params();
158 nsICommandParams_SetCStringValue(nsparam
, NSSTATE_ATTRIBUTE
, align_str
);
160 do_ns_command(This
, NSCMD_ALIGN
, nsparam
);
162 nsICommandParams_Release(nsparam
);
165 static DWORD
query_align_status(HTMLDocument
*This
, const WCHAR
*align
)
167 DWORD ret
= OLECMDF_SUPPORTED
| OLECMDF_ENABLED
;
168 nsAString justify_str
;
172 if(This
->doc_obj
->usermode
!= EDITMODE
|| This
->window
->readystate
< READYSTATE_INTERACTIVE
)
173 return OLECMDF_SUPPORTED
;
175 nsAString_Init(&justify_str
, align
);
176 nsres
= nsIDOMHTMLDocument_QueryCommandState(This
->doc_node
->nsdoc
, &justify_str
, &b
);
177 nsAString_Finish(&justify_str
);
178 if(NS_SUCCEEDED(nsres
) && b
)
179 ret
|= OLECMDF_LATCHED
;
185 static nsISelection
*get_ns_selection(HTMLDocument
*This
)
187 nsISelection
*nsselection
= NULL
;
190 nsres
= nsIDOMWindow_GetSelection(This
->window
->nswindow
, &nsselection
);
192 ERR("GetSelection failed %08x\n", nsres
);
198 static void remove_child_attr(nsIDOMElement
*elem
, LPCWSTR tag
, nsAString
*attr_str
)
200 cpp_bool has_children
;
202 nsIDOMNode
*child_node
;
203 nsIDOMNodeList
*node_list
;
206 nsIDOMElement_HasChildNodes(elem
, &has_children
);
210 nsIDOMElement_GetChildNodes(elem
, &node_list
);
211 nsIDOMNodeList_GetLength(node_list
, &child_cnt
);
213 for(i
=0; i
<child_cnt
; i
++) {
214 nsIDOMNodeList_Item(node_list
, i
, &child_node
);
216 nsIDOMNode_GetNodeType(child_node
, &node_type
);
217 if(node_type
== ELEMENT_NODE
) {
218 nsIDOMElement
*child_elem
;
220 const PRUnichar
*ctag
;
222 nsIDOMNode_QueryInterface(child_node
, &IID_nsIDOMElement
, (void**)&child_elem
);
224 nsAString_Init(&tag_str
, NULL
);
225 nsIDOMElement_GetTagName(child_elem
, &tag_str
);
226 nsAString_GetData(&tag_str
, &ctag
);
228 if(!strcmpiW(ctag
, tag
))
229 /* FIXME: remove node if there are no more attributes */
230 nsIDOMElement_RemoveAttribute(child_elem
, attr_str
);
232 nsAString_Finish(&tag_str
);
234 remove_child_attr(child_elem
, tag
, attr_str
);
236 nsIDOMElement_Release(child_elem
);
239 nsIDOMNode_Release(child_node
);
242 nsIDOMNodeList_Release(node_list
);
245 static void get_font_size(HTMLDocument
*This
, WCHAR
*ret
)
247 nsISelection
*nsselection
= get_ns_selection(This
);
248 nsIDOMHTMLElement
*elem
= NULL
;
249 nsIDOMNode
*node
= NULL
, *tmp_node
;
260 nsISelection_GetFocusNode(nsselection
, &node
);
261 nsISelection_Release(nsselection
);
264 nsres
= nsIDOMNode_GetNodeType(node
, &node_type
);
265 if(NS_FAILED(nsres
) || node_type
== DOCUMENT_NODE
)
268 if(node_type
== ELEMENT_NODE
) {
269 nsIDOMNode_QueryInterface(node
, &IID_nsIDOMHTMLElement
, (void**)&elem
);
271 nsAString_Init(&tag_str
, NULL
);
272 nsIDOMHTMLElement_GetTagName(elem
, &tag_str
);
273 nsAString_GetData(&tag_str
, &tag
);
275 if(!strcmpiW(tag
, fontW
)) {
277 const PRUnichar
*val
;
279 TRACE("found font tag %p\n", elem
);
281 get_elem_attr_value(elem
, sizeW
, &val_str
, &val
);
283 TRACE("found size %s\n", debugstr_w(val
));
287 nsAString_Finish(&val_str
);
290 nsAString_Finish(&tag_str
);
291 nsIDOMHTMLElement_Release(elem
);
298 nsIDOMNode_GetParentNode(node
, &node
);
299 nsIDOMNode_Release(tmp_node
);
303 nsIDOMNode_Release(node
);
306 static void set_font_size(HTMLDocument
*This
, LPCWSTR size
)
308 nsISelection
*nsselection
;
310 nsIDOMHTMLElement
*elem
;
316 if(!This
->doc_node
->nsdoc
) {
317 WARN("NULL nsdoc\n");
321 nsselection
= get_ns_selection(This
);
325 nsISelection_GetRangeCount(nsselection
, &range_cnt
);
327 FIXME("range_cnt %d not supprted\n", range_cnt
);
329 nsISelection_Release(nsselection
);
334 create_nselem(This
->doc_node
, fontW
, &elem
);
336 nsAString_InitDepend(&size_str
, sizeW
);
337 nsAString_InitDepend(&val_str
, size
);
339 nsIDOMHTMLElement_SetAttribute(elem
, &size_str
, &val_str
);
340 nsAString_Finish(&val_str
);
342 nsISelection_GetRangeAt(nsselection
, 0, &range
);
343 nsISelection_GetIsCollapsed(nsselection
, &collapsed
);
344 nsISelection_RemoveAllRanges(nsselection
);
346 nsIDOMRange_SurroundContents(range
, (nsIDOMNode
*)elem
);
349 nsISelection_Collapse(nsselection
, (nsIDOMNode
*)elem
, 0);
351 /* Remove all size attributes from the range */
352 remove_child_attr((nsIDOMElement
*)elem
, fontW
, &size_str
);
353 nsISelection_SelectAllChildren(nsselection
, (nsIDOMNode
*)elem
);
356 nsISelection_Release(nsselection
);
357 nsIDOMRange_Release(range
);
358 nsIDOMHTMLElement_Release(elem
);
360 nsAString_Finish(&size_str
);
362 set_dirty(This
, VARIANT_TRUE
);
365 static void handle_arrow_key(HTMLDocument
*This
, nsIDOMKeyEvent
*event
, const char * const cmds
[4])
370 nsIDOMKeyEvent_GetCtrlKey(event
, &b
);
374 nsIDOMKeyEvent_GetShiftKey(event
, &b
);
379 do_ns_editor_command(This
->doc_obj
->nscontainer
, cmds
[i
]);
381 nsIDOMKeyEvent_PreventDefault(event
);
384 void handle_edit_event(HTMLDocument
*This
, nsIDOMEvent
*event
)
386 nsIDOMKeyEvent
*key_event
;
389 nsIDOMEvent_QueryInterface(event
, &IID_nsIDOMKeyEvent
, (void**)&key_event
);
391 nsIDOMKeyEvent_GetKeyCode(key_event
, &code
);
395 static const char * const cmds
[] = {
398 NSCMD_SELECTCHARPREVIOUS
,
399 NSCMD_SELECTWORDPREVIOUS
403 handle_arrow_key(This
, key_event
, cmds
);
407 static const char * const cmds
[] = {
410 NSCMD_SELECTCHARNEXT
,
415 handle_arrow_key(This
, key_event
, cmds
);
419 static const char * const cmds
[] = {
422 NSCMD_SELECTLINEPREVIOUS
,
427 handle_arrow_key(This
, key_event
, cmds
);
431 static const char * const cmds
[] = {
434 NSCMD_SELECTLINENEXT
,
439 handle_arrow_key(This
, key_event
, cmds
);
442 case DOM_VK_DELETE
: {
443 static const char * const cmds
[] = {
444 NSCMD_DELETECHARFORWARD
,
445 NSCMD_DELETEWORDFORWARD
,
450 handle_arrow_key(This
, key_event
, cmds
);
454 static const char * const cmds
[] = {
457 NSCMD_SELECTBEGINLINE
,
462 handle_arrow_key(This
, key_event
, cmds
);
466 static const char * const cmds
[] = {
474 handle_arrow_key(This
, key_event
, cmds
);
479 nsIDOMKeyEvent_Release(key_event
);
482 void handle_edit_load(HTMLDocument
*This
)
484 get_editor_controller(This
->doc_obj
->nscontainer
);
487 static void set_ns_fontname(HTMLDocument
*This
, const char *fontname
)
489 nsICommandParams
*nsparam
= create_nscommand_params();
491 nsICommandParams_SetCStringValue(nsparam
, NSSTATE_ATTRIBUTE
, fontname
);
492 do_ns_command(This
, NSCMD_FONTFACE
, nsparam
);
493 nsICommandParams_Release(nsparam
);
496 static HRESULT
exec_delete(HTMLDocument
*This
, DWORD cmdexecopt
, VARIANT
*in
, VARIANT
*out
)
498 TRACE("(%p)->(%p %p)\n", This
, in
, out
);
500 if(This
->doc_obj
->nscontainer
)
501 do_ns_editor_command(This
->doc_obj
->nscontainer
, NSCMD_DELETECHARFORWARD
);
503 update_doc(This
, UPDATE_UI
);
507 static HRESULT
exec_fontname(HTMLDocument
*This
, DWORD cmdexecopt
, VARIANT
*in
, VARIANT
*out
)
509 TRACE("(%p)->(%p %p)\n", This
, in
, out
);
511 if(!This
->doc_obj
->nscontainer
) {
512 update_doc(This
, UPDATE_UI
);
519 if(V_VT(in
) != VT_BSTR
) {
520 FIXME("Unsupported fontname %s\n", debugstr_variant(out
));
524 TRACE("%s\n", debugstr_w(V_BSTR(in
)));
526 stra
= heap_strdupWtoA(V_BSTR(in
));
527 set_ns_fontname(This
, stra
);
530 update_doc(This
, UPDATE_UI
);
534 nsICommandParams
*nsparam
;
543 nsparam
= create_nscommand_params();
545 nsres
= get_ns_command_state(This
->doc_obj
->nscontainer
, NSCMD_FONTFACE
, nsparam
);
549 nsICommandParams_GetCStringValue(nsparam
, NSSTATE_ATTRIBUTE
, &stra
);
550 nsICommandParams_Release(nsparam
);
552 len
= MultiByteToWideChar(CP_ACP
, 0, stra
, -1, NULL
, 0);
553 strw
= heap_alloc(len
*sizeof(WCHAR
));
554 MultiByteToWideChar(CP_ACP
, 0, stra
, -1, strw
, len
);
557 V_BSTR(out
) = SysAllocString(strw
);
564 static HRESULT
exec_forecolor(HTMLDocument
*This
, DWORD cmdexecopt
, VARIANT
*in
, VARIANT
*out
)
566 TRACE("(%p)->(%p %p)\n", This
, in
, out
);
569 if(V_VT(in
) == VT_I4
) {
570 nsICommandParams
*nsparam
= create_nscommand_params();
573 sprintf(color_str
, "#%02x%02x%02x",
574 V_I4(in
)&0xff, (V_I4(in
)>>8)&0xff, (V_I4(in
)>>16)&0xff);
576 nsICommandParams_SetCStringValue(nsparam
, NSSTATE_ATTRIBUTE
, color_str
);
577 do_ns_command(This
, NSCMD_FONTCOLOR
, nsparam
);
579 nsICommandParams_Release(nsparam
);
581 FIXME("unsupported forecolor %s\n", debugstr_variant(in
));
584 update_doc(This
, UPDATE_UI
);
588 FIXME("unsupported out\n");
595 static HRESULT
exec_fontsize(HTMLDocument
*This
, DWORD cmdexecopt
, VARIANT
*in
, VARIANT
*out
)
597 TRACE("(%p)->(%p %p)\n", This
, in
, out
);
602 get_font_size(This
, val
);
604 V_I4(out
) = strtolW(val
, NULL
, 10);
611 static const WCHAR format
[] = {'%','d',0};
612 wsprintfW(size
, format
, V_I4(in
));
613 set_font_size(This
, size
);
617 set_font_size(This
, V_BSTR(in
));
620 FIXME("unsupported fontsize %s\n", debugstr_variant(in
));
623 update_doc(This
, UPDATE_UI
);
629 static HRESULT
exec_font(HTMLDocument
*This
, DWORD cmdexecopt
, VARIANT
*in
, VARIANT
*out
)
632 FIXME("(%p)->(%p %p)\n", This
, in
, out
);
636 static HRESULT
exec_bold(HTMLDocument
*This
, DWORD cmdexecopt
, VARIANT
*in
, VARIANT
*out
)
638 TRACE("(%p)\n", This
);
641 FIXME("unsupported args\n");
643 if(This
->doc_obj
->nscontainer
)
644 do_ns_command(This
, NSCMD_BOLD
, NULL
);
646 update_doc(This
, UPDATE_UI
);
650 static HRESULT
exec_italic(HTMLDocument
*This
, DWORD cmdexecopt
, VARIANT
*in
, VARIANT
*out
)
652 TRACE("(%p)\n", This
);
655 FIXME("unsupported args\n");
657 if(This
->doc_obj
->nscontainer
)
658 do_ns_command(This
, NSCMD_ITALIC
, NULL
);
660 update_doc(This
, UPDATE_UI
);
664 static HRESULT
query_justify(HTMLDocument
*This
, OLECMD
*cmd
)
666 static const PRUnichar justifycenterW
[] = {'j','u','s','t','i','f','y','c','e','n','t','e','r',0};
667 static const PRUnichar justifyrightW
[] = {'j','u','s','t','i','f','y','r','i','g','h','t',0};
670 case IDM_JUSTIFYCENTER
:
671 TRACE("(%p) IDM_JUSTIFYCENTER\n", This
);
672 cmd
->cmdf
= query_align_status(This
, justifycenterW
);
674 case IDM_JUSTIFYLEFT
:
675 TRACE("(%p) IDM_JUSTIFYLEFT\n", This
);
676 /* FIXME: We should set OLECMDF_LATCHED only if it's set explicitly. */
677 if(This
->doc_obj
->usermode
!= EDITMODE
|| This
->window
->readystate
< READYSTATE_INTERACTIVE
)
678 cmd
->cmdf
= OLECMDF_SUPPORTED
;
680 cmd
->cmdf
= OLECMDF_SUPPORTED
| OLECMDF_ENABLED
;
682 case IDM_JUSTIFYRIGHT
:
683 TRACE("(%p) IDM_JUSTIFYRIGHT\n", This
);
684 cmd
->cmdf
= query_align_status(This
, justifyrightW
);
691 static HRESULT
exec_justifycenter(HTMLDocument
*This
, DWORD cmdexecopt
, VARIANT
*in
, VARIANT
*out
)
693 TRACE("(%p)\n", This
);
696 FIXME("unsupported args\n");
698 set_ns_align(This
, NSALIGN_CENTER
);
699 update_doc(This
, UPDATE_UI
);
703 static HRESULT
exec_justifyleft(HTMLDocument
*This
, DWORD cmdexecopt
, VARIANT
*in
, VARIANT
*out
)
705 TRACE("(%p)\n", This
);
708 FIXME("unsupported args\n");
710 set_ns_align(This
, NSALIGN_LEFT
);
711 update_doc(This
, UPDATE_UI
);
715 static HRESULT
exec_justifyright(HTMLDocument
*This
, DWORD cmdexecopt
, VARIANT
*in
, VARIANT
*out
)
717 TRACE("(%p)\n", This
);
720 FIXME("unsupported args\n");
722 set_ns_align(This
, NSALIGN_RIGHT
);
723 update_doc(This
, UPDATE_UI
);
727 static HRESULT
exec_underline(HTMLDocument
*This
, DWORD cmdexecopt
, VARIANT
*in
, VARIANT
*out
)
729 TRACE("(%p)\n", This
);
732 FIXME("unsupported args\n");
734 do_ns_command(This
, NSCMD_UNDERLINE
, NULL
);
735 update_doc(This
, UPDATE_UI
);
739 static HRESULT
exec_horizontalline(HTMLDocument
*This
, DWORD cmdexecopt
, VARIANT
*in
, VARIANT
*out
)
741 TRACE("(%p)\n", This
);
744 FIXME("unsupported args\n");
746 do_ns_command(This
, NSCMD_INSERTHR
, NULL
);
747 update_doc(This
, UPDATE_UI
);
751 static HRESULT
exec_orderlist(HTMLDocument
*This
, DWORD cmdexecopt
, VARIANT
*in
, VARIANT
*out
)
753 TRACE("(%p)\n", This
);
756 FIXME("unsupported args\n");
758 do_ns_command(This
, NSCMD_OL
, NULL
);
759 update_doc(This
, UPDATE_UI
);
763 static HRESULT
exec_unorderlist(HTMLDocument
*This
, DWORD cmdexecopt
, VARIANT
*in
, VARIANT
*out
)
765 TRACE("(%p)\n", This
);
768 FIXME("unsupported args\n");
770 do_ns_command(This
, NSCMD_UL
, NULL
);
771 update_doc(This
, UPDATE_UI
);
775 static HRESULT
exec_indent(HTMLDocument
*This
, DWORD cmdexecopt
, VARIANT
*in
, VARIANT
*out
)
777 TRACE("(%p)\n", This
);
780 FIXME("unsupported args\n");
782 do_ns_command(This
, NSCMD_INDENT
, NULL
);
783 update_doc(This
, UPDATE_UI
);
787 static HRESULT
exec_outdent(HTMLDocument
*This
, DWORD cmdexecopt
, VARIANT
*in
, VARIANT
*out
)
789 TRACE("(%p)\n", This
);
792 FIXME("unsupported args\n");
794 do_ns_command(This
, NSCMD_OUTDENT
, NULL
);
795 update_doc(This
, UPDATE_UI
);
799 static HRESULT
exec_composesettings(HTMLDocument
*This
, DWORD cmdexecopt
, VARIANT
*in
, VARIANT
*out
)
803 if(out
|| !in
|| V_VT(in
) != VT_BSTR
) {
804 WARN("invalid arg %s\n", debugstr_variant(in
));
808 TRACE("(%p)->(%x %s)\n", This
, cmdexecopt
, debugstr_w(V_BSTR(in
)));
810 update_doc(This
, UPDATE_UI
);
814 exec_bold(This
, cmdexecopt
, NULL
, NULL
);
815 ptr
= strchrW(ptr
, ',');
820 exec_italic(This
, cmdexecopt
, NULL
, NULL
);
821 ptr
= strchrW(ptr
, ',');
826 exec_underline(This
, cmdexecopt
, NULL
, NULL
);
827 ptr
= strchrW(ptr
, ',');
831 if(isdigitW(*++ptr
)) {
837 exec_fontsize(This
, cmdexecopt
, &v
, NULL
);
839 ptr
= strchrW(ptr
, ',');
844 FIXME("set font color\n");
845 ptr
= strchrW(ptr
, ',');
850 FIXME("set background color\n");
851 ptr
= strchrW(ptr
, ',');
860 V_BSTR(&v
) = SysAllocString(ptr
);
862 exec_fontname(This
, cmdexecopt
, &v
, NULL
);
864 SysFreeString(V_BSTR(&v
));
870 HRESULT
editor_exec_copy(HTMLDocument
*This
, DWORD cmdexecopt
, VARIANT
*in
, VARIANT
*out
)
872 update_doc(This
, UPDATE_UI
);
874 if(!This
->doc_obj
->nscontainer
)
877 do_ns_editor_command(This
->doc_obj
->nscontainer
, NSCMD_COPY
);
881 HRESULT
editor_exec_cut(HTMLDocument
*This
, DWORD cmdexecopt
, VARIANT
*in
, VARIANT
*out
)
883 update_doc(This
, UPDATE_UI
);
885 if(!This
->doc_obj
->nscontainer
)
888 do_ns_editor_command(This
->doc_obj
->nscontainer
, NSCMD_CUT
);
892 HRESULT
editor_exec_paste(HTMLDocument
*This
, DWORD cmdexecopt
, VARIANT
*in
, VARIANT
*out
)
894 update_doc(This
, UPDATE_UI
);
896 if(!This
->doc_obj
->nscontainer
)
899 do_ns_editor_command(This
->doc_obj
->nscontainer
, NSCMD_PASTE
);
903 static HRESULT
exec_setdirty(HTMLDocument
*This
, DWORD cmdexecopt
, VARIANT
*in
, VARIANT
*out
)
905 TRACE("(%p)->(%08x %p %p)\n", This
, cmdexecopt
, in
, out
);
910 if(V_VT(in
) == VT_BOOL
)
911 set_dirty(This
, V_BOOL(in
));
913 FIXME("unsupported arg %s\n", debugstr_variant(in
));
918 static HRESULT
query_edit_status(HTMLDocument
*This
, OLECMD
*cmd
)
922 TRACE("CGID_MSHTML: IDM_DELETE\n");
923 cmd
->cmdf
= query_ns_edit_status(This
, NULL
);
926 TRACE("CGID_MSHTML: IDM_FONTNAME\n");
927 cmd
->cmdf
= query_ns_edit_status(This
, NULL
);
930 TRACE("CGID_MSHTML: IDM_FONTSIZE\n");
931 cmd
->cmdf
= query_ns_edit_status(This
, NULL
);
934 TRACE("CGID_MSHTML: IDM_BOLD\n");
935 cmd
->cmdf
= query_ns_edit_status(This
, NSCMD_BOLD
);
938 TRACE("CGID_MSHTML: IDM_FORECOLOR\n");
939 cmd
->cmdf
= query_ns_edit_status(This
, NULL
);
942 TRACE("CGID_MSHTML: IDM_ITALIC\n");
943 cmd
->cmdf
= query_ns_edit_status(This
, NSCMD_ITALIC
);
946 TRACE("CGID_MSHTML: IDM_UNDERLINE\n");
947 cmd
->cmdf
= query_ns_edit_status(This
, NSCMD_UNDERLINE
);
949 case IDM_HORIZONTALLINE
:
950 TRACE("CGID_MSHTML: IDM_HORIZONTALLINE\n");
951 cmd
->cmdf
= query_ns_edit_status(This
, NULL
);
954 TRACE("CGID_MSHTML: IDM_ORDERLIST\n");
955 cmd
->cmdf
= query_ns_edit_status(This
, NSCMD_OL
);
957 case IDM_UNORDERLIST
:
958 TRACE("CGID_MSHTML: IDM_HORIZONTALLINE\n");
959 cmd
->cmdf
= query_ns_edit_status(This
, NSCMD_UL
);
962 TRACE("CGID_MSHTML: IDM_INDENT\n");
963 cmd
->cmdf
= query_ns_edit_status(This
, NULL
);
966 TRACE("CGID_MSHTML: IDM_OUTDENT\n");
967 cmd
->cmdf
= query_ns_edit_status(This
, NULL
);
970 TRACE("CGID_MSHTML: IDM_HYPERLINK\n");
971 cmd
->cmdf
= query_ns_edit_status(This
, NULL
);
978 static INT_PTR CALLBACK
hyperlink_dlgproc(HWND hwnd
, UINT msg
, WPARAM wparam
, LPARAM lparam
)
980 static const WCHAR wszOther
[] = {'(','o','t','h','e','r',')',0};
981 static const WCHAR wszFile
[] = {'f','i','l','e',':',0};
982 static const WCHAR wszFtp
[] = {'f','t','p',':',0};
983 static const WCHAR wszHttp
[] = {'h','t','t','p',':',0};
984 static const WCHAR wszHttps
[] = {'h','t','t','p','s',':',0};
985 static const WCHAR wszMailto
[] = {'m','a','i','l','t','o',':',0};
986 static const WCHAR wszNews
[] = {'n','e','w','s',':',0};
993 HWND hwndCB
= GetDlgItem(hwnd
, IDC_TYPE
);
994 HWND hwndURL
= GetDlgItem(hwnd
, IDC_URL
);
997 SetWindowLongPtrW(hwnd
, DWLP_USER
, lparam
);
999 SendMessageW(hwndCB
, CB_INSERTSTRING
, -1, (LPARAM
)wszOther
);
1000 SendMessageW(hwndCB
, CB_INSERTSTRING
, -1, (LPARAM
)wszFile
);
1001 SendMessageW(hwndCB
, CB_INSERTSTRING
, -1, (LPARAM
)wszFtp
);
1002 def_idx
= SendMessageW(hwndCB
, CB_INSERTSTRING
, -1, (LPARAM
)wszHttp
);
1003 SendMessageW(hwndCB
, CB_INSERTSTRING
, -1, (LPARAM
)wszHttps
);
1004 SendMessageW(hwndCB
, CB_INSERTSTRING
, -1, (LPARAM
)wszMailto
);
1005 SendMessageW(hwndCB
, CB_INSERTSTRING
, -1, (LPARAM
)wszNews
);
1006 SendMessageW(hwndCB
, CB_SETCURSEL
, def_idx
, 0);
1008 /* force the updating of the URL edit box */
1009 SendMessageW(hwnd
, WM_COMMAND
, MAKEWPARAM(IDC_TYPE
, CBN_SELCHANGE
), (LPARAM
)hwndCB
);
1012 len
= SendMessageW(hwndURL
, WM_GETTEXTLENGTH
, 0, 0);
1013 SendMessageW(hwndURL
, EM_SETSEL
, 0, len
);
1020 case MAKEWPARAM(IDCANCEL
, BN_CLICKED
):
1021 EndDialog(hwnd
, wparam
);
1023 case MAKEWPARAM(IDOK
, BN_CLICKED
):
1025 BSTR
*url
= (BSTR
*)GetWindowLongPtrW(hwnd
, DWLP_USER
);
1026 HWND hwndURL
= GetDlgItem(hwnd
, IDC_URL
);
1027 INT len
= GetWindowTextLengthW(hwndURL
);
1028 *url
= SysAllocStringLen(NULL
, len
+ 1);
1029 GetWindowTextW(hwndURL
, *url
, len
+ 1);
1030 EndDialog(hwnd
, wparam
);
1033 case MAKEWPARAM(IDC_TYPE
, CBN_SELCHANGE
):
1035 HWND hwndURL
= GetDlgItem(hwnd
, IDC_URL
);
1041 static const WCHAR wszSlashSlash
[] = {'/','/'};
1043 /* get string of currently selected hyperlink type */
1044 item
= SendMessageW((HWND
)lparam
, CB_GETCURSEL
, 0, 0);
1045 len
= SendMessageW((HWND
)lparam
, CB_GETLBTEXTLEN
, item
, 0);
1046 type
= HeapAlloc(GetProcessHeap(), 0, (len
+ 1) * sizeof(WCHAR
));
1047 SendMessageW((HWND
)lparam
, CB_GETLBTEXT
, item
, (LPARAM
)type
);
1049 if (!strcmpW(type
, wszOther
))
1052 /* get current URL */
1053 len
= GetWindowTextLengthW(hwndURL
);
1054 url
= HeapAlloc(GetProcessHeap(), 0, (len
+ strlenW(type
) + 3) * sizeof(WCHAR
));
1055 GetWindowTextW(hwndURL
, url
, len
+ 1);
1057 /* strip off old protocol */
1058 p
= strchrW(url
, ':');
1059 if (p
&& p
[1] == '/' && p
[2] == '/')
1062 memmove(url
+ (*type
!= '\0' ? strlenW(type
) + 2 : 0), p
, (len
+ 1 - (p
- url
)) * sizeof(WCHAR
));
1064 /* add new protocol */
1067 memcpy(url
, type
, (strlenW(type
) + 1) * sizeof(WCHAR
));
1068 if (strcmpW(type
, wszMailto
) && strcmpW(type
, wszNews
))
1069 memcpy(url
+ strlenW(type
), wszSlashSlash
, sizeof(wszSlashSlash
));
1072 SetWindowTextW(hwndURL
, url
);
1074 HeapFree(GetProcessHeap(), 0, url
);
1075 HeapFree(GetProcessHeap(), 0, type
);
1081 EndDialog(hwnd
, IDCANCEL
);
1088 static HRESULT
exec_hyperlink(HTMLDocument
*This
, DWORD cmdexecopt
, VARIANT
*in
, VARIANT
*out
)
1090 nsAString href_str
, ns_url
;
1091 nsIHTMLEditor
*html_editor
;
1092 nsIDOMHTMLElement
*anchor_elem
;
1093 cpp_bool insert_link_at_caret
;
1094 nsISelection
*nsselection
;
1097 HRESULT hres
= E_FAIL
;
1099 static const WCHAR aW
[] = {'a',0};
1100 static const WCHAR hrefW
[] = {'h','r','e','f',0};
1102 TRACE("%p, 0x%x, %p, %p\n", This
, cmdexecopt
, in
, out
);
1104 if (cmdexecopt
== OLECMDEXECOPT_DONTPROMPTUSER
)
1106 if (!in
|| V_VT(in
) != VT_BSTR
)
1108 WARN("invalid arg\n");
1109 return E_INVALIDARG
;
1115 ret
= DialogBoxParamW(hInst
, MAKEINTRESOURCEW(IDD_HYPERLINK
), NULL
/* FIXME */, hyperlink_dlgproc
, (LPARAM
)&url
);
1117 return OLECMDERR_E_CANCELED
;
1120 if(!This
->doc_node
->nsdoc
) {
1121 WARN("NULL nsdoc\n");
1122 return E_UNEXPECTED
;
1125 nsselection
= get_ns_selection(This
);
1129 /* create an element for the link */
1130 create_nselem(This
->doc_node
, aW
, &anchor_elem
);
1132 nsAString_InitDepend(&href_str
, hrefW
);
1133 nsAString_InitDepend(&ns_url
, url
);
1134 nsIDOMHTMLElement_SetAttribute(anchor_elem
, &href_str
, &ns_url
);
1135 nsAString_Finish(&href_str
);
1137 nsISelection_GetIsCollapsed(nsselection
, &insert_link_at_caret
);
1139 /* create an element with text of URL */
1140 if (insert_link_at_caret
) {
1141 nsIDOMNode
*unused_node
;
1142 nsIDOMText
*text_node
;
1144 nsIDOMHTMLDocument_CreateTextNode(This
->doc_node
->nsdoc
, &ns_url
, &text_node
);
1146 /* wrap the <a> tags around the text element */
1147 nsIDOMHTMLElement_AppendChild(anchor_elem
, (nsIDOMNode
*)text_node
, &unused_node
);
1148 nsIDOMText_Release(text_node
);
1149 nsIDOMNode_Release(unused_node
);
1152 nsAString_Finish(&ns_url
);
1154 nsIEditor_QueryInterface(This
->doc_obj
->nscontainer
->editor
, &IID_nsIHTMLEditor
, (void **)&html_editor
);
1158 if (insert_link_at_caret
) {
1159 /* add them to the document at the caret position */
1160 nsres
= nsIHTMLEditor_InsertElementAtSelection(html_editor
, (nsIDOMElement
*)anchor_elem
, FALSE
);
1161 nsISelection_SelectAllChildren(nsselection
, (nsIDOMNode
*)anchor_elem
);
1162 }else /* add them around the selection using the magic provided to us by nsIHTMLEditor */
1163 nsres
= nsIHTMLEditor_InsertLinkAroundSelection(html_editor
, (nsIDOMElement
*)anchor_elem
);
1165 nsIHTMLEditor_Release(html_editor
);
1166 hres
= NS_SUCCEEDED(nsres
) ? S_OK
: E_FAIL
;
1169 nsISelection_Release(nsselection
);
1170 nsIDOMHTMLElement_Release(anchor_elem
);
1172 if (cmdexecopt
!= OLECMDEXECOPT_DONTPROMPTUSER
)
1175 TRACE("-- 0x%08x\n", hres
);
1179 const cmdtable_t editmode_cmds
[] = {
1180 {IDM_DELETE
, query_edit_status
, exec_delete
},
1181 {IDM_FONTNAME
, query_edit_status
, exec_fontname
},
1182 {IDM_FONTSIZE
, query_edit_status
, exec_fontsize
},
1183 {IDM_FORECOLOR
, query_edit_status
, exec_forecolor
},
1184 {IDM_BOLD
, query_edit_status
, exec_bold
},
1185 {IDM_ITALIC
, query_edit_status
, exec_italic
},
1186 {IDM_JUSTIFYCENTER
, query_justify
, exec_justifycenter
},
1187 {IDM_JUSTIFYRIGHT
, query_justify
, exec_justifyright
},
1188 {IDM_JUSTIFYLEFT
, query_justify
, exec_justifyleft
},
1189 {IDM_FONT
, NULL
, exec_font
},
1190 {IDM_UNDERLINE
, query_edit_status
, exec_underline
},
1191 {IDM_HORIZONTALLINE
, query_edit_status
, exec_horizontalline
},
1192 {IDM_ORDERLIST
, query_edit_status
, exec_orderlist
},
1193 {IDM_UNORDERLIST
, query_edit_status
, exec_unorderlist
},
1194 {IDM_INDENT
, query_edit_status
, exec_indent
},
1195 {IDM_OUTDENT
, query_edit_status
, exec_outdent
},
1196 {IDM_COMPOSESETTINGS
, NULL
, exec_composesettings
},
1197 {IDM_HYPERLINK
, query_edit_status
, exec_hyperlink
},
1198 {IDM_SETDIRTY
, NULL
, exec_setdirty
},
1202 void init_editor(HTMLDocument
*This
)
1204 update_doc(This
, UPDATE_UI
);
1206 set_ns_fontname(This
, "Times New Roman");
1209 HRESULT
editor_is_dirty(HTMLDocument
*This
)
1213 if(!This
->doc_obj
->nscontainer
|| !This
->doc_obj
->nscontainer
->editor
)
1216 nsIEditor_GetDocumentModified(This
->doc_obj
->nscontainer
->editor
, &modified
);
1218 return modified
? S_OK
: S_FALSE
;
1221 HRESULT
setup_edit_mode(HTMLDocumentObj
*doc
)
1226 if(doc
->usermode
== EDITMODE
)
1229 doc
->usermode
= EDITMODE
;
1231 if(doc
->basedoc
.window
->mon
) {
1232 CLSID clsid
= IID_NULL
;
1233 hres
= IMoniker_GetClassID(doc
->basedoc
.window
->mon
, &clsid
);
1234 if(SUCCEEDED(hres
)) {
1235 /* We should use IMoniker::Save here */
1236 FIXME("Use CLSID %s\n", debugstr_guid(&clsid
));
1241 IOleInPlaceFrame_SetStatusText(doc
->frame
, NULL
);
1243 doc
->basedoc
.window
->readystate
= READYSTATE_UNINITIALIZED
;
1246 IOleCommandTarget
*cmdtrg
;
1248 hres
= IOleClientSite_QueryInterface(doc
->client
, &IID_IOleCommandTarget
, (void**)&cmdtrg
);
1249 if(SUCCEEDED(hres
)) {
1254 IOleCommandTarget_Exec(cmdtrg
, &CGID_ShellDocView
, 37, 0, &var
, NULL
);
1256 IOleCommandTarget_Release(cmdtrg
);
1261 DOCHOSTUIINFO hostinfo
;
1263 memset(&hostinfo
, 0, sizeof(DOCHOSTUIINFO
));
1264 hostinfo
.cbSize
= sizeof(DOCHOSTUIINFO
);
1265 hres
= IDocHostUIHandler_GetHostInfo(doc
->hostui
, &hostinfo
);
1267 /* FIXME: use hostinfo */
1268 TRACE("hostinfo = {%u %08x %08x %s %s}\n",
1269 hostinfo
.cbSize
, hostinfo
.dwFlags
, hostinfo
.dwDoubleClick
,
1270 debugstr_w(hostinfo
.pchHostCss
), debugstr_w(hostinfo
.pchHostNS
));
1273 update_doc(&doc
->basedoc
, UPDATE_UI
);
1275 if(doc
->basedoc
.window
->mon
) {
1276 /* FIXME: We should find nicer way to do this */
1277 remove_target_tasks(doc
->basedoc
.task_magic
);
1279 mon
= doc
->basedoc
.window
->mon
;
1280 IMoniker_AddRef(mon
);
1282 static const WCHAR about_blankW
[] = {'a','b','o','u','t',':','b','l','a','n','k',0};
1284 hres
= CreateURLMoniker(NULL
, about_blankW
, &mon
);
1286 FIXME("CreateURLMoniker failed: %08x\n", hres
);
1291 hres
= IPersistMoniker_Load(&doc
->basedoc
.IPersistMoniker_iface
, TRUE
, mon
, NULL
, 0);
1292 IMoniker_Release(mon
);
1296 if(doc
->ui_active
) {
1298 call_set_active_object(doc
->ip_window
, NULL
);
1300 IDocHostUIHandler_HideUI(doc
->hostui
);
1303 if(doc
->ui_active
) {
1304 RECT rcBorderWidths
;
1307 IDocHostUIHandler_ShowUI(doc
->hostui
, DOCHOSTUITYPE_AUTHOR
,
1308 &doc
->basedoc
.IOleInPlaceActiveObject_iface
, &doc
->basedoc
.IOleCommandTarget_iface
,
1309 doc
->frame
, doc
->ip_window
);
1312 call_set_active_object(doc
->ip_window
, &doc
->basedoc
.IOleInPlaceActiveObject_iface
);
1314 memset(&rcBorderWidths
, 0, sizeof(rcBorderWidths
));
1316 IOleInPlaceFrame_SetBorderSpace(doc
->frame
, &rcBorderWidths
);