Bug 460926 A11y hierachy is broken on Ubuntu 8.10 (GNOME 2.24), r=Evan.Yan sr=roc
[wine-gecko.git] / rdf / base / src / nsContainerEnumerator.cpp
blobba4dceeb42cda2707e64b09cdb31c30af6d3dab0
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /* ***** BEGIN LICENSE BLOCK *****
3 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 * The contents of this file are subject to the Mozilla Public License Version
6 * 1.1 (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 * http://www.mozilla.org/MPL/
10 * Software distributed under the License is distributed on an "AS IS" basis,
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 * for the specific language governing rights and limitations under the
13 * License.
15 * The Original Code is mozilla.org code.
17 * The Initial Developer of the Original Code is
18 * Netscape Communications Corporation.
19 * Portions created by the Initial Developer are Copyright (C) 1998
20 * the Initial Developer. All Rights Reserved.
22 * Contributor(s):
23 * Pierre Phaneuf <pp@ludusdesign.com>
25 * Alternatively, the contents of this file may be used under the terms of
26 * either of the GNU General Public License Version 2 or later (the "GPL"),
27 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28 * in which case the provisions of the GPL or the LGPL are applicable instead
29 * of those above. If you wish to allow use of your version of this file only
30 * under the terms of either the GPL or the LGPL, and not to allow others to
31 * use your version of this file under the terms of the MPL, indicate your
32 * decision by deleting the provisions above and replace them with the notice
33 * and other provisions required by the GPL or the LGPL. If you do not delete
34 * the provisions above, a recipient may use your version of this file under
35 * the terms of any one of the MPL, the GPL or the LGPL.
37 * ***** END LICENSE BLOCK ***** */
41 A simple cursor that enumerates the elements of an RDF container
42 (RDF:Bag, RDF:Seq, or RDF:Alt).
44 Caveats
45 -------
47 1. This uses an implementation-specific detail to determine the
48 index of the last element in the container; specifically, the RDF
49 utilities maintain a counter attribute on the container that
50 holds the numeric value of the next value that is to be
51 assigned. So, this cursor will bust if you use it with a bag that
52 hasn't been created using the RDF utility routines.
56 #include "nscore.h"
57 #include "nsCOMPtr.h"
58 #include "nsIRDFContainerUtils.h"
59 #include "nsIRDFDataSource.h"
60 #include "nsIRDFNode.h"
61 #include "nsIRDFService.h"
62 #include "nsIServiceManager.h"
63 #include "nsRDFCID.h"
64 #include "nsString.h"
65 #include "nsXPIDLString.h"
66 #include "prlog.h"
67 #include "rdf.h"
68 #include "rdfutil.h"
70 ////////////////////////////////////////////////////////////////////////
72 static NS_DEFINE_CID(kRDFServiceCID, NS_RDFSERVICE_CID);
73 static NS_DEFINE_CID(kRDFContainerUtilsCID, NS_RDFCONTAINERUTILS_CID);
75 ////////////////////////////////////////////////////////////////////////
77 class ContainerEnumeratorImpl : public nsISimpleEnumerator {
78 private:
79 // pseudo-constants
80 static nsrefcnt gRefCnt;
81 static nsIRDFResource* kRDF_nextVal;
82 static nsIRDFContainerUtils* gRDFC;
84 nsCOMPtr<nsIRDFDataSource> mDataSource;
85 nsCOMPtr<nsIRDFResource> mContainer;
86 nsCOMPtr<nsIRDFResource> mOrdinalProperty;
88 nsCOMPtr<nsISimpleEnumerator> mCurrent;
89 nsCOMPtr<nsIRDFNode> mResult;
90 PRInt32 mNextIndex;
92 public:
93 ContainerEnumeratorImpl(nsIRDFDataSource* ds, nsIRDFResource* container);
94 virtual ~ContainerEnumeratorImpl();
96 nsresult Init();
98 NS_DECL_ISUPPORTS
99 NS_DECL_NSISIMPLEENUMERATOR
102 nsrefcnt ContainerEnumeratorImpl::gRefCnt;
103 nsIRDFResource* ContainerEnumeratorImpl::kRDF_nextVal;
104 nsIRDFContainerUtils* ContainerEnumeratorImpl::gRDFC;
107 ContainerEnumeratorImpl::ContainerEnumeratorImpl(nsIRDFDataSource* aDataSource,
108 nsIRDFResource* aContainer)
109 : mDataSource(aDataSource),
110 mContainer(aContainer),
111 mNextIndex(1)
115 nsresult
116 ContainerEnumeratorImpl::Init()
118 if (gRefCnt++ == 0) {
119 nsresult rv;
120 nsCOMPtr<nsIRDFService> rdf = do_GetService(kRDFServiceCID);
121 NS_ASSERTION(rdf != nsnull, "unable to acquire resource manager");
122 if (! rdf)
123 return NS_ERROR_FAILURE;
125 rv = rdf->GetResource(NS_LITERAL_CSTRING(RDF_NAMESPACE_URI "nextVal"), &kRDF_nextVal);
126 NS_ASSERTION(NS_SUCCEEDED(rv), "unable to get resource");
127 if (NS_FAILED(rv)) return rv;
129 rv = CallGetService(kRDFContainerUtilsCID, &gRDFC);
130 if (NS_FAILED(rv)) return rv;
133 return NS_OK;
137 ContainerEnumeratorImpl::~ContainerEnumeratorImpl()
139 if (--gRefCnt == 0) {
140 NS_IF_RELEASE(kRDF_nextVal);
141 NS_IF_RELEASE(gRDFC);
145 NS_IMPL_ISUPPORTS1(ContainerEnumeratorImpl, nsISimpleEnumerator)
148 NS_IMETHODIMP
149 ContainerEnumeratorImpl::HasMoreElements(PRBool* aResult)
151 NS_PRECONDITION(aResult != nsnull, "null ptr");
152 if (! aResult)
153 return NS_ERROR_NULL_POINTER;
155 nsresult rv;
157 // If we've already queued up a next value, then we know there are more elements.
158 if (mResult) {
159 *aResult = PR_TRUE;
160 return NS_OK;
163 // Otherwise, we need to grovel
165 // Figure out the upper bound so we'll know when we're done. Since it's
166 // possible that we're targeting a composite datasource, we'll need to
167 // "GetTargets()" and take the maximum value of "nextVal" to know the
168 // upper bound.
170 // Remember that since nextVal is the next index that we'd assign
171 // to an element in a container, it's *one more* than count of
172 // elements in the container.
173 PRInt32 max = 0;
175 nsCOMPtr<nsISimpleEnumerator> targets;
176 rv = mDataSource->GetTargets(mContainer, kRDF_nextVal, PR_TRUE, getter_AddRefs(targets));
177 if (NS_FAILED(rv)) return rv;
179 while (1) {
180 PRBool hasmore;
181 targets->HasMoreElements(&hasmore);
182 if (! hasmore)
183 break;
185 nsCOMPtr<nsISupports> isupports;
186 targets->GetNext(getter_AddRefs(isupports));
188 nsCOMPtr<nsIRDFLiteral> nextValLiteral = do_QueryInterface(isupports);
189 if (! nextValLiteral)
190 continue;
192 const PRUnichar *nextValStr;
193 nextValLiteral->GetValueConst(&nextValStr);
195 PRInt32 err;
196 PRInt32 nextVal = nsAutoString(nextValStr).ToInteger(&err);
198 if (nextVal > max)
199 max = nextVal;
202 // Now pre-fetch our next value into mResult.
203 while (mCurrent || mNextIndex < max) {
205 // If mCurrent has been depleted, then conjure up a new one
206 if (! mCurrent) {
207 rv = gRDFC->IndexToOrdinalResource(mNextIndex, getter_AddRefs(mOrdinalProperty));
208 if (NS_FAILED(rv)) return rv;
210 rv = mDataSource->GetTargets(mContainer, mOrdinalProperty, PR_TRUE, getter_AddRefs(mCurrent));
211 if (NS_FAILED(rv)) return rv;
213 ++mNextIndex;
216 if (mCurrent) {
217 PRBool hasMore;
218 rv = mCurrent->HasMoreElements(&hasMore);
219 if (NS_FAILED(rv)) return rv;
221 // Is the current enumerator depleted? If so, iterate to
222 // the next index.
223 if (! hasMore) {
224 mCurrent = nsnull;
225 continue;
228 // "Peek" ahead and pull out the next target.
229 nsCOMPtr<nsISupports> result;
230 rv = mCurrent->GetNext(getter_AddRefs(result));
231 if (NS_FAILED(rv)) return rv;
233 mResult = do_QueryInterface(result, &rv);
234 if (NS_FAILED(rv)) return rv;
236 *aResult = PR_TRUE;
237 return NS_OK;
241 // If we get here, we ran out of elements. The cursor is empty.
242 *aResult = PR_FALSE;
243 return NS_OK;
247 NS_IMETHODIMP
248 ContainerEnumeratorImpl::GetNext(nsISupports** aResult)
250 nsresult rv;
252 PRBool hasMore;
253 rv = HasMoreElements(&hasMore);
254 if (NS_FAILED(rv)) return rv;
256 if (! hasMore)
257 return NS_ERROR_UNEXPECTED;
259 NS_ADDREF(*aResult = mResult);
260 mResult = nsnull;
262 return NS_OK;
266 ////////////////////////////////////////////////////////////////////////
268 nsresult
269 NS_NewContainerEnumerator(nsIRDFDataSource* aDataSource,
270 nsIRDFResource* aContainer,
271 nsISimpleEnumerator** aResult)
273 NS_PRECONDITION(aDataSource != nsnull, "null ptr");
274 if (! aDataSource)
275 return NS_ERROR_NULL_POINTER;
277 NS_PRECONDITION(aContainer != nsnull, "null ptr");
278 if (! aContainer)
279 return NS_ERROR_NULL_POINTER;
281 NS_PRECONDITION(aResult != nsnull, "null ptr");
282 if (! aResult)
283 return NS_ERROR_NULL_POINTER;
285 ContainerEnumeratorImpl* result = new ContainerEnumeratorImpl(aDataSource, aContainer);
286 if (! result)
287 return NS_ERROR_OUT_OF_MEMORY;
289 NS_ADDREF(result);
291 nsresult rv = result->Init();
292 if (NS_FAILED(rv))
293 NS_RELEASE(result);
295 *aResult = result;
296 return rv;