Revert "explorerframe: Allow treeview expandos to open with a single click.".
[wine.git] / dlls / msxml3 / nodelist.c
blob2c1d10efb6aa24d8af3fd492759c5a4038e29e38
1 /*
2 * Node list implementation
4 * Copyright 2005 Mike McCormack
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #define COBJMACROS
23 #include "config.h"
25 #include <stdarg.h>
26 #ifdef HAVE_LIBXML2
27 # include <libxml/parser.h>
28 # include <libxml/xmlerror.h>
29 #endif
31 #include "windef.h"
32 #include "winbase.h"
33 #include "winuser.h"
34 #include "ole2.h"
35 #include "msxml6.h"
36 #include "msxml2did.h"
38 #include "msxml_private.h"
40 #include "wine/debug.h"
42 /* This file implements the object returned by childNodes property. Note that this is
43 * not the IXMLDOMNodeList returned by XPath queries - it's implemented in selection.c.
44 * They are different because the list returned by childNodes:
45 * - is "live" - changes to the XML tree are automatically reflected in the list
46 * - doesn't supports IXMLDOMSelection
47 * - note that an attribute node have a text child in DOM but not in the XPath data model
48 * thus the child is inaccessible by an XPath query
51 #ifdef HAVE_LIBXML2
53 WINE_DEFAULT_DEBUG_CHANNEL(msxml);
55 typedef struct
57 DispatchEx dispex;
58 IXMLDOMNodeList IXMLDOMNodeList_iface;
59 LONG ref;
60 xmlNodePtr parent;
61 xmlNodePtr current;
62 IEnumVARIANT *enumvariant;
63 } xmlnodelist;
65 static HRESULT nodelist_get_item(IUnknown *iface, LONG index, VARIANT *item)
67 V_VT(item) = VT_DISPATCH;
68 return IXMLDOMNodeList_get_item((IXMLDOMNodeList*)iface, index, (IXMLDOMNode**)&V_DISPATCH(item));
71 static const struct enumvariant_funcs nodelist_enumvariant = {
72 nodelist_get_item,
73 NULL
76 static inline xmlnodelist *impl_from_IXMLDOMNodeList( IXMLDOMNodeList *iface )
78 return CONTAINING_RECORD(iface, xmlnodelist, IXMLDOMNodeList_iface);
81 static HRESULT WINAPI xmlnodelist_QueryInterface(
82 IXMLDOMNodeList *iface,
83 REFIID riid,
84 void** ppvObject )
86 xmlnodelist *This = impl_from_IXMLDOMNodeList( iface );
88 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppvObject);
90 if ( IsEqualGUID( riid, &IID_IUnknown ) ||
91 IsEqualGUID( riid, &IID_IDispatch ) ||
92 IsEqualGUID( riid, &IID_IXMLDOMNodeList ) )
94 *ppvObject = iface;
96 else if (IsEqualGUID( riid, &IID_IEnumVARIANT ))
98 if (!This->enumvariant)
100 HRESULT hr = create_enumvariant((IUnknown*)iface, FALSE, &nodelist_enumvariant, &This->enumvariant);
101 if (FAILED(hr)) return hr;
104 return IEnumVARIANT_QueryInterface(This->enumvariant, &IID_IEnumVARIANT, ppvObject);
106 else if (dispex_query_interface(&This->dispex, riid, ppvObject))
108 return *ppvObject ? S_OK : E_NOINTERFACE;
110 else
112 TRACE("interface %s not implemented\n", debugstr_guid(riid));
113 *ppvObject = NULL;
114 return E_NOINTERFACE;
117 IXMLDOMNodeList_AddRef( iface );
119 return S_OK;
122 static ULONG WINAPI xmlnodelist_AddRef(
123 IXMLDOMNodeList *iface )
125 xmlnodelist *This = impl_from_IXMLDOMNodeList( iface );
126 ULONG ref = InterlockedIncrement( &This->ref );
127 TRACE("(%p)->(%d)\n", This, ref);
128 return ref;
131 static ULONG WINAPI xmlnodelist_Release(
132 IXMLDOMNodeList *iface )
134 xmlnodelist *This = impl_from_IXMLDOMNodeList( iface );
135 ULONG ref = InterlockedDecrement( &This->ref );
137 TRACE("(%p)->(%d)\n", This, ref);
138 if ( ref == 0 )
140 xmldoc_release( This->parent->doc );
141 if (This->enumvariant) IEnumVARIANT_Release(This->enumvariant);
142 heap_free( This );
145 return ref;
148 static HRESULT WINAPI xmlnodelist_GetTypeInfoCount(
149 IXMLDOMNodeList *iface,
150 UINT* pctinfo )
152 xmlnodelist *This = impl_from_IXMLDOMNodeList( iface );
153 return IDispatchEx_GetTypeInfoCount(&This->dispex.IDispatchEx_iface, pctinfo);
156 static HRESULT WINAPI xmlnodelist_GetTypeInfo(
157 IXMLDOMNodeList *iface,
158 UINT iTInfo,
159 LCID lcid,
160 ITypeInfo** ppTInfo )
162 xmlnodelist *This = impl_from_IXMLDOMNodeList( iface );
163 return IDispatchEx_GetTypeInfo(&This->dispex.IDispatchEx_iface,
164 iTInfo, lcid, ppTInfo);
167 static HRESULT WINAPI xmlnodelist_GetIDsOfNames(
168 IXMLDOMNodeList *iface,
169 REFIID riid,
170 LPOLESTR* rgszNames,
171 UINT cNames,
172 LCID lcid,
173 DISPID* rgDispId )
175 xmlnodelist *This = impl_from_IXMLDOMNodeList( iface );
176 return IDispatchEx_GetIDsOfNames(&This->dispex.IDispatchEx_iface,
177 riid, rgszNames, cNames, lcid, rgDispId);
180 static HRESULT WINAPI xmlnodelist_Invoke(
181 IXMLDOMNodeList *iface,
182 DISPID dispIdMember,
183 REFIID riid,
184 LCID lcid,
185 WORD wFlags,
186 DISPPARAMS* pDispParams,
187 VARIANT* pVarResult,
188 EXCEPINFO* pExcepInfo,
189 UINT* puArgErr )
191 xmlnodelist *This = impl_from_IXMLDOMNodeList( iface );
192 return IDispatchEx_Invoke(&This->dispex.IDispatchEx_iface,
193 dispIdMember, riid, lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
196 static HRESULT WINAPI xmlnodelist_get_item(
197 IXMLDOMNodeList* iface,
198 LONG index,
199 IXMLDOMNode** listItem)
201 xmlnodelist *This = impl_from_IXMLDOMNodeList( iface );
202 xmlNodePtr curr;
203 LONG nodeIndex = 0;
205 TRACE("(%p)->(%d %p)\n", This, index, listItem);
207 if(!listItem)
208 return E_INVALIDARG;
210 *listItem = NULL;
212 if (index < 0)
213 return S_FALSE;
215 curr = This->parent->children;
216 while(curr)
218 if(nodeIndex++ == index) break;
219 curr = curr->next;
221 if(!curr) return S_FALSE;
223 *listItem = create_node( curr );
225 return S_OK;
228 static HRESULT WINAPI xmlnodelist_get_length(
229 IXMLDOMNodeList* iface,
230 LONG* listLength)
233 xmlNodePtr curr;
234 LONG nodeCount = 0;
236 xmlnodelist *This = impl_from_IXMLDOMNodeList( iface );
238 TRACE("(%p)->(%p)\n", This, listLength);
240 if(!listLength)
241 return E_INVALIDARG;
243 curr = This->parent->children;
244 while (curr)
246 nodeCount++;
247 curr = curr->next;
250 *listLength = nodeCount;
251 return S_OK;
254 static HRESULT WINAPI xmlnodelist_nextNode(
255 IXMLDOMNodeList* iface,
256 IXMLDOMNode** nextItem)
258 xmlnodelist *This = impl_from_IXMLDOMNodeList( iface );
260 TRACE("(%p)->(%p)\n", This, nextItem );
262 if(!nextItem)
263 return E_INVALIDARG;
265 *nextItem = NULL;
267 if (!This->current)
268 return S_FALSE;
270 *nextItem = create_node( This->current );
271 This->current = This->current->next;
272 return S_OK;
275 static HRESULT WINAPI xmlnodelist_reset(
276 IXMLDOMNodeList* iface)
278 xmlnodelist *This = impl_from_IXMLDOMNodeList( iface );
280 TRACE("%p\n", This);
281 This->current = This->parent->children;
282 return S_OK;
285 static HRESULT WINAPI xmlnodelist__newEnum(
286 IXMLDOMNodeList* iface,
287 IUnknown** enumv)
289 xmlnodelist *This = impl_from_IXMLDOMNodeList( iface );
290 TRACE("(%p)->(%p)\n", This, enumv);
291 return create_enumvariant((IUnknown*)iface, TRUE, &nodelist_enumvariant, (IEnumVARIANT**)enumv);
294 static const struct IXMLDOMNodeListVtbl xmlnodelist_vtbl =
296 xmlnodelist_QueryInterface,
297 xmlnodelist_AddRef,
298 xmlnodelist_Release,
299 xmlnodelist_GetTypeInfoCount,
300 xmlnodelist_GetTypeInfo,
301 xmlnodelist_GetIDsOfNames,
302 xmlnodelist_Invoke,
303 xmlnodelist_get_item,
304 xmlnodelist_get_length,
305 xmlnodelist_nextNode,
306 xmlnodelist_reset,
307 xmlnodelist__newEnum,
310 static HRESULT xmlnodelist_get_dispid(IUnknown *iface, BSTR name, DWORD flags, DISPID *dispid)
312 WCHAR *ptr;
313 int idx = 0;
315 for(ptr = name; *ptr && isdigitW(*ptr); ptr++)
316 idx = idx*10 + (*ptr-'0');
317 if(*ptr)
318 return DISP_E_UNKNOWNNAME;
320 *dispid = DISPID_DOM_COLLECTION_BASE + idx;
321 TRACE("ret %x\n", *dispid);
322 return S_OK;
325 static HRESULT xmlnodelist_invoke(IUnknown *iface, DISPID id, LCID lcid, WORD flags, DISPPARAMS *params,
326 VARIANT *res, EXCEPINFO *ei)
328 xmlnodelist *This = impl_from_IXMLDOMNodeList( (IXMLDOMNodeList*)iface );
330 TRACE("(%p)->(%x %x %x %p %p %p)\n", This, id, lcid, flags, params, res, ei);
332 if (id >= DISPID_DOM_COLLECTION_BASE && id <= DISPID_DOM_COLLECTION_MAX)
334 switch(flags)
336 case DISPATCH_PROPERTYGET:
338 IXMLDOMNode *disp = NULL;
340 V_VT(res) = VT_DISPATCH;
341 IXMLDOMNodeList_get_item(&This->IXMLDOMNodeList_iface, id - DISPID_DOM_COLLECTION_BASE, &disp);
342 V_DISPATCH(res) = (IDispatch*)disp;
343 break;
345 default:
347 FIXME("unimplemented flags %x\n", flags);
348 break;
352 else if (id == DISPID_VALUE)
354 switch(flags)
356 case DISPATCH_METHOD|DISPATCH_PROPERTYGET:
357 case DISPATCH_PROPERTYGET:
358 case DISPATCH_METHOD:
360 IXMLDOMNode *item;
361 VARIANT index;
362 HRESULT hr;
364 if (params->cArgs - params->cNamedArgs != 1) return DISP_E_BADPARAMCOUNT;
366 VariantInit(&index);
367 hr = VariantChangeType(&index, params->rgvarg, 0, VT_I4);
368 if(FAILED(hr))
370 FIXME("failed to convert arg, %s\n", debugstr_variant(params->rgvarg));
371 return hr;
374 IXMLDOMNodeList_get_item(&This->IXMLDOMNodeList_iface, V_I4(&index), &item);
375 V_VT(res) = VT_DISPATCH;
376 V_DISPATCH(res) = (IDispatch*)item;
377 break;
379 default:
381 FIXME("DISPID_VALUE: unimplemented flags %x\n", flags);
382 break;
386 else
387 return DISP_E_UNKNOWNNAME;
389 TRACE("ret %p\n", V_DISPATCH(res));
391 return S_OK;
394 static const dispex_static_data_vtbl_t xmlnodelist_dispex_vtbl = {
395 xmlnodelist_get_dispid,
396 xmlnodelist_invoke
399 static const tid_t xmlnodelist_iface_tids[] = {
400 IXMLDOMNodeList_tid,
403 static dispex_static_data_t xmlnodelist_dispex = {
404 &xmlnodelist_dispex_vtbl,
405 IXMLDOMNodeList_tid,
406 NULL,
407 xmlnodelist_iface_tids
410 IXMLDOMNodeList* create_children_nodelist( xmlNodePtr node )
412 xmlnodelist *This;
414 This = heap_alloc( sizeof *This );
415 if ( !This )
416 return NULL;
418 This->IXMLDOMNodeList_iface.lpVtbl = &xmlnodelist_vtbl;
419 This->ref = 1;
420 This->parent = node;
421 This->current = node->children;
422 This->enumvariant = NULL;
423 xmldoc_add_ref( node->doc );
425 init_dispex(&This->dispex, (IUnknown*)&This->IXMLDOMNodeList_iface, &xmlnodelist_dispex);
427 return &This->IXMLDOMNodeList_iface;
430 #endif