зеркало из https://github.com/mozilla/pjs.git
Bug 285631, new template builder, r+sr=bz
This commit is contained in:
Родитель
0fbe251311
Коммит
5e55605551
|
@ -356,6 +356,7 @@ GK_ATOM(i, "i")
|
|||
GK_ATOM(id, "id")
|
||||
GK_ATOM(_if, "if")
|
||||
GK_ATOM(iframe, "iframe")
|
||||
GK_ATOM(ignorecase, "ignorecase")
|
||||
GK_ATOM(ignorekeys, "ignorekeys")
|
||||
GK_ATOM(ilayer, "ilayer")
|
||||
GK_ATOM(image, "image")
|
||||
|
@ -464,6 +465,7 @@ GK_ATOM(namespaceAlias, "namespace-alias")
|
|||
GK_ATOM(namespaceUri, "namespace-uri")
|
||||
GK_ATOM(NaN, "NaN")
|
||||
GK_ATOM(nativescrollbar, "nativescrollbar")
|
||||
GK_ATOM(negate, "negate")
|
||||
GK_ATOM(never, "never")
|
||||
GK_ATOM(nextBidi, "NextBidi")
|
||||
GK_ATOM(no, "no")
|
||||
|
@ -611,6 +613,8 @@ GK_ATOM(propagate, "propagate")
|
|||
GK_ATOM(properties, "properties")
|
||||
GK_ATOM(property, "property")
|
||||
GK_ATOM(q, "q")
|
||||
GK_ATOM(query, "query")
|
||||
GK_ATOM(queryset, "queryset")
|
||||
GK_ATOM(radio, "radio")
|
||||
GK_ATOM(radiogroup, "radiogroup")
|
||||
GK_ATOM(readonly, "readonly")
|
||||
|
@ -777,6 +781,7 @@ GK_ATOM(valign, "valign")
|
|||
GK_ATOM(value, "value")
|
||||
GK_ATOM(valueOf, "value-of")
|
||||
GK_ATOM(valuetype, "valuetype")
|
||||
GK_ATOM(var, "var")
|
||||
GK_ATOM(variable, "variable")
|
||||
GK_ATOM(vbox, "vbox")
|
||||
GK_ATOM(vcard_name, "vcard_name")
|
||||
|
@ -789,6 +794,7 @@ GK_ATOM(vlink, "vlink")
|
|||
GK_ATOM(vspace, "vspace")
|
||||
GK_ATOM(wbr, "wbr")
|
||||
GK_ATOM(when, "when")
|
||||
GK_ATOM(where, "where")
|
||||
GK_ATOM(widget, "widget")
|
||||
GK_ATOM(width, "width")
|
||||
GK_ATOM(window, "window")
|
||||
|
|
|
@ -48,6 +48,9 @@ XPIDLSRCS = \
|
|||
nsIXULSortService.idl \
|
||||
nsIXULTemplateBuilder.idl \
|
||||
nsIXULBuilderListener.idl \
|
||||
nsIXULTemplateQueryProcessor.idl \
|
||||
nsIXULTemplateResult.idl \
|
||||
nsIXULTemplateRuleFilter.idl \
|
||||
$(NULL)
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
* Ben Goodger <ben@netscape.com>
|
||||
* Jan Varga <varga@ku.sk>
|
||||
* Benjamin Smedberg <bsmedberg@covad.net>
|
||||
* Neil Deakin <enndeakin@sympatico.ca>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
|
@ -44,26 +45,148 @@
|
|||
#include "nsIRDFCompositeDataSource.idl"
|
||||
#include "nsIRDFResource.idl"
|
||||
|
||||
interface nsIAtom;
|
||||
interface nsIXULBuilderListener;
|
||||
interface nsIXULTemplateResult;
|
||||
interface nsIXULTemplateRuleFilter;
|
||||
interface nsIXULTemplateQueryProcessor;
|
||||
|
||||
[ptr] native nsIContent_ptr(nsIContent);
|
||||
|
||||
[scriptable, uuid(9da147a7-5854-49e3-a397-22ecdd93e96d)]
|
||||
/**
|
||||
* A template builder, given an input source of data, a template, and a
|
||||
* reference point, generates a list of results from the input, and copies
|
||||
* part of the template for each result. Templates may generate content
|
||||
* recursively, using the same template, but with the previous iteration's
|
||||
* results as the reference point. As an example, for an XML datasource the
|
||||
* initial reference point would be a specific node in the DOM tree and a
|
||||
* template might generate a list of all child nodes. For the next iteration,
|
||||
* those children would be used to generate output for their child nodes and
|
||||
* so forth.
|
||||
*
|
||||
* A template builder is attached to a single DOM node; this node is called
|
||||
* the root node and is expected to contain a XUL template element as a direct
|
||||
* child. Different template builders may be specialized in the manner in
|
||||
* which they generate and display the resulting content from the template.
|
||||
*
|
||||
* The structure of a template is as follows:
|
||||
*
|
||||
* <rootnode datasources="" ref="">
|
||||
* <template>
|
||||
* <queryset>
|
||||
* <query>
|
||||
* </query>
|
||||
* <rule>
|
||||
* <conditions>...</conditions>
|
||||
* <bindings>...</bindings>
|
||||
* <action>...</action>
|
||||
* </rule>
|
||||
* </queryset>
|
||||
* </template>
|
||||
* </rootnode>
|
||||
*
|
||||
* The datasources attribute on the root node is used to identify the source
|
||||
* of data to be used. The ref attribute is used to specify the reference
|
||||
* point for the query. Currently, the datasource will either be an
|
||||
* nsIRDFDataSource or a DOM node. In the future, other datasource types may
|
||||
* be used.
|
||||
*
|
||||
* The <queryset> element contains a single query and one or more <rule>
|
||||
* elements. There may be more than one <queryset> if multiple queries are
|
||||
* desired, and this element is optional if only one query is needed -- in
|
||||
* that case the <query> and <rule>s are allowed to be children of the
|
||||
* <template> node
|
||||
*
|
||||
* The contents of the query are processed by a separate component called a
|
||||
* query processor. This query processor is expected to use this query to
|
||||
* generate results when asked by the template builder. The template builder
|
||||
* then generates output for each result based on the <rule> elements.
|
||||
*
|
||||
* This allows the query processor to be specific to a particular kind of
|
||||
* input data or query syntax, while the template builder remains independent
|
||||
* of the kind of data being used. Due to this, the query processor will be
|
||||
* supplied with the datasource and query which the template builder handles
|
||||
* in an opaque way, while the query processor handles these more
|
||||
* specifically.
|
||||
*
|
||||
* Results implement the nsIXULTemplateResult interface and may be identified
|
||||
* by an id which must be unique within a given set of query results.
|
||||
*
|
||||
* Each query may be accompanied by one or more <rule> elements. These rules
|
||||
* are evaluated by the template builder for each result produced by the
|
||||
* query. A rule consists of conditions that cause a rule to be either
|
||||
* accepted or rejected. The condition syntax allows for common conditional
|
||||
* handling; additional filtering may be applied by adding a custom filter
|
||||
* to a rule with the builder's addRuleFilter method.
|
||||
*
|
||||
* If a result passes a rule's conditions, this is considered a match, and the
|
||||
* content within the rule's <action> body is inserted as a sibling of the
|
||||
* <template>, assuming the template builder creates real DOM content. Only
|
||||
* one rule will match a result. For a tree builder, for example, the content
|
||||
* within the action body is used to create the tree rows instead. A matching
|
||||
* result must have its ruleMatched method called. When a result no longer
|
||||
* matches, the result's hasBeenRemoved method must be called.
|
||||
*
|
||||
* Optionally, the rule may have a <bindings> section which may be used to
|
||||
* define additional variables to be used within an action body. Each of these
|
||||
* declared bindings must be supplied to the query processor via its
|
||||
* addBinding method. The bindings are evaluated after a rule has matched.
|
||||
*
|
||||
* Templates may generate content recursively, using the previous iteration's
|
||||
* results as reference point to invoke the same queries. Since the reference
|
||||
* point is different, different output will typically be generated.
|
||||
*
|
||||
* The reference point nsIXULTemplateResult object for the first iteration is
|
||||
* determined by calling the query processor's translateRef method using the
|
||||
* value of the root node's ref attribute. This object may be retrieved later
|
||||
* via the builder's rootResult property.
|
||||
*
|
||||
* For convenience, each reference point as well as all results implement the
|
||||
* nsIXULTemplateResult interface, allowing the result objects from each
|
||||
* iteration to be used directly as the reference points for the next
|
||||
* iteration.
|
||||
*
|
||||
* When using multiple queries, each may generate results with the same id.
|
||||
* More than one of these results may match one of the rules in their
|
||||
* respective queries, however only the result for the earliest matching query
|
||||
* in the template becomes the active match and generates output. The
|
||||
* addResult, removeResult, replaceResult and resultBindingChanged methods may
|
||||
* be called by the query processor to indicate that the set of valid results
|
||||
* has changed, such that a different query may match. If a different match
|
||||
* would become active, the content for the existing match is removed and the
|
||||
* content for the new match is generated. A query processor is not required
|
||||
* to provide any support for updating results after they have been generated.
|
||||
*
|
||||
* See http://wiki.mozilla.org/XUL:Templates_Plan for details about templates.
|
||||
*/
|
||||
[scriptable, uuid(e025ef24-d508-11d9-9633-cd2d4a843228)]
|
||||
interface nsIXULTemplateBuilder : nsISupports
|
||||
{
|
||||
/**
|
||||
* The ``root'' node in the DOM to which this builder is attached
|
||||
* The root node in the DOM to which this builder is attached.
|
||||
*/
|
||||
readonly attribute nsIDOMElement root;
|
||||
|
||||
/**
|
||||
* The composite datasource that the template builder observes
|
||||
* and uses to create content
|
||||
* and uses to create content. This is used only for RDF queries and
|
||||
* is maintained for backwards compatibility.
|
||||
*/
|
||||
readonly attribute nsIRDFCompositeDataSource database;
|
||||
|
||||
/**
|
||||
* Force the template builder to rebuild its content.
|
||||
* The virtual result representing the starting reference point,
|
||||
* determined by calling the query processor's translateRef method
|
||||
* with the root node's ref attribute as an argument.
|
||||
*/
|
||||
readonly attribute nsIXULTemplateResult rootResult;
|
||||
|
||||
/**
|
||||
* Force the template builder to rebuild its content. All existing content
|
||||
* will be removed first. The query processor's done() method will be
|
||||
* invoked during cleanup, followed by its initializeForBuilding method
|
||||
* when the content is to be regenerated.
|
||||
*
|
||||
*/
|
||||
void rebuild();
|
||||
|
||||
|
@ -76,6 +199,100 @@ interface nsIXULTemplateBuilder : nsISupports
|
|||
*/
|
||||
void refresh();
|
||||
|
||||
/**
|
||||
* Inform the template builder that a new result is available. The builder
|
||||
* will add this result to the set of results. The query node that the
|
||||
* new result applies to must be specified using the aQueryNode parameter.
|
||||
*
|
||||
* The builder will apply the rules associated with the query to the new
|
||||
* result, unless a result with the same id from an earlier query
|
||||
* supersedes it, and the result's RuleMatched method will be called if it
|
||||
* matches.
|
||||
*
|
||||
* @param aResult the result to add
|
||||
* @param aQueryNode the query that the result applies to
|
||||
*
|
||||
* @throws NS_ERROR_NULL_POINTER if aResult or aQueryNode are null
|
||||
*/
|
||||
void addResult(in nsIXULTemplateResult aResult, in nsIDOMNode aQueryNode);
|
||||
|
||||
/**
|
||||
* Inform the template builder that a result no longer applies. The builder
|
||||
* will call the remove content generated for the result, if any. If a different
|
||||
* query would then match instead, it will become the active match. This
|
||||
* method will have no effect if the result isn't known to the builder.
|
||||
*
|
||||
* @param aResult the result to remove
|
||||
*
|
||||
* @throws NS_ERROR_NULL_POINTER if aResult is null
|
||||
*/
|
||||
void removeResult(in nsIXULTemplateResult aResult);
|
||||
|
||||
/**
|
||||
* Inform the template builder that one result should be replaced with
|
||||
* another. Both the old result (aOldResult) and the new result
|
||||
* (aNewResult) must have the same id. The query node that the new result
|
||||
* applies to must be specified using the aQueryNode parameter.
|
||||
*
|
||||
* This method is expected to have the same effect as calling both
|
||||
* removeResult for the old result and addResult for the new result.
|
||||
*
|
||||
* @param aOldResult the old result
|
||||
* @param aNewResult the new result
|
||||
* @param aQueryNode the query that the new result applies to
|
||||
*
|
||||
* @throws NS_ERROR_NULL_POINTER if either argument is null, or
|
||||
* NS_ERROR_INVALID_ARG if the ids don't match
|
||||
*/
|
||||
void replaceResult(in nsIXULTemplateResult aOldResult,
|
||||
in nsIXULTemplateResult aNewResult,
|
||||
in nsIDOMNode aQueryNode);
|
||||
|
||||
/**
|
||||
* Inform the template builder that one or more of the optional bindings
|
||||
* for a result has changed. In this case, the rules are not reapplied as
|
||||
* it is expected that the same rule will still apply. The builder will
|
||||
* resynchronize any variables that are referenced in the action body.
|
||||
*
|
||||
* @param aResult the result to change
|
||||
*
|
||||
* @throws NS_ERROR_NULL_POINTER if aResult is null
|
||||
*/
|
||||
void resultBindingChanged(in nsIXULTemplateResult aResult);
|
||||
|
||||
/**
|
||||
* Return the result for a given id. Only one such result is returned and
|
||||
* is always the result with that id associated with the active match.
|
||||
* This method will return null is there is no result for the id.
|
||||
*
|
||||
* @param aId the id to return the result for
|
||||
*/
|
||||
nsIXULTemplateResult getResultForId(in AString aId);
|
||||
|
||||
/**
|
||||
* Returns true if the node has content generated for it. This method is
|
||||
* intended to be called only by the RDF query processor. If aTag is set,
|
||||
* the content must have a tag name that matches aTag. aTag may be ignored
|
||||
* for builders that don't generate real DOM content.
|
||||
*
|
||||
* @param aNode node to check
|
||||
* @param aTag tag that must match
|
||||
*/
|
||||
boolean hasGeneratedContent(in nsIRDFResource aNode, in nsIAtom aTag);
|
||||
|
||||
/**
|
||||
* Adds a rule filter for a given rule, which may be used for specialized
|
||||
* rule filtering. Any existing filter on the rule is removed. The default
|
||||
* conditions specified inside the <rule> tag are applied before the
|
||||
* rule filter is applied, meaning that the filter may be used to further
|
||||
* filter out results but not reaccept results that have already been
|
||||
* rejected.
|
||||
*
|
||||
* @param aRule the rule to apply the filter to
|
||||
* @param aFilter the filter to add
|
||||
*/
|
||||
void addRuleFilter(in nsIDOMNode aRule, in nsIXULTemplateRuleFilter aFilter);
|
||||
|
||||
/**
|
||||
* Called to initialize a XUL content builder on a particular root
|
||||
* element. This element presumably has a ``datasources''
|
||||
|
@ -131,7 +348,7 @@ interface nsIXULTreeBuilderObserver : nsISupports
|
|||
/**
|
||||
* Called when an item is opened or closed.
|
||||
*/
|
||||
void onToggleOpenState (in long index);
|
||||
void onToggleOpenState (in long index);
|
||||
|
||||
/**
|
||||
* Called when a header is clicked.
|
||||
|
|
|
@ -0,0 +1,265 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Neil Deakin.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2005
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include "domstubs.idl"
|
||||
#include "nsISupports.idl"
|
||||
|
||||
interface nsIAtom;
|
||||
interface nsISimpleEnumerator;
|
||||
interface nsIXULTemplateResult;
|
||||
interface nsIXULTemplateRuleFilter;
|
||||
interface nsIXULTemplateBuilder;
|
||||
|
||||
/**
|
||||
* A query processor takes a template query and generates results for it given
|
||||
* a datasource and a reference point. There is a one-to-one relationship
|
||||
* between a template builder and a query processor. The template builder
|
||||
* creates the query processor, and there is no other means to retrieve it.
|
||||
*
|
||||
* A template query is the contents inside a <query> element within the
|
||||
* template. The actual syntax is opaque to the template builder and defined
|
||||
* by a query processor. The query is expected to consist of either text or
|
||||
* DOM nodes that, when executed by a call to the generateResults method, will
|
||||
* allow the generation of a list of results.
|
||||
*
|
||||
* The template builder will supply two variables, the reference variable and
|
||||
* the member variable to further indicate what part of the datasource is to
|
||||
* be examined in addition to the query itself. The reference is always
|
||||
* a placeholder for the starting point and the member is always a placeholder
|
||||
* for the end points (the results).
|
||||
*
|
||||
* The reference point is important when generating output recursively, as
|
||||
* the query will be the same for each iteration, however, the reference point
|
||||
* will differ.
|
||||
*
|
||||
* For instance, when examining an XML source, an XML query processor might
|
||||
* begin at the node referred by the reference variable and end at a list of
|
||||
* that node's children.
|
||||
*
|
||||
* Some queries may not need the reference variable if the syntax or the form
|
||||
* of the data implies the value. For instance, a datasource that holds a
|
||||
* table that can only produce one set of results.
|
||||
*
|
||||
* The reference variable may be specified in a template by setting the
|
||||
* "container" attribute on the <template> element to the variable to use. The
|
||||
* member variable may be specified in a similar way using the "member"
|
||||
* attribute, or it may be specified in the first <action> body in the
|
||||
* template as the value of a uri attribute on an element. A breadth-first
|
||||
* search of the first action is performed to find this element.
|
||||
*
|
||||
* If unspecified, the default value of the reference variable is ?uri.
|
||||
*
|
||||
* For example, a query might have the following syntax:
|
||||
*
|
||||
* (?id, ?name, ?url) from Bookmarks where parentfolder = ?start
|
||||
*
|
||||
* This query might generate a result for each bookmark within a given folder.
|
||||
* The variable ?start would be the reference variable, while the variable ?id
|
||||
* would be the member variable, since it is the unique value that identifies
|
||||
* a result. Each result will have the four variables referred to defined for
|
||||
* it and the values may be retrieved using the result's getBindingFor and
|
||||
* getBindingObjectFor methods.
|
||||
*
|
||||
* The template builder must call initializeForBuilding before the other
|
||||
* methods, except for translateRef. The builder will then call compileQuery
|
||||
* for each query in the template to compile the queries. When results need
|
||||
* to be generated, the builder will call generateResults. The
|
||||
* initializeForBuilding, compileQuery and addBinding methods may not be
|
||||
* called after generateResults has been called until the builder indicates
|
||||
* that the generated output is being removed by calling the done method.
|
||||
*
|
||||
* Currently, the datasource supplied to the methods will always be an
|
||||
* nsIRDFDataSource or a DOM node, and will always be the same one in between
|
||||
* calls to initializeForBuilding and done.
|
||||
*/
|
||||
[scriptable, uuid(11c63d9e-0c0c-444f-b252-f06c546c2ec7)]
|
||||
interface nsIXULTemplateQueryProcessor : nsISupports
|
||||
{
|
||||
/**
|
||||
* Initialize for query generation. This will be called before the rules are
|
||||
* processed and whenever the template is rebuilt. This method must be
|
||||
* called once before any of the other query processor methods except for
|
||||
* translateRef.
|
||||
*
|
||||
* @param aDatasource datasource for the data
|
||||
* @param aBuilder the template builder
|
||||
* @param aRootNode the root node the builder is attached to
|
||||
*
|
||||
* @throws NS_ERROR_INVALID_ARG if the datasource is not supported or
|
||||
* NS_ERROR_UNEXPECTED if generateResults has already been called.
|
||||
*/
|
||||
void initializeForBuilding(in nsISupports aDatasource,
|
||||
in nsIXULTemplateBuilder aBuilder,
|
||||
in nsIDOMNode aRootNode);
|
||||
|
||||
/**
|
||||
* Called when the template builder is being destroyed so that the query
|
||||
* processor can clean up any state. The query processor should remove as
|
||||
* much state as possible, such as results or references to the builder.
|
||||
* This method will also be called when the template is going to be rebuilt.
|
||||
*/
|
||||
void done();
|
||||
|
||||
/**
|
||||
* Compile a query from a node. The result of this function will later be
|
||||
* passed to generateResults for result generation. If null is returned,
|
||||
* the query will be ignored.
|
||||
*
|
||||
* The template builder will call this method once for each query within
|
||||
* the template, before any results can be generated using generateResults,
|
||||
* but after initializeForBuilding has been called. This method should not
|
||||
* be called again for the same query unless the template is rebuilt.
|
||||
*
|
||||
* The reference variable may be used by the query processor as a
|
||||
* placeholder for the reference point, or starting point in the query.
|
||||
*
|
||||
* The member variable is determined from the member attribute on the
|
||||
* template, or from the uri in the first action's rule if that attribute is
|
||||
* not present. A rule processor may use the member variable as a hint to
|
||||
* indicate what variable is expected to contain the results.
|
||||
*
|
||||
* @param aBuilder the template builder
|
||||
* @param aQuery <query> node to compile
|
||||
* @param aRefVariable the reference variable
|
||||
* @param aMemberVariable the member variable
|
||||
*
|
||||
* @returns a compiled query object
|
||||
*/
|
||||
nsISupports compileQuery(in nsIXULTemplateBuilder aBuilder,
|
||||
in nsIDOMNode aQuery,
|
||||
in nsIAtom aRefVariable,
|
||||
in nsIAtom aMemberVariable);
|
||||
|
||||
/**
|
||||
* Generate the results of a query and return them in an enumerator. The
|
||||
* enumerator must contain nsIXULTemplateResult objects. If there are no
|
||||
* results, an empty enumerator must be returned.
|
||||
*
|
||||
* The datasource will be the same as the one passed to the earlier
|
||||
* initializeForBuilding method. The context reference (aRef) is a reference
|
||||
* point used when calculating results.
|
||||
*
|
||||
* The value of aQuery must be the result of a previous call to compileQuery
|
||||
* from this query processor. This method may be called multiple times,
|
||||
* typically with different values for aRef.
|
||||
*
|
||||
* @param aDatasource datasource for the data
|
||||
* @param aRef context reference value used as a starting point
|
||||
* @param aQuery the compiled query returned from query compilation
|
||||
*
|
||||
* @returns an enumerator of nsIXULTemplateResult objects as the results
|
||||
*
|
||||
* @throws NS_ERROR_INVALID_ARG if aQuery is invalid
|
||||
*/
|
||||
nsISimpleEnumerator generateResults(in nsISupports aDatasource,
|
||||
in nsIXULTemplateResult aRef,
|
||||
in nsISupports aQuery);
|
||||
|
||||
/**
|
||||
* Add a variable binding for a particular rule. A binding allows an
|
||||
* additional variable to be set for a result, outside of those defined
|
||||
* within the query. These bindings are always optional, in that they will
|
||||
* never affect the results generated.
|
||||
*
|
||||
* This function will never be called after generateResults. Any bindings
|
||||
* that were added should be applied to each result when the result's
|
||||
* ruleMatched method is called, since the bindings are different for each
|
||||
* rule.
|
||||
*
|
||||
* The reference aRef may be used to determine the reference when
|
||||
* calculating the value for the binding, for example when a value should
|
||||
* depend on the value of another variable.
|
||||
*
|
||||
* The syntax of the expression aExpr is defined by the query processor. If
|
||||
* the syntax is invalid, the binding should be ignored. Only fatal errors
|
||||
* should be thrown, or NS_ERROR_UNEXPECTED if generateResults has already
|
||||
* been called.
|
||||
*
|
||||
* As an example, if the reference aRef is the variable '?count' which
|
||||
* holds the value 5, and the expression aExpr is the string '+2', the value
|
||||
* of the variable aVar would be 7, assuming the query processor considers
|
||||
* the syntax '+2' to mean add two to the reference.
|
||||
*
|
||||
* @param aRuleNode rule to add the binding to
|
||||
* @param aVar variable that will be bound
|
||||
* @param aRef variable that holds reference value
|
||||
* @param aExpr expression used to compute the value to assign
|
||||
*/
|
||||
void addBinding(in nsIDOMNode aRuleNode,
|
||||
in nsIAtom aVar,
|
||||
in nsIAtom aRef,
|
||||
in AString aExpr);
|
||||
|
||||
/**
|
||||
* Translate a ref attribute string into a result. This is used as the
|
||||
* reference point by the template builder when generating the first level
|
||||
* of content. For recursive generation, the result from the parent
|
||||
* generation phase will be used directly as the reference so a translation
|
||||
* is not needed. This allows all levels to be generated using objects that
|
||||
* all implement the nsIXULTemplateResult interface.
|
||||
*
|
||||
* This method may be called before initializeForBuilding, so the
|
||||
* implementation may use the supplied datasource if it is needed to
|
||||
* translate the reference.
|
||||
*
|
||||
* @param aDatasource datasource for the data
|
||||
* @param aRefString the ref attribute string
|
||||
*
|
||||
* @return the translated ref
|
||||
*/
|
||||
nsIXULTemplateResult translateRef(in nsISupports aDatasource,
|
||||
in AString aRefString);
|
||||
|
||||
/**
|
||||
* Compare two results to determine their order, used when sorting results.
|
||||
* This method should return -1 when the left result is less than the right,
|
||||
* 0 if both are equivalent, and 1 if the left is greater than the right.
|
||||
* The comparison should only consider the values for the specified
|
||||
* variable.
|
||||
*
|
||||
* This method must only be called with results that were created by this
|
||||
* query processor.
|
||||
*
|
||||
* @param aLeft the left result to compare
|
||||
* @param aRight the right result to compare
|
||||
* @param aVar variable to compare
|
||||
*
|
||||
* @param returns -1 if less, 0 if equal, or 1 if greater
|
||||
*/
|
||||
PRInt32 compareResults(in nsIXULTemplateResult aLeft,
|
||||
in nsIXULTemplateResult aRight,
|
||||
in nsIAtom aVar);
|
||||
};
|
|
@ -0,0 +1,140 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Neil Deakin.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2005
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include "nsISupports.idl"
|
||||
|
||||
interface nsIAtom;
|
||||
interface nsIDOMNode;
|
||||
interface nsIRDFResource;
|
||||
|
||||
/**
|
||||
* A single result generated from a template query. Each result is identified
|
||||
* by an id, which must be unique within the set of results produced from a
|
||||
* query. The result may optionally be identified by an RDF resource.
|
||||
*
|
||||
* Generally, the result and its id will be able to uniquely identify a node
|
||||
* in the source data, such as an RDF or XML node. In other contexts, such as
|
||||
* a database query, a result would represent a particular record.
|
||||
*
|
||||
* A result is expected to only be created by a query processor.
|
||||
*
|
||||
* Each result also contains a set of variable bindings. The value for a
|
||||
* particular variable may be retrieved using the getBindingFor and
|
||||
* getBindingObjectFor methods.
|
||||
*/
|
||||
[scriptable, uuid(d035f34f-d8ee-444a-bd46-41163f54ed25)]
|
||||
interface nsIXULTemplateResult : nsISupports
|
||||
{
|
||||
/**
|
||||
* True if the result represents a container.
|
||||
*/
|
||||
readonly attribute boolean isContainer;
|
||||
|
||||
/**
|
||||
* True if the result represents an empty container.
|
||||
*/
|
||||
readonly attribute boolean isEmpty;
|
||||
|
||||
/**
|
||||
* True if the template builder may use this result as the reference point
|
||||
* for additional recursive processing of the template. The template builder
|
||||
* will reprocess the template using this result as the reference point and
|
||||
* generate output content that is expected to be inserted as children of the
|
||||
* output generated for this result. If false, child content is not
|
||||
* processed. This property identifies only the default handling and may be
|
||||
* overriden by syntax used in the template.
|
||||
*/
|
||||
readonly attribute boolean mayProcessChildren;
|
||||
|
||||
/**
|
||||
* ID of the result. The DOM element created for this result, if any, will
|
||||
* have its id attribute set to this value. The id must be unique for a
|
||||
* query.
|
||||
*/
|
||||
readonly attribute AString id;
|
||||
|
||||
/**
|
||||
* Resource for the result, which may be null. If set, the resource uri
|
||||
* must be the same as the ID property.
|
||||
*/
|
||||
readonly attribute nsIRDFResource resource;
|
||||
|
||||
/**
|
||||
* Get the string representation of the value of a variable for this
|
||||
* result. This string will be used in the action body from a template as
|
||||
* the replacement text. For instance, if the text ?name appears in an
|
||||
* attribute within the action body, it will be replaced with the result
|
||||
* of this method. The question mark is considered part of the variable
|
||||
* name, thus aVar should be ?name and not simply name.
|
||||
*
|
||||
* @param aVar the variable to look up
|
||||
*
|
||||
* @return the value for the variable or a null string if it has no value
|
||||
*/
|
||||
AString getBindingFor(in nsIAtom aVar);
|
||||
|
||||
/**
|
||||
* Get an object value for a variable such as ?name for this result.
|
||||
*
|
||||
* This method may return null for a variable, even if getBindingFor returns
|
||||
* a non-null value for the same variable. This method is provided as a
|
||||
* convenience when sorting results.
|
||||
*
|
||||
* @param aVar the variable to look up
|
||||
*
|
||||
* @return the value for the variable or null if it has no value
|
||||
*/
|
||||
nsISupports getBindingObjectFor(in nsIAtom aVar);
|
||||
|
||||
/**
|
||||
* Indicate that a particular rule of a query has matched and that output
|
||||
* will be generated for it. Both the query as compiled by the query
|
||||
* processor's compileQuery method and the XUL <rule> element are supplied.
|
||||
* The query must always be one that was compiled by the query processor
|
||||
* that created this result. The <rule> element must always be a child of
|
||||
* the <query> element that was used to compile the query.
|
||||
*
|
||||
* @param aQuery the query that matched
|
||||
* @param aRuleNode the rule node that matched
|
||||
*/
|
||||
void ruleMatched(in nsISupports aQuery, in nsIDOMNode aRuleNode);
|
||||
|
||||
/**
|
||||
* Indicate that the output for a result has beeen removed and that the
|
||||
* result is no longer being used by the builder.
|
||||
*/
|
||||
void hasBeenRemoved();
|
||||
};
|
|
@ -0,0 +1,67 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Neil Deakin.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2005
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include "domstubs.idl"
|
||||
|
||||
interface nsISupports;
|
||||
interface nsIXULTemplateResult;
|
||||
|
||||
/**
|
||||
* A rule filter may be used to add additional filtering of results to a rule.
|
||||
* The filter is used to further reject results from matching the template's
|
||||
* rules, beyond what the template syntax can do itself, thus allowing for
|
||||
* more complex result filtering. The rule filter is applied after the rule
|
||||
* syntax within the template.
|
||||
*
|
||||
* Only one filter may apply to each rule within the template and may be
|
||||
* assigned using the template builder's addRuleFilter method.
|
||||
*/
|
||||
[scriptable, uuid(819cd1ed-8010-42e1-a8b9-778b726a1ff3)]
|
||||
interface nsIXULTemplateRuleFilter : nsISupports
|
||||
{
|
||||
/**
|
||||
* Evaluate a result and return true if the result is accepted by this
|
||||
* filter, or false if it is rejected. Accepted results will have output
|
||||
* generated for them for the rule. Rejected results will not, but they
|
||||
* may still match another rule.
|
||||
*
|
||||
* @param aRef the result to examine
|
||||
* @param aRule the rule node
|
||||
*
|
||||
* @return true if the rule matches
|
||||
*/
|
||||
boolean match(in nsIXULTemplateResult aRef, in nsIDOMNode aRule);
|
||||
};
|
|
@ -66,28 +66,27 @@ REQUIRES = xpcom \
|
|||
$(NULL)
|
||||
|
||||
CPPSRCS = \
|
||||
nsClusterKey.cpp \
|
||||
nsClusterKeySet.cpp \
|
||||
nsConflictSet.cpp \
|
||||
nsContentSupportMap.cpp \
|
||||
nsContentTagTestNode.cpp \
|
||||
nsContentTestNode.cpp \
|
||||
nsInstantiationNode.cpp \
|
||||
nsTreeRowTestNode.cpp \
|
||||
nsTreeRows.cpp \
|
||||
nsRDFConInstanceTestNode.cpp \
|
||||
nsRDFConMemberTestNode.cpp \
|
||||
nsRDFPropertyTestNode.cpp \
|
||||
nsRDFBinding.cpp \
|
||||
nsRDFQuery.cpp \
|
||||
nsResourceSet.cpp \
|
||||
nsRuleNetwork.cpp \
|
||||
nsTemplateMatch.cpp \
|
||||
nsTemplateMatchSet.cpp \
|
||||
nsTemplateRule.cpp \
|
||||
nsXULContentBuilder.cpp \
|
||||
nsXULContentUtils.cpp \
|
||||
nsXULTreeBuilder.cpp \
|
||||
nsXULSortService.cpp \
|
||||
nsXULTemplateBuilder.cpp \
|
||||
nsXULTemplateQueryProcessorRDF.cpp \
|
||||
nsXULTemplateResultRDF.cpp \
|
||||
nsXULTemplateResultSetRDF.cpp \
|
||||
$(NULL)
|
||||
|
||||
# we don't want the shared lib, but we want to force the creation of a static lib.
|
||||
|
|
|
@ -36,37 +36,29 @@
|
|||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include "nsConflictSet.h"
|
||||
#include "nsContentTestNode.h"
|
||||
#include "nsISupportsArray.h"
|
||||
#include "nsIXULDocument.h"
|
||||
#include "nsIRDFResource.h"
|
||||
#include "nsIAtom.h"
|
||||
#include "nsIDOMElement.h"
|
||||
#include "nsXULContentUtils.h"
|
||||
#include "nsPrintfCString.h"
|
||||
#include "nsIXULTemplateResult.h"
|
||||
#include "nsIXULTemplateBuilder.h"
|
||||
#include "nsXULTemplateQueryProcessorRDF.h"
|
||||
|
||||
#include "prlog.h"
|
||||
#ifdef PR_LOGGING
|
||||
extern PRLogModuleInfo* gXULTemplateLog;
|
||||
#endif
|
||||
|
||||
PRBool
|
||||
IsElementInBuilder(nsIContent *aContent, nsIXULTemplateBuilder *aBuilder);
|
||||
|
||||
nsContentTestNode::nsContentTestNode(InnerNode* aParent,
|
||||
nsConflictSet& aConflictSet,
|
||||
nsIXULDocument* aDocument,
|
||||
nsIXULTemplateBuilder* aBuilder,
|
||||
PRInt32 aContentVariable,
|
||||
PRInt32 aIdVariable,
|
||||
nsIAtom* aTag)
|
||||
: TestNode(aParent),
|
||||
mConflictSet(aConflictSet),
|
||||
mDocument(aDocument),
|
||||
mBuilder(aBuilder),
|
||||
mContentVariable(aContentVariable),
|
||||
mIdVariable(aIdVariable),
|
||||
mTag(aTag)
|
||||
nsContentTestNode::nsContentTestNode(nsXULTemplateQueryProcessorRDF* aProcessor,
|
||||
nsIAtom* aRefVariable)
|
||||
: TestNode(nsnull),
|
||||
mProcessor(aProcessor),
|
||||
mDocument(nsnull),
|
||||
mRefVariable(aRefVariable),
|
||||
mTag(nsnull)
|
||||
{
|
||||
#ifdef PR_LOGGING
|
||||
if (PR_LOG_TEST(gXULTemplateLog, PR_LOG_DEBUG)) {
|
||||
|
@ -74,214 +66,57 @@ nsContentTestNode::nsContentTestNode(InnerNode* aParent,
|
|||
if (mTag)
|
||||
mTag->ToString(tag);
|
||||
|
||||
nsAutoString refvar(NS_LITERAL_STRING("(none)"));
|
||||
if (aRefVariable)
|
||||
aRefVariable->ToString(refvar);
|
||||
|
||||
PR_LOG(gXULTemplateLog, PR_LOG_DEBUG,
|
||||
("nsContentTestNode[%p]: parent=%p content-var=%d id-var=%d tag=%s",
|
||||
this, aParent, mContentVariable, mIdVariable,
|
||||
("nsContentTestNode[%p]: ref-var=%s tag=%s",
|
||||
this, NS_ConvertUTF16toUTF8(refvar).get(),
|
||||
NS_ConvertUTF16toUTF8(tag).get()));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef PR_LOGGING
|
||||
static void
|
||||
ElementToString(nsIContent *aContent, nsString &aResult)
|
||||
{
|
||||
aContent->Tag()->ToString(aResult);
|
||||
|
||||
AppendASCIItoUTF16(nsPrintfCString(18, "@%p", aContent), aResult);
|
||||
}
|
||||
#endif
|
||||
|
||||
nsresult
|
||||
nsContentTestNode::FilterInstantiations(InstantiationSet& aInstantiations, void* aClosure) const
|
||||
nsContentTestNode::FilterInstantiations(InstantiationSet& aInstantiations) const
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
nsCOMPtr<nsISupportsArray> elements;
|
||||
rv = NS_NewISupportsArray(getter_AddRefs(elements));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
InstantiationSet::Iterator last = aInstantiations.Last();
|
||||
for (InstantiationSet::Iterator inst = aInstantiations.First(); inst != last; ++inst) {
|
||||
Value contentValue;
|
||||
PRBool hasContentBinding = inst->mAssignments.GetAssignmentFor(mContentVariable, &contentValue);
|
||||
|
||||
Value idValue;
|
||||
PRBool hasIdBinding = inst->mAssignments.GetAssignmentFor(mIdVariable, &idValue);
|
||||
|
||||
#ifdef PR_LOGGING
|
||||
if (PR_LOG_TEST(gXULTemplateLog, PR_LOG_DEBUG)) {
|
||||
nsAutoString content(NS_LITERAL_STRING("(unbound)"));
|
||||
if (hasContentBinding)
|
||||
ElementToString(VALUE_TO_ICONTENT(contentValue), content);
|
||||
|
||||
const char *id = "(unbound)";
|
||||
if (hasIdBinding)
|
||||
VALUE_TO_IRDFRESOURCE(idValue)->GetValueConst(&id);
|
||||
|
||||
PR_LOG(gXULTemplateLog, PR_LOG_DEBUG,
|
||||
("nsContentTestNode[%p]: FilterInstantiations() content=%s id=%s",
|
||||
this, NS_LossyConvertUTF16toASCII(content).get(), id));
|
||||
}
|
||||
#endif
|
||||
|
||||
if (hasContentBinding && hasIdBinding) {
|
||||
// both are bound, consistency check
|
||||
PRBool consistent = PR_TRUE;
|
||||
|
||||
nsIContent* content = VALUE_TO_ICONTENT(contentValue);
|
||||
|
||||
if (mTag) {
|
||||
// If we're supposed to be checking the tag, do it now.
|
||||
if (content->Tag() != mTag)
|
||||
consistent = PR_FALSE;
|
||||
}
|
||||
|
||||
if (consistent) {
|
||||
nsCOMPtr<nsIRDFResource> resource;
|
||||
nsXULContentUtils::GetElementRefResource(content, getter_AddRefs(resource));
|
||||
|
||||
if (resource.get() != VALUE_TO_IRDFRESOURCE(idValue))
|
||||
consistent = PR_FALSE;
|
||||
}
|
||||
|
||||
PR_LOG(gXULTemplateLog, PR_LOG_DEBUG,
|
||||
(" consistency check => %s", consistent ? "passed" : "failed"));
|
||||
|
||||
if (consistent) {
|
||||
Element* element =
|
||||
nsContentTestNode::Element::Create(mConflictSet.GetPool(),
|
||||
VALUE_TO_ICONTENT(contentValue));
|
||||
|
||||
if (! element)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
inst->AddSupportingElement(element);
|
||||
}
|
||||
else {
|
||||
aInstantiations.Erase(inst--);
|
||||
}
|
||||
}
|
||||
else if (hasContentBinding) {
|
||||
// the content node is bound, get its id
|
||||
PRBool consistent = PR_TRUE;
|
||||
|
||||
nsIContent* content = VALUE_TO_ICONTENT(contentValue);
|
||||
|
||||
if (mTag) {
|
||||
// If we're supposed to be checking the tag, do it now.
|
||||
nsIAtom *tag = content->Tag();
|
||||
|
||||
if (tag != mTag) {
|
||||
consistent = PR_FALSE;
|
||||
|
||||
const char *expected, *actual;
|
||||
mTag->GetUTF8String(&expected);
|
||||
tag->GetUTF8String(&actual);
|
||||
|
||||
PR_LOG(gXULTemplateLog, PR_LOG_DEBUG,
|
||||
(" => tag mismatch; expected %s, actual %s",
|
||||
expected,
|
||||
actual));
|
||||
}
|
||||
}
|
||||
|
||||
if (consistent) {
|
||||
nsCOMPtr<nsIRDFResource> resource;
|
||||
nsXULContentUtils::GetElementRefResource(content, getter_AddRefs(resource));
|
||||
|
||||
if (resource) {
|
||||
#ifdef PR_LOGGING
|
||||
if (PR_LOG_TEST(gXULTemplateLog, PR_LOG_DEBUG)) {
|
||||
const char *str;
|
||||
resource->GetValueConst(&str);
|
||||
PR_LOG(gXULTemplateLog, PR_LOG_DEBUG,
|
||||
(" => [%s]", str));
|
||||
}
|
||||
#endif
|
||||
|
||||
Instantiation newinst = *inst;
|
||||
newinst.AddAssignment(mIdVariable, Value(resource.get()));
|
||||
|
||||
Element* element =
|
||||
nsContentTestNode::Element::Create(mConflictSet.GetPool(), content);
|
||||
|
||||
if (! element)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
newinst.AddSupportingElement(element);
|
||||
|
||||
aInstantiations.Insert(inst, newinst);
|
||||
}
|
||||
else {
|
||||
PR_LOG(gXULTemplateLog, PR_LOG_DEBUG,
|
||||
(" => element has no resource"));
|
||||
}
|
||||
}
|
||||
|
||||
aInstantiations.Erase(inst--);
|
||||
}
|
||||
else if (hasIdBinding) {
|
||||
// the 'id' is bound, find elements in the content tree that match
|
||||
const char* uri;
|
||||
VALUE_TO_IRDFRESOURCE(idValue)->GetValueConst(&uri);
|
||||
|
||||
mDocument->GetElementsForID(NS_ConvertUTF8toUTF16(uri), elements);
|
||||
|
||||
PRUint32 count;
|
||||
elements->Count(&count);
|
||||
|
||||
for (PRInt32 j = PRInt32(count) - 1; j >= 0; --j) {
|
||||
nsISupports* isupports = elements->ElementAt(j);
|
||||
nsCOMPtr<nsIContent> content = do_QueryInterface(isupports);
|
||||
NS_IF_RELEASE(isupports);
|
||||
|
||||
if (IsElementInBuilder(content, mBuilder)) {
|
||||
if (mTag) {
|
||||
// If we've got a tag, check it to ensure
|
||||
// we're consistent.
|
||||
if (content->Tag() != mTag)
|
||||
continue;
|
||||
}
|
||||
|
||||
#ifdef PR_LOGGING
|
||||
if (PR_LOG_TEST(gXULTemplateLog, PR_LOG_DEBUG)) {
|
||||
nsAutoString str;
|
||||
ElementToString(content, str);
|
||||
|
||||
PR_LOG(gXULTemplateLog, PR_LOG_DEBUG,
|
||||
(" => %s", NS_LossyConvertUTF16toASCII(str).get()));
|
||||
}
|
||||
#endif
|
||||
|
||||
Instantiation newinst = *inst;
|
||||
newinst.AddAssignment(mContentVariable, Value(content.get()));
|
||||
|
||||
Element* element =
|
||||
nsContentTestNode::Element::Create(mConflictSet.GetPool(), content);
|
||||
|
||||
if (! element)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
newinst.AddSupportingElement(element);
|
||||
|
||||
aInstantiations.Insert(inst, newinst);
|
||||
}
|
||||
}
|
||||
|
||||
aInstantiations.Erase(inst--);
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsContentTestNode::GetAncestorVariables(VariableSet& aVariables) const
|
||||
nsContentTestNode::Constrain(InstantiationSet& aInstantiations)
|
||||
{
|
||||
aVariables.Add(mContentVariable);
|
||||
aVariables.Add(mIdVariable);
|
||||
// contrain the matches to those that have matched in the template builder
|
||||
|
||||
return TestNode::GetAncestorVariables(aVariables);
|
||||
nsIXULTemplateBuilder* builder = mProcessor->GetBuilder();
|
||||
if (!builder) {
|
||||
aInstantiations.Clear();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult rv;
|
||||
|
||||
InstantiationSet::Iterator last = aInstantiations.Last();
|
||||
for (InstantiationSet::Iterator inst = aInstantiations.First(); inst != last; ++inst) {
|
||||
|
||||
nsCOMPtr<nsIRDFNode> refValue;
|
||||
PRBool hasRefBinding = inst->mAssignments.GetAssignmentFor(mRefVariable,
|
||||
getter_AddRefs(refValue));
|
||||
if (hasRefBinding) {
|
||||
nsCOMPtr<nsIRDFResource> refResource = do_QueryInterface(refValue);
|
||||
if (refResource) {
|
||||
PRBool generated;
|
||||
rv = builder->HasGeneratedContent(refResource, mTag, &generated);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
if (generated)
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
aInstantiations.Erase(inst--);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -43,78 +43,37 @@
|
|||
#include "nsRuleNetwork.h"
|
||||
#include "nsFixedSizeAllocator.h"
|
||||
#include "nsIAtom.h"
|
||||
#include "nsIDOMDocument.h"
|
||||
|
||||
class nsIXULTemplateBuilder;
|
||||
class nsIXULDocument;
|
||||
class nsConflictSet;
|
||||
|
||||
/**
|
||||
* The nsContentTestNode is always the top node in a query's rule network. It
|
||||
* exists so that Constrain can filter out resources that aren't part of a
|
||||
* result.
|
||||
*/
|
||||
class nsContentTestNode : public TestNode
|
||||
{
|
||||
public:
|
||||
nsContentTestNode(InnerNode* aParent,
|
||||
nsConflictSet& aConflictSet,
|
||||
nsIXULDocument* aDocument,
|
||||
nsIXULTemplateBuilder* aBuilder,
|
||||
PRInt32 aContentVariable,
|
||||
PRInt32 aIdVariable,
|
||||
nsIAtom* aTag);
|
||||
nsContentTestNode(nsXULTemplateQueryProcessorRDF* aProcessor,
|
||||
nsIAtom* aContentVariable);
|
||||
|
||||
virtual nsresult
|
||||
FilterInstantiations(InstantiationSet& aInstantiations, void* aClosure) const;
|
||||
FilterInstantiations(InstantiationSet& aInstantiations) const;
|
||||
|
||||
virtual nsresult
|
||||
GetAncestorVariables(VariableSet& aVariables) const;
|
||||
nsresult
|
||||
Constrain(InstantiationSet& aInstantiations);
|
||||
|
||||
class Element : public MemoryElement {
|
||||
private:
|
||||
// Hide so that only Create() and Destroy() can be used to
|
||||
// allocate and deallocate from the heap
|
||||
static void* operator new(size_t) CPP_THROW_NEW { return 0; }
|
||||
static void operator delete(void*, size_t) {}
|
||||
|
||||
public:
|
||||
Element(nsIContent* aContent)
|
||||
: mContent(aContent) {
|
||||
MOZ_COUNT_CTOR(nsContentTestNode::Element); }
|
||||
|
||||
virtual ~Element() { MOZ_COUNT_DTOR(nsContentTestNode::Element); }
|
||||
|
||||
static Element*
|
||||
Create(nsFixedSizeAllocator& aPool, nsIContent* aContent) {
|
||||
void* place = aPool.Alloc(sizeof(Element));
|
||||
return place ? ::new (place) Element(aContent) : nsnull; }
|
||||
|
||||
static void
|
||||
Destroy(nsFixedSizeAllocator& aPool, Element* aElement) {
|
||||
aElement->~Element();
|
||||
aPool.Free(aElement, sizeof(*aElement)); }
|
||||
|
||||
virtual const char* Type() const {
|
||||
return "nsContentTestNode::Element"; }
|
||||
|
||||
virtual PLHashNumber Hash() const {
|
||||
return PLHashNumber(NS_PTR_TO_INT32(mContent.get())) >> 2; }
|
||||
|
||||
virtual PRBool Equals(const MemoryElement& aElement) const {
|
||||
if (aElement.Type() == Type()) {
|
||||
const Element& element = NS_STATIC_CAST(const Element&, aElement);
|
||||
return mContent == element.mContent;
|
||||
}
|
||||
return PR_FALSE; }
|
||||
|
||||
virtual MemoryElement* Clone(void* aPool) const {
|
||||
return Create(*NS_STATIC_CAST(nsFixedSizeAllocator*, aPool), mContent); }
|
||||
|
||||
protected:
|
||||
nsCOMPtr<nsIContent> mContent;
|
||||
};
|
||||
void SetTag(nsIAtom* aTag, nsIDOMDocument* aDocument)
|
||||
{
|
||||
mTag = aTag;
|
||||
mDocument = aDocument;
|
||||
}
|
||||
|
||||
protected:
|
||||
nsConflictSet& mConflictSet;
|
||||
nsIXULDocument* mDocument; // [WEAK] because we know the document will outlive us
|
||||
nsIXULTemplateBuilder *mBuilder;
|
||||
PRInt32 mContentVariable;
|
||||
PRInt32 mIdVariable;
|
||||
nsXULTemplateQueryProcessorRDF *mProcessor;
|
||||
nsIDOMDocument* mDocument;
|
||||
nsCOMPtr<nsIAtom> mRefVariable;
|
||||
nsCOMPtr<nsIAtom> mTag;
|
||||
};
|
||||
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
*
|
||||
* Contributor(s):
|
||||
* Chris Waterson <waterson@netscape.com>
|
||||
* Neil Deakin <enndeakin@sympatico.ca>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
|
@ -38,64 +39,83 @@
|
|||
|
||||
#include "nsInstantiationNode.h"
|
||||
#include "nsTemplateRule.h"
|
||||
#include "nsClusterKeySet.h"
|
||||
#include "nsConflictSet.h"
|
||||
#include "nsXULTemplateQueryProcessorRDF.h"
|
||||
|
||||
#include "prlog.h"
|
||||
#ifdef PR_LOGGING
|
||||
extern PRLogModuleInfo* gXULTemplateLog;
|
||||
#endif
|
||||
|
||||
nsInstantiationNode::nsInstantiationNode(nsConflictSet& aConflictSet,
|
||||
nsTemplateRule* aRule,
|
||||
nsIRDFDataSource* aDataSource)
|
||||
: mConflictSet(aConflictSet),
|
||||
mRule(aRule)
|
||||
nsInstantiationNode::nsInstantiationNode(nsXULTemplateQueryProcessorRDF* aProcessor,
|
||||
nsRDFQuery* aQuery)
|
||||
: mProcessor(aProcessor),
|
||||
mQuery(aQuery)
|
||||
{
|
||||
#ifdef PR_LOGGING
|
||||
PR_LOG(gXULTemplateLog, PR_LOG_DEBUG,
|
||||
("nsInstantiationNode[%p] rule=%p", this, aRule));
|
||||
("nsInstantiationNode[%p] query=%p", this, aQuery));
|
||||
#endif
|
||||
|
||||
MOZ_COUNT_CTOR(nsInstantiationNode);
|
||||
}
|
||||
|
||||
|
||||
nsInstantiationNode::~nsInstantiationNode()
|
||||
{
|
||||
delete mRule;
|
||||
MOZ_COUNT_DTOR(nsInstantiationNode);
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsInstantiationNode::Propagate(const InstantiationSet& aInstantiations, void* aClosure)
|
||||
nsInstantiationNode::Propagate(InstantiationSet& aInstantiations,
|
||||
PRBool aIsUpdate, PRBool& aTakenInstantiations)
|
||||
{
|
||||
// If we get here, we've matched the rule associated with this
|
||||
// node. Extend it with any <bindings> that we might have, add it
|
||||
// to the conflict set, and the set of new <content, member>
|
||||
// pairs.
|
||||
nsClusterKeySet* newkeys = NS_STATIC_CAST(nsClusterKeySet*, aClosure);
|
||||
// In update mode, iterate through the results and call the template
|
||||
// builder to update them. In non-update mode, cache them in the processor
|
||||
// to be used during processing. The results are cached in the processor
|
||||
// so that the simple rules are only computed once. In this situation, all
|
||||
// data for all queries are calculated at once.
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
InstantiationSet::ConstIterator last = aInstantiations.Last();
|
||||
for (InstantiationSet::ConstIterator inst = aInstantiations.First(); inst != last; ++inst) {
|
||||
nsAssignmentSet assignments = inst->mAssignments;
|
||||
aTakenInstantiations = PR_FALSE;
|
||||
|
||||
nsTemplateMatch* match =
|
||||
nsTemplateMatch::Create(mConflictSet.GetPool(), mRule, *inst, assignments);
|
||||
if (aIsUpdate) {
|
||||
// Iterate through newly added keys to determine which rules fired.
|
||||
//
|
||||
// XXXwaterson Unfortunately, this could also lead to retractions;
|
||||
// e.g., (container ?a ^empty false) could become "unmatched". How
|
||||
// to track those?
|
||||
nsCOMPtr<nsIDOMNode> querynode;
|
||||
mQuery->GetQueryNode(getter_AddRefs(querynode));
|
||||
|
||||
if (! match)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
InstantiationSet::ConstIterator last = aInstantiations.Last();
|
||||
for (InstantiationSet::ConstIterator inst = aInstantiations.First(); inst != last; ++inst) {
|
||||
nsAssignmentSet assignments = inst->mAssignments;
|
||||
|
||||
// Temporarily AddRef() to keep the match alive.
|
||||
match->AddRef();
|
||||
nsCOMPtr<nsIRDFNode> node;
|
||||
assignments.GetAssignmentFor(mQuery->mMemberVariable,
|
||||
getter_AddRefs(node));
|
||||
if (node) {
|
||||
nsCOMPtr<nsIRDFResource> resource = do_QueryInterface(node);
|
||||
if (resource) {
|
||||
nsRefPtr<nsXULTemplateResultRDF> nextresult =
|
||||
new nsXULTemplateResultRDF(mQuery, *inst, resource);
|
||||
if (! nextresult)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
mRule->InitBindings(mConflictSet, match);
|
||||
rv = mProcessor->AddMemoryElements(*inst, nextresult);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
mConflictSet.Add(match);
|
||||
|
||||
// Give back our "local" reference. The conflict set will have
|
||||
// taken what it needs.
|
||||
match->Release(mConflictSet.GetPool());
|
||||
|
||||
newkeys->Add(nsClusterKey(*inst, mRule));
|
||||
mProcessor->GetBuilder()->AddResult(nextresult, querynode);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
else {
|
||||
nsresult rv = mQuery->SetCachedResults(mProcessor, aInstantiations);
|
||||
if (NS_SUCCEEDED(rv))
|
||||
aTakenInstantiations = PR_TRUE;
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
*
|
||||
* Contributor(s):
|
||||
* Chris Waterson <waterson@netscape.com>
|
||||
* Neil Deakin <enndeakin@sympatico.ca>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
|
@ -40,9 +41,9 @@
|
|||
#define nsInstantiationNode_h__
|
||||
|
||||
#include "nsRuleNetwork.h"
|
||||
class nsIRDFDataSource;
|
||||
class nsConflictSet;
|
||||
class nsTemplateRule;
|
||||
#include "nsRDFQuery.h"
|
||||
|
||||
class nsXULTemplateQueryProcessorRDF;
|
||||
|
||||
/**
|
||||
* A leaf-level node in the rule network. If any instantiations
|
||||
|
@ -51,24 +52,19 @@ class nsTemplateRule;
|
|||
class nsInstantiationNode : public ReteNode
|
||||
{
|
||||
public:
|
||||
nsInstantiationNode(nsConflictSet& aConflictSet,
|
||||
nsTemplateRule* aRule,
|
||||
nsIRDFDataSource* aDataSource);
|
||||
nsInstantiationNode(nsXULTemplateQueryProcessorRDF* aProcessor,
|
||||
nsRDFQuery* aRule);
|
||||
|
||||
~nsInstantiationNode();
|
||||
|
||||
// "downward" propagations
|
||||
virtual nsresult Propagate(const InstantiationSet& aInstantiations, void* aClosure);
|
||||
virtual nsresult Propagate(InstantiationSet& aInstantiations,
|
||||
PRBool aIsUpdate, PRBool& aMatched);
|
||||
|
||||
protected:
|
||||
nsConflictSet& mConflictSet;
|
||||
|
||||
/**
|
||||
* The rule that the node instantiates. The instantiation node
|
||||
* assumes ownership of the rule in its ctor, and will destroy
|
||||
* the rule in its dtor.
|
||||
*/
|
||||
nsTemplateRule* mRule;
|
||||
nsXULTemplateQueryProcessorRDF* mProcessor;
|
||||
nsRDFQuery* mQuery;
|
||||
};
|
||||
|
||||
#endif // nsInstantiationNode_h__
|
||||
|
|
|
@ -0,0 +1,306 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Neil Deakin
|
||||
* Portions created by the Initial Developer are Copyright (C) 2005
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include "nsXULTemplateQueryProcessorRDF.h"
|
||||
#include "nsXULTemplateResultRDF.h"
|
||||
#include "nsRDFBinding.h"
|
||||
|
||||
#ifdef DEBUG
|
||||
#include "nsXULContentUtils.h"
|
||||
#endif
|
||||
|
||||
RDFBindingSet::~RDFBindingSet()
|
||||
{
|
||||
while (mFirst) {
|
||||
RDFBinding* doomed = mFirst;
|
||||
mFirst = mFirst->mNext;
|
||||
delete doomed;
|
||||
}
|
||||
|
||||
MOZ_COUNT_DTOR(RDFBindingSet);
|
||||
}
|
||||
|
||||
nsresult
|
||||
RDFBindingSet::AddBinding(nsIAtom* aVar, nsIAtom* aRef, nsIRDFResource* aPredicate)
|
||||
{
|
||||
RDFBinding* newbinding = new RDFBinding(aRef, aPredicate, aVar);
|
||||
if (! newbinding)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
if (mFirst) {
|
||||
RDFBinding* binding = mFirst;
|
||||
|
||||
while (binding) {
|
||||
// the binding is dependant on the calculation of a previous binding
|
||||
if (binding->mSubjectVariable == aVar)
|
||||
newbinding->mHasDependency = PR_TRUE;
|
||||
|
||||
// if the target variable is already used in a binding, ignore it
|
||||
// since it won't be useful for anything
|
||||
if (binding->mTargetVariable == aVar) {
|
||||
delete newbinding;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// add the binding at the end of the list
|
||||
if (! binding->mNext) {
|
||||
binding->mNext = newbinding;
|
||||
break;
|
||||
}
|
||||
|
||||
binding = binding->mNext;
|
||||
}
|
||||
}
|
||||
else {
|
||||
mFirst = newbinding;
|
||||
}
|
||||
|
||||
mCount++;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
PRBool
|
||||
RDFBindingSet::SyncAssignments(nsIRDFResource* aSubject,
|
||||
nsIRDFResource* aPredicate,
|
||||
nsIRDFNode* aTarget,
|
||||
nsIAtom* aMemberVariable,
|
||||
nsXULTemplateResultRDF* aResult,
|
||||
nsBindingValues& aBindingValues)
|
||||
{
|
||||
NS_ASSERTION(aBindingValues.GetBindingSet() == this,
|
||||
"nsBindingValues not for this RDFBindingSet");
|
||||
NS_PRECONDITION(aResult, "Must have result");
|
||||
|
||||
PRBool needSync = PR_FALSE;
|
||||
nsCOMPtr<nsIRDFNode>* valuesArray = aBindingValues.ValuesArray();
|
||||
if (!valuesArray)
|
||||
return PR_FALSE;
|
||||
|
||||
RDFBinding* binding = mFirst;
|
||||
PRInt32 count = 0;
|
||||
|
||||
// QI for proper comparisons just to be safe
|
||||
nsCOMPtr<nsIRDFNode> subjectnode = do_QueryInterface(aSubject);
|
||||
|
||||
// iterate through the bindings looking for ones that would match the RDF
|
||||
// nodes that were involved in a change
|
||||
nsCOMPtr<nsIRDFNode> value;
|
||||
while (binding) {
|
||||
if (aPredicate == binding->mPredicate) {
|
||||
// if the source of the binding is the member variable, optimize
|
||||
if (binding->mSubjectVariable == aMemberVariable) {
|
||||
valuesArray[count] = aTarget;
|
||||
needSync = PR_TRUE;
|
||||
}
|
||||
else {
|
||||
aResult->GetAssignment(binding->mSubjectVariable, getter_AddRefs(value));
|
||||
if (value == subjectnode) {
|
||||
valuesArray[count] = aTarget;
|
||||
needSync = PR_TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
binding = binding->mNext;
|
||||
count++;
|
||||
}
|
||||
|
||||
return needSync;
|
||||
}
|
||||
|
||||
void
|
||||
RDFBindingSet::AddDependencies(nsIRDFResource* aSubject,
|
||||
nsXULTemplateResultRDF* aResult)
|
||||
{
|
||||
NS_PRECONDITION(aResult, "Must have result");
|
||||
|
||||
// iterate through the bindings and add binding dependencies to the
|
||||
// processor
|
||||
|
||||
nsXULTemplateQueryProcessorRDF* processor = aResult->GetProcessor();
|
||||
if (! processor)
|
||||
return;
|
||||
|
||||
nsCOMPtr<nsIRDFNode> value;
|
||||
|
||||
RDFBinding* binding = mFirst;
|
||||
while (binding) {
|
||||
aResult->GetAssignment(binding->mSubjectVariable, getter_AddRefs(value));
|
||||
|
||||
nsCOMPtr<nsIRDFResource> valueres = do_QueryInterface(value);
|
||||
if (valueres)
|
||||
processor->AddBindingDependency(aResult, valueres);
|
||||
|
||||
binding = binding->mNext;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
RDFBindingSet::RemoveDependencies(nsIRDFResource* aSubject,
|
||||
nsXULTemplateResultRDF* aResult)
|
||||
{
|
||||
NS_PRECONDITION(aResult, "Must have result");
|
||||
|
||||
// iterate through the bindings and remove binding dependencies from the
|
||||
// processor
|
||||
|
||||
nsXULTemplateQueryProcessorRDF* processor = aResult->GetProcessor();
|
||||
if (! processor)
|
||||
return;
|
||||
|
||||
nsCOMPtr<nsIRDFNode> value;
|
||||
|
||||
RDFBinding* binding = mFirst;
|
||||
while (binding) {
|
||||
aResult->GetAssignment(binding->mSubjectVariable, getter_AddRefs(value));
|
||||
|
||||
nsCOMPtr<nsIRDFResource> valueres = do_QueryInterface(value);
|
||||
if (valueres)
|
||||
processor->RemoveBindingDependency(aResult, valueres);
|
||||
|
||||
binding = binding->mNext;
|
||||
}
|
||||
}
|
||||
|
||||
PRInt32
|
||||
RDFBindingSet::LookupTargetIndex(nsIAtom* aTargetVariable, RDFBinding** aBinding)
|
||||
{
|
||||
PRInt32 idx = 0;
|
||||
RDFBinding* binding = mFirst;
|
||||
|
||||
while (binding) {
|
||||
if (binding->mTargetVariable == aTargetVariable) {
|
||||
*aBinding = binding;
|
||||
return idx;
|
||||
}
|
||||
idx++;
|
||||
binding = binding->mNext;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
nsBindingValues::~nsBindingValues()
|
||||
{
|
||||
ClearBindingSet();
|
||||
MOZ_COUNT_DTOR(nsBindingValues);
|
||||
}
|
||||
|
||||
void
|
||||
nsBindingValues::ClearBindingSet()
|
||||
{
|
||||
if (mBindings && mValues) {
|
||||
delete [] mValues;
|
||||
mValues = nsnull;
|
||||
}
|
||||
|
||||
mBindings = nsnull;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsBindingValues::SetBindingSet(RDFBindingSet* aBindings)
|
||||
{
|
||||
ClearBindingSet();
|
||||
|
||||
PRInt32 count = aBindings->Count();
|
||||
if (count) {
|
||||
mValues = new nsCOMPtr<nsIRDFNode>[count];
|
||||
if (!mValues)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
mBindings = aBindings;
|
||||
}
|
||||
else {
|
||||
mValues = nsnull;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
nsBindingValues::GetAssignmentFor(nsXULTemplateResultRDF* aResult,
|
||||
nsIAtom* aVar,
|
||||
nsIRDFNode** aValue)
|
||||
{
|
||||
*aValue = nsnull;
|
||||
|
||||
// assignments are calculated lazily when asked for. The only issue is
|
||||
// when a binding has no value in the RDF graph, it will be checked again
|
||||
// every time.
|
||||
|
||||
if (mBindings && mValues) {
|
||||
RDFBinding* binding;
|
||||
PRInt32 idx = mBindings->LookupTargetIndex(aVar, &binding);
|
||||
if (idx >= 0) {
|
||||
*aValue = mValues[idx];
|
||||
if (*aValue) {
|
||||
NS_ADDREF(*aValue);
|
||||
}
|
||||
else {
|
||||
nsXULTemplateQueryProcessorRDF* processor = aResult->GetProcessor();
|
||||
if (! processor)
|
||||
return;
|
||||
|
||||
nsIRDFDataSource* ds = processor->GetDataSource();
|
||||
if (! ds)
|
||||
return;
|
||||
|
||||
nsCOMPtr<nsIRDFNode> subjectValue;
|
||||
aResult->GetAssignment(binding->mSubjectVariable,
|
||||
getter_AddRefs(subjectValue));
|
||||
|
||||
NS_ASSERTION(subjectValue, "Value of subject is not set");
|
||||
|
||||
if (subjectValue) {
|
||||
nsCOMPtr<nsIRDFResource> subject = do_QueryInterface(subjectValue);
|
||||
|
||||
ds->GetTarget(subject, binding->mPredicate, PR_TRUE, aValue);
|
||||
if (*aValue)
|
||||
mValues[idx] = *aValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsBindingValues::RemoveDependencies(nsIRDFResource* aSubject,
|
||||
nsXULTemplateResultRDF* aResult)
|
||||
{
|
||||
if (mBindings)
|
||||
mBindings->RemoveDependencies(aSubject, aResult);
|
||||
}
|
|
@ -0,0 +1,263 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Neil Deakin
|
||||
* Portions created by the Initial Developer are Copyright (C) 2005
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef nsRDFBinding_h__
|
||||
#define nsRDFBinding_h__
|
||||
|
||||
#include "nsAutoPtr.h"
|
||||
#include "nsIAtom.h"
|
||||
#include "nsIRDFResource.h"
|
||||
|
||||
class nsXULTemplateResultRDF;
|
||||
class nsBindingValues;
|
||||
|
||||
/*
|
||||
* Classes related to storing bindings for RDF handling.
|
||||
*/
|
||||
|
||||
/*
|
||||
* a <binding> descriptors
|
||||
*/
|
||||
class RDFBinding {
|
||||
|
||||
public:
|
||||
|
||||
nsCOMPtr<nsIAtom> mSubjectVariable;
|
||||
nsCOMPtr<nsIRDFResource> mPredicate;
|
||||
nsCOMPtr<nsIAtom> mTargetVariable;
|
||||
|
||||
// indicates whether a binding is dependant on the result from a
|
||||
// previous binding
|
||||
PRBool mHasDependency;
|
||||
|
||||
RDFBinding* mNext;
|
||||
|
||||
private:
|
||||
|
||||
friend class RDFBindingSet;
|
||||
|
||||
RDFBinding(nsIAtom* aSubjectVariable,
|
||||
nsIRDFResource* aPredicate,
|
||||
nsIAtom* aTargetVariable)
|
||||
: mSubjectVariable(aSubjectVariable),
|
||||
mPredicate(aPredicate),
|
||||
mTargetVariable(aTargetVariable),
|
||||
mHasDependency(PR_FALSE),
|
||||
mNext(nsnull)
|
||||
{
|
||||
MOZ_COUNT_CTOR(RDFBinding);
|
||||
}
|
||||
|
||||
~RDFBinding()
|
||||
{
|
||||
MOZ_COUNT_DTOR(RDFBinding);
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
* a collection of <binding> descriptors. This object is refcounted by
|
||||
* nsBindingValues objects and the query processor.
|
||||
*/
|
||||
class RDFBindingSet
|
||||
{
|
||||
protected:
|
||||
|
||||
// results hold a reference to a binding set in their nsBindingValues fields
|
||||
PRInt32 mRefCnt;
|
||||
|
||||
// the number of bindings
|
||||
PRInt32 mCount;
|
||||
|
||||
// pointer to the first binding in a linked list
|
||||
RDFBinding* mFirst;
|
||||
|
||||
public:
|
||||
|
||||
RDFBindingSet()
|
||||
: mRefCnt(0),
|
||||
mCount(0),
|
||||
mFirst(nsnull)
|
||||
{
|
||||
MOZ_COUNT_CTOR(RDFBindingSet);
|
||||
}
|
||||
|
||||
~RDFBindingSet();
|
||||
|
||||
PRInt32 AddRef() {
|
||||
mRefCnt++;
|
||||
NS_LOG_ADDREF(this, mRefCnt, "RDFBindingSet", sizeof(*this));
|
||||
return mRefCnt;
|
||||
}
|
||||
|
||||
PRInt32 Release()
|
||||
{
|
||||
PRInt32 refcnt = --mRefCnt;
|
||||
NS_LOG_RELEASE(this, refcnt, "RDFBindingSet");
|
||||
if (refcnt == 0) delete this;
|
||||
return refcnt;
|
||||
}
|
||||
|
||||
PRInt32 Count() const { return mCount; }
|
||||
|
||||
/*
|
||||
* Add a binding (aRef -> aPredicate -> aVar) to the set
|
||||
*/
|
||||
nsresult
|
||||
AddBinding(nsIAtom* aVar, nsIAtom* aRef, nsIRDFResource* aPredicate);
|
||||
|
||||
/*
|
||||
* Return true if the binding set contains a binding which would cause
|
||||
* the result to need resynchronizing for an RDF triple. The member
|
||||
* variable may be supplied as an optimization since bindings most
|
||||
* commonly use the member variable as the subject. If aMemberVariable
|
||||
* is set, aSubject must be the value of the member variable for the
|
||||
* result. The supplied binding values aBindingValues must be values
|
||||
* using this binding set (that is aBindingValues->GetBindingSet() == this)
|
||||
*
|
||||
* @param aSubject subject of the RDF triple
|
||||
* @param aPredicate predicate of the RDF triple
|
||||
* @param aTarget target of the RDF triple
|
||||
* @param aMemberVariable member variable for the query for the binding
|
||||
* @param aResult result to synchronize
|
||||
* @param aBindingValues the values for the bindings for the result
|
||||
*/
|
||||
PRBool
|
||||
SyncAssignments(nsIRDFResource* aSubject,
|
||||
nsIRDFResource* aPredicate,
|
||||
nsIRDFNode* aTarget,
|
||||
nsIAtom* aMemberVariable,
|
||||
nsXULTemplateResultRDF* aResult,
|
||||
nsBindingValues& aBindingValues);
|
||||
|
||||
/*
|
||||
* The query processor maintains a map of subjects to an array of results.
|
||||
* This is used such that when a new assertion is added to the RDF graph,
|
||||
* the results associated with the subject of that triple may be checked
|
||||
* to see if their bindings have changed. The AddDependencies method adds
|
||||
* these subject dependencies to the map.
|
||||
*/
|
||||
void
|
||||
AddDependencies(nsIRDFResource* aSubject,
|
||||
nsXULTemplateResultRDF* aResult);
|
||||
|
||||
/*
|
||||
* Remove the results from the dependencies map when results are deleted.
|
||||
*/
|
||||
void
|
||||
RemoveDependencies(nsIRDFResource* aSubject,
|
||||
nsXULTemplateResultRDF* aResult);
|
||||
|
||||
/*
|
||||
* The nsBindingValues classes stores an array of values, one for each
|
||||
* target symbol that could be set by the bindings in the set.
|
||||
* LookupTargetIndex determines the index into the array for a given
|
||||
* target symbol.
|
||||
*/
|
||||
PRInt32
|
||||
LookupTargetIndex(nsIAtom* aTargetVariable, RDFBinding** aBinding);
|
||||
};
|
||||
|
||||
/*
|
||||
* A set of values of bindings. This object is used once per result.
|
||||
* This stores a reference to the binding set and an array of node values.
|
||||
* Since the binding set is used once per query and the values are
|
||||
* used once per result, we reduce size by only storing the value array's
|
||||
* length in the binding set. This is possible since the array is always
|
||||
* a fixed length for a particular binding set.
|
||||
*
|
||||
* XXX ndeakin We may want to revisit this later since it makes the code
|
||||
* more complicated.
|
||||
*/
|
||||
class nsBindingValues
|
||||
{
|
||||
protected:
|
||||
|
||||
// the binding set
|
||||
nsRefPtr<RDFBindingSet> mBindings;
|
||||
|
||||
/*
|
||||
* A set of values for variable bindings. To look up a binding value,
|
||||
* scan through the binding set in mBindings for the right target atom.
|
||||
* Its index will correspond to the index in this array. The size of this
|
||||
* array is determined by the RDFBindingSet's Count().
|
||||
*/
|
||||
nsCOMPtr<nsIRDFNode>* mValues;
|
||||
|
||||
public:
|
||||
|
||||
nsBindingValues()
|
||||
: mBindings(nsnull),
|
||||
mValues(nsnull)
|
||||
{
|
||||
MOZ_COUNT_CTOR(nsBindingValues);
|
||||
}
|
||||
|
||||
~nsBindingValues();
|
||||
|
||||
|
||||
/**
|
||||
* Clear the binding set, to be called when the nsBindingValues is deleted
|
||||
* or a new binding set is being set.
|
||||
*/
|
||||
void ClearBindingSet();
|
||||
|
||||
RDFBindingSet* GetBindingSet() { return mBindings; }
|
||||
|
||||
/**
|
||||
* Set the binding set to use. This needs to be called once a rule matches
|
||||
* since it is then known which bindings will apply.
|
||||
*/
|
||||
nsresult SetBindingSet(RDFBindingSet* aBindings);
|
||||
|
||||
nsCOMPtr<nsIRDFNode>* ValuesArray() { return mValues; }
|
||||
|
||||
/*
|
||||
* Retrieve the assignment for a particular variable
|
||||
*/
|
||||
void
|
||||
GetAssignmentFor(nsXULTemplateResultRDF* aResult,
|
||||
nsIAtom* aVar,
|
||||
nsIRDFNode** aValue);
|
||||
|
||||
/*
|
||||
* Remove depenedencies the bindings have on particular resources
|
||||
*/
|
||||
void
|
||||
RemoveDependencies(nsIRDFResource* aSubject,
|
||||
nsXULTemplateResultRDF* aResult);
|
||||
};
|
||||
|
||||
#endif // nsRDFBinding_h__
|
|
@ -36,7 +36,6 @@
|
|||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include "nsConflictSet.h"
|
||||
#include "nsIComponentManager.h"
|
||||
#include "nsIRDFContainer.h"
|
||||
#include "nsIRDFContainerUtils.h"
|
||||
|
@ -44,7 +43,6 @@
|
|||
#include "nsRDFCID.h"
|
||||
#include "nsRDFConInstanceTestNode.h"
|
||||
#include "nsResourceSet.h"
|
||||
#include "nsString.h"
|
||||
|
||||
#include "prlog.h"
|
||||
#ifdef PR_LOGGING
|
||||
|
@ -62,17 +60,13 @@ TestToString(nsRDFConInstanceTestNode::Test aTest) {
|
|||
}
|
||||
#endif
|
||||
|
||||
nsRDFConInstanceTestNode::nsRDFConInstanceTestNode(InnerNode* aParent,
|
||||
nsConflictSet& aConflictSet,
|
||||
nsIRDFDataSource* aDataSource,
|
||||
const nsResourceSet& aMembershipProperties,
|
||||
PRInt32 aContainerVariable,
|
||||
nsRDFConInstanceTestNode::nsRDFConInstanceTestNode(TestNode* aParent,
|
||||
nsXULTemplateQueryProcessorRDF* aProcessor,
|
||||
nsIAtom* aContainerVariable,
|
||||
Test aContainer,
|
||||
Test aEmpty)
|
||||
: nsRDFTestNode(aParent),
|
||||
mConflictSet(aConflictSet),
|
||||
mDataSource(aDataSource),
|
||||
mMembershipProperties(aMembershipProperties),
|
||||
mProcessor(aProcessor),
|
||||
mContainerVariable(aContainerVariable),
|
||||
mContainer(aContainer),
|
||||
mEmpty(aEmpty)
|
||||
|
@ -81,8 +75,9 @@ nsRDFConInstanceTestNode::nsRDFConInstanceTestNode(InnerNode* aParent,
|
|||
if (PR_LOG_TEST(gXULTemplateLog, PR_LOG_DEBUG)) {
|
||||
nsCAutoString props;
|
||||
|
||||
nsResourceSet::ConstIterator last = aMembershipProperties.Last();
|
||||
nsResourceSet::ConstIterator first = aMembershipProperties.First();
|
||||
nsResourceSet& containmentProps = aProcessor->ContainmentProperties();
|
||||
nsResourceSet::ConstIterator last = containmentProps.Last();
|
||||
nsResourceSet::ConstIterator first = containmentProps.First();
|
||||
nsResourceSet::ConstIterator iter;
|
||||
|
||||
for (iter = first; iter != last; ++iter) {
|
||||
|
@ -95,12 +90,16 @@ nsRDFConInstanceTestNode::nsRDFConInstanceTestNode(InnerNode* aParent,
|
|||
props += str;
|
||||
}
|
||||
|
||||
nsAutoString cvar(NS_LITERAL_STRING("(none)"));
|
||||
if (mContainerVariable)
|
||||
mContainerVariable->ToString(cvar);
|
||||
|
||||
PR_LOG(gXULTemplateLog, PR_LOG_DEBUG,
|
||||
("nsRDFConInstanceTestNode[%p]: parent=%p member-props=(%s) container-var=%d container=%s empty=%s",
|
||||
("nsRDFConInstanceTestNode[%p]: parent=%p member-props=(%s) container-var=%s container=%s empty=%s",
|
||||
this,
|
||||
aParent,
|
||||
props.get(),
|
||||
mContainerVariable,
|
||||
NS_ConvertUTF16toUTF8(cvar).get(),
|
||||
TestToString(aContainer),
|
||||
TestToString(aEmpty)));
|
||||
}
|
||||
|
@ -108,7 +107,7 @@ nsRDFConInstanceTestNode::nsRDFConInstanceTestNode(InnerNode* aParent,
|
|||
}
|
||||
|
||||
nsresult
|
||||
nsRDFConInstanceTestNode::FilterInstantiations(InstantiationSet& aInstantiations, void* aClosure) const
|
||||
nsRDFConInstanceTestNode::FilterInstantiations(InstantiationSet& aInstantiations) const
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
|
@ -118,18 +117,26 @@ nsRDFConInstanceTestNode::FilterInstantiations(InstantiationSet& aInstantiations
|
|||
if (! rdfc)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
nsIRDFDataSource* ds = mProcessor->GetDataSource();
|
||||
|
||||
InstantiationSet::Iterator last = aInstantiations.Last();
|
||||
for (InstantiationSet::Iterator inst = aInstantiations.First(); inst != last; ++inst) {
|
||||
Value value;
|
||||
if (! inst->mAssignments.GetAssignmentFor(mContainerVariable, &value)) {
|
||||
nsCOMPtr<nsIRDFNode> value;
|
||||
if (! inst->mAssignments.GetAssignmentFor(mContainerVariable, getter_AddRefs(value))) {
|
||||
NS_ERROR("can't do unbounded container testing");
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIRDFResource> valueres = do_QueryInterface(value);
|
||||
if (! valueres) {
|
||||
aInstantiations.Erase(inst--);
|
||||
continue;
|
||||
}
|
||||
|
||||
#ifdef PR_LOGGING
|
||||
if (PR_LOG_TEST(gXULTemplateLog, PR_LOG_DEBUG)) {
|
||||
const char* container;
|
||||
VALUE_TO_IRDFRESOURCE(value)->GetValueConst(&container);
|
||||
const char* container = "(unbound)";
|
||||
valueres->GetValueConst(&container);
|
||||
|
||||
PR_LOG(gXULTemplateLog, PR_LOG_DEBUG,
|
||||
("nsRDFConInstanceTestNode[%p]::FilterInstantiations() container=[%s]",
|
||||
|
@ -140,7 +147,7 @@ nsRDFConInstanceTestNode::FilterInstantiations(InstantiationSet& aInstantiations
|
|||
nsCOMPtr<nsIRDFContainer> rdfcontainer;
|
||||
|
||||
PRBool isRDFContainer;
|
||||
rv = rdfc->IsContainer(mDataSource, VALUE_TO_IRDFRESOURCE(value), &isRDFContainer);
|
||||
rv = rdfc->IsContainer(ds, valueres, &isRDFContainer);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
if (mEmpty != eDontCare || mContainer != eDontCare) {
|
||||
|
@ -156,7 +163,7 @@ nsRDFConInstanceTestNode::FilterInstantiations(InstantiationSet& aInstantiations
|
|||
rdfcontainer = do_CreateInstance("@mozilla.org/rdf/container;1", &rv);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
rv = rdfcontainer->Init(mDataSource, VALUE_TO_IRDFRESOURCE(value));
|
||||
rv = rdfcontainer->Init(ds, valueres);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
PRInt32 count;
|
||||
|
@ -169,13 +176,14 @@ nsRDFConInstanceTestNode::FilterInstantiations(InstantiationSet& aInstantiations
|
|||
container = eFalse;
|
||||
|
||||
// First do the simple check of finding some outward
|
||||
// arcs; mMembershipProperties should be short, so this can
|
||||
// arcs; there should be only a few containment arcs, so this can
|
||||
// save us time from dealing with an iterator later on
|
||||
for (nsResourceSet::ConstIterator property = mMembershipProperties.First();
|
||||
property != mMembershipProperties.Last();
|
||||
nsResourceSet& containmentProps = mProcessor->ContainmentProperties();
|
||||
for (nsResourceSet::ConstIterator property = containmentProps.First();
|
||||
property != containmentProps.Last();
|
||||
++property) {
|
||||
nsCOMPtr<nsIRDFNode> target;
|
||||
rv = mDataSource->GetTarget(VALUE_TO_IRDFRESOURCE(value), *property, PR_TRUE, getter_AddRefs(target));
|
||||
rv = ds->GetTarget(valueres, *property, PR_TRUE, getter_AddRefs(target));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
if (target != nsnull) {
|
||||
|
@ -191,7 +199,7 @@ nsRDFConInstanceTestNode::FilterInstantiations(InstantiationSet& aInstantiations
|
|||
// to check ArcLabelsOut for potential container arcs.
|
||||
if (container == eFalse && mContainer != eDontCare) {
|
||||
nsCOMPtr<nsISimpleEnumerator> arcsout;
|
||||
rv = mDataSource->ArcLabelsOut(VALUE_TO_IRDFRESOURCE(value), getter_AddRefs(arcsout));
|
||||
rv = ds->ArcLabelsOut(valueres, getter_AddRefs(arcsout));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
while (1) {
|
||||
|
@ -211,7 +219,7 @@ nsRDFConInstanceTestNode::FilterInstantiations(InstantiationSet& aInstantiations
|
|||
if (! property)
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
|
||||
if (mMembershipProperties.Contains(property)) {
|
||||
if (mProcessor->ContainmentProperties().Contains(property)) {
|
||||
container = eTrue;
|
||||
break;
|
||||
}
|
||||
|
@ -232,9 +240,8 @@ nsRDFConInstanceTestNode::FilterInstantiations(InstantiationSet& aInstantiations
|
|||
((mContainer == eDontCare) && (mEmpty == empty)))
|
||||
{
|
||||
Element* element =
|
||||
nsRDFConInstanceTestNode::Element::Create(mConflictSet.GetPool(),
|
||||
VALUE_TO_IRDFRESOURCE(value),
|
||||
container, empty);
|
||||
nsRDFConInstanceTestNode::Element::Create(mProcessor->GetPool(),
|
||||
valueres, container, empty);
|
||||
|
||||
if (! element)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
@ -250,17 +257,6 @@ nsRDFConInstanceTestNode::FilterInstantiations(InstantiationSet& aInstantiations
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsRDFConInstanceTestNode::GetAncestorVariables(VariableSet& aVariables) const
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
rv = aVariables.Add(mContainerVariable);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
return TestNode::GetAncestorVariables(aVariables);
|
||||
}
|
||||
|
||||
PRBool
|
||||
nsRDFConInstanceTestNode::CanPropagate(nsIRDFResource* aSource,
|
||||
nsIRDFResource* aProperty,
|
||||
|
@ -282,7 +278,7 @@ nsRDFConInstanceTestNode::CanPropagate(nsIRDFResource* aSource,
|
|||
if (NS_FAILED(rv)) return PR_FALSE;
|
||||
|
||||
if (! canpropagate) {
|
||||
canpropagate = mMembershipProperties.Contains(aProperty);
|
||||
canpropagate = mProcessor->ContainmentProperties().Contains(aProperty);
|
||||
}
|
||||
|
||||
#ifdef PR_LOGGING
|
||||
|
@ -304,7 +300,7 @@ nsRDFConInstanceTestNode::CanPropagate(nsIRDFResource* aSource,
|
|||
#endif
|
||||
|
||||
if (canpropagate) {
|
||||
aInitialBindings.AddAssignment(mContainerVariable, Value(aSource));
|
||||
aInitialBindings.AddAssignment(mContainerVariable, aSource);
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
|
@ -314,13 +310,11 @@ nsRDFConInstanceTestNode::CanPropagate(nsIRDFResource* aSource,
|
|||
void
|
||||
nsRDFConInstanceTestNode::Retract(nsIRDFResource* aSource,
|
||||
nsIRDFResource* aProperty,
|
||||
nsIRDFNode* aTarget,
|
||||
nsTemplateMatchSet& aFirings,
|
||||
nsTemplateMatchSet& aRetractions) const
|
||||
nsIRDFNode* aTarget) const
|
||||
{
|
||||
// XXXwaterson oof. complicated. figure this out.
|
||||
if (0) {
|
||||
mConflictSet.Remove(Element(aSource, mContainer, mEmpty), aFirings, aRetractions);
|
||||
mProcessor->RetractElement(Element(aSource, mContainer, mEmpty));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -40,12 +40,11 @@
|
|||
#define nsRDFConInstanceTestNode_h__
|
||||
|
||||
#include "nscore.h"
|
||||
#include "nsRDFTestNode.h"
|
||||
#include "nsFixedSizeAllocator.h"
|
||||
#include "nsRDFTestNode.h"
|
||||
#include "nsIRDFResource.h"
|
||||
#include "nsIRDFDataSource.h"
|
||||
class nsConflictSet;
|
||||
class nsResourceSet;
|
||||
#include "nsXULTemplateQueryProcessorRDF.h"
|
||||
|
||||
/**
|
||||
* Rule network node that tests if a resource is an RDF container, or
|
||||
|
@ -56,17 +55,13 @@ class nsRDFConInstanceTestNode : public nsRDFTestNode
|
|||
public:
|
||||
enum Test { eFalse, eTrue, eDontCare };
|
||||
|
||||
nsRDFConInstanceTestNode(InnerNode* aParent,
|
||||
nsConflictSet& aConflictSet,
|
||||
nsIRDFDataSource* aDataSource,
|
||||
const nsResourceSet& aMembershipProperties,
|
||||
PRInt32 aContainerVariable,
|
||||
nsRDFConInstanceTestNode(TestNode* aParent,
|
||||
nsXULTemplateQueryProcessorRDF* aProcessor,
|
||||
nsIAtom* aContainerVariable,
|
||||
Test aContainer,
|
||||
Test aEmpty);
|
||||
|
||||
virtual nsresult FilterInstantiations(InstantiationSet& aInstantiations, void* aClosure) const;
|
||||
|
||||
virtual nsresult GetAncestorVariables(VariableSet& aVariables) const;
|
||||
virtual nsresult FilterInstantiations(InstantiationSet& aInstantiations) const;
|
||||
|
||||
virtual PRBool
|
||||
CanPropagate(nsIRDFResource* aSource,
|
||||
|
@ -77,9 +72,7 @@ public:
|
|||
virtual void
|
||||
Retract(nsIRDFResource* aSource,
|
||||
nsIRDFResource* aProperty,
|
||||
nsIRDFNode* aTarget,
|
||||
nsTemplateMatchSet& aFirings,
|
||||
nsTemplateMatchSet& aRetractions) const;
|
||||
nsIRDFNode* aTarget) const;
|
||||
|
||||
|
||||
class Element : public MemoryElement {
|
||||
|
@ -139,10 +132,8 @@ public:
|
|||
};
|
||||
|
||||
protected:
|
||||
nsConflictSet& mConflictSet;
|
||||
nsCOMPtr<nsIRDFDataSource> mDataSource;
|
||||
const nsResourceSet& mMembershipProperties;
|
||||
PRInt32 mContainerVariable;
|
||||
nsXULTemplateQueryProcessorRDF* mProcessor;
|
||||
nsCOMPtr<nsIAtom> mContainerVariable;
|
||||
Test mContainer;
|
||||
Test mEmpty;
|
||||
};
|
||||
|
|
|
@ -42,7 +42,6 @@
|
|||
#include "nsRDFCID.h"
|
||||
#include "nsIServiceManager.h"
|
||||
#include "nsResourceSet.h"
|
||||
#include "nsConflictSet.h"
|
||||
#include "nsString.h"
|
||||
|
||||
#include "prlog.h"
|
||||
|
@ -51,16 +50,12 @@
|
|||
extern PRLogModuleInfo* gXULTemplateLog;
|
||||
#endif
|
||||
|
||||
nsRDFConMemberTestNode::nsRDFConMemberTestNode(InnerNode* aParent,
|
||||
nsConflictSet& aConflictSet,
|
||||
nsIRDFDataSource* aDataSource,
|
||||
const nsResourceSet& aMembershipProperties,
|
||||
PRInt32 aContainerVariable,
|
||||
PRInt32 aMemberVariable)
|
||||
nsRDFConMemberTestNode::nsRDFConMemberTestNode(TestNode* aParent,
|
||||
nsXULTemplateQueryProcessorRDF* aProcessor,
|
||||
nsIAtom *aContainerVariable,
|
||||
nsIAtom *aMemberVariable)
|
||||
: nsRDFTestNode(aParent),
|
||||
mConflictSet(aConflictSet),
|
||||
mDataSource(aDataSource),
|
||||
mMembershipProperties(aMembershipProperties),
|
||||
mProcessor(aProcessor),
|
||||
mContainerVariable(aContainerVariable),
|
||||
mMemberVariable(aMemberVariable)
|
||||
{
|
||||
|
@ -68,8 +63,9 @@ nsRDFConMemberTestNode::nsRDFConMemberTestNode(InnerNode* aParent,
|
|||
if (PR_LOG_TEST(gXULTemplateLog, PR_LOG_DEBUG)) {
|
||||
nsCAutoString props;
|
||||
|
||||
nsResourceSet::ConstIterator last = aMembershipProperties.Last();
|
||||
nsResourceSet::ConstIterator first = aMembershipProperties.First();
|
||||
nsResourceSet& containmentProps = aProcessor->ContainmentProperties();
|
||||
nsResourceSet::ConstIterator last = containmentProps.Last();
|
||||
nsResourceSet::ConstIterator first = containmentProps.First();
|
||||
nsResourceSet::ConstIterator iter;
|
||||
|
||||
for (iter = first; iter != last; ++iter) {
|
||||
|
@ -82,19 +78,27 @@ nsRDFConMemberTestNode::nsRDFConMemberTestNode(InnerNode* aParent,
|
|||
props += str;
|
||||
}
|
||||
|
||||
nsAutoString cvar(NS_LITERAL_STRING("(none)"));
|
||||
if (mContainerVariable)
|
||||
mContainerVariable->ToString(cvar);
|
||||
|
||||
nsAutoString mvar(NS_LITERAL_STRING("(none)"));
|
||||
if (mMemberVariable)
|
||||
mMemberVariable->ToString(mvar);
|
||||
|
||||
PR_LOG(gXULTemplateLog, PR_LOG_DEBUG,
|
||||
("nsRDFConMemberTestNode[%p]: parent=%p member-props=(%s) container-var=%d member-var=%d",
|
||||
("nsRDFConMemberTestNode[%p]: parent=%p member-props=(%s) container-var=%s member-var=%s",
|
||||
this,
|
||||
aParent,
|
||||
props.get(),
|
||||
mContainerVariable,
|
||||
mMemberVariable));
|
||||
NS_ConvertUTF16toUTF8(cvar).get(),
|
||||
NS_ConvertUTF16toUTF8(mvar).get()));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsRDFConMemberTestNode::FilterInstantiations(InstantiationSet& aInstantiations, void* aClosure) const
|
||||
nsRDFConMemberTestNode::FilterInstantiations(InstantiationSet& aInstantiations) const
|
||||
{
|
||||
// XXX Uh, factor me, please!
|
||||
nsresult rv;
|
||||
|
@ -105,46 +109,50 @@ nsRDFConMemberTestNode::FilterInstantiations(InstantiationSet& aInstantiations,
|
|||
if (! rdfc)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
nsIRDFDataSource* ds = mProcessor->GetDataSource();
|
||||
|
||||
InstantiationSet::Iterator last = aInstantiations.Last();
|
||||
for (InstantiationSet::Iterator inst = aInstantiations.First(); inst != last; ++inst) {
|
||||
PRBool hasContainerBinding;
|
||||
Value containerValue;
|
||||
hasContainerBinding = inst->mAssignments.GetAssignmentFor(mContainerVariable, &containerValue);
|
||||
nsCOMPtr<nsIRDFNode> containerValue;
|
||||
hasContainerBinding = inst->mAssignments.GetAssignmentFor(mContainerVariable,
|
||||
getter_AddRefs(containerValue));
|
||||
|
||||
nsCOMPtr<nsIRDFResource> containerRes = do_QueryInterface(containerValue);
|
||||
|
||||
nsCOMPtr<nsIRDFContainer> rdfcontainer;
|
||||
|
||||
if (hasContainerBinding) {
|
||||
if (hasContainerBinding && containerRes) {
|
||||
// If we have a container assignment, then see if the
|
||||
// container is an RDF container (bag, seq, alt), and if
|
||||
// so, wrap it.
|
||||
PRBool isRDFContainer;
|
||||
rv = rdfc->IsContainer(mDataSource,
|
||||
VALUE_TO_IRDFRESOURCE(containerValue),
|
||||
&isRDFContainer);
|
||||
rv = rdfc->IsContainer(ds, containerRes, &isRDFContainer);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
if (isRDFContainer) {
|
||||
rdfcontainer = do_CreateInstance("@mozilla.org/rdf/container;1", &rv);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
rv = rdfcontainer->Init(mDataSource, VALUE_TO_IRDFRESOURCE(containerValue));
|
||||
rv = rdfcontainer->Init(ds, containerRes);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
}
|
||||
}
|
||||
|
||||
PRBool hasMemberBinding;
|
||||
Value memberValue;
|
||||
hasMemberBinding = inst->mAssignments.GetAssignmentFor(mMemberVariable, &memberValue);
|
||||
nsCOMPtr<nsIRDFNode> memberValue;
|
||||
hasMemberBinding = inst->mAssignments.GetAssignmentFor(mMemberVariable,
|
||||
getter_AddRefs(memberValue));
|
||||
|
||||
#ifdef PR_LOGGING
|
||||
if (PR_LOG_TEST(gXULTemplateLog, PR_LOG_DEBUG)) {
|
||||
const char* container = "(unbound)";
|
||||
if (hasContainerBinding)
|
||||
VALUE_TO_IRDFRESOURCE(containerValue)->GetValueConst(&container);
|
||||
containerRes->GetValueConst(&container);
|
||||
|
||||
nsAutoString member(NS_LITERAL_STRING("(unbound)"));
|
||||
if (hasMemberBinding)
|
||||
nsXULContentUtils::GetTextForNode(VALUE_TO_IRDFRESOURCE(memberValue), member);
|
||||
nsXULContentUtils::GetTextForNode(memberValue, member);
|
||||
|
||||
PR_LOG(gXULTemplateLog, PR_LOG_DEBUG,
|
||||
("nsRDFConMemberTestNode[%p]: FilterInstantiations() container=[%s] member=[%s]",
|
||||
|
@ -159,7 +167,7 @@ nsRDFConMemberTestNode::FilterInstantiations(InstantiationSet& aInstantiations,
|
|||
if (rdfcontainer) {
|
||||
// RDF containers are easy. Just use the container API.
|
||||
PRInt32 index;
|
||||
rv = rdfcontainer->IndexOf(VALUE_TO_IRDFRESOURCE(memberValue), &index);
|
||||
rv = rdfcontainer->IndexOf(memberValue, &index);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
if (index >= 0)
|
||||
|
@ -174,15 +182,16 @@ nsRDFConMemberTestNode::FilterInstantiations(InstantiationSet& aInstantiations,
|
|||
// Othewise, we'll need to grovel through the
|
||||
// membership properties to see if we have an
|
||||
// assertion that indicates membership.
|
||||
for (nsResourceSet::ConstIterator property = mMembershipProperties.First();
|
||||
property != mMembershipProperties.Last();
|
||||
nsResourceSet& containmentProps = mProcessor->ContainmentProperties();
|
||||
for (nsResourceSet::ConstIterator property = containmentProps.First();
|
||||
property != containmentProps.Last();
|
||||
++property) {
|
||||
PRBool hasAssertion;
|
||||
rv = mDataSource->HasAssertion(VALUE_TO_IRDFRESOURCE(containerValue),
|
||||
*property,
|
||||
VALUE_TO_IRDFNODE(memberValue),
|
||||
PR_TRUE,
|
||||
&hasAssertion);
|
||||
rv = ds->HasAssertion(containerRes,
|
||||
*property,
|
||||
memberValue,
|
||||
PR_TRUE,
|
||||
&hasAssertion);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
if (hasAssertion) {
|
||||
|
@ -200,9 +209,9 @@ nsRDFConMemberTestNode::FilterInstantiations(InstantiationSet& aInstantiations,
|
|||
if (isconsistent) {
|
||||
// Add a memory element to our set-of-support.
|
||||
Element* element =
|
||||
nsRDFConMemberTestNode::Element::Create(mConflictSet.GetPool(),
|
||||
VALUE_TO_IRDFRESOURCE(containerValue),
|
||||
VALUE_TO_IRDFNODE(memberValue));
|
||||
nsRDFConMemberTestNode::Element::Create(mProcessor->GetPool(),
|
||||
containerRes,
|
||||
memberValue);
|
||||
|
||||
if (! element)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
@ -253,18 +262,17 @@ nsRDFConMemberTestNode::FilterInstantiations(InstantiationSet& aInstantiations,
|
|||
#endif
|
||||
|
||||
Instantiation newinst = *inst;
|
||||
newinst.AddAssignment(mMemberVariable, Value(node.get()));
|
||||
newinst.AddAssignment(mMemberVariable, node);
|
||||
|
||||
Element* element =
|
||||
nsRDFConMemberTestNode::Element::Create(mConflictSet.GetPool(),
|
||||
VALUE_TO_IRDFRESOURCE(containerValue),
|
||||
nsRDFConMemberTestNode::Element::Create(mProcessor->GetPool(),
|
||||
containerRes,
|
||||
node);
|
||||
|
||||
if (! element)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
newinst.AddSupportingElement(element);
|
||||
|
||||
aInstantiations.Insert(inst, newinst);
|
||||
}
|
||||
}
|
||||
|
@ -276,7 +284,7 @@ nsRDFConMemberTestNode::FilterInstantiations(InstantiationSet& aInstantiations,
|
|||
// container might have). If so, walk it backwards to get
|
||||
// the container we're in.
|
||||
nsCOMPtr<nsISimpleEnumerator> arcsin;
|
||||
rv = mDataSource->ArcLabelsIn(VALUE_TO_IRDFNODE(memberValue), getter_AddRefs(arcsin));
|
||||
rv = ds->ArcLabelsIn(memberValue, getter_AddRefs(arcsin));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
while (1) {
|
||||
|
@ -314,8 +322,8 @@ nsRDFConMemberTestNode::FilterInstantiations(InstantiationSet& aInstantiations,
|
|||
// member node. Find all the people that point to
|
||||
// it, and call them containers.
|
||||
nsCOMPtr<nsISimpleEnumerator> sources;
|
||||
rv = mDataSource->GetSources(property, VALUE_TO_IRDFNODE(memberValue), PR_TRUE,
|
||||
getter_AddRefs(sources));
|
||||
rv = ds->GetSources(property, memberValue, PR_TRUE,
|
||||
getter_AddRefs(sources));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
while (1) {
|
||||
|
@ -346,12 +354,12 @@ nsRDFConMemberTestNode::FilterInstantiations(InstantiationSet& aInstantiations,
|
|||
|
||||
// Add a new instantiation
|
||||
Instantiation newinst = *inst;
|
||||
newinst.AddAssignment(mContainerVariable, Value(source.get()));
|
||||
newinst.AddAssignment(mContainerVariable, source);
|
||||
|
||||
Element* element =
|
||||
nsRDFConMemberTestNode::Element::Create(mConflictSet.GetPool(),
|
||||
nsRDFConMemberTestNode::Element::Create(mProcessor->GetPool(),
|
||||
source,
|
||||
VALUE_TO_IRDFNODE(memberValue));
|
||||
memberValue);
|
||||
|
||||
if (! element)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
@ -369,17 +377,18 @@ nsRDFConMemberTestNode::FilterInstantiations(InstantiationSet& aInstantiations,
|
|||
// it's an open ended query on the container or member. go
|
||||
// through our containment properties to see if anything
|
||||
// applies.
|
||||
for (nsResourceSet::ConstIterator property = mMembershipProperties.First();
|
||||
property != mMembershipProperties.Last();
|
||||
nsResourceSet& containmentProps = mProcessor->ContainmentProperties();
|
||||
for (nsResourceSet::ConstIterator property = containmentProps.First();
|
||||
property != containmentProps.Last();
|
||||
++property) {
|
||||
nsCOMPtr<nsISimpleEnumerator> results;
|
||||
if (hasContainerBinding) {
|
||||
rv = mDataSource->GetTargets(VALUE_TO_IRDFRESOURCE(containerValue), *property, PR_TRUE,
|
||||
getter_AddRefs(results));
|
||||
rv = ds->GetTargets(containerRes, *property, PR_TRUE,
|
||||
getter_AddRefs(results));
|
||||
}
|
||||
else {
|
||||
rv = mDataSource->GetSources(*property, VALUE_TO_IRDFNODE(memberValue), PR_TRUE,
|
||||
getter_AddRefs(results));
|
||||
rv = ds->GetSources(*property, memberValue, PR_TRUE,
|
||||
getter_AddRefs(results));
|
||||
}
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
|
@ -395,46 +404,43 @@ nsRDFConMemberTestNode::FilterInstantiations(InstantiationSet& aInstantiations,
|
|||
rv = results->GetNext(getter_AddRefs(isupports));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
PRInt32 variable;
|
||||
Value value;
|
||||
nsIAtom* variable;
|
||||
nsCOMPtr<nsIRDFNode> value;
|
||||
nsCOMPtr<nsIRDFResource> valueRes;
|
||||
|
||||
if (hasContainerBinding) {
|
||||
variable = mMemberVariable;
|
||||
|
||||
nsCOMPtr<nsIRDFNode> member = do_QueryInterface(isupports);
|
||||
NS_ASSERTION(member != nsnull, "member is not an nsIRDFNode");
|
||||
if (! member) continue;
|
||||
value = do_QueryInterface(isupports);
|
||||
NS_ASSERTION(value != nsnull, "member is not an nsIRDFNode");
|
||||
if (! value) continue;
|
||||
|
||||
#ifdef PR_LOGGING
|
||||
if (PR_LOG_TEST(gXULTemplateLog, PR_LOG_DEBUG)) {
|
||||
nsAutoString s;
|
||||
nsXULContentUtils::GetTextForNode(member, s);
|
||||
nsXULContentUtils::GetTextForNode(value, s);
|
||||
|
||||
PR_LOG(gXULTemplateLog, PR_LOG_DEBUG,
|
||||
(" member => %s", NS_ConvertUTF16toUTF8(s).get()));
|
||||
}
|
||||
#endif
|
||||
|
||||
value = member.get();
|
||||
}
|
||||
else {
|
||||
variable = mContainerVariable;
|
||||
|
||||
nsCOMPtr<nsIRDFResource> container = do_QueryInterface(isupports);
|
||||
NS_ASSERTION(container != nsnull, "container is not an nsIRDFResource");
|
||||
if (! container) continue;
|
||||
valueRes = do_QueryInterface(isupports);
|
||||
NS_ASSERTION(valueRes != nsnull, "container is not an nsIRDFResource");
|
||||
if (! valueRes) continue;
|
||||
|
||||
#ifdef PR_LOGGING
|
||||
if (PR_LOG_TEST(gXULTemplateLog, PR_LOG_DEBUG)) {
|
||||
const char* s;
|
||||
container->GetValueConst(&s);
|
||||
valueRes->GetValueConst(&s);
|
||||
|
||||
PR_LOG(gXULTemplateLog, PR_LOG_DEBUG,
|
||||
(" container => %s", s));
|
||||
}
|
||||
#endif
|
||||
|
||||
value = container.get();
|
||||
}
|
||||
|
||||
// Copy the original instantiation, and add it to the
|
||||
|
@ -446,15 +452,14 @@ nsRDFConMemberTestNode::FilterInstantiations(InstantiationSet& aInstantiations,
|
|||
Element* element;
|
||||
if (hasContainerBinding) {
|
||||
element =
|
||||
nsRDFConMemberTestNode::Element::Create(mConflictSet.GetPool(),
|
||||
VALUE_TO_IRDFRESOURCE(containerValue),
|
||||
VALUE_TO_IRDFNODE(value));
|
||||
nsRDFConMemberTestNode::Element::Create(mProcessor->GetPool(),
|
||||
containerRes,
|
||||
value);
|
||||
}
|
||||
else {
|
||||
element =
|
||||
nsRDFConMemberTestNode::Element::Create(mConflictSet.GetPool(),
|
||||
VALUE_TO_IRDFRESOURCE(value),
|
||||
VALUE_TO_IRDFNODE(memberValue));
|
||||
nsRDFConMemberTestNode::Element::Create(mProcessor->GetPool(),
|
||||
valueRes, memberValue);
|
||||
}
|
||||
|
||||
if (! element)
|
||||
|
@ -480,21 +485,6 @@ nsRDFConMemberTestNode::FilterInstantiations(InstantiationSet& aInstantiations,
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsRDFConMemberTestNode::GetAncestorVariables(VariableSet& aVariables) const
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
rv = aVariables.Add(mContainerVariable);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
rv = aVariables.Add(mMemberVariable);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
return TestNode::GetAncestorVariables(aVariables);
|
||||
}
|
||||
|
||||
|
||||
PRBool
|
||||
nsRDFConMemberTestNode::CanPropagate(nsIRDFResource* aSource,
|
||||
nsIRDFResource* aProperty,
|
||||
|
@ -516,7 +506,7 @@ nsRDFConMemberTestNode::CanPropagate(nsIRDFResource* aSource,
|
|||
if (NS_FAILED(rv)) return PR_FALSE;
|
||||
|
||||
if (! canpropagate) {
|
||||
canpropagate = mMembershipProperties.Contains(aProperty);
|
||||
canpropagate = mProcessor->ContainmentProperties().Contains(aProperty);
|
||||
}
|
||||
|
||||
#ifdef PR_LOGGING
|
||||
|
@ -538,8 +528,8 @@ nsRDFConMemberTestNode::CanPropagate(nsIRDFResource* aSource,
|
|||
#endif
|
||||
|
||||
if (canpropagate) {
|
||||
aInitialBindings.AddAssignment(mContainerVariable, Value(aSource));
|
||||
aInitialBindings.AddAssignment(mMemberVariable, Value(aTarget));
|
||||
aInitialBindings.AddAssignment(mContainerVariable, aSource);
|
||||
aInitialBindings.AddAssignment(mMemberVariable, aTarget);
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
|
@ -549,9 +539,7 @@ nsRDFConMemberTestNode::CanPropagate(nsIRDFResource* aSource,
|
|||
void
|
||||
nsRDFConMemberTestNode::Retract(nsIRDFResource* aSource,
|
||||
nsIRDFResource* aProperty,
|
||||
nsIRDFNode* aTarget,
|
||||
nsTemplateMatchSet& aFirings,
|
||||
nsTemplateMatchSet& aRetractions) const
|
||||
nsIRDFNode* aTarget) const
|
||||
{
|
||||
PRBool canretract = PR_FALSE;
|
||||
|
||||
|
@ -567,10 +555,10 @@ nsRDFConMemberTestNode::Retract(nsIRDFResource* aSource,
|
|||
if (NS_FAILED(rv)) return;
|
||||
|
||||
if (! canretract) {
|
||||
canretract = mMembershipProperties.Contains(aProperty);
|
||||
canretract = mProcessor->ContainmentProperties().Contains(aProperty);
|
||||
}
|
||||
|
||||
if (canretract) {
|
||||
mConflictSet.Remove(Element(aSource, aTarget), aFirings, aRetractions);
|
||||
mProcessor->RetractElement(Element(aSource, aTarget));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -42,9 +42,7 @@
|
|||
#include "nscore.h"
|
||||
#include "nsRDFTestNode.h"
|
||||
#include "nsIRDFDataSource.h"
|
||||
#include "nsFixedSizeAllocator.h"
|
||||
class nsConflictSet;
|
||||
class nsResourceSet;
|
||||
#include "nsXULTemplateQueryProcessorRDF.h"
|
||||
|
||||
/**
|
||||
* Rule network node that test if a resource is a member of an RDF
|
||||
|
@ -54,16 +52,12 @@ class nsResourceSet;
|
|||
class nsRDFConMemberTestNode : public nsRDFTestNode
|
||||
{
|
||||
public:
|
||||
nsRDFConMemberTestNode(InnerNode* aParent,
|
||||
nsConflictSet& aConflictSet,
|
||||
nsIRDFDataSource* aDataSource,
|
||||
const nsResourceSet& aMembershipProperties,
|
||||
PRInt32 aContainerVariable,
|
||||
PRInt32 aMemberVariable);
|
||||
nsRDFConMemberTestNode(TestNode* aParent,
|
||||
nsXULTemplateQueryProcessorRDF* aProcessor,
|
||||
nsIAtom* aContainerVariable,
|
||||
nsIAtom* aMemberVariable);
|
||||
|
||||
virtual nsresult FilterInstantiations(InstantiationSet& aInstantiations, void* aClosure) const;
|
||||
|
||||
virtual nsresult GetAncestorVariables(VariableSet& aVariables) const;
|
||||
virtual nsresult FilterInstantiations(InstantiationSet& aInstantiations) const;
|
||||
|
||||
virtual PRBool
|
||||
CanPropagate(nsIRDFResource* aSource,
|
||||
|
@ -74,9 +68,7 @@ public:
|
|||
virtual void
|
||||
Retract(nsIRDFResource* aSource,
|
||||
nsIRDFResource* aProperty,
|
||||
nsIRDFNode* aTarget,
|
||||
nsTemplateMatchSet& aFirings,
|
||||
nsTemplateMatchSet& aRetractions) const;
|
||||
nsIRDFNode* aTarget) const;
|
||||
|
||||
class Element : public MemoryElement {
|
||||
protected:
|
||||
|
@ -130,11 +122,9 @@ public:
|
|||
};
|
||||
|
||||
protected:
|
||||
nsConflictSet& mConflictSet;
|
||||
nsCOMPtr<nsIRDFDataSource> mDataSource;
|
||||
const nsResourceSet& mMembershipProperties;
|
||||
PRInt32 mContainerVariable;
|
||||
PRInt32 mMemberVariable;
|
||||
nsXULTemplateQueryProcessorRDF* mProcessor;
|
||||
nsCOMPtr<nsIAtom> mContainerVariable;
|
||||
nsCOMPtr<nsIAtom> mMemberVariable;
|
||||
};
|
||||
|
||||
#endif // nsRDFConMemberTestNode_h__
|
||||
|
|
|
@ -37,7 +37,6 @@
|
|||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include "nsRDFPropertyTestNode.h"
|
||||
#include "nsConflictSet.h"
|
||||
#include "nsString.h"
|
||||
|
||||
#include "prlog.h"
|
||||
|
@ -47,15 +46,13 @@ extern PRLogModuleInfo* gXULTemplateLog;
|
|||
#include "nsXULContentUtils.h"
|
||||
#endif
|
||||
|
||||
nsRDFPropertyTestNode::nsRDFPropertyTestNode(InnerNode* aParent,
|
||||
nsConflictSet& aConflictSet,
|
||||
nsIRDFDataSource* aDataSource,
|
||||
PRInt32 aSourceVariable,
|
||||
nsRDFPropertyTestNode::nsRDFPropertyTestNode(TestNode* aParent,
|
||||
nsXULTemplateQueryProcessorRDF* aProcessor,
|
||||
nsIAtom* aSourceVariable,
|
||||
nsIRDFResource* aProperty,
|
||||
PRInt32 aTargetVariable)
|
||||
nsIAtom* aTargetVariable)
|
||||
: nsRDFTestNode(aParent),
|
||||
mConflictSet(aConflictSet),
|
||||
mDataSource(aDataSource),
|
||||
mProcessor(aProcessor),
|
||||
mSourceVariable(aSourceVariable),
|
||||
mSource(nsnull),
|
||||
mProperty(aProperty),
|
||||
|
@ -68,23 +65,29 @@ nsRDFPropertyTestNode::nsRDFPropertyTestNode(InnerNode* aParent,
|
|||
if (aProperty)
|
||||
aProperty->GetValueConst(&prop);
|
||||
|
||||
nsAutoString svar(NS_LITERAL_STRING("(none)"));
|
||||
if (mSourceVariable)
|
||||
mSourceVariable->ToString(svar);
|
||||
|
||||
nsAutoString tvar(NS_LITERAL_STRING("(none)"));
|
||||
if (mTargetVariable)
|
||||
mTargetVariable->ToString(tvar);
|
||||
|
||||
PR_LOG(gXULTemplateLog, PR_LOG_DEBUG,
|
||||
("nsRDFPropertyTestNode[%p]: parent=%p source=%d property=%s target=%d",
|
||||
this, aParent, aSourceVariable, prop, aTargetVariable));
|
||||
("nsRDFPropertyTestNode[%p]: parent=%p source=%s property=%s target=%s",
|
||||
this, aParent, NS_ConvertUTF16toUTF8(svar).get(), prop, NS_ConvertUTF16toUTF8(tvar).get()));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
nsRDFPropertyTestNode::nsRDFPropertyTestNode(InnerNode* aParent,
|
||||
nsConflictSet& aConflictSet,
|
||||
nsIRDFDataSource* aDataSource,
|
||||
nsRDFPropertyTestNode::nsRDFPropertyTestNode(TestNode* aParent,
|
||||
nsXULTemplateQueryProcessorRDF* aProcessor,
|
||||
nsIRDFResource* aSource,
|
||||
nsIRDFResource* aProperty,
|
||||
PRInt32 aTargetVariable)
|
||||
nsIAtom* aTargetVariable)
|
||||
: nsRDFTestNode(aParent),
|
||||
mConflictSet(aConflictSet),
|
||||
mDataSource(aDataSource),
|
||||
mProcessor(aProcessor),
|
||||
mSourceVariable(0),
|
||||
mSource(aSource),
|
||||
mProperty(aProperty),
|
||||
|
@ -101,23 +104,25 @@ nsRDFPropertyTestNode::nsRDFPropertyTestNode(InnerNode* aParent,
|
|||
if (aProperty)
|
||||
aProperty->GetValueConst(&prop);
|
||||
|
||||
nsAutoString tvar(NS_LITERAL_STRING("(none)"));
|
||||
if (mTargetVariable)
|
||||
mTargetVariable->ToString(tvar);
|
||||
|
||||
PR_LOG(gXULTemplateLog, PR_LOG_DEBUG,
|
||||
("nsRDFPropertyTestNode[%p]: parent=%p source=%s property=%s target=%d",
|
||||
this, source, prop, aTargetVariable));
|
||||
("nsRDFPropertyTestNode[%p]: parent=%p source=%s property=%s target=%s",
|
||||
this, aParent, source, prop, NS_ConvertUTF16toUTF8(tvar).get()));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
nsRDFPropertyTestNode::nsRDFPropertyTestNode(InnerNode* aParent,
|
||||
nsConflictSet& aConflictSet,
|
||||
nsIRDFDataSource* aDataSource,
|
||||
PRInt32 aSourceVariable,
|
||||
nsRDFPropertyTestNode::nsRDFPropertyTestNode(TestNode* aParent,
|
||||
nsXULTemplateQueryProcessorRDF* aProcessor,
|
||||
nsIAtom* aSourceVariable,
|
||||
nsIRDFResource* aProperty,
|
||||
nsIRDFNode* aTarget)
|
||||
: nsRDFTestNode(aParent),
|
||||
mConflictSet(aConflictSet),
|
||||
mDataSource(aDataSource),
|
||||
mProcessor(aProcessor),
|
||||
mSourceVariable(aSourceVariable),
|
||||
mSource(nsnull),
|
||||
mProperty(aProperty),
|
||||
|
@ -126,6 +131,10 @@ nsRDFPropertyTestNode::nsRDFPropertyTestNode(InnerNode* aParent,
|
|||
{
|
||||
#ifdef PR_LOGGING
|
||||
if (PR_LOG_TEST(gXULTemplateLog, PR_LOG_DEBUG)) {
|
||||
nsAutoString svar(NS_LITERAL_STRING("(none)"));
|
||||
if (mSourceVariable)
|
||||
mSourceVariable->ToString(svar);
|
||||
|
||||
const char* prop = "(null)";
|
||||
if (aProperty)
|
||||
aProperty->GetValueConst(&prop);
|
||||
|
@ -134,51 +143,57 @@ nsRDFPropertyTestNode::nsRDFPropertyTestNode(InnerNode* aParent,
|
|||
nsXULContentUtils::GetTextForNode(aTarget, target);
|
||||
|
||||
PR_LOG(gXULTemplateLog, PR_LOG_DEBUG,
|
||||
("nsRDFPropertyTestNode[%p]: parent=%p source=%s property=%s target=%d",
|
||||
this, aSourceVariable, prop, NS_ConvertUTF16toUTF8(target).get()));
|
||||
("nsRDFPropertyTestNode[%p]: parent=%p source=%s property=%s target=%s",
|
||||
this, aParent, NS_ConvertUTF16toUTF8(svar).get(), prop, NS_ConvertUTF16toUTF8(target).get()));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
nsresult
|
||||
nsRDFPropertyTestNode::FilterInstantiations(InstantiationSet& aInstantiations, void* aClosure) const
|
||||
nsRDFPropertyTestNode::FilterInstantiations(InstantiationSet& aInstantiations) const
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
nsIRDFDataSource* ds = mProcessor->GetDataSource();
|
||||
|
||||
InstantiationSet::Iterator last = aInstantiations.Last();
|
||||
for (InstantiationSet::Iterator inst = aInstantiations.First(); inst != last; ++inst) {
|
||||
PRBool hasSourceBinding;
|
||||
Value sourceValue;
|
||||
nsCOMPtr<nsIRDFResource> sourceRes;
|
||||
|
||||
if (mSource) {
|
||||
hasSourceBinding = PR_TRUE;
|
||||
sourceValue = mSource;
|
||||
sourceRes = mSource;
|
||||
}
|
||||
else {
|
||||
hasSourceBinding = inst->mAssignments.GetAssignmentFor(mSourceVariable, &sourceValue);
|
||||
nsCOMPtr<nsIRDFNode> sourceValue;
|
||||
hasSourceBinding = inst->mAssignments.GetAssignmentFor(mSourceVariable,
|
||||
getter_AddRefs(sourceValue));
|
||||
sourceRes = do_QueryInterface(sourceValue);
|
||||
}
|
||||
|
||||
PRBool hasTargetBinding;
|
||||
Value targetValue;
|
||||
nsCOMPtr<nsIRDFNode> targetValue;
|
||||
|
||||
if (mTarget) {
|
||||
hasTargetBinding = PR_TRUE;
|
||||
targetValue = mTarget;
|
||||
}
|
||||
else {
|
||||
hasTargetBinding = inst->mAssignments.GetAssignmentFor(mTargetVariable, &targetValue);
|
||||
hasTargetBinding = inst->mAssignments.GetAssignmentFor(mTargetVariable,
|
||||
getter_AddRefs(targetValue));
|
||||
}
|
||||
|
||||
#ifdef PR_LOGGING
|
||||
if (PR_LOG_TEST(gXULTemplateLog, PR_LOG_DEBUG)) {
|
||||
const char* source = "(unbound)";
|
||||
if (hasSourceBinding)
|
||||
VALUE_TO_IRDFRESOURCE(sourceValue)->GetValueConst(&source);
|
||||
sourceRes->GetValueConst(&source);
|
||||
|
||||
nsAutoString target(NS_LITERAL_STRING("(unbound)"));
|
||||
if (hasTargetBinding)
|
||||
nsXULContentUtils::GetTextForNode(VALUE_TO_IRDFNODE(targetValue), target);
|
||||
nsXULContentUtils::GetTextForNode(targetValue, target);
|
||||
|
||||
PR_LOG(gXULTemplateLog, PR_LOG_DEBUG,
|
||||
("nsRDFPropertyTestNode[%p]: FilterInstantiations() source=[%s] target=[%s]",
|
||||
|
@ -189,11 +204,8 @@ nsRDFPropertyTestNode::FilterInstantiations(InstantiationSet& aInstantiations, v
|
|||
if (hasSourceBinding && hasTargetBinding) {
|
||||
// it's a consistency check. see if we have a assignment that is consistent
|
||||
PRBool hasAssertion;
|
||||
rv = mDataSource->HasAssertion(VALUE_TO_IRDFRESOURCE(sourceValue),
|
||||
mProperty,
|
||||
VALUE_TO_IRDFNODE(targetValue),
|
||||
PR_TRUE,
|
||||
&hasAssertion);
|
||||
rv = ds->HasAssertion(sourceRes, mProperty, targetValue,
|
||||
PR_TRUE, &hasAssertion);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
#ifdef PR_LOGGING
|
||||
|
@ -204,10 +216,10 @@ nsRDFPropertyTestNode::FilterInstantiations(InstantiationSet& aInstantiations, v
|
|||
if (hasAssertion) {
|
||||
// it's consistent.
|
||||
Element* element =
|
||||
nsRDFPropertyTestNode::Element::Create(mConflictSet.GetPool(),
|
||||
VALUE_TO_IRDFRESOURCE(sourceValue),
|
||||
nsRDFPropertyTestNode::Element::Create(mProcessor->GetPool(),
|
||||
sourceRes,
|
||||
mProperty,
|
||||
VALUE_TO_IRDFNODE(targetValue));
|
||||
targetValue);
|
||||
|
||||
if (! element)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
@ -226,16 +238,16 @@ nsRDFPropertyTestNode::FilterInstantiations(InstantiationSet& aInstantiations, v
|
|||
// cross-product.
|
||||
nsCOMPtr<nsISimpleEnumerator> results;
|
||||
if (hasSourceBinding) {
|
||||
rv = mDataSource->GetTargets(VALUE_TO_IRDFRESOURCE(sourceValue),
|
||||
mProperty,
|
||||
PR_TRUE,
|
||||
getter_AddRefs(results));
|
||||
rv = ds->GetTargets(sourceRes,
|
||||
mProperty,
|
||||
PR_TRUE,
|
||||
getter_AddRefs(results));
|
||||
}
|
||||
else {
|
||||
rv = mDataSource->GetSources(mProperty,
|
||||
VALUE_TO_IRDFNODE(targetValue),
|
||||
PR_TRUE,
|
||||
getter_AddRefs(results));
|
||||
rv = ds->GetSources(mProperty,
|
||||
targetValue,
|
||||
PR_TRUE,
|
||||
getter_AddRefs(results));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
}
|
||||
|
||||
|
@ -251,29 +263,29 @@ nsRDFPropertyTestNode::FilterInstantiations(InstantiationSet& aInstantiations, v
|
|||
rv = results->GetNext(getter_AddRefs(isupports));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
PRInt32 variable;
|
||||
Value value;
|
||||
nsIAtom* variable;
|
||||
nsCOMPtr<nsIRDFNode> value;
|
||||
|
||||
if (hasSourceBinding) {
|
||||
variable = mTargetVariable;
|
||||
|
||||
nsCOMPtr<nsIRDFNode> target = do_QueryInterface(isupports);
|
||||
NS_ASSERTION(target != nsnull, "target is not an nsIRDFNode");
|
||||
value = do_QueryInterface(isupports);
|
||||
NS_ASSERTION(value != nsnull, "target is not an nsIRDFNode");
|
||||
|
||||
#ifdef PR_LOGGING
|
||||
if (PR_LOG_TEST(gXULTemplateLog, PR_LOG_DEBUG)) {
|
||||
nsAutoString s(NS_LITERAL_STRING("(none found)"));
|
||||
if (target)
|
||||
nsXULContentUtils::GetTextForNode(target, s);
|
||||
if (value)
|
||||
nsXULContentUtils::GetTextForNode(value, s);
|
||||
|
||||
PR_LOG(gXULTemplateLog, PR_LOG_DEBUG,
|
||||
(" target => %s", NS_ConvertUTF16toUTF8(s).get()));
|
||||
}
|
||||
#endif
|
||||
|
||||
if (! target) continue;
|
||||
if (! value) continue;
|
||||
|
||||
targetValue = value = target.get();
|
||||
targetValue = value;
|
||||
}
|
||||
else {
|
||||
variable = mSourceVariable;
|
||||
|
@ -294,7 +306,7 @@ nsRDFPropertyTestNode::FilterInstantiations(InstantiationSet& aInstantiations, v
|
|||
|
||||
if (! source) continue;
|
||||
|
||||
sourceValue = value = source.get();
|
||||
value = sourceRes = source;
|
||||
}
|
||||
|
||||
// Copy the original instantiation, and add it to the
|
||||
|
@ -304,10 +316,10 @@ nsRDFPropertyTestNode::FilterInstantiations(InstantiationSet& aInstantiations, v
|
|||
newinst.AddAssignment(variable, value);
|
||||
|
||||
Element* element =
|
||||
nsRDFPropertyTestNode::Element::Create(mConflictSet.GetPool(),
|
||||
VALUE_TO_IRDFRESOURCE(sourceValue),
|
||||
nsRDFPropertyTestNode::Element::Create(mProcessor->GetPool(),
|
||||
sourceRes,
|
||||
mProperty,
|
||||
VALUE_TO_IRDFNODE(targetValue));
|
||||
targetValue);
|
||||
|
||||
if (! element)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
@ -330,25 +342,6 @@ nsRDFPropertyTestNode::FilterInstantiations(InstantiationSet& aInstantiations, v
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
nsresult
|
||||
nsRDFPropertyTestNode::GetAncestorVariables(VariableSet& aVariables) const
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
if (mSourceVariable) {
|
||||
rv = aVariables.Add(mSourceVariable);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
}
|
||||
|
||||
if (mTargetVariable) {
|
||||
rv = aVariables.Add(mTargetVariable);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
}
|
||||
|
||||
return TestNode::GetAncestorVariables(aVariables);
|
||||
}
|
||||
|
||||
PRBool
|
||||
nsRDFPropertyTestNode::CanPropagate(nsIRDFResource* aSource,
|
||||
nsIRDFResource* aProperty,
|
||||
|
@ -364,10 +357,10 @@ nsRDFPropertyTestNode::CanPropagate(nsIRDFResource* aSource,
|
|||
}
|
||||
else {
|
||||
if (mSourceVariable)
|
||||
aInitialBindings.AddAssignment(mSourceVariable, Value(aSource));
|
||||
aInitialBindings.AddAssignment(mSourceVariable, aSource);
|
||||
|
||||
if (mTargetVariable)
|
||||
aInitialBindings.AddAssignment(mTargetVariable, Value(aTarget));
|
||||
aInitialBindings.AddAssignment(mTargetVariable, aTarget);
|
||||
|
||||
result = PR_TRUE;
|
||||
}
|
||||
|
@ -396,9 +389,7 @@ nsRDFPropertyTestNode::CanPropagate(nsIRDFResource* aSource,
|
|||
void
|
||||
nsRDFPropertyTestNode::Retract(nsIRDFResource* aSource,
|
||||
nsIRDFResource* aProperty,
|
||||
nsIRDFNode* aTarget,
|
||||
nsTemplateMatchSet& aFirings,
|
||||
nsTemplateMatchSet& aRetractions) const
|
||||
nsIRDFNode* aTarget) const
|
||||
{
|
||||
if (aProperty == mProperty.get()) {
|
||||
#ifdef PR_LOGGING
|
||||
|
@ -418,7 +409,7 @@ nsRDFPropertyTestNode::Retract(nsIRDFResource* aSource,
|
|||
}
|
||||
#endif
|
||||
|
||||
mConflictSet.Remove(Element(aSource, aProperty, aTarget), aFirings, aRetractions);
|
||||
mProcessor->RetractElement(Element(aSource, aProperty, aTarget));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -40,11 +40,10 @@
|
|||
#define nsRDFPropertyTestNode_h__
|
||||
|
||||
#include "nscore.h"
|
||||
#include "nsFixedSizeAllocator.h"
|
||||
#include "nsRDFTestNode.h"
|
||||
#include "nsIRDFDataSource.h"
|
||||
#include "nsIRDFResource.h"
|
||||
class nsConflictSet;
|
||||
#include "nsXULTemplateQueryProcessorRDF.h"
|
||||
|
||||
class nsRDFPropertyTestNode : public nsRDFTestNode
|
||||
{
|
||||
|
@ -52,36 +51,31 @@ public:
|
|||
/**
|
||||
* Both source and target unbound (?source ^property ?target)
|
||||
*/
|
||||
nsRDFPropertyTestNode(InnerNode* aParent,
|
||||
nsConflictSet& aConflictSet,
|
||||
nsIRDFDataSource* aDataSource,
|
||||
PRInt32 aSourceVariable,
|
||||
nsRDFPropertyTestNode(TestNode* aParent,
|
||||
nsXULTemplateQueryProcessorRDF* aProcessor,
|
||||
nsIAtom* aSourceVariable,
|
||||
nsIRDFResource* aProperty,
|
||||
PRInt32 aTargetVariable);
|
||||
nsIAtom* aTargetVariable);
|
||||
|
||||
/**
|
||||
* Source bound, target unbound (source ^property ?target)
|
||||
*/
|
||||
nsRDFPropertyTestNode(InnerNode* aParent,
|
||||
nsConflictSet& aConflictSet,
|
||||
nsIRDFDataSource* aDataSource,
|
||||
nsRDFPropertyTestNode(TestNode* aParent,
|
||||
nsXULTemplateQueryProcessorRDF* aProcessor,
|
||||
nsIRDFResource* aSource,
|
||||
nsIRDFResource* aProperty,
|
||||
PRInt32 aTargetVariable);
|
||||
nsIAtom* aTargetVariable);
|
||||
|
||||
/**
|
||||
* Source unbound, target bound (?source ^property target)
|
||||
*/
|
||||
nsRDFPropertyTestNode(InnerNode* aParent,
|
||||
nsConflictSet& aConflictSet,
|
||||
nsIRDFDataSource* aDataSource,
|
||||
PRInt32 aSourceVariable,
|
||||
nsRDFPropertyTestNode(TestNode* aParent,
|
||||
nsXULTemplateQueryProcessorRDF* aProcessor,
|
||||
nsIAtom* aSourceVariable,
|
||||
nsIRDFResource* aProperty,
|
||||
nsIRDFNode* aTarget);
|
||||
|
||||
virtual nsresult FilterInstantiations(InstantiationSet& aInstantiations, void* aClosure) const;
|
||||
|
||||
virtual nsresult GetAncestorVariables(VariableSet& aVariables) const;
|
||||
virtual nsresult FilterInstantiations(InstantiationSet& aInstantiations) const;
|
||||
|
||||
virtual PRBool
|
||||
CanPropagate(nsIRDFResource* aSource,
|
||||
|
@ -92,9 +86,7 @@ public:
|
|||
virtual void
|
||||
Retract(nsIRDFResource* aSource,
|
||||
nsIRDFResource* aProperty,
|
||||
nsIRDFNode* aTarget,
|
||||
nsTemplateMatchSet& aFirings,
|
||||
nsTemplateMatchSet& aRetractions) const;
|
||||
nsIRDFNode* aTarget) const;
|
||||
|
||||
|
||||
class Element : public MemoryElement {
|
||||
|
@ -156,12 +148,11 @@ public:
|
|||
};
|
||||
|
||||
protected:
|
||||
nsConflictSet& mConflictSet;
|
||||
nsCOMPtr<nsIRDFDataSource> mDataSource;
|
||||
PRInt32 mSourceVariable;
|
||||
nsXULTemplateQueryProcessorRDF* mProcessor;
|
||||
nsCOMPtr<nsIAtom> mSourceVariable;
|
||||
nsCOMPtr<nsIRDFResource> mSource;
|
||||
nsCOMPtr<nsIRDFResource> mProperty;
|
||||
PRInt32 mTargetVariable;
|
||||
nsCOMPtr<nsIAtom> mTargetVariable;
|
||||
nsCOMPtr<nsIRDFNode> mTarget;
|
||||
};
|
||||
|
||||
|
|
|
@ -0,0 +1,73 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Neil Deakin
|
||||
* Portions created by the Initial Developer are Copyright (C) 2005
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include "nscore.h"
|
||||
#include "nsCOMPtr.h"
|
||||
|
||||
#include "nsXULTemplateQueryProcessorRDF.h"
|
||||
#include "nsRDFQuery.h"
|
||||
|
||||
NS_IMPL_ISUPPORTS1(nsRDFQuery, nsITemplateRDFQuery)
|
||||
|
||||
void
|
||||
nsRDFQuery::Finish()
|
||||
{
|
||||
// the template builder is going away and the query processor likely as
|
||||
// well. Clear the reference to avoid calling it.
|
||||
mProcessor = nsnull;
|
||||
mCachedResults = nsnull;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsRDFQuery::SetCachedResults(nsXULTemplateQueryProcessorRDF* aProcessor,
|
||||
const InstantiationSet& aInstantiations)
|
||||
{
|
||||
mCachedResults = new nsXULTemplateResultSetRDF(aProcessor, this, &aInstantiations);
|
||||
if (! mCachedResults)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
nsRDFQuery::UseCachedResults(nsISimpleEnumerator** aResults)
|
||||
{
|
||||
*aResults = mCachedResults;
|
||||
NS_IF_ADDREF(*aResults);
|
||||
|
||||
mCachedResults = nsnull;
|
||||
}
|
|
@ -0,0 +1,157 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Neil Deakin
|
||||
* Portions created by the Initial Developer are Copyright (C) 2005
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef nsRDFQuery_h__
|
||||
#define nsRDFQuery_h__
|
||||
|
||||
#include "nsAutoPtr.h"
|
||||
#include "nsISimpleEnumerator.h"
|
||||
|
||||
#define NS_ITEMPLATERDFQUERY_IID \
|
||||
{0x8929ff60, 0x1c9c, 0x4d87, \
|
||||
{ 0xac, 0x02, 0x09, 0x14, 0x15, 0x3b, 0x48, 0xc4 }}
|
||||
|
||||
/**
|
||||
* A compiled query in the RDF query processor. This interface should not be
|
||||
* used directly outside of the RDF query processor.
|
||||
*/
|
||||
class nsITemplateRDFQuery : public nsISupports
|
||||
{
|
||||
public:
|
||||
NS_DECLARE_STATIC_IID_ACCESSOR(NS_ITEMPLATERDFQUERY_IID)
|
||||
|
||||
// return the processor the query was created from
|
||||
virtual nsXULTemplateQueryProcessorRDF* Processor() = 0; // not addrefed
|
||||
|
||||
// return the member variable for the query
|
||||
virtual nsIAtom* GetMemberVariable() = 0; // not addrefed
|
||||
|
||||
// return the <query> node the query was compiled from
|
||||
virtual void GetQueryNode(nsIDOMNode** aQueryNode) = 0;
|
||||
|
||||
// remove any results that are cached by the query
|
||||
virtual void ClearCachedResults() = 0;
|
||||
};
|
||||
|
||||
class nsRDFQuery : public nsITemplateRDFQuery
|
||||
{
|
||||
public:
|
||||
|
||||
nsRDFQuery(nsXULTemplateQueryProcessorRDF* aProcessor)
|
||||
: mProcessor(aProcessor),
|
||||
mSimple(PR_FALSE),
|
||||
mRoot(nsnull),
|
||||
mCachedResults(nsnull)
|
||||
{ }
|
||||
|
||||
~nsRDFQuery() { Finish(); }
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
/**
|
||||
* Retrieve the root node in the rule network
|
||||
* @return the root node in the rule network
|
||||
*/
|
||||
TestNode* GetRoot() { return mRoot; };
|
||||
|
||||
void SetRoot(TestNode* aRoot) { mRoot = aRoot; };
|
||||
|
||||
void GetQueryNode(nsIDOMNode** aQueryNode)
|
||||
{
|
||||
*aQueryNode = mQueryNode;
|
||||
NS_IF_ADDREF(*aQueryNode);
|
||||
}
|
||||
|
||||
void SetQueryNode(nsIDOMNode* aQueryNode)
|
||||
{
|
||||
mQueryNode = aQueryNode;
|
||||
}
|
||||
|
||||
// an optimization is used when several queries all use the simple query
|
||||
// syntax. Since simple queries can only generate one possible set of
|
||||
// results, they only need to be calculated once and reused for every
|
||||
// simple query. The results may be cached in the query for this purpose.
|
||||
// If successful, this method takes ownership of aInstantiations.
|
||||
nsresult SetCachedResults(nsXULTemplateQueryProcessorRDF* aProcessor,
|
||||
const InstantiationSet& aInstantiations);
|
||||
|
||||
// grab the cached results, if any, causing the caller to take ownership
|
||||
// of them. This also has the effect of setting the cached results in this
|
||||
// nsRDFQuery to null.
|
||||
void UseCachedResults(nsISimpleEnumerator** aResults);
|
||||
|
||||
// clear the cached results
|
||||
void ClearCachedResults()
|
||||
{
|
||||
mCachedResults = nsnull;
|
||||
}
|
||||
|
||||
nsXULTemplateQueryProcessorRDF* Processor() { return mProcessor; }
|
||||
|
||||
nsIAtom* GetMemberVariable() { return mMemberVariable; }
|
||||
|
||||
PRBool IsSimple() { return mSimple; }
|
||||
|
||||
void SetSimple() { mSimple = PR_TRUE; }
|
||||
|
||||
// the reference and member variables for the query
|
||||
nsCOMPtr<nsIAtom> mRefVariable;
|
||||
nsCOMPtr<nsIAtom> mMemberVariable;
|
||||
|
||||
protected:
|
||||
|
||||
nsXULTemplateQueryProcessorRDF* mProcessor;
|
||||
|
||||
// true if the query is a simple rule (one with a default query)
|
||||
PRBool mSimple;
|
||||
|
||||
/**
|
||||
* The root node in the network for this query
|
||||
*/
|
||||
TestNode *mRoot;
|
||||
|
||||
// the <query> node
|
||||
nsCOMPtr<nsIDOMNode> mQueryNode;
|
||||
|
||||
// used for simple rules since their results are all determined in one step
|
||||
nsCOMPtr<nsISimpleEnumerator> mCachedResults;
|
||||
|
||||
void Finish();
|
||||
};
|
||||
|
||||
NS_DEFINE_STATIC_IID_ACCESSOR(nsRDFQuery, NS_ITEMPLATERDFQUERY_IID)
|
||||
|
||||
#endif // nsRDFQuery_h__
|
|
@ -40,9 +40,9 @@
|
|||
#define nsRDFTestNode_h__
|
||||
|
||||
#include "nsRuleNetwork.h"
|
||||
|
||||
class nsIRDFResource;
|
||||
class nsIRDFNode;
|
||||
class nsTemplateMatchSet;
|
||||
|
||||
/**
|
||||
* An abstract base class for all of the RDF-related tests. This interface
|
||||
|
@ -52,7 +52,7 @@ class nsTemplateMatchSet;
|
|||
class nsRDFTestNode : public TestNode
|
||||
{
|
||||
public:
|
||||
nsRDFTestNode(InnerNode* aParent)
|
||||
nsRDFTestNode(TestNode* aParent)
|
||||
: TestNode(aParent) {}
|
||||
|
||||
/**
|
||||
|
@ -76,9 +76,7 @@ public:
|
|||
*/
|
||||
virtual void Retract(nsIRDFResource* aSource,
|
||||
nsIRDFResource* aProperty,
|
||||
nsIRDFNode* aTarget,
|
||||
nsTemplateMatchSet& aFirings,
|
||||
nsTemplateMatchSet& aRetractions) const = 0;
|
||||
nsIRDFNode* aTarget) const = 0;
|
||||
};
|
||||
|
||||
#endif // nsRDFTestNode_h__
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
*
|
||||
* Contributor(s):
|
||||
* Chris Waterson <waterson@netscape.com>
|
||||
* Neil Deakin <enndeakin@sympatico.ca>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
|
@ -54,461 +55,27 @@
|
|||
#include "nsCRT.h"
|
||||
#include "nsIComponentManager.h"
|
||||
#include "nsIContent.h"
|
||||
#include "nsRuleNetwork.h"
|
||||
#include "plhash.h"
|
||||
#include "nsReadableUtils.h"
|
||||
|
||||
#include "prlog.h"
|
||||
#ifdef PR_LOGGING
|
||||
extern PRLogModuleInfo* gXULTemplateLog;
|
||||
|
||||
#include "nsString.h"
|
||||
#include "nsUnicharUtils.h"
|
||||
#include "nsXULContentUtils.h"
|
||||
|
||||
#endif
|
||||
|
||||
#include "nsRuleNetwork.h"
|
||||
#include "nsXULTemplateResultSetRDF.h"
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
//
|
||||
// nsRuleNetwork
|
||||
//
|
||||
|
||||
static PLDHashNumber PR_CALLBACK
|
||||
HashEntry(PLDHashTable* aTable, const void* aKey)
|
||||
{
|
||||
return nsCRT::HashCode(NS_STATIC_CAST(const PRUnichar*, aKey));
|
||||
}
|
||||
|
||||
static PRBool PR_CALLBACK
|
||||
MatchEntry(PLDHashTable* aTable, const PLDHashEntryHdr* aEntry, const void* aKey)
|
||||
{
|
||||
const nsRuleNetwork::SymtabEntry* entry =
|
||||
NS_REINTERPRET_CAST(const nsRuleNetwork::SymtabEntry*, aEntry);
|
||||
|
||||
return 0 == nsCRT::strcmp(entry->mSymbol, NS_STATIC_CAST(const PRUnichar*, aKey));
|
||||
}
|
||||
|
||||
static void PR_CALLBACK
|
||||
ClearEntry(PLDHashTable* aTable, PLDHashEntryHdr* aEntry)
|
||||
{
|
||||
nsRuleNetwork::SymtabEntry* entry =
|
||||
NS_REINTERPRET_CAST(nsRuleNetwork::SymtabEntry*, aEntry);
|
||||
|
||||
nsCRT::free(entry->mSymbol);
|
||||
PL_DHashClearEntryStub(aTable, aEntry);
|
||||
}
|
||||
|
||||
PLDHashTableOps nsRuleNetwork::gOps = {
|
||||
PL_DHashAllocTable,
|
||||
PL_DHashFreeTable,
|
||||
PL_DHashGetKeyStub,
|
||||
HashEntry,
|
||||
MatchEntry,
|
||||
PL_DHashMoveEntryStub,
|
||||
ClearEntry,
|
||||
PL_DHashFinalizeStub
|
||||
};
|
||||
|
||||
void
|
||||
nsRuleNetwork::Init()
|
||||
{
|
||||
mNextVariable = 0;
|
||||
if (!PL_DHashTableInit(&mSymtab, &gOps, nsnull,
|
||||
sizeof(SymtabEntry), PL_DHASH_MIN_SIZE))
|
||||
mSymtab.ops = nsnull;
|
||||
}
|
||||
|
||||
void
|
||||
nsRuleNetwork::Finish()
|
||||
{
|
||||
if (mSymtab.ops)
|
||||
PL_DHashTableFinish(&mSymtab);
|
||||
|
||||
// We "own" the nodes. So it's up to us to delete 'em
|
||||
for (ReteNodeSet::Iterator node = mNodes.First(); node != mNodes.Last(); ++node)
|
||||
delete *node;
|
||||
|
||||
mNodes.Clear();
|
||||
mRoot.RemoveAllChildren();
|
||||
}
|
||||
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
//
|
||||
// Value
|
||||
//
|
||||
|
||||
#ifdef DEBUG
|
||||
/**
|
||||
* A debug-only implementation that verifies that 1) aValue really
|
||||
* is an nsISupports, and 2) that it really does support the IID
|
||||
* that is being asked for.
|
||||
*/
|
||||
nsISupports*
|
||||
value_to_isupports(const nsIID& aIID, const Value& aValue)
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
// Need to const_cast aValue because QI() & Release() are not const
|
||||
nsISupports* isupports = NS_STATIC_CAST(nsISupports*, NS_CONST_CAST(Value&, aValue));
|
||||
if (isupports) {
|
||||
nsCOMPtr<nsISupports> dummy;
|
||||
rv = isupports->QueryInterface(aIID, getter_AddRefs(dummy));
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_ERROR("value does not support expected interface");
|
||||
}
|
||||
}
|
||||
return isupports;
|
||||
}
|
||||
#endif
|
||||
|
||||
Value::Value(const Value& aValue)
|
||||
: mType(aValue.mType)
|
||||
{
|
||||
MOZ_COUNT_CTOR(Value);
|
||||
|
||||
switch (mType) {
|
||||
case eUndefined:
|
||||
break;
|
||||
|
||||
case eISupports:
|
||||
mISupports = aValue.mISupports;
|
||||
NS_IF_ADDREF(mISupports);
|
||||
break;
|
||||
|
||||
case eString:
|
||||
mString = nsCRT::strdup(aValue.mString);
|
||||
break;
|
||||
|
||||
case eInteger:
|
||||
mInteger = aValue.mInteger;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Value::Value(nsISupports* aISupports)
|
||||
: mType(eISupports)
|
||||
{
|
||||
MOZ_COUNT_CTOR(Value);
|
||||
mISupports = aISupports;
|
||||
NS_IF_ADDREF(mISupports);
|
||||
}
|
||||
|
||||
Value::Value(const PRUnichar* aString)
|
||||
: mType(eString)
|
||||
{
|
||||
MOZ_COUNT_CTOR(Value);
|
||||
mString = nsCRT::strdup(aString);
|
||||
}
|
||||
|
||||
Value::Value(PRInt32 aInteger)
|
||||
: mType(eInteger)
|
||||
{
|
||||
MOZ_COUNT_CTOR(Value);
|
||||
mInteger = aInteger;
|
||||
}
|
||||
|
||||
Value&
|
||||
Value::operator=(const Value& aValue)
|
||||
{
|
||||
Clear();
|
||||
|
||||
mType = aValue.mType;
|
||||
|
||||
switch (mType) {
|
||||
case eUndefined:
|
||||
break;
|
||||
|
||||
case eISupports:
|
||||
mISupports = aValue.mISupports;
|
||||
NS_IF_ADDREF(mISupports);
|
||||
break;
|
||||
|
||||
case eString:
|
||||
mString = nsCRT::strdup(aValue.mString);
|
||||
break;
|
||||
|
||||
case eInteger:
|
||||
mInteger = aValue.mInteger;
|
||||
break;
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
Value&
|
||||
Value::operator=(nsISupports* aISupports)
|
||||
{
|
||||
Clear();
|
||||
|
||||
mType = eISupports;
|
||||
mISupports = aISupports;
|
||||
NS_IF_ADDREF(mISupports);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
Value&
|
||||
Value::operator=(const PRUnichar* aString)
|
||||
{
|
||||
Clear();
|
||||
|
||||
mType = eString;
|
||||
mString = nsCRT::strdup(aString);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
Value::~Value()
|
||||
{
|
||||
MOZ_COUNT_DTOR(Value);
|
||||
Clear();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Value::Clear()
|
||||
{
|
||||
switch (mType) {
|
||||
case eInteger:
|
||||
case eUndefined:
|
||||
break;
|
||||
|
||||
case eISupports:
|
||||
NS_IF_RELEASE(mISupports);
|
||||
break;
|
||||
|
||||
case eString:
|
||||
nsCRT::free(mString);
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
PRBool
|
||||
Value::Equals(const Value& aValue) const
|
||||
{
|
||||
if (mType == aValue.mType) {
|
||||
switch (mType) {
|
||||
case eUndefined:
|
||||
return PR_FALSE;
|
||||
|
||||
case eISupports:
|
||||
return mISupports == aValue.mISupports;
|
||||
|
||||
case eString:
|
||||
return nsCRT::strcmp(mString, aValue.mString) == 0;
|
||||
|
||||
case eInteger:
|
||||
return mInteger == aValue.mInteger;
|
||||
}
|
||||
}
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
PRBool
|
||||
Value::Equals(nsISupports* aISupports) const
|
||||
{
|
||||
return (mType == eISupports) && (mISupports == aISupports);
|
||||
}
|
||||
|
||||
PRBool
|
||||
Value::Equals(const PRUnichar* aString) const
|
||||
{
|
||||
return (mType == eString) && (nsCRT::strcmp(aString, mString) == 0);
|
||||
}
|
||||
|
||||
PRBool
|
||||
Value::Equals(PRInt32 aInteger) const
|
||||
{
|
||||
return (mType == eInteger) && (mInteger == aInteger);
|
||||
}
|
||||
|
||||
|
||||
PLHashNumber
|
||||
Value::Hash() const
|
||||
{
|
||||
PLHashNumber temp = 0;
|
||||
|
||||
switch (mType) {
|
||||
case eUndefined:
|
||||
break;
|
||||
|
||||
case eISupports:
|
||||
temp = PLHashNumber(NS_PTR_TO_INT32(mISupports)) >> 2; // strip alignment bits
|
||||
break;
|
||||
|
||||
case eString:
|
||||
{
|
||||
PRUnichar* p = mString;
|
||||
PRUnichar c;
|
||||
while ((c = *p) != 0) {
|
||||
temp = (temp >> 28) ^ (temp << 4) ^ c;
|
||||
++p;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case eInteger:
|
||||
temp = mInteger;
|
||||
break;
|
||||
}
|
||||
|
||||
return temp;
|
||||
}
|
||||
|
||||
|
||||
Value::operator nsISupports*() const
|
||||
{
|
||||
NS_ASSERTION(mType == eISupports, "not an nsISupports");
|
||||
return (mType == eISupports) ? mISupports : 0;
|
||||
}
|
||||
|
||||
Value::operator const PRUnichar*() const
|
||||
{
|
||||
NS_ASSERTION(mType == eString, "not a string");
|
||||
return (mType == eString) ? mString : 0;
|
||||
}
|
||||
|
||||
Value::operator PRInt32() const
|
||||
{
|
||||
NS_ASSERTION(mType == eInteger, "not an integer");
|
||||
return (mType == eInteger) ? mInteger : 0;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
#include "nsIRDFResource.h"
|
||||
#include "nsIRDFLiteral.h"
|
||||
#include "nsString.h"
|
||||
#include "nsPrintfCString.h"
|
||||
|
||||
void
|
||||
Value::ToCString(nsACString& aResult)
|
||||
{
|
||||
switch (mType) {
|
||||
case eUndefined:
|
||||
aResult = "[(undefined)]";
|
||||
break;
|
||||
|
||||
case eISupports:
|
||||
do {
|
||||
nsCOMPtr<nsIRDFResource> res = do_QueryInterface(mISupports);
|
||||
if (res) {
|
||||
aResult = "[nsIRDFResource ";
|
||||
const char* s;
|
||||
res->GetValueConst(&s);
|
||||
aResult += s;
|
||||
aResult += "]";
|
||||
break;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIRDFLiteral> lit = do_QueryInterface(mISupports);
|
||||
if (lit) {
|
||||
aResult = "[nsIRDFLiteral \"";
|
||||
const PRUnichar* s;
|
||||
lit->GetValueConst(&s);
|
||||
AppendUTF16toUTF8(s, aResult);
|
||||
aResult += "\"]";
|
||||
break;
|
||||
}
|
||||
|
||||
aResult = "[nsISupports ";
|
||||
aResult += nsPrintfCString("%p", mISupports);
|
||||
aResult += "]";
|
||||
} while (0);
|
||||
break;
|
||||
|
||||
case eString:
|
||||
aResult = "[string \"";
|
||||
AppendUTF16toUTF8(mString, aResult);
|
||||
aResult += "\"]";
|
||||
break;
|
||||
|
||||
case eInteger:
|
||||
aResult = "[integer ";
|
||||
aResult += nsPrintfCString("%d", mInteger);
|
||||
aResult += "]";
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
//
|
||||
// VariableSet
|
||||
//
|
||||
|
||||
|
||||
VariableSet::VariableSet()
|
||||
: mVariables(nsnull), mCount(0), mCapacity(0)
|
||||
{
|
||||
}
|
||||
|
||||
VariableSet::~VariableSet()
|
||||
{
|
||||
delete[] mVariables;
|
||||
}
|
||||
|
||||
nsresult
|
||||
VariableSet::Add(PRInt32 aVariable)
|
||||
{
|
||||
if (Contains(aVariable))
|
||||
return NS_OK;
|
||||
|
||||
if (mCount >= mCapacity) {
|
||||
PRInt32 capacity = mCapacity + 4;
|
||||
PRInt32* variables = new PRInt32[capacity];
|
||||
if (! variables)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
for (PRInt32 i = mCount - 1; i >= 0; --i)
|
||||
variables[i] = mVariables[i];
|
||||
|
||||
delete[] mVariables;
|
||||
|
||||
mVariables = variables;
|
||||
mCapacity = capacity;
|
||||
}
|
||||
|
||||
mVariables[mCount++] = aVariable;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
VariableSet::Remove(PRInt32 aVariable)
|
||||
{
|
||||
PRInt32 i = 0;
|
||||
while (i < mCount) {
|
||||
if (aVariable == mVariables[i])
|
||||
break;
|
||||
|
||||
++i;
|
||||
}
|
||||
|
||||
if (i >= mCount)
|
||||
return NS_OK;
|
||||
|
||||
--mCount;
|
||||
|
||||
while (i < mCount) {
|
||||
mVariables[i] = mVariables[i + 1];
|
||||
++i;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
PRBool
|
||||
VariableSet::Contains(PRInt32 aVariable) const
|
||||
{
|
||||
for (PRInt32 i = mCount - 1; i >= 0; --i) {
|
||||
if (aVariable == mVariables[i])
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------=
|
||||
|
||||
nsresult
|
||||
MemoryElementSet::Add(MemoryElement* aElement)
|
||||
{
|
||||
|
@ -542,6 +109,8 @@ nsresult
|
|||
nsAssignmentSet::Add(const nsAssignment& aAssignment)
|
||||
{
|
||||
NS_PRECONDITION(! HasAssignmentFor(aAssignment.mVariable), "variable already bound");
|
||||
|
||||
// XXXndeakin should this just silently fail?
|
||||
if (HasAssignmentFor(aAssignment.mVariable))
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
|
||||
|
@ -569,7 +138,7 @@ nsAssignmentSet::Count() const
|
|||
}
|
||||
|
||||
PRBool
|
||||
nsAssignmentSet::HasAssignment(PRInt32 aVariable, const Value& aValue) const
|
||||
nsAssignmentSet::HasAssignment(nsIAtom* aVariable, nsIRDFNode* aValue) const
|
||||
{
|
||||
for (ConstIterator assignment = First(); assignment != Last(); ++assignment) {
|
||||
if (assignment->mVariable == aVariable && assignment->mValue == aValue)
|
||||
|
@ -580,7 +149,7 @@ nsAssignmentSet::HasAssignment(PRInt32 aVariable, const Value& aValue) const
|
|||
}
|
||||
|
||||
PRBool
|
||||
nsAssignmentSet::HasAssignmentFor(PRInt32 aVariable) const
|
||||
nsAssignmentSet::HasAssignmentFor(nsIAtom* aVariable) const
|
||||
{
|
||||
for (ConstIterator assignment = First(); assignment != Last(); ++assignment) {
|
||||
if (assignment->mVariable == aVariable)
|
||||
|
@ -591,15 +160,17 @@ nsAssignmentSet::HasAssignmentFor(PRInt32 aVariable) const
|
|||
}
|
||||
|
||||
PRBool
|
||||
nsAssignmentSet::GetAssignmentFor(PRInt32 aVariable, Value* aValue) const
|
||||
nsAssignmentSet::GetAssignmentFor(nsIAtom* aVariable, nsIRDFNode** aValue) const
|
||||
{
|
||||
for (ConstIterator assignment = First(); assignment != Last(); ++assignment) {
|
||||
if (assignment->mVariable == aVariable) {
|
||||
*aValue = assignment->mValue;
|
||||
NS_IF_ADDREF(*aValue);
|
||||
return PR_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
*aValue = nsnull;
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
|
@ -614,9 +185,9 @@ nsAssignmentSet::Equals(const nsAssignmentSet& aSet) const
|
|||
return PR_FALSE;
|
||||
|
||||
// XXX O(n^2)! Ugh!
|
||||
nsCOMPtr<nsIRDFNode> value;
|
||||
for (ConstIterator assignment = First(); assignment != Last(); ++assignment) {
|
||||
Value value;
|
||||
if (! aSet.GetAssignmentFor(assignment->mVariable, &value))
|
||||
if (! aSet.GetAssignmentFor(assignment->mVariable, getter_AddRefs(value)))
|
||||
return PR_FALSE;
|
||||
|
||||
if (assignment->mValue != value)
|
||||
|
@ -636,7 +207,8 @@ Instantiation::Hash(const void* aKey)
|
|||
PLHashNumber result = 0;
|
||||
|
||||
nsAssignmentSet::ConstIterator last = inst->mAssignments.Last();
|
||||
for (nsAssignmentSet::ConstIterator assignment = inst->mAssignments.First(); assignment != last; ++assignment)
|
||||
for (nsAssignmentSet::ConstIterator assignment = inst->mAssignments.First();
|
||||
assignment != last; ++assignment)
|
||||
result ^= assignment->Hash();
|
||||
|
||||
return result;
|
||||
|
@ -730,7 +302,7 @@ InstantiationSet::Erase(Iterator aIterator)
|
|||
|
||||
|
||||
PRBool
|
||||
InstantiationSet::HasAssignmentFor(PRInt32 aVariable) const
|
||||
InstantiationSet::HasAssignmentFor(nsIAtom* aVariable) const
|
||||
{
|
||||
return !Empty() ? First()->mAssignments.HasAssignmentFor(aVariable) : PR_FALSE;
|
||||
}
|
||||
|
@ -742,281 +314,6 @@ InstantiationSet::HasAssignmentFor(PRInt32 aVariable) const
|
|||
// The basic node in the network.
|
||||
//
|
||||
|
||||
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
//
|
||||
// RootNode
|
||||
//
|
||||
|
||||
nsresult
|
||||
RootNode::Propagate(const InstantiationSet& aInstantiations, void* aClosure)
|
||||
{
|
||||
PR_LOG(gXULTemplateLog, PR_LOG_DEBUG,
|
||||
("RootNode[%p]: Propagate() begin", this));
|
||||
|
||||
ReteNodeSet::Iterator last = mKids.Last();
|
||||
for (ReteNodeSet::Iterator kid = mKids.First(); kid != last; ++kid)
|
||||
kid->Propagate(aInstantiations, aClosure);
|
||||
|
||||
PR_LOG(gXULTemplateLog, PR_LOG_DEBUG,
|
||||
("RootNode[%p]: Propagate() end", this));
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
RootNode::Constrain(InstantiationSet& aInstantiations, void* aClosure)
|
||||
{
|
||||
PR_LOG(gXULTemplateLog, PR_LOG_DEBUG,
|
||||
("RootNode[%p]: Constrain()", this));
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
nsresult
|
||||
RootNode::GetAncestorVariables(VariableSet& aVariables) const
|
||||
{
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
PRBool
|
||||
RootNode::HasAncestor(const ReteNode* aNode) const
|
||||
{
|
||||
return aNode == this;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
//
|
||||
// JoinNode
|
||||
//
|
||||
// A node that performs a join in the network.
|
||||
//
|
||||
|
||||
JoinNode::JoinNode(InnerNode* aLeftParent,
|
||||
PRInt32 aLeftVariable,
|
||||
InnerNode* aRightParent,
|
||||
PRInt32 aRightVariable,
|
||||
Operator aOperator)
|
||||
: mLeftParent(aLeftParent),
|
||||
mLeftVariable(aLeftVariable),
|
||||
mRightParent(aRightParent),
|
||||
mRightVariable(aRightVariable),
|
||||
mOperator(aOperator)
|
||||
{
|
||||
}
|
||||
|
||||
nsresult
|
||||
JoinNode::Propagate(const InstantiationSet& aInstantiations, void* aClosure)
|
||||
{
|
||||
// the add will have been propagated down from one of the parent
|
||||
// nodes: either the left or the right. Test the other node for
|
||||
// matches.
|
||||
nsresult rv;
|
||||
|
||||
PRBool hasLeftAssignment = aInstantiations.HasAssignmentFor(mLeftVariable);
|
||||
PRBool hasRightAssignment = aInstantiations.HasAssignmentFor(mRightVariable);
|
||||
|
||||
NS_ASSERTION(hasLeftAssignment ^ hasRightAssignment, "there isn't exactly one assignment specified");
|
||||
if (! (hasLeftAssignment ^ hasRightAssignment))
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
|
||||
InstantiationSet instantiations = aInstantiations;
|
||||
InnerNode* test = hasLeftAssignment ? mRightParent : mLeftParent;
|
||||
|
||||
{
|
||||
// extend the assignments
|
||||
InstantiationSet::Iterator last = instantiations.Last();
|
||||
for (InstantiationSet::Iterator inst = instantiations.First(); inst != last; ++inst) {
|
||||
if (hasLeftAssignment) {
|
||||
// the left is bound
|
||||
Value leftValue;
|
||||
inst->mAssignments.GetAssignmentFor(mLeftVariable, &leftValue);
|
||||
rv = inst->AddAssignment(mRightVariable, leftValue);
|
||||
}
|
||||
else {
|
||||
// the right is bound
|
||||
Value rightValue;
|
||||
inst->mAssignments.GetAssignmentFor(mRightVariable, &rightValue);
|
||||
rv = inst->AddAssignment(mLeftVariable, rightValue);
|
||||
}
|
||||
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
}
|
||||
}
|
||||
|
||||
if (! instantiations.Empty()) {
|
||||
// propagate consistency checking back up the tree
|
||||
rv = test->Constrain(instantiations, aClosure);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
ReteNodeSet::Iterator last = mKids.Last();
|
||||
for (ReteNodeSet::Iterator kid = mKids.First(); kid != last; ++kid)
|
||||
kid->Propagate(instantiations, aClosure);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
nsresult
|
||||
JoinNode::GetNumBound(InnerNode* aAncestor, const InstantiationSet& aInstantiations, PRInt32* aBoundCount)
|
||||
{
|
||||
// Compute the number of variables for an ancestor that are bound
|
||||
// in the current instantiation set.
|
||||
nsresult rv;
|
||||
|
||||
VariableSet vars;
|
||||
rv = aAncestor->GetAncestorVariables(vars);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
PRInt32 count = 0;
|
||||
for (PRInt32 i = vars.GetCount() - 1; i >= 0; --i) {
|
||||
if (aInstantiations.HasAssignmentFor(vars.GetVariableAt(i)))
|
||||
++count;
|
||||
}
|
||||
|
||||
*aBoundCount = count;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
nsresult
|
||||
JoinNode::Bind(InstantiationSet& aInstantiations, PRBool* aDidBind)
|
||||
{
|
||||
// Try to use the instantiation set to bind the unbound join
|
||||
// variable. If successful, aDidBind <= PR_TRUE.
|
||||
nsresult rv;
|
||||
|
||||
PRBool hasLeftAssignment = aInstantiations.HasAssignmentFor(mLeftVariable);
|
||||
PRBool hasRightAssignment = aInstantiations.HasAssignmentFor(mRightVariable);
|
||||
|
||||
NS_ASSERTION(! (hasLeftAssignment && hasRightAssignment), "there is more than one assignment specified");
|
||||
if (hasLeftAssignment && hasRightAssignment)
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
|
||||
if (hasLeftAssignment || hasRightAssignment) {
|
||||
InstantiationSet::Iterator last = aInstantiations.Last();
|
||||
for (InstantiationSet::Iterator inst = aInstantiations.First(); inst != last; ++inst) {
|
||||
if (hasLeftAssignment) {
|
||||
// the left is bound
|
||||
Value leftValue;
|
||||
inst->mAssignments.GetAssignmentFor(mLeftVariable, &leftValue);
|
||||
rv = inst->AddAssignment(mRightVariable, leftValue);
|
||||
}
|
||||
else {
|
||||
// the right is bound
|
||||
Value rightValue;
|
||||
inst->mAssignments.GetAssignmentFor(mRightVariable, &rightValue);
|
||||
rv = inst->AddAssignment(mLeftVariable, rightValue);
|
||||
}
|
||||
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
}
|
||||
|
||||
*aDidBind = PR_TRUE;
|
||||
}
|
||||
else {
|
||||
*aDidBind = PR_FALSE;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
JoinNode::Constrain(InstantiationSet& aInstantiations, void* aClosure)
|
||||
{
|
||||
if (aInstantiations.Empty())
|
||||
return NS_OK;
|
||||
|
||||
nsresult rv;
|
||||
PRBool didBind;
|
||||
|
||||
rv = Bind(aInstantiations, &didBind);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
PRInt32 numLeftBound;
|
||||
rv = GetNumBound(mLeftParent, aInstantiations, &numLeftBound);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
PRInt32 numRightBound;
|
||||
rv = GetNumBound(mRightParent, aInstantiations, &numRightBound);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
InnerNode *first, *last;
|
||||
if (numLeftBound > numRightBound) {
|
||||
first = mLeftParent;
|
||||
last = mRightParent;
|
||||
}
|
||||
else {
|
||||
first = mRightParent;
|
||||
last = mLeftParent;
|
||||
}
|
||||
|
||||
rv = first->Constrain(aInstantiations, aClosure);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
if (! didBind) {
|
||||
rv = Bind(aInstantiations, &didBind);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
NS_ASSERTION(didBind, "uh oh, still no assignment");
|
||||
}
|
||||
|
||||
rv = last->Constrain(aInstantiations, aClosure);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
if (! didBind) {
|
||||
// sort throught the full cross product
|
||||
NS_NOTYETIMPLEMENTED("write me");
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
nsresult
|
||||
JoinNode::GetAncestorVariables(VariableSet& aVariables) const
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
rv = mLeftParent->GetAncestorVariables(aVariables);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
rv = mRightParent->GetAncestorVariables(aVariables);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
|
||||
if (mLeftVariable) {
|
||||
rv = aVariables.Add(mLeftVariable);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
}
|
||||
|
||||
if (mRightVariable) {
|
||||
rv = aVariables.Add(mRightVariable);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
PRBool
|
||||
JoinNode::HasAncestor(const ReteNode* aNode) const
|
||||
{
|
||||
if (aNode == this) {
|
||||
return PR_TRUE;
|
||||
}
|
||||
else if (mLeftParent->HasAncestor(aNode) || mRightParent->HasAncestor(aNode)) {
|
||||
return PR_TRUE;
|
||||
}
|
||||
else {
|
||||
return PR_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
//
|
||||
// TestNode
|
||||
|
@ -1026,31 +323,55 @@ JoinNode::HasAncestor(const ReteNode* aNode) const
|
|||
//
|
||||
|
||||
|
||||
TestNode::TestNode(InnerNode* aParent)
|
||||
TestNode::TestNode(TestNode* aParent)
|
||||
: mParent(aParent)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
nsresult
|
||||
TestNode::Propagate(const InstantiationSet& aInstantiations, void* aClosure)
|
||||
TestNode::Propagate(InstantiationSet& aInstantiations,
|
||||
PRBool aIsUpdate, PRBool& aTakenInstantiations)
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
PR_LOG(gXULTemplateLog, PR_LOG_DEBUG,
|
||||
("TestNode[%p]: Propagate() begin", this));
|
||||
|
||||
InstantiationSet instantiations = aInstantiations;
|
||||
rv = FilterInstantiations(instantiations, aClosure);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
aTakenInstantiations = PR_FALSE;
|
||||
|
||||
if (! instantiations.Empty()) {
|
||||
nsresult rv = FilterInstantiations(aInstantiations);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
// if there is more than one child, each will need to be supplied with the
|
||||
// original set of instantiations from this node, so create a copy in this
|
||||
// case. If there is only one child, optimize and just pass the
|
||||
// instantiations along to the child without copying
|
||||
PRBool shouldCopy = (mKids.Count() > 1);
|
||||
|
||||
// See the header file for details about how instantiation ownership works.
|
||||
if (! aInstantiations.Empty()) {
|
||||
ReteNodeSet::Iterator last = mKids.Last();
|
||||
for (ReteNodeSet::Iterator kid = mKids.First(); kid != last; ++kid) {
|
||||
PR_LOG(gXULTemplateLog, PR_LOG_DEBUG,
|
||||
("TestNode[%p]: Propagate() passing to child %p", this, kid.operator->()));
|
||||
|
||||
kid->Propagate(instantiations, aClosure);
|
||||
// create a copy of the instantiations
|
||||
if (shouldCopy) {
|
||||
PRBool owned = PR_FALSE;
|
||||
InstantiationSet* instantiations =
|
||||
new InstantiationSet(aInstantiations);
|
||||
if (!instantiations)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
rv = kid->Propagate(*instantiations, aIsUpdate, owned);
|
||||
if (!owned)
|
||||
delete instantiations;
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
}
|
||||
else {
|
||||
rv = kid->Propagate(aInstantiations, aIsUpdate, aTakenInstantiations);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1062,24 +383,24 @@ TestNode::Propagate(const InstantiationSet& aInstantiations, void* aClosure)
|
|||
|
||||
|
||||
nsresult
|
||||
TestNode::Constrain(InstantiationSet& aInstantiations, void* aClosure)
|
||||
TestNode::Constrain(InstantiationSet& aInstantiations)
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
PR_LOG(gXULTemplateLog, PR_LOG_DEBUG,
|
||||
("TestNode[%p]: Constrain() begin", this));
|
||||
|
||||
rv = FilterInstantiations(aInstantiations, aClosure);
|
||||
rv = FilterInstantiations(aInstantiations);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
if (! aInstantiations.Empty()) {
|
||||
if (mParent && ! aInstantiations.Empty()) {
|
||||
// if we still have instantiations, then ride 'em on up to the
|
||||
// parent to narrow them.
|
||||
|
||||
PR_LOG(gXULTemplateLog, PR_LOG_DEBUG,
|
||||
("TestNode[%p]: Constrain() passing to parent %p", this, mParent));
|
||||
|
||||
rv = mParent->Constrain(aInstantiations, aClosure);
|
||||
rv = mParent->Constrain(aInstantiations);
|
||||
}
|
||||
else {
|
||||
PR_LOG(gXULTemplateLog, PR_LOG_DEBUG,
|
||||
|
@ -1095,21 +416,14 @@ TestNode::Constrain(InstantiationSet& aInstantiations, void* aClosure)
|
|||
}
|
||||
|
||||
|
||||
nsresult
|
||||
TestNode::GetAncestorVariables(VariableSet& aVariables) const
|
||||
{
|
||||
return mParent->GetAncestorVariables(aVariables);
|
||||
}
|
||||
|
||||
|
||||
PRBool
|
||||
TestNode::HasAncestor(const ReteNode* aNode) const
|
||||
{
|
||||
return aNode == this ? PR_TRUE : mParent->HasAncestor(aNode);
|
||||
return aNode == this || (mParent && mParent->HasAncestor(aNode));
|
||||
}
|
||||
|
||||
|
||||
//----------------------------------------------------------------------0
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
ReteNodeSet::ReteNodeSet()
|
||||
: mNodes(nsnull), mCount(0), mCapacity(0)
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
*
|
||||
* Contributor(s):
|
||||
* Chris Waterson <waterson@netscape.com>
|
||||
* Neil Deakin <enndeakin@sympatico.ca>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
|
@ -62,181 +63,33 @@
|
|||
#define nsRuleNetwork_h__
|
||||
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsCOMArray.h"
|
||||
#include "nsIAtom.h"
|
||||
#include "nsIContent.h"
|
||||
#include "nsIDOMNode.h"
|
||||
#include "plhash.h"
|
||||
#include "pldhash.h"
|
||||
#include "nsCRT.h"
|
||||
#include "nsIRDFNode.h"
|
||||
|
||||
class nsIRDFResource;
|
||||
class nsIRDFNode;
|
||||
class nsXULTemplateResultSetRDF;
|
||||
class nsXULTemplateQueryProcessorRDF;
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* A type-safe value that can be bound to a variable in the rule
|
||||
* network.
|
||||
*/
|
||||
class Value {
|
||||
public:
|
||||
enum Type { eUndefined, eISupports, eString, eInteger };
|
||||
|
||||
protected:
|
||||
Type mType;
|
||||
|
||||
union {
|
||||
nsISupports* mISupports;
|
||||
PRUnichar* mString;
|
||||
PRInt32 mInteger;
|
||||
};
|
||||
|
||||
PRBool Equals(const Value& aValue) const;
|
||||
PRBool Equals(nsISupports* aISupports) const;
|
||||
PRBool Equals(const PRUnichar* aString) const;
|
||||
PRBool Equals(PRInt32 aInteger) const;
|
||||
|
||||
void Clear();
|
||||
|
||||
public:
|
||||
Value() : mType(eUndefined) {
|
||||
MOZ_COUNT_CTOR(Value); }
|
||||
|
||||
Value(const Value& aValue);
|
||||
Value(nsISupports* aISupports);
|
||||
Value(const PRUnichar* aString);
|
||||
Value(PRInt32 aInteger);
|
||||
|
||||
Value& operator=(const Value& aValue);
|
||||
Value& operator=(nsISupports* aISupports);
|
||||
Value& operator=(const PRUnichar* aString);
|
||||
Value& operator=(PRInt32 aInteger);
|
||||
|
||||
~Value();
|
||||
|
||||
PRBool operator==(const Value& aValue) const { return Equals(aValue); }
|
||||
PRBool operator==(nsISupports* aISupports) const { return Equals(aISupports); }
|
||||
PRBool operator==(const PRUnichar* aString) const { return Equals(aString); }
|
||||
PRBool operator==(PRInt32 aInteger) const { return Equals(aInteger); }
|
||||
|
||||
PRBool operator!=(const Value& aValue) const { return !Equals(aValue); }
|
||||
PRBool operator!=(nsISupports* aISupports) const { return !Equals(aISupports); }
|
||||
PRBool operator!=(const PRUnichar* aString) const { return !Equals(aString); }
|
||||
PRBool operator!=(PRInt32 aInteger) const { return !Equals(aInteger); }
|
||||
|
||||
/**
|
||||
* Get the value's type
|
||||
* @return the value's type
|
||||
*/
|
||||
Type GetType() const { return mType; }
|
||||
|
||||
/**
|
||||
* Treat the Value as an nsISupports. (Note that the result
|
||||
* is _not_ addref'd.)
|
||||
* @return the value as an nsISupports, or null if the value is
|
||||
* not an nsISupports.
|
||||
*/
|
||||
operator nsISupports*() const;
|
||||
|
||||
/**
|
||||
* Treat the value as a Unicode string.
|
||||
* @return the value as a Unicode string, or null if the value
|
||||
* is not a Unicode string.
|
||||
*/
|
||||
operator const PRUnichar*() const;
|
||||
|
||||
/**
|
||||
* Treat the value as an integer.
|
||||
* @return the value as an integer, or zero if the value is
|
||||
* not an integer
|
||||
*/
|
||||
operator PRInt32() const;
|
||||
|
||||
PLHashNumber Hash() const;
|
||||
|
||||
#ifdef DEBUG
|
||||
void ToCString(nsACString& aResult);
|
||||
#endif
|
||||
};
|
||||
|
||||
#ifdef DEBUG
|
||||
nsISupports*
|
||||
value_to_isupports(const nsIID& aIID, const Value& aValue);
|
||||
|
||||
# define VALUE_TO_ISUPPORTS(type, v) \
|
||||
NS_STATIC_CAST(type*, value_to_isupports(NS_GET_IID(type), (v)))
|
||||
#else
|
||||
# define VALUE_TO_ISUPPORTS(type, v) \
|
||||
NS_STATIC_CAST(type*, NS_STATIC_CAST(nsISupports*, (v)))
|
||||
#endif
|
||||
|
||||
// Convenience wrappers for |Value::operator nsISupports*()|. In a
|
||||
// debug build, they expand to versions that will call QI() and verify
|
||||
// that the types are kosher. In an optimized build, they'll just cast
|
||||
// n' go. Rock on!
|
||||
#define VALUE_TO_IRDFRESOURCE(v) VALUE_TO_ISUPPORTS(nsIRDFResource, (v))
|
||||
#define VALUE_TO_IRDFNODE(v) VALUE_TO_ISUPPORTS(nsIRDFNode, (v))
|
||||
#define VALUE_TO_ICONTENT(v) VALUE_TO_ISUPPORTS(nsIContent, (v))
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* A set of variables
|
||||
*/
|
||||
class VariableSet
|
||||
{
|
||||
public:
|
||||
VariableSet();
|
||||
~VariableSet();
|
||||
|
||||
/**
|
||||
* Add a variable to the set
|
||||
* @param aVariable the variable to add
|
||||
* @returns NS_OK, unless something went wrong.
|
||||
*/
|
||||
nsresult Add(PRInt32 aVariable);
|
||||
|
||||
/**
|
||||
* Remove a variable from the set
|
||||
* @param aVariable the variable to remove
|
||||
* @returns NS_OK, unless something went wrong.
|
||||
*/
|
||||
nsresult Remove(PRInt32 aVariable);
|
||||
|
||||
/**
|
||||
* Determine if the set contains a variable
|
||||
* @param aVariable the variable to test
|
||||
* @return PR_TRUE if the set contains the variable, PR_FALSE otherwise.
|
||||
*/
|
||||
PRBool Contains(PRInt32 aVariable) const;
|
||||
|
||||
/**
|
||||
* Determine the number of variables in the set
|
||||
* @return the number of variables in the set
|
||||
*/
|
||||
PRInt32 GetCount() const { return mCount; }
|
||||
|
||||
/**
|
||||
* Get the <i>i</i>th variable in the set
|
||||
* @param aIndex the index to retrieve
|
||||
* @return the <i>i</i>th variable in the set, or -1 if no such
|
||||
* variable exists.
|
||||
*/
|
||||
PRInt32 GetVariableAt(PRInt32 aIndex) const { return mVariables[aIndex]; }
|
||||
|
||||
protected:
|
||||
PRInt32* mVariables;
|
||||
PRInt32 mCount;
|
||||
PRInt32 mCapacity;
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* A memory element that supports an instantiation
|
||||
* A memory element that supports an instantiation. A memory element holds a
|
||||
* set of nodes involved in an RDF test such as <member> or <triple> test. A
|
||||
* memory element is created when a specific test matches. The query processor
|
||||
* maintains a map between the memory elements and the results they eventually
|
||||
* matched. When an assertion is removed from the graph, this map is consulted
|
||||
* to determine which results will no longer match.
|
||||
*/
|
||||
class MemoryElement {
|
||||
public:
|
||||
MemoryElement() {}
|
||||
virtual ~MemoryElement() {}
|
||||
MemoryElement() { MOZ_COUNT_CTOR(MemoryElement); }
|
||||
virtual ~MemoryElement() { MOZ_COUNT_DTOR(MemoryElement); }
|
||||
|
||||
virtual const char* Type() const = 0;
|
||||
virtual PLHashNumber Hash() const = 0;
|
||||
|
@ -367,13 +220,13 @@ public:
|
|||
*/
|
||||
class nsAssignment {
|
||||
public:
|
||||
PRInt32 mVariable;
|
||||
Value mValue;
|
||||
nsCOMPtr<nsIAtom> mVariable;
|
||||
nsCOMPtr<nsIRDFNode> mValue;
|
||||
|
||||
nsAssignment() : mVariable(-1), mValue()
|
||||
nsAssignment() : mValue()
|
||||
{ MOZ_COUNT_CTOR(nsAssignment); }
|
||||
|
||||
nsAssignment(PRInt32 aVariable, const Value& aValue)
|
||||
nsAssignment(nsIAtom* aVariable, nsIRDFNode* aValue)
|
||||
: mVariable(aVariable),
|
||||
mValue(aValue)
|
||||
{ MOZ_COUNT_CTOR(nsAssignment); }
|
||||
|
@ -397,8 +250,9 @@ public:
|
|||
return mVariable != aAssignment.mVariable || mValue != aAssignment.mValue; }
|
||||
|
||||
PLHashNumber Hash() const {
|
||||
// XXX I have no idea if this hashing function is good or not
|
||||
return (mValue.Hash() & 0xffff) | (mVariable << 16); }
|
||||
// XXX I have no idea if this hashing function is good or not // XXX change this
|
||||
PLHashNumber temp = PLHashNumber(NS_PTR_TO_INT32(mValue.get())) >> 2; // strip alignment bits
|
||||
return (temp & 0xffff) | ((PRInt32)mVariable.get()); }
|
||||
};
|
||||
|
||||
|
||||
|
@ -524,7 +378,7 @@ public:
|
|||
* @param aValue the value to query
|
||||
* @return PR_TRUE if aVariable is bound to aValue; PR_FALSE otherwise.
|
||||
*/
|
||||
PRBool HasAssignment(PRInt32 aVariable, const Value& aValue) const;
|
||||
PRBool HasAssignment(nsIAtom* aVariable, nsIRDFNode* aValue) const;
|
||||
|
||||
/**
|
||||
* Determine if the assignment set contains the specified assignment
|
||||
|
@ -541,7 +395,7 @@ public:
|
|||
* @return PR_TRUE if the assignment set has an assignment for the variable,
|
||||
* PR_FALSE otherwise.
|
||||
*/
|
||||
PRBool HasAssignmentFor(PRInt32 aVariable) const;
|
||||
PRBool HasAssignmentFor(nsIAtom* aVariable) const;
|
||||
|
||||
/**
|
||||
* Retrieve the assignment for the specified variable
|
||||
|
@ -551,7 +405,7 @@ public:
|
|||
* @return PR_TRUE if the variable has an assignment, PR_FALSE
|
||||
* if there was no assignment for the variable.
|
||||
*/
|
||||
PRBool GetAssignmentFor(PRInt32 aVariable, Value* aValue) const;
|
||||
PRBool GetAssignmentFor(nsIAtom* aVariable, nsIRDFNode** aValue) const;
|
||||
|
||||
/**
|
||||
* Count the number of assignments in the set
|
||||
|
@ -574,8 +428,14 @@ public:
|
|||
//----------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* A collection of varible-to-value bindings, with the memory elements
|
||||
* that support those bindings.
|
||||
* A collection of variable-to-value bindings, with the memory elements
|
||||
* that support those bindings. Essentially, an instantiation is the
|
||||
* collection of variables and values assigned to those variables for a single
|
||||
* result. For each RDF rule in the rule network, each instantiation is
|
||||
* examined and either extended with additional bindings specified by the RDF
|
||||
* rule, or removed if the rule doesn't apply (for instance if a node has no
|
||||
* children). When an instantiation gets to the last node of the rule network,
|
||||
* which is always an nsInstantiationNode, a result is created for it.
|
||||
*
|
||||
* An instantiation object is typically created by "extending" another
|
||||
* instantiation object. That is, using the copy constructor, and
|
||||
|
@ -616,7 +476,7 @@ public:
|
|||
* @return NS_OK if no errors, NS_ERROR_OUT_OF_MEMORY if there
|
||||
* is not enough memory to perform the operation
|
||||
*/
|
||||
nsresult AddAssignment(PRInt32 aVariable, const Value& aValue) {
|
||||
nsresult AddAssignment(nsIAtom* aVariable, nsIRDFNode* aValue) {
|
||||
mAssignments.Add(nsAssignment(aVariable, aValue));
|
||||
return NS_OK; }
|
||||
|
||||
|
@ -668,6 +528,8 @@ public:
|
|||
class Iterator;
|
||||
friend class Iterator;
|
||||
|
||||
friend class nsXULTemplateResultSetRDF; // so it can get to the List
|
||||
|
||||
protected:
|
||||
class List {
|
||||
public:
|
||||
|
@ -782,8 +644,7 @@ public:
|
|||
|
||||
void Clear();
|
||||
|
||||
PRBool HasAssignmentFor(PRInt32 aVariable) const;
|
||||
|
||||
PRBool HasAssignmentFor(nsIAtom* aVariable) const;
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
@ -813,13 +674,18 @@ public:
|
|||
* node must recursively call Propagate() on its children. We
|
||||
* should fix this to make the algorithm interruptable.)
|
||||
*
|
||||
* See TestNode::Propagate for details about instantiation set ownership
|
||||
*
|
||||
* @param aInstantiations the set of instantiations to propagate
|
||||
* down through the network.
|
||||
* @param aClosure any application-specific information that
|
||||
* needs to be passed through the network.
|
||||
* @param aIsUpdate true if updating, false for first generation
|
||||
* @param aTakenInstantiations true if the ownership over aInstantiations
|
||||
* has been taken from the caller. If false,
|
||||
* the caller owns it.
|
||||
* @return NS_OK if no errors occurred.
|
||||
*/
|
||||
virtual nsresult Propagate(const InstantiationSet& aInstantiations, void* aClosure) = 0;
|
||||
virtual nsresult Propagate(InstantiationSet& aInstantiations,
|
||||
PRBool aIsUpdate, PRBool& aTakenInstantiations) = 0;
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
@ -907,6 +773,8 @@ public:
|
|||
Iterator First() { return Iterator(mNodes); }
|
||||
Iterator Last() { return Iterator(mNodes + mCount); }
|
||||
|
||||
PRInt32 Count() const { return mCount; }
|
||||
|
||||
protected:
|
||||
ReteNode** mNodes;
|
||||
PRInt32 mCount;
|
||||
|
@ -916,12 +784,63 @@ protected:
|
|||
//----------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* An abstract base class for an "inner node" in the rule
|
||||
* network. Adds support for children and "upward" queries.
|
||||
* A node that applies a test condition to a set of instantiations.
|
||||
*
|
||||
* This class provides implementations of Propagate() and Constrain()
|
||||
* in terms of one simple operation, FilterInstantiations(). A node
|
||||
* that is a "simple test node" in a rule network should derive from
|
||||
* this class, and need only implement FilterInstantiations().
|
||||
*/
|
||||
class InnerNode : public ReteNode
|
||||
class TestNode : public ReteNode
|
||||
{
|
||||
public:
|
||||
TestNode(TestNode* aParent);
|
||||
|
||||
/**
|
||||
* Retrieve the test node's parent
|
||||
* @return the test node's parent
|
||||
*/
|
||||
TestNode* GetParent() const { return mParent; }
|
||||
|
||||
/**
|
||||
* Calls FilterInstantiations() on the instantiation set, and if
|
||||
* the resulting set isn't empty, propagates the new set down to
|
||||
* each of the test node's children.
|
||||
*
|
||||
* Note that the caller of Propagate is responsible for deleting
|
||||
* aInstantiations if necessary as described below.
|
||||
*
|
||||
* Propagate may be called in update or non-update mode as indicated
|
||||
* by the aIsUpdate argument. Non-update mode is used when initially
|
||||
* generating results, whereas update mode is used when the datasource
|
||||
* changes and new results might be available.
|
||||
*
|
||||
* The last node in a chain of TestNodes is always an nsInstantiationNode.
|
||||
* In non-update mode, this nsInstantiationNode will cache the results
|
||||
* in the query using the SetCachedResults method. The query processor
|
||||
* takes these cached results and creates a nsXULTemplateResultSetRDF
|
||||
* which is the enumeration returned to the template builder. This
|
||||
* nsXULTemplateResultSetRDF owns the instantiations and they will be
|
||||
* deleted when the nsXULTemplateResultSetRDF goes away.
|
||||
*
|
||||
* In update mode, the nsInstantiationNode node will iterate over the
|
||||
* instantiations itself and callback to the builder to update any matches
|
||||
* and generated content. If no instantiations match, then the builder
|
||||
* will never be called.
|
||||
*
|
||||
* Thus, the difference between update and non-update modes is that in
|
||||
* update mode, the results and instantiations have been already handled
|
||||
* whereas in non-update mode they are expected to be returned in an
|
||||
* nsXULTemplateResultSetRDF for further processing by the builder.
|
||||
*
|
||||
* Regardless, aTakenInstantiations will be set to true if the
|
||||
* ownership over aInstantiations has been transferred to a result set.
|
||||
* If set to false, the caller is still responsible for aInstantiations.
|
||||
* aTakenInstantiations will be set properly even if an error occurs.
|
||||
*/
|
||||
virtual nsresult Propagate(InstantiationSet& aInstantiations,
|
||||
PRBool aIsUpdate, PRBool& aTakenInstantiations);
|
||||
|
||||
/**
|
||||
* This is called by a child node on its parent to allow the
|
||||
* parent's constraints to apply to the set of instantiations.
|
||||
|
@ -938,24 +857,22 @@ public:
|
|||
*
|
||||
* @param aInstantiations the set of instantiations that must
|
||||
* be constrained
|
||||
* @param aClosure application-specific information that needs to
|
||||
* be passed through the network.
|
||||
* @return NS_OK if no errors occurred
|
||||
*/
|
||||
virtual nsresult Constrain(InstantiationSet& aInstantiations, void* aClosure) = 0;
|
||||
virtual nsresult Constrain(InstantiationSet& aInstantiations);
|
||||
|
||||
/**
|
||||
* Retrieve the set of variables that are introduced by this node
|
||||
* and any of its ancestors. To correctly implement this method, a
|
||||
* node must add any variables that it introduces to the variable
|
||||
* set, and then recursively call GetAncestorVariables() on its
|
||||
* parent (or parents).
|
||||
* Given a set of instantiations, filter out any that are
|
||||
* inconsistent with the test node's test, and append
|
||||
* variable-to-value assignments and memory element support for
|
||||
* those which do pass the test node's test.
|
||||
*
|
||||
* @param aVariables The variable set to which the callee will add
|
||||
* its variables, and its ancestors variables.
|
||||
* @return NS_OK if no errors occur.
|
||||
* @param aInstantiations the set of instantiations to be
|
||||
* filtered
|
||||
* @return NS_OK if no errors occurred.
|
||||
*/
|
||||
virtual nsresult GetAncestorVariables(VariableSet& aVariables) const = 0;
|
||||
virtual nsresult FilterInstantiations(InstantiationSet& aInstantiations) const = 0;
|
||||
//XXX probably better named "ApplyConstraints" or "Discrminiate" or something
|
||||
|
||||
/**
|
||||
* Determine if this node has another node as its direct ancestor.
|
||||
|
@ -963,7 +880,7 @@ public:
|
|||
* @return PR_TRUE if aNode is a direct ancestor of this node, PR_FALSE
|
||||
* otherwise.
|
||||
*/
|
||||
virtual PRBool HasAncestor(const ReteNode* aNode) const = 0;
|
||||
PRBool HasAncestor(const ReteNode* aNode) const;
|
||||
|
||||
/**
|
||||
* Add another node as a child of this node.
|
||||
|
@ -979,236 +896,8 @@ public:
|
|||
nsresult RemoveAllChildren() { return mKids.Clear(); }
|
||||
|
||||
protected:
|
||||
TestNode* mParent;
|
||||
ReteNodeSet mKids;
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* The root node in the rule network.
|
||||
*/
|
||||
class RootNode : public InnerNode
|
||||
{
|
||||
public:
|
||||
// "downward" propagations
|
||||
virtual nsresult Propagate(const InstantiationSet& aInstantiations, void* aClosure);
|
||||
|
||||
// "upward" propagations
|
||||
virtual nsresult Constrain(InstantiationSet& aInstantiations, void* aClosure);
|
||||
|
||||
virtual nsresult GetAncestorVariables(VariableSet& aVariables) const;
|
||||
|
||||
virtual PRBool HasAncestor(const ReteNode* aNode) const;
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* A node that joins to paths from the root node, and binds a
|
||||
* variable from the left ancestor to a variable in the right
|
||||
* ancestor.
|
||||
*/
|
||||
class JoinNode : public InnerNode
|
||||
{
|
||||
public:
|
||||
enum Operator { eEquality };
|
||||
|
||||
JoinNode(InnerNode* aLeftParent,
|
||||
PRInt32 aLeftVariable,
|
||||
InnerNode* aRightParent,
|
||||
PRInt32 aRightVariable,
|
||||
Operator aOperator);
|
||||
|
||||
// "downward" propagations
|
||||
virtual nsresult Propagate(const InstantiationSet& aInstantiations, void* aClosure);
|
||||
|
||||
// "upward" propagations
|
||||
virtual nsresult Constrain(InstantiationSet& aInstantiations, void* aClosure);
|
||||
|
||||
virtual nsresult GetAncestorVariables(VariableSet& aVariables) const;
|
||||
|
||||
virtual PRBool HasAncestor(const ReteNode* aNode) const;
|
||||
|
||||
protected:
|
||||
InnerNode* mLeftParent;
|
||||
PRInt32 mLeftVariable;
|
||||
InnerNode* mRightParent;
|
||||
PRInt32 mRightVariable;
|
||||
Operator mOperator;
|
||||
|
||||
static nsresult GetNumBound(InnerNode* aAncestor, const InstantiationSet& aInstantiations, PRInt32* aBoundCount);
|
||||
|
||||
nsresult Bind(InstantiationSet& aInstantiations, PRBool* aDidBind);
|
||||
};
|
||||
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* A node that applies a test condition to a set of instantiations.
|
||||
*
|
||||
* This class provides implementations of Propagate() and Constrain()
|
||||
* in terms of one simple operation, FilterInstantiations(). A node
|
||||
* that is a "simple test node" in a rule network should derive from
|
||||
* this class, and need only implement FilterInstantiations() and
|
||||
* GetAncestorVariables().
|
||||
*/
|
||||
class TestNode : public InnerNode
|
||||
{
|
||||
public:
|
||||
TestNode(InnerNode* aParent);
|
||||
|
||||
/**
|
||||
* Retrieve the test node's parent
|
||||
* @return the test node's parent
|
||||
*/
|
||||
InnerNode* GetParent() const { return mParent; }
|
||||
|
||||
/**
|
||||
* Calls FilterInstantiations() on the instantiation set, and if
|
||||
* the resulting set isn't empty, propagates the new set down to
|
||||
* each of the test node's children.
|
||||
*/
|
||||
virtual nsresult Propagate(const InstantiationSet& aInstantiations, void* aClosure);
|
||||
|
||||
/**
|
||||
* Calls FilterInstantiations() on the instantiation set, and if
|
||||
* the resulting set isn't empty, propagates the new set up to the
|
||||
* test node's parent.
|
||||
*/
|
||||
virtual nsresult Constrain(InstantiationSet& aInstantiations, void* aClosure);
|
||||
|
||||
/**
|
||||
* Given a set of instantiations, filter out any that are
|
||||
* inconsistent with the test node's test, and append
|
||||
* variable-to-value assignments and memory element support for
|
||||
* those which do pass the test node's test.
|
||||
*
|
||||
* @param aInstantiations the set of instantiations to be
|
||||
* filtered
|
||||
* @param aClosure application-specific data that is to be passed
|
||||
* through the network.
|
||||
* @return NS_OK if no errors occurred.
|
||||
*/
|
||||
virtual nsresult FilterInstantiations(InstantiationSet& aInstantiations, void* aClosure) const = 0; //XXX probably better named "ApplyConstraints" or "Discrminiate" or something
|
||||
|
||||
virtual nsresult GetAncestorVariables(VariableSet& aVariables) const;
|
||||
|
||||
virtual PRBool HasAncestor(const ReteNode* aNode) const;
|
||||
|
||||
protected:
|
||||
InnerNode* mParent;
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
class nsRuleNetwork
|
||||
{
|
||||
public:
|
||||
struct SymtabEntry {
|
||||
PLDHashEntryHdr mHdr;
|
||||
PRUnichar* mSymbol;
|
||||
PRInt32 mVariable;
|
||||
};
|
||||
|
||||
nsRuleNetwork() { Init(); }
|
||||
~nsRuleNetwork() { Finish(); }
|
||||
|
||||
/**
|
||||
* Remove all the nodes from the network. The nodes will be
|
||||
* destroyed
|
||||
* @return NS_OK if no errors occur
|
||||
*/
|
||||
void Clear() { Finish(); Init(); }
|
||||
|
||||
/**
|
||||
* Add a node to the network. The network assumes ownership of the
|
||||
* node; it will be destroyed when the network is destroyed, or if
|
||||
* Clear() is called.
|
||||
*
|
||||
* @param aNode the node to add to the network
|
||||
* @return NS_OK if no errors occur
|
||||
*/
|
||||
nsresult AddNode(ReteNode* aNode) { return mNodes.Add(aNode); }
|
||||
|
||||
/**
|
||||
* Retrieve the root node in the rule network
|
||||
* @return the root node in the rule network
|
||||
*/
|
||||
RootNode* GetRoot() { return &mRoot; };
|
||||
|
||||
/**
|
||||
* Create an unnamed variable
|
||||
*/
|
||||
PRInt32 CreateAnonymousVariable() { return ++mNextVariable; }
|
||||
|
||||
/**
|
||||
* Assign a symbol to a variable
|
||||
*/
|
||||
void PutSymbol(const PRUnichar* aSymbol, PRInt32 aVariable) {
|
||||
if (!mSymtab.ops) return;
|
||||
NS_PRECONDITION(LookupSymbol(aSymbol) == 0, "symbol already defined");
|
||||
|
||||
SymtabEntry* entry =
|
||||
NS_REINTERPRET_CAST(SymtabEntry*,
|
||||
PL_DHashTableOperate(&mSymtab,
|
||||
aSymbol,
|
||||
PL_DHASH_ADD));
|
||||
|
||||
if (entry) {
|
||||
entry->mSymbol = nsCRT::strdup(aSymbol);
|
||||
entry->mVariable = aVariable;
|
||||
} };
|
||||
|
||||
/**
|
||||
* Lookup the variable associated with the symbol
|
||||
*/
|
||||
PRInt32 LookupSymbol(const PRUnichar* aSymbol, PRBool aCreate = PR_FALSE) {
|
||||
if (!mSymtab.ops) return 0;
|
||||
SymtabEntry* entry =
|
||||
NS_REINTERPRET_CAST(SymtabEntry*,
|
||||
PL_DHashTableOperate(&mSymtab,
|
||||
aSymbol,
|
||||
PL_DHASH_LOOKUP));
|
||||
|
||||
if (PL_DHASH_ENTRY_IS_BUSY(&entry->mHdr))
|
||||
return entry->mVariable;
|
||||
|
||||
PRInt32 result = 0;
|
||||
if (aCreate) {
|
||||
result = CreateAnonymousVariable();
|
||||
PutSymbol(aSymbol, result);
|
||||
}
|
||||
|
||||
return result; }
|
||||
|
||||
protected:
|
||||
/**
|
||||
* The root node in the network
|
||||
*/
|
||||
RootNode mRoot;
|
||||
|
||||
/**
|
||||
* Other nodes in the network
|
||||
*/
|
||||
ReteNodeSet mNodes;
|
||||
|
||||
void Init();
|
||||
void Finish();
|
||||
|
||||
/**
|
||||
* Symbol table, mapping symbolic names to variable identifiers
|
||||
*/
|
||||
PLDHashTable mSymtab;
|
||||
|
||||
/**
|
||||
* The next available variable identifier
|
||||
*/
|
||||
PRInt32 mNextVariable;
|
||||
|
||||
static PLDHashTableOps gOps;
|
||||
};
|
||||
|
||||
|
||||
|
||||
#endif // nsRuleNetwork_h__
|
||||
|
|
|
@ -44,14 +44,19 @@ nsTemplateMatch::nsTemplateMatch(const nsTemplateMatch& aMatch) {}
|
|||
void nsTemplateMatch::operator=(const nsTemplateMatch& aMatch) {}
|
||||
#endif
|
||||
|
||||
PRBool
|
||||
nsTemplateMatch::GetAssignmentFor(nsConflictSet& aConflictSet, PRInt32 aVariable, Value* aValue)
|
||||
nsresult
|
||||
nsTemplateMatch::RuleMatched(nsTemplateQuerySet* aQuerySet,
|
||||
nsTemplateRule* aRule,
|
||||
nsIXULTemplateResult* aResult)
|
||||
{
|
||||
if (mAssignments.GetAssignmentFor(aVariable, aValue)) {
|
||||
return PR_TRUE;
|
||||
}
|
||||
else {
|
||||
return mRule->ComputeAssignmentFor(aConflictSet, this, aVariable, aValue);
|
||||
}
|
||||
}
|
||||
mRule = aRule;
|
||||
|
||||
nsCOMPtr<nsIDOMNode> rulenode;
|
||||
aRule->GetRuleNode(getter_AddRefs(rulenode));
|
||||
if (rulenode) {
|
||||
nsCOMPtr<nsIDOMNode> querynode = do_QueryInterface(aQuerySet->mQueryNode);
|
||||
return aResult->RuleMatched(querynode, rulenode);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
|
|
@ -40,22 +40,28 @@
|
|||
#define nsTemplateMatch_h__
|
||||
|
||||
#include "nsFixedSizeAllocator.h"
|
||||
#include "nsResourceSet.h"
|
||||
#include "nsIContent.h"
|
||||
#include "nsIXULTemplateQueryProcessor.h"
|
||||
#include "nsIXULTemplateResult.h"
|
||||
#include "nsRuleNetwork.h"
|
||||
#include NEW_H
|
||||
|
||||
/**
|
||||
* A "match" is a fully instantiated rule; that is, a complete and
|
||||
* consistent set of variable-to-value assignments for all the rule's
|
||||
* condition elements.
|
||||
* A match object, where each match object is associated with one result.
|
||||
* There will be one match list for each unique id generated. However, since
|
||||
* there are multiple querysets and each may generate results with the same
|
||||
* id, they are all chained together in a linked list, ordered in the same
|
||||
* order as the respective <queryset> elements they were generated from.
|
||||
* Only one match is active at a time, but which match is active may change
|
||||
* as new results are added or removed. When a match is active, content is
|
||||
* generated for that match.
|
||||
*
|
||||
* Each match also contains information about the "optional"
|
||||
* variable-to-value assignments that can be specified using the
|
||||
* <bindings> element in a rule.
|
||||
* Matches are stored and owned by the mMatchToMap hash in the template
|
||||
* builder.
|
||||
*/
|
||||
|
||||
class nsConflictSet;
|
||||
class nsTemplateRule;
|
||||
class nsTemplateQuerySet;
|
||||
|
||||
class nsTemplateMatch {
|
||||
private:
|
||||
|
@ -64,25 +70,22 @@ private:
|
|||
void* operator new(size_t) CPP_THROW_NEW { return 0; }
|
||||
void operator delete(void*, size_t) {}
|
||||
|
||||
protected:
|
||||
PRInt32 mRefCnt;
|
||||
|
||||
nsTemplateMatch(const nsTemplateRule* aRule,
|
||||
const Instantiation& aInstantiation,
|
||||
const nsAssignmentSet& aAssignments)
|
||||
: mRefCnt(0),
|
||||
mRule(aRule),
|
||||
mInstantiation(aInstantiation),
|
||||
mAssignments(aAssignments) {}
|
||||
|
||||
public:
|
||||
nsTemplateMatch(nsTemplateQuerySet* aQuerySet,
|
||||
nsIXULTemplateResult* aResult)
|
||||
: mRule(nsnull),
|
||||
mQuerySet(aQuerySet),
|
||||
mResult(aResult),
|
||||
mNext(nsnull) {}
|
||||
|
||||
~nsTemplateMatch() {}
|
||||
|
||||
static nsTemplateMatch*
|
||||
Create(nsFixedSizeAllocator& aPool,
|
||||
const nsTemplateRule* aRule,
|
||||
const Instantiation& aInstantiation,
|
||||
const nsAssignmentSet& aAssignments) {
|
||||
nsTemplateQuerySet* aQuerySet,
|
||||
nsIXULTemplateResult* aResult) {
|
||||
void* place = aPool.Alloc(sizeof(nsTemplateMatch));
|
||||
return place ? ::new (place) nsTemplateMatch(aRule, aInstantiation, aAssignments) : nsnull; }
|
||||
return place ? ::new (place) nsTemplateMatch(aQuerySet, aResult) : nsnull; }
|
||||
|
||||
static void
|
||||
Destroy(nsFixedSizeAllocator& aPool, nsTemplateMatch* aMatch) {
|
||||
|
@ -90,65 +93,44 @@ public:
|
|||
aPool.Free(aMatch, sizeof(*aMatch)); }
|
||||
|
||||
PRBool operator==(const nsTemplateMatch& aMatch) const {
|
||||
return mRule == aMatch.mRule && mInstantiation == aMatch.mInstantiation; }
|
||||
return mRule == aMatch.mRule && mResult == aMatch.mResult; }
|
||||
|
||||
PRBool operator!=(const nsTemplateMatch& aMatch) const {
|
||||
return !(*this == aMatch); }
|
||||
|
||||
/**
|
||||
* Get the assignment for the specified variable, computing the
|
||||
* value using the rule's bindings, if necessary.
|
||||
* @param aConflictSet
|
||||
* @param aVariable the variable for which to determine the assignment
|
||||
* @param aValue an out parameter that receives the value assigned to
|
||||
* aVariable.
|
||||
* @return PR_TRUE if aVariable has an assignment, PR_FALSE otherwise.
|
||||
*/
|
||||
PRBool GetAssignmentFor(nsConflictSet& aConflictSet, PRInt32 aVariable, Value* aValue);
|
||||
nsresult RuleMatched(nsTemplateQuerySet* aQuerySet,
|
||||
nsTemplateRule* aRule,
|
||||
nsIXULTemplateResult* aResult);
|
||||
|
||||
/**
|
||||
* The rule that this match applies for.
|
||||
* The rule that this match applies to. If the rule is null, the result
|
||||
* has not matched a rule and no content has been generated. However, a
|
||||
* later queryset may still have matched.
|
||||
*/
|
||||
const nsTemplateRule* mRule;
|
||||
nsTemplateRule* mRule; // not owned
|
||||
|
||||
/**
|
||||
* The fully bound instantiation (variable-to-value assignments, with
|
||||
* memory element support) that match the rule's conditions.
|
||||
* The queryset for this rule
|
||||
*/
|
||||
Instantiation mInstantiation;
|
||||
nsTemplateQuerySet* mQuerySet; // not owned
|
||||
|
||||
/**
|
||||
* Any additional assignments that apply because of the rule's
|
||||
* bindings. These are computed lazily.
|
||||
* The result associated with this match
|
||||
*/
|
||||
nsAssignmentSet mAssignments;
|
||||
nsCOMPtr<nsIXULTemplateResult> mResult;
|
||||
|
||||
/**
|
||||
* The set of resources that the nsTemplateMatch's bindings depend on. Should the
|
||||
* assertions relating to these resources change, then the rule will
|
||||
* still match (i.e., this match object is still "good"); however, we
|
||||
* may need to recompute the assignments that have been made using the
|
||||
* rule's bindings.
|
||||
* Matches are stored in a linked list, in priority order. This first
|
||||
* match that has a rule set (mRule) is the active match and generates
|
||||
* content. The next match is owned by the builder, which will delete
|
||||
* template matches when needed.
|
||||
*/
|
||||
nsResourceSet mBindingDependencies;
|
||||
|
||||
PRInt32 AddRef() {
|
||||
++mRefCnt;
|
||||
NS_LOG_ADDREF(this, mRefCnt, "nsTemplateMatch", sizeof(*this));
|
||||
return mRefCnt; }
|
||||
|
||||
PRInt32 Release(nsFixedSizeAllocator& aPool) {
|
||||
NS_PRECONDITION(mRefCnt > 0, "bad refcnt");
|
||||
PRInt32 refcnt = --mRefCnt;
|
||||
NS_LOG_RELEASE(this, mRefCnt, "nsTemplateMatch");
|
||||
if (refcnt == 0)
|
||||
Destroy(aPool, this);
|
||||
return refcnt; }
|
||||
nsTemplateMatch *mNext;
|
||||
|
||||
private:
|
||||
nsTemplateMatch(const nsTemplateMatch& aMatch); // not to be implemented
|
||||
void operator=(const nsTemplateMatch& aMatch); // not to be implemented
|
||||
};
|
||||
|
||||
#endif // nsConflictSet_h__
|
||||
#endif // nsTemplateMatch_h__
|
||||
|
||||
|
|
|
@ -38,9 +38,264 @@
|
|||
|
||||
#include "nsTemplateRule.h"
|
||||
#include "nsTemplateMatch.h"
|
||||
#include "nsRuleNetwork.h"
|
||||
#include "nsConflictSet.h"
|
||||
#include "nsVoidArray.h"
|
||||
#include "nsXULContentUtils.h"
|
||||
#include "nsUnicharUtils.h"
|
||||
#include "nsReadableUtils.h"
|
||||
#include "nsICollation.h"
|
||||
|
||||
nsTemplateCondition::nsTemplateCondition(nsIAtom* aSourceVariable,
|
||||
const nsAString& aRelation,
|
||||
nsIAtom* aTargetVariable,
|
||||
PRBool aIgnoreCase,
|
||||
PRBool aNegate)
|
||||
: mSourceVariable(aSourceVariable),
|
||||
mTargetVariable(aTargetVariable),
|
||||
mIgnoreCase(aIgnoreCase),
|
||||
mNegate(aNegate),
|
||||
mNext(nsnull)
|
||||
{
|
||||
SetRelation(aRelation);
|
||||
|
||||
MOZ_COUNT_CTOR(nsTemplateCondition);
|
||||
}
|
||||
|
||||
nsTemplateCondition::nsTemplateCondition(nsIAtom* aSourceVariable,
|
||||
const nsAString& aRelation,
|
||||
const nsAString& aTargets,
|
||||
PRBool aIgnoreCase,
|
||||
PRBool aNegate,
|
||||
PRBool aIsMultiple)
|
||||
: mSourceVariable(aSourceVariable),
|
||||
mIgnoreCase(aIgnoreCase),
|
||||
mNegate(aNegate),
|
||||
mNext(nsnull)
|
||||
{
|
||||
SetRelation(aRelation);
|
||||
|
||||
if (aIsMultiple) {
|
||||
PRInt32 start = 0, end = 0;
|
||||
while ((end = aTargets.FindChar(',',start)) >= 0) {
|
||||
if (end > start) {
|
||||
mTargetList.AppendString(Substring(aTargets, start, end - start));
|
||||
}
|
||||
start = end + 1;
|
||||
}
|
||||
if (start < (PRInt32)aTargets.Length()) {
|
||||
mTargetList.AppendString(Substring(aTargets, start));
|
||||
}
|
||||
}
|
||||
else {
|
||||
mTargetList.AppendString(aTargets);
|
||||
}
|
||||
|
||||
MOZ_COUNT_CTOR(nsTemplateCondition);
|
||||
}
|
||||
|
||||
nsTemplateCondition::nsTemplateCondition(const nsAString& aSource,
|
||||
const nsAString& aRelation,
|
||||
nsIAtom* aTargetVariable,
|
||||
PRBool aIgnoreCase,
|
||||
PRBool aNegate)
|
||||
: mSource(aSource),
|
||||
mTargetVariable(aTargetVariable),
|
||||
mIgnoreCase(aIgnoreCase),
|
||||
mNegate(aNegate),
|
||||
mNext(nsnull)
|
||||
{
|
||||
SetRelation(aRelation);
|
||||
|
||||
MOZ_COUNT_CTOR(nsTemplateCondition);
|
||||
}
|
||||
|
||||
void
|
||||
nsTemplateCondition::SetRelation(const nsAString& aRelation)
|
||||
{
|
||||
if (aRelation.EqualsLiteral("equals") || aRelation.IsEmpty())
|
||||
mRelation = eEquals;
|
||||
else if (aRelation.EqualsLiteral("less"))
|
||||
mRelation = eLess;
|
||||
else if (aRelation.EqualsLiteral("greater"))
|
||||
mRelation = eGreater;
|
||||
else if (aRelation.EqualsLiteral("before"))
|
||||
mRelation = eBefore;
|
||||
else if (aRelation.EqualsLiteral("after"))
|
||||
mRelation = eAfter;
|
||||
else if (aRelation.EqualsLiteral("startswith"))
|
||||
mRelation = eStartswith;
|
||||
else if (aRelation.EqualsLiteral("endswith"))
|
||||
mRelation = eEndswith;
|
||||
else if (aRelation.EqualsLiteral("contains"))
|
||||
mRelation = eContains;
|
||||
else
|
||||
mRelation = eUnknown;
|
||||
}
|
||||
|
||||
PRBool
|
||||
nsTemplateCondition::CheckMatch(nsIXULTemplateResult* aResult)
|
||||
{
|
||||
PRBool match = PR_FALSE;
|
||||
|
||||
nsAutoString leftString;
|
||||
if (mSourceVariable)
|
||||
aResult->GetBindingFor(mSourceVariable, leftString);
|
||||
else
|
||||
leftString.Assign(mSource);
|
||||
|
||||
if (mTargetVariable) {
|
||||
nsAutoString rightString;
|
||||
aResult->GetBindingFor(mTargetVariable, rightString);
|
||||
|
||||
match = CheckMatchStrings(leftString, rightString);
|
||||
}
|
||||
else {
|
||||
// iterate over the strings in the target and determine
|
||||
// whether there is a match.
|
||||
PRInt32 length = mTargetList.Count();
|
||||
for (PRInt32 t = 0; t < length; t++) {
|
||||
match = CheckMatchStrings(leftString, *mTargetList[t]);
|
||||
|
||||
// stop once a match is found. In negate mode, stop once a
|
||||
// target does not match.
|
||||
if (match != mNegate) break;
|
||||
}
|
||||
}
|
||||
|
||||
return match;
|
||||
}
|
||||
|
||||
|
||||
PRBool
|
||||
nsTemplateCondition::CheckMatchStrings(const nsAString& aLeftString,
|
||||
const nsAString& aRightString)
|
||||
{
|
||||
PRBool match = PR_FALSE;
|
||||
|
||||
if (aRightString.IsEmpty()) {
|
||||
if ((mRelation == eEquals) && aLeftString.IsEmpty())
|
||||
match = PR_TRUE;
|
||||
}
|
||||
else {
|
||||
switch (mRelation) {
|
||||
case eEquals:
|
||||
if (mIgnoreCase)
|
||||
match = aLeftString.Equals(aRightString,
|
||||
nsCaseInsensitiveStringComparator());
|
||||
else
|
||||
match = aLeftString.Equals(aRightString);
|
||||
break;
|
||||
|
||||
case eLess:
|
||||
case eGreater:
|
||||
{
|
||||
// non-numbers always compare false
|
||||
PRInt32 err;
|
||||
PRInt32 leftint = PromiseFlatString(aLeftString).ToInteger(&err);
|
||||
if (NS_SUCCEEDED(err)) {
|
||||
PRInt32 rightint = PromiseFlatString(aRightString).ToInteger(&err);
|
||||
if (NS_SUCCEEDED(err)) {
|
||||
match = (mRelation == eLess) ? (leftint < rightint) :
|
||||
(leftint > rightint);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case eBefore:
|
||||
{
|
||||
nsICollation* collation = nsXULContentUtils::GetCollation();
|
||||
if (collation) {
|
||||
PRInt32 sortOrder;
|
||||
collation->CompareString((mIgnoreCase ?
|
||||
nsICollation::kCollationCaseInSensitive :
|
||||
nsICollation::kCollationCaseSensitive),
|
||||
aLeftString,
|
||||
aRightString,
|
||||
&sortOrder);
|
||||
match = (sortOrder < 0);
|
||||
}
|
||||
else if (mIgnoreCase) {
|
||||
match = (Compare(aLeftString, aRightString,
|
||||
nsCaseInsensitiveStringComparator()) < 0);
|
||||
}
|
||||
else {
|
||||
match = (Compare(aLeftString, aRightString) < 0);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case eAfter:
|
||||
{
|
||||
nsICollation* collation = nsXULContentUtils::GetCollation();
|
||||
if (collation) {
|
||||
PRInt32 sortOrder;
|
||||
collation->CompareString((mIgnoreCase ?
|
||||
nsICollation::kCollationCaseInSensitive :
|
||||
nsICollation::kCollationCaseSensitive),
|
||||
aLeftString,
|
||||
aRightString,
|
||||
&sortOrder);
|
||||
match = (sortOrder > 0);
|
||||
}
|
||||
else if (mIgnoreCase) {
|
||||
match = (Compare(aLeftString, aRightString,
|
||||
nsCaseInsensitiveStringComparator()) > 0);
|
||||
}
|
||||
else {
|
||||
match = (Compare(aLeftString, aRightString) > 0);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case eStartswith:
|
||||
if (mIgnoreCase)
|
||||
match = (StringBeginsWith(aLeftString, aRightString,
|
||||
nsCaseInsensitiveStringComparator()));
|
||||
else
|
||||
match = (StringBeginsWith(aLeftString, aRightString));
|
||||
break;
|
||||
|
||||
case eEndswith:
|
||||
if (mIgnoreCase)
|
||||
match = (StringEndsWith(aLeftString, aRightString,
|
||||
nsCaseInsensitiveStringComparator()));
|
||||
else
|
||||
match = (StringEndsWith(aLeftString, aRightString));
|
||||
break;
|
||||
|
||||
case eContains:
|
||||
{
|
||||
nsAString::const_iterator start, end;
|
||||
aLeftString.BeginReading(start);
|
||||
aLeftString.EndReading(end);
|
||||
if (mIgnoreCase)
|
||||
match = CaseInsensitiveFindInReadable(aRightString, start, end);
|
||||
else
|
||||
match = FindInReadable(aRightString, start, end);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (mNegate) match = !match;
|
||||
|
||||
return match;
|
||||
}
|
||||
|
||||
nsTemplateRule::nsTemplateRule(nsIContent* aRuleNode,
|
||||
nsIContent* aAction,
|
||||
nsTemplateQuerySet* aQuerySet)
|
||||
: mQuerySet(aQuerySet),
|
||||
mAction(aAction),
|
||||
mBindings(nsnull),
|
||||
mConditions(nsnull)
|
||||
{
|
||||
MOZ_COUNT_CTOR(nsTemplateRule);
|
||||
mRuleNode = do_QueryInterface(aRuleNode);
|
||||
}
|
||||
|
||||
nsTemplateRule::~nsTemplateRule()
|
||||
{
|
||||
|
@ -51,25 +306,72 @@ nsTemplateRule::~nsTemplateRule()
|
|||
mBindings = mBindings->mNext;
|
||||
delete doomed;
|
||||
}
|
||||
|
||||
while (mConditions) {
|
||||
nsTemplateCondition* cdel = mConditions;
|
||||
mConditions = mConditions->GetNext();
|
||||
delete cdel;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
nsresult
|
||||
nsTemplateRule::GetContent(nsIContent** aResult) const
|
||||
nsTemplateRule::GetAction(nsIContent** aAction) const
|
||||
{
|
||||
*aResult = mContent.get();
|
||||
NS_IF_ADDREF(*aResult);
|
||||
*aAction = mAction;
|
||||
NS_IF_ADDREF(*aAction);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsTemplateRule::GetRuleNode(nsIDOMNode** aRuleNode) const
|
||||
{
|
||||
*aRuleNode = mRuleNode;
|
||||
NS_IF_ADDREF(*aRuleNode);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void nsTemplateRule::SetCondition(nsTemplateCondition* aCondition)
|
||||
{
|
||||
while (mConditions) {
|
||||
nsTemplateCondition* cdel = mConditions;
|
||||
mConditions = mConditions->GetNext();
|
||||
delete cdel;
|
||||
}
|
||||
|
||||
mConditions = aCondition;
|
||||
}
|
||||
|
||||
PRBool
|
||||
nsTemplateRule::HasBinding(PRInt32 aSourceVariable,
|
||||
nsIRDFResource* aProperty,
|
||||
PRInt32 aTargetVariable) const
|
||||
nsTemplateRule::CheckMatch(nsIXULTemplateResult* aResult) const
|
||||
{
|
||||
// check the conditions in the rule first
|
||||
nsTemplateCondition* condition = mConditions;
|
||||
while (condition) {
|
||||
if (!condition->CheckMatch(aResult))
|
||||
return PR_FALSE;
|
||||
|
||||
condition = condition->GetNext();
|
||||
}
|
||||
|
||||
if (mRuleFilter) {
|
||||
// if a rule filter was set, check it for a match. If an error occurs,
|
||||
// assume that the match was acceptable
|
||||
PRBool match;
|
||||
nsresult rv = mRuleFilter->Match(aResult, mRuleNode, &match);
|
||||
return NS_FAILED(rv) || match;
|
||||
}
|
||||
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
PRBool
|
||||
nsTemplateRule::HasBinding(nsIAtom* aSourceVariable,
|
||||
nsAString& aExpr,
|
||||
nsIAtom* aTargetVariable) const
|
||||
{
|
||||
for (Binding* binding = mBindings; binding != nsnull; binding = binding->mNext) {
|
||||
if ((binding->mSourceVariable == aSourceVariable) &&
|
||||
(binding->mProperty == aProperty) &&
|
||||
(binding->mExpr.Equals(aExpr)) &&
|
||||
(binding->mTargetVariable == aTargetVariable))
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
@ -78,23 +380,19 @@ nsTemplateRule::HasBinding(PRInt32 aSourceVariable,
|
|||
}
|
||||
|
||||
nsresult
|
||||
nsTemplateRule::AddBinding(PRInt32 aSourceVariable,
|
||||
nsIRDFResource* aProperty,
|
||||
PRInt32 aTargetVariable)
|
||||
nsTemplateRule::AddBinding(nsIAtom* aSourceVariable,
|
||||
nsAString& aExpr,
|
||||
nsIAtom* aTargetVariable)
|
||||
{
|
||||
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),
|
||||
NS_ASSERTION(! HasBinding(aSourceVariable, aExpr, aTargetVariable),
|
||||
"binding added twice");
|
||||
|
||||
Binding* newbinding = new Binding;
|
||||
|
@ -102,10 +400,11 @@ nsTemplateRule::AddBinding(PRInt32 aSourceVariable,
|
|||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
newbinding->mSourceVariable = aSourceVariable;
|
||||
newbinding->mProperty = aProperty;
|
||||
newbinding->mTargetVariable = aTargetVariable;
|
||||
newbinding->mParent = nsnull;
|
||||
|
||||
newbinding->mExpr.Assign(aExpr);
|
||||
|
||||
Binding* binding = mBindings;
|
||||
Binding** link = &mBindings;
|
||||
|
||||
|
@ -137,215 +436,18 @@ nsTemplateRule::AddBinding(PRInt32 aSourceVariable,
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
PRBool
|
||||
nsTemplateRule::DependsOn(PRInt32 aChildVariable, PRInt32 aParentVariable) const
|
||||
{
|
||||
// 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;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
//
|
||||
// nsTemplateRule
|
||||
//
|
||||
|
||||
nsresult
|
||||
nsTemplateRule::InitBindings(nsConflictSet& aConflictSet, nsTemplateMatch* aMatch) const
|
||||
nsTemplateRule::AddBindingsToQueryProcessor(nsIXULTemplateQueryProcessor* aProcessor)
|
||||
{
|
||||
// Initialize a match's binding dependencies, so we can handle
|
||||
// updates and queries later.
|
||||
Binding* binding = mBindings;
|
||||
|
||||
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);
|
||||
while (binding) {
|
||||
nsresult rv = aProcessor->AddBinding(mRuleNode, binding->mTargetVariable,
|
||||
binding->mSourceVariable, binding->mExpr);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
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);
|
||||
}
|
||||
binding = binding->mNext;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsTemplateRule::RecomputeBindings(nsConflictSet& aConflictSet,
|
||||
nsTemplateMatch* aMatch,
|
||||
nsIRDFResource* aSource,
|
||||
nsIRDFResource* aProperty,
|
||||
nsIRDFNode* aOldTarget,
|
||||
nsIRDFNode* aNewTarget,
|
||||
VariableSet& aModifiedVars) const
|
||||
{
|
||||
// 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;
|
||||
}
|
||||
|
||||
PRBool
|
||||
nsTemplateRule::ComputeAssignmentFor(nsConflictSet& aConflictSet,
|
||||
nsTemplateMatch* aMatch,
|
||||
PRInt32 aVariable,
|
||||
Value* aValue) const
|
||||
{
|
||||
// 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;
|
||||
}
|
||||
|
|
|
@ -40,14 +40,84 @@
|
|||
#define nsTemplateRule_h__
|
||||
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsIAtom.h"
|
||||
#include "nsIRDFDataSource.h"
|
||||
#include "nsIRDFResource.h"
|
||||
#include "nsIContent.h"
|
||||
#include "nsIDOMNode.h"
|
||||
#include "nsVoidArray.h"
|
||||
#include "nsString.h"
|
||||
#include "nsIXULTemplateRuleFilter.h"
|
||||
|
||||
class nsConflictSet;
|
||||
class nsTemplateMatch;
|
||||
class Value;
|
||||
class VariableSet;
|
||||
class nsIXULTemplateQueryProcessor;
|
||||
class nsTemplateQuerySet;
|
||||
|
||||
class nsTemplateCondition
|
||||
{
|
||||
public:
|
||||
// relations that may be used in a rule. They may be negated with the
|
||||
// negate flag. Less and Greater are used for numeric comparisons and
|
||||
// Before and After are used for string comparisons. For Less, Greater,
|
||||
// Before, After, Startswith, Endswith, and Contains, the source is
|
||||
// conceptually on the left of the relation and the target is on the
|
||||
// right. For example, if the relation is Contains, that means Match if
|
||||
// the source contains the target.
|
||||
enum ConditionRelation {
|
||||
eUnknown,
|
||||
eEquals,
|
||||
eLess,
|
||||
eGreater,
|
||||
eBefore,
|
||||
eAfter,
|
||||
eStartswith,
|
||||
eEndswith,
|
||||
eContains
|
||||
};
|
||||
|
||||
nsTemplateCondition(nsIAtom* aSourceVariable,
|
||||
const nsAString& aRelation,
|
||||
nsIAtom* aTargetVariable,
|
||||
PRBool mIgnoreCase,
|
||||
PRBool mNegate);
|
||||
|
||||
nsTemplateCondition(nsIAtom* aSourceVariable,
|
||||
const nsAString& aRelation,
|
||||
const nsAString& aTargets,
|
||||
PRBool mIgnoreCase,
|
||||
PRBool mNegate,
|
||||
PRBool aIsMultiple);
|
||||
|
||||
nsTemplateCondition(const nsAString& aSource,
|
||||
const nsAString& aRelation,
|
||||
nsIAtom* aTargetVariable,
|
||||
PRBool mIgnoreCase,
|
||||
PRBool mNegate);
|
||||
|
||||
~nsTemplateCondition() { MOZ_COUNT_DTOR(nsTemplateCondition); }
|
||||
|
||||
nsTemplateCondition* GetNext() { return mNext; }
|
||||
void SetNext(nsTemplateCondition* aNext) { mNext = aNext; }
|
||||
|
||||
void SetRelation(const nsAString& aRelation);
|
||||
|
||||
PRBool
|
||||
CheckMatch(nsIXULTemplateResult* aResult);
|
||||
|
||||
PRBool
|
||||
CheckMatchStrings(const nsAString& aLeftString,
|
||||
const nsAString& aRightString);
|
||||
protected:
|
||||
|
||||
nsCOMPtr<nsIAtom> mSourceVariable;
|
||||
nsString mSource;
|
||||
ConditionRelation mRelation;
|
||||
nsCOMPtr<nsIAtom> mTargetVariable;
|
||||
nsStringArray mTargetList;
|
||||
PRPackedBool mIgnoreCase;
|
||||
PRPackedBool mNegate;
|
||||
|
||||
nsTemplateCondition* mNext;
|
||||
};
|
||||
|
||||
/**
|
||||
* A rule consists of:
|
||||
|
@ -64,85 +134,71 @@ class VariableSet;
|
|||
*
|
||||
* - Content that should be constructed when the rule is "activated".
|
||||
*
|
||||
* - Priority, which helps to determine which rule should be
|
||||
* considered "active" if several rules "match".
|
||||
*
|
||||
*/
|
||||
class nsTemplateRule
|
||||
{
|
||||
public:
|
||||
nsTemplateRule(nsIRDFDataSource* aDataSource,
|
||||
nsIContent* aContent,
|
||||
PRInt32 aPriority)
|
||||
: mDataSource(aDataSource),
|
||||
mContent(aContent),
|
||||
mContainerVariable(0),
|
||||
mMemberVariable(0),
|
||||
mPriority(aPriority),
|
||||
mCount(0),
|
||||
mCapacity(0),
|
||||
mBindings(nsnull)
|
||||
{ MOZ_COUNT_CTOR(nsTemplateRule); }
|
||||
nsTemplateRule(nsIContent* aRuleNode,
|
||||
nsIContent* aAction,
|
||||
nsTemplateQuerySet* aQuerySet);
|
||||
|
||||
~nsTemplateRule();
|
||||
|
||||
/**
|
||||
* Return the content node that this rule was constructed from.
|
||||
* @param aResult an out parameter, which will contain the content node
|
||||
* that this rule was constructed from
|
||||
* Return the <action> node that this rule was constructed from, or its
|
||||
* logical equivalent for shorthand syntaxes. That is, the parent node of
|
||||
* the content that should be generated for this rule.
|
||||
* @param aAction an out parameter, which will contain the content node
|
||||
* that this rule uses to generated content
|
||||
* @return NS_OK if no errors occur.
|
||||
*/
|
||||
nsresult GetContent(nsIContent** aResult) const;
|
||||
nsresult GetAction(nsIContent** aAction) const;
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* @param aContainerVariable the variable that should be used as the
|
||||
* "container variable" in this rule
|
||||
* Return the <rule> content node that this rule was constructed from.
|
||||
* @param aResult an out parameter, which will contain the rule node
|
||||
* @return NS_OK if no errors occur.
|
||||
*/
|
||||
void SetContainerVariable(PRInt32 aContainerVariable) {
|
||||
mContainerVariable = aContainerVariable; }
|
||||
nsresult GetRuleNode(nsIDOMNode** aResult) const;
|
||||
|
||||
void SetVars(nsIAtom* aRefVariable, nsIAtom* aMemberVariable)
|
||||
{
|
||||
mRefVariable = aRefVariable;
|
||||
mMemberVariable = aMemberVariable;
|
||||
}
|
||||
|
||||
void SetRuleFilter(nsIXULTemplateRuleFilter* aRuleFilter)
|
||||
{
|
||||
mRuleFilter = aRuleFilter;
|
||||
}
|
||||
|
||||
nsIAtom* GetTag() { return mTag; }
|
||||
void SetTag(nsIAtom* aTag) { mTag = aTag; }
|
||||
|
||||
nsIAtom* GetMemberVariable() { return mMemberVariable; }
|
||||
|
||||
/**
|
||||
* Retrieve the variable that this rule uses as its "container variable".
|
||||
* @return the variable that this rule uses as its "container variable".
|
||||
* Set the first condition for the rule. Other conditions are linked
|
||||
* to it using the condition's SetNext method.
|
||||
*/
|
||||
PRInt32 GetContainerVariable() const {
|
||||
return mContainerVariable; }
|
||||
void SetCondition(nsTemplateCondition* aConditions);
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* @param aMemberVariable the variable that should be used as the
|
||||
* "member variable" in this rule.
|
||||
* Check if the result matches the rule by first looking at the conditions.
|
||||
* If the results is accepted by the conditions, the rule filter, if any
|
||||
* was set, is checked. If either check rejects a result, a match cannot
|
||||
* occur for this rule and result.
|
||||
*/
|
||||
void SetMemberVariable(PRInt32 aMemberVariable) {
|
||||
mMemberVariable = aMemberVariable; }
|
||||
|
||||
/**
|
||||
* Retrieve the variable that this rule uses as its "member variable".
|
||||
* @return the variable that this rule uses as its "member variable"
|
||||
*/
|
||||
PRInt32 GetMemberVariable() const {
|
||||
return mMemberVariable; }
|
||||
|
||||
/**
|
||||
* Retrieve the "priority" of the rule with respect to the
|
||||
* other rules in the template
|
||||
* @return the rule's priority, lower values mean "use this first".
|
||||
*/
|
||||
PRInt32 GetPriority() const {
|
||||
return mPriority; }
|
||||
PRBool
|
||||
CheckMatch(nsIXULTemplateResult* aResult) const;
|
||||
|
||||
/**
|
||||
* Determine if the rule has the specified binding
|
||||
*/
|
||||
PRBool
|
||||
HasBinding(PRInt32 aSourceVariable,
|
||||
nsIRDFResource* aProperty,
|
||||
PRInt32 aTargetVariable) const;
|
||||
HasBinding(nsIAtom* aSourceVariable,
|
||||
nsAString& aExpr,
|
||||
nsIAtom* aTargetVariable) const;
|
||||
|
||||
/**
|
||||
* Add a binding to the rule. A binding consists of an already-bound
|
||||
|
@ -152,100 +208,128 @@ public:
|
|||
*
|
||||
* @param aSourceVariable the source variable that will be used in
|
||||
* the RDF query.
|
||||
* @param aProperty the RDF property that will be used in the RDF
|
||||
* query.
|
||||
* @param aExpr the expression that will be used in the query.
|
||||
* @param aTargetVariable the variable whose value will be bound
|
||||
* to the RDF node that is returned when querying the binding
|
||||
* @return NS_OK if no errors occur.
|
||||
*/
|
||||
nsresult AddBinding(PRInt32 aSourceVariable,
|
||||
nsIRDFResource* aProperty,
|
||||
PRInt32 aTargetVariable);
|
||||
nsresult AddBinding(nsIAtom* aSourceVariable,
|
||||
nsAString& aExpr,
|
||||
nsIAtom* aTargetVariable);
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* @param aConflictSet the conflict set
|
||||
* @param aMatch the match we to initialize
|
||||
* @return NS_OK if no errors occur.
|
||||
* Inform the query processor of the bindings that are set for a rule.
|
||||
* This should be called after all the bindings for a rule are compiled.
|
||||
*/
|
||||
nsresult InitBindings(nsConflictSet& aConflictSet, nsTemplateMatch* aMatch) 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.
|
||||
* @param aConflictSet the conflict set, which we may need to manipulate
|
||||
* to update the binding dependencies.
|
||||
* @param aMatch the match for which we must recompute the bindings
|
||||
* @param aSource the "source" resource in the RDF graph
|
||||
* @param aProperty the "property" resource in the RDF graph
|
||||
* @param aOldTarget the old "target" node in the RDF graph
|
||||
* @param aNewTarget the new "target" node in the RDF graph.
|
||||
* @param aModifiedVars a VariableSet, into which this routine
|
||||
* will assign each variable whose value has changed.
|
||||
* @return NS_OK if no errors occurred.
|
||||
*/
|
||||
nsresult RecomputeBindings(nsConflictSet& aConflictSet,
|
||||
nsTemplateMatch* aMatch,
|
||||
nsIRDFResource* aSource,
|
||||
nsIRDFResource* aProperty,
|
||||
nsIRDFNode* aOldTarget,
|
||||
nsIRDFNode* aNewTarget,
|
||||
VariableSet& aModifiedVars) 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.
|
||||
* @param aConflictSet the 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.
|
||||
* @param aMatch the match that provides the "seed" variable assignments,
|
||||
* which we may need to extend using the rule's bindings.
|
||||
* @param aVariable the variable for which we are to compute the
|
||||
* assignment.
|
||||
* @param aValue an out parameter that will receive the value that
|
||||
* was assigned to aVariable, if we could find one.
|
||||
* @return PR_TRUE if an assignment was found for aVariable, PR_FALSE
|
||||
* otherwise.
|
||||
*/
|
||||
PRBool ComputeAssignmentFor(nsConflictSet& aConflictSet,
|
||||
nsTemplateMatch* aMatch,
|
||||
PRInt32 aVariable,
|
||||
Value* aValue) const;
|
||||
|
||||
/**
|
||||
* Determine if one variable depends on another in the rule's
|
||||
* bindings.
|
||||
* @param aChild the dependent variable, whose value may
|
||||
* depend on the assignment of aParent.
|
||||
* @param aParent the variable whose value aChild is depending on.
|
||||
* @return PR_TRUE if aChild's assignment depends on the assignment
|
||||
* for aParent, PR_FALSE otherwise.
|
||||
*/
|
||||
PRBool DependsOn(PRInt32 aChild, PRInt32 aParent) const;
|
||||
nsresult
|
||||
AddBindingsToQueryProcessor(nsIXULTemplateQueryProcessor* aProcessor);
|
||||
|
||||
protected:
|
||||
nsCOMPtr<nsIRDFDataSource> mDataSource;
|
||||
nsCOMPtr<nsIContent> mContent;
|
||||
PRInt32 mContainerVariable;
|
||||
PRInt32 mMemberVariable;
|
||||
PRInt32 mPriority;
|
||||
|
||||
PRInt32 mCount;
|
||||
PRInt32 mCapacity;
|
||||
|
||||
struct Binding {
|
||||
PRInt32 mSourceVariable;
|
||||
nsCOMPtr<nsIRDFResource> mProperty;
|
||||
PRInt32 mTargetVariable;
|
||||
nsCOMPtr<nsIAtom> mSourceVariable;
|
||||
nsCOMPtr<nsIAtom> mTargetVariable;
|
||||
nsString mExpr;
|
||||
Binding* mNext;
|
||||
Binding* mParent;
|
||||
};
|
||||
|
||||
// backreference to the query set which owns this rule
|
||||
nsTemplateQuerySet* mQuerySet;
|
||||
|
||||
// the <rule> node, or the <template> node if there is no <rule>
|
||||
nsCOMPtr<nsIDOMNode> mRuleNode;
|
||||
|
||||
// the <action> node, or, if there is no <action>, the container node
|
||||
// which contains the content to generate
|
||||
nsCOMPtr<nsIContent> mAction;
|
||||
|
||||
// the rule filter set by the builder's SetRuleFilter function
|
||||
nsCOMPtr<nsIXULTemplateRuleFilter> mRuleFilter;
|
||||
|
||||
// indicates that the rule will only match when generating content
|
||||
// to be inserted into a container with this tag
|
||||
nsCOMPtr<nsIAtom> mTag;
|
||||
|
||||
// linked-list of the bindings for the rule, owned by the rule.
|
||||
Binding* mBindings;
|
||||
|
||||
nsCOMPtr<nsIAtom> mRefVariable;
|
||||
nsCOMPtr<nsIAtom> mMemberVariable;
|
||||
|
||||
nsTemplateCondition* mConditions; // owned by nsTemplateRule
|
||||
};
|
||||
|
||||
/** nsTemplateQuerySet
|
||||
*
|
||||
* A single <queryset> which holds the query node and the rules for it.
|
||||
* All builders have at least one queryset, which may be created with an
|
||||
* explicit <queryset> tag or implied if the tag is not used.
|
||||
*
|
||||
* These queryset objects are created and owned by the builder in its
|
||||
* mQuerySets array.
|
||||
*/
|
||||
class nsTemplateQuerySet
|
||||
{
|
||||
protected:
|
||||
nsVoidArray mRules; // rules owned by nsTemplateQuerySet
|
||||
|
||||
// a number which increments for each successive queryset. It is stored so
|
||||
// it can be used as an optimization when updating results so that it is
|
||||
// known where to insert them into a match.
|
||||
PRInt32 mPriority;
|
||||
|
||||
public:
|
||||
|
||||
// <query> node
|
||||
nsCOMPtr<nsIContent> mQueryNode;
|
||||
|
||||
// compiled opaque query object returned by the query processor's
|
||||
// CompileQuery call
|
||||
nsCOMPtr<nsISupports> mCompiledQuery;
|
||||
|
||||
nsTemplateQuerySet(PRInt32 aPriority)
|
||||
: mPriority(aPriority)
|
||||
{
|
||||
MOZ_COUNT_CTOR(nsTemplateQuerySet);
|
||||
}
|
||||
|
||||
~nsTemplateQuerySet()
|
||||
{
|
||||
MOZ_COUNT_DTOR(nsTemplateQuerySet);
|
||||
Clear();
|
||||
}
|
||||
|
||||
PRInt32 Priority() const
|
||||
{
|
||||
return mPriority;
|
||||
}
|
||||
|
||||
nsresult AddRule(nsTemplateRule *aChild)
|
||||
{
|
||||
if (!mRules.AppendElement(aChild))
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
PRInt32 RuleCount() const
|
||||
{
|
||||
return mRules.Count();
|
||||
}
|
||||
|
||||
nsTemplateRule* GetRuleAt(PRInt32 aIndex)
|
||||
{
|
||||
return NS_STATIC_CAST(nsTemplateRule*, mRules[aIndex]);
|
||||
}
|
||||
|
||||
void Clear()
|
||||
{
|
||||
for (PRInt32 r = mRules.Count() - 1; r >= 0; r--) {
|
||||
nsTemplateRule* rule = NS_STATIC_CAST(nsTemplateRule* , mRules[r]);
|
||||
delete rule;
|
||||
}
|
||||
mRules.Clear();
|
||||
}
|
||||
};
|
||||
|
||||
#endif // nsTemplateRule_h__
|
||||
|
|
|
@ -36,13 +36,12 @@
|
|||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include "nsString.h"
|
||||
#include "nsTreeRows.h"
|
||||
#include "nsTemplateMatch.h"
|
||||
#include "nsTemplateRule.h"
|
||||
|
||||
nsTreeRows::Subtree*
|
||||
nsTreeRows::EnsureSubtreeFor(Subtree* aParent,
|
||||
PRInt32 aChildIndex)
|
||||
PRInt32 aChildIndex)
|
||||
{
|
||||
Subtree* subtree = GetSubtreeFor(aParent, aChildIndex);
|
||||
|
||||
|
@ -174,20 +173,59 @@ nsTreeRows::operator[](PRInt32 aRow)
|
|||
}
|
||||
|
||||
nsTreeRows::iterator
|
||||
nsTreeRows::Find(nsConflictSet& aConflictSet, nsIRDFResource* aMember)
|
||||
nsTreeRows::FindByResource(nsIRDFResource* aResource)
|
||||
{
|
||||
// XXX Mmm, scan through the rows one-by-one...
|
||||
iterator last = Last();
|
||||
iterator iter;
|
||||
|
||||
nsresult rv;
|
||||
nsAutoString resourceid;
|
||||
PRBool stringmode = PR_FALSE;
|
||||
|
||||
for (iter = First(); iter != last; ++iter) {
|
||||
if (!stringmode) {
|
||||
nsCOMPtr<nsIRDFResource> findres;
|
||||
rv = iter->mMatch->mResult->GetResource(getter_AddRefs(findres));
|
||||
if (NS_FAILED(rv)) return last;
|
||||
|
||||
if (findres == aResource)
|
||||
break;
|
||||
|
||||
if (! findres) {
|
||||
const char *uri;
|
||||
aResource->GetValueConst(&uri);
|
||||
CopyUTF8toUTF16(uri, resourceid);
|
||||
|
||||
// set stringmode and fall through
|
||||
stringmode = PR_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
// additional check because previous block could change stringmode
|
||||
if (stringmode) {
|
||||
nsAutoString findid;
|
||||
rv = iter->mMatch->mResult->GetId(findid);
|
||||
if (NS_FAILED(rv)) return last;
|
||||
|
||||
if (resourceid.Equals(findid))
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return iter;
|
||||
}
|
||||
|
||||
nsTreeRows::iterator
|
||||
nsTreeRows::Find(nsIXULTemplateResult *aResult)
|
||||
{
|
||||
// XXX Mmm, scan through the rows one-by-one...
|
||||
iterator last = Last();
|
||||
iterator iter;
|
||||
|
||||
for (iter = First(); iter != last; ++iter) {
|
||||
nsTemplateMatch* match = iter->mMatch;
|
||||
|
||||
Value val;
|
||||
match->GetAssignmentFor(aConflictSet, match->mRule->GetMemberVariable(), &val);
|
||||
|
||||
if (VALUE_TO_IRDFRESOURCE(val) == aMember)
|
||||
break;
|
||||
if (aResult == iter->mMatch->mResult)
|
||||
break;
|
||||
}
|
||||
|
||||
return iter;
|
||||
|
|
|
@ -40,10 +40,11 @@
|
|||
#define nsTreeRows_h__
|
||||
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsIRDFResource.h"
|
||||
#include "pldhash.h"
|
||||
class nsConflictSet;
|
||||
class nsTemplateMatch;
|
||||
#include "nsIXULTemplateResult.h"
|
||||
#include "nsTemplateMatch.h"
|
||||
#include "nsIRDFResource.h"
|
||||
|
||||
|
||||
/**
|
||||
* This class maintains the state of the XUL tree builder's
|
||||
|
@ -311,17 +312,21 @@ public:
|
|||
iterator Last();
|
||||
|
||||
/**
|
||||
* Find the row that contains the match with the specified member
|
||||
* resource.
|
||||
* Find the row that contains the given resource
|
||||
*/
|
||||
iterator Find(nsConflictSet& aConflictSet, nsIRDFResource* aMember);
|
||||
iterator FindByResource(nsIRDFResource* aResource);
|
||||
|
||||
/**
|
||||
* Find the row that contains the result
|
||||
*/
|
||||
iterator Find(nsIXULTemplateResult* aResult);
|
||||
|
||||
/**
|
||||
* Retrieve the ith element in the view
|
||||
*/
|
||||
iterator operator[](PRInt32 aIndex);
|
||||
|
||||
nsTreeRows() : mRoot(nsnull), mRootResource(nsnull) {}
|
||||
nsTreeRows() : mRoot(nsnull) {}
|
||||
~nsTreeRows() {}
|
||||
|
||||
/**
|
||||
|
@ -431,7 +436,7 @@ public:
|
|||
mRootResource = aResource; }
|
||||
|
||||
/**
|
||||
* Retrieve hte root resource for the view
|
||||
* Retrieve the root resource for the view
|
||||
*/
|
||||
nsIRDFResource* GetRootResource() {
|
||||
return mRootResource.get(); }
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -86,16 +86,22 @@
|
|||
#include "nsIDateTimeFormat.h"
|
||||
#include "nsDateTimeFormatCID.h"
|
||||
#include "nsIScriptableDateFormat.h"
|
||||
|
||||
#include "nsICollation.h"
|
||||
#include "nsCollationCID.h"
|
||||
#include "nsILocale.h"
|
||||
#include "nsILocaleService.h"
|
||||
|
||||
static NS_DEFINE_CID(kDateTimeFormatCID, NS_DATETIMEFORMAT_CID);
|
||||
static NS_DEFINE_CID(kRDFServiceCID, NS_RDFSERVICE_CID);
|
||||
static NS_DEFINE_CID(kCollationFactoryCID, NS_COLLATIONFACTORY_CID);
|
||||
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
|
||||
nsrefcnt nsXULContentUtils::gRefCnt;
|
||||
nsIRDFService* nsXULContentUtils::gRDF;
|
||||
nsIDateTimeFormat* nsXULContentUtils::gFormat;
|
||||
nsICollation *nsXULContentUtils::gCollation;
|
||||
|
||||
#define XUL_RESOURCE(ident, uri) nsIRDFResource* nsXULContentUtils::ident
|
||||
#define XUL_LITERAL(ident, val) nsIRDFLiteral* nsXULContentUtils::ident
|
||||
|
@ -136,6 +142,26 @@ nsXULContentUtils::Init()
|
|||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
// get a locale service
|
||||
nsCOMPtr<nsILocaleService> localeService =
|
||||
do_GetService(NS_LOCALESERVICE_CONTRACTID, &rv);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
nsCOMPtr<nsILocale> locale;
|
||||
rv = localeService->GetApplicationLocale(getter_AddRefs(locale));
|
||||
if (NS_SUCCEEDED(rv) && locale) {
|
||||
nsCOMPtr<nsICollationFactory> colFactory =
|
||||
do_CreateInstance(kCollationFactoryCID);
|
||||
if (colFactory) {
|
||||
rv = colFactory->CreateCollation(locale, &gCollation);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv),
|
||||
"couldn't create collation instance");
|
||||
} else
|
||||
NS_ERROR("couldn't create instance of collation factory");
|
||||
} else
|
||||
NS_ERROR("unable to get application locale");
|
||||
} else
|
||||
NS_ERROR("couldn't get locale factory");
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
|
@ -155,6 +181,7 @@ nsXULContentUtils::Finish()
|
|||
#undef XUL_LITERAL
|
||||
|
||||
NS_IF_RELEASE(gFormat);
|
||||
NS_IF_RELEASE(gCollation);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
|
@ -215,42 +242,6 @@ nsXULContentUtils::GetElementResource(nsIContent* aElement, nsIRDFResource** aRe
|
|||
}
|
||||
|
||||
|
||||
nsresult
|
||||
nsXULContentUtils::GetElementRefResource(nsIContent* aElement, nsIRDFResource** aResult)
|
||||
{
|
||||
*aResult = nsnull;
|
||||
// Perform a reverse mapping from an element in the content model
|
||||
// to an RDF resource. Check for a "ref" attribute first, then
|
||||
// fallback on an "id" attribute.
|
||||
nsresult rv;
|
||||
PRUnichar buf[128];
|
||||
nsFixedString uri(buf, NS_ARRAY_LENGTH(buf), 0);
|
||||
|
||||
aElement->GetAttr(kNameSpaceID_None, nsXULAtoms::ref, uri);
|
||||
if (!uri.IsEmpty()) {
|
||||
// We'll use rdf_MakeAbsolute() to translate this to a URL.
|
||||
nsCOMPtr<nsIDocument> doc = aElement->GetDocument();
|
||||
|
||||
nsIURI *url = doc->GetDocumentURI();
|
||||
NS_ASSERTION(url != nsnull, "element has no document");
|
||||
if (! url)
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
|
||||
// N.B. that if this fails (e.g., because necko doesn't grok
|
||||
// the protocol), uriStr will be untouched.
|
||||
NS_MakeAbsoluteURI(uri, uri, url);
|
||||
|
||||
rv = gRDF->GetUnicodeResource(uri, aResult);
|
||||
}
|
||||
else {
|
||||
rv = GetElementResource(aElement, aResult);
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
Note: this routine is similar, yet distinctly different from, nsBookmarksService::GetTextForNode
|
||||
*/
|
||||
|
@ -511,5 +502,3 @@ nsXULContentUtils::SetCommandUpdater(nsIDocument* aDocument, nsIContent* aElemen
|
|||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -59,6 +59,7 @@ class nsIRDFLiteral;
|
|||
class nsIRDFService;
|
||||
class nsINameSpaceManager;
|
||||
class nsIDateTimeFormat;
|
||||
class nsICollation;
|
||||
|
||||
class nsXULContentUtils
|
||||
{
|
||||
|
@ -66,6 +67,7 @@ protected:
|
|||
static nsrefcnt gRefCnt;
|
||||
static nsIRDFService* gRDF;
|
||||
static nsIDateTimeFormat* gFormat;
|
||||
static nsICollation *gCollation;
|
||||
|
||||
static PRBool gDisableXULCache;
|
||||
|
||||
|
@ -93,9 +95,6 @@ public:
|
|||
static nsresult
|
||||
GetElementResource(nsIContent* aElement, nsIRDFResource** aResult);
|
||||
|
||||
static nsresult
|
||||
GetElementRefResource(nsIContent* aElement, nsIRDFResource** aResult);
|
||||
|
||||
static nsresult
|
||||
GetTextForNode(nsIRDFNode* aNode, nsAString& aResult);
|
||||
|
||||
|
@ -123,6 +122,12 @@ public:
|
|||
return gRDF;
|
||||
}
|
||||
|
||||
static nsICollation*
|
||||
GetCollation()
|
||||
{
|
||||
return gCollation;
|
||||
}
|
||||
|
||||
#define XUL_RESOURCE(ident, uri) static nsIRDFResource* ident
|
||||
#define XUL_LITERAL(ident, val) static nsIRDFLiteral* ident
|
||||
#include "nsXULResourceList.h"
|
||||
|
@ -130,6 +135,4 @@ public:
|
|||
#undef XUL_LITERAL
|
||||
};
|
||||
|
||||
|
||||
#endif // nsXULContentUtils_h__
|
||||
|
||||
|
|
|
@ -82,7 +82,6 @@
|
|||
#include "nsIXULSortService.h"
|
||||
#include "prlog.h"
|
||||
#include "nsICollation.h"
|
||||
#include "nsCollationCID.h"
|
||||
#include "nsLayoutCID.h"
|
||||
#include "nsIDOMXULElement.h"
|
||||
#include "nsILocale.h"
|
||||
|
@ -95,7 +94,6 @@
|
|||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static NS_DEFINE_CID(kRDFServiceCID, NS_RDFSERVICE_CID);
|
||||
static NS_DEFINE_CID(kCollationFactoryCID, NS_COLLATIONFACTORY_CID);
|
||||
static NS_DEFINE_CID(kRDFInMemoryDataSourceCID, NS_RDFINMEMORYDATASOURCE_CID);
|
||||
static NS_DEFINE_CID(kRDFContainerUtilsCID, NS_RDFCONTAINERUTILS_CID);
|
||||
|
||||
|
@ -149,8 +147,6 @@ protected:
|
|||
XULSortServiceImpl(void);
|
||||
virtual ~XULSortServiceImpl(void);
|
||||
|
||||
static nsICollation *gCollation;
|
||||
|
||||
friend nsresult NS_NewXULSortService(nsIXULSortService** mgr);
|
||||
|
||||
private:
|
||||
|
@ -193,7 +189,6 @@ public:
|
|||
PRBool &bothValid, PRInt32 & sortOrder);
|
||||
};
|
||||
|
||||
nsICollation *XULSortServiceImpl::gCollation = nsnull;
|
||||
nsIRDFService *XULSortServiceImpl::gRDFService = nsnull;
|
||||
nsIRDFContainerUtils *XULSortServiceImpl::gRDFC = nsnull;
|
||||
nsrefcnt XULSortServiceImpl::gRefCnt = 0;
|
||||
|
@ -220,23 +215,6 @@ XULSortServiceImpl::XULSortServiceImpl(void)
|
|||
rv = CallGetService(kRDFContainerUtilsCID, &gRDFC);
|
||||
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "couldn't create rdf container utils");
|
||||
|
||||
// get a locale service
|
||||
nsCOMPtr<nsILocaleService> localeService = do_GetService(NS_LOCALESERVICE_CONTRACTID, &rv);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
nsCOMPtr<nsILocale> locale;
|
||||
if (NS_SUCCEEDED(rv = localeService->GetApplicationLocale(getter_AddRefs(locale))) && (locale)) {
|
||||
nsCOMPtr<nsICollationFactory> colFactory = do_CreateInstance(kCollationFactoryCID);
|
||||
if (colFactory) {
|
||||
rv = colFactory->CreateCollation(locale, &gCollation);
|
||||
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "couldn't create collation instance");
|
||||
} else
|
||||
NS_ERROR("couldn't create instance of collation factory");
|
||||
} else
|
||||
NS_ERROR("unable to get application locale");
|
||||
} else
|
||||
NS_ERROR("couldn't get locale factory");
|
||||
}
|
||||
|
||||
++gRefCnt;
|
||||
|
@ -259,8 +237,6 @@ XULSortServiceImpl::~XULSortServiceImpl(void) {
|
|||
delete kNaturalStr;
|
||||
kNaturalStr = nsnull;
|
||||
|
||||
NS_IF_RELEASE(gCollation);
|
||||
|
||||
NS_IF_RELEASE(gRDFService);
|
||||
NS_IF_RELEASE(gRDFC);
|
||||
}
|
||||
|
@ -462,8 +438,10 @@ XULSortServiceImpl::CompareNodes(nsIRDFNode *cellNode1, PRBool isCollationKey1,
|
|||
r->GetValue(&rkey);
|
||||
r->GetLength(&rlen);
|
||||
bothValid = PR_TRUE;
|
||||
if (gCollation)
|
||||
return gCollation->CompareRawSortKey(lkey, llen, rkey, rlen, &sortOrder);
|
||||
|
||||
nsICollation* collation = nsXULContentUtils::GetCollation();
|
||||
if (collation)
|
||||
return collation->CompareRawSortKey(lkey, llen, rkey, rlen, &sortOrder);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -481,18 +459,21 @@ XULSortServiceImpl::CompareNodes(nsIRDFNode *cellNode1, PRBool isCollationKey1,
|
|||
l->GetValueConst(&luni);
|
||||
r->GetValueConst(&runi);
|
||||
bothValid = PR_TRUE;
|
||||
if (isCollationKey1 && isCollationKey2)
|
||||
return gCollation->CompareRawSortKey(NS_REINTERPRET_CAST(const PRUint8*, luni),
|
||||
|
||||
nsICollation* collation = nsXULContentUtils::GetCollation();
|
||||
if (collation && isCollationKey1 && isCollationKey2) {
|
||||
return collation->CompareRawSortKey(NS_REINTERPRET_CAST(const PRUint8*, luni),
|
||||
nsCRT::strlen(luni)*sizeof(PRUnichar),
|
||||
NS_REINTERPRET_CAST(const PRUint8*, runi),
|
||||
nsCRT::strlen(runi)*sizeof(PRUnichar),
|
||||
&sortOrder);
|
||||
}
|
||||
else
|
||||
{
|
||||
nsresult rv = NS_ERROR_FAILURE;
|
||||
nsDependentString lstr(luni), rstr(runi);
|
||||
if (gCollation)
|
||||
rv = gCollation->CompareString(nsICollation::kCollationCaseInSensitive, lstr, rstr, &sortOrder);
|
||||
if (collation)
|
||||
rv = collation->CompareString(nsICollation::kCollationCaseInSensitive, lstr, rstr, &sortOrder);
|
||||
if (NS_FAILED(rv))
|
||||
sortOrder = Compare(lstr, rstr, nsCaseInsensitiveStringComparator());
|
||||
return NS_OK;
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -24,6 +24,7 @@
|
|||
* David Hyatt <hyatt@netscape.com>
|
||||
* Chris Waterson <waterson@netscape.com>
|
||||
* Pierre Phaneuf <pp@ludusdesign.com>
|
||||
* Neil Deakin <enndeakin@sympatico.ca>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
|
@ -44,6 +45,7 @@
|
|||
|
||||
#include "nsStubDocumentObserver.h"
|
||||
#include "nsIScriptSecurityManager.h"
|
||||
#include "nsIContent.h"
|
||||
#include "nsIRDFCompositeDataSource.h"
|
||||
#include "nsIRDFContainer.h"
|
||||
#include "nsIRDFContainerUtils.h"
|
||||
|
@ -52,21 +54,20 @@
|
|||
#include "nsIRDFService.h"
|
||||
#include "nsIXULTemplateBuilder.h"
|
||||
|
||||
#include "nsConflictSet.h"
|
||||
#include "nsFixedSizeAllocator.h"
|
||||
#include "nsResourceSet.h"
|
||||
#include "nsRuleNetwork.h"
|
||||
#include "nsVoidArray.h"
|
||||
#include "nsCOMArray.h"
|
||||
#include "nsTArray.h"
|
||||
#include "nsDataHashtable.h"
|
||||
#include "nsTemplateRule.h"
|
||||
#include "nsTemplateMatch.h"
|
||||
#include "nsIXULTemplateQueryProcessor.h"
|
||||
|
||||
#include "prlog.h"
|
||||
#ifdef PR_LOGGING
|
||||
extern PRLogModuleInfo* gXULTemplateLog;
|
||||
#endif
|
||||
|
||||
class nsClusterKeySet;
|
||||
class nsTemplateMatch;
|
||||
class nsTemplateRule;
|
||||
class nsIXULDocument;
|
||||
class nsIRDFCompositeDataSource;
|
||||
|
||||
|
@ -75,14 +76,19 @@ class nsIRDFCompositeDataSource;
|
|||
* set of rules.
|
||||
*/
|
||||
class nsXULTemplateBuilder : public nsIXULTemplateBuilder,
|
||||
public nsStubDocumentObserver,
|
||||
public nsIRDFObserver
|
||||
public nsStubDocumentObserver
|
||||
{
|
||||
public:
|
||||
nsXULTemplateBuilder();
|
||||
virtual ~nsXULTemplateBuilder();
|
||||
|
||||
nsresult Init();
|
||||
nsresult InitGlobals();
|
||||
|
||||
/**
|
||||
* Clear the template builder structures. The aIsFinal flag is set to true
|
||||
* when the template is going away.
|
||||
*/
|
||||
virtual void Uninit(PRBool aIsFinal);
|
||||
|
||||
// nsISupports interface
|
||||
NS_DECL_ISUPPORTS
|
||||
|
@ -96,8 +102,10 @@ public:
|
|||
PRInt32 aModType);
|
||||
virtual void DocumentWillBeDestroyed(nsIDocument *aDocument);
|
||||
|
||||
// nsIRDFObserver interface
|
||||
NS_DECL_NSIRDFOBSERVER
|
||||
nsresult
|
||||
UpdateResult(nsIXULTemplateResult* aOldResult,
|
||||
nsIXULTemplateResult* aNewResult,
|
||||
nsIDOMNode* aQueryNode);
|
||||
|
||||
nsresult
|
||||
ComputeContainmentProperties();
|
||||
|
@ -105,19 +113,6 @@ public:
|
|||
static PRBool
|
||||
IsTemplateElement(nsIContent* aContent);
|
||||
|
||||
/**
|
||||
* Initialize the rule network.
|
||||
*/
|
||||
virtual nsresult
|
||||
InitializeRuleNetwork();
|
||||
|
||||
/**
|
||||
* Initialize the rule network for handling rules that use the
|
||||
* ``simple'' syntax.
|
||||
*/
|
||||
virtual nsresult
|
||||
InitializeRuleNetworkForSimpleRules(InnerNode** aChildNode) = 0;
|
||||
|
||||
virtual nsresult
|
||||
RebuildAll() = 0; // must be implemented by subclasses
|
||||
|
||||
|
@ -128,60 +123,100 @@ public:
|
|||
GetTemplateRoot(nsIContent** aResult);
|
||||
|
||||
/**
|
||||
* Compile the template's rules
|
||||
* Compile the template's queries
|
||||
*/
|
||||
nsresult
|
||||
CompileRules();
|
||||
CompileQueries();
|
||||
|
||||
/**
|
||||
* Compile a rule that's specified using the extended template
|
||||
* syntax.
|
||||
* Compile the template given a <template> in aTemplate. This function
|
||||
* is called recursively to handle queries inside a queryset. For the
|
||||
* outer pass, aIsQuerySet will be false, while the inner pass this will
|
||||
* be true.
|
||||
*
|
||||
* aCanUseTemplate will be set to true if the template's queries could be
|
||||
* compiled, and false otherwise. If false, the entire template is
|
||||
* invalid.
|
||||
*
|
||||
* @param aTemplate <template> to compile
|
||||
* @param aQuerySet first queryset
|
||||
* @param aIsQuerySet true if
|
||||
* @param aPriority the queryset index, incremented when a new one is added
|
||||
* @param aCanUseTemplate true if template is valid
|
||||
*/
|
||||
nsresult
|
||||
CompileExtendedRule(nsIContent* aRuleElement,
|
||||
PRInt32 aPriority,
|
||||
InnerNode* aParentNode);
|
||||
CompileTemplate(nsIContent* aTemplate,
|
||||
nsTemplateQuerySet* aQuerySet,
|
||||
PRBool aIsQuerySet,
|
||||
PRInt32* aPriority,
|
||||
PRBool* aCanUseTemplate);
|
||||
|
||||
/**
|
||||
* Compile the <conditions> of a rule that uses the extended
|
||||
* template syntax.
|
||||
* Compile a query using the extended syntax. For backwards compatible RDF
|
||||
* syntax where there is no <query>, the <conditions> becomes the query.
|
||||
*
|
||||
* @param aRuleElement <rule> element
|
||||
* @param aActionElement <action> element
|
||||
* @param aMemberVariable member variable for the query
|
||||
* @param aTag tag specified in <content> element
|
||||
* @param aQuerySet the queryset
|
||||
*/
|
||||
nsresult
|
||||
CompileExtendedQuery(nsIContent* aRuleElement,
|
||||
nsIContent* aActionElement,
|
||||
nsIAtom* aMemberVariable,
|
||||
nsIAtom* aTag,
|
||||
nsTemplateQuerySet* aQuerySet);
|
||||
|
||||
/**
|
||||
* Determine the ref variable and tag from inside a RDF query.
|
||||
*/
|
||||
void DetermineRDFQueryRef(nsIContent* aQueryElement, nsIAtom** tag);
|
||||
|
||||
/**
|
||||
* Determine the member variable from inside an action body. It will be
|
||||
* the value of the uri attribute on a node.
|
||||
*/
|
||||
nsresult
|
||||
CompileConditions(nsTemplateRule* aRule,
|
||||
nsIContent* aConditions,
|
||||
InnerNode* aParentNode,
|
||||
InnerNode** aLastNode);
|
||||
DetermineMemberVariable(nsIContent* aActionElement, nsIAtom** aMemberVariable);
|
||||
|
||||
/**
|
||||
* Compile a single condition from an extended template syntax
|
||||
* rule. Subclasses may override to provide additional,
|
||||
* subclass-specific condition processing.
|
||||
* Compile a simple query. A simple query is one that doesn't have a
|
||||
* <query> and should use a default query which would normally just return
|
||||
* a list of children of the reference point.
|
||||
*
|
||||
* @param aRuleElement the <rule>
|
||||
* @param aQuerySet the query set
|
||||
* @param aCanUseTemplate true if the query is valid
|
||||
*/
|
||||
virtual nsresult
|
||||
CompileCondition(nsIAtom* aTag,
|
||||
nsTemplateRule* aRule,
|
||||
nsIContent* aConditions,
|
||||
InnerNode* aParentNode,
|
||||
TestNode** aResult);
|
||||
nsresult
|
||||
CompileSimpleQuery(nsIContent* aRuleElement,
|
||||
nsTemplateQuerySet* aQuerySet,
|
||||
PRBool* aCanUseTemplate);
|
||||
|
||||
/**
|
||||
* Compile a <triple> condition
|
||||
* Compile the <conditions> tag in a rule
|
||||
*
|
||||
* @param aRule template rule
|
||||
* @param aConditions <conditions> element
|
||||
*/
|
||||
nsresult
|
||||
CompileTripleCondition(nsTemplateRule* aRule,
|
||||
nsIContent* aCondition,
|
||||
InnerNode* aParentNode,
|
||||
TestNode** aResult);
|
||||
CompileConditions(nsTemplateRule* aRule, nsIContent* aConditions);
|
||||
|
||||
/**
|
||||
* Compile a <member> condition
|
||||
* Compile a <where> tag in a condition. The caller should set
|
||||
* *aCurrentCondition to null for the first condition. This value will be
|
||||
* updated to point to the new condition before returning. The conditions
|
||||
* will be added to the rule aRule by this method.
|
||||
*
|
||||
* @param aRule template rule
|
||||
* @param aCondition <where> element
|
||||
* @param aCurrentCondition compiled condition
|
||||
*/
|
||||
nsresult
|
||||
CompileMemberCondition(nsTemplateRule* aRule,
|
||||
nsIContent* aCondition,
|
||||
InnerNode* aParentNode,
|
||||
TestNode** aResult);
|
||||
|
||||
CompileWhereCondition(nsTemplateRule* aRule,
|
||||
nsIContent* aCondition,
|
||||
nsTemplateCondition** aCurrentCondition);
|
||||
|
||||
/**
|
||||
* Compile the <bindings> for an extended template syntax rule.
|
||||
|
@ -195,33 +230,6 @@ public:
|
|||
nsresult
|
||||
CompileBinding(nsTemplateRule* aRule, nsIContent* aBinding);
|
||||
|
||||
/**
|
||||
* Compile a rule that's specified using the simple template
|
||||
* syntax.
|
||||
*/
|
||||
nsresult
|
||||
CompileSimpleRule(nsIContent* aRuleElement, PRInt32 aPriorty, InnerNode* aParentNode);
|
||||
|
||||
/**
|
||||
* Can be overridden by subclasses to handle special attribute conditions
|
||||
* for the simple syntax.
|
||||
* @return PR_TRUE if the condition was handled
|
||||
*/
|
||||
virtual PRBool
|
||||
CompileSimpleAttributeCondition(PRInt32 aNameSpaceID,
|
||||
nsIAtom* aAttribute,
|
||||
const nsAString& aValue,
|
||||
InnerNode* aParentNode,
|
||||
TestNode** aResult);
|
||||
|
||||
/**
|
||||
* Parse the value of a property test assertion for a condition or a simple
|
||||
* rule based on the parseType attribute into the appropriate literal type.
|
||||
*/
|
||||
nsresult ParseLiteral(const nsString& aParseType,
|
||||
const nsString& aValue,
|
||||
nsIRDFNode** aResult);
|
||||
|
||||
/**
|
||||
* Add automatic bindings for simple rules
|
||||
*/
|
||||
|
@ -233,6 +241,38 @@ public:
|
|||
const nsAString& aVariable,
|
||||
void* aClosure);
|
||||
|
||||
nsresult
|
||||
LoadDataSources(nsIDocument* aDoc);
|
||||
|
||||
nsresult
|
||||
InitHTMLTemplateRoot();
|
||||
|
||||
/**
|
||||
* Determine which rule matches a given result. aContainer is used for
|
||||
* tag matching and is optional for non-content generating builders.
|
||||
* The returned matched rule is always one of the rules owned by the
|
||||
* query set aQuerySet.
|
||||
*
|
||||
* @param aContainer parent when generated content will be inserted
|
||||
* @param aResult result to match
|
||||
* @param aQuerySet query set to examine the rules of
|
||||
* @param aMatchedRule [out] rule that has matched, or null if any.
|
||||
*/
|
||||
nsresult
|
||||
DetermineMatchedRule(nsIContent* aContainer,
|
||||
nsIXULTemplateResult* aResult,
|
||||
nsTemplateQuerySet* aQuerySet,
|
||||
nsTemplateRule** aMatchedRule);
|
||||
|
||||
/**
|
||||
* Return true if the supplied content or the content generated from the
|
||||
* result has the given tag.
|
||||
*/
|
||||
PRBool
|
||||
MatchTagForResult(nsIContent* aContent,
|
||||
nsIXULTemplateResult* aResult,
|
||||
nsIAtom* aTag);
|
||||
|
||||
// XXX sigh, the string template foo doesn't mix with
|
||||
// operator->*() on egcs-1.1.2, so we'll need to explicitly pass
|
||||
// "this" and use good ol' fashioned static callbacks.
|
||||
|
@ -243,13 +283,7 @@ public:
|
|||
void* aClosure);
|
||||
|
||||
nsresult
|
||||
LoadDataSources(nsIDocument* aDoc);
|
||||
|
||||
nsresult
|
||||
InitHTMLTemplateRoot();
|
||||
|
||||
nsresult
|
||||
SubstituteText(nsTemplateMatch& aMatch,
|
||||
SubstituteText(nsIXULTemplateResult* aMatch,
|
||||
const nsAString& aAttributeValue,
|
||||
nsAString& aResult);
|
||||
|
||||
|
@ -259,81 +293,71 @@ public:
|
|||
static void
|
||||
SubstituteTextReplaceVariable(nsXULTemplateBuilder* aThis, const nsAString& aVariable, void* aClosure);
|
||||
|
||||
PRBool
|
||||
IsAttrImpactedByVars(nsTemplateMatch& aMatch,
|
||||
const nsAString& aAttributeValue,
|
||||
const VariableSet& aModifiedVars);
|
||||
|
||||
static void
|
||||
IsVarInSet(nsXULTemplateBuilder* aThis, const nsAString& aVariable, void* aClosure);
|
||||
|
||||
nsresult
|
||||
SynchronizeAll(nsIRDFResource* aSource,
|
||||
nsIRDFResource* aProperty,
|
||||
nsIRDFNode* aOldTarget,
|
||||
nsIRDFNode* aNewTarget);
|
||||
|
||||
nsresult
|
||||
Propagate(nsIRDFResource* aSource,
|
||||
nsIRDFResource* aProperty,
|
||||
nsIRDFNode* aTarget,
|
||||
nsClusterKeySet& aNewKeys);
|
||||
|
||||
nsresult
|
||||
FireNewlyMatchedRules(const nsClusterKeySet& aNewKeys);
|
||||
|
||||
nsresult
|
||||
Retract(nsIRDFResource* aSource,
|
||||
nsIRDFResource* aProperty,
|
||||
nsIRDFNode* aTarget);
|
||||
|
||||
nsresult
|
||||
CheckContainer(nsIRDFResource* aTargetResource, PRBool* aIsContainer, PRBool* aIsEmpty);
|
||||
|
||||
nsresult
|
||||
IsSystemPrincipal(nsIPrincipal *principal, PRBool *result);
|
||||
|
||||
#ifdef PR_LOGGING
|
||||
nsresult
|
||||
Log(const char* aOperation,
|
||||
nsIRDFResource* aSource,
|
||||
nsIRDFResource* aProperty,
|
||||
nsIRDFNode* aTarget);
|
||||
|
||||
#define LOG(_op, _src, _prop, _targ) \
|
||||
Log(_op, _src, _prop, _targ)
|
||||
|
||||
#else
|
||||
#define LOG(_op, _src, _prop, _targ)
|
||||
#endif
|
||||
/**
|
||||
* Convenience method which gets a resource for a result. If a result
|
||||
* doesn't have a resource set, it will create one from the result's id.
|
||||
*/
|
||||
nsresult GetResultResource(nsIXULTemplateResult* aResult,
|
||||
nsIRDFResource** aResource);
|
||||
|
||||
protected:
|
||||
// We are an observer of the composite datasource. The cycle is
|
||||
// broken when the document is destroyed.
|
||||
nsCOMPtr<nsIRDFDataSource> mDB;
|
||||
nsCOMPtr<nsIRDFCompositeDataSource> mCompDB;
|
||||
|
||||
// Circular reference, broken when the document is destroyed.
|
||||
/**
|
||||
* Circular reference, broken when the document is destroyed.
|
||||
*/
|
||||
nsCOMPtr<nsIContent> mRoot;
|
||||
|
||||
nsCOMPtr<nsIRDFDataSource> mCache;
|
||||
/**
|
||||
* The root result, translated from the root element's ref
|
||||
*/
|
||||
nsCOMPtr<nsIXULTemplateResult> mRootResult;
|
||||
|
||||
nsCOMArray<nsIXULBuilderListener> mListeners;
|
||||
|
||||
PRInt32 mUpdateBatchNest;
|
||||
/**
|
||||
* The query processor which generates results
|
||||
*/
|
||||
nsCOMPtr<nsIXULTemplateQueryProcessor> mQueryProcessor;
|
||||
|
||||
// For the rule network
|
||||
nsResourceSet mContainmentProperties;
|
||||
PRBool mRulesCompiled;
|
||||
/**
|
||||
* The list of querysets
|
||||
*/
|
||||
nsTArray<nsTemplateQuerySet *> mQuerySets;
|
||||
|
||||
/**
|
||||
* Set to true if the rules have already been compiled
|
||||
*/
|
||||
PRBool mQueriesCompiled;
|
||||
|
||||
/**
|
||||
* The default reference and member variables.
|
||||
*/
|
||||
nsCOMPtr<nsIAtom> mRefVariable;
|
||||
nsCOMPtr<nsIAtom> mMemberVariable;
|
||||
|
||||
/**
|
||||
* The match map contains nsTemplateMatch objects, one for each unique
|
||||
* match found, keyed by the resource for that match. A particular match
|
||||
* will contain a linked list of all of the matches for that unique result
|
||||
* id. Only one is active at a time. When a match is retracted, look in
|
||||
* the match map, remove it, and apply the next valid match in sequence to
|
||||
* make active.
|
||||
*/
|
||||
nsDataHashtable<nsISupportsHashKey, nsTemplateMatch*> mMatchMap;
|
||||
|
||||
/**
|
||||
* Fixed size allocator used to allocate matches
|
||||
*/
|
||||
nsFixedSizeAllocator mPool;
|
||||
|
||||
public:
|
||||
nsRuleNetwork mRules;
|
||||
PRInt32 mContainerVar;
|
||||
nsString mContainerSymbol;
|
||||
PRInt32 mMemberVar;
|
||||
nsString mMemberSymbol;
|
||||
nsConflictSet mConflictSet;
|
||||
ReteNodeSet mRDFTests;
|
||||
|
||||
nsFixedSizeAllocator& GetPool() { return mPool; }
|
||||
|
||||
protected:
|
||||
// pseudo-constants
|
||||
|
@ -344,7 +368,8 @@ protected:
|
|||
static nsIPrincipal* gSystemPrincipal;
|
||||
|
||||
enum {
|
||||
eDontTestEmpty = (1 << 0)
|
||||
eDontTestEmpty = (1 << 0),
|
||||
eDontRecurse = (2 << 0)
|
||||
};
|
||||
|
||||
PRInt32 mFlags;
|
||||
|
@ -381,22 +406,41 @@ protected:
|
|||
IsActivated(nsIRDFResource *aResource);
|
||||
|
||||
/**
|
||||
* Must be implemented by subclasses. Handle replacing aOldMatch
|
||||
* with aNewMatch. Either aOldMatch or aNewMatch may be null.
|
||||
* Returns true if content may be generated for a result, or false if it
|
||||
* cannot, for example, if it would be created inside a closed container.
|
||||
* Those results will be generated when the container is opened.
|
||||
* If false is returned, no content should be generated. The insertion
|
||||
* location may optionally be set for new content, depending on the
|
||||
* builder being used. This argument is used to optimize the content
|
||||
* builder so that it doesn't need to determined again when ReplaceMatch
|
||||
* is called.
|
||||
*/
|
||||
virtual PRBool
|
||||
MayGenerateResult(nsIXULTemplateResult* aOldResult,
|
||||
void** aLocation) = 0;
|
||||
|
||||
/**
|
||||
* Must be implemented by subclasses. Handle removing the generated
|
||||
* output for aOldMatch and adding new output for aNewMatch. Either
|
||||
* aOldMatch or aNewMatch may be null. aContext is the location returned
|
||||
* from the call to MayGenerateResult.
|
||||
*/
|
||||
virtual nsresult
|
||||
ReplaceMatch(nsIRDFResource* aMember, const nsTemplateMatch* aOldMatch, nsTemplateMatch* aNewMatch) = 0;
|
||||
ReplaceMatch(nsIXULTemplateResult* aOldResult,
|
||||
nsTemplateMatch* aNewMatch,
|
||||
nsTemplateRule* aNewMatchRule,
|
||||
void *aContext) = 0;
|
||||
|
||||
/**
|
||||
* Must be implemented by subclasses. Handle change in bound
|
||||
* variable values for aMatch. aModifiedVars contains the set
|
||||
* variable values for aResult. aModifiedVars contains the set
|
||||
* of variables that have changed.
|
||||
* @param aMatch the match for which variable bindings has changed.
|
||||
* @param aResult the ersult for which variable bindings has changed.
|
||||
* @param aModifiedVars the set of variables for which the bindings
|
||||
* have changed.
|
||||
*/
|
||||
virtual nsresult
|
||||
SynchronizeMatch(nsTemplateMatch* aMatch, const VariableSet& aModifiedVars) = 0;
|
||||
SynchronizeResult(nsIXULTemplateResult* aResult) = 0;
|
||||
};
|
||||
|
||||
#endif // nsXULTemplateBuilder_h__
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -0,0 +1,371 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Mozilla Communicator client code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 1998
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Robert Churchill <rjc@netscape.com>
|
||||
* David Hyatt <hyatt@netscape.com>
|
||||
* Chris Waterson <waterson@netscape.com>
|
||||
* Pierre Phaneuf <pp@ludusdesign.com>
|
||||
* Neil Deakin <enndeakin@sympatico.ca>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
|
||||
#ifndef nsXULTemplateQueryProcessorRDF_h__
|
||||
#define nsXULTemplateQueryProcessorRDF_h__
|
||||
|
||||
#include "nsIContent.h"
|
||||
#include "nsIRDFContainer.h"
|
||||
#include "nsIRDFContainerUtils.h"
|
||||
#include "nsIRDFDataSource.h"
|
||||
#include "nsIRDFObserver.h"
|
||||
#include "nsIRDFService.h"
|
||||
#include "nsIXULTemplateBuilder.h"
|
||||
#include "nsIXULTemplateQueryProcessor.h"
|
||||
#include "nsICollation.h"
|
||||
#include "nsCollationCID.h"
|
||||
|
||||
#include "nsFixedSizeAllocator.h"
|
||||
#include "nsResourceSet.h"
|
||||
#include "nsRuleNetwork.h"
|
||||
#include "nsRDFQuery.h"
|
||||
#include "nsRDFBinding.h"
|
||||
#include "nsXULTemplateResultSetRDF.h"
|
||||
#include "nsVoidArray.h"
|
||||
#include "nsCOMArray.h"
|
||||
#include "nsIArray.h"
|
||||
#include "nsString.h"
|
||||
#include "nsClassHashtable.h"
|
||||
#include "nsRefPtrHashtable.h"
|
||||
|
||||
#include "prlog.h"
|
||||
#ifdef PR_LOGGING
|
||||
extern PRLogModuleInfo* gXULTemplateLog;
|
||||
#endif
|
||||
|
||||
class nsIRDFCompositeDataSource;
|
||||
class nsXULTemplateResultRDF;
|
||||
|
||||
/**
|
||||
* An object that generates results from a query on an RDF graph
|
||||
*/
|
||||
class nsXULTemplateQueryProcessorRDF : public nsIXULTemplateQueryProcessor,
|
||||
public nsIRDFObserver
|
||||
{
|
||||
public:
|
||||
|
||||
nsXULTemplateQueryProcessorRDF();
|
||||
|
||||
~nsXULTemplateQueryProcessorRDF();
|
||||
|
||||
nsresult InitGlobals();
|
||||
|
||||
// nsISupports interface
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
// nsIXULTemplateQueryProcessor interface
|
||||
NS_DECL_NSIXULTEMPLATEQUERYPROCESSOR
|
||||
|
||||
// nsIRDFObserver interface
|
||||
NS_DECL_NSIRDFOBSERVER
|
||||
|
||||
/*
|
||||
* Propagate all changes through the rule network when an assertion is
|
||||
* added to the graph, adding any new results.
|
||||
*/
|
||||
nsresult
|
||||
Propagate(nsIRDFResource* aSource,
|
||||
nsIRDFResource* aProperty,
|
||||
nsIRDFNode* aTarget);
|
||||
|
||||
/*
|
||||
* Retract all changes through the rule network when an assertion is
|
||||
* removed from the graph, removing any results that no longer match.
|
||||
*/
|
||||
nsresult
|
||||
Retract(nsIRDFResource* aSource,
|
||||
nsIRDFResource* aProperty,
|
||||
nsIRDFNode* aTarget);
|
||||
|
||||
/*
|
||||
* Synchronize results when the graph changes, updating their bindings.
|
||||
*/
|
||||
nsresult
|
||||
SynchronizeAll(nsIRDFResource* aSource,
|
||||
nsIRDFResource* aProperty,
|
||||
nsIRDFNode* aOldTarget,
|
||||
nsIRDFNode* aNewTarget);
|
||||
|
||||
/*
|
||||
* Return true if a resource is a container
|
||||
*/
|
||||
nsresult
|
||||
CheckContainer(nsIRDFResource* aTargetResource,
|
||||
PRBool* aIsContainer);
|
||||
|
||||
/*
|
||||
* Check if a resource does not have any children
|
||||
*/
|
||||
nsresult
|
||||
CheckEmpty(nsIRDFResource* aTargetResource,
|
||||
PRBool* aIsEmpty);
|
||||
|
||||
/*
|
||||
* Compute the containment properties which are additional arcs which
|
||||
* indicate that a node is a container, in additional to the RDF container
|
||||
* tests. The computed list is stored in mContainmentProperties
|
||||
*/
|
||||
nsresult
|
||||
ComputeContainmentProperties(nsIDOMNode* aRootNode);
|
||||
|
||||
/**
|
||||
* Compile a query that uses the extended template syntax. The last
|
||||
* compiled node of the query is returned as aLastNode. This node will
|
||||
* have been added to mAllTests which owns the node.
|
||||
*/
|
||||
nsresult
|
||||
CompileExtendedQuery(nsRDFQuery* aQuery,
|
||||
nsIContent* aConditions,
|
||||
TestNode** aLastNode);
|
||||
|
||||
/**
|
||||
* Compile a single query child and return the compiled node in aResult.
|
||||
* This node will have been added to mAllTests which owns the node and
|
||||
* set as a child of aParentNode.
|
||||
*/
|
||||
virtual nsresult
|
||||
CompileQueryChild(nsIAtom* aTag,
|
||||
nsRDFQuery* aQuery,
|
||||
nsIContent* aConditions,
|
||||
TestNode* aParentNode,
|
||||
TestNode** aResult);
|
||||
|
||||
/**
|
||||
* Parse the value of a property test assertion for a condition or a simple
|
||||
* rule based on the parseType attribute into the appropriate literal type.
|
||||
*/
|
||||
nsresult ParseLiteral(const nsString& aParseType,
|
||||
const nsString& aValue,
|
||||
nsIRDFNode** aResult);
|
||||
|
||||
/**
|
||||
* Compile a <triple> condition and return the compiled node in aResult.
|
||||
* This node will have been added to mAllTests which owns the node and
|
||||
* set as a child of aParentNode.
|
||||
*/
|
||||
nsresult
|
||||
CompileTripleCondition(nsRDFQuery* aQuery,
|
||||
nsIContent* aCondition,
|
||||
TestNode* aParentNode,
|
||||
TestNode** aResult);
|
||||
|
||||
/**
|
||||
* Compile a <member> condition and return the compiled node in aResult.
|
||||
* This node will have been added to mAllTests which owns the node and
|
||||
* set as a child of aParentNode.
|
||||
*/
|
||||
nsresult
|
||||
CompileMemberCondition(nsRDFQuery* aQuery,
|
||||
nsIContent* aCondition,
|
||||
TestNode* aParentNode,
|
||||
TestNode** aResult);
|
||||
|
||||
/**
|
||||
* Add the default rules shared by all simple queries. This creates
|
||||
* the content start node followed by a member test. The member TestNode
|
||||
* is returned in aChildNode. Both nodes will have been added to mAllTests
|
||||
* which owns the nodes.
|
||||
*/
|
||||
nsresult
|
||||
AddDefaultSimpleRules(nsRDFQuery* aQuery,
|
||||
TestNode** aChildNode);
|
||||
|
||||
/**
|
||||
* Compile a query that's specified using the simple template
|
||||
* syntax. Each TestNode is created in a chain, the last compiled node
|
||||
* is retured as aLastNode. All nodes will have been added to mAllTests
|
||||
* which owns the nodes.
|
||||
*/
|
||||
nsresult
|
||||
CompileSimpleQuery(nsRDFQuery* aQuery,
|
||||
nsIContent* aQueryElement,
|
||||
TestNode** aLastNode);
|
||||
|
||||
RDFBindingSet*
|
||||
GetBindingsForRule(nsIDOMNode* aRule);
|
||||
|
||||
/*
|
||||
* Indicate that a result is dependant on a particular resource. When an
|
||||
* assertion is added to or removed from the graph involving that
|
||||
* resource, that result must be recalculated.
|
||||
*/
|
||||
nsresult
|
||||
AddBindingDependency(nsXULTemplateResultRDF* aResult,
|
||||
nsIRDFResource* aResource);
|
||||
|
||||
/**
|
||||
* Remove a dependency a result has on a particular resource.
|
||||
*/
|
||||
nsresult
|
||||
RemoveBindingDependency(nsXULTemplateResultRDF* aResult,
|
||||
nsIRDFResource* aResource);
|
||||
|
||||
/**
|
||||
* A memory element is a hash of an RDF triple. One exists for each triple
|
||||
* that was involved in generating a result. This function adds this to a
|
||||
* map, keyed by memory element, when the value is a list of results that
|
||||
* depend on that memory element. When an RDF triple is removed from the
|
||||
* datasource, RetractElement is called, and this map is examined to
|
||||
* determine which results are no longer valid.
|
||||
*/
|
||||
nsresult
|
||||
AddMemoryElements(const Instantiation& aInst,
|
||||
nsXULTemplateResultRDF* aResult);
|
||||
|
||||
/**
|
||||
* Remove the memory elements associated with a result when the result is
|
||||
* no longer being used.
|
||||
*/
|
||||
nsresult
|
||||
RemoveMemoryElements(const Instantiation& aInst,
|
||||
nsXULTemplateResultRDF* aResult);
|
||||
|
||||
/**
|
||||
* Remove the results associated with a memory element since the
|
||||
* RDF triple the memory element is a hash of has been removed.
|
||||
*/
|
||||
void RetractElement(const MemoryElement& aMemoryElement);
|
||||
|
||||
nsIRDFDataSource* GetDataSource() { return mDB; }
|
||||
|
||||
nsIXULTemplateBuilder* GetBuilder() { return mBuilder; }
|
||||
|
||||
nsResourceSet& ContainmentProperties() { return mContainmentProperties; }
|
||||
|
||||
#ifdef PR_LOGGING
|
||||
nsresult
|
||||
Log(const char* aOperation,
|
||||
nsIRDFResource* aSource,
|
||||
nsIRDFResource* aProperty,
|
||||
nsIRDFNode* aTarget);
|
||||
|
||||
#define LOG(_op, _src, _prop, _targ) \
|
||||
Log(_op, _src, _prop, _targ)
|
||||
|
||||
#else
|
||||
#define LOG(_op, _src, _prop, _targ)
|
||||
#endif
|
||||
|
||||
protected:
|
||||
// We are an observer of the composite datasource. The cycle is
|
||||
// broken when the document is destroyed.
|
||||
nsCOMPtr<nsIRDFDataSource> mDB;
|
||||
|
||||
// weak reference to the builder, cleared when the document is destroyed
|
||||
nsIXULTemplateBuilder* mBuilder;
|
||||
|
||||
// true if the query processor has been initialized
|
||||
PRBool mQueryProcessorRDFInited;
|
||||
|
||||
// true if results have been generated. Once set, bindings can no longer
|
||||
// be added. If they were, the binding value arrays for results that have
|
||||
// already been generated would be the wrong size
|
||||
PRBool mGenerationStarted;
|
||||
|
||||
// nesting level for RDF batch notifications
|
||||
PRInt32 mUpdateBatchNest;
|
||||
|
||||
// containment properties that are checked to determine if a resource is
|
||||
// a container
|
||||
nsResourceSet mContainmentProperties;
|
||||
|
||||
// the end node of the default simple node hierarchy
|
||||
TestNode* mSimpleRuleMemberTest;
|
||||
|
||||
// fixed size allocator used to allocate rule network structures
|
||||
nsFixedSizeAllocator mPool;
|
||||
|
||||
// the last ref that was calculated, used for simple rules
|
||||
nsCOMPtr<nsIXULTemplateResult> mLastRef;
|
||||
|
||||
/**
|
||||
* A map between nsIRDFNodes that form the left-hand side (the subject) of
|
||||
* a <binding> and an array of nsIXULTemplateResults. When a new assertion
|
||||
* is added to the graph involving a particular rdf node, it is looked up
|
||||
* in this binding map. If it exists, the corresponding results must then
|
||||
* be synchronized.
|
||||
*/
|
||||
nsClassHashtable<nsISupportsHashKey,
|
||||
nsCOMArray<nsXULTemplateResultRDF> > mBindingDependencies;
|
||||
|
||||
/**
|
||||
* A map between memory elements and an array of nsIXULTemplateResults.
|
||||
* When a triple is unasserted from the graph, the corresponding results
|
||||
* no longer match so they must be removed.
|
||||
*/
|
||||
nsClassHashtable<nsUint32HashKey,
|
||||
nsCOMArray<nsXULTemplateResultRDF> > mMemoryElementToResultMap;
|
||||
|
||||
// map of the rules to the bindings for those rules.
|
||||
// XXXndeakin this might be better just as an array since there is usually
|
||||
// ten or fewer rules
|
||||
nsRefPtrHashtable<nsISupportsHashKey, RDFBindingSet> mRuleToBindingsMap;
|
||||
|
||||
/**
|
||||
* The queries
|
||||
*/
|
||||
nsCOMArray<nsITemplateRDFQuery> mQueries;
|
||||
|
||||
/**
|
||||
* All of the RDF tests in the rule network, which are checked when a new
|
||||
* assertion is added to the graph. This is a subset of mAllTests, which
|
||||
* also includes non-RDF tests.
|
||||
*/
|
||||
ReteNodeSet mRDFTests;
|
||||
|
||||
/**
|
||||
* All of the tests in the rule network, owned by this list
|
||||
*/
|
||||
ReteNodeSet mAllTests;
|
||||
|
||||
// pseudo-constants
|
||||
static nsrefcnt gRefCnt;
|
||||
|
||||
public:
|
||||
static nsIRDFService* gRDFService;
|
||||
static nsIRDFContainerUtils* gRDFContainerUtils;
|
||||
|
||||
nsFixedSizeAllocator& GetPool() { return mPool; }
|
||||
};
|
||||
|
||||
#endif // nsXULTemplateQueryProcessorRDF_h__
|
|
@ -0,0 +1,213 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Neil Deakin
|
||||
* Portions created by the Initial Developer are Copyright (C) 2005
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include "nsXULTemplateResultRDF.h"
|
||||
#include "nsXULContentUtils.h"
|
||||
|
||||
// XXXndeakin for some reason, making this class have classinfo breaks trees.
|
||||
//#include "nsIDOMClassInfo.h"
|
||||
|
||||
NS_IMPL_ISUPPORTS1(nsXULTemplateResultRDF, nsIXULTemplateResult)
|
||||
|
||||
nsXULTemplateResultRDF::nsXULTemplateResultRDF(nsIRDFResource* aNode)
|
||||
: mQuery(nsnull),
|
||||
mNode(aNode)
|
||||
{
|
||||
}
|
||||
|
||||
nsXULTemplateResultRDF::nsXULTemplateResultRDF(nsRDFQuery* aQuery,
|
||||
const Instantiation& aInst,
|
||||
nsIRDFResource *aNode)
|
||||
: mQuery(aQuery),
|
||||
mNode(aNode),
|
||||
mInst(aInst)
|
||||
{
|
||||
}
|
||||
|
||||
nsXULTemplateResultRDF::~nsXULTemplateResultRDF()
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsXULTemplateResultRDF::GetIsContainer(PRBool* aIsContainer)
|
||||
{
|
||||
*aIsContainer = PR_FALSE;
|
||||
|
||||
if (mNode) {
|
||||
nsXULTemplateQueryProcessorRDF* processor = GetProcessor();
|
||||
if (processor)
|
||||
return processor->CheckContainer(mNode, aIsContainer);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsXULTemplateResultRDF::GetIsEmpty(PRBool* aIsEmpty)
|
||||
{
|
||||
*aIsEmpty = PR_TRUE;
|
||||
|
||||
if (mNode) {
|
||||
nsXULTemplateQueryProcessorRDF* processor = GetProcessor();
|
||||
if (processor)
|
||||
return processor->CheckEmpty(mNode, aIsEmpty);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsXULTemplateResultRDF::GetMayProcessChildren(PRBool* aMayProcessChildren)
|
||||
{
|
||||
// RDF always allows recursion
|
||||
*aMayProcessChildren = PR_TRUE;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsXULTemplateResultRDF::GetId(nsAString& aId)
|
||||
{
|
||||
if (! mNode)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
const char* uri;
|
||||
mNode->GetValueConst(&uri);
|
||||
|
||||
CopyUTF8toUTF16(uri, aId);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsXULTemplateResultRDF::GetResource(nsIRDFResource** aResource)
|
||||
{
|
||||
*aResource = mNode;
|
||||
NS_IF_ADDREF(*aResource);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsXULTemplateResultRDF::GetBindingFor(nsIAtom* aVar, nsAString& aValue)
|
||||
{
|
||||
nsCOMPtr<nsIRDFNode> val;
|
||||
GetAssignment(aVar, getter_AddRefs(val));
|
||||
|
||||
return nsXULContentUtils::GetTextForNode(val, aValue);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsXULTemplateResultRDF::GetBindingObjectFor(nsIAtom* aVar, nsISupports** aValue)
|
||||
{
|
||||
GetAssignment(aVar, (nsIRDFNode **)aValue);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsXULTemplateResultRDF::RuleMatched(nsISupports* aQuery, nsIDOMNode* aRuleNode)
|
||||
{
|
||||
// when a rule matches, set the bindings that must be used.
|
||||
nsXULTemplateQueryProcessorRDF* processor = GetProcessor();
|
||||
if (processor) {
|
||||
RDFBindingSet* bindings = processor->GetBindingsForRule(aRuleNode);
|
||||
if (bindings) {
|
||||
nsresult rv = mBindingValues.SetBindingSet(bindings);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
bindings->AddDependencies(mNode, this);
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsXULTemplateResultRDF::HasBeenRemoved()
|
||||
{
|
||||
// when a result is no longer used, clean up the dependencies and
|
||||
// memory elements that refer to it
|
||||
mBindingValues.RemoveDependencies(mNode, this);
|
||||
|
||||
nsXULTemplateQueryProcessorRDF* processor = GetProcessor();
|
||||
if (processor)
|
||||
processor->RemoveMemoryElements(mInst, this);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
nsXULTemplateResultRDF::GetAssignment(nsIAtom* aVar, nsIRDFNode** aValue)
|
||||
{
|
||||
// look up a variable in the assignments map
|
||||
*aValue = nsnull;
|
||||
mInst.mAssignments.GetAssignmentFor(aVar, aValue);
|
||||
|
||||
// if not found, look up the variable in the bindings
|
||||
if (! *aValue)
|
||||
mBindingValues.GetAssignmentFor(this, aVar, aValue);
|
||||
}
|
||||
|
||||
|
||||
PRBool
|
||||
nsXULTemplateResultRDF::SyncAssignments(nsIRDFResource* aSubject,
|
||||
nsIRDFResource* aPredicate,
|
||||
nsIRDFNode* aTarget)
|
||||
{
|
||||
// synchronize the bindings when an assertion is added or removed
|
||||
RDFBindingSet* bindingset = mBindingValues.GetBindingSet();
|
||||
if (bindingset) {
|
||||
return bindingset->SyncAssignments(aSubject, aPredicate, aTarget,
|
||||
(aSubject == mNode) ? mQuery->GetMemberVariable() : nsnull,
|
||||
this, mBindingValues);
|
||||
}
|
||||
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
PRBool
|
||||
nsXULTemplateResultRDF::HasMemoryElement(const MemoryElement& aMemoryElement)
|
||||
{
|
||||
MemoryElementSet::ConstIterator last = mInst.mSupport.Last();
|
||||
for (MemoryElementSet::ConstIterator element = mInst.mSupport.First();
|
||||
element != last; ++element) {
|
||||
if ((*element).Equals(aMemoryElement))
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
return PR_FALSE;
|
||||
}
|
|
@ -0,0 +1,111 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Neil Deakin
|
||||
* Portions created by the Initial Developer are Copyright (C) 2005
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef nsXULTemplateResultRDF_h__
|
||||
#define nsXULTemplateResultRDF_h__
|
||||
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsIRDFResource.h"
|
||||
#include "nsXULTemplateQueryProcessorRDF.h"
|
||||
#include "nsRDFQuery.h"
|
||||
#include "nsRuleNetwork.h"
|
||||
#include "nsIXULTemplateResult.h"
|
||||
#include "nsRDFBinding.h"
|
||||
|
||||
/**
|
||||
* A single result of a query on an RDF graph
|
||||
*/
|
||||
class nsXULTemplateResultRDF : public nsIXULTemplateResult
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
NS_DECL_NSIXULTEMPLATERESULT
|
||||
|
||||
nsXULTemplateResultRDF(nsIRDFResource* aNode);
|
||||
|
||||
nsXULTemplateResultRDF(nsRDFQuery* aQuery,
|
||||
const Instantiation& aInst,
|
||||
nsIRDFResource* aNode);
|
||||
|
||||
~nsXULTemplateResultRDF();
|
||||
|
||||
nsITemplateRDFQuery* Query() { return mQuery; }
|
||||
|
||||
nsXULTemplateQueryProcessorRDF* GetProcessor()
|
||||
{
|
||||
return (mQuery ? mQuery->Processor() : nsnull);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the value of a variable, first by looking in the assignments and
|
||||
* then the bindings
|
||||
*/
|
||||
void
|
||||
GetAssignment(nsIAtom* aVar, nsIRDFNode** aValue);
|
||||
|
||||
/**
|
||||
* Synchronize the bindings after a change in the RDF graph. Bindings that
|
||||
* would be affected will be assigned appropriately based on the change.
|
||||
*/
|
||||
PRBool
|
||||
SyncAssignments(nsIRDFResource* aSubject,
|
||||
nsIRDFResource* aPredicate,
|
||||
nsIRDFNode* aTarget);
|
||||
|
||||
/**
|
||||
* Return true if the result has an instantiation involving a particular
|
||||
* memory element.
|
||||
*/
|
||||
PRBool
|
||||
HasMemoryElement(const MemoryElement& aMemoryElement);
|
||||
|
||||
protected:
|
||||
|
||||
// query that generated the result
|
||||
nsCOMPtr<nsITemplateRDFQuery> mQuery;
|
||||
|
||||
// resource node
|
||||
nsCOMPtr<nsIRDFResource> mNode;
|
||||
|
||||
// data computed from query
|
||||
Instantiation mInst;
|
||||
|
||||
// extra assignments made by rules (<binding> tags)
|
||||
nsBindingValues mBindingValues;
|
||||
};
|
||||
|
||||
#endif // nsXULTemplateResultRDF_h__
|
|
@ -0,0 +1,114 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Neil Deakin
|
||||
* Portions created by the Initial Developer are Copyright (C) 2005
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include "nsXULTemplateResultSetRDF.h"
|
||||
#include "nsXULTemplateQueryProcessorRDF.h"
|
||||
|
||||
NS_IMPL_ISUPPORTS1(nsXULTemplateResultSetRDF, nsISimpleEnumerator)
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsXULTemplateResultSetRDF::HasMoreElements(PRBool *aResult)
|
||||
{
|
||||
*aResult = PR_TRUE;
|
||||
|
||||
nsCOMPtr<nsIRDFNode> node;
|
||||
|
||||
if (! mInstantiations || ! mQuery) {
|
||||
*aResult = PR_FALSE;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (mCheckedNext) {
|
||||
if (!mCurrent || mCurrent == &(mInstantiations->mHead))
|
||||
*aResult = PR_FALSE;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
mCheckedNext = PR_TRUE;
|
||||
|
||||
do {
|
||||
if (mCurrent) {
|
||||
mCurrent = mCurrent->mNext;
|
||||
if (mCurrent == &(mInstantiations->mHead)) {
|
||||
*aResult = PR_FALSE;
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
else {
|
||||
*aResult = ! mInstantiations->Empty();
|
||||
if (*aResult)
|
||||
mCurrent = mInstantiations->mHead.mNext;
|
||||
}
|
||||
|
||||
// get the value of the member variable. If it is not set, skip
|
||||
// the result and move on to the next result
|
||||
if (mCurrent) {
|
||||
mCurrent->mInstantiation.mAssignments.
|
||||
GetAssignmentFor(mQuery->mMemberVariable, getter_AddRefs(node));
|
||||
}
|
||||
|
||||
// only resources may be used as results
|
||||
mResource = do_QueryInterface(node);
|
||||
} while (! mResource);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsXULTemplateResultSetRDF::GetNext(nsISupports **aResult)
|
||||
{
|
||||
if (!aResult)
|
||||
return NS_ERROR_NULL_POINTER;
|
||||
|
||||
if (!mCurrent || !mCheckedNext)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
nsRefPtr<nsXULTemplateResultRDF> nextresult =
|
||||
new nsXULTemplateResultRDF(mQuery, mCurrent->mInstantiation, mResource);
|
||||
if (!nextresult)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
// add the supporting memory elements to the processor's map. These are
|
||||
// used to remove the results when an assertion is removed from the graph
|
||||
mProcessor->AddMemoryElements(mCurrent->mInstantiation, nextresult);
|
||||
|
||||
mCheckedNext = PR_FALSE;
|
||||
|
||||
*aResult = nextresult;
|
||||
NS_ADDREF(*aResult);
|
||||
|
||||
return NS_OK;
|
||||
}
|
|
@ -0,0 +1,91 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Neil Deakin
|
||||
* Portions created by the Initial Developer are Copyright (C) 2005
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef nsXULTemplateResultSetRDF_h__
|
||||
#define nsXULTemplateResultSetRDF_h__
|
||||
|
||||
#include "nsFixedSizeAllocator.h"
|
||||
#include "nsISimpleEnumerator.h"
|
||||
#include "nsRuleNetwork.h"
|
||||
#include "nsRDFQuery.h"
|
||||
#include "nsXULTemplateResultRDF.h"
|
||||
|
||||
class nsXULTemplateQueryProcessorRDF;
|
||||
class nsXULTemplateResultRDF;
|
||||
|
||||
/**
|
||||
* An enumerator used to iterate over a set of results.
|
||||
*/
|
||||
class nsXULTemplateResultSetRDF : public nsISimpleEnumerator
|
||||
{
|
||||
private:
|
||||
nsXULTemplateQueryProcessorRDF* mProcessor;
|
||||
|
||||
nsRDFQuery* mQuery;
|
||||
|
||||
const InstantiationSet* mInstantiations;
|
||||
|
||||
nsCOMPtr<nsIRDFResource> mResource;
|
||||
|
||||
InstantiationSet::List *mCurrent;
|
||||
|
||||
PRBool mCheckedNext;
|
||||
|
||||
public:
|
||||
|
||||
// nsISupports interface
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
// nsISimpleEnumerator interface
|
||||
NS_DECL_NSISIMPLEENUMERATOR
|
||||
|
||||
nsXULTemplateResultSetRDF(nsXULTemplateQueryProcessorRDF *aProcessor,
|
||||
nsRDFQuery* aQuery,
|
||||
const InstantiationSet* aInstantiations)
|
||||
: mProcessor(aProcessor),
|
||||
mQuery(aQuery),
|
||||
mInstantiations(aInstantiations),
|
||||
mCurrent(nsnull),
|
||||
mCheckedNext(PR_FALSE)
|
||||
{ }
|
||||
|
||||
~nsXULTemplateResultSetRDF()
|
||||
{
|
||||
delete mInstantiations;
|
||||
}
|
||||
};
|
||||
|
||||
#endif // nsXULTemplateResultSetRDF_h__
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Загрузка…
Ссылка в новой задаче