content/xul/templates/src/nsRDFConInstanceTestNode.cpp

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

mercurial