Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /* This Source Code Form is subject to the terms of the Mozilla Public
3 : * License, v. 2.0. If a copy of the MPL was not distributed with this
4 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 :
6 : #include "nsIComponentManager.h"
7 : #include "nsIRDFContainer.h"
8 : #include "nsIRDFContainerUtils.h"
9 : #include "nsIServiceManager.h"
10 : #include "nsRDFCID.h"
11 : #include "nsRDFConInstanceTestNode.h"
12 : #include "nsResourceSet.h"
13 :
14 : #include "mozilla/Logging.h"
15 : #include "nsXULContentUtils.h"
16 :
17 : using mozilla::LogLevel;
18 :
19 : extern mozilla::LazyLogModule gXULTemplateLog;
20 :
21 : static const char*
22 0 : TestToString(nsRDFConInstanceTestNode::Test aTest) {
23 0 : switch (aTest) {
24 0 : case nsRDFConInstanceTestNode::eFalse: return "false";
25 0 : case nsRDFConInstanceTestNode::eTrue: return "true";
26 0 : case nsRDFConInstanceTestNode::eDontCare: return "dontcare";
27 : }
28 0 : return "?";
29 : }
30 :
31 0 : nsRDFConInstanceTestNode::nsRDFConInstanceTestNode(TestNode* aParent,
32 : nsXULTemplateQueryProcessorRDF* aProcessor,
33 : nsIAtom* aContainerVariable,
34 : Test aContainer,
35 0 : Test aEmpty)
36 : : nsRDFTestNode(aParent),
37 : mProcessor(aProcessor),
38 : mContainerVariable(aContainerVariable),
39 : mContainer(aContainer),
40 0 : mEmpty(aEmpty)
41 : {
42 0 : if (MOZ_LOG_TEST(gXULTemplateLog, LogLevel::Debug)) {
43 0 : nsAutoCString props;
44 :
45 0 : nsResourceSet& containmentProps = aProcessor->ContainmentProperties();
46 0 : nsResourceSet::ConstIterator last = containmentProps.Last();
47 0 : nsResourceSet::ConstIterator first = containmentProps.First();
48 0 : nsResourceSet::ConstIterator iter;
49 :
50 0 : for (iter = first; iter != last; ++iter) {
51 0 : if (iter != first)
52 0 : props += " ";
53 :
54 : const char* str;
55 0 : iter->GetValueConst(&str);
56 :
57 0 : props += str;
58 : }
59 :
60 0 : nsAutoString cvar(NS_LITERAL_STRING("(none)"));
61 0 : if (mContainerVariable)
62 0 : mContainerVariable->ToString(cvar);
63 :
64 0 : MOZ_LOG(gXULTemplateLog, LogLevel::Debug,
65 : ("nsRDFConInstanceTestNode[%p]: parent=%p member-props=(%s) container-var=%s container=%s empty=%s",
66 : this,
67 : aParent,
68 : props.get(),
69 : NS_ConvertUTF16toUTF8(cvar).get(),
70 : TestToString(aContainer),
71 : TestToString(aEmpty)));
72 : }
73 0 : }
74 :
75 : nsresult
76 0 : nsRDFConInstanceTestNode::FilterInstantiations(InstantiationSet& aInstantiations,
77 : bool* aCantHandleYet) const
78 : {
79 : nsresult rv;
80 :
81 0 : if (aCantHandleYet)
82 0 : *aCantHandleYet = false;
83 :
84 : nsCOMPtr<nsIRDFContainerUtils> rdfc
85 0 : = do_GetService("@mozilla.org/rdf/container-utils;1");
86 :
87 0 : if (! rdfc)
88 0 : return NS_ERROR_FAILURE;
89 :
90 0 : nsIRDFDataSource* ds = mProcessor->GetDataSource();
91 :
92 0 : InstantiationSet::Iterator last = aInstantiations.Last();
93 0 : for (InstantiationSet::Iterator inst = aInstantiations.First(); inst != last; ++inst) {
94 0 : nsCOMPtr<nsIRDFNode> value;
95 0 : if (! inst->mAssignments.GetAssignmentFor(mContainerVariable, getter_AddRefs(value))) {
96 0 : NS_ERROR("can't do unbounded container testing");
97 0 : return NS_ERROR_UNEXPECTED;
98 : }
99 :
100 0 : nsCOMPtr<nsIRDFResource> valueres = do_QueryInterface(value);
101 0 : if (! valueres) {
102 0 : aInstantiations.Erase(inst--);
103 0 : continue;
104 : }
105 :
106 0 : if (MOZ_LOG_TEST(gXULTemplateLog, LogLevel::Debug)) {
107 0 : const char* container = "(unbound)";
108 0 : valueres->GetValueConst(&container);
109 :
110 0 : MOZ_LOG(gXULTemplateLog, LogLevel::Debug,
111 : ("nsRDFConInstanceTestNode[%p]::FilterInstantiations() container=[%s]",
112 : this, container));
113 : }
114 :
115 0 : nsCOMPtr<nsIRDFContainer> rdfcontainer;
116 :
117 : bool isRDFContainer;
118 0 : rv = rdfc->IsContainer(ds, valueres, &isRDFContainer);
119 0 : if (NS_FAILED(rv)) return rv;
120 :
121 0 : if (mEmpty != eDontCare || mContainer != eDontCare) {
122 0 : Test empty = eDontCare;
123 0 : Test container = eDontCare;
124 :
125 0 : if (isRDFContainer) {
126 : // It's an RDF container. Use the container utilities
127 : // to deduce what's in it.
128 0 : container = eTrue;
129 :
130 : // XXX should cache the factory
131 0 : rdfcontainer = do_CreateInstance("@mozilla.org/rdf/container;1", &rv);
132 0 : if (NS_FAILED(rv)) return rv;
133 :
134 0 : rv = rdfcontainer->Init(ds, valueres);
135 0 : if (NS_FAILED(rv)) return rv;
136 :
137 : int32_t count;
138 0 : rv = rdfcontainer->GetCount(&count);
139 0 : if (NS_FAILED(rv)) return rv;
140 :
141 0 : empty = (count == 0) ? eTrue : eFalse;
142 : } else {
143 0 : empty = eTrue;
144 0 : container = eFalse;
145 :
146 : // First do the simple check of finding some outward
147 : // arcs; there should be only a few containment arcs, so this can
148 : // save us time from dealing with an iterator later on
149 0 : nsResourceSet& containmentProps = mProcessor->ContainmentProperties();
150 0 : for (nsResourceSet::ConstIterator property = containmentProps.First();
151 0 : property != containmentProps.Last();
152 : ++property) {
153 0 : nsCOMPtr<nsIRDFNode> target;
154 0 : rv = ds->GetTarget(valueres, *property, true, getter_AddRefs(target));
155 0 : if (NS_FAILED(rv)) return rv;
156 :
157 0 : if (target != nullptr) {
158 : // bingo. we found one.
159 0 : empty = eFalse;
160 0 : container = eTrue;
161 0 : break;
162 : }
163 : }
164 :
165 : // if we still don't think its a container, but we
166 : // want to know for sure whether it is or not, we need
167 : // to check ArcLabelsOut for potential container arcs.
168 0 : if (container == eFalse && mContainer != eDontCare) {
169 0 : nsCOMPtr<nsISimpleEnumerator> arcsout;
170 0 : rv = ds->ArcLabelsOut(valueres, getter_AddRefs(arcsout));
171 0 : if (NS_FAILED(rv)) return rv;
172 :
173 : while (1) {
174 : bool hasmore;
175 0 : rv = arcsout->HasMoreElements(&hasmore);
176 0 : if (NS_FAILED(rv)) return rv;
177 :
178 0 : if (! hasmore)
179 0 : break;
180 :
181 0 : nsCOMPtr<nsISupports> isupports;
182 0 : rv = arcsout->GetNext(getter_AddRefs(isupports));
183 0 : if (NS_FAILED(rv)) return rv;
184 :
185 0 : nsCOMPtr<nsIRDFResource> property = do_QueryInterface(isupports);
186 0 : NS_ASSERTION(property != nullptr, "not a property");
187 0 : if (! property)
188 0 : return NS_ERROR_UNEXPECTED;
189 :
190 0 : if (mProcessor->ContainmentProperties().Contains(property)) {
191 0 : container = eTrue;
192 0 : break;
193 : }
194 0 : }
195 : }
196 : }
197 :
198 0 : MOZ_LOG(gXULTemplateLog, LogLevel::Debug,
199 : (" empty => %s",
200 : (empty == mEmpty) ? "consistent" : "inconsistent"));
201 :
202 0 : MOZ_LOG(gXULTemplateLog, LogLevel::Debug,
203 : (" container => %s",
204 : (container == mContainer) ? "consistent" : "inconsistent"));
205 :
206 0 : if (((mEmpty == empty) && (mContainer == container)) ||
207 0 : ((mEmpty == eDontCare) && (mContainer == container)) ||
208 0 : ((mContainer == eDontCare) && (mEmpty == empty)))
209 : {
210 : Element* element =
211 0 : new nsRDFConInstanceTestNode::Element(valueres, container, empty);
212 0 : inst->AddSupportingElement(element);
213 : }
214 : else {
215 0 : aInstantiations.Erase(inst--);
216 : }
217 : }
218 : }
219 :
220 0 : return NS_OK;
221 : }
222 :
223 : bool
224 0 : nsRDFConInstanceTestNode::CanPropagate(nsIRDFResource* aSource,
225 : nsIRDFResource* aProperty,
226 : nsIRDFNode* aTarget,
227 : Instantiation& aInitialBindings) const
228 : {
229 : nsresult rv;
230 :
231 0 : bool canpropagate = false;
232 :
233 : nsCOMPtr<nsIRDFContainerUtils> rdfc
234 0 : = do_GetService("@mozilla.org/rdf/container-utils;1");
235 :
236 0 : if (! rdfc)
237 0 : return false;
238 :
239 : // We can certainly propagate ordinal properties
240 0 : rv = rdfc->IsOrdinalProperty(aProperty, &canpropagate);
241 0 : if (NS_FAILED(rv)) return false;
242 :
243 0 : if (! canpropagate) {
244 0 : canpropagate = mProcessor->ContainmentProperties().Contains(aProperty);
245 : }
246 :
247 0 : if (MOZ_LOG_TEST(gXULTemplateLog, LogLevel::Debug)) {
248 : const char* source;
249 0 : aSource->GetValueConst(&source);
250 :
251 : const char* property;
252 0 : aProperty->GetValueConst(&property);
253 :
254 0 : nsAutoString target;
255 0 : nsXULContentUtils::GetTextForNode(aTarget, target);
256 :
257 0 : MOZ_LOG(gXULTemplateLog, LogLevel::Debug,
258 : ("nsRDFConInstanceTestNode[%p]: CanPropagate([%s]==[%s]=>[%s]) => %s",
259 : this, source, property, NS_ConvertUTF16toUTF8(target).get(),
260 : canpropagate ? "true" : "false"));
261 : }
262 :
263 0 : if (canpropagate) {
264 0 : aInitialBindings.AddAssignment(mContainerVariable, aSource);
265 0 : return true;
266 : }
267 :
268 0 : return false;
269 : }
270 :
271 : void
272 0 : nsRDFConInstanceTestNode::Retract(nsIRDFResource* aSource,
273 : nsIRDFResource* aProperty,
274 : nsIRDFNode* aTarget) const
275 : {
276 : // XXXwaterson oof. complicated. figure this out.
277 : if (0) {
278 : mProcessor->RetractElement(Element(aSource, mContainer, mEmpty));
279 : }
280 0 : }
281 :
|