gecko-dev/dom/xul/templates/nsRDFConInstanceTestNode.cpp

286 строки
9.9 KiB
C++

/* -*- 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 PRLogModuleInfo* 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);
if (! element)
return NS_ERROR_OUT_OF_MEMORY;
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));
}
}