|
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 "nsXULTemplateQueryProcessorRDF.h" |
|
7 #include "nsXULTemplateResultRDF.h" |
|
8 #include "nsRDFBinding.h" |
|
9 |
|
10 #ifdef DEBUG |
|
11 #include "nsXULContentUtils.h" |
|
12 #endif |
|
13 |
|
14 RDFBindingSet::~RDFBindingSet() |
|
15 { |
|
16 while (mFirst) { |
|
17 RDFBinding* doomed = mFirst; |
|
18 mFirst = mFirst->mNext; |
|
19 delete doomed; |
|
20 } |
|
21 |
|
22 MOZ_COUNT_DTOR(RDFBindingSet); |
|
23 } |
|
24 |
|
25 nsresult |
|
26 RDFBindingSet::AddBinding(nsIAtom* aVar, nsIAtom* aRef, nsIRDFResource* aPredicate) |
|
27 { |
|
28 RDFBinding* newbinding = new RDFBinding(aRef, aPredicate, aVar); |
|
29 if (! newbinding) |
|
30 return NS_ERROR_OUT_OF_MEMORY; |
|
31 |
|
32 if (mFirst) { |
|
33 RDFBinding* binding = mFirst; |
|
34 |
|
35 while (binding) { |
|
36 // the binding is dependant on the calculation of a previous binding |
|
37 if (binding->mSubjectVariable == aVar) |
|
38 newbinding->mHasDependency = true; |
|
39 |
|
40 // if the target variable is already used in a binding, ignore it |
|
41 // since it won't be useful for anything |
|
42 if (binding->mTargetVariable == aVar) { |
|
43 delete newbinding; |
|
44 return NS_OK; |
|
45 } |
|
46 |
|
47 // add the binding at the end of the list |
|
48 if (! binding->mNext) { |
|
49 binding->mNext = newbinding; |
|
50 break; |
|
51 } |
|
52 |
|
53 binding = binding->mNext; |
|
54 } |
|
55 } |
|
56 else { |
|
57 mFirst = newbinding; |
|
58 } |
|
59 |
|
60 mCount++; |
|
61 |
|
62 return NS_OK; |
|
63 } |
|
64 |
|
65 bool |
|
66 RDFBindingSet::SyncAssignments(nsIRDFResource* aSubject, |
|
67 nsIRDFResource* aPredicate, |
|
68 nsIRDFNode* aTarget, |
|
69 nsIAtom* aMemberVariable, |
|
70 nsXULTemplateResultRDF* aResult, |
|
71 nsBindingValues& aBindingValues) |
|
72 { |
|
73 NS_ASSERTION(aBindingValues.GetBindingSet() == this, |
|
74 "nsBindingValues not for this RDFBindingSet"); |
|
75 NS_PRECONDITION(aResult, "Must have result"); |
|
76 |
|
77 bool needSync = false; |
|
78 nsCOMPtr<nsIRDFNode>* valuesArray = aBindingValues.ValuesArray(); |
|
79 if (!valuesArray) |
|
80 return false; |
|
81 |
|
82 RDFBinding* binding = mFirst; |
|
83 int32_t count = 0; |
|
84 |
|
85 // QI for proper comparisons just to be safe |
|
86 nsCOMPtr<nsIRDFNode> subjectnode = do_QueryInterface(aSubject); |
|
87 |
|
88 // iterate through the bindings looking for ones that would match the RDF |
|
89 // nodes that were involved in a change |
|
90 nsCOMPtr<nsIRDFNode> value; |
|
91 while (binding) { |
|
92 if (aPredicate == binding->mPredicate) { |
|
93 // if the source of the binding is the member variable, optimize |
|
94 if (binding->mSubjectVariable == aMemberVariable) { |
|
95 valuesArray[count] = aTarget; |
|
96 needSync = true; |
|
97 } |
|
98 else { |
|
99 aResult->GetAssignment(binding->mSubjectVariable, getter_AddRefs(value)); |
|
100 if (value == subjectnode) { |
|
101 valuesArray[count] = aTarget; |
|
102 needSync = true; |
|
103 } |
|
104 } |
|
105 } |
|
106 |
|
107 binding = binding->mNext; |
|
108 count++; |
|
109 } |
|
110 |
|
111 return needSync; |
|
112 } |
|
113 |
|
114 void |
|
115 RDFBindingSet::AddDependencies(nsIRDFResource* aSubject, |
|
116 nsXULTemplateResultRDF* aResult) |
|
117 { |
|
118 NS_PRECONDITION(aResult, "Must have result"); |
|
119 |
|
120 // iterate through the bindings and add binding dependencies to the |
|
121 // processor |
|
122 |
|
123 nsXULTemplateQueryProcessorRDF* processor = aResult->GetProcessor(); |
|
124 if (! processor) |
|
125 return; |
|
126 |
|
127 nsCOMPtr<nsIRDFNode> value; |
|
128 |
|
129 RDFBinding* binding = mFirst; |
|
130 while (binding) { |
|
131 aResult->GetAssignment(binding->mSubjectVariable, getter_AddRefs(value)); |
|
132 |
|
133 nsCOMPtr<nsIRDFResource> valueres = do_QueryInterface(value); |
|
134 if (valueres) |
|
135 processor->AddBindingDependency(aResult, valueres); |
|
136 |
|
137 binding = binding->mNext; |
|
138 } |
|
139 } |
|
140 |
|
141 void |
|
142 RDFBindingSet::RemoveDependencies(nsIRDFResource* aSubject, |
|
143 nsXULTemplateResultRDF* aResult) |
|
144 { |
|
145 NS_PRECONDITION(aResult, "Must have result"); |
|
146 |
|
147 // iterate through the bindings and remove binding dependencies from the |
|
148 // processor |
|
149 |
|
150 nsXULTemplateQueryProcessorRDF* processor = aResult->GetProcessor(); |
|
151 if (! processor) |
|
152 return; |
|
153 |
|
154 nsCOMPtr<nsIRDFNode> value; |
|
155 |
|
156 RDFBinding* binding = mFirst; |
|
157 while (binding) { |
|
158 aResult->GetAssignment(binding->mSubjectVariable, getter_AddRefs(value)); |
|
159 |
|
160 nsCOMPtr<nsIRDFResource> valueres = do_QueryInterface(value); |
|
161 if (valueres) |
|
162 processor->RemoveBindingDependency(aResult, valueres); |
|
163 |
|
164 binding = binding->mNext; |
|
165 } |
|
166 } |
|
167 |
|
168 int32_t |
|
169 RDFBindingSet::LookupTargetIndex(nsIAtom* aTargetVariable, RDFBinding** aBinding) |
|
170 { |
|
171 int32_t idx = 0; |
|
172 RDFBinding* binding = mFirst; |
|
173 |
|
174 while (binding) { |
|
175 if (binding->mTargetVariable == aTargetVariable) { |
|
176 *aBinding = binding; |
|
177 return idx; |
|
178 } |
|
179 idx++; |
|
180 binding = binding->mNext; |
|
181 } |
|
182 |
|
183 return -1; |
|
184 } |
|
185 |
|
186 nsBindingValues::~nsBindingValues() |
|
187 { |
|
188 ClearBindingSet(); |
|
189 MOZ_COUNT_DTOR(nsBindingValues); |
|
190 } |
|
191 |
|
192 void |
|
193 nsBindingValues::ClearBindingSet() |
|
194 { |
|
195 if (mBindings && mValues) { |
|
196 delete [] mValues; |
|
197 mValues = nullptr; |
|
198 } |
|
199 |
|
200 mBindings = nullptr; |
|
201 } |
|
202 |
|
203 nsresult |
|
204 nsBindingValues::SetBindingSet(RDFBindingSet* aBindings) |
|
205 { |
|
206 ClearBindingSet(); |
|
207 |
|
208 int32_t count = aBindings->Count(); |
|
209 if (count) { |
|
210 mValues = new nsCOMPtr<nsIRDFNode>[count]; |
|
211 if (!mValues) |
|
212 return NS_ERROR_OUT_OF_MEMORY; |
|
213 |
|
214 mBindings = aBindings; |
|
215 } |
|
216 else { |
|
217 mValues = nullptr; |
|
218 } |
|
219 |
|
220 return NS_OK; |
|
221 } |
|
222 |
|
223 void |
|
224 nsBindingValues::GetAssignmentFor(nsXULTemplateResultRDF* aResult, |
|
225 nsIAtom* aVar, |
|
226 nsIRDFNode** aValue) |
|
227 { |
|
228 *aValue = nullptr; |
|
229 |
|
230 // assignments are calculated lazily when asked for. The only issue is |
|
231 // when a binding has no value in the RDF graph, it will be checked again |
|
232 // every time. |
|
233 |
|
234 if (mBindings && mValues) { |
|
235 RDFBinding* binding; |
|
236 int32_t idx = mBindings->LookupTargetIndex(aVar, &binding); |
|
237 if (idx >= 0) { |
|
238 *aValue = mValues[idx]; |
|
239 if (*aValue) { |
|
240 NS_ADDREF(*aValue); |
|
241 } |
|
242 else { |
|
243 nsXULTemplateQueryProcessorRDF* processor = aResult->GetProcessor(); |
|
244 if (! processor) |
|
245 return; |
|
246 |
|
247 nsIRDFDataSource* ds = processor->GetDataSource(); |
|
248 if (! ds) |
|
249 return; |
|
250 |
|
251 nsCOMPtr<nsIRDFNode> subjectValue; |
|
252 aResult->GetAssignment(binding->mSubjectVariable, |
|
253 getter_AddRefs(subjectValue)); |
|
254 if (subjectValue) { |
|
255 nsCOMPtr<nsIRDFResource> subject = do_QueryInterface(subjectValue); |
|
256 ds->GetTarget(subject, binding->mPredicate, true, aValue); |
|
257 if (*aValue) |
|
258 mValues[idx] = *aValue; |
|
259 } |
|
260 } |
|
261 } |
|
262 } |
|
263 } |
|
264 |
|
265 void |
|
266 nsBindingValues::RemoveDependencies(nsIRDFResource* aSubject, |
|
267 nsXULTemplateResultRDF* aResult) |
|
268 { |
|
269 if (mBindings) |
|
270 mBindings->RemoveDependencies(aSubject, aResult); |
|
271 } |