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 : #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 0 : ~nsTemplateCondition() { MOZ_COUNT_DTOR(nsTemplateCondition); }
65 :
66 0 : nsTemplateCondition* GetNext() { return mNext; }
67 0 : 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 0 : 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 0 : void SetVars(nsIAtom* aRefVariable, nsIAtom* aMemberVariable)
136 : {
137 0 : mRefVariable = aRefVariable;
138 0 : mMemberVariable = aMemberVariable;
139 0 : }
140 :
141 0 : void SetRuleFilter(nsIXULTemplateRuleFilter* aRuleFilter)
142 : {
143 0 : mRuleFilter = aRuleFilter;
144 0 : }
145 :
146 0 : nsIAtom* GetTag() { return mTag; }
147 0 : void SetTag(nsIAtom* aTag) { mTag = aTag; }
148 :
149 0 : 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 0 : void Traverse(nsCycleCollectionTraversalCallback &cb) const
199 : {
200 0 : cb.NoteXPCOMChild(mRuleNode);
201 0 : cb.NoteXPCOMChild(mAction);
202 0 : }
203 :
204 : protected:
205 :
206 0 : 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 0 : explicit nsTemplateQuerySet(int32_t aPriority)
273 0 : : mPriority(aPriority)
274 : {
275 0 : MOZ_COUNT_CTOR(nsTemplateQuerySet);
276 0 : }
277 :
278 0 : ~nsTemplateQuerySet()
279 0 : {
280 0 : MOZ_COUNT_DTOR(nsTemplateQuerySet);
281 0 : }
282 :
283 0 : int32_t Priority() const
284 : {
285 0 : return mPriority;
286 : }
287 :
288 0 : nsIAtom* GetTag() { return mTag; }
289 0 : void SetTag(nsIAtom* aTag) { mTag = aTag; }
290 :
291 0 : 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 0 : if (mRules.Length() == INT16_MAX)
298 0 : return nullptr;
299 :
300 0 : return mRules.AppendElement(nsTemplateRule(aRuleNode, aAction,
301 0 : aQuerySet));
302 : }
303 :
304 0 : void RemoveRule(nsTemplateRule *aRule)
305 : {
306 0 : mRules.RemoveElementAt(aRule - mRules.Elements());
307 0 : }
308 :
309 0 : int16_t RuleCount() const
310 : {
311 0 : return mRules.Length();
312 : }
313 :
314 0 : nsTemplateRule* GetRuleAt(int16_t aIndex)
315 : {
316 0 : if (uint32_t(aIndex) < mRules.Length()) {
317 0 : return &mRules[aIndex];
318 : }
319 0 : return nullptr;
320 : }
321 :
322 : void Clear()
323 : {
324 : mRules.Clear();
325 : }
326 : };
327 :
328 : #endif // nsTemplateRule_h__
|