Back to index

lightning-sunbird  0.9+nobinonly
Classes | Public Member Functions | Protected Attributes
nsTemplateRule Class Reference

A rule consists of: More...

#include <nsTemplateRule.h>

Collaboration diagram for nsTemplateRule:
Collaboration graph
[legend]

List of all members.

Classes

struct  Binding

Public Member Functions

 nsTemplateRule (nsIRDFDataSource *aDataSource, nsIContent *aContent, PRInt32 aPriority)
 ~nsTemplateRule ()
nsresult GetContent (nsIContent **aResult) const
 Return the content node that this rule was constructed from.
void SetContainerVariable (PRInt32 aContainerVariable)
 Set the variable which should be used as the "container variable" in this rule.
PRInt32 GetContainerVariable () const
 Retrieve the variable that this rule uses as its "container variable".
void SetMemberVariable (PRInt32 aMemberVariable)
 Set the variable which should be used as the "member variable" in this rule.
PRInt32 GetMemberVariable () const
 Retrieve the variable that this rule uses as its "member variable".
PRInt32 GetPriority () const
 Retrieve the "priority" of the rule with respect to the other rules in the template.
PRBool HasBinding (PRInt32 aSourceVariable, nsIRDFResource *aProperty, PRInt32 aTargetVariable) const
 Determine if the rule has the specified binding.
nsresult AddBinding (PRInt32 aSourceVariable, nsIRDFResource *aProperty, PRInt32 aTargetVariable)
 Add a binding to the rule.
nsresult InitBindings (nsConflictSet &aConflictSet, nsTemplateMatch *aMatch) const
 Initialize a match by adding necessary binding dependencies to the conflict set.
nsresult RecomputeBindings (nsConflictSet &aConflictSet, nsTemplateMatch *aMatch, nsIRDFResource *aSource, nsIRDFResource *aProperty, nsIRDFNode *aOldTarget, nsIRDFNode *aNewTarget, VariableSet &aModifiedVars) const
 Compute the minimal set of changes to a match's bindings that must occur which the specified change is made to the RDF graph.
PRBool ComputeAssignmentFor (nsConflictSet &aConflictSet, nsTemplateMatch *aMatch, PRInt32 aVariable, Value *aValue) const
 Compute the value to assign to an arbitrary variable in a match.
PRBool DependsOn (PRInt32 aChild, PRInt32 aParent) const
 Determine if one variable depends on another in the rule's bindings.

Protected Attributes

nsCOMPtr< nsIRDFDataSourcemDataSource
nsCOMPtr< nsIContentmContent
PRInt32 mContainerVariable
PRInt32 mMemberVariable
PRInt32 mPriority
PRInt32 mCount
PRInt32 mCapacity
BindingmBindings

Detailed Description

A rule consists of:

Definition at line 71 of file nsTemplateRule.h.


Class Documentation

struct nsTemplateRule::Binding

Definition at line 240 of file nsTemplateRule.h.

Collaboration diagram for nsTemplateRule::Binding:
Class Members
Binding * mNext
Binding * mParent
nsCOMPtr< nsIRDFResource > mProperty
PRInt32 mSourceVariable
PRInt32 mTargetVariable

Constructor & Destructor Documentation

nsTemplateRule::nsTemplateRule ( nsIRDFDataSource aDataSource,
nsIContent aContent,
PRInt32  aPriority 
) [inline]

Definition at line 74 of file nsTemplateRule.h.

Definition at line 45 of file nsTemplateRule.cpp.

{
    MOZ_COUNT_DTOR(nsTemplateRule);

    while (mBindings) {
        Binding* doomed = mBindings;
        mBindings = mBindings->mNext;
        delete doomed;
    }
}

Member Function Documentation

nsresult nsTemplateRule::AddBinding ( PRInt32  aSourceVariable,
nsIRDFResource aProperty,
PRInt32  aTargetVariable 
)

Add a binding to the rule.

A binding consists of an already-bound source variable, and the RDF property that should be tested to generate a target value. The target value is bound to a target variable.

Parameters:
aSourceVariablethe source variable that will be used in the RDF query.
aPropertythe RDF property that will be used in the RDF query.
aTargetVariablethe variable whose value will be bound to the RDF node that is returned when querying the binding
Returns:
NS_OK if no errors occur.

Definition at line 81 of file nsTemplateRule.cpp.

{
    NS_PRECONDITION(aSourceVariable != 0, "no source variable!");
    if (! aSourceVariable)
        return NS_ERROR_INVALID_ARG;

    NS_PRECONDITION(aProperty != nsnull, "null ptr");
    if (! aProperty)
        return NS_ERROR_INVALID_ARG;

    NS_PRECONDITION(aTargetVariable != 0, "no target variable!");
    if (! aTargetVariable)
        return NS_ERROR_INVALID_ARG;

    NS_ASSERTION(! HasBinding(aSourceVariable, aProperty, aTargetVariable),
                 "binding added twice");

    Binding* newbinding = new Binding;
    if (! newbinding)
        return NS_ERROR_OUT_OF_MEMORY;

    newbinding->mSourceVariable = aSourceVariable;
    newbinding->mProperty       = aProperty;
    newbinding->mTargetVariable = aTargetVariable;
    newbinding->mParent         = nsnull;

    Binding* binding = mBindings;
    Binding** link = &mBindings;

    // Insert it at the end, unless we detect that an existing
    // binding's source is dependent on the newbinding's target.
    //
    // XXXwaterson this isn't enough to make sure that we get all of
    // the dependencies worked out right, but it'll do for now. For
    // example, if you have (ab, bc, cd), and insert them in the order
    // (cd, ab, bc), you'll get (bc, cd, ab). The good news is, if the
    // person uses a natural ordering when writing the XUL, it'll all
    // work out ok.
    while (binding) {
        if (binding->mSourceVariable == newbinding->mTargetVariable) {
            binding->mParent = newbinding;
            break;
        }
        else if (binding->mTargetVariable == newbinding->mSourceVariable) {
            newbinding->mParent = binding;
        }

        link = &binding->mNext;
        binding = binding->mNext;
    }

    // Insert the newbinding
    *link = newbinding;
    newbinding->mNext = binding;
    return NS_OK;
}

Here is the call graph for this function:

Here is the caller graph for this function:

PRBool nsTemplateRule::ComputeAssignmentFor ( nsConflictSet aConflictSet,
nsTemplateMatch aMatch,
PRInt32  aVariable,
Value aValue 
) const

Compute the value to assign to an arbitrary variable in a match.

This may require us to work out several dependancies, if there are bindings set up for this rule.

Parameters:
aConflictSetthe conflict set; if necessary, we may add a "binding dependency" to the conflict set, which will allow us to correctly recompute the bindings later if they should change.
aMatchthe match that provides the "seed" variable assignments, which we may need to extend using the rule's bindings.
aVariablethe variable for which we are to compute the assignment.
aValuean out parameter that will receive the value that was assigned to aVariable, if we could find one.
Returns:
PR_TRUE if an assignment was found for aVariable, PR_FALSE otherwise.

Definition at line 302 of file nsTemplateRule.cpp.

{
    // Compute the value assignment for an arbitrary variable in a
    // match. Potentially fill in dependencies if they haven't been
    // resolved yet.
    for (Binding* binding = mBindings; binding != nsnull; binding = binding->mNext) {
        if (binding->mTargetVariable != aVariable)
            continue;

        // Potentially recur to find the value of the source.
        //
        // XXXwaterson this is sloppy, and could be dealt with more
        // directly by following binding->mParent.
        Value sourceValue;
        PRBool hasSourceAssignment =
            aMatch->GetAssignmentFor(aConflictSet, binding->mSourceVariable, &sourceValue);

        if (! hasSourceAssignment)
            return PR_FALSE;

        nsCOMPtr<nsIRDFNode> target;

        nsIRDFResource* source = VALUE_TO_IRDFRESOURCE(sourceValue);

        if (source) {
            mDataSource->GetTarget(source,
                                   binding->mProperty,
                                   PR_TRUE,
                                   getter_AddRefs(target));

            // Store the assignment in the match so we won't need to
            // retrieve it again.
            nsAssignment assignment(binding->mTargetVariable, Value(target.get()));
            aMatch->mAssignments.Add(assignment);

            // Add a dependency on the source, so we'll recompute the
            // assignment if somebody tweaks it.
            aMatch->mBindingDependencies.Add(source);
            aConflictSet.AddBindingDependency(aMatch, source);
        }

        *aValue = target.get();
        return PR_TRUE;
    }

    return PR_FALSE;
}

Here is the call graph for this function:

Here is the caller graph for this function:

PRBool nsTemplateRule::DependsOn ( PRInt32  aChild,
PRInt32  aParent 
) const

Determine if one variable depends on another in the rule's bindings.

Parameters:
aChildthe dependent variable, whose value may depend on the assignment of aParent.
aParentthe variable whose value aChild is depending on.
Returns:
PR_TRUE if aChild's assignment depends on the assignment for aParent, PR_FALSE otherwise.

Definition at line 141 of file nsTemplateRule.cpp.

{
    // Determine whether the value for aChildVariable will depend on
    // the value for aParentVariable by examining the rule's bindings.
    Binding* child = mBindings;
    while ((child != nsnull) && (child->mSourceVariable != aChildVariable))
        child = child->mNext;

    if (! child)
        return PR_FALSE;

    Binding* parent = child->mParent;
    while (parent != nsnull) {
        if (parent->mSourceVariable == aParentVariable)
            return PR_TRUE;

        parent = parent->mParent;
    }

    return PR_FALSE;
}

Here is the caller graph for this function:

Retrieve the variable that this rule uses as its "container variable".

Returns:
the variable that this rule uses as its "container variable".

Definition at line 111 of file nsTemplateRule.h.

                                         {
        return mContainerVariable; }

Here is the caller graph for this function:

Return the content node that this rule was constructed from.

Parameters:
aResultan out parameter, which will contain the content node that this rule was constructed from
Returns:
NS_OK if no errors occur.

Definition at line 58 of file nsTemplateRule.cpp.

{
    *aResult = mContent.get();
    NS_IF_ADDREF(*aResult);
    return NS_OK;
}

Here is the call graph for this function:

Here is the caller graph for this function:

Retrieve the variable that this rule uses as its "member variable".

Returns:
the variable that this rule uses as its "member variable"

Definition at line 128 of file nsTemplateRule.h.

                                      {
        return mMemberVariable; }

Here is the caller graph for this function:

Retrieve the "priority" of the rule with respect to the other rules in the template.

Returns:
the rule's priority, lower values mean "use this first".

Definition at line 136 of file nsTemplateRule.h.

                                {
        return mPriority; }
PRBool nsTemplateRule::HasBinding ( PRInt32  aSourceVariable,
nsIRDFResource aProperty,
PRInt32  aTargetVariable 
) const

Determine if the rule has the specified binding.

Definition at line 66 of file nsTemplateRule.cpp.

{
    for (Binding* binding = mBindings; binding != nsnull; binding = binding->mNext) {
        if ((binding->mSourceVariable == aSourceVariable) &&
            (binding->mProperty == aProperty) &&
            (binding->mTargetVariable == aTargetVariable))
            return PR_TRUE;
    }

    return PR_FALSE;
}

Here is the caller graph for this function:

nsresult nsTemplateRule::InitBindings ( nsConflictSet aConflictSet,
nsTemplateMatch aMatch 
) const

Initialize a match by adding necessary binding dependencies to the conflict set.

This will allow us to properly update the match later if a value should change that the match's bindings depend on.

Parameters:
aConflictSetthe conflict set
aMatchthe match we to initialize
Returns:
NS_OK if no errors occur.

Definition at line 169 of file nsTemplateRule.cpp.

{
    // Initialize a match's binding dependencies, so we can handle
    // updates and queries later.

    for (Binding* binding = mBindings; binding != nsnull; binding = binding->mNext) {
        // Add a dependency for bindings whose source variable comes
        // from one of the <conditions>.
        Value sourceValue;
        PRBool hasBinding =
            aMatch->mInstantiation.mAssignments.GetAssignmentFor(binding->mSourceVariable, &sourceValue);

        if (hasBinding) {
            nsIRDFResource* source = VALUE_TO_IRDFRESOURCE(sourceValue);
            aMatch->mBindingDependencies.Add(source);
            aConflictSet.AddBindingDependency(aMatch, source);
        }

        // If this binding is dependant on another binding, then we
        // need to eagerly compute its source variable's assignment.
        if (binding->mParent) {
            Value value;
            ComputeAssignmentFor(aConflictSet, aMatch, binding->mSourceVariable, &value);
        }
    }

    return NS_OK;
}

Here is the call graph for this function:

Here is the caller graph for this function:

nsresult nsTemplateRule::RecomputeBindings ( nsConflictSet aConflictSet,
nsTemplateMatch aMatch,
nsIRDFResource aSource,
nsIRDFResource aProperty,
nsIRDFNode aOldTarget,
nsIRDFNode aNewTarget,
VariableSet aModifiedVars 
) const

Compute the minimal set of changes to a match's bindings that must occur which the specified change is made to the RDF graph.

Parameters:
aConflictSetthe conflict set, which we may need to manipulate to update the binding dependencies.
aMatchthe match for which we must recompute the bindings
aSourcethe "source" resource in the RDF graph
aPropertythe "property" resource in the RDF graph
aOldTargetthe old "target" node in the RDF graph
aNewTargetthe new "target" node in the RDF graph.
aModifiedVarsa VariableSet, into which this routine will assign each variable whose value has changed.
Returns:
NS_OK if no errors occurred.

Definition at line 199 of file nsTemplateRule.cpp.

{
    // Given a match with a source, property, old target, and new
    // target, compute the minimal changes to the match's bindings.

    // A temporary, mutable collection for holding all of the
    // assignments that comprise the current match.
    nsAutoVoidArray assignments;

    {
        // Collect -all- of the assignments in match into a temporary,
        // mutable collection
        nsAssignmentSet::ConstIterator last = aMatch->mAssignments.Last();
        for (nsAssignmentSet::ConstIterator binding = aMatch->mAssignments.First(); binding != last; ++binding)
            assignments.AppendElement(new nsAssignment(*binding));

        // Truncate the match's assignments to only include
        // assignments made via condition tests. We'll add back
        // assignments as they are recomputed.
        aMatch->mAssignments = aMatch->mInstantiation.mAssignments;
    }

    PRInt32 i;

    // Iterate through each assignment, looking for the assignment
    // whose value corresponds to the source of the assertion that's
    // changing.
    for (i = 0; i < assignments.Count(); ++i) {
        nsAssignment* assignment = NS_STATIC_CAST(nsAssignment*, assignments[i]);
        if ((assignment->mValue.GetType() == Value::eISupports) &&
            (NS_STATIC_CAST(nsISupports*, assignment->mValue) == aSource)) {

            // ...When we find it, look for binding's whose source
            // variable depends on the assignment's variable
            for (Binding* binding = mBindings; binding != nsnull; binding = binding->mNext) {
                if ((binding->mSourceVariable != assignment->mVariable) ||
                    (binding->mProperty.get() != aProperty))
                    continue;

                // Found one. Now we iterate through the assignments,
                // doing fixup.
                for (PRInt32 j = 0; j < assignments.Count(); ++j) {
                    nsAssignment* dependent = NS_STATIC_CAST(nsAssignment*, assignments[j]);
                    if (dependent->mVariable == binding->mTargetVariable) {
                        // The assignment's variable is the target
                        // varible for the binding: we can update it
                        // in-place.
                        dependent->mValue = Value(aNewTarget);
                        aModifiedVars.Add(dependent->mVariable);
                    }
                    else if (DependsOn(dependent->mVariable, binding->mTargetVariable)) {
                        // The assignment's variable depends on the
                        // binding's target variable, which is
                        // changing. Rip it out.
                        nsIRDFResource* target = VALUE_TO_IRDFRESOURCE(dependent->mValue);
                        aMatch->mBindingDependencies.Remove(target);
                        aConflictSet.RemoveBindingDependency(aMatch, target);

                        delete dependent;
                        assignments.RemoveElementAt(j--);

                        aModifiedVars.Add(dependent->mVariable);
                    }
                    else {
                        // The dependent variable is irrelevant. Leave
                        // it alone.
                    }
                }
            }
        }
    }

    // Now our set of assignments will contain the original
    // assignments from the conditions, any unchanged assignments, and
    // the single assignment that was updated by iterating through the
    // bindings.
    //
    // Add these assignments *back* to the match (modulo the ones
    // already in the conditions).
    //
    // The values for any dependent assignments that we've ripped out
    // will be computed the next time that somebody asks us for them.
    for (i = assignments.Count() - 1; i >= 0; --i) {
        nsAssignment* assignment = NS_STATIC_CAST(nsAssignment*, assignments[i]);

        // Only add it if it's not already in the match's conditions
        if (! aMatch->mInstantiation.mAssignments.HasAssignment(*assignment)) {
            aMatch->mAssignments.Add(*assignment);
        }

        delete assignment;
    }

    return NS_OK;
}

Here is the call graph for this function:

Here is the caller graph for this function:

void nsTemplateRule::SetContainerVariable ( PRInt32  aContainerVariable) [inline]

Set the variable which should be used as the "container variable" in this rule.

The container variable will be bound to an RDF resource that is the parent of the member resources.

Parameters:
aContainerVariablethe variable that should be used as the "container variable" in this rule

Definition at line 104 of file nsTemplateRule.h.

                                                          {
        mContainerVariable = aContainerVariable; }

Here is the caller graph for this function:

void nsTemplateRule::SetMemberVariable ( PRInt32  aMemberVariable) [inline]

Set the variable which should be used as the "member variable" in this rule.

The member variable will be bound to an RDF resource that is the child of the container resource.

Parameters:
aMemberVariablethe variable that should be used as the "member variable" in this rule.

Definition at line 121 of file nsTemplateRule.h.

                                                    {
        mMemberVariable = aMemberVariable; }

Here is the caller graph for this function:


Member Data Documentation

Definition at line 248 of file nsTemplateRule.h.

Definition at line 238 of file nsTemplateRule.h.

Definition at line 233 of file nsTemplateRule.h.

Definition at line 232 of file nsTemplateRule.h.

Definition at line 237 of file nsTemplateRule.h.

Definition at line 231 of file nsTemplateRule.h.

Definition at line 234 of file nsTemplateRule.h.

Definition at line 235 of file nsTemplateRule.h.


The documentation for this class was generated from the following files: