nsresult nsRDFPropertyTestNode::FilterInstantiations(InstantiationSet& aInstantiations, bool* aCantHandleYet) const { nsresult rv; if (aCantHandleYet) *aCantHandleYet = false; nsIRDFDataSource* ds = mProcessor->GetDataSource(); InstantiationSet::Iterator last = aInstantiations.Last(); for (InstantiationSet::Iterator inst = aInstantiations.First(); inst != last; ++inst) { bool hasSourceBinding; nsCOMPtr<nsIRDFResource> sourceRes; if (mSource) { hasSourceBinding = true; sourceRes = mSource; } else { nsCOMPtr<nsIRDFNode> sourceValue; hasSourceBinding = inst->mAssignments.GetAssignmentFor(mSourceVariable, getter_AddRefs(sourceValue)); sourceRes = do_QueryInterface(sourceValue); } bool hasTargetBinding; nsCOMPtr<nsIRDFNode> targetValue; if (mTarget) { hasTargetBinding = true; targetValue = mTarget; } else { hasTargetBinding = inst->mAssignments.GetAssignmentFor(mTargetVariable, getter_AddRefs(targetValue)); } #ifdef PR_LOGGING if (PR_LOG_TEST(gXULTemplateLog, PR_LOG_DEBUG)) { const char* source = "(unbound)"; if (hasSourceBinding) sourceRes->GetValueConst(&source); nsAutoString target(NS_LITERAL_STRING("(unbound)")); if (hasTargetBinding) nsXULContentUtils::GetTextForNode(targetValue, target); PR_LOG(gXULTemplateLog, PR_LOG_DEBUG, ("nsRDFPropertyTestNode[%p]: FilterInstantiations() source=[%s] target=[%s]", this, source, NS_ConvertUTF16toUTF8(target).get())); } #endif if (hasSourceBinding && hasTargetBinding) { // it's a consistency check. see if we have a assignment that is consistent bool hasAssertion; rv = ds->HasAssertion(sourceRes, mProperty, targetValue, true, &hasAssertion); if (NS_FAILED(rv)) return rv; #ifdef PR_LOGGING PR_LOG(gXULTemplateLog, PR_LOG_DEBUG, (" consistency check => %s", hasAssertion ? "passed" : "failed")); #endif if (hasAssertion) { // it's consistent. Element* element = new nsRDFPropertyTestNode::Element(sourceRes, mProperty, targetValue); if (! element) return NS_ERROR_OUT_OF_MEMORY; inst->AddSupportingElement(element); } else { // it's inconsistent. remove it. aInstantiations.Erase(inst--); } } else if ((hasSourceBinding && ! hasTargetBinding) || (! hasSourceBinding && hasTargetBinding)) { // it's an open ended query on the source or // target. figure out what matches and add as a // cross-product. nsCOMPtr<nsISimpleEnumerator> results; if (hasSourceBinding) { rv = ds->GetTargets(sourceRes, mProperty, true, getter_AddRefs(results)); } else { rv = ds->GetSources(mProperty, targetValue, true, getter_AddRefs(results)); if (NS_FAILED(rv)) return rv; } while (1) { bool hasMore; rv = results->HasMoreElements(&hasMore); if (NS_FAILED(rv)) return rv; if (! hasMore) break; nsCOMPtr<nsISupports> isupports; rv = results->GetNext(getter_AddRefs(isupports)); if (NS_FAILED(rv)) return rv; nsIAtom* variable; nsCOMPtr<nsIRDFNode> value; if (hasSourceBinding) { variable = mTargetVariable; value = do_QueryInterface(isupports); NS_ASSERTION(value != nullptr, "target is not an nsIRDFNode"); #ifdef PR_LOGGING if (PR_LOG_TEST(gXULTemplateLog, PR_LOG_DEBUG)) { nsAutoString s(NS_LITERAL_STRING("(none found)")); if (value) nsXULContentUtils::GetTextForNode(value, s); PR_LOG(gXULTemplateLog, PR_LOG_DEBUG, (" target => %s", NS_ConvertUTF16toUTF8(s).get())); } #endif if (! value) continue; targetValue = value; } else { variable = mSourceVariable; nsCOMPtr<nsIRDFResource> source = do_QueryInterface(isupports); NS_ASSERTION(source != nullptr, "source is not an nsIRDFResource"); #ifdef PR_LOGGING if (PR_LOG_TEST(gXULTemplateLog, PR_LOG_DEBUG)) { const char* s = "(none found)"; if (source) source->GetValueConst(&s); PR_LOG(gXULTemplateLog, PR_LOG_DEBUG, (" source => %s", s)); } #endif if (! source) continue; value = sourceRes = source; } // Copy the original instantiation, and add it to the // instantiation set with the new assignment that we've // introduced. Ownership will be transferred to the Instantiation newinst = *inst; newinst.AddAssignment(variable, value); Element* element = new nsRDFPropertyTestNode::Element(sourceRes, mProperty, targetValue); if (! element) return NS_ERROR_OUT_OF_MEMORY; newinst.AddSupportingElement(element); aInstantiations.Insert(inst, newinst); } // finally, remove the "under specified" instantiation. aInstantiations.Erase(inst--); } else { if (!aCantHandleYet) { nsXULContentUtils::LogTemplateError(ERROR_TEMPLATE_TRIPLE_UNBOUND); // Neither source nor target assignment! return NS_ERROR_UNEXPECTED; } *aCantHandleYet = true; return NS_OK; } } return NS_OK; }
nsresult nsRDFConInstanceTestNode::FilterInstantiations(InstantiationSet& aInstantiations, PRBool* aCantHandleYet) const { nsresult rv; if (aCantHandleYet) *aCantHandleYet = PR_FALSE; nsCOMPtr<nsIRDFContainerUtils> rdfc = do_GetService("@mozilla.org/rdf/container-utils;1"); if (! rdfc) return NS_ERROR_FAILURE; nsIRDFDataSource* ds = mProcessor->GetDataSource(); InstantiationSet::Iterator last = aInstantiations.Last(); for (InstantiationSet::Iterator inst = aInstantiations.First(); inst != last; ++inst) { nsCOMPtr<nsIRDFNode> value; if (! inst->mAssignments.GetAssignmentFor(mContainerVariable, getter_AddRefs(value))) { NS_ERROR("can't do unbounded container testing"); return NS_ERROR_UNEXPECTED; } nsCOMPtr<nsIRDFResource> valueres = do_QueryInterface(value); if (! valueres) { aInstantiations.Erase(inst--); continue; } #ifdef PR_LOGGING if (PR_LOG_TEST(gXULTemplateLog, PR_LOG_DEBUG)) { const char* container = "(unbound)"; valueres->GetValueConst(&container); PR_LOG(gXULTemplateLog, PR_LOG_DEBUG, ("nsRDFConInstanceTestNode[%p]::FilterInstantiations() container=[%s]", this, container)); } #endif nsCOMPtr<nsIRDFContainer> rdfcontainer; PRBool isRDFContainer; rv = rdfc->IsContainer(ds, valueres, &isRDFContainer); if (NS_FAILED(rv)) return rv; if (mEmpty != eDontCare || mContainer != eDontCare) { Test empty = eDontCare; Test container = eDontCare; if (isRDFContainer) { // It's an RDF container. Use the container utilities // to deduce what's in it. container = eTrue; // XXX should cache the factory rdfcontainer = do_CreateInstance("@mozilla.org/rdf/container;1", &rv); if (NS_FAILED(rv)) return rv; rv = rdfcontainer->Init(ds, valueres); if (NS_FAILED(rv)) return rv; PRInt32 count; rv = rdfcontainer->GetCount(&count); if (NS_FAILED(rv)) return rv; empty = (count == 0) ? eTrue : eFalse; } else { empty = eTrue; container = eFalse; // First do the simple check of finding some outward // arcs; there should be only a few containment arcs, so this can // save us time from dealing with an iterator later on nsResourceSet& containmentProps = mProcessor->ContainmentProperties(); for (nsResourceSet::ConstIterator property = containmentProps.First(); property != containmentProps.Last(); ++property) { nsCOMPtr<nsIRDFNode> target; rv = ds->GetTarget(valueres, *property, PR_TRUE, getter_AddRefs(target)); if (NS_FAILED(rv)) return rv; if (target != nsnull) { // bingo. we found one. empty = eFalse; container = eTrue; break; } } // if we still don't think its a container, but we // want to know for sure whether it is or not, we need // to check ArcLabelsOut for potential container arcs. if (container == eFalse && mContainer != eDontCare) { nsCOMPtr<nsISimpleEnumerator> arcsout; rv = ds->ArcLabelsOut(valueres, getter_AddRefs(arcsout)); if (NS_FAILED(rv)) return rv; while (1) { PRBool hasmore; rv = arcsout->HasMoreElements(&hasmore); if (NS_FAILED(rv)) return rv; if (! hasmore) break; nsCOMPtr<nsISupports> isupports; rv = arcsout->GetNext(getter_AddRefs(isupports)); if (NS_FAILED(rv)) return rv; nsCOMPtr<nsIRDFResource> property = do_QueryInterface(isupports); NS_ASSERTION(property != nsnull, "not a property"); if (! property) return NS_ERROR_UNEXPECTED; if (mProcessor->ContainmentProperties().Contains(property)) { container = eTrue; break; } } } } PR_LOG(gXULTemplateLog, PR_LOG_DEBUG, (" empty => %s", (empty == mEmpty) ? "consistent" : "inconsistent")); PR_LOG(gXULTemplateLog, PR_LOG_DEBUG, (" container => %s", (container == mContainer) ? "consistent" : "inconsistent")); if (((mEmpty == empty) && (mContainer == container)) || ((mEmpty == eDontCare) && (mContainer == container)) || ((mContainer == eDontCare) && (mEmpty == empty))) { Element* element = nsRDFConInstanceTestNode::Element::Create(valueres, container, empty); if (! element) return NS_ERROR_OUT_OF_MEMORY; inst->AddSupportingElement(element); } else { aInstantiations.Erase(inst--); } } } return NS_OK; }
nsresult nsRDFConMemberTestNode::FilterInstantiations(InstantiationSet& aInstantiations, bool* aCantHandleYet) const { // XXX Uh, factor me, please! nsresult rv; if (aCantHandleYet) *aCantHandleYet = false; nsCOMPtr<nsIRDFContainerUtils> rdfc = do_GetService("@mozilla.org/rdf/container-utils;1"); if (! rdfc) return NS_ERROR_FAILURE; nsIRDFDataSource* ds = mProcessor->GetDataSource(); InstantiationSet::Iterator last = aInstantiations.Last(); for (InstantiationSet::Iterator inst = aInstantiations.First(); inst != last; ++inst) { bool hasContainerBinding; nsCOMPtr<nsIRDFNode> containerValue; hasContainerBinding = inst->mAssignments.GetAssignmentFor(mContainerVariable, getter_AddRefs(containerValue)); nsCOMPtr<nsIRDFResource> containerRes = do_QueryInterface(containerValue); nsCOMPtr<nsIRDFContainer> rdfcontainer; if (hasContainerBinding && containerRes) { // If we have a container assignment, then see if the // container is an RDF container (bag, seq, alt), and if // so, wrap it. bool isRDFContainer; rv = rdfc->IsContainer(ds, containerRes, &isRDFContainer); if (NS_FAILED(rv)) return rv; if (isRDFContainer) { rdfcontainer = do_CreateInstance("@mozilla.org/rdf/container;1", &rv); if (NS_FAILED(rv)) return rv; rv = rdfcontainer->Init(ds, containerRes); if (NS_FAILED(rv)) return rv; } } bool hasMemberBinding; nsCOMPtr<nsIRDFNode> memberValue; hasMemberBinding = inst->mAssignments.GetAssignmentFor(mMemberVariable, getter_AddRefs(memberValue)); #ifdef PR_LOGGING if (PR_LOG_TEST(gXULTemplateLog, PR_LOG_DEBUG)) { const char* container = "(unbound)"; if (hasContainerBinding) containerRes->GetValueConst(&container); nsAutoString member(NS_LITERAL_STRING("(unbound)")); if (hasMemberBinding) nsXULContentUtils::GetTextForNode(memberValue, member); PR_LOG(gXULTemplateLog, PR_LOG_DEBUG, ("nsRDFConMemberTestNode[%p]: FilterInstantiations() container=[%s] member=[%s]", this, container, NS_ConvertUTF16toUTF8(member).get())); } #endif if (hasContainerBinding && hasMemberBinding) { // it's a consistency check. see if we have a assignment that is consistent bool isconsistent = false; if (rdfcontainer) { // RDF containers are easy. Just use the container API. PRInt32 index; rv = rdfcontainer->IndexOf(memberValue, &index); if (NS_FAILED(rv)) return rv; if (index >= 0) isconsistent = true; } // XXXwaterson oof. if we *are* an RDF container, why do // we still need to grovel through all the containment // properties if the thing we're looking for wasn't there? if (! isconsistent) { // Othewise, we'll need to grovel through the // membership properties to see if we have an // assertion that indicates membership. nsResourceSet& containmentProps = mProcessor->ContainmentProperties(); for (nsResourceSet::ConstIterator property = containmentProps.First(); property != containmentProps.Last(); ++property) { bool hasAssertion; rv = ds->HasAssertion(containerRes, *property, memberValue, true, &hasAssertion); if (NS_FAILED(rv)) return rv; if (hasAssertion) { // it's consistent. leave it in the set and we'll // run it up to our parent. isconsistent = true; break; } } } PR_LOG(gXULTemplateLog, PR_LOG_DEBUG, (" consistency check => %s", isconsistent ? "passed" : "failed")); if (isconsistent) { // Add a memory element to our set-of-support. Element* element = nsRDFConMemberTestNode::Element::Create(containerRes, memberValue); if (! element) return NS_ERROR_OUT_OF_MEMORY; inst->AddSupportingElement(element); } else { // it's inconsistent. remove it. aInstantiations.Erase(inst--); } // We're done, go on to the next instantiation continue; } if (hasContainerBinding && rdfcontainer) { // We've got a container assignment, and the container is // bound to an RDF container. Add each member as a new // instantiation. nsCOMPtr<nsISimpleEnumerator> elements; rv = rdfcontainer->GetElements(getter_AddRefs(elements)); if (NS_FAILED(rv)) return rv; while (1) { bool hasmore; rv = elements->HasMoreElements(&hasmore); if (NS_FAILED(rv)) return rv; if (! hasmore) break; nsCOMPtr<nsISupports> isupports; rv = elements->GetNext(getter_AddRefs(isupports)); if (NS_FAILED(rv)) return rv; nsCOMPtr<nsIRDFNode> node = do_QueryInterface(isupports); if (! node) return NS_ERROR_UNEXPECTED; #ifdef PR_LOGGING if (PR_LOG_TEST(gXULTemplateLog, PR_LOG_DEBUG)) { nsAutoString member; nsXULContentUtils::GetTextForNode(node, member); PR_LOG(gXULTemplateLog, PR_LOG_DEBUG, (" member => %s", NS_ConvertUTF16toUTF8(member).get())); } #endif Instantiation newinst = *inst; newinst.AddAssignment(mMemberVariable, node); Element* element = nsRDFConMemberTestNode::Element::Create(containerRes, node); if (! element) return NS_ERROR_OUT_OF_MEMORY; newinst.AddSupportingElement(element); aInstantiations.Insert(inst, newinst); } } if (hasMemberBinding) { // Oh, this is so nasty. If we have a member assignment, then // grovel through each one of our inbound arcs to see if // any of them are ordinal properties (like an RDF // container might have). If so, walk it backwards to get // the container we're in. nsCOMPtr<nsISimpleEnumerator> arcsin; rv = ds->ArcLabelsIn(memberValue, getter_AddRefs(arcsin)); if (NS_FAILED(rv)) return rv; while (1) { nsCOMPtr<nsIRDFResource> property; { bool hasmore; rv = arcsin->HasMoreElements(&hasmore); if (NS_FAILED(rv)) return rv; if (! hasmore) break; nsCOMPtr<nsISupports> isupports; rv = arcsin->GetNext(getter_AddRefs(isupports)); if (NS_FAILED(rv)) return rv; property = do_QueryInterface(isupports); if (! property) return NS_ERROR_UNEXPECTED; } // Ordinal properties automagically indicate container // membership as far as we're concerned. Note that // we're *only* concerned with ordinal properties // here: the next block will worry about the other // membership properties. bool isordinal; rv = rdfc->IsOrdinalProperty(property, &isordinal); if (NS_FAILED(rv)) return rv; if (isordinal) { // If we get here, we've found a property that // indicates container membership leading *into* a // member node. Find all the people that point to // it, and call them containers. nsCOMPtr<nsISimpleEnumerator> sources; rv = ds->GetSources(property, memberValue, true, getter_AddRefs(sources)); if (NS_FAILED(rv)) return rv; while (1) { bool hasmore; rv = sources->HasMoreElements(&hasmore); if (NS_FAILED(rv)) return rv; if (! hasmore) break; nsCOMPtr<nsISupports> isupports; rv = sources->GetNext(getter_AddRefs(isupports)); if (NS_FAILED(rv)) return rv; nsCOMPtr<nsIRDFResource> source = do_QueryInterface(isupports); if (! source) return NS_ERROR_UNEXPECTED; #ifdef PR_LOGGING if (PR_LOG_TEST(gXULTemplateLog, PR_LOG_DEBUG)) { const char* container; source->GetValueConst(&container); PR_LOG(gXULTemplateLog, PR_LOG_DEBUG, (" container => %s", container)); } #endif // Add a new instantiation Instantiation newinst = *inst; newinst.AddAssignment(mContainerVariable, source); Element* element = nsRDFConMemberTestNode::Element::Create(source, memberValue); if (! element) return NS_ERROR_OUT_OF_MEMORY; newinst.AddSupportingElement(element); aInstantiations.Insert(inst, newinst); } } } } if ((hasContainerBinding && ! hasMemberBinding) || (! hasContainerBinding && hasMemberBinding)) { // it's an open ended query on the container or member. go // through our containment properties to see if anything // applies. nsResourceSet& containmentProps = mProcessor->ContainmentProperties(); for (nsResourceSet::ConstIterator property = containmentProps.First(); property != containmentProps.Last(); ++property) { nsCOMPtr<nsISimpleEnumerator> results; if (hasContainerBinding) { rv = ds->GetTargets(containerRes, *property, true, getter_AddRefs(results)); } else { rv = ds->GetSources(*property, memberValue, true, getter_AddRefs(results)); } if (NS_FAILED(rv)) return rv; while (1) { bool hasmore; rv = results->HasMoreElements(&hasmore); if (NS_FAILED(rv)) return rv; if (! hasmore) break; nsCOMPtr<nsISupports> isupports; rv = results->GetNext(getter_AddRefs(isupports)); if (NS_FAILED(rv)) return rv; nsIAtom* variable; nsCOMPtr<nsIRDFNode> value; nsCOMPtr<nsIRDFResource> valueRes; if (hasContainerBinding) { variable = mMemberVariable; value = do_QueryInterface(isupports); NS_ASSERTION(value != nsnull, "member is not an nsIRDFNode"); if (! value) continue; #ifdef PR_LOGGING if (PR_LOG_TEST(gXULTemplateLog, PR_LOG_DEBUG)) { nsAutoString s; nsXULContentUtils::GetTextForNode(value, s); PR_LOG(gXULTemplateLog, PR_LOG_DEBUG, (" member => %s", NS_ConvertUTF16toUTF8(s).get())); } #endif } else { variable = mContainerVariable; valueRes = do_QueryInterface(isupports); NS_ASSERTION(valueRes != nsnull, "container is not an nsIRDFResource"); if (! valueRes) continue; value = valueRes; #ifdef PR_LOGGING if (PR_LOG_TEST(gXULTemplateLog, PR_LOG_DEBUG)) { const char* s; valueRes->GetValueConst(&s); PR_LOG(gXULTemplateLog, PR_LOG_DEBUG, (" container => %s", s)); } #endif } // Copy the original instantiation, and add it to the // instantiation set with the new assignment that we've // introduced. Ownership will be transferred to the Instantiation newinst = *inst; newinst.AddAssignment(variable, value); Element* element; if (hasContainerBinding) { element = nsRDFConMemberTestNode::Element::Create(containerRes, value); } else { element = nsRDFConMemberTestNode::Element::Create(valueRes, memberValue); } if (! element) return NS_ERROR_OUT_OF_MEMORY; newinst.AddSupportingElement(element); aInstantiations.Insert(inst, newinst); } } } if (! hasContainerBinding && ! hasMemberBinding) { // Neither container nor member assignment! if (!aCantHandleYet) { nsXULContentUtils::LogTemplateError(ERROR_TEMPLATE_MEMBER_UNBOUND); return NS_ERROR_UNEXPECTED; } *aCantHandleYet = true; return NS_OK; } // finally, remove the "under specified" instantiation. aInstantiations.Erase(inst--); } return NS_OK; }