shdocvw: Added InternetExplorer object tests.
[wine] / dlls / mshtml / selection.c
1 /*
2  * Copyright 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 <stdarg.h>
20
21 #define COBJMACROS
22
23 #include "windef.h"
24 #include "winbase.h"
25 #include "winuser.h"
26 #include "ole2.h"
27
28 #include "wine/debug.h"
29 #include "wine/unicode.h"
30
31 #include "mshtml_private.h"
32
33 WINE_DEFAULT_DEBUG_CHANNEL(mshtml);
34
35 typedef struct {
36     IHTMLSelectionObject IHTMLSelectionObject_iface;
37
38     LONG ref;
39
40     nsISelection *nsselection;
41     HTMLDocumentNode *doc;
42
43     struct list entry;
44 } HTMLSelectionObject;
45
46 static inline HTMLSelectionObject *impl_from_IHTMLSelectionObject(IHTMLSelectionObject *iface)
47 {
48     return CONTAINING_RECORD(iface, HTMLSelectionObject, IHTMLSelectionObject_iface);
49 }
50
51 static HRESULT WINAPI HTMLSelectionObject_QueryInterface(IHTMLSelectionObject *iface,
52                                                          REFIID riid, void **ppv)
53 {
54     HTMLSelectionObject *This = impl_from_IHTMLSelectionObject(iface);
55
56     *ppv = NULL;
57
58     if(IsEqualGUID(&IID_IUnknown, riid)) {
59         TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
60         *ppv = &This->IHTMLSelectionObject_iface;
61     }else if(IsEqualGUID(&IID_IDispatch, riid)) {
62         TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
63         *ppv = &This->IHTMLSelectionObject_iface;
64     }else if(IsEqualGUID(&IID_IHTMLSelectionObject, riid)) {
65         TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
66         *ppv = &This->IHTMLSelectionObject_iface;
67     }
68
69     if(*ppv) {
70         IUnknown_AddRef((IUnknown*)*ppv);
71         return S_OK;
72     }
73
74     WARN("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
75     return E_NOINTERFACE;
76 }
77
78 static ULONG WINAPI HTMLSelectionObject_AddRef(IHTMLSelectionObject *iface)
79 {
80     HTMLSelectionObject *This = impl_from_IHTMLSelectionObject(iface);
81     LONG ref = InterlockedIncrement(&This->ref);
82
83     TRACE("(%p) ref=%d\n", This, ref);
84
85     return ref;
86 }
87
88 static ULONG WINAPI HTMLSelectionObject_Release(IHTMLSelectionObject *iface)
89 {
90     HTMLSelectionObject *This = impl_from_IHTMLSelectionObject(iface);
91     LONG ref = InterlockedDecrement(&This->ref);
92
93     TRACE("(%p) ref=%d\n", This, ref);
94
95     if(!ref) {
96         if(This->nsselection)
97             nsISelection_Release(This->nsselection);
98         if(This->doc)
99             list_remove(&This->entry);
100         heap_free(This);
101     }
102
103     return ref;
104 }
105
106 static HRESULT WINAPI HTMLSelectionObject_GetTypeInfoCount(IHTMLSelectionObject *iface, UINT *pctinfo)
107 {
108     HTMLSelectionObject *This = impl_from_IHTMLSelectionObject(iface);
109     FIXME("(%p)->(%p)\n", This, pctinfo);
110     return E_NOTIMPL;
111 }
112
113 static HRESULT WINAPI HTMLSelectionObject_GetTypeInfo(IHTMLSelectionObject *iface, UINT iTInfo,
114                                               LCID lcid, ITypeInfo **ppTInfo)
115 {
116     HTMLSelectionObject *This = impl_from_IHTMLSelectionObject(iface);
117     FIXME("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
118     return E_NOTIMPL;
119 }
120
121 static HRESULT WINAPI HTMLSelectionObject_GetIDsOfNames(IHTMLSelectionObject *iface, REFIID riid,
122                                                 LPOLESTR *rgszNames, UINT cNames,
123                                                 LCID lcid, DISPID *rgDispId)
124 {
125     HTMLSelectionObject *This = impl_from_IHTMLSelectionObject(iface);
126     FIXME("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames,
127           lcid, rgDispId);
128     return E_NOTIMPL;
129 }
130
131 static HRESULT WINAPI HTMLSelectionObject_Invoke(IHTMLSelectionObject *iface, DISPID dispIdMember,
132                             REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams,
133                             VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
134 {
135     HTMLSelectionObject *This = impl_from_IHTMLSelectionObject(iface);
136     FIXME("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
137           lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
138     return E_NOTIMPL;
139 }
140
141 static HRESULT WINAPI HTMLSelectionObject_createRange(IHTMLSelectionObject *iface, IDispatch **range)
142 {
143     HTMLSelectionObject *This = impl_from_IHTMLSelectionObject(iface);
144     IHTMLTxtRange *range_obj = NULL;
145     nsIDOMRange *nsrange = NULL;
146     HRESULT hres;
147
148     TRACE("(%p)->(%p)\n", This, range);
149
150     if(This->nsselection) {
151         PRInt32 nsrange_cnt = 0;
152         nsresult nsres;
153
154         nsISelection_GetRangeCount(This->nsselection, &nsrange_cnt);
155         if(!nsrange_cnt) {
156             nsIDOMHTMLElement *nsbody = NULL;
157
158             TRACE("nsrange_cnt = 0\n");
159
160             if(!This->doc->nsdoc) {
161                 WARN("nsdoc is NULL\n");
162                 return E_UNEXPECTED;
163             }
164
165             nsres = nsIDOMHTMLDocument_GetBody(This->doc->nsdoc, &nsbody);
166             if(NS_FAILED(nsres) || !nsbody) {
167                 ERR("Could not get body: %08x\n", nsres);
168                 return E_FAIL;
169             }
170
171             nsres = nsISelection_Collapse(This->nsselection, (nsIDOMNode*)nsbody, 0);
172             nsIDOMHTMLElement_Release(nsbody);
173             if(NS_FAILED(nsres))
174                 ERR("Collapse failed: %08x\n", nsres);
175         }else if(nsrange_cnt > 1) {
176             FIXME("range_cnt = %d\n", nsrange_cnt);
177         }
178
179         nsres = nsISelection_GetRangeAt(This->nsselection, 0, &nsrange);
180         if(NS_FAILED(nsres))
181             ERR("GetRangeAt failed: %08x\n", nsres);
182     }
183
184     hres = HTMLTxtRange_Create(This->doc, nsrange, &range_obj);
185
186     if (nsrange) nsIDOMRange_Release(nsrange);
187     *range = (IDispatch*)range_obj;
188     return hres;
189 }
190
191 static HRESULT WINAPI HTMLSelectionObject_empty(IHTMLSelectionObject *iface)
192 {
193     HTMLSelectionObject *This = impl_from_IHTMLSelectionObject(iface);
194     FIXME("(%p)\n", This);
195     return E_NOTIMPL;
196 }
197
198 static HRESULT WINAPI HTMLSelectionObject_clear(IHTMLSelectionObject *iface)
199 {
200     HTMLSelectionObject *This = impl_from_IHTMLSelectionObject(iface);
201     FIXME("(%p)\n", This);
202     return E_NOTIMPL;
203 }
204
205 static HRESULT WINAPI HTMLSelectionObject_get_type(IHTMLSelectionObject *iface, BSTR *p)
206 {
207     HTMLSelectionObject *This = impl_from_IHTMLSelectionObject(iface);
208     PRBool collapsed = TRUE;
209
210     static const WCHAR wszNone[] = {'N','o','n','e',0};
211     static const WCHAR wszText[] = {'T','e','x','t',0};
212
213     TRACE("(%p)->(%p)\n", This, p);
214
215     if(This->nsselection)
216         nsISelection_GetIsCollapsed(This->nsselection, &collapsed);
217
218     *p = SysAllocString(collapsed ? wszNone : wszText); /* FIXME: control */
219     TRACE("ret %s\n", debugstr_w(*p));
220     return S_OK;
221 }
222
223 static const IHTMLSelectionObjectVtbl HTMLSelectionObjectVtbl = {
224     HTMLSelectionObject_QueryInterface,
225     HTMLSelectionObject_AddRef,
226     HTMLSelectionObject_Release,
227     HTMLSelectionObject_GetTypeInfoCount,
228     HTMLSelectionObject_GetTypeInfo,
229     HTMLSelectionObject_GetIDsOfNames,
230     HTMLSelectionObject_Invoke,
231     HTMLSelectionObject_createRange,
232     HTMLSelectionObject_empty,
233     HTMLSelectionObject_clear,
234     HTMLSelectionObject_get_type
235 };
236
237 HRESULT HTMLSelectionObject_Create(HTMLDocumentNode *doc, nsISelection *nsselection, IHTMLSelectionObject **ret)
238 {
239     HTMLSelectionObject *selection;
240
241     selection = heap_alloc(sizeof(HTMLSelectionObject));
242     if(!selection)
243         return E_OUTOFMEMORY;
244
245     selection->IHTMLSelectionObject_iface.lpVtbl = &HTMLSelectionObjectVtbl;
246     selection->ref = 1;
247     selection->nsselection = nsselection; /* We shouldn't call AddRef here */
248
249     selection->doc = doc;
250     list_add_head(&doc->selection_list, &selection->entry);
251
252     *ret = &selection->IHTMLSelectionObject_iface;
253     return S_OK;
254 }
255
256 void detach_selection(HTMLDocumentNode *This)
257 {
258     HTMLSelectionObject *iter;
259
260     LIST_FOR_EACH_ENTRY(iter, &This->selection_list, HTMLSelectionObject, entry) {
261         iter->doc = NULL;
262     }
263 }