Bug 470455 - test_database_sync_embed_visits.js leaks, r=sdwilsh
[wine-gecko.git] / content / xul / templates / src / nsRDFConMemberTestNode.cpp
blob634966857c312136c18018e2676d1c8f760ed853
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 * Chris Waterson <waterson@netscape.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 ***** */
39 #include "nsRDFConMemberTestNode.h"
40 #include "nsIRDFContainer.h"
41 #include "nsIRDFContainerUtils.h"
42 #include "nsRDFCID.h"
43 #include "nsIServiceManager.h"
44 #include "nsResourceSet.h"
45 #include "nsString.h"
47 #include "prlog.h"
48 #ifdef PR_LOGGING
49 #include "nsXULContentUtils.h"
50 extern PRLogModuleInfo* gXULTemplateLog;
51 #endif
53 nsRDFConMemberTestNode::nsRDFConMemberTestNode(TestNode* aParent,
54 nsXULTemplateQueryProcessorRDF* aProcessor,
55 nsIAtom *aContainerVariable,
56 nsIAtom *aMemberVariable)
57 : nsRDFTestNode(aParent),
58 mProcessor(aProcessor),
59 mContainerVariable(aContainerVariable),
60 mMemberVariable(aMemberVariable)
62 #ifdef PR_LOGGING
63 if (PR_LOG_TEST(gXULTemplateLog, PR_LOG_DEBUG)) {
64 nsCAutoString props;
66 nsResourceSet& containmentProps = aProcessor->ContainmentProperties();
67 nsResourceSet::ConstIterator last = containmentProps.Last();
68 nsResourceSet::ConstIterator first = containmentProps.First();
69 nsResourceSet::ConstIterator iter;
71 for (iter = first; iter != last; ++iter) {
72 if (iter != first)
73 props += " ";
75 const char* str;
76 iter->GetValueConst(&str);
78 props += str;
81 nsAutoString cvar(NS_LITERAL_STRING("(none)"));
82 if (mContainerVariable)
83 mContainerVariable->ToString(cvar);
85 nsAutoString mvar(NS_LITERAL_STRING("(none)"));
86 if (mMemberVariable)
87 mMemberVariable->ToString(mvar);
89 PR_LOG(gXULTemplateLog, PR_LOG_DEBUG,
90 ("nsRDFConMemberTestNode[%p]: parent=%p member-props=(%s) container-var=%s member-var=%s",
91 this,
92 aParent,
93 props.get(),
94 NS_ConvertUTF16toUTF8(cvar).get(),
95 NS_ConvertUTF16toUTF8(mvar).get()));
97 #endif
100 nsresult
101 nsRDFConMemberTestNode::FilterInstantiations(InstantiationSet& aInstantiations,
102 PRBool* aCantHandleYet) const
104 // XXX Uh, factor me, please!
105 nsresult rv;
107 if (aCantHandleYet)
108 *aCantHandleYet = PR_FALSE;
110 nsCOMPtr<nsIRDFContainerUtils> rdfc =
111 do_GetService("@mozilla.org/rdf/container-utils;1");
113 if (! rdfc)
114 return NS_ERROR_FAILURE;
116 nsIRDFDataSource* ds = mProcessor->GetDataSource();
118 InstantiationSet::Iterator last = aInstantiations.Last();
119 for (InstantiationSet::Iterator inst = aInstantiations.First(); inst != last; ++inst) {
120 PRBool hasContainerBinding;
121 nsCOMPtr<nsIRDFNode> containerValue;
122 hasContainerBinding = inst->mAssignments.GetAssignmentFor(mContainerVariable,
123 getter_AddRefs(containerValue));
125 nsCOMPtr<nsIRDFResource> containerRes = do_QueryInterface(containerValue);
127 nsCOMPtr<nsIRDFContainer> rdfcontainer;
129 if (hasContainerBinding && containerRes) {
130 // If we have a container assignment, then see if the
131 // container is an RDF container (bag, seq, alt), and if
132 // so, wrap it.
133 PRBool isRDFContainer;
134 rv = rdfc->IsContainer(ds, containerRes, &isRDFContainer);
135 if (NS_FAILED(rv)) return rv;
137 if (isRDFContainer) {
138 rdfcontainer = do_CreateInstance("@mozilla.org/rdf/container;1", &rv);
139 if (NS_FAILED(rv)) return rv;
141 rv = rdfcontainer->Init(ds, containerRes);
142 if (NS_FAILED(rv)) return rv;
146 PRBool hasMemberBinding;
147 nsCOMPtr<nsIRDFNode> memberValue;
148 hasMemberBinding = inst->mAssignments.GetAssignmentFor(mMemberVariable,
149 getter_AddRefs(memberValue));
151 #ifdef PR_LOGGING
152 if (PR_LOG_TEST(gXULTemplateLog, PR_LOG_DEBUG)) {
153 const char* container = "(unbound)";
154 if (hasContainerBinding)
155 containerRes->GetValueConst(&container);
157 nsAutoString member(NS_LITERAL_STRING("(unbound)"));
158 if (hasMemberBinding)
159 nsXULContentUtils::GetTextForNode(memberValue, member);
161 PR_LOG(gXULTemplateLog, PR_LOG_DEBUG,
162 ("nsRDFConMemberTestNode[%p]: FilterInstantiations() container=[%s] member=[%s]",
163 this, container, NS_ConvertUTF16toUTF8(member).get()));
165 #endif
167 if (hasContainerBinding && hasMemberBinding) {
168 // it's a consistency check. see if we have a assignment that is consistent
169 PRBool isconsistent = PR_FALSE;
171 if (rdfcontainer) {
172 // RDF containers are easy. Just use the container API.
173 PRInt32 index;
174 rv = rdfcontainer->IndexOf(memberValue, &index);
175 if (NS_FAILED(rv)) return rv;
177 if (index >= 0)
178 isconsistent = PR_TRUE;
181 // XXXwaterson oof. if we *are* an RDF container, why do
182 // we still need to grovel through all the containment
183 // properties if the thing we're looking for wasn't there?
185 if (! isconsistent) {
186 // Othewise, we'll need to grovel through the
187 // membership properties to see if we have an
188 // assertion that indicates membership.
189 nsResourceSet& containmentProps = mProcessor->ContainmentProperties();
190 for (nsResourceSet::ConstIterator property = containmentProps.First();
191 property != containmentProps.Last();
192 ++property) {
193 PRBool hasAssertion;
194 rv = ds->HasAssertion(containerRes,
195 *property,
196 memberValue,
197 PR_TRUE,
198 &hasAssertion);
199 if (NS_FAILED(rv)) return rv;
201 if (hasAssertion) {
202 // it's consistent. leave it in the set and we'll
203 // run it up to our parent.
204 isconsistent = PR_TRUE;
205 break;
210 PR_LOG(gXULTemplateLog, PR_LOG_DEBUG,
211 (" consistency check => %s", isconsistent ? "passed" : "failed"));
213 if (isconsistent) {
214 // Add a memory element to our set-of-support.
215 Element* element =
216 nsRDFConMemberTestNode::Element::Create(containerRes,
217 memberValue);
219 if (! element)
220 return NS_ERROR_OUT_OF_MEMORY;
222 inst->AddSupportingElement(element);
224 else {
225 // it's inconsistent. remove it.
226 aInstantiations.Erase(inst--);
229 // We're done, go on to the next instantiation
230 continue;
233 if (hasContainerBinding && rdfcontainer) {
234 // We've got a container assignment, and the container is
235 // bound to an RDF container. Add each member as a new
236 // instantiation.
237 nsCOMPtr<nsISimpleEnumerator> elements;
238 rv = rdfcontainer->GetElements(getter_AddRefs(elements));
239 if (NS_FAILED(rv)) return rv;
241 while (1) {
242 PRBool hasmore;
243 rv = elements->HasMoreElements(&hasmore);
244 if (NS_FAILED(rv)) return rv;
246 if (! hasmore)
247 break;
249 nsCOMPtr<nsISupports> isupports;
250 rv = elements->GetNext(getter_AddRefs(isupports));
251 if (NS_FAILED(rv)) return rv;
253 nsCOMPtr<nsIRDFNode> node = do_QueryInterface(isupports);
254 if (! node)
255 return NS_ERROR_UNEXPECTED;
257 #ifdef PR_LOGGING
258 if (PR_LOG_TEST(gXULTemplateLog, PR_LOG_DEBUG)) {
259 nsAutoString member;
260 nsXULContentUtils::GetTextForNode(node, member);
262 PR_LOG(gXULTemplateLog, PR_LOG_DEBUG,
263 (" member => %s", NS_ConvertUTF16toUTF8(member).get()));
265 #endif
267 Instantiation newinst = *inst;
268 newinst.AddAssignment(mMemberVariable, node);
270 Element* element =
271 nsRDFConMemberTestNode::Element::Create(containerRes, node);
273 if (! element)
274 return NS_ERROR_OUT_OF_MEMORY;
276 newinst.AddSupportingElement(element);
277 aInstantiations.Insert(inst, newinst);
281 if (hasMemberBinding) {
282 // Oh, this is so nasty. If we have a member assignment, then
283 // grovel through each one of our inbound arcs to see if
284 // any of them are ordinal properties (like an RDF
285 // container might have). If so, walk it backwards to get
286 // the container we're in.
287 nsCOMPtr<nsISimpleEnumerator> arcsin;
288 rv = ds->ArcLabelsIn(memberValue, getter_AddRefs(arcsin));
289 if (NS_FAILED(rv)) return rv;
291 while (1) {
292 nsCOMPtr<nsIRDFResource> property;
295 PRBool hasmore;
296 rv = arcsin->HasMoreElements(&hasmore);
297 if (NS_FAILED(rv)) return rv;
299 if (! hasmore)
300 break;
302 nsCOMPtr<nsISupports> isupports;
303 rv = arcsin->GetNext(getter_AddRefs(isupports));
304 if (NS_FAILED(rv)) return rv;
306 property = do_QueryInterface(isupports);
307 if (! property)
308 return NS_ERROR_UNEXPECTED;
311 // Ordinal properties automagically indicate container
312 // membership as far as we're concerned. Note that
313 // we're *only* concerned with ordinal properties
314 // here: the next block will worry about the other
315 // membership properties.
316 PRBool isordinal;
317 rv = rdfc->IsOrdinalProperty(property, &isordinal);
318 if (NS_FAILED(rv)) return rv;
320 if (isordinal) {
321 // If we get here, we've found a property that
322 // indicates container membership leading *into* a
323 // member node. Find all the people that point to
324 // it, and call them containers.
325 nsCOMPtr<nsISimpleEnumerator> sources;
326 rv = ds->GetSources(property, memberValue, PR_TRUE,
327 getter_AddRefs(sources));
328 if (NS_FAILED(rv)) return rv;
330 while (1) {
331 PRBool hasmore;
332 rv = sources->HasMoreElements(&hasmore);
333 if (NS_FAILED(rv)) return rv;
335 if (! hasmore)
336 break;
338 nsCOMPtr<nsISupports> isupports;
339 rv = sources->GetNext(getter_AddRefs(isupports));
340 if (NS_FAILED(rv)) return rv;
342 nsCOMPtr<nsIRDFResource> source = do_QueryInterface(isupports);
343 if (! source)
344 return NS_ERROR_UNEXPECTED;
346 #ifdef PR_LOGGING
347 if (PR_LOG_TEST(gXULTemplateLog, PR_LOG_DEBUG)) {
348 const char* container;
349 source->GetValueConst(&container);
351 PR_LOG(gXULTemplateLog, PR_LOG_DEBUG,
352 (" container => %s", container));
354 #endif
356 // Add a new instantiation
357 Instantiation newinst = *inst;
358 newinst.AddAssignment(mContainerVariable, source);
360 Element* element =
361 nsRDFConMemberTestNode::Element::Create(source,
362 memberValue);
364 if (! element)
365 return NS_ERROR_OUT_OF_MEMORY;
367 newinst.AddSupportingElement(element);
369 aInstantiations.Insert(inst, newinst);
375 if ((hasContainerBinding && ! hasMemberBinding) ||
376 (! hasContainerBinding && hasMemberBinding)) {
377 // it's an open ended query on the container or member. go
378 // through our containment properties to see if anything
379 // applies.
380 nsResourceSet& containmentProps = mProcessor->ContainmentProperties();
381 for (nsResourceSet::ConstIterator property = containmentProps.First();
382 property != containmentProps.Last();
383 ++property) {
384 nsCOMPtr<nsISimpleEnumerator> results;
385 if (hasContainerBinding) {
386 rv = ds->GetTargets(containerRes, *property, PR_TRUE,
387 getter_AddRefs(results));
389 else {
390 rv = ds->GetSources(*property, memberValue, PR_TRUE,
391 getter_AddRefs(results));
393 if (NS_FAILED(rv)) return rv;
395 while (1) {
396 PRBool hasmore;
397 rv = results->HasMoreElements(&hasmore);
398 if (NS_FAILED(rv)) return rv;
400 if (! hasmore)
401 break;
403 nsCOMPtr<nsISupports> isupports;
404 rv = results->GetNext(getter_AddRefs(isupports));
405 if (NS_FAILED(rv)) return rv;
407 nsIAtom* variable;
408 nsCOMPtr<nsIRDFNode> value;
409 nsCOMPtr<nsIRDFResource> valueRes;
411 if (hasContainerBinding) {
412 variable = mMemberVariable;
414 value = do_QueryInterface(isupports);
415 NS_ASSERTION(value != nsnull, "member is not an nsIRDFNode");
416 if (! value) continue;
418 #ifdef PR_LOGGING
419 if (PR_LOG_TEST(gXULTemplateLog, PR_LOG_DEBUG)) {
420 nsAutoString s;
421 nsXULContentUtils::GetTextForNode(value, s);
423 PR_LOG(gXULTemplateLog, PR_LOG_DEBUG,
424 (" member => %s", NS_ConvertUTF16toUTF8(s).get()));
426 #endif
428 else {
429 variable = mContainerVariable;
431 valueRes = do_QueryInterface(isupports);
432 NS_ASSERTION(valueRes != nsnull, "container is not an nsIRDFResource");
433 if (! valueRes) continue;
435 value = valueRes;
437 #ifdef PR_LOGGING
438 if (PR_LOG_TEST(gXULTemplateLog, PR_LOG_DEBUG)) {
439 const char* s;
440 valueRes->GetValueConst(&s);
442 PR_LOG(gXULTemplateLog, PR_LOG_DEBUG,
443 (" container => %s", s));
445 #endif
448 // Copy the original instantiation, and add it to the
449 // instantiation set with the new assignment that we've
450 // introduced. Ownership will be transferred to the
451 Instantiation newinst = *inst;
452 newinst.AddAssignment(variable, value);
454 Element* element;
455 if (hasContainerBinding) {
456 element =
457 nsRDFConMemberTestNode::Element::Create(containerRes, value);
459 else {
460 element =
461 nsRDFConMemberTestNode::Element::Create(valueRes, memberValue);
464 if (! element)
465 return NS_ERROR_OUT_OF_MEMORY;
467 newinst.AddSupportingElement(element);
469 aInstantiations.Insert(inst, newinst);
474 if (! hasContainerBinding && ! hasMemberBinding) {
475 // Neither container nor member assignment!
476 if (!aCantHandleYet) {
477 return NS_ERROR_UNEXPECTED;
480 *aCantHandleYet = PR_TRUE;
481 return NS_OK;
484 // finally, remove the "under specified" instantiation.
485 aInstantiations.Erase(inst--);
488 return NS_OK;
491 PRBool
492 nsRDFConMemberTestNode::CanPropagate(nsIRDFResource* aSource,
493 nsIRDFResource* aProperty,
494 nsIRDFNode* aTarget,
495 Instantiation& aInitialBindings) const
497 nsresult rv;
499 PRBool canpropagate = PR_FALSE;
501 nsCOMPtr<nsIRDFContainerUtils> rdfc =
502 do_GetService("@mozilla.org/rdf/container-utils;1");
504 if (! rdfc)
505 return PR_FALSE;
507 // We can certainly propagate ordinal properties
508 rv = rdfc->IsOrdinalProperty(aProperty, &canpropagate);
509 if (NS_FAILED(rv)) return PR_FALSE;
511 if (! canpropagate) {
512 canpropagate = mProcessor->ContainmentProperties().Contains(aProperty);
515 #ifdef PR_LOGGING
516 if (PR_LOG_TEST(gXULTemplateLog, PR_LOG_DEBUG)) {
517 const char* source;
518 aSource->GetValueConst(&source);
520 const char* property;
521 aProperty->GetValueConst(&property);
523 nsAutoString target;
524 nsXULContentUtils::GetTextForNode(aTarget, target);
526 PR_LOG(gXULTemplateLog, PR_LOG_DEBUG,
527 ("nsRDFConMemberTestNode[%p]: CanPropagate([%s]==[%s]=>[%s]) => %s",
528 this, source, property, NS_ConvertUTF16toUTF8(target).get(),
529 canpropagate ? "true" : "false"));
531 #endif
533 if (canpropagate) {
534 aInitialBindings.AddAssignment(mContainerVariable, aSource);
535 aInitialBindings.AddAssignment(mMemberVariable, aTarget);
536 return PR_TRUE;
539 return PR_FALSE;
542 void
543 nsRDFConMemberTestNode::Retract(nsIRDFResource* aSource,
544 nsIRDFResource* aProperty,
545 nsIRDFNode* aTarget) const
547 PRBool canretract = PR_FALSE;
549 nsCOMPtr<nsIRDFContainerUtils> rdfc =
550 do_GetService("@mozilla.org/rdf/container-utils;1");
552 if (! rdfc)
553 return;
555 // We can certainly retract ordinal properties
556 nsresult rv;
557 rv = rdfc->IsOrdinalProperty(aProperty, &canretract);
558 if (NS_FAILED(rv)) return;
560 if (! canretract) {
561 canretract = mProcessor->ContainmentProperties().Contains(aProperty);
564 if (canretract) {
565 mProcessor->RetractElement(Element(aSource, aTarget));