Bug 460926 A11y hierachy is broken on Ubuntu 8.10 (GNOME 2.24), r=Evan.Yan sr=roc
[wine-gecko.git] / rdf / base / src / nsRDFContainerUtils.cpp
blob6efb79aa90626f0fd98b79549c6994108efccf1f
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 Communicator client 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 Implementation for the RDF container utils.
46 #include "nsCOMPtr.h"
47 #include "nsIServiceManager.h"
48 #include "nsIRDFContainer.h"
49 #include "nsIRDFContainerUtils.h"
50 #include "nsIRDFService.h"
51 #include "nsRDFCID.h"
52 #include "nsString.h"
53 #include "nsXPIDLString.h"
54 #include "plstr.h"
55 #include "prprf.h"
56 #include "rdf.h"
57 #include "rdfutil.h"
59 static NS_DEFINE_CID(kRDFServiceCID, NS_RDFSERVICE_CID);
60 static const char kRDFNameSpaceURI[] = RDF_NAMESPACE_URI;
62 class RDFContainerUtilsImpl : public nsIRDFContainerUtils
64 public:
65 // nsISupports interface
66 NS_DECL_ISUPPORTS
68 // nsIRDFContainerUtils interface
69 NS_DECL_NSIRDFCONTAINERUTILS
71 private:
72 friend nsresult NS_NewRDFContainerUtils(nsIRDFContainerUtils** aResult);
74 RDFContainerUtilsImpl();
75 virtual ~RDFContainerUtilsImpl();
77 nsresult MakeContainer(nsIRDFDataSource* aDataSource,
78 nsIRDFResource* aResource,
79 nsIRDFResource* aType,
80 nsIRDFContainer** aResult);
82 PRBool IsA(nsIRDFDataSource* aDataSource, nsIRDFResource* aResource, nsIRDFResource* aType);
84 // pseudo constants
85 static PRInt32 gRefCnt;
86 static nsIRDFService* gRDFService;
87 static nsIRDFResource* kRDF_instanceOf;
88 static nsIRDFResource* kRDF_nextVal;
89 static nsIRDFResource* kRDF_Bag;
90 static nsIRDFResource* kRDF_Seq;
91 static nsIRDFResource* kRDF_Alt;
92 static nsIRDFLiteral* kOne;
96 PRInt32 RDFContainerUtilsImpl::gRefCnt = 0;
97 nsIRDFService* RDFContainerUtilsImpl::gRDFService;
98 nsIRDFResource* RDFContainerUtilsImpl::kRDF_instanceOf;
99 nsIRDFResource* RDFContainerUtilsImpl::kRDF_nextVal;
100 nsIRDFResource* RDFContainerUtilsImpl::kRDF_Bag;
101 nsIRDFResource* RDFContainerUtilsImpl::kRDF_Seq;
102 nsIRDFResource* RDFContainerUtilsImpl::kRDF_Alt;
103 nsIRDFLiteral* RDFContainerUtilsImpl::kOne;
105 ////////////////////////////////////////////////////////////////////////
106 // nsISupports interface
108 NS_IMPL_THREADSAFE_ISUPPORTS1(RDFContainerUtilsImpl, nsIRDFContainerUtils)
110 ////////////////////////////////////////////////////////////////////////
111 // nsIRDFContainerUtils interface
113 NS_IMETHODIMP
114 RDFContainerUtilsImpl::IsOrdinalProperty(nsIRDFResource *aProperty, PRBool *_retval)
116 NS_PRECONDITION(aProperty != nsnull, "null ptr");
117 if (! aProperty)
118 return NS_ERROR_NULL_POINTER;
120 nsresult rv;
122 const char *propertyStr;
123 rv = aProperty->GetValueConst( &propertyStr );
124 if (NS_FAILED(rv)) return rv;
126 if (PL_strncmp(propertyStr, kRDFNameSpaceURI, sizeof(kRDFNameSpaceURI) - 1) != 0) {
127 *_retval = PR_FALSE;
128 return NS_OK;
131 const char* s = propertyStr;
132 s += sizeof(kRDFNameSpaceURI) - 1;
133 if (*s != '_') {
134 *_retval = PR_FALSE;
135 return NS_OK;
138 ++s;
139 while (*s) {
140 if (*s < '0' || *s > '9') {
141 *_retval = PR_FALSE;
142 return NS_OK;
145 ++s;
148 *_retval = PR_TRUE;
149 return NS_OK;
153 NS_IMETHODIMP
154 RDFContainerUtilsImpl::IndexToOrdinalResource(PRInt32 aIndex, nsIRDFResource **aOrdinal)
156 NS_PRECONDITION(aIndex > 0, "illegal value");
157 if (aIndex <= 0)
158 return NS_ERROR_ILLEGAL_VALUE;
160 nsCAutoString uri(kRDFNameSpaceURI);
161 uri.Append('_');
162 uri.AppendInt(aIndex);
164 nsresult rv = gRDFService->GetResource(uri, aOrdinal);
165 NS_ASSERTION(NS_SUCCEEDED(rv), "unable to get ordinal resource");
166 if (NS_FAILED(rv)) return rv;
168 return NS_OK;
172 NS_IMETHODIMP
173 RDFContainerUtilsImpl::OrdinalResourceToIndex(nsIRDFResource *aOrdinal, PRInt32 *aIndex)
175 NS_PRECONDITION(aOrdinal != nsnull, "null ptr");
176 if (! aOrdinal)
177 return NS_ERROR_NULL_POINTER;
179 const char *ordinalStr;
180 if (NS_FAILED(aOrdinal->GetValueConst( &ordinalStr )))
181 return NS_ERROR_FAILURE;
183 const char* s = ordinalStr;
184 if (PL_strncmp(s, kRDFNameSpaceURI, sizeof(kRDFNameSpaceURI) - 1) != 0) {
185 NS_ERROR("not an ordinal");
186 return NS_ERROR_UNEXPECTED;
189 s += sizeof(kRDFNameSpaceURI) - 1;
190 if (*s != '_') {
191 NS_ERROR("not an ordinal");
192 return NS_ERROR_UNEXPECTED;
195 PRInt32 idx = 0;
197 ++s;
198 while (*s) {
199 if (*s < '0' || *s > '9') {
200 NS_ERROR("not an ordinal");
201 return NS_ERROR_UNEXPECTED;
204 idx *= 10;
205 idx += (*s - '0');
207 ++s;
210 *aIndex = idx;
211 return NS_OK;
214 NS_IMETHODIMP
215 RDFContainerUtilsImpl::IsContainer(nsIRDFDataSource *aDataSource, nsIRDFResource *aResource, PRBool *_retval)
217 NS_PRECONDITION(aDataSource != nsnull, "null ptr");
218 if (! aDataSource)
219 return NS_ERROR_NULL_POINTER;
221 NS_PRECONDITION(aResource != nsnull, "null ptr");
222 if (! aResource)
223 return NS_ERROR_NULL_POINTER;
225 NS_PRECONDITION(_retval != nsnull, "null ptr");
226 if (! _retval)
227 return NS_ERROR_NULL_POINTER;
229 if (IsA(aDataSource, aResource, kRDF_Seq) ||
230 IsA(aDataSource, aResource, kRDF_Bag) ||
231 IsA(aDataSource, aResource, kRDF_Alt)) {
232 *_retval = PR_TRUE;
234 else {
235 *_retval = PR_FALSE;
237 return NS_OK;
241 NS_IMETHODIMP
242 RDFContainerUtilsImpl::IsEmpty(nsIRDFDataSource* aDataSource, nsIRDFResource* aResource, PRBool* _retval)
244 if (! aDataSource)
245 return NS_ERROR_NULL_POINTER;
247 nsresult rv;
249 // By default, say that we're an empty container. Even if we're not
250 // really even a container.
251 *_retval = PR_TRUE;
253 nsCOMPtr<nsIRDFNode> nextValNode;
254 rv = aDataSource->GetTarget(aResource, kRDF_nextVal, PR_TRUE, getter_AddRefs(nextValNode));
255 if (NS_FAILED(rv)) return rv;
257 if (rv == NS_RDF_NO_VALUE)
258 return NS_OK;
260 nsCOMPtr<nsIRDFLiteral> nextValLiteral;
261 rv = nextValNode->QueryInterface(NS_GET_IID(nsIRDFLiteral), getter_AddRefs(nextValLiteral));
262 if (NS_FAILED(rv)) return rv;
264 if (nextValLiteral.get() != kOne)
265 *_retval = PR_FALSE;
267 return NS_OK;
271 NS_IMETHODIMP
272 RDFContainerUtilsImpl::IsBag(nsIRDFDataSource *aDataSource, nsIRDFResource *aResource, PRBool *_retval)
274 NS_PRECONDITION(aDataSource != nsnull, "null ptr");
275 if (! aDataSource)
276 return NS_ERROR_NULL_POINTER;
278 NS_PRECONDITION(aResource != nsnull, "null ptr");
279 if (! aResource)
280 return NS_ERROR_NULL_POINTER;
282 NS_PRECONDITION(_retval != nsnull, "null ptr");
283 if (! _retval)
284 return NS_ERROR_NULL_POINTER;
286 *_retval = IsA(aDataSource, aResource, kRDF_Bag);
287 return NS_OK;
291 NS_IMETHODIMP
292 RDFContainerUtilsImpl::IsSeq(nsIRDFDataSource *aDataSource, nsIRDFResource *aResource, PRBool *_retval)
294 NS_PRECONDITION(aDataSource != nsnull, "null ptr");
295 if (! aDataSource)
296 return NS_ERROR_NULL_POINTER;
298 NS_PRECONDITION(aResource != nsnull, "null ptr");
299 if (! aResource)
300 return NS_ERROR_NULL_POINTER;
302 NS_PRECONDITION(_retval != nsnull, "null ptr");
303 if (! _retval)
304 return NS_ERROR_NULL_POINTER;
306 *_retval = IsA(aDataSource, aResource, kRDF_Seq);
307 return NS_OK;
311 NS_IMETHODIMP
312 RDFContainerUtilsImpl::IsAlt(nsIRDFDataSource *aDataSource, nsIRDFResource *aResource, PRBool *_retval)
314 NS_PRECONDITION(aDataSource != nsnull, "null ptr");
315 if (! aDataSource)
316 return NS_ERROR_NULL_POINTER;
318 NS_PRECONDITION(aResource != nsnull, "null ptr");
319 if (! aResource)
320 return NS_ERROR_NULL_POINTER;
322 NS_PRECONDITION(_retval != nsnull, "null ptr");
323 if (! _retval)
324 return NS_ERROR_NULL_POINTER;
326 *_retval = IsA(aDataSource, aResource, kRDF_Alt);
327 return NS_OK;
331 NS_IMETHODIMP
332 RDFContainerUtilsImpl::MakeBag(nsIRDFDataSource *aDataSource, nsIRDFResource *aResource, nsIRDFContainer **_retval)
334 return MakeContainer(aDataSource, aResource, kRDF_Bag, _retval);
338 NS_IMETHODIMP
339 RDFContainerUtilsImpl::MakeSeq(nsIRDFDataSource *aDataSource, nsIRDFResource *aResource, nsIRDFContainer **_retval)
341 return MakeContainer(aDataSource, aResource, kRDF_Seq, _retval);
345 NS_IMETHODIMP
346 RDFContainerUtilsImpl::MakeAlt(nsIRDFDataSource *aDataSource, nsIRDFResource *aResource, nsIRDFContainer **_retval)
348 return MakeContainer(aDataSource, aResource, kRDF_Alt, _retval);
353 ////////////////////////////////////////////////////////////////////////
356 RDFContainerUtilsImpl::RDFContainerUtilsImpl()
358 if (gRefCnt++ == 0) {
359 nsresult rv;
361 rv = CallGetService(kRDFServiceCID, &gRDFService);
363 NS_ASSERTION(NS_SUCCEEDED(rv), "unable to get RDF service");
364 if (NS_SUCCEEDED(rv)) {
365 gRDFService->GetResource(NS_LITERAL_CSTRING(RDF_NAMESPACE_URI "instanceOf"),
366 &kRDF_instanceOf);
367 gRDFService->GetResource(NS_LITERAL_CSTRING(RDF_NAMESPACE_URI "nextVal"),
368 &kRDF_nextVal);
369 gRDFService->GetResource(NS_LITERAL_CSTRING(RDF_NAMESPACE_URI "Bag"),
370 &kRDF_Bag);
371 gRDFService->GetResource(NS_LITERAL_CSTRING(RDF_NAMESPACE_URI "Seq"),
372 &kRDF_Seq);
373 gRDFService->GetResource(NS_LITERAL_CSTRING(RDF_NAMESPACE_URI "Alt"),
374 &kRDF_Alt);
375 gRDFService->GetLiteral(NS_LITERAL_STRING("1").get(), &kOne);
381 RDFContainerUtilsImpl::~RDFContainerUtilsImpl()
383 #ifdef DEBUG_REFS
384 --gInstanceCount;
385 fprintf(stdout, "%d - RDF: RDFContainerUtilsImpl\n", gInstanceCount);
386 #endif
388 if (--gRefCnt == 0) {
389 NS_IF_RELEASE(gRDFService);
390 NS_IF_RELEASE(kRDF_instanceOf);
391 NS_IF_RELEASE(kRDF_nextVal);
392 NS_IF_RELEASE(kRDF_Bag);
393 NS_IF_RELEASE(kRDF_Seq);
394 NS_IF_RELEASE(kRDF_Alt);
395 NS_IF_RELEASE(kOne);
401 nsresult
402 NS_NewRDFContainerUtils(nsIRDFContainerUtils** aResult)
404 NS_PRECONDITION(aResult != nsnull, "null ptr");
405 if (! aResult)
406 return NS_ERROR_NULL_POINTER;
408 RDFContainerUtilsImpl* result =
409 new RDFContainerUtilsImpl();
411 if (! result)
412 return NS_ERROR_OUT_OF_MEMORY;
414 NS_ADDREF(result);
415 *aResult = result;
416 return NS_OK;
420 nsresult
421 RDFContainerUtilsImpl::MakeContainer(nsIRDFDataSource* aDataSource, nsIRDFResource* aResource, nsIRDFResource* aType, nsIRDFContainer** aResult)
423 NS_PRECONDITION(aDataSource != nsnull, "null ptr");
424 if (! aDataSource) return NS_ERROR_NULL_POINTER;
426 NS_PRECONDITION(aResource != nsnull, "null ptr");
427 if (! aResource) return NS_ERROR_NULL_POINTER;
429 NS_PRECONDITION(aType != nsnull, "null ptr");
430 if (! aType) return NS_ERROR_NULL_POINTER;
432 if (aResult) *aResult = nsnull;
434 nsresult rv;
436 // Check to see if somebody has already turned it into a container; if so
437 // don't try to do it again.
438 PRBool isContainer;
439 rv = IsContainer(aDataSource, aResource, &isContainer);
440 if (NS_FAILED(rv)) return rv;
442 if (isContainer == PR_FALSE)
444 rv = aDataSource->Assert(aResource, kRDF_instanceOf, aType, PR_TRUE);
445 if (NS_FAILED(rv)) return rv;
447 rv = aDataSource->Assert(aResource, kRDF_nextVal, kOne, PR_TRUE);
448 if (NS_FAILED(rv)) return rv;
451 if (aResult) {
452 rv = NS_NewRDFContainer(aResult);
453 if (NS_FAILED(rv)) return rv;
455 rv = (*aResult)->Init(aDataSource, aResource);
456 if (NS_FAILED(rv)) return rv;
459 return NS_OK;
462 PRBool
463 RDFContainerUtilsImpl::IsA(nsIRDFDataSource* aDataSource, nsIRDFResource* aResource, nsIRDFResource* aType)
465 if (!aDataSource || !aResource || !aType)
466 return NS_ERROR_NULL_POINTER;
468 nsresult rv;
470 PRBool result;
471 rv = aDataSource->HasAssertion(aResource, kRDF_instanceOf, aType, PR_TRUE, &result);
472 if (NS_FAILED(rv)) return PR_FALSE;
474 return result;
477 NS_IMETHODIMP
478 RDFContainerUtilsImpl::IndexOf(nsIRDFDataSource* aDataSource, nsIRDFResource* aContainer, nsIRDFNode* aElement, PRInt32* aIndex)
480 if (!aDataSource || !aContainer)
481 return NS_ERROR_NULL_POINTER;
483 // Assume we can't find it.
484 *aIndex = -1;
486 // If the resource is null, bail quietly
487 if (! aElement)
488 return NS_OK;
490 // We'll assume that fan-out is much higher than fan-in, so grovel
491 // through the inbound arcs, look for an ordinal resource, and
492 // decode it.
493 nsCOMPtr<nsISimpleEnumerator> arcsIn;
494 aDataSource->ArcLabelsIn(aElement, getter_AddRefs(arcsIn));
495 if (! arcsIn)
496 return NS_OK;
498 while (1) {
499 PRBool hasMoreArcs = PR_FALSE;
500 arcsIn->HasMoreElements(&hasMoreArcs);
501 if (! hasMoreArcs)
502 break;
504 nsCOMPtr<nsISupports> isupports;
505 arcsIn->GetNext(getter_AddRefs(isupports));
506 if (! isupports)
507 break;
509 nsCOMPtr<nsIRDFResource> property =
510 do_QueryInterface(isupports);
512 if (! property)
513 continue;
515 PRBool isOrdinal;
516 IsOrdinalProperty(property, &isOrdinal);
517 if (! isOrdinal)
518 continue;
520 nsCOMPtr<nsISimpleEnumerator> sources;
521 aDataSource->GetSources(property, aElement, PR_TRUE, getter_AddRefs(sources));
522 if (! sources)
523 continue;
525 while (1) {
526 PRBool hasMoreSources = PR_FALSE;
527 sources->HasMoreElements(&hasMoreSources);
528 if (! hasMoreSources)
529 break;
531 nsCOMPtr<nsISupports> isupports2;
532 sources->GetNext(getter_AddRefs(isupports2));
533 if (! isupports2)
534 break;
536 nsCOMPtr<nsIRDFResource> source =
537 do_QueryInterface(isupports2);
539 if (source == aContainer)
540 // Found it.
541 return OrdinalResourceToIndex(property, aIndex);
545 return NS_OK;