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
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.
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).
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.
58 #include "nsIRDFContainerUtils.h"
59 #include "nsIRDFDataSource.h"
60 #include "nsIRDFNode.h"
61 #include "nsIRDFService.h"
62 #include "nsIServiceManager.h"
65 #include "nsXPIDLString.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
{
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
;
93 ContainerEnumeratorImpl(nsIRDFDataSource
* ds
, nsIRDFResource
* container
);
94 virtual ~ContainerEnumeratorImpl();
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
),
116 ContainerEnumeratorImpl::Init()
118 if (gRefCnt
++ == 0) {
120 nsCOMPtr
<nsIRDFService
> rdf
= do_GetService(kRDFServiceCID
);
121 NS_ASSERTION(rdf
!= nsnull
, "unable to acquire resource manager");
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
;
137 ContainerEnumeratorImpl::~ContainerEnumeratorImpl()
139 if (--gRefCnt
== 0) {
140 NS_IF_RELEASE(kRDF_nextVal
);
141 NS_IF_RELEASE(gRDFC
);
145 NS_IMPL_ISUPPORTS1(ContainerEnumeratorImpl
, nsISimpleEnumerator
)
149 ContainerEnumeratorImpl::HasMoreElements(PRBool
* aResult
)
151 NS_PRECONDITION(aResult
!= nsnull
, "null ptr");
153 return NS_ERROR_NULL_POINTER
;
157 // If we've already queued up a next value, then we know there are more elements.
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
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.
175 nsCOMPtr
<nsISimpleEnumerator
> targets
;
176 rv
= mDataSource
->GetTargets(mContainer
, kRDF_nextVal
, PR_TRUE
, getter_AddRefs(targets
));
177 if (NS_FAILED(rv
)) return rv
;
181 targets
->HasMoreElements(&hasmore
);
185 nsCOMPtr
<nsISupports
> isupports
;
186 targets
->GetNext(getter_AddRefs(isupports
));
188 nsCOMPtr
<nsIRDFLiteral
> nextValLiteral
= do_QueryInterface(isupports
);
189 if (! nextValLiteral
)
192 const PRUnichar
*nextValStr
;
193 nextValLiteral
->GetValueConst(&nextValStr
);
196 PRInt32 nextVal
= nsAutoString(nextValStr
).ToInteger(&err
);
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
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
;
218 rv
= mCurrent
->HasMoreElements(&hasMore
);
219 if (NS_FAILED(rv
)) return rv
;
221 // Is the current enumerator depleted? If so, iterate to
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
;
241 // If we get here, we ran out of elements. The cursor is empty.
248 ContainerEnumeratorImpl::GetNext(nsISupports
** aResult
)
253 rv
= HasMoreElements(&hasMore
);
254 if (NS_FAILED(rv
)) return rv
;
257 return NS_ERROR_UNEXPECTED
;
259 NS_ADDREF(*aResult
= mResult
);
266 ////////////////////////////////////////////////////////////////////////
269 NS_NewContainerEnumerator(nsIRDFDataSource
* aDataSource
,
270 nsIRDFResource
* aContainer
,
271 nsISimpleEnumerator
** aResult
)
273 NS_PRECONDITION(aDataSource
!= nsnull
, "null ptr");
275 return NS_ERROR_NULL_POINTER
;
277 NS_PRECONDITION(aContainer
!= nsnull
, "null ptr");
279 return NS_ERROR_NULL_POINTER
;
281 NS_PRECONDITION(aResult
!= nsnull
, "null ptr");
283 return NS_ERROR_NULL_POINTER
;
285 ContainerEnumeratorImpl
* result
= new ContainerEnumeratorImpl(aDataSource
, aContainer
);
287 return NS_ERROR_OUT_OF_MEMORY
;
291 nsresult rv
= result
->Init();