michael@0: /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #ifndef nsTemplateRule_h__ michael@0: #define nsTemplateRule_h__ michael@0: michael@0: #include "nsCOMPtr.h" michael@0: #include "nsIAtom.h" michael@0: #include "nsIRDFDataSource.h" michael@0: #include "nsIRDFResource.h" michael@0: #include "nsIContent.h" michael@0: #include "nsIDOMNode.h" michael@0: #include "nsTArray.h" michael@0: #include "nsString.h" michael@0: #include "nsIXULTemplateRuleFilter.h" michael@0: #include "nsCycleCollectionParticipant.h" michael@0: michael@0: class nsIXULTemplateQueryProcessor; michael@0: class nsTemplateQuerySet; michael@0: michael@0: class nsTemplateCondition michael@0: { michael@0: public: michael@0: // relations that may be used in a rule. They may be negated with the michael@0: // negate flag. Less and Greater are used for numeric comparisons and michael@0: // Before and After are used for string comparisons. For Less, Greater, michael@0: // Before, After, Startswith, Endswith, and Contains, the source is michael@0: // conceptually on the left of the relation and the target is on the michael@0: // right. For example, if the relation is Contains, that means Match if michael@0: // the source contains the target. michael@0: enum ConditionRelation { michael@0: eUnknown, michael@0: eEquals, michael@0: eLess, michael@0: eGreater, michael@0: eBefore, michael@0: eAfter, michael@0: eStartswith, michael@0: eEndswith, michael@0: eContains michael@0: }; michael@0: michael@0: nsTemplateCondition(nsIAtom* aSourceVariable, michael@0: const nsAString& aRelation, michael@0: nsIAtom* aTargetVariable, michael@0: bool mIgnoreCase, michael@0: bool mNegate); michael@0: michael@0: nsTemplateCondition(nsIAtom* aSourceVariable, michael@0: const nsAString& aRelation, michael@0: const nsAString& aTargets, michael@0: bool mIgnoreCase, michael@0: bool mNegate, michael@0: bool aIsMultiple); michael@0: michael@0: nsTemplateCondition(const nsAString& aSource, michael@0: const nsAString& aRelation, michael@0: nsIAtom* aTargetVariable, michael@0: bool mIgnoreCase, michael@0: bool mNegate); michael@0: michael@0: ~nsTemplateCondition() { MOZ_COUNT_DTOR(nsTemplateCondition); } michael@0: michael@0: nsTemplateCondition* GetNext() { return mNext; } michael@0: void SetNext(nsTemplateCondition* aNext) { mNext = aNext; } michael@0: michael@0: void SetRelation(const nsAString& aRelation); michael@0: michael@0: bool michael@0: CheckMatch(nsIXULTemplateResult* aResult); michael@0: michael@0: bool michael@0: CheckMatchStrings(const nsAString& aLeftString, michael@0: const nsAString& aRightString); michael@0: protected: michael@0: michael@0: nsCOMPtr mSourceVariable; michael@0: nsString mSource; michael@0: ConditionRelation mRelation; michael@0: nsCOMPtr mTargetVariable; michael@0: nsTArray mTargetList; michael@0: bool mIgnoreCase; michael@0: bool mNegate; michael@0: michael@0: nsTemplateCondition* mNext; michael@0: }; michael@0: michael@0: /** michael@0: * A rule consists of: michael@0: * michael@0: * - Conditions, a set of unbound variables with consistency michael@0: * constraints that specify the values that each variable can michael@0: * assume. The conditions must be completely and consistently michael@0: * "bound" for the rule to be considered "matched". michael@0: * michael@0: * - Bindings, a set of unbound variables with consistency constraints michael@0: * that specify the values that each variable can assume. Unlike the michael@0: * conditions, the bindings need not be bound for the rule to be michael@0: * considered matched. michael@0: * michael@0: * - Content that should be constructed when the rule is "activated". michael@0: * michael@0: */ michael@0: class nsTemplateRule michael@0: { michael@0: public: michael@0: nsTemplateRule(nsIContent* aRuleNode, michael@0: nsIContent* aAction, michael@0: nsTemplateQuerySet* aQuerySet); michael@0: /** michael@0: * The copy-constructor should only be called from nsTArray when appending michael@0: * a new rule, otherwise things break because the copy constructor expects michael@0: * mBindings and mConditions to be nullptr. michael@0: */ michael@0: nsTemplateRule(const nsTemplateRule& aOtherRule); michael@0: michael@0: ~nsTemplateRule(); michael@0: michael@0: /** michael@0: * Return the node that this rule was constructed from, or its michael@0: * logical equivalent for shorthand syntaxes. That is, the parent node of michael@0: * the content that should be generated for this rule. michael@0: */ michael@0: nsIContent* GetAction() const { return mAction; } michael@0: michael@0: /** michael@0: * Return the content node that this rule was constructed from. michael@0: * @param aResult an out parameter, which will contain the rule node michael@0: * @return NS_OK if no errors occur. michael@0: */ michael@0: nsresult GetRuleNode(nsIDOMNode** aResult) const; michael@0: michael@0: void SetVars(nsIAtom* aRefVariable, nsIAtom* aMemberVariable) michael@0: { michael@0: mRefVariable = aRefVariable; michael@0: mMemberVariable = aMemberVariable; michael@0: } michael@0: michael@0: void SetRuleFilter(nsIXULTemplateRuleFilter* aRuleFilter) michael@0: { michael@0: mRuleFilter = aRuleFilter; michael@0: } michael@0: michael@0: nsIAtom* GetTag() { return mTag; } michael@0: void SetTag(nsIAtom* aTag) { mTag = aTag; } michael@0: michael@0: nsIAtom* GetMemberVariable() { return mMemberVariable; } michael@0: michael@0: /** michael@0: * Set the first condition for the rule. Other conditions are linked michael@0: * to it using the condition's SetNext method. michael@0: */ michael@0: void SetCondition(nsTemplateCondition* aConditions); michael@0: michael@0: /** michael@0: * Check if the result matches the rule by first looking at the conditions. michael@0: * If the results is accepted by the conditions, the rule filter, if any michael@0: * was set, is checked. If either check rejects a result, a match cannot michael@0: * occur for this rule and result. michael@0: */ michael@0: bool michael@0: CheckMatch(nsIXULTemplateResult* aResult) const; michael@0: michael@0: /** michael@0: * Determine if the rule has the specified binding michael@0: */ michael@0: bool michael@0: HasBinding(nsIAtom* aSourceVariable, michael@0: nsAString& aExpr, michael@0: nsIAtom* aTargetVariable) const; michael@0: michael@0: /** michael@0: * Add a binding to the rule. A binding consists of an already-bound michael@0: * source variable, and the RDF property that should be tested to michael@0: * generate a target value. The target value is bound to a target michael@0: * variable. michael@0: * michael@0: * @param aSourceVariable the source variable that will be used in michael@0: * the RDF query. michael@0: * @param aExpr the expression that will be used in the query. michael@0: * @param aTargetVariable the variable whose value will be bound michael@0: * to the RDF node that is returned when querying the binding michael@0: * @return NS_OK if no errors occur. michael@0: */ michael@0: nsresult AddBinding(nsIAtom* aSourceVariable, michael@0: nsAString& aExpr, michael@0: nsIAtom* aTargetVariable); michael@0: michael@0: /** michael@0: * Inform the query processor of the bindings that are set for a rule. michael@0: * This should be called after all the bindings for a rule are compiled. michael@0: */ michael@0: nsresult michael@0: AddBindingsToQueryProcessor(nsIXULTemplateQueryProcessor* aProcessor); michael@0: michael@0: void Traverse(nsCycleCollectionTraversalCallback &cb) const michael@0: { michael@0: cb.NoteXPCOMChild(mRuleNode); michael@0: cb.NoteXPCOMChild(mAction); michael@0: } michael@0: michael@0: protected: michael@0: michael@0: struct Binding { michael@0: nsCOMPtr mSourceVariable; michael@0: nsCOMPtr mTargetVariable; michael@0: nsString mExpr; michael@0: Binding* mNext; michael@0: Binding* mParent; michael@0: }; michael@0: michael@0: // backreference to the query set which owns this rule michael@0: nsTemplateQuerySet* mQuerySet; michael@0: michael@0: // the node, or the