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