|
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 "nsRDFPropertyTestNode.h" |
|
7 #include "nsString.h" |
|
8 #include "nsXULContentUtils.h" |
|
9 |
|
10 #include "prlog.h" |
|
11 #ifdef PR_LOGGING |
|
12 extern PRLogModuleInfo* gXULTemplateLog; |
|
13 #include "nsIRDFLiteral.h" |
|
14 #endif |
|
15 |
|
16 nsRDFPropertyTestNode::nsRDFPropertyTestNode(TestNode* aParent, |
|
17 nsXULTemplateQueryProcessorRDF* aProcessor, |
|
18 nsIAtom* aSourceVariable, |
|
19 nsIRDFResource* aProperty, |
|
20 nsIAtom* aTargetVariable) |
|
21 : nsRDFTestNode(aParent), |
|
22 mProcessor(aProcessor), |
|
23 mSourceVariable(aSourceVariable), |
|
24 mSource(nullptr), |
|
25 mProperty(aProperty), |
|
26 mTargetVariable(aTargetVariable), |
|
27 mTarget(nullptr) |
|
28 { |
|
29 #ifdef PR_LOGGING |
|
30 if (PR_LOG_TEST(gXULTemplateLog, PR_LOG_DEBUG)) { |
|
31 const char* prop = "(null)"; |
|
32 if (aProperty) |
|
33 aProperty->GetValueConst(&prop); |
|
34 |
|
35 nsAutoString svar(NS_LITERAL_STRING("(none)")); |
|
36 if (mSourceVariable) |
|
37 mSourceVariable->ToString(svar); |
|
38 |
|
39 nsAutoString tvar(NS_LITERAL_STRING("(none)")); |
|
40 if (mTargetVariable) |
|
41 mTargetVariable->ToString(tvar); |
|
42 |
|
43 PR_LOG(gXULTemplateLog, PR_LOG_DEBUG, |
|
44 ("nsRDFPropertyTestNode[%p]: parent=%p source=%s property=%s target=%s", |
|
45 this, aParent, NS_ConvertUTF16toUTF8(svar).get(), prop, NS_ConvertUTF16toUTF8(tvar).get())); |
|
46 } |
|
47 #endif |
|
48 } |
|
49 |
|
50 |
|
51 nsRDFPropertyTestNode::nsRDFPropertyTestNode(TestNode* aParent, |
|
52 nsXULTemplateQueryProcessorRDF* aProcessor, |
|
53 nsIRDFResource* aSource, |
|
54 nsIRDFResource* aProperty, |
|
55 nsIAtom* aTargetVariable) |
|
56 : nsRDFTestNode(aParent), |
|
57 mProcessor(aProcessor), |
|
58 mSourceVariable(0), |
|
59 mSource(aSource), |
|
60 mProperty(aProperty), |
|
61 mTargetVariable(aTargetVariable), |
|
62 mTarget(nullptr) |
|
63 { |
|
64 #ifdef PR_LOGGING |
|
65 if (PR_LOG_TEST(gXULTemplateLog, PR_LOG_DEBUG)) { |
|
66 const char* source = "(null)"; |
|
67 if (aSource) |
|
68 aSource->GetValueConst(&source); |
|
69 |
|
70 const char* prop = "(null)"; |
|
71 if (aProperty) |
|
72 aProperty->GetValueConst(&prop); |
|
73 |
|
74 nsAutoString tvar(NS_LITERAL_STRING("(none)")); |
|
75 if (mTargetVariable) |
|
76 mTargetVariable->ToString(tvar); |
|
77 |
|
78 PR_LOG(gXULTemplateLog, PR_LOG_DEBUG, |
|
79 ("nsRDFPropertyTestNode[%p]: parent=%p source=%s property=%s target=%s", |
|
80 this, aParent, source, prop, NS_ConvertUTF16toUTF8(tvar).get())); |
|
81 } |
|
82 #endif |
|
83 } |
|
84 |
|
85 |
|
86 nsRDFPropertyTestNode::nsRDFPropertyTestNode(TestNode* aParent, |
|
87 nsXULTemplateQueryProcessorRDF* aProcessor, |
|
88 nsIAtom* aSourceVariable, |
|
89 nsIRDFResource* aProperty, |
|
90 nsIRDFNode* aTarget) |
|
91 : nsRDFTestNode(aParent), |
|
92 mProcessor(aProcessor), |
|
93 mSourceVariable(aSourceVariable), |
|
94 mSource(nullptr), |
|
95 mProperty(aProperty), |
|
96 mTargetVariable(0), |
|
97 mTarget(aTarget) |
|
98 { |
|
99 #ifdef PR_LOGGING |
|
100 if (PR_LOG_TEST(gXULTemplateLog, PR_LOG_DEBUG)) { |
|
101 nsAutoString svar(NS_LITERAL_STRING("(none)")); |
|
102 if (mSourceVariable) |
|
103 mSourceVariable->ToString(svar); |
|
104 |
|
105 const char* prop = "(null)"; |
|
106 if (aProperty) |
|
107 aProperty->GetValueConst(&prop); |
|
108 |
|
109 nsAutoString target; |
|
110 nsXULContentUtils::GetTextForNode(aTarget, target); |
|
111 |
|
112 PR_LOG(gXULTemplateLog, PR_LOG_DEBUG, |
|
113 ("nsRDFPropertyTestNode[%p]: parent=%p source=%s property=%s target=%s", |
|
114 this, aParent, NS_ConvertUTF16toUTF8(svar).get(), prop, NS_ConvertUTF16toUTF8(target).get())); |
|
115 } |
|
116 #endif |
|
117 } |
|
118 |
|
119 |
|
120 nsresult |
|
121 nsRDFPropertyTestNode::FilterInstantiations(InstantiationSet& aInstantiations, |
|
122 bool* aCantHandleYet) const |
|
123 { |
|
124 nsresult rv; |
|
125 |
|
126 if (aCantHandleYet) |
|
127 *aCantHandleYet = false; |
|
128 |
|
129 nsIRDFDataSource* ds = mProcessor->GetDataSource(); |
|
130 |
|
131 InstantiationSet::Iterator last = aInstantiations.Last(); |
|
132 for (InstantiationSet::Iterator inst = aInstantiations.First(); inst != last; ++inst) { |
|
133 bool hasSourceBinding; |
|
134 nsCOMPtr<nsIRDFResource> sourceRes; |
|
135 |
|
136 if (mSource) { |
|
137 hasSourceBinding = true; |
|
138 sourceRes = mSource; |
|
139 } |
|
140 else { |
|
141 nsCOMPtr<nsIRDFNode> sourceValue; |
|
142 hasSourceBinding = inst->mAssignments.GetAssignmentFor(mSourceVariable, |
|
143 getter_AddRefs(sourceValue)); |
|
144 sourceRes = do_QueryInterface(sourceValue); |
|
145 } |
|
146 |
|
147 bool hasTargetBinding; |
|
148 nsCOMPtr<nsIRDFNode> targetValue; |
|
149 |
|
150 if (mTarget) { |
|
151 hasTargetBinding = true; |
|
152 targetValue = mTarget; |
|
153 } |
|
154 else { |
|
155 hasTargetBinding = inst->mAssignments.GetAssignmentFor(mTargetVariable, |
|
156 getter_AddRefs(targetValue)); |
|
157 } |
|
158 |
|
159 #ifdef PR_LOGGING |
|
160 if (PR_LOG_TEST(gXULTemplateLog, PR_LOG_DEBUG)) { |
|
161 const char* source = "(unbound)"; |
|
162 if (hasSourceBinding) |
|
163 sourceRes->GetValueConst(&source); |
|
164 |
|
165 nsAutoString target(NS_LITERAL_STRING("(unbound)")); |
|
166 if (hasTargetBinding) |
|
167 nsXULContentUtils::GetTextForNode(targetValue, target); |
|
168 |
|
169 PR_LOG(gXULTemplateLog, PR_LOG_DEBUG, |
|
170 ("nsRDFPropertyTestNode[%p]: FilterInstantiations() source=[%s] target=[%s]", |
|
171 this, source, NS_ConvertUTF16toUTF8(target).get())); |
|
172 } |
|
173 #endif |
|
174 |
|
175 if (hasSourceBinding && hasTargetBinding) { |
|
176 // it's a consistency check. see if we have a assignment that is consistent |
|
177 bool hasAssertion; |
|
178 rv = ds->HasAssertion(sourceRes, mProperty, targetValue, |
|
179 true, &hasAssertion); |
|
180 if (NS_FAILED(rv)) return rv; |
|
181 |
|
182 #ifdef PR_LOGGING |
|
183 PR_LOG(gXULTemplateLog, PR_LOG_DEBUG, |
|
184 (" consistency check => %s", hasAssertion ? "passed" : "failed")); |
|
185 #endif |
|
186 |
|
187 if (hasAssertion) { |
|
188 // it's consistent. |
|
189 Element* element = |
|
190 new nsRDFPropertyTestNode::Element(sourceRes, mProperty, |
|
191 targetValue); |
|
192 |
|
193 if (! element) |
|
194 return NS_ERROR_OUT_OF_MEMORY; |
|
195 |
|
196 inst->AddSupportingElement(element); |
|
197 } |
|
198 else { |
|
199 // it's inconsistent. remove it. |
|
200 aInstantiations.Erase(inst--); |
|
201 } |
|
202 } |
|
203 else if ((hasSourceBinding && ! hasTargetBinding) || |
|
204 (! hasSourceBinding && hasTargetBinding)) { |
|
205 // it's an open ended query on the source or |
|
206 // target. figure out what matches and add as a |
|
207 // cross-product. |
|
208 nsCOMPtr<nsISimpleEnumerator> results; |
|
209 if (hasSourceBinding) { |
|
210 rv = ds->GetTargets(sourceRes, |
|
211 mProperty, |
|
212 true, |
|
213 getter_AddRefs(results)); |
|
214 } |
|
215 else { |
|
216 rv = ds->GetSources(mProperty, |
|
217 targetValue, |
|
218 true, |
|
219 getter_AddRefs(results)); |
|
220 if (NS_FAILED(rv)) return rv; |
|
221 } |
|
222 |
|
223 while (1) { |
|
224 bool hasMore; |
|
225 rv = results->HasMoreElements(&hasMore); |
|
226 if (NS_FAILED(rv)) return rv; |
|
227 |
|
228 if (! hasMore) |
|
229 break; |
|
230 |
|
231 nsCOMPtr<nsISupports> isupports; |
|
232 rv = results->GetNext(getter_AddRefs(isupports)); |
|
233 if (NS_FAILED(rv)) return rv; |
|
234 |
|
235 nsIAtom* variable; |
|
236 nsCOMPtr<nsIRDFNode> value; |
|
237 |
|
238 if (hasSourceBinding) { |
|
239 variable = mTargetVariable; |
|
240 |
|
241 value = do_QueryInterface(isupports); |
|
242 NS_ASSERTION(value != nullptr, "target is not an nsIRDFNode"); |
|
243 |
|
244 #ifdef PR_LOGGING |
|
245 if (PR_LOG_TEST(gXULTemplateLog, PR_LOG_DEBUG)) { |
|
246 nsAutoString s(NS_LITERAL_STRING("(none found)")); |
|
247 if (value) |
|
248 nsXULContentUtils::GetTextForNode(value, s); |
|
249 |
|
250 PR_LOG(gXULTemplateLog, PR_LOG_DEBUG, |
|
251 (" target => %s", NS_ConvertUTF16toUTF8(s).get())); |
|
252 } |
|
253 #endif |
|
254 |
|
255 if (! value) continue; |
|
256 |
|
257 targetValue = value; |
|
258 } |
|
259 else { |
|
260 variable = mSourceVariable; |
|
261 |
|
262 nsCOMPtr<nsIRDFResource> source = do_QueryInterface(isupports); |
|
263 NS_ASSERTION(source != nullptr, "source is not an nsIRDFResource"); |
|
264 |
|
265 #ifdef PR_LOGGING |
|
266 if (PR_LOG_TEST(gXULTemplateLog, PR_LOG_DEBUG)) { |
|
267 const char* s = "(none found)"; |
|
268 if (source) |
|
269 source->GetValueConst(&s); |
|
270 |
|
271 PR_LOG(gXULTemplateLog, PR_LOG_DEBUG, |
|
272 (" source => %s", s)); |
|
273 } |
|
274 #endif |
|
275 |
|
276 if (! source) continue; |
|
277 |
|
278 value = sourceRes = source; |
|
279 } |
|
280 |
|
281 // Copy the original instantiation, and add it to the |
|
282 // instantiation set with the new assignment that we've |
|
283 // introduced. Ownership will be transferred to the |
|
284 Instantiation newinst = *inst; |
|
285 newinst.AddAssignment(variable, value); |
|
286 |
|
287 Element* element = |
|
288 new nsRDFPropertyTestNode::Element(sourceRes, mProperty, |
|
289 targetValue); |
|
290 |
|
291 if (! element) |
|
292 return NS_ERROR_OUT_OF_MEMORY; |
|
293 |
|
294 newinst.AddSupportingElement(element); |
|
295 |
|
296 aInstantiations.Insert(inst, newinst); |
|
297 } |
|
298 |
|
299 // finally, remove the "under specified" instantiation. |
|
300 aInstantiations.Erase(inst--); |
|
301 } |
|
302 else { |
|
303 if (!aCantHandleYet) { |
|
304 nsXULContentUtils::LogTemplateError(ERROR_TEMPLATE_TRIPLE_UNBOUND); |
|
305 // Neither source nor target assignment! |
|
306 return NS_ERROR_UNEXPECTED; |
|
307 } |
|
308 |
|
309 *aCantHandleYet = true; |
|
310 return NS_OK; |
|
311 } |
|
312 } |
|
313 |
|
314 return NS_OK; |
|
315 } |
|
316 |
|
317 bool |
|
318 nsRDFPropertyTestNode::CanPropagate(nsIRDFResource* aSource, |
|
319 nsIRDFResource* aProperty, |
|
320 nsIRDFNode* aTarget, |
|
321 Instantiation& aInitialBindings) const |
|
322 { |
|
323 bool result; |
|
324 |
|
325 if ((mProperty.get() != aProperty) || |
|
326 (mSource && mSource.get() != aSource) || |
|
327 (mTarget && mTarget.get() != aTarget)) { |
|
328 result = false; |
|
329 } |
|
330 else { |
|
331 if (mSourceVariable) |
|
332 aInitialBindings.AddAssignment(mSourceVariable, aSource); |
|
333 |
|
334 if (mTargetVariable) |
|
335 aInitialBindings.AddAssignment(mTargetVariable, aTarget); |
|
336 |
|
337 result = true; |
|
338 } |
|
339 |
|
340 #ifdef PR_LOGGING |
|
341 if (PR_LOG_TEST(gXULTemplateLog, PR_LOG_DEBUG)) { |
|
342 const char* source; |
|
343 aSource->GetValueConst(&source); |
|
344 |
|
345 const char* property; |
|
346 aProperty->GetValueConst(&property); |
|
347 |
|
348 nsAutoString target; |
|
349 nsXULContentUtils::GetTextForNode(aTarget, target); |
|
350 |
|
351 PR_LOG(gXULTemplateLog, PR_LOG_DEBUG, |
|
352 ("nsRDFPropertyTestNode[%p]: CanPropagate([%s]==[%s]=>[%s]) => %s", |
|
353 this, source, property, NS_ConvertUTF16toUTF8(target).get(), |
|
354 result ? "true" : "false")); |
|
355 } |
|
356 #endif |
|
357 |
|
358 return result; |
|
359 } |
|
360 |
|
361 void |
|
362 nsRDFPropertyTestNode::Retract(nsIRDFResource* aSource, |
|
363 nsIRDFResource* aProperty, |
|
364 nsIRDFNode* aTarget) const |
|
365 { |
|
366 if (aProperty == mProperty.get()) { |
|
367 #ifdef PR_LOGGING |
|
368 if (PR_LOG_TEST(gXULTemplateLog, PR_LOG_DEBUG)) { |
|
369 const char* source; |
|
370 aSource->GetValueConst(&source); |
|
371 |
|
372 const char* property; |
|
373 aProperty->GetValueConst(&property); |
|
374 |
|
375 nsAutoString target; |
|
376 nsXULContentUtils::GetTextForNode(aTarget, target); |
|
377 |
|
378 PR_LOG(gXULTemplateLog, PR_LOG_DEBUG, |
|
379 ("nsRDFPropertyTestNode[%p]: Retract([%s]==[%s]=>[%s])", |
|
380 this, source, property, NS_ConvertUTF16toUTF8(target).get())); |
|
381 } |
|
382 #endif |
|
383 |
|
384 mProcessor->RetractElement(Element(aSource, aProperty, aTarget)); |
|
385 } |
|
386 } |
|
387 |