summaryrefslogtreecommitdiffstats
path: root/dom/xul/templates/nsRDFConInstanceTestNode.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'dom/xul/templates/nsRDFConInstanceTestNode.cpp')
-rw-r--r--dom/xul/templates/nsRDFConInstanceTestNode.cpp281
1 files changed, 281 insertions, 0 deletions
diff --git a/dom/xul/templates/nsRDFConInstanceTestNode.cpp b/dom/xul/templates/nsRDFConInstanceTestNode.cpp
new file mode 100644
index 000000000..a96809743
--- /dev/null
+++ b/dom/xul/templates/nsRDFConInstanceTestNode.cpp
@@ -0,0 +1,281 @@
+/* -*- 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 "nsIComponentManager.h"
+#include "nsIRDFContainer.h"
+#include "nsIRDFContainerUtils.h"
+#include "nsIServiceManager.h"
+#include "nsRDFCID.h"
+#include "nsRDFConInstanceTestNode.h"
+#include "nsResourceSet.h"
+
+#include "mozilla/Logging.h"
+#include "nsXULContentUtils.h"
+
+using mozilla::LogLevel;
+
+extern mozilla::LazyLogModule gXULTemplateLog;
+
+static const char*
+TestToString(nsRDFConInstanceTestNode::Test aTest) {
+ switch (aTest) {
+ case nsRDFConInstanceTestNode::eFalse: return "false";
+ case nsRDFConInstanceTestNode::eTrue: return "true";
+ case nsRDFConInstanceTestNode::eDontCare: return "dontcare";
+ }
+ return "?";
+}
+
+nsRDFConInstanceTestNode::nsRDFConInstanceTestNode(TestNode* aParent,
+ nsXULTemplateQueryProcessorRDF* aProcessor,
+ nsIAtom* aContainerVariable,
+ Test aContainer,
+ Test aEmpty)
+ : nsRDFTestNode(aParent),
+ mProcessor(aProcessor),
+ mContainerVariable(aContainerVariable),
+ mContainer(aContainer),
+ mEmpty(aEmpty)
+{
+ 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);
+
+ MOZ_LOG(gXULTemplateLog, LogLevel::Debug,
+ ("nsRDFConInstanceTestNode[%p]: parent=%p member-props=(%s) container-var=%s container=%s empty=%s",
+ this,
+ aParent,
+ props.get(),
+ NS_ConvertUTF16toUTF8(cvar).get(),
+ TestToString(aContainer),
+ TestToString(aEmpty)));
+ }
+}
+
+nsresult
+nsRDFConInstanceTestNode::FilterInstantiations(InstantiationSet& aInstantiations,
+ bool* aCantHandleYet) const
+{
+ 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) {
+ 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;
+ }
+
+ if (MOZ_LOG_TEST(gXULTemplateLog, LogLevel::Debug)) {
+ const char* container = "(unbound)";
+ valueres->GetValueConst(&container);
+
+ MOZ_LOG(gXULTemplateLog, LogLevel::Debug,
+ ("nsRDFConInstanceTestNode[%p]::FilterInstantiations() container=[%s]",
+ this, container));
+ }
+
+ nsCOMPtr<nsIRDFContainer> rdfcontainer;
+
+ bool 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;
+
+ int32_t 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, true, getter_AddRefs(target));
+ if (NS_FAILED(rv)) return rv;
+
+ if (target != nullptr) {
+ // 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) {
+ bool 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 != nullptr, "not a property");
+ if (! property)
+ return NS_ERROR_UNEXPECTED;
+
+ if (mProcessor->ContainmentProperties().Contains(property)) {
+ container = eTrue;
+ break;
+ }
+ }
+ }
+ }
+
+ MOZ_LOG(gXULTemplateLog, LogLevel::Debug,
+ (" empty => %s",
+ (empty == mEmpty) ? "consistent" : "inconsistent"));
+
+ MOZ_LOG(gXULTemplateLog, LogLevel::Debug,
+ (" container => %s",
+ (container == mContainer) ? "consistent" : "inconsistent"));
+
+ if (((mEmpty == empty) && (mContainer == container)) ||
+ ((mEmpty == eDontCare) && (mContainer == container)) ||
+ ((mContainer == eDontCare) && (mEmpty == empty)))
+ {
+ Element* element =
+ new nsRDFConInstanceTestNode::Element(valueres, container, empty);
+ inst->AddSupportingElement(element);
+ }
+ else {
+ aInstantiations.Erase(inst--);
+ }
+ }
+ }
+
+ return NS_OK;
+}
+
+bool
+nsRDFConInstanceTestNode::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,
+ ("nsRDFConInstanceTestNode[%p]: CanPropagate([%s]==[%s]=>[%s]) => %s",
+ this, source, property, NS_ConvertUTF16toUTF8(target).get(),
+ canpropagate ? "true" : "false"));
+ }
+
+ if (canpropagate) {
+ aInitialBindings.AddAssignment(mContainerVariable, aSource);
+ return true;
+ }
+
+ return false;
+}
+
+void
+nsRDFConInstanceTestNode::Retract(nsIRDFResource* aSource,
+ nsIRDFResource* aProperty,
+ nsIRDFNode* aTarget) const
+{
+ // XXXwaterson oof. complicated. figure this out.
+ if (0) {
+ mProcessor->RetractElement(Element(aSource, mContainer, mEmpty));
+ }
+}
+