1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/content/xul/templates/src/nsRDFConInstanceTestNode.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,290 @@ 1.4 +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +#include "nsIComponentManager.h" 1.10 +#include "nsIRDFContainer.h" 1.11 +#include "nsIRDFContainerUtils.h" 1.12 +#include "nsIServiceManager.h" 1.13 +#include "nsRDFCID.h" 1.14 +#include "nsRDFConInstanceTestNode.h" 1.15 +#include "nsResourceSet.h" 1.16 + 1.17 +#include "prlog.h" 1.18 +#ifdef PR_LOGGING 1.19 +#include "nsXULContentUtils.h" 1.20 +extern PRLogModuleInfo* gXULTemplateLog; 1.21 + 1.22 +static const char* 1.23 +TestToString(nsRDFConInstanceTestNode::Test aTest) { 1.24 + switch (aTest) { 1.25 + case nsRDFConInstanceTestNode::eFalse: return "false"; 1.26 + case nsRDFConInstanceTestNode::eTrue: return "true"; 1.27 + case nsRDFConInstanceTestNode::eDontCare: return "dontcare"; 1.28 + } 1.29 + return "?"; 1.30 +} 1.31 +#endif 1.32 + 1.33 +nsRDFConInstanceTestNode::nsRDFConInstanceTestNode(TestNode* aParent, 1.34 + nsXULTemplateQueryProcessorRDF* aProcessor, 1.35 + nsIAtom* aContainerVariable, 1.36 + Test aContainer, 1.37 + Test aEmpty) 1.38 + : nsRDFTestNode(aParent), 1.39 + mProcessor(aProcessor), 1.40 + mContainerVariable(aContainerVariable), 1.41 + mContainer(aContainer), 1.42 + mEmpty(aEmpty) 1.43 +{ 1.44 +#ifdef PR_LOGGING 1.45 + if (PR_LOG_TEST(gXULTemplateLog, PR_LOG_DEBUG)) { 1.46 + nsAutoCString props; 1.47 + 1.48 + nsResourceSet& containmentProps = aProcessor->ContainmentProperties(); 1.49 + nsResourceSet::ConstIterator last = containmentProps.Last(); 1.50 + nsResourceSet::ConstIterator first = containmentProps.First(); 1.51 + nsResourceSet::ConstIterator iter; 1.52 + 1.53 + for (iter = first; iter != last; ++iter) { 1.54 + if (iter != first) 1.55 + props += " "; 1.56 + 1.57 + const char* str; 1.58 + iter->GetValueConst(&str); 1.59 + 1.60 + props += str; 1.61 + } 1.62 + 1.63 + nsAutoString cvar(NS_LITERAL_STRING("(none)")); 1.64 + if (mContainerVariable) 1.65 + mContainerVariable->ToString(cvar); 1.66 + 1.67 + PR_LOG(gXULTemplateLog, PR_LOG_DEBUG, 1.68 + ("nsRDFConInstanceTestNode[%p]: parent=%p member-props=(%s) container-var=%s container=%s empty=%s", 1.69 + this, 1.70 + aParent, 1.71 + props.get(), 1.72 + NS_ConvertUTF16toUTF8(cvar).get(), 1.73 + TestToString(aContainer), 1.74 + TestToString(aEmpty))); 1.75 + } 1.76 +#endif 1.77 +} 1.78 + 1.79 +nsresult 1.80 +nsRDFConInstanceTestNode::FilterInstantiations(InstantiationSet& aInstantiations, 1.81 + bool* aCantHandleYet) const 1.82 +{ 1.83 + nsresult rv; 1.84 + 1.85 + if (aCantHandleYet) 1.86 + *aCantHandleYet = false; 1.87 + 1.88 + nsCOMPtr<nsIRDFContainerUtils> rdfc 1.89 + = do_GetService("@mozilla.org/rdf/container-utils;1"); 1.90 + 1.91 + if (! rdfc) 1.92 + return NS_ERROR_FAILURE; 1.93 + 1.94 + nsIRDFDataSource* ds = mProcessor->GetDataSource(); 1.95 + 1.96 + InstantiationSet::Iterator last = aInstantiations.Last(); 1.97 + for (InstantiationSet::Iterator inst = aInstantiations.First(); inst != last; ++inst) { 1.98 + nsCOMPtr<nsIRDFNode> value; 1.99 + if (! inst->mAssignments.GetAssignmentFor(mContainerVariable, getter_AddRefs(value))) { 1.100 + NS_ERROR("can't do unbounded container testing"); 1.101 + return NS_ERROR_UNEXPECTED; 1.102 + } 1.103 + 1.104 + nsCOMPtr<nsIRDFResource> valueres = do_QueryInterface(value); 1.105 + if (! valueres) { 1.106 + aInstantiations.Erase(inst--); 1.107 + continue; 1.108 + } 1.109 + 1.110 +#ifdef PR_LOGGING 1.111 + if (PR_LOG_TEST(gXULTemplateLog, PR_LOG_DEBUG)) { 1.112 + const char* container = "(unbound)"; 1.113 + valueres->GetValueConst(&container); 1.114 + 1.115 + PR_LOG(gXULTemplateLog, PR_LOG_DEBUG, 1.116 + ("nsRDFConInstanceTestNode[%p]::FilterInstantiations() container=[%s]", 1.117 + this, container)); 1.118 + } 1.119 +#endif 1.120 + 1.121 + nsCOMPtr<nsIRDFContainer> rdfcontainer; 1.122 + 1.123 + bool isRDFContainer; 1.124 + rv = rdfc->IsContainer(ds, valueres, &isRDFContainer); 1.125 + if (NS_FAILED(rv)) return rv; 1.126 + 1.127 + if (mEmpty != eDontCare || mContainer != eDontCare) { 1.128 + Test empty = eDontCare; 1.129 + Test container = eDontCare; 1.130 + 1.131 + if (isRDFContainer) { 1.132 + // It's an RDF container. Use the container utilities 1.133 + // to deduce what's in it. 1.134 + container = eTrue; 1.135 + 1.136 + // XXX should cache the factory 1.137 + rdfcontainer = do_CreateInstance("@mozilla.org/rdf/container;1", &rv); 1.138 + if (NS_FAILED(rv)) return rv; 1.139 + 1.140 + rv = rdfcontainer->Init(ds, valueres); 1.141 + if (NS_FAILED(rv)) return rv; 1.142 + 1.143 + int32_t count; 1.144 + rv = rdfcontainer->GetCount(&count); 1.145 + if (NS_FAILED(rv)) return rv; 1.146 + 1.147 + empty = (count == 0) ? eTrue : eFalse; 1.148 + } else { 1.149 + empty = eTrue; 1.150 + container = eFalse; 1.151 + 1.152 + // First do the simple check of finding some outward 1.153 + // arcs; there should be only a few containment arcs, so this can 1.154 + // save us time from dealing with an iterator later on 1.155 + nsResourceSet& containmentProps = mProcessor->ContainmentProperties(); 1.156 + for (nsResourceSet::ConstIterator property = containmentProps.First(); 1.157 + property != containmentProps.Last(); 1.158 + ++property) { 1.159 + nsCOMPtr<nsIRDFNode> target; 1.160 + rv = ds->GetTarget(valueres, *property, true, getter_AddRefs(target)); 1.161 + if (NS_FAILED(rv)) return rv; 1.162 + 1.163 + if (target != nullptr) { 1.164 + // bingo. we found one. 1.165 + empty = eFalse; 1.166 + container = eTrue; 1.167 + break; 1.168 + } 1.169 + } 1.170 + 1.171 + // if we still don't think its a container, but we 1.172 + // want to know for sure whether it is or not, we need 1.173 + // to check ArcLabelsOut for potential container arcs. 1.174 + if (container == eFalse && mContainer != eDontCare) { 1.175 + nsCOMPtr<nsISimpleEnumerator> arcsout; 1.176 + rv = ds->ArcLabelsOut(valueres, getter_AddRefs(arcsout)); 1.177 + if (NS_FAILED(rv)) return rv; 1.178 + 1.179 + while (1) { 1.180 + bool hasmore; 1.181 + rv = arcsout->HasMoreElements(&hasmore); 1.182 + if (NS_FAILED(rv)) return rv; 1.183 + 1.184 + if (! hasmore) 1.185 + break; 1.186 + 1.187 + nsCOMPtr<nsISupports> isupports; 1.188 + rv = arcsout->GetNext(getter_AddRefs(isupports)); 1.189 + if (NS_FAILED(rv)) return rv; 1.190 + 1.191 + nsCOMPtr<nsIRDFResource> property = do_QueryInterface(isupports); 1.192 + NS_ASSERTION(property != nullptr, "not a property"); 1.193 + if (! property) 1.194 + return NS_ERROR_UNEXPECTED; 1.195 + 1.196 + if (mProcessor->ContainmentProperties().Contains(property)) { 1.197 + container = eTrue; 1.198 + break; 1.199 + } 1.200 + } 1.201 + } 1.202 + } 1.203 + 1.204 + PR_LOG(gXULTemplateLog, PR_LOG_DEBUG, 1.205 + (" empty => %s", 1.206 + (empty == mEmpty) ? "consistent" : "inconsistent")); 1.207 + 1.208 + PR_LOG(gXULTemplateLog, PR_LOG_DEBUG, 1.209 + (" container => %s", 1.210 + (container == mContainer) ? "consistent" : "inconsistent")); 1.211 + 1.212 + if (((mEmpty == empty) && (mContainer == container)) || 1.213 + ((mEmpty == eDontCare) && (mContainer == container)) || 1.214 + ((mContainer == eDontCare) && (mEmpty == empty))) 1.215 + { 1.216 + Element* element = 1.217 + new nsRDFConInstanceTestNode::Element(valueres, container, empty); 1.218 + 1.219 + if (! element) 1.220 + return NS_ERROR_OUT_OF_MEMORY; 1.221 + 1.222 + inst->AddSupportingElement(element); 1.223 + } 1.224 + else { 1.225 + aInstantiations.Erase(inst--); 1.226 + } 1.227 + } 1.228 + } 1.229 + 1.230 + return NS_OK; 1.231 +} 1.232 + 1.233 +bool 1.234 +nsRDFConInstanceTestNode::CanPropagate(nsIRDFResource* aSource, 1.235 + nsIRDFResource* aProperty, 1.236 + nsIRDFNode* aTarget, 1.237 + Instantiation& aInitialBindings) const 1.238 +{ 1.239 + nsresult rv; 1.240 + 1.241 + bool canpropagate = false; 1.242 + 1.243 + nsCOMPtr<nsIRDFContainerUtils> rdfc 1.244 + = do_GetService("@mozilla.org/rdf/container-utils;1"); 1.245 + 1.246 + if (! rdfc) 1.247 + return false; 1.248 + 1.249 + // We can certainly propagate ordinal properties 1.250 + rv = rdfc->IsOrdinalProperty(aProperty, &canpropagate); 1.251 + if (NS_FAILED(rv)) return false; 1.252 + 1.253 + if (! canpropagate) { 1.254 + canpropagate = mProcessor->ContainmentProperties().Contains(aProperty); 1.255 + } 1.256 + 1.257 +#ifdef PR_LOGGING 1.258 + if (PR_LOG_TEST(gXULTemplateLog, PR_LOG_DEBUG)) { 1.259 + const char* source; 1.260 + aSource->GetValueConst(&source); 1.261 + 1.262 + const char* property; 1.263 + aProperty->GetValueConst(&property); 1.264 + 1.265 + nsAutoString target; 1.266 + nsXULContentUtils::GetTextForNode(aTarget, target); 1.267 + 1.268 + PR_LOG(gXULTemplateLog, PR_LOG_DEBUG, 1.269 + ("nsRDFConInstanceTestNode[%p]: CanPropagate([%s]==[%s]=>[%s]) => %s", 1.270 + this, source, property, NS_ConvertUTF16toUTF8(target).get(), 1.271 + canpropagate ? "true" : "false")); 1.272 + } 1.273 +#endif 1.274 + 1.275 + if (canpropagate) { 1.276 + aInitialBindings.AddAssignment(mContainerVariable, aSource); 1.277 + return true; 1.278 + } 1.279 + 1.280 + return false; 1.281 +} 1.282 + 1.283 +void 1.284 +nsRDFConInstanceTestNode::Retract(nsIRDFResource* aSource, 1.285 + nsIRDFResource* aProperty, 1.286 + nsIRDFNode* aTarget) const 1.287 +{ 1.288 + // XXXwaterson oof. complicated. figure this out. 1.289 + if (0) { 1.290 + mProcessor->RetractElement(Element(aSource, mContainer, mEmpty)); 1.291 + } 1.292 +} 1.293 +