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