1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /* ***** BEGIN LICENSE BLOCK *****
3 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 : *
5 : * The contents of this file are subject to the Mozilla Public License Version
6 : * 1.1 (the "License"); you may not use this file except in compliance with
7 : * the License. You may obtain a copy of the License at
8 : * http://www.mozilla.org/MPL/
9 : *
10 : * Software distributed under the License is distributed on an "AS IS" basis,
11 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 : * for the specific language governing rights and limitations under the
13 : * License.
14 : *
15 : * The Original Code is Mozilla Communicator client code.
16 : *
17 : * The Initial Developer of the Original Code is
18 : * Netscape Communications Corporation.
19 : * Portions created by the Initial Developer are Copyright (C) 1998
20 : * the Initial Developer. All Rights Reserved.
21 : *
22 : * Contributor(s):
23 : * Chris Waterson <waterson@netscape.com>
24 : *
25 : * Alternatively, the contents of this file may be used under the terms of
26 : * either of the GNU General Public License Version 2 or later (the "GPL"),
27 : * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28 : * in which case the provisions of the GPL or the LGPL are applicable instead
29 : * of those above. If you wish to allow use of your version of this file only
30 : * under the terms of either the GPL or the LGPL, and not to allow others to
31 : * use your version of this file under the terms of the MPL, indicate your
32 : * decision by deleting the provisions above and replace them with the notice
33 : * and other provisions required by the GPL or the LGPL. If you do not delete
34 : * the provisions above, a recipient may use your version of this file under
35 : * the terms of any one of the MPL, the GPL or the LGPL.
36 : *
37 : * ***** END LICENSE BLOCK ***** */
38 :
39 : #include "nsIComponentManager.h"
40 : #include "nsIRDFContainer.h"
41 : #include "nsIRDFContainerUtils.h"
42 : #include "nsIServiceManager.h"
43 : #include "nsRDFCID.h"
44 : #include "nsRDFConInstanceTestNode.h"
45 : #include "nsResourceSet.h"
46 :
47 : #include "prlog.h"
48 : #ifdef PR_LOGGING
49 : #include "nsXULContentUtils.h"
50 : extern PRLogModuleInfo* gXULTemplateLog;
51 :
52 : static const char*
53 0 : TestToString(nsRDFConInstanceTestNode::Test aTest) {
54 0 : switch (aTest) {
55 0 : case nsRDFConInstanceTestNode::eFalse: return "false";
56 0 : case nsRDFConInstanceTestNode::eTrue: return "true";
57 0 : case nsRDFConInstanceTestNode::eDontCare: return "dontcare";
58 : }
59 0 : return "?";
60 : }
61 : #endif
62 :
63 0 : nsRDFConInstanceTestNode::nsRDFConInstanceTestNode(TestNode* aParent,
64 : nsXULTemplateQueryProcessorRDF* aProcessor,
65 : nsIAtom* aContainerVariable,
66 : Test aContainer,
67 : Test aEmpty)
68 : : nsRDFTestNode(aParent),
69 : mProcessor(aProcessor),
70 : mContainerVariable(aContainerVariable),
71 : mContainer(aContainer),
72 0 : mEmpty(aEmpty)
73 : {
74 : #ifdef PR_LOGGING
75 0 : if (PR_LOG_TEST(gXULTemplateLog, PR_LOG_DEBUG)) {
76 0 : nsCAutoString props;
77 :
78 0 : nsResourceSet& containmentProps = aProcessor->ContainmentProperties();
79 0 : nsResourceSet::ConstIterator last = containmentProps.Last();
80 0 : nsResourceSet::ConstIterator first = containmentProps.First();
81 0 : nsResourceSet::ConstIterator iter;
82 :
83 0 : for (iter = first; iter != last; ++iter) {
84 0 : if (iter != first)
85 0 : props += " ";
86 :
87 : const char* str;
88 0 : iter->GetValueConst(&str);
89 :
90 0 : props += str;
91 : }
92 :
93 0 : nsAutoString cvar(NS_LITERAL_STRING("(none)"));
94 0 : if (mContainerVariable)
95 0 : mContainerVariable->ToString(cvar);
96 :
97 0 : PR_LOG(gXULTemplateLog, PR_LOG_DEBUG,
98 : ("nsRDFConInstanceTestNode[%p]: parent=%p member-props=(%s) container-var=%s container=%s empty=%s",
99 : this,
100 : aParent,
101 : props.get(),
102 : NS_ConvertUTF16toUTF8(cvar).get(),
103 : TestToString(aContainer),
104 : TestToString(aEmpty)));
105 : }
106 : #endif
107 0 : }
108 :
109 : nsresult
110 0 : nsRDFConInstanceTestNode::FilterInstantiations(InstantiationSet& aInstantiations,
111 : bool* aCantHandleYet) const
112 : {
113 : nsresult rv;
114 :
115 0 : if (aCantHandleYet)
116 0 : *aCantHandleYet = false;
117 :
118 : nsCOMPtr<nsIRDFContainerUtils> rdfc
119 0 : = do_GetService("@mozilla.org/rdf/container-utils;1");
120 :
121 0 : if (! rdfc)
122 0 : return NS_ERROR_FAILURE;
123 :
124 0 : nsIRDFDataSource* ds = mProcessor->GetDataSource();
125 :
126 0 : InstantiationSet::Iterator last = aInstantiations.Last();
127 0 : for (InstantiationSet::Iterator inst = aInstantiations.First(); inst != last; ++inst) {
128 0 : nsCOMPtr<nsIRDFNode> value;
129 0 : if (! inst->mAssignments.GetAssignmentFor(mContainerVariable, getter_AddRefs(value))) {
130 0 : NS_ERROR("can't do unbounded container testing");
131 0 : return NS_ERROR_UNEXPECTED;
132 : }
133 :
134 0 : nsCOMPtr<nsIRDFResource> valueres = do_QueryInterface(value);
135 0 : if (! valueres) {
136 0 : aInstantiations.Erase(inst--);
137 0 : continue;
138 : }
139 :
140 : #ifdef PR_LOGGING
141 0 : if (PR_LOG_TEST(gXULTemplateLog, PR_LOG_DEBUG)) {
142 0 : const char* container = "(unbound)";
143 0 : valueres->GetValueConst(&container);
144 :
145 0 : PR_LOG(gXULTemplateLog, PR_LOG_DEBUG,
146 : ("nsRDFConInstanceTestNode[%p]::FilterInstantiations() container=[%s]",
147 : this, container));
148 : }
149 : #endif
150 :
151 0 : nsCOMPtr<nsIRDFContainer> rdfcontainer;
152 :
153 : bool isRDFContainer;
154 0 : rv = rdfc->IsContainer(ds, valueres, &isRDFContainer);
155 0 : if (NS_FAILED(rv)) return rv;
156 :
157 0 : if (mEmpty != eDontCare || mContainer != eDontCare) {
158 0 : Test empty = eDontCare;
159 0 : Test container = eDontCare;
160 :
161 0 : if (isRDFContainer) {
162 : // It's an RDF container. Use the container utilities
163 : // to deduce what's in it.
164 0 : container = eTrue;
165 :
166 : // XXX should cache the factory
167 0 : rdfcontainer = do_CreateInstance("@mozilla.org/rdf/container;1", &rv);
168 0 : if (NS_FAILED(rv)) return rv;
169 :
170 0 : rv = rdfcontainer->Init(ds, valueres);
171 0 : if (NS_FAILED(rv)) return rv;
172 :
173 : PRInt32 count;
174 0 : rv = rdfcontainer->GetCount(&count);
175 0 : if (NS_FAILED(rv)) return rv;
176 :
177 0 : empty = (count == 0) ? eTrue : eFalse;
178 : } else {
179 0 : empty = eTrue;
180 0 : container = eFalse;
181 :
182 : // First do the simple check of finding some outward
183 : // arcs; there should be only a few containment arcs, so this can
184 : // save us time from dealing with an iterator later on
185 0 : nsResourceSet& containmentProps = mProcessor->ContainmentProperties();
186 0 : for (nsResourceSet::ConstIterator property = containmentProps.First();
187 0 : property != containmentProps.Last();
188 : ++property) {
189 0 : nsCOMPtr<nsIRDFNode> target;
190 0 : rv = ds->GetTarget(valueres, *property, true, getter_AddRefs(target));
191 0 : if (NS_FAILED(rv)) return rv;
192 :
193 0 : if (target != nsnull) {
194 : // bingo. we found one.
195 0 : empty = eFalse;
196 0 : container = eTrue;
197 : break;
198 : }
199 : }
200 :
201 : // if we still don't think its a container, but we
202 : // want to know for sure whether it is or not, we need
203 : // to check ArcLabelsOut for potential container arcs.
204 0 : if (container == eFalse && mContainer != eDontCare) {
205 0 : nsCOMPtr<nsISimpleEnumerator> arcsout;
206 0 : rv = ds->ArcLabelsOut(valueres, getter_AddRefs(arcsout));
207 0 : if (NS_FAILED(rv)) return rv;
208 :
209 0 : while (1) {
210 : bool hasmore;
211 0 : rv = arcsout->HasMoreElements(&hasmore);
212 0 : if (NS_FAILED(rv)) return rv;
213 :
214 0 : if (! hasmore)
215 0 : break;
216 :
217 0 : nsCOMPtr<nsISupports> isupports;
218 0 : rv = arcsout->GetNext(getter_AddRefs(isupports));
219 0 : if (NS_FAILED(rv)) return rv;
220 :
221 0 : nsCOMPtr<nsIRDFResource> property = do_QueryInterface(isupports);
222 0 : NS_ASSERTION(property != nsnull, "not a property");
223 0 : if (! property)
224 0 : return NS_ERROR_UNEXPECTED;
225 :
226 0 : if (mProcessor->ContainmentProperties().Contains(property)) {
227 0 : container = eTrue;
228 : break;
229 : }
230 : }
231 : }
232 : }
233 :
234 0 : PR_LOG(gXULTemplateLog, PR_LOG_DEBUG,
235 : (" empty => %s",
236 : (empty == mEmpty) ? "consistent" : "inconsistent"));
237 :
238 0 : PR_LOG(gXULTemplateLog, PR_LOG_DEBUG,
239 : (" container => %s",
240 : (container == mContainer) ? "consistent" : "inconsistent"));
241 :
242 0 : if (((mEmpty == empty) && (mContainer == container)) ||
243 : ((mEmpty == eDontCare) && (mContainer == container)) ||
244 : ((mContainer == eDontCare) && (mEmpty == empty)))
245 : {
246 : Element* element =
247 0 : nsRDFConInstanceTestNode::Element::Create(valueres, container, empty);
248 :
249 0 : if (! element)
250 0 : return NS_ERROR_OUT_OF_MEMORY;
251 :
252 0 : inst->AddSupportingElement(element);
253 : }
254 : else {
255 0 : aInstantiations.Erase(inst--);
256 : }
257 : }
258 : }
259 :
260 0 : return NS_OK;
261 : }
262 :
263 : bool
264 0 : nsRDFConInstanceTestNode::CanPropagate(nsIRDFResource* aSource,
265 : nsIRDFResource* aProperty,
266 : nsIRDFNode* aTarget,
267 : Instantiation& aInitialBindings) const
268 : {
269 : nsresult rv;
270 :
271 0 : bool canpropagate = false;
272 :
273 : nsCOMPtr<nsIRDFContainerUtils> rdfc
274 0 : = do_GetService("@mozilla.org/rdf/container-utils;1");
275 :
276 0 : if (! rdfc)
277 0 : return false;
278 :
279 : // We can certainly propagate ordinal properties
280 0 : rv = rdfc->IsOrdinalProperty(aProperty, &canpropagate);
281 0 : if (NS_FAILED(rv)) return false;
282 :
283 0 : if (! canpropagate) {
284 0 : canpropagate = mProcessor->ContainmentProperties().Contains(aProperty);
285 : }
286 :
287 : #ifdef PR_LOGGING
288 0 : if (PR_LOG_TEST(gXULTemplateLog, PR_LOG_DEBUG)) {
289 : const char* source;
290 0 : aSource->GetValueConst(&source);
291 :
292 : const char* property;
293 0 : aProperty->GetValueConst(&property);
294 :
295 0 : nsAutoString target;
296 0 : nsXULContentUtils::GetTextForNode(aTarget, target);
297 :
298 0 : PR_LOG(gXULTemplateLog, PR_LOG_DEBUG,
299 : ("nsRDFConInstanceTestNode[%p]: CanPropagate([%s]==[%s]=>[%s]) => %s",
300 : this, source, property, NS_ConvertUTF16toUTF8(target).get(),
301 : canpropagate ? "true" : "false"));
302 : }
303 : #endif
304 :
305 0 : if (canpropagate) {
306 0 : aInitialBindings.AddAssignment(mContainerVariable, aSource);
307 0 : return true;
308 : }
309 :
310 0 : return false;
311 : }
312 :
313 : void
314 0 : nsRDFConInstanceTestNode::Retract(nsIRDFResource* aSource,
315 : nsIRDFResource* aProperty,
316 : nsIRDFNode* aTarget) const
317 : {
318 : // XXXwaterson oof. complicated. figure this out.
319 : if (0) {
320 : mProcessor->RetractElement(Element(aSource, mContainer, mEmpty));
321 : }
322 0 : }
323 :
|