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.org code.
16 : *
17 : * The Initial Developer of the Original Code is Neil Deakin
18 : * Portions created by the Initial Developer are Copyright (C) 2005
19 : * the Initial Developer. All Rights Reserved.
20 : *
21 : * Contributor(s):
22 : *
23 : * Alternatively, the contents of this file may be used under the terms of
24 : * either of the GNU General Public License Version 2 or later (the "GPL"),
25 : * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
26 : * in which case the provisions of the GPL or the LGPL are applicable instead
27 : * of those above. If you wish to allow use of your version of this file only
28 : * under the terms of either the GPL or the LGPL, and not to allow others to
29 : * use your version of this file under the terms of the MPL, indicate your
30 : * decision by deleting the provisions above and replace them with the notice
31 : * and other provisions required by the GPL or the LGPL. If you do not delete
32 : * the provisions above, a recipient may use your version of this file under
33 : * the terms of any one of the MPL, the GPL or the LGPL.
34 : *
35 : * ***** END LICENSE BLOCK ***** */
36 :
37 : #include "nsXULTemplateQueryProcessorRDF.h"
38 : #include "nsXULTemplateResultRDF.h"
39 : #include "nsRDFBinding.h"
40 :
41 : #ifdef DEBUG
42 : #include "nsXULContentUtils.h"
43 : #endif
44 :
45 0 : RDFBindingSet::~RDFBindingSet()
46 : {
47 0 : while (mFirst) {
48 0 : RDFBinding* doomed = mFirst;
49 0 : mFirst = mFirst->mNext;
50 0 : delete doomed;
51 : }
52 :
53 0 : MOZ_COUNT_DTOR(RDFBindingSet);
54 0 : }
55 :
56 : nsresult
57 0 : RDFBindingSet::AddBinding(nsIAtom* aVar, nsIAtom* aRef, nsIRDFResource* aPredicate)
58 : {
59 0 : RDFBinding* newbinding = new RDFBinding(aRef, aPredicate, aVar);
60 0 : if (! newbinding)
61 0 : return NS_ERROR_OUT_OF_MEMORY;
62 :
63 0 : if (mFirst) {
64 0 : RDFBinding* binding = mFirst;
65 :
66 0 : while (binding) {
67 : // the binding is dependant on the calculation of a previous binding
68 0 : if (binding->mSubjectVariable == aVar)
69 0 : newbinding->mHasDependency = true;
70 :
71 : // if the target variable is already used in a binding, ignore it
72 : // since it won't be useful for anything
73 0 : if (binding->mTargetVariable == aVar) {
74 0 : delete newbinding;
75 0 : return NS_OK;
76 : }
77 :
78 : // add the binding at the end of the list
79 0 : if (! binding->mNext) {
80 0 : binding->mNext = newbinding;
81 0 : break;
82 : }
83 :
84 0 : binding = binding->mNext;
85 : }
86 : }
87 : else {
88 0 : mFirst = newbinding;
89 : }
90 :
91 0 : mCount++;
92 :
93 0 : return NS_OK;
94 : }
95 :
96 : bool
97 0 : RDFBindingSet::SyncAssignments(nsIRDFResource* aSubject,
98 : nsIRDFResource* aPredicate,
99 : nsIRDFNode* aTarget,
100 : nsIAtom* aMemberVariable,
101 : nsXULTemplateResultRDF* aResult,
102 : nsBindingValues& aBindingValues)
103 : {
104 0 : NS_ASSERTION(aBindingValues.GetBindingSet() == this,
105 : "nsBindingValues not for this RDFBindingSet");
106 0 : NS_PRECONDITION(aResult, "Must have result");
107 :
108 0 : bool needSync = false;
109 0 : nsCOMPtr<nsIRDFNode>* valuesArray = aBindingValues.ValuesArray();
110 0 : if (!valuesArray)
111 0 : return false;
112 :
113 0 : RDFBinding* binding = mFirst;
114 0 : PRInt32 count = 0;
115 :
116 : // QI for proper comparisons just to be safe
117 0 : nsCOMPtr<nsIRDFNode> subjectnode = do_QueryInterface(aSubject);
118 :
119 : // iterate through the bindings looking for ones that would match the RDF
120 : // nodes that were involved in a change
121 0 : nsCOMPtr<nsIRDFNode> value;
122 0 : while (binding) {
123 0 : if (aPredicate == binding->mPredicate) {
124 : // if the source of the binding is the member variable, optimize
125 0 : if (binding->mSubjectVariable == aMemberVariable) {
126 0 : valuesArray[count] = aTarget;
127 0 : needSync = true;
128 : }
129 : else {
130 0 : aResult->GetAssignment(binding->mSubjectVariable, getter_AddRefs(value));
131 0 : if (value == subjectnode) {
132 0 : valuesArray[count] = aTarget;
133 0 : needSync = true;
134 : }
135 : }
136 : }
137 :
138 0 : binding = binding->mNext;
139 0 : count++;
140 : }
141 :
142 0 : return needSync;
143 : }
144 :
145 : void
146 0 : RDFBindingSet::AddDependencies(nsIRDFResource* aSubject,
147 : nsXULTemplateResultRDF* aResult)
148 : {
149 0 : NS_PRECONDITION(aResult, "Must have result");
150 :
151 : // iterate through the bindings and add binding dependencies to the
152 : // processor
153 :
154 0 : nsXULTemplateQueryProcessorRDF* processor = aResult->GetProcessor();
155 0 : if (! processor)
156 0 : return;
157 :
158 0 : nsCOMPtr<nsIRDFNode> value;
159 :
160 0 : RDFBinding* binding = mFirst;
161 0 : while (binding) {
162 0 : aResult->GetAssignment(binding->mSubjectVariable, getter_AddRefs(value));
163 :
164 0 : nsCOMPtr<nsIRDFResource> valueres = do_QueryInterface(value);
165 0 : if (valueres)
166 0 : processor->AddBindingDependency(aResult, valueres);
167 :
168 0 : binding = binding->mNext;
169 : }
170 : }
171 :
172 : void
173 0 : RDFBindingSet::RemoveDependencies(nsIRDFResource* aSubject,
174 : nsXULTemplateResultRDF* aResult)
175 : {
176 0 : NS_PRECONDITION(aResult, "Must have result");
177 :
178 : // iterate through the bindings and remove binding dependencies from the
179 : // processor
180 :
181 0 : nsXULTemplateQueryProcessorRDF* processor = aResult->GetProcessor();
182 0 : if (! processor)
183 0 : return;
184 :
185 0 : nsCOMPtr<nsIRDFNode> value;
186 :
187 0 : RDFBinding* binding = mFirst;
188 0 : while (binding) {
189 0 : aResult->GetAssignment(binding->mSubjectVariable, getter_AddRefs(value));
190 :
191 0 : nsCOMPtr<nsIRDFResource> valueres = do_QueryInterface(value);
192 0 : if (valueres)
193 0 : processor->RemoveBindingDependency(aResult, valueres);
194 :
195 0 : binding = binding->mNext;
196 : }
197 : }
198 :
199 : PRInt32
200 0 : RDFBindingSet::LookupTargetIndex(nsIAtom* aTargetVariable, RDFBinding** aBinding)
201 : {
202 0 : PRInt32 idx = 0;
203 0 : RDFBinding* binding = mFirst;
204 :
205 0 : while (binding) {
206 0 : if (binding->mTargetVariable == aTargetVariable) {
207 0 : *aBinding = binding;
208 0 : return idx;
209 : }
210 0 : idx++;
211 0 : binding = binding->mNext;
212 : }
213 :
214 0 : return -1;
215 : }
216 :
217 0 : nsBindingValues::~nsBindingValues()
218 : {
219 0 : ClearBindingSet();
220 0 : MOZ_COUNT_DTOR(nsBindingValues);
221 0 : }
222 :
223 : void
224 0 : nsBindingValues::ClearBindingSet()
225 : {
226 0 : if (mBindings && mValues) {
227 0 : delete [] mValues;
228 0 : mValues = nsnull;
229 : }
230 :
231 0 : mBindings = nsnull;
232 0 : }
233 :
234 : nsresult
235 0 : nsBindingValues::SetBindingSet(RDFBindingSet* aBindings)
236 : {
237 0 : ClearBindingSet();
238 :
239 0 : PRInt32 count = aBindings->Count();
240 0 : if (count) {
241 0 : mValues = new nsCOMPtr<nsIRDFNode>[count];
242 0 : if (!mValues)
243 0 : return NS_ERROR_OUT_OF_MEMORY;
244 :
245 0 : mBindings = aBindings;
246 : }
247 : else {
248 0 : mValues = nsnull;
249 : }
250 :
251 0 : return NS_OK;
252 : }
253 :
254 : void
255 0 : nsBindingValues::GetAssignmentFor(nsXULTemplateResultRDF* aResult,
256 : nsIAtom* aVar,
257 : nsIRDFNode** aValue)
258 : {
259 0 : *aValue = nsnull;
260 :
261 : // assignments are calculated lazily when asked for. The only issue is
262 : // when a binding has no value in the RDF graph, it will be checked again
263 : // every time.
264 :
265 0 : if (mBindings && mValues) {
266 : RDFBinding* binding;
267 0 : PRInt32 idx = mBindings->LookupTargetIndex(aVar, &binding);
268 0 : if (idx >= 0) {
269 0 : *aValue = mValues[idx];
270 0 : if (*aValue) {
271 0 : NS_ADDREF(*aValue);
272 : }
273 : else {
274 0 : nsXULTemplateQueryProcessorRDF* processor = aResult->GetProcessor();
275 0 : if (! processor)
276 0 : return;
277 :
278 0 : nsIRDFDataSource* ds = processor->GetDataSource();
279 0 : if (! ds)
280 0 : return;
281 :
282 0 : nsCOMPtr<nsIRDFNode> subjectValue;
283 : aResult->GetAssignment(binding->mSubjectVariable,
284 0 : getter_AddRefs(subjectValue));
285 0 : if (subjectValue) {
286 0 : nsCOMPtr<nsIRDFResource> subject = do_QueryInterface(subjectValue);
287 0 : ds->GetTarget(subject, binding->mPredicate, true, aValue);
288 0 : if (*aValue)
289 0 : mValues[idx] = *aValue;
290 : }
291 : }
292 : }
293 : }
294 : }
295 :
296 : void
297 0 : nsBindingValues::RemoveDependencies(nsIRDFResource* aSubject,
298 : nsXULTemplateResultRDF* aResult)
299 : {
300 0 : if (mBindings)
301 0 : mBindings->RemoveDependencies(aSubject, aResult);
302 0 : }
|