123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511 |
- /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
- /* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
- #include "nsRDFConMemberTestNode.h"
- #include "nsIRDFContainer.h"
- #include "nsIRDFContainerUtils.h"
- #include "nsRDFCID.h"
- #include "nsIServiceManager.h"
- #include "nsResourceSet.h"
- #include "nsString.h"
- #include "nsXULContentUtils.h"
- #include "mozilla/Logging.h"
- using mozilla::LogLevel;
- extern mozilla::LazyLogModule gXULTemplateLog;
- nsRDFConMemberTestNode::nsRDFConMemberTestNode(TestNode* aParent,
- nsXULTemplateQueryProcessorRDF* aProcessor,
- nsIAtom *aContainerVariable,
- nsIAtom *aMemberVariable)
- : nsRDFTestNode(aParent),
- mProcessor(aProcessor),
- mContainerVariable(aContainerVariable),
- mMemberVariable(aMemberVariable)
- {
- if (MOZ_LOG_TEST(gXULTemplateLog, LogLevel::Debug)) {
- nsAutoCString props;
- nsResourceSet& containmentProps = aProcessor->ContainmentProperties();
- nsResourceSet::ConstIterator last = containmentProps.Last();
- nsResourceSet::ConstIterator first = containmentProps.First();
- nsResourceSet::ConstIterator iter;
- for (iter = first; iter != last; ++iter) {
- if (iter != first)
- props += " ";
- const char* str;
- iter->GetValueConst(&str);
- props += str;
- }
- nsAutoString cvar(NS_LITERAL_STRING("(none)"));
- if (mContainerVariable)
- mContainerVariable->ToString(cvar);
- nsAutoString mvar(NS_LITERAL_STRING("(none)"));
- if (mMemberVariable)
- mMemberVariable->ToString(mvar);
- MOZ_LOG(gXULTemplateLog, LogLevel::Debug,
- ("nsRDFConMemberTestNode[%p]: parent=%p member-props=(%s) container-var=%s member-var=%s",
- this,
- aParent,
- props.get(),
- NS_ConvertUTF16toUTF8(cvar).get(),
- NS_ConvertUTF16toUTF8(mvar).get()));
- }
- }
- 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));
- if (MOZ_LOG_TEST(gXULTemplateLog, LogLevel::Debug)) {
- const char* container = "(unbound)";
- if (hasContainerBinding)
- containerRes->GetValueConst(&container);
- nsAutoString member(NS_LITERAL_STRING("(unbound)"));
- if (hasMemberBinding)
- nsXULContentUtils::GetTextForNode(memberValue, member);
- MOZ_LOG(gXULTemplateLog, LogLevel::Debug,
- ("nsRDFConMemberTestNode[%p]: FilterInstantiations() container=[%s] member=[%s]",
- this, container, NS_ConvertUTF16toUTF8(member).get()));
- }
- 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.
- int32_t 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;
- }
- }
- }
- MOZ_LOG(gXULTemplateLog, LogLevel::Debug,
- (" consistency check => %s", isconsistent ? "passed" : "failed"));
- if (isconsistent) {
- // Add a memory element to our set-of-support.
- Element* element =
- new nsRDFConMemberTestNode::Element(containerRes,
- memberValue);
- 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;
- if (MOZ_LOG_TEST(gXULTemplateLog, LogLevel::Debug)) {
- nsAutoString member;
- nsXULContentUtils::GetTextForNode(node, member);
- MOZ_LOG(gXULTemplateLog, LogLevel::Debug,
- (" member => %s", NS_ConvertUTF16toUTF8(member).get()));
- }
- Instantiation newinst = *inst;
- newinst.AddAssignment(mMemberVariable, node);
- Element* element =
- new nsRDFConMemberTestNode::Element(containerRes, node);
- 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;
- if (MOZ_LOG_TEST(gXULTemplateLog, LogLevel::Debug)) {
- const char* container;
- source->GetValueConst(&container);
- MOZ_LOG(gXULTemplateLog, LogLevel::Debug,
- (" container => %s", container));
- }
- // Add a new instantiation
- Instantiation newinst = *inst;
- newinst.AddAssignment(mContainerVariable, source);
- Element* element =
- new nsRDFConMemberTestNode::Element(source,
- memberValue);
- 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 != nullptr, "member is not an nsIRDFNode");
- if (! value) continue;
- if (MOZ_LOG_TEST(gXULTemplateLog, LogLevel::Debug)) {
- nsAutoString s;
- nsXULContentUtils::GetTextForNode(value, s);
- MOZ_LOG(gXULTemplateLog, LogLevel::Debug,
- (" member => %s", NS_ConvertUTF16toUTF8(s).get()));
- }
- }
- else {
- variable = mContainerVariable;
- valueRes = do_QueryInterface(isupports);
- NS_ASSERTION(valueRes != nullptr, "container is not an nsIRDFResource");
- if (! valueRes) continue;
- value = valueRes;
- if (MOZ_LOG_TEST(gXULTemplateLog, LogLevel::Debug)) {
- const char* s;
- valueRes->GetValueConst(&s);
- MOZ_LOG(gXULTemplateLog, LogLevel::Debug,
- (" container => %s", s));
- }
- }
- // 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 =
- new nsRDFConMemberTestNode::Element(containerRes, value);
- }
- else {
- element =
- new nsRDFConMemberTestNode::Element(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;
- }
- bool
- nsRDFConMemberTestNode::CanPropagate(nsIRDFResource* aSource,
- nsIRDFResource* aProperty,
- nsIRDFNode* aTarget,
- Instantiation& aInitialBindings) const
- {
- nsresult rv;
- bool canpropagate = false;
- nsCOMPtr<nsIRDFContainerUtils> rdfc =
- do_GetService("@mozilla.org/rdf/container-utils;1");
- if (! rdfc)
- return false;
- // We can certainly propagate ordinal properties
- rv = rdfc->IsOrdinalProperty(aProperty, &canpropagate);
- if (NS_FAILED(rv)) return false;
- if (! canpropagate) {
- canpropagate = mProcessor->ContainmentProperties().Contains(aProperty);
- }
- if (MOZ_LOG_TEST(gXULTemplateLog, LogLevel::Debug)) {
- const char* source;
- aSource->GetValueConst(&source);
- const char* property;
- aProperty->GetValueConst(&property);
- nsAutoString target;
- nsXULContentUtils::GetTextForNode(aTarget, target);
- MOZ_LOG(gXULTemplateLog, LogLevel::Debug,
- ("nsRDFConMemberTestNode[%p]: CanPropagate([%s]==[%s]=>[%s]) => %s",
- this, source, property, NS_ConvertUTF16toUTF8(target).get(),
- canpropagate ? "true" : "false"));
- }
- if (canpropagate) {
- aInitialBindings.AddAssignment(mContainerVariable, aSource);
- aInitialBindings.AddAssignment(mMemberVariable, aTarget);
- return true;
- }
- return false;
- }
- void
- nsRDFConMemberTestNode::Retract(nsIRDFResource* aSource,
- nsIRDFResource* aProperty,
- nsIRDFNode* aTarget) const
- {
- bool canretract = false;
- nsCOMPtr<nsIRDFContainerUtils> rdfc =
- do_GetService("@mozilla.org/rdf/container-utils;1");
- if (! rdfc)
- return;
- // We can certainly retract ordinal properties
- nsresult rv;
- rv = rdfc->IsOrdinalProperty(aProperty, &canretract);
- if (NS_FAILED(rv)) return;
- if (! canretract) {
- canretract = mProcessor->ContainmentProperties().Contains(aProperty);
- }
- if (canretract) {
- mProcessor->RetractElement(Element(aSource, aTarget));
- }
- }
|