|
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 #ifndef nsTemplateRule_h__ |
|
7 #define nsTemplateRule_h__ |
|
8 |
|
9 #include "nsCOMPtr.h" |
|
10 #include "nsIAtom.h" |
|
11 #include "nsIRDFDataSource.h" |
|
12 #include "nsIRDFResource.h" |
|
13 #include "nsIContent.h" |
|
14 #include "nsIDOMNode.h" |
|
15 #include "nsTArray.h" |
|
16 #include "nsString.h" |
|
17 #include "nsIXULTemplateRuleFilter.h" |
|
18 #include "nsCycleCollectionParticipant.h" |
|
19 |
|
20 class nsIXULTemplateQueryProcessor; |
|
21 class nsTemplateQuerySet; |
|
22 |
|
23 class nsTemplateCondition |
|
24 { |
|
25 public: |
|
26 // relations that may be used in a rule. They may be negated with the |
|
27 // negate flag. Less and Greater are used for numeric comparisons and |
|
28 // Before and After are used for string comparisons. For Less, Greater, |
|
29 // Before, After, Startswith, Endswith, and Contains, the source is |
|
30 // conceptually on the left of the relation and the target is on the |
|
31 // right. For example, if the relation is Contains, that means Match if |
|
32 // the source contains the target. |
|
33 enum ConditionRelation { |
|
34 eUnknown, |
|
35 eEquals, |
|
36 eLess, |
|
37 eGreater, |
|
38 eBefore, |
|
39 eAfter, |
|
40 eStartswith, |
|
41 eEndswith, |
|
42 eContains |
|
43 }; |
|
44 |
|
45 nsTemplateCondition(nsIAtom* aSourceVariable, |
|
46 const nsAString& aRelation, |
|
47 nsIAtom* aTargetVariable, |
|
48 bool mIgnoreCase, |
|
49 bool mNegate); |
|
50 |
|
51 nsTemplateCondition(nsIAtom* aSourceVariable, |
|
52 const nsAString& aRelation, |
|
53 const nsAString& aTargets, |
|
54 bool mIgnoreCase, |
|
55 bool mNegate, |
|
56 bool aIsMultiple); |
|
57 |
|
58 nsTemplateCondition(const nsAString& aSource, |
|
59 const nsAString& aRelation, |
|
60 nsIAtom* aTargetVariable, |
|
61 bool mIgnoreCase, |
|
62 bool mNegate); |
|
63 |
|
64 ~nsTemplateCondition() { MOZ_COUNT_DTOR(nsTemplateCondition); } |
|
65 |
|
66 nsTemplateCondition* GetNext() { return mNext; } |
|
67 void SetNext(nsTemplateCondition* aNext) { mNext = aNext; } |
|
68 |
|
69 void SetRelation(const nsAString& aRelation); |
|
70 |
|
71 bool |
|
72 CheckMatch(nsIXULTemplateResult* aResult); |
|
73 |
|
74 bool |
|
75 CheckMatchStrings(const nsAString& aLeftString, |
|
76 const nsAString& aRightString); |
|
77 protected: |
|
78 |
|
79 nsCOMPtr<nsIAtom> mSourceVariable; |
|
80 nsString mSource; |
|
81 ConditionRelation mRelation; |
|
82 nsCOMPtr<nsIAtom> mTargetVariable; |
|
83 nsTArray<nsString> mTargetList; |
|
84 bool mIgnoreCase; |
|
85 bool mNegate; |
|
86 |
|
87 nsTemplateCondition* mNext; |
|
88 }; |
|
89 |
|
90 /** |
|
91 * A rule consists of: |
|
92 * |
|
93 * - Conditions, a set of unbound variables with consistency |
|
94 * constraints that specify the values that each variable can |
|
95 * assume. The conditions must be completely and consistently |
|
96 * "bound" for the rule to be considered "matched". |
|
97 * |
|
98 * - Bindings, a set of unbound variables with consistency constraints |
|
99 * that specify the values that each variable can assume. Unlike the |
|
100 * conditions, the bindings need not be bound for the rule to be |
|
101 * considered matched. |
|
102 * |
|
103 * - Content that should be constructed when the rule is "activated". |
|
104 * |
|
105 */ |
|
106 class nsTemplateRule |
|
107 { |
|
108 public: |
|
109 nsTemplateRule(nsIContent* aRuleNode, |
|
110 nsIContent* aAction, |
|
111 nsTemplateQuerySet* aQuerySet); |
|
112 /** |
|
113 * The copy-constructor should only be called from nsTArray when appending |
|
114 * a new rule, otherwise things break because the copy constructor expects |
|
115 * mBindings and mConditions to be nullptr. |
|
116 */ |
|
117 nsTemplateRule(const nsTemplateRule& aOtherRule); |
|
118 |
|
119 ~nsTemplateRule(); |
|
120 |
|
121 /** |
|
122 * Return the <action> node that this rule was constructed from, or its |
|
123 * logical equivalent for shorthand syntaxes. That is, the parent node of |
|
124 * the content that should be generated for this rule. |
|
125 */ |
|
126 nsIContent* GetAction() const { return mAction; } |
|
127 |
|
128 /** |
|
129 * Return the <rule> content node that this rule was constructed from. |
|
130 * @param aResult an out parameter, which will contain the rule node |
|
131 * @return NS_OK if no errors occur. |
|
132 */ |
|
133 nsresult GetRuleNode(nsIDOMNode** aResult) const; |
|
134 |
|
135 void SetVars(nsIAtom* aRefVariable, nsIAtom* aMemberVariable) |
|
136 { |
|
137 mRefVariable = aRefVariable; |
|
138 mMemberVariable = aMemberVariable; |
|
139 } |
|
140 |
|
141 void SetRuleFilter(nsIXULTemplateRuleFilter* aRuleFilter) |
|
142 { |
|
143 mRuleFilter = aRuleFilter; |
|
144 } |
|
145 |
|
146 nsIAtom* GetTag() { return mTag; } |
|
147 void SetTag(nsIAtom* aTag) { mTag = aTag; } |
|
148 |
|
149 nsIAtom* GetMemberVariable() { return mMemberVariable; } |
|
150 |
|
151 /** |
|
152 * Set the first condition for the rule. Other conditions are linked |
|
153 * to it using the condition's SetNext method. |
|
154 */ |
|
155 void SetCondition(nsTemplateCondition* aConditions); |
|
156 |
|
157 /** |
|
158 * Check if the result matches the rule by first looking at the conditions. |
|
159 * If the results is accepted by the conditions, the rule filter, if any |
|
160 * was set, is checked. If either check rejects a result, a match cannot |
|
161 * occur for this rule and result. |
|
162 */ |
|
163 bool |
|
164 CheckMatch(nsIXULTemplateResult* aResult) const; |
|
165 |
|
166 /** |
|
167 * Determine if the rule has the specified binding |
|
168 */ |
|
169 bool |
|
170 HasBinding(nsIAtom* aSourceVariable, |
|
171 nsAString& aExpr, |
|
172 nsIAtom* aTargetVariable) const; |
|
173 |
|
174 /** |
|
175 * Add a binding to the rule. A binding consists of an already-bound |
|
176 * source variable, and the RDF property that should be tested to |
|
177 * generate a target value. The target value is bound to a target |
|
178 * variable. |
|
179 * |
|
180 * @param aSourceVariable the source variable that will be used in |
|
181 * the RDF query. |
|
182 * @param aExpr the expression that will be used in the query. |
|
183 * @param aTargetVariable the variable whose value will be bound |
|
184 * to the RDF node that is returned when querying the binding |
|
185 * @return NS_OK if no errors occur. |
|
186 */ |
|
187 nsresult AddBinding(nsIAtom* aSourceVariable, |
|
188 nsAString& aExpr, |
|
189 nsIAtom* aTargetVariable); |
|
190 |
|
191 /** |
|
192 * Inform the query processor of the bindings that are set for a rule. |
|
193 * This should be called after all the bindings for a rule are compiled. |
|
194 */ |
|
195 nsresult |
|
196 AddBindingsToQueryProcessor(nsIXULTemplateQueryProcessor* aProcessor); |
|
197 |
|
198 void Traverse(nsCycleCollectionTraversalCallback &cb) const |
|
199 { |
|
200 cb.NoteXPCOMChild(mRuleNode); |
|
201 cb.NoteXPCOMChild(mAction); |
|
202 } |
|
203 |
|
204 protected: |
|
205 |
|
206 struct Binding { |
|
207 nsCOMPtr<nsIAtom> mSourceVariable; |
|
208 nsCOMPtr<nsIAtom> mTargetVariable; |
|
209 nsString mExpr; |
|
210 Binding* mNext; |
|
211 Binding* mParent; |
|
212 }; |
|
213 |
|
214 // backreference to the query set which owns this rule |
|
215 nsTemplateQuerySet* mQuerySet; |
|
216 |
|
217 // the <rule> node, or the <template> node if there is no <rule> |
|
218 nsCOMPtr<nsIDOMNode> mRuleNode; |
|
219 |
|
220 // the <action> node, or, if there is no <action>, the container node |
|
221 // which contains the content to generate |
|
222 nsCOMPtr<nsIContent> mAction; |
|
223 |
|
224 // the rule filter set by the builder's SetRuleFilter function |
|
225 nsCOMPtr<nsIXULTemplateRuleFilter> mRuleFilter; |
|
226 |
|
227 // indicates that the rule will only match when generating content |
|
228 // to be inserted into a container with this tag |
|
229 nsCOMPtr<nsIAtom> mTag; |
|
230 |
|
231 // linked-list of the bindings for the rule, owned by the rule. |
|
232 Binding* mBindings; |
|
233 |
|
234 nsCOMPtr<nsIAtom> mRefVariable; |
|
235 nsCOMPtr<nsIAtom> mMemberVariable; |
|
236 |
|
237 nsTemplateCondition* mConditions; // owned by nsTemplateRule |
|
238 }; |
|
239 |
|
240 /** nsTemplateQuerySet |
|
241 * |
|
242 * A single <queryset> which holds the query node and the rules for it. |
|
243 * All builders have at least one queryset, which may be created with an |
|
244 * explicit <queryset> tag or implied if the tag is not used. |
|
245 * |
|
246 * These queryset objects are created and owned by the builder in its |
|
247 * mQuerySets array. |
|
248 */ |
|
249 class nsTemplateQuerySet |
|
250 { |
|
251 protected: |
|
252 nsTArray<nsTemplateRule> mRules; |
|
253 |
|
254 // a number which increments for each successive queryset. It is stored so |
|
255 // it can be used as an optimization when updating results so that it is |
|
256 // known where to insert them into a match. |
|
257 int32_t mPriority; |
|
258 |
|
259 public: |
|
260 |
|
261 // <query> node |
|
262 nsCOMPtr<nsIContent> mQueryNode; |
|
263 |
|
264 // compiled opaque query object returned by the query processor's |
|
265 // CompileQuery call |
|
266 nsCOMPtr<nsISupports> mCompiledQuery; |
|
267 |
|
268 // indicates that the query will only generate content to be inserted into |
|
269 // a container with this tag |
|
270 nsCOMPtr<nsIAtom> mTag; |
|
271 |
|
272 nsTemplateQuerySet(int32_t aPriority) |
|
273 : mPriority(aPriority) |
|
274 { |
|
275 MOZ_COUNT_CTOR(nsTemplateQuerySet); |
|
276 } |
|
277 |
|
278 ~nsTemplateQuerySet() |
|
279 { |
|
280 MOZ_COUNT_DTOR(nsTemplateQuerySet); |
|
281 } |
|
282 |
|
283 int32_t Priority() const |
|
284 { |
|
285 return mPriority; |
|
286 } |
|
287 |
|
288 nsIAtom* GetTag() { return mTag; } |
|
289 void SetTag(nsIAtom* aTag) { mTag = aTag; } |
|
290 |
|
291 nsTemplateRule* NewRule(nsIContent* aRuleNode, |
|
292 nsIContent* aAction, |
|
293 nsTemplateQuerySet* aQuerySet) |
|
294 { |
|
295 // nsTemplateMatch stores the index as a 16-bit value, |
|
296 // so check to make sure for overflow |
|
297 if (mRules.Length() == INT16_MAX) |
|
298 return nullptr; |
|
299 |
|
300 return mRules.AppendElement(nsTemplateRule(aRuleNode, aAction, |
|
301 aQuerySet)); |
|
302 } |
|
303 |
|
304 void RemoveRule(nsTemplateRule *aRule) |
|
305 { |
|
306 mRules.RemoveElementAt(aRule - mRules.Elements()); |
|
307 } |
|
308 |
|
309 int16_t RuleCount() const |
|
310 { |
|
311 return mRules.Length(); |
|
312 } |
|
313 |
|
314 nsTemplateRule* GetRuleAt(int16_t aIndex) |
|
315 { |
|
316 if (uint32_t(aIndex) < mRules.Length()) { |
|
317 return &mRules[aIndex]; |
|
318 } |
|
319 return nullptr; |
|
320 } |
|
321 |
|
322 void Clear() |
|
323 { |
|
324 mRules.Clear(); |
|
325 } |
|
326 }; |
|
327 |
|
328 #endif // nsTemplateRule_h__ |