Bug 1425356 - remove XUL template support, r=bz

MozReview-Commit-ID: HdBoQ15DFOu

--HG--
rename : dom/xul/templates/nsIXULSortService.idl => dom/xul/nsIXULSortService.idl
rename : dom/xul/templates/nsXULContentUtils.cpp => dom/xul/nsXULContentUtils.cpp
rename : dom/xul/templates/nsXULContentUtils.h => dom/xul/nsXULContentUtils.h
rename : dom/xul/templates/nsXULSortService.cpp => dom/xul/nsXULSortService.cpp
rename : dom/xul/templates/nsXULSortService.h => dom/xul/nsXULSortService.h
extra : rebase_source : e3f3504c529e7bd9aa52aecf34b94bb5b0ff92b4
This commit is contained in:
Gijs Kruitbosch 2017-12-19 14:11:06 +00:00
parent e8c1471db1
commit a8bb5924c6
311 changed files with 254 additions and 38283 deletions

View File

@ -340,7 +340,6 @@
@RESPATH@/components/xpconnect.xpt
@RESPATH@/components/xulapp.xpt
@RESPATH@/components/xul.xpt
@RESPATH@/components/xultmpl.xpt
@RESPATH@/components/zipwriter.xpt
@RESPATH@/components/telemetry.xpt

View File

@ -1274,12 +1274,6 @@ var interfaceNamesInGlobalScope =
{name: "XULElement", xbl: true},
// IMPORTANT: Do not change this list without review from a DOM peer!
{name: "XULLabeledControlElement", xbl: true},
// IMPORTANT: Do not change this list without review from a DOM peer!
{name: "XULTemplateBuilder", xbl: true},
// IMPORTANT: Do not change this list without review from a DOM peer!
{name: "XULTreeBuilder", xbl: true},
// IMPORTANT: Do not change this list without review from a DOM peer!
{name: "XULTreeBuilderObserver", xbl: true},
// IMPORTANT: Do not change this list without review from a DOM peer!
];
// IMPORTANT: Do not change the list above without review from a DOM peer!

View File

@ -92,4 +92,3 @@ XMLHttpRequest implements LegacyQueryInterface;
XMLHttpRequestUpload implements LegacyQueryInterface;
XMLSerializer implements LegacyQueryInterface;
XPathEvaluator implements LegacyQueryInterface;
XULTemplateBuilder implements LegacyQueryInterface;

View File

@ -5,8 +5,6 @@
*/
interface XULControllers;
interface MozRDFCompositeDataSource;
interface MozRDFResource;
[HTMLConstructor, Func="IsChromeOrXBL"]
interface XULElement : Element {
@ -68,12 +66,6 @@ interface XULElement : Element {
[SetterThrows]
attribute DOMString top;
// XUL Template Builder
[SetterThrows]
attribute DOMString datasources;
[SetterThrows]
attribute DOMString ref;
// Tooltip and status info
[SetterThrows]
attribute DOMString tooltipText;
@ -86,10 +78,6 @@ interface XULElement : Element {
attribute boolean allowEvents;
readonly attribute MozRDFCompositeDataSource? database;
readonly attribute XULTemplateBuilder? builder;
[Throws]
readonly attribute MozRDFResource? resource;
[Throws, ChromeOnly]
readonly attribute XULControllers controllers;
[Throws]

View File

@ -1,398 +0,0 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
interface MozRDFCompositeDataSource;
interface MozRDFResource;
interface nsISupports;
interface XULTemplateResult;
interface XULTemplateRuleFilter;
callback interface XULBuilderListener
{
void willRebuild(XULTemplateBuilder aBuilder);
void didRebuild(XULTemplateBuilder aBuilder);
};
/**
* 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.
*/
[Func="IsChromeOrXBL"]
interface XULTemplateBuilder
{
/**
* The root node in the DOM to which this builder is attached.
*/
readonly attribute Element? root;
/**
* The opaque datasource object that is used for the template. This object
* is created by the getDataSource method of the query processor. May be
* null if the datasource has not been loaded yet. Set this attribute to
* use a different datasource and rebuild the template.
*
* For an RDF datasource, this will be the same as the database. For XML
* this will be the nsIDOMNode for the datasource document or node for
* an inline reference (such as #name). Other query processors may use
* other types for the datasource.
*/
[SetterThrows]
attribute nsISupports? datasource;
/**
* The composite datasource that the template builder observes
* and uses to create content. This is used only for RDF queries and is
* maintained for backwards compatibility. It will be the same object as
* the datasource property. For non-RDF queries, it will always be null.
*/
readonly attribute MozRDFCompositeDataSource? database;
/**
* 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 XULTemplateResult? 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.
*
*/
[Throws]
void rebuild();
/**
* Reload any of our RDF datasources that support nsIRDFRemoteDatasource.
*
* @note This is a temporary hack so that remote-XUL authors can
* reload remote datasources. When RDF becomes remote-scriptable,
* this will no longer be necessary.
*/
[Throws]
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]
void addResult(XULTemplateResult aResult, Node 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
*/
[Throws]
void removeResult(XULTemplateResult 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
*/
[Throws]
void replaceResult(XULTemplateResult aOldResult,
XULTemplateResult aNewResult,
Node 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
*/
[Throws]
void resultBindingChanged(XULTemplateResult 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
*/
[Throws]
XULTemplateResult? getResultForId(DOMString aId);
/**
* Retrieve the result corresponding to a generated element, or null is
* there isn't one.
*
* @param aContent element to result the result of
*/
XULTemplateResult? getResultForContent(Element aElement);
/**
* 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
*/
[Throws]
boolean hasGeneratedContent(MozRDFResource aNode, DOMString? 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
*/
[Throws]
void addRuleFilter(Node aRule, XULTemplateRuleFilter aFilter);
/**
* Add a listener to this template builder. The template builder
* holds a strong reference to the listener.
*/
void addListener(XULBuilderListener aListener);
/**
* Remove a listener from this template builder.
*/
void removeListener(XULBuilderListener aListener);
};
/**
* XULTreeBuilderObserver
* This interface allows clients of the XULTreeBuilder to define domain
* specific handling of specific nsITreeView methods that
* XULTreeBuilder does not implement.
*/
[Func="IsChromeOrXBL"]
callback interface XULTreeBuilderObserver
{
const long DROP_BEFORE = -1;
const long DROP_ON = 0;
const long DROP_AFTER = 1;
/**
* Methods used by the drag feedback code to determine if a drag is
* allowable at the current location. To get the behavior where drops are
* only allowed on items, such as the mailNews folder pane, always return
* false when the orientation is not DROP_ON.
*/
boolean canDrop(long index, long orientation, DataTransfer? dataTransfer);
/**
* Called when the user drops something on this view. The |orientation|
* param specifies before/on/after the given |row|.
*/
void onDrop(long row, long orientation, DataTransfer? dataTransfer);
/**
* Called when an item is opened or closed.
*/
void onToggleOpenState(long index);
/**
* Called when a header is clicked.
*/
void onCycleHeader(DOMString colID, Element? elt);
/**
* Called when a cell in a non-selectable cycling column (e.g.
* unread/flag/etc.) is clicked.
*/
void onCycleCell(long row, DOMString colID);
/**
* Called when selection in the tree changes
*/
void onSelectionChanged();
/**
* A command API that can be used to invoke commands on the selection.
* The tree will automatically invoke this method when certain keys
* are pressed. For example, when the DEL key is pressed, performAction
* will be called with the "delete" string.
*/
void onPerformAction(DOMString action);
/**
* A command API that can be used to invoke commands on a specific row.
*/
void onPerformActionOnRow(DOMString action, long row);
/**
* A command API that can be used to invoke commands on a specific cell.
*/
void onPerformActionOnCell(DOMString action, long row, DOMString colID);
};
[Func="IsChromeOrXBL"]
interface XULTreeBuilder : XULTemplateBuilder
{
/**
* Retrieve the RDF resource associated with the specified row.
*/
[Throws]
MozRDFResource? getResourceAtIndex(long aRowIndex);
/**
* Retrieve the index associated with specified RDF resource.
*/
[Throws]
long getIndexOfResource(MozRDFResource resource);
/**
* Add a Tree Builder Observer to handle Tree View
* methods that the base builder does not implement.
*/
void addObserver(XULTreeBuilderObserver aObserver);
/**
* Remove an Tree Builder Observer.
*/
void removeObserver(XULTreeBuilderObserver aObserver);
/**
* Sort the contents of the tree using the specified column.
*/
void sort(Element aColumnElement);
};
XULTreeBuilder implements TreeView;

View File

@ -971,7 +971,6 @@ WEBIDL_FILES = [
'XULCommandEvent.webidl',
'XULDocument.webidl',
'XULElement.webidl',
'XULTemplateBuilder.webidl',
]
if CONFIG['MOZ_WEBRTC']:

View File

@ -51,7 +51,6 @@
#include "nsXULCommandDispatcher.h"
#include "nsXULElement.h"
#include "mozilla/Logging.h"
#include "rdf.h"
#include "nsIFrame.h"
#include "nsXBLService.h"
#include "nsCExternalHandlerService.h"
@ -59,6 +58,7 @@
#include "nsIObjectInputStream.h"
#include "nsIObjectOutputStream.h"
#include "nsContentList.h"
#include "nsISimpleEnumerator.h"
#include "nsIScriptGlobalObject.h"
#include "nsIScriptSecurityManager.h"
#include "nsNodeInfoManager.h"
@ -95,8 +95,6 @@
#include "xpcpublic.h"
#include "mozilla/StyleSheet.h"
#include "mozilla/StyleSheetInlines.h"
#include "nsXULTemplateBuilder.h"
#include "nsXULTreeBuilder.h"
using namespace mozilla;
using namespace mozilla::dom;
@ -197,7 +195,6 @@ XULDocument::XULDocument(void)
mDocumentLoaded(false),
mStillWalking(false),
mRestrictPersistence(false),
mTemplateBuilderTable(nullptr),
mPendingSheets(0),
mDocLWTheme(Doc_Theme_Uninitialized),
mState(eState_Master),
@ -237,8 +234,6 @@ XULDocument::~XULDocument()
// Destroy our broadcaster map.
delete mBroadcasterMap;
delete mTemplateBuilderTable;
Preferences::UnregisterCallback(XULDocument::DirectionChanged,
"intl.uidirection", this);
@ -285,19 +280,6 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(XULDocument, XMLDocument)
// XXX tmp->mForwardReferences?
// XXX tmp->mContextStack?
// An element will only have a template builder as long as it's in the
// document, so we'll traverse the table here instead of from the element.
if (tmp->mTemplateBuilderTable) {
for (auto iter = tmp->mTemplateBuilderTable->Iter();
!iter.Done();
iter.Next()) {
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mTemplateBuilderTable key");
cb.NoteXPCOMChild(iter.Key());
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mTemplateBuilderTable value");
cb.NoteXPCOMChild(iter.UserData());
}
}
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCurrentPrototype)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMasterPrototype)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCommandDispatcher)
@ -323,9 +305,6 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(XULDocument, XMLDocument)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(XULDocument, XMLDocument)
delete tmp->mTemplateBuilderTable;
tmp->mTemplateBuilderTable = nullptr;
NS_IMPL_CYCLE_COLLECTION_UNLINK(mCommandDispatcher)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mLocalStore)
//XXX We should probably unlink all the objects we traverse.
@ -1667,26 +1646,6 @@ XULDocument::AddElementToDocumentPost(Element* aElement)
nsXBLService::AttachGlobalKeyHandler(aElement);
}
// See if we need to attach a XUL template to this node
bool needsHookup;
nsresult rv = CheckTemplateBuilderHookup(aElement, &needsHookup);
if (NS_FAILED(rv))
return rv;
if (needsHookup) {
if (mResolutionPhase == nsForwardReference::eDone) {
rv = CreateTemplateBuilder(aElement);
if (NS_FAILED(rv))
return rv;
}
else {
TemplateBuilderHookup* hookup = new TemplateBuilderHookup(aElement);
rv = AddForwardReference(hookup);
if (NS_FAILED(rv))
return rv;
}
}
return NS_OK;
}
@ -1784,40 +1743,6 @@ XULDocument::RemoveSubtreeFromDocument(nsIContent* aContent)
return NS_OK;
}
NS_IMETHODIMP
XULDocument::SetTemplateBuilderFor(nsIContent* aContent,
nsIXULTemplateBuilder* aBuilder)
{
if (! mTemplateBuilderTable) {
if (!aBuilder) {
return NS_OK;
}
mTemplateBuilderTable = new BuilderTable;
}
if (aBuilder) {
mTemplateBuilderTable->Put(aContent, aBuilder);
}
else {
mTemplateBuilderTable->Remove(aContent);
}
return NS_OK;
}
NS_IMETHODIMP
XULDocument::GetTemplateBuilderFor(nsIContent* aContent,
nsIXULTemplateBuilder** aResult)
{
if (mTemplateBuilderTable) {
mTemplateBuilderTable->Get(aContent, aResult);
}
else
*aResult = nullptr;
return NS_OK;
}
static void
GetRefMapAttribute(Element* aElement, nsAutoString* aValue)
{
@ -3630,95 +3555,6 @@ XULDocument::AddAttributes(nsXULPrototypeElement* aPrototype,
}
nsresult
XULDocument::CheckTemplateBuilderHookup(Element* aElement,
bool* aNeedsHookup)
{
// See if the element already has a `database' attribute. If it
// does, then the template builder has already been created.
//
// XXX This approach will crash and burn (well, maybe not _that_
// bad) if aElement is not a XUL element.
//
// XXXvarga Do we still want to support non XUL content?
RefPtr<nsXULElement> xulElement = nsXULElement::FromContent(aElement);
if (xulElement) {
nsCOMPtr<nsIRDFCompositeDataSource> ds = xulElement->GetDatabase();
if (ds) {
*aNeedsHookup = false;
return NS_OK;
}
}
// Check aElement for a 'datasources' attribute, if it has
// one a XUL template builder needs to be hooked up.
*aNeedsHookup = aElement->HasAttr(kNameSpaceID_None,
nsGkAtoms::datasources);
return NS_OK;
}
/* static */ nsresult
XULDocument::CreateTemplateBuilder(Element* aElement)
{
// Check if need to construct a tree builder or content builder.
bool isTreeBuilder = false;
// return successful if the element is not is a document, as an inline
// script could have removed it
nsIDocument* document = aElement->GetUncomposedDoc();
NS_ENSURE_TRUE(document, NS_OK);
int32_t nameSpaceID;
nsAtom* baseTag = document->BindingManager()->
ResolveTag(aElement, &nameSpaceID);
if ((nameSpaceID == kNameSpaceID_XUL) && (baseTag == nsGkAtoms::tree)) {
// By default, we build content for a tree and then we attach
// the tree content view. However, if the `dont-build-content'
// flag is set, then we we'll attach a tree builder which
// directly implements the tree view.
nsAutoString flags;
aElement->GetAttr(kNameSpaceID_None, nsGkAtoms::flags, flags);
if (flags.Find(NS_LITERAL_STRING("dont-build-content")) >= 0) {
isTreeBuilder = true;
}
}
if (isTreeBuilder) {
// Create and initialize a tree builder.
RefPtr<nsXULTreeBuilder> builder = new nsXULTreeBuilder(aElement);
nsresult rv = builder->Init();
NS_ENSURE_SUCCESS(rv, rv);
// Create a <treechildren> if one isn't there already.
// XXXvarga what about attributes?
RefPtr<Element> bodyContent;
nsXULContentUtils::FindChildByTag(aElement, kNameSpaceID_XUL,
nsGkAtoms::treechildren,
getter_AddRefs(bodyContent));
if (!bodyContent) {
bodyContent =
document->CreateElem(nsDependentAtomString(nsGkAtoms::treechildren),
nullptr, kNameSpaceID_XUL);
aElement->AppendChildTo(bodyContent, false);
}
}
else {
// Create and initialize a content builder.
nsCOMPtr<nsIXULTemplateBuilder> builder;
nsresult rv = NS_NewXULContentBuilder(aElement, getter_AddRefs(builder));
NS_ENSURE_SUCCESS(rv, rv);
builder->CreateContents(aElement, false);
}
return NS_OK;
}
nsresult
XULDocument::AddPrototypeSheets()
{
@ -4034,30 +3870,6 @@ XULDocument::BroadcasterHookup::~BroadcasterHookup()
}
}
//----------------------------------------------------------------------
//
// XULDocument::TemplateBuilderHookup
//
nsForwardReference::Result
XULDocument::TemplateBuilderHookup::Resolve()
{
bool needsHookup;
nsresult rv = CheckTemplateBuilderHookup(mElement, &needsHookup);
if (NS_FAILED(rv))
return eResolve_Error;
if (needsHookup) {
rv = CreateTemplateBuilder(mElement);
if (NS_FAILED(rv))
return eResolve_Error;
}
return eResolve_Succeeded;
}
//----------------------------------------------------------------------
nsresult

View File

@ -130,10 +130,6 @@ public:
NS_IMETHOD AddSubtreeToDocument(nsIContent* aContent) override;
NS_IMETHOD RemoveSubtreeFromDocument(nsIContent* aContent) override;
NS_IMETHOD SetTemplateBuilderFor(nsIContent* aContent,
nsIXULTemplateBuilder* aBuilder) override;
NS_IMETHOD GetTemplateBuilderFor(nsIContent* aContent,
nsIXULTemplateBuilder** aResult) override;
NS_IMETHOD OnPrototypeLoadDone(bool aResumeWalk) override;
bool OnDocumentParserError() override;
@ -352,12 +348,6 @@ protected:
nsCOMPtr<nsIDOMXULCommandDispatcher> mCommandDispatcher; // [OWNER] of the focus tracker
// Maintains the template builders that have been attached to
// content elements
typedef nsInterfaceHashtable<nsISupportsHashKey, nsIXULTemplateBuilder>
BuilderTable;
BuilderTable* mTemplateBuilderTable;
uint32_t mPendingSheets;
/**
@ -468,18 +458,6 @@ protected:
char16_t* mOffThreadCompileStringBuf;
size_t mOffThreadCompileStringLength;
/**
* Check if a XUL template builder has already been hooked up.
*/
static nsresult
CheckTemplateBuilderHookup(mozilla::dom::Element* aElement, bool* aNeedsHookup);
/**
* Create a XUL template builder on the specified node.
*/
static nsresult
CreateTemplateBuilder(Element* aElement);
/**
* Add the current prototype's style sheets (currently it's just
* style overlays from the chrome registry) to the document.
@ -567,21 +545,6 @@ protected:
friend class OverlayForwardReference;
class TemplateBuilderHookup : public nsForwardReference
{
protected:
nsCOMPtr<Element> mElement; // [OWNER]
public:
explicit TemplateBuilderHookup(Element* aElement)
: mElement(aElement) {}
virtual Phase GetPhase() override { return eHookup; }
virtual Result Resolve() override;
};
friend class TemplateBuilderHookup;
// The out params of FindBroadcaster only have values that make sense when
// the method returns NS_FINDBROADCASTER_FOUND. In all other cases, the
// values of the out params should not be relied on (though *aListener and

View File

@ -12,8 +12,6 @@ MOCHITEST_MANIFESTS += ['test/mochitest.ini']
MOCHITEST_CHROME_MANIFESTS += ['test/chrome.ini']
if CONFIG['MOZ_XUL']:
DIRS += ['templates']
XPIDL_SOURCES += [
'nsIXULOverlayProvider.idl',
]
@ -26,16 +24,19 @@ if CONFIG['MOZ_XUL']:
UNIFIED_SOURCES += [
'nsXULCommandDispatcher.cpp',
'nsXULContentSink.cpp',
'nsXULContentUtils.cpp',
'nsXULElement.cpp',
'nsXULPopupListener.cpp',
'nsXULPrototypeCache.cpp',
'nsXULPrototypeDocument.cpp',
'nsXULSortService.cpp',
'XULDocument.cpp',
]
XPIDL_SOURCES += [
'nsIController.idl',
'nsIControllers.idl',
'nsIXULSortService.idl',
]
XPIDL_MODULE = 'xul'
@ -50,7 +51,6 @@ LOCAL_INCLUDES += [
'/dom/html',
'/dom/xbl',
'/dom/xml',
'/dom/xul/templates',
'/layout/base',
'/layout/generic',
'/layout/style',

View File

@ -53,19 +53,6 @@ public:
*/
NS_IMETHOD RemoveSubtreeFromDocument(nsIContent* aElement) = 0;
/**
* Attach a XUL template builder to the specified content node.
* @param aBuilder the template builder to attach, or null if
* the builder is to be removed.
*/
NS_IMETHOD SetTemplateBuilderFor(nsIContent* aContent, nsIXULTemplateBuilder* aBuilder) = 0;
/**
* Retrieve the XUL template builder that's attached to a content
* node.
*/
NS_IMETHOD GetTemplateBuilderFor(nsIContent* aContent, nsIXULTemplateBuilder** aResult) = 0;
/**
* This is invoked whenever the prototype for this document is loaded
* and should be walked, regardless of whether the XUL cache is

View File

@ -0,0 +1,158 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/*
A package of routines shared by the XUL content code.
*/
#include "mozilla/ArrayUtils.h"
#include "nsCollationCID.h"
#include "nsCOMPtr.h"
#include "nsIContent.h"
#include "nsICollation.h"
#include "nsIDocument.h"
#include "nsIDOMElement.h"
#include "nsIDOMXULCommandDispatcher.h"
#include "nsIDOMXULDocument.h"
#include "nsIRDFService.h"
#include "nsIServiceManager.h"
#include "nsXULContentUtils.h"
#include "nsLayoutCID.h"
#include "nsRDFCID.h"
#include "nsString.h"
#include "nsGkAtoms.h"
using namespace mozilla;
//------------------------------------------------------------------------
nsIRDFService* nsXULContentUtils::gRDF;
nsICollation *nsXULContentUtils::gCollation;
//------------------------------------------------------------------------
// Constructors n' stuff
//
nsresult
nsXULContentUtils::Init()
{
static NS_DEFINE_CID(kRDFServiceCID, NS_RDFSERVICE_CID);
nsresult rv = CallGetService(kRDFServiceCID, &gRDF);
if (NS_FAILED(rv)) {
return rv;
}
return NS_OK;
}
nsresult
nsXULContentUtils::Finish()
{
NS_IF_RELEASE(gRDF);
NS_IF_RELEASE(gCollation);
return NS_OK;
}
nsICollation*
nsXULContentUtils::GetCollation()
{
if (!gCollation) {
nsCOMPtr<nsICollationFactory> colFactory =
do_CreateInstance(NS_COLLATIONFACTORY_CONTRACTID);
if (colFactory) {
DebugOnly<nsresult> rv = colFactory->CreateCollation(&gCollation);
NS_ASSERTION(NS_SUCCEEDED(rv),
"couldn't create collation instance");
} else
NS_ERROR("couldn't create instance of collation factory");
}
return gCollation;
}
//------------------------------------------------------------------------
//
nsresult
nsXULContentUtils::FindChildByTag(nsIContent* aElement,
int32_t aNameSpaceID,
nsAtom* aTag,
Element** aResult)
{
for (nsIContent* child = aElement->GetFirstChild();
child;
child = child->GetNextSibling()) {
if (child->IsElement() &&
child->NodeInfo()->Equals(aTag, aNameSpaceID)) {
NS_ADDREF(*aResult = child->AsElement());
return NS_OK;
}
}
*aResult = nullptr;
return NS_RDF_NO_VALUE; // not found
}
nsresult
nsXULContentUtils::SetCommandUpdater(nsIDocument* aDocument, Element* aElement)
{
// Deal with setting up a 'commandupdater'. Pulls the 'events' and
// 'targets' attributes off of aElement, and adds it to the
// document's command dispatcher.
NS_PRECONDITION(aDocument != nullptr, "null ptr");
if (! aDocument)
return NS_ERROR_NULL_POINTER;
NS_PRECONDITION(aElement != nullptr, "null ptr");
if (! aElement)
return NS_ERROR_NULL_POINTER;
nsresult rv;
nsCOMPtr<nsIDOMXULDocument> xuldoc = do_QueryInterface(aDocument);
NS_ASSERTION(xuldoc != nullptr, "not a xul document");
if (! xuldoc)
return NS_ERROR_UNEXPECTED;
nsCOMPtr<nsIDOMXULCommandDispatcher> dispatcher;
rv = xuldoc->GetCommandDispatcher(getter_AddRefs(dispatcher));
NS_ASSERTION(NS_SUCCEEDED(rv), "unable to get dispatcher");
if (NS_FAILED(rv)) return rv;
NS_ASSERTION(dispatcher != nullptr, "no dispatcher");
if (! dispatcher)
return NS_ERROR_UNEXPECTED;
nsAutoString events;
aElement->GetAttr(kNameSpaceID_None, nsGkAtoms::events, events);
if (events.IsEmpty())
events.Assign('*');
nsAutoString targets;
aElement->GetAttr(kNameSpaceID_None, nsGkAtoms::targets, targets);
if (targets.IsEmpty())
targets.Assign('*');
nsCOMPtr<nsIDOMElement> domelement = do_QueryInterface(aElement);
NS_ASSERTION(domelement != nullptr, "not a DOM element");
if (! domelement)
return NS_ERROR_UNEXPECTED;
rv = dispatcher->AddCommandUpdater(domelement, events, targets);
if (NS_FAILED(rv)) return rv;
return NS_OK;
}

View File

@ -0,0 +1,66 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/*
A package of routines shared by the XUL content code.
*/
#ifndef nsXULContentUtils_h__
#define nsXULContentUtils_h__
#include "nsISupports.h"
class nsAtom;
class nsICollation;
class nsIContent;
class nsIDocument;
class nsIRDFService;
namespace mozilla {
namespace dom {
class Element;
}
}
class nsXULContentUtils
{
protected:
static nsIRDFService* gRDF;
static nsICollation *gCollation;
static bool gDisableXULCache;
static int
DisableXULCacheChangedCallback(const char* aPrefName, void* aClosure);
public:
static nsresult
Init();
static nsresult
Finish();
static nsresult
FindChildByTag(nsIContent *aElement,
int32_t aNameSpaceID,
nsAtom* aTag,
mozilla::dom::Element** aResult);
static nsresult
SetCommandUpdater(nsIDocument* aDocument, mozilla::dom::Element* aElement);
static nsIRDFService*
RDFService()
{
return gRDF;
}
static nsICollation*
GetCollation();
};
#endif // nsXULContentUtils_h__

View File

@ -33,9 +33,6 @@
#include "nsIObjectOutputStream.h"
#include "nsIPresShell.h"
#include "nsIPrincipal.h"
#include "nsIRDFCompositeDataSource.h"
#include "nsIRDFNode.h"
#include "nsIRDFService.h"
#include "nsIScriptContext.h"
#include "nsIScriptError.h"
#include "nsIScriptSecurityManager.h"
@ -45,11 +42,9 @@
#include "nsViewManager.h"
#include "nsIWidget.h"
#include "nsIXULDocument.h"
#include "nsIXULTemplateBuilder.h"
#include "nsLayoutCID.h"
#include "nsContentCID.h"
#include "mozilla/dom/Event.h"
#include "nsRDFCID.h"
#include "nsStyleConsts.h"
#include "nsString.h"
#include "nsXULControllers.h"
@ -70,11 +65,9 @@
#include "nsJSPrincipals.h"
#include "nsDOMAttributeMap.h"
#include "nsGkAtoms.h"
#include "nsXULContentUtils.h"
#include "nsNodeUtils.h"
#include "nsFrameLoader.h"
#include "mozilla/Logging.h"
#include "rdf.h"
#include "nsIControllers.h"
#include "nsAttrValueOrString.h"
#include "nsAttrValueInlines.h"
@ -332,11 +325,6 @@ nsXULElement::Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
aPreallocateChildren);
NS_ENSURE_SUCCESS(rv, rv);
// XXX TODO: set up RDF generic builder n' stuff if there is a
// 'datasources' attribute? This is really kind of tricky,
// because then we'd need to -selectively- copy children that
// -weren't- generated from RDF. Ugh. Forget it.
// Note that we're _not_ copying mControllers.
uint32_t count = mAttrsAndChildren.AttrCount();
@ -1336,54 +1324,6 @@ nsXULElement::PreHandleEvent(EventChainVisitor& aVisitor)
return nsStyledElement::PreHandleEvent(aVisitor);
}
// XXX This _should_ be an implementation method, _not_ publicly exposed :-(
already_AddRefed<nsIRDFResource>
nsXULElement::GetResource(ErrorResult& rv)
{
nsAutoString id;
GetAttr(kNameSpaceID_None, nsGkAtoms::ref, id);
if (id.IsEmpty()) {
GetAttr(kNameSpaceID_None, nsGkAtoms::id, id);
}
if (id.IsEmpty()) {
return nullptr;
}
nsCOMPtr<nsIRDFResource> resource;
rv = nsXULContentUtils::RDFService()->
GetUnicodeResource(id, getter_AddRefs(resource));
return resource.forget();
}
already_AddRefed<nsIRDFCompositeDataSource>
nsXULElement::GetDatabase()
{
nsCOMPtr<nsIXULTemplateBuilder> builder = GetBuilder();
if (!builder) {
return nullptr;
}
nsCOMPtr<nsIRDFCompositeDataSource> database;
builder->GetDatabase(getter_AddRefs(database));
return database.forget();
}
already_AddRefed<nsIXULTemplateBuilder>
nsXULElement::GetBuilder()
{
// XXX sXBL/XBL2 issue! Owner or current document?
nsCOMPtr<nsIXULDocument> xuldoc = do_QueryInterface(GetUncomposedDoc());
if (!xuldoc) {
return nullptr;
}
nsCOMPtr<nsIXULTemplateBuilder> builder;
xuldoc->GetTemplateBuilderFor(this, getter_AddRefs(builder));
return builder.forget();
}
//----------------------------------------------------------------------
// Implementation methods

View File

@ -22,10 +22,7 @@
#include "nsIDOMElement.h"
#include "nsIDOMXULElement.h"
#include "nsIDOMXULMultSelectCntrlEl.h"
#include "nsIRDFCompositeDataSource.h"
#include "nsIRDFResource.h"
#include "nsIURI.h"
#include "nsIXULTemplateBuilder.h"
#include "nsLayoutCID.h"
#include "nsAttrAndChildArray.h"
#include "nsGkAtoms.h"
@ -333,12 +330,11 @@ public:
// XUL element specific bits
enum {
XUL_ELEMENT_TEMPLATE_GENERATED = XUL_ELEMENT_FLAG_BIT(0),
XUL_ELEMENT_HAS_CONTENTMENU_LISTENER = XUL_ELEMENT_FLAG_BIT(1),
XUL_ELEMENT_HAS_POPUP_LISTENER = XUL_ELEMENT_FLAG_BIT(2)
XUL_ELEMENT_HAS_CONTENTMENU_LISTENER = XUL_ELEMENT_FLAG_BIT(0),
XUL_ELEMENT_HAS_POPUP_LISTENER = XUL_ELEMENT_FLAG_BIT(1)
};
ASSERT_NODE_FLAGS_SPACE(ELEMENT_TYPE_SPECIFIC_BITS_OFFSET + 3);
ASSERT_NODE_FLAGS_SPACE(ELEMENT_TYPE_SPECIFIC_BITS_OFFSET + 2);
#undef XUL_ELEMENT_FLAG_BIT
@ -397,15 +393,6 @@ public:
int32_t aModType) const override;
NS_IMETHOD_(bool) IsAttributeMapped(const nsAtom* aAttribute) const override;
// XUL element methods
/**
* The template-generated flag is used to indicate that a
* template-generated element has already had its children generated.
*/
void SetTemplateGenerated() { SetFlags(XUL_ELEMENT_TEMPLATE_GENERATED); }
void ClearTemplateGenerated() { UnsetFlags(XUL_ELEMENT_TEMPLATE_GENERATED); }
bool GetTemplateGenerated() { return HasFlag(XUL_ELEMENT_TEMPLATE_GENERATED); }
// nsIDOMNode
NS_FORWARD_NSIDOMNODE_TO_NSINODE
// And since that shadowed GetParentElement with the XPCOM
@ -636,14 +623,6 @@ public:
{
SetXULAttr(nsGkAtoms::top, aValue, rv);
}
void GetDatasources(DOMString& aValue) const
{
GetXULAttr(nsGkAtoms::datasources, aValue);
}
void SetDatasources(const nsAString& aValue, mozilla::ErrorResult& rv)
{
SetXULAttr(nsGkAtoms::datasources, aValue, rv);
}
void GetRef(DOMString& aValue) const
{
GetXULAttr(nsGkAtoms::ref, aValue);
@ -684,9 +663,6 @@ public:
{
SetXULBoolAttr(nsGkAtoms::allowevents, aAllowEvents);
}
already_AddRefed<nsIRDFCompositeDataSource> GetDatabase();
already_AddRefed<nsIXULTemplateBuilder> GetBuilder();
already_AddRefed<nsIRDFResource> GetResource(mozilla::ErrorResult& rv);
nsIControllers* GetControllers(mozilla::ErrorResult& rv);
// Note: this can only fail if the do_CreateInstance for the boxobject
// contact fails for some reason.

View File

@ -20,8 +20,6 @@
#include "nsWhitespaceTokenizer.h"
#include "nsXULSortService.h"
#include "nsXULElement.h"
#include "nsIXULTemplateBuilder.h"
#include "nsTemplateMatch.h"
#include "nsICollation.h"
#include "nsUnicharUtils.h"
@ -93,23 +91,8 @@ XULSortServiceImpl::GetItemsToSort(nsIContent *aContainer,
nsSortState* aSortState,
nsTArray<contentSortInfo>& aSortItems)
{
// if there is a template attached to the sort node, use the builder to get
// the items to be sorted
RefPtr<nsXULElement> element = nsXULElement::FromContent(aContainer);
if (element) {
nsCOMPtr<nsIXULTemplateBuilder> builder = element->GetBuilder();
if (builder) {
nsresult rv = builder->GetQueryProcessor(getter_AddRefs(aSortState->processor));
if (NS_FAILED(rv) || !aSortState->processor)
return rv;
return GetTemplateItemsToSort(aContainer, builder, aSortState, aSortItems);
}
}
// if there is no template builder, just get the children. For trees,
// get the treechildren element as use that as the parent
// Get the children. For trees, get the treechildren element and
// use that as the parent
RefPtr<Element> treechildren;
if (aContainer->NodeInfo()->Equals(nsGkAtoms::tree, kNameSpaceID_XUL)) {
nsXULContentUtils::FindChildByTag(aContainer,
@ -136,39 +119,6 @@ XULSortServiceImpl::GetItemsToSort(nsIContent *aContainer,
}
nsresult
XULSortServiceImpl::GetTemplateItemsToSort(nsIContent* aContainer,
nsIXULTemplateBuilder* aBuilder,
nsSortState* aSortState,
nsTArray<contentSortInfo>& aSortItems)
{
for (nsIContent* child = aContainer->GetFirstChild();
child;
child = child->GetNextSibling()) {
nsCOMPtr<nsIDOMElement> childnode = do_QueryInterface(child);
nsCOMPtr<nsIXULTemplateResult> result;
nsresult rv = aBuilder->GetResultForContent(childnode, getter_AddRefs(result));
NS_ENSURE_SUCCESS(rv, rv);
if (result) {
contentSortInfo* cinfo = aSortItems.AppendElement();
if (!cinfo)
return NS_ERROR_OUT_OF_MEMORY;
cinfo->content = child;
cinfo->result = result;
}
else if (!aContainer->IsXULElement(nsGkAtoms::_template)) {
rv = GetTemplateItemsToSort(child, aBuilder, aSortState, aSortItems);
NS_ENSURE_SUCCESS(rv, rv);
}
}
return NS_OK;
}
int
testSortCallback(const void *data1, const void *data2, void *privateData)
{
@ -179,37 +129,21 @@ testSortCallback(const void *data1, const void *data2, void *privateData)
int32_t sortOrder = 0;
if (sortState->direction == nsSortState_natural && sortState->processor) {
// sort in natural order
sortState->processor->CompareResults(left->result, right->result,
nullptr, sortState->sortHints, &sortOrder);
}
else {
int32_t length = sortState->sortKeys.Length();
for (int32_t t = 0; t < length; t++) {
// for templates, use the query processor to do sorting
if (sortState->processor) {
sortState->processor->CompareResults(left->result, right->result,
sortState->sortKeys[t],
sortState->sortHints, &sortOrder);
if (sortOrder)
break;
} else {
// no template, so just compare attributes. Ignore namespaces for now.
nsAutoString leftstr, rightstr;
if (left->content->IsElement()) {
left->content->AsElement()->GetAttr(kNameSpaceID_None,
sortState->sortKeys[t],
leftstr);
}
if (right->content->IsElement()) {
right->content->AsElement()->GetAttr(kNameSpaceID_None,
sortState->sortKeys[t], rightstr);
}
sortOrder = XULSortServiceImpl::CompareValues(leftstr, rightstr, sortState->sortHints);
}
int32_t length = sortState->sortKeys.Length();
for (int32_t t = 0; t < length; t++) {
// compare attributes. Ignore namespaces for now.
nsAutoString leftstr, rightstr;
if (left->content->IsElement()) {
left->content->AsElement()->GetAttr(kNameSpaceID_None,
sortState->sortKeys[t],
leftstr);
}
if (right->content->IsElement()) {
right->content->AsElement()->GetAttr(kNameSpaceID_None,
sortState->sortKeys[t], rightstr);
}
sortOrder = XULSortServiceImpl::CompareValues(leftstr, rightstr, sortState->sortHints);
}
if (sortState->direction == nsSortState_descending)
@ -489,7 +423,6 @@ XULSortServiceImpl::Sort(nsIDOMNode* aNode,
SetSortHints(sortNode, &sortState);
rv = SortContainer(sortNode, &sortState);
sortState.processor = nullptr; // don't hang on to this reference
return rv;
}

View File

@ -4,18 +4,16 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/*
This sort service is used to sort template built content or content by attribute.
This sort service is used to sort content by attribute.
*/
#ifndef nsXULTemplateResultSetRDF_h
#define nsXULTemplateResultSetRDF_h
#ifndef nsXULSortService_h
#define nsXULSortService_h
#include "nsCOMPtr.h"
#include "nsCOMArray.h"
#include "nsTArray.h"
#include "nsIContent.h"
#include "nsIXULTemplateResult.h"
#include "nsIXULTemplateQueryProcessor.h"
#include "nsIXULSortService.h"
#include "nsCycleCollectionParticipant.h"
@ -32,7 +30,6 @@ struct nsSortState
MOZ_INIT_OUTSIDE_CTOR bool invertSort;
MOZ_INIT_OUTSIDE_CTOR bool inbetweenSeparatorSort;
MOZ_INIT_OUTSIDE_CTOR bool sortStaticsLast;
MOZ_INIT_OUTSIDE_CTOR bool isContainerRDFSeq;
uint32_t sortHints;
@ -40,19 +37,16 @@ struct nsSortState
nsAutoString sort;
nsTArray<RefPtr<nsAtom>> sortKeys;
nsCOMPtr<nsIXULTemplateQueryProcessor> processor;
nsCOMPtr<nsIContent> lastContainer;
MOZ_INIT_OUTSIDE_CTOR bool lastWasFirst, lastWasLast;
nsSortState()
: initialized(false),
isContainerRDFSeq(false),
sortHints(0)
{
}
void Traverse(nsCycleCollectionTraversalCallback &cb) const
{
cb.NoteXPCOMChild(processor);
cb.NoteXPCOMChild(lastContainer);
}
};
@ -61,12 +55,10 @@ struct nsSortState
struct contentSortInfo {
nsCOMPtr<nsIContent> content;
nsCOMPtr<nsIContent> parent;
nsCOMPtr<nsIXULTemplateResult> result;
void swap(contentSortInfo& other)
{
content.swap(other.content);
parent.swap(other.parent);
result.swap(other.result);
}
};
@ -122,15 +114,6 @@ public:
nsSortState* aSortState,
nsTArray<contentSortInfo>& aSortItems);
/**
* Get the list of items to sort for template built content
*/
nsresult
GetTemplateItemsToSort(nsIContent* aContainer,
nsIXULTemplateBuilder* aBuilder,
nsSortState* aSortState,
nsTArray<contentSortInfo>& aSortItems);
/**
* Sort a container using the supplied sort state details.
*/
@ -171,4 +154,4 @@ public:
uint32_t aSortHints);
};
#endif
#endif // nsXULSortService_h

View File

@ -1,13 +0,0 @@
<?xml version="1.0"?>
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:m="urn:foo#">
<rdf:Seq about="urn:x-rec:1">
<rdf:li rdf:resource="urn:x-rec:2"/>
</rdf:Seq>
<rdf:Seq about="urn:x-rec:2">
<rdf:li rdf:resource="urn:x-rec:3"/>
</rdf:Seq>
<rdf:Seq about="urn:x-rec:3">
<rdf:li rdf:resource="urn:x-rec:1"/>
</rdf:Seq>
</rdf:RDF>

View File

@ -1,28 +0,0 @@
<?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
<window id="child-iterate-recurse"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<vbox flex="1" style="overflow: auto;">
<vbox datasources="257752-1-recursion.rdf" ref="urn:x-rec:1">
<template>
<rule>
<conditions>
<content uri="?uri"/>
<member container="?uri" child="?child"/>
</conditions>
<action>
<vbox uri="?child" style="border: 1px solid grey; margin: 1em;">
<label value="hi"/>
</vbox>
</action>
</rule>
</template>
</vbox>
</vbox>
</window>

View File

@ -1,20 +0,0 @@
<?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<script>
function rM(q1) { q1.parentNode.removeChild(q1); }
function init2()
{
rM(document.getElementById("t"));
}
window.addEventListener("load", init2, false);
</script>
<foo id="t" datasources="1.rdf" />
</window>

View File

@ -1,13 +0,0 @@
<?xml version="1.0"?>
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:s="urn:squarefree:a1:">
<rdf:Description about="urn:root">
<s:grapes>
<rdf:Bag>
<rdf:li>
<rdf:Description/>
</rdf:li>
</rdf:Bag>
</s:grapes>
</rdf:Description>
</rdf:RDF>

View File

@ -1,22 +0,0 @@
<?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<foo id="foo" datasources="330012-1.rdf" ref="urn:root">
<template>
<rule>
<conditions>
<content uri="?root"/>
<triple subject="?root"
predicate="urn:squarefree:a1:grapes"
object="?lalala"/>
<member container="?grapes" child="?grape"/>
</conditions>
<action>
<bar uri="?grape"/>
</action>
</rule>
</template>
</foo>
</window>

View File

@ -1,7 +0,0 @@
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<box id="b">
<box id="a" template="b"/>
<triple/>
</box>
<box datasources="" observes="a" ref="bbb"/>
</window>

View File

@ -1,14 +0,0 @@
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<hbox datasources="nosuch.rdf" ref="urn:root">
<template>
<rule>
<conditions>
<triple subject="?a"/>
</conditions>
<action>
<vbox uri="?b"/>
</action>
</rule>
</template>
</hbox>
</window>

View File

@ -1 +0,0 @@
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" onload="document.getElementById('foo').removeAttribute('ref');"><foo id="foo" datasources="nosuch.rdf" ref="urn:root"><template/></foo></window>

View File

@ -1 +0,0 @@
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"><hbox datasources="u"/></window>

View File

@ -1,7 +0,0 @@
load 257752-1-recursion.xul
load 329884-1.xul
skip-if(winWidget) load 330012-1.xul # bug 742455
load 404346-1.xul
load 415019-1.xul
load 417840-1.xul
load 424418-1.xul

View File

@ -1,64 +0,0 @@
# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=python:
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
MOCHITEST_CHROME_MANIFESTS += ['tests/chrome/chrome.ini']
XPIDL_SOURCES += [
'nsIXULBuilderListener.idl',
'nsIXULSortService.idl',
'nsIXULTemplateBuilder.idl',
'nsIXULTemplateQueryProcessor.idl',
'nsIXULTemplateResult.idl',
'nsIXULTemplateRuleFilter.idl',
]
XPIDL_MODULE = 'xultmpl'
EXPORTS += [
'nsTreeRows.h',
'nsXULTemplateBuilder.h',
'nsXULTreeBuilder.h',
]
UNIFIED_SOURCES += [
'nsContentSupportMap.cpp',
'nsContentTestNode.cpp',
'nsInstantiationNode.cpp',
'nsRDFBinding.cpp',
'nsRDFConInstanceTestNode.cpp',
'nsRDFConMemberTestNode.cpp',
'nsRDFPropertyTestNode.cpp',
'nsRDFQuery.cpp',
'nsResourceSet.cpp',
'nsRuleNetwork.cpp',
'nsTemplateMatch.cpp',
'nsTemplateRule.cpp',
'nsTreeRows.cpp',
'nsXMLBinding.cpp',
'nsXULContentBuilder.cpp',
'nsXULContentUtils.cpp',
'nsXULSortService.cpp',
'nsXULTemplateBuilder.cpp',
'nsXULTemplateQueryProcessorRDF.cpp',
'nsXULTemplateQueryProcessorStorage.cpp',
'nsXULTemplateQueryProcessorXML.cpp',
'nsXULTemplateResultRDF.cpp',
'nsXULTemplateResultSetRDF.cpp',
'nsXULTemplateResultStorage.cpp',
'nsXULTemplateResultXML.cpp',
'nsXULTreeBuilder.cpp',
]
LOCAL_INCLUDES += [
'/dom/base',
'/dom/xul',
'/layout/xul/tree/',
]
FINAL_LIBRARY = 'xul'
if CONFIG['CC_TYPE'] in ('clang', 'gcc'):
CXXFLAGS += ['-Wno-error=shadow']

View File

@ -1,18 +0,0 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsContentSupportMap.h"
#include "nsXULElement.h"
void
nsContentSupportMap::Remove(nsIContent* aElement)
{
nsIContent* child = aElement;
do {
mMap.Remove(child);
child = child->GetNextNode(aElement);
} while(child);
}

View File

@ -1,62 +0,0 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef nsContentSupportMap_h__
#define nsContentSupportMap_h__
#include "PLDHashTable.h"
#include "nsTemplateMatch.h"
/**
* The nsContentSupportMap maintains a mapping from a "resource element"
* in the content tree to the nsTemplateMatch that was used to instantiate it. This
* is necessary to allow the XUL content to be built lazily. Specifically,
* when building "resumes" on a partially-built content element, the builder
* will walk upwards in the content tree to find the first element with an
* 'id' attribute. This element is assumed to be the "resource element",
* and allows the content builder to access the nsTemplateMatch (variable assignments
* and rule information).
*/
class nsContentSupportMap {
public:
nsContentSupportMap() : mMap(PLDHashTable::StubOps(), sizeof(Entry)) { }
~nsContentSupportMap() { }
nsresult Put(nsIContent* aElement, nsTemplateMatch* aMatch) {
PLDHashEntryHdr* hdr = mMap.Add(aElement, mozilla::fallible);
if (!hdr)
return NS_ERROR_OUT_OF_MEMORY;
Entry* entry = static_cast<Entry*>(hdr);
NS_ASSERTION(entry->mMatch == nullptr, "over-writing entry");
entry->mContent = aElement;
entry->mMatch = aMatch;
return NS_OK;
}
bool Get(nsIContent* aElement, nsTemplateMatch** aMatch) {
PLDHashEntryHdr* hdr = mMap.Search(aElement);
if (!hdr)
return false;
Entry* entry = static_cast<Entry*>(hdr);
*aMatch = entry->mMatch;
return true;
}
void Remove(nsIContent* aElement);
void Clear() { mMap.Clear(); }
protected:
PLDHashTable mMap;
struct Entry : public PLDHashEntryHdr {
nsIContent* mContent;
nsTemplateMatch* mMatch;
};
};
#endif

View File

@ -1,90 +0,0 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsContentTestNode.h"
#include "nsIRDFResource.h"
#include "nsAtom.h"
#include "nsIDOMElement.h"
#include "nsXULContentUtils.h"
#include "nsIXULTemplateResult.h"
#include "nsIXULTemplateBuilder.h"
#include "nsXULTemplateQueryProcessorRDF.h"
#include "mozilla/Logging.h"
using mozilla::LogLevel;
extern mozilla::LazyLogModule gXULTemplateLog;
nsContentTestNode::nsContentTestNode(nsXULTemplateQueryProcessorRDF* aProcessor,
nsAtom* aRefVariable)
: TestNode(nullptr),
mProcessor(aProcessor),
mDocument(nullptr),
mRefVariable(aRefVariable),
mTag(nullptr)
{
if (MOZ_LOG_TEST(gXULTemplateLog, LogLevel::Debug)) {
nsAutoString tag(NS_LITERAL_STRING("(none)"));
if (mTag)
mTag->ToString(tag);
nsAutoString refvar(NS_LITERAL_STRING("(none)"));
if (aRefVariable)
aRefVariable->ToString(refvar);
MOZ_LOG(gXULTemplateLog, LogLevel::Debug,
("nsContentTestNode[%p]: ref-var=%s tag=%s",
this, NS_ConvertUTF16toUTF8(refvar).get(),
NS_ConvertUTF16toUTF8(tag).get()));
}
}
nsresult
nsContentTestNode::FilterInstantiations(InstantiationSet& aInstantiations,
bool* aCantHandleYet) const
{
if (aCantHandleYet)
*aCantHandleYet = false;
return NS_OK;
}
nsresult
nsContentTestNode::Constrain(InstantiationSet& aInstantiations)
{
// contrain the matches to those that have matched in the template builder
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;
bool hasRefBinding = inst->mAssignments.GetAssignmentFor(mRefVariable,
getter_AddRefs(refValue));
if (hasRefBinding) {
nsCOMPtr<nsIRDFResource> refResource = do_QueryInterface(refValue);
if (refResource) {
bool generated;
rv = builder->HasGeneratedContent(refResource, mTag, &generated);
if (NS_FAILED(rv)) return rv;
if (generated)
continue;
}
}
aInstantiations.Erase(inst--);
}
return NS_OK;
}

View File

@ -1,48 +0,0 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef nsContentTestNode_h__
#define nsContentTestNode_h__
#include "mozilla/Attributes.h"
#include "nscore.h"
#include "nsRuleNetwork.h"
#include "nsAtom.h"
#include "nsIDOMDocument.h"
class nsXULTemplateQueryProcessorRDF;
/**
* 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(nsXULTemplateQueryProcessorRDF* aProcessor,
nsAtom* aContentVariable);
virtual nsresult FilterInstantiations(InstantiationSet& aInstantiations,
bool* aCantHandleYet) const override;
nsresult
Constrain(InstantiationSet& aInstantiations) override;
void SetTag(nsAtom* aTag, nsIDOMDocument* aDocument)
{
mTag = aTag;
mDocument = aDocument;
}
protected:
nsXULTemplateQueryProcessorRDF *mProcessor;
nsIDOMDocument* mDocument;
RefPtr<nsAtom> mRefVariable;
RefPtr<nsAtom> mTag;
};
#endif // nsContentTestNode_h__

View File

@ -1,28 +0,0 @@
/* -*- Mode: idl; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsISupports.idl"
interface nsIXULTemplateBuilder;
// An nsIXULBuilderListener object is a listener that will be notified
// when a template builder rebuilds its content.
[scriptable, uuid(ac46be8f-c863-4c23-84a2-d0fcc8dfa9f4)]
interface nsIXULBuilderListener: nsISupports {
/**
* Called before a template builder rebuilds its content.
* @param aBuilder the template builder that rebuilds the content.
*/
void willRebuild(in nsIXULTemplateBuilder aBuilder);
/**
* Called after a template builder has rebuilt its content.
* @param aBuilder the template builder that has rebuilt the content.
*/
void didRebuild(in nsIXULTemplateBuilder aBuilder);
};

View File

@ -1,407 +0,0 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "domstubs.idl"
interface nsIContent;
interface nsIXULBuilderListener;
interface nsIXULTemplateResult;
interface nsIXULTemplateRuleFilter;
interface nsIXULTemplateQueryProcessor;
interface nsIRDFResource;
interface nsIRDFCompositeDataSource;
interface nsIDOMDataTransfer;
%{C++
class nsAtom;
%}
[ptr] native nsAtomPtr(nsAtom);
[ptr] native Element (mozilla::dom::Element);
/**
* 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(A583B676-5B02-4F9C-A0C9-CB850CB99818)]
interface nsIXULTemplateBuilder : nsISupports
{
/**
* The root node in the DOM to which this builder is attached.
*/
readonly attribute nsIDOMElement root;
/**
* The opaque datasource object that is used for the template. This object
* is created by the getDataSource method of the query processor. May be
* null if the datasource has not been loaded yet. Set this attribute to
* use a different datasource and rebuild the template.
*
* For an RDF datasource, this will be the same as the database. For XML
* this will be the nsIDOMNode for the datasource document or node for
* an inline reference (such as #name). Other query processors may use
* other types for the datasource.
*/
attribute nsISupports datasource;
/**
* The composite datasource that the template builder observes
* and uses to create content. This is used only for RDF queries and is
* maintained for backwards compatibility. It will be the same object as
* the datasource property. For non-RDF queries, it will always be null.
*/
readonly attribute nsIRDFCompositeDataSource database;
/**
* 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;
/**
* The query processor used to generate results.
*/
[noscript] readonly attribute nsIXULTemplateQueryProcessor queryProcessor;
/**
* 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();
/**
* Reload any of our RDF datasources that support nsIRDFRemoteDatasource.
*
* @note This is a temporary hack so that remote-XUL authors can
* reload remote datasources. When RDF becomes remote-scriptable,
* this will no longer be necessary.
*/
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);
/**
* Retrieve the result corresponding to a generated element, or null is
* there isn't one.
*
* @param aContent element to result the result of
*/
nsIXULTemplateResult getResultForContent(in nsIDOMElement aElement);
/**
* 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
*/
[noscript] boolean hasGeneratedContent(in nsIRDFResource aNode,
in nsAtomPtr 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);
/**
* Invoked lazily by a XUL element that needs its child content built.
* If aForceCreation is true, then the contents of an element will be
* generated even if it is closed. If false, the element will only
* generate its contents if it is open. This behaviour is used with menus.
*/
[noscript] void createContents(in Element aElement,
in boolean aForceCreation);
/**
* Add a listener to this template builder. The template builder
* holds a strong reference to the listener.
*/
void addListener(in nsIXULBuilderListener aListener);
/**
* Remove a listener from this template builder.
*/
void removeListener(in nsIXULBuilderListener aListener);
};
/**
* nsIXULTreeBuilderObserver
* This interface allows clients of the XULTreeBuilder to define domain
* specific handling of specific nsITreeView methods that
* XULTreeBuilder does not implement.
*/
[scriptable, uuid(57CED9A7-EC0B-4A0E-8AEB-5DA32EBE951C)]
interface nsIXULTreeBuilderObserver : nsISupports
{
const long DROP_BEFORE = -1;
const long DROP_ON = 0;
const long DROP_AFTER = 1;
/**
* Methods used by the drag feedback code to determine if a drag is allowable at
* the current location. To get the behavior where drops are only allowed on
* items, such as the mailNews folder pane, always return false whe
* the orientation is not DROP_ON.
*/
boolean canDrop(in long index, in long orientation, in nsIDOMDataTransfer dataTransfer);
/**
* Called when the user drops something on this view. The |orientation| param
* specifies before/on/after the given |row|.
*/
void onDrop(in long row, in long orientation, in nsIDOMDataTransfer dataTransfer);
/**
* Called when an item is opened or closed.
*/
void onToggleOpenState (in long index);
/**
* Called when a header is clicked.
*/
void onCycleHeader(in wstring colID, in nsIDOMElement elt);
/**
* Called when a cell in a non-selectable cycling column (e.g.
* unread/flag/etc.) is clicked.
*/
void onCycleCell(in long row, in wstring colID);
/**
* Called when selection in the tree changes
*/
void onSelectionChanged();
/**
* A command API that can be used to invoke commands on the selection.
* The tree will automatically invoke this method when certain keys
* are pressed. For example, when the DEL key is pressed, performAction
* will be called with the "delete" string.
*/
void onPerformAction(in wstring action);
/**
* A command API that can be used to invoke commands on a specific row.
*/
void onPerformActionOnRow(in wstring action, in long row);
/**
* A command API that can be used to invoke commands on a specific cell.
*/
void onPerformActionOnCell(in wstring action, in long row, in wstring colID);
};
[scriptable, uuid(06b31b15-ebf5-4e74-a0e2-6bc0a18a3969)]
interface nsIXULTreeBuilder : nsISupports
{
/**
* Retrieve the RDF resource associated with the specified row.
*/
nsIRDFResource getResourceAtIndex(in long aRowIndex);
/**
* Retrieve the index associated with specified RDF resource.
*/
long getIndexOfResource(in nsIRDFResource resource);
/**
* Add a Tree Builder Observer to handle Tree View
* methods that the base builder does not implement.
*/
void addObserver(in nsIXULTreeBuilderObserver aObserver);
/**
* Remove an Tree Builder Observer.
*/
void removeObserver(in nsIXULTreeBuilderObserver aObserver);
/**
* Sort the contents of the tree using the specified column.
*/
void sort(in nsIDOMElement aColumnElement);
};

View File

@ -1,280 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "domstubs.idl"
interface nsIArray;
interface nsISimpleEnumerator;
interface nsIXULTemplateResult;
interface nsIXULTemplateRuleFilter;
interface nsIXULTemplateBuilder;
%{C++
class nsAtom;
%}
[ptr] native nsAtomPtr(nsAtom);
/**
* 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(C257573F-444F-468A-BA27-DE979DC55FE4)]
interface nsIXULTemplateQueryProcessor : nsISupports
{
/**
* Retrieve the datasource to use for the query processor. The list of
* datasources in a template is specified using the datasources attribute as
* a space separated list of URIs. This list is processed by the builder and
* supplied to the query processor in the aDataSources array as a list of
* nsIURI objects or nsIDOMNode objects. This method may return an object
* corresponding to these URIs and the builder will supply this object to
* other query processor methods. For example, for an XML source, the
* datasource might be an nsIDOMNode.
*
* All of these URIs are checked by the builder so it is safe to use them,
* however note that a URI that redirects may still needs to be checked to
* ensure that the document containing aRootNode may access it. This is the
* responsibility of the query processor if it needs to load the content of
* the URI.
*
* If the query processor needs to load the datasource asynchronously, it
* may set the aShouldDelayBuilding returned parameter to true to delay
* building the template content, and call the builder's Rebuild method when
* the data is available.
*
* @param aDataSources the list of nsIURI objects and/or nsIDOMNode objects
* @param aRootNode the root node the builder is attached to
* @param aIsTrusted true if the template is in a trusted document
* @param aBuilder the template builder
* @param aShouldDelayBuilding [out] whether the builder should wait to
* build the content or not
* @returns a datasource object
*/
nsISupports getDatasource(in nsIArray aDataSources,
in nsIDOMNode aRootNode,
in boolean aIsTrusted,
in nsIXULTemplateBuilder aBuilder,
out boolean aShouldDelayBuilding);
/**
* 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
*/
[noscript] nsISupports compileQuery(in nsIXULTemplateBuilder aBuilder,
in nsIDOMNode aQuery,
in nsAtomPtr aRefVariable,
in nsAtomPtr 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
*/
[noscript] void addBinding(in nsIDOMNode aRuleNode,
in nsAtomPtr aVar,
in nsAtomPtr 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.
*
* If the comparison variable is null, the results may be
* sorted in a natural order, for instance, based on the order the data in
* stored in the datasource.
*
* The sort hints are the flags in nsIXULSortService.
*
* 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
*/
[noscript] int32_t compareResults(in nsIXULTemplateResult aLeft,
in nsIXULTemplateResult aRight,
in nsAtomPtr aVar,
in unsigned long aSortHints);
};

View File

@ -1,120 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsISupports.idl"
interface nsIDOMNode;
interface nsIRDFResource;
%{C++
class nsAtom;
%}
[ptr] native nsAtomPtr(nsAtom);
/**
* 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(ebea0230-36fa-41b7-8e31-760806057965)]
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;
/**
* The type of the object. The predefined value 'separator' may be used
* for separators. Other values may be used for application specific
* purposes.
*/
readonly attribute AString type;
/**
* 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
*/
[noscript] AString getBindingFor(in nsAtomPtr 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
*/
[noscript] nsISupports getBindingObjectFor(in nsAtomPtr 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();
};

View File

@ -1,36 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#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);
};

View File

@ -1,83 +0,0 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsInstantiationNode.h"
#include "nsTemplateRule.h"
#include "nsXULTemplateQueryProcessorRDF.h"
#include "mozilla/Logging.h"
extern mozilla::LazyLogModule gXULTemplateLog;
nsInstantiationNode::nsInstantiationNode(nsXULTemplateQueryProcessorRDF* aProcessor,
nsRDFQuery* aQuery)
: mProcessor(aProcessor),
mQuery(aQuery)
{
MOZ_LOG(gXULTemplateLog, LogLevel::Debug,
("nsInstantiationNode[%p] query=%p", this, aQuery));
MOZ_COUNT_CTOR(nsInstantiationNode);
}
nsInstantiationNode::~nsInstantiationNode()
{
MOZ_COUNT_DTOR(nsInstantiationNode);
}
nsresult
nsInstantiationNode::Propagate(InstantiationSet& aInstantiations,
bool aIsUpdate, bool& aTakenInstantiations)
{
// 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;
aTakenInstantiations = false;
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));
InstantiationSet::ConstIterator last = aInstantiations.Last();
for (InstantiationSet::ConstIterator inst = aInstantiations.First(); inst != last; ++inst) {
nsAssignmentSet assignments = inst->mAssignments;
nsCOMPtr<nsIRDFNode> node;
assignments.GetAssignmentFor(mQuery->mMemberVariable,
getter_AddRefs(node));
if (node) {
nsCOMPtr<nsIRDFResource> resource = do_QueryInterface(node);
if (resource) {
RefPtr<nsXULTemplateResultRDF> nextresult =
new nsXULTemplateResultRDF(mQuery, *inst, resource);
if (! nextresult)
return NS_ERROR_OUT_OF_MEMORY;
rv = mProcessor->AddMemoryElements(*inst, nextresult);
if (NS_FAILED(rv))
return rv;
mProcessor->GetBuilder()->AddResult(nextresult, querynode);
}
}
}
}
else {
nsresult rv = mQuery->SetCachedResults(mProcessor, aInstantiations);
if (NS_SUCCEEDED(rv))
aTakenInstantiations = true;
}
return rv;
}

View File

@ -1,37 +0,0 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef nsInstantiationNode_h__
#define nsInstantiationNode_h__
#include "mozilla/Attributes.h"
#include "nsRuleNetwork.h"
#include "nsRDFQuery.h"
class nsXULTemplateQueryProcessorRDF;
/**
* A leaf-level node in the rule network. If any instantiations
* propagate to this node, then we know we've matched a rule.
*/
class nsInstantiationNode : public ReteNode
{
public:
nsInstantiationNode(nsXULTemplateQueryProcessorRDF* aProcessor,
nsRDFQuery* aRule);
~nsInstantiationNode();
// "downward" propagations
virtual nsresult Propagate(InstantiationSet& aInstantiations,
bool aIsUpdate, bool& aMatched) override;
protected:
nsXULTemplateQueryProcessorRDF* mProcessor;
nsRDFQuery* mQuery;
};
#endif // nsInstantiationNode_h__

View File

@ -1,265 +0,0 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#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(nsAtom* aVar, nsAtom* aRef, nsIRDFResource* aPredicate)
{
RDFBinding* newbinding = new RDFBinding(aRef, aPredicate, aVar);
if (mFirst) {
RDFBinding* binding = mFirst;
while (binding) {
// the binding is dependant on the calculation of a previous binding
if (binding->mSubjectVariable == aVar)
newbinding->mHasDependency = 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;
}
bool
RDFBindingSet::SyncAssignments(nsIRDFResource* aSubject,
nsIRDFResource* aPredicate,
nsIRDFNode* aTarget,
nsAtom* aMemberVariable,
nsXULTemplateResultRDF* aResult,
nsBindingValues& aBindingValues)
{
NS_ASSERTION(aBindingValues.GetBindingSet() == this,
"nsBindingValues not for this RDFBindingSet");
NS_PRECONDITION(aResult, "Must have result");
bool needSync = false;
nsCOMPtr<nsIRDFNode>* valuesArray = aBindingValues.ValuesArray();
if (!valuesArray)
return false;
RDFBinding* binding = mFirst;
int32_t 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 = true;
}
else {
aResult->GetAssignment(binding->mSubjectVariable, getter_AddRefs(value));
if (value == subjectnode) {
valuesArray[count] = aTarget;
needSync = 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;
}
}
int32_t
RDFBindingSet::LookupTargetIndex(nsAtom* aTargetVariable, RDFBinding** aBinding)
{
int32_t 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 = nullptr;
}
mBindings = nullptr;
}
nsresult
nsBindingValues::SetBindingSet(RDFBindingSet* aBindings)
{
ClearBindingSet();
int32_t count = aBindings->Count();
if (count) {
mValues = new nsCOMPtr<nsIRDFNode>[count];
mBindings = aBindings;
}
else {
mValues = nullptr;
}
return NS_OK;
}
void
nsBindingValues::GetAssignmentFor(nsXULTemplateResultRDF* aResult,
nsAtom* aVar,
nsIRDFNode** aValue)
{
*aValue = nullptr;
// 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;
int32_t 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));
if (subjectValue) {
nsCOMPtr<nsIRDFResource> subject = do_QueryInterface(subjectValue);
ds->GetTarget(subject, binding->mPredicate, true, aValue);
if (*aValue)
mValues[idx] = *aValue;
}
}
}
}
}
void
nsBindingValues::RemoveDependencies(nsIRDFResource* aSubject,
nsXULTemplateResultRDF* aResult)
{
if (mBindings)
mBindings->RemoveDependencies(aSubject, aResult);
}

View File

@ -1,216 +0,0 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef nsRDFBinding_h__
#define nsRDFBinding_h__
#include "nsAtom.h"
#include "nsIRDFResource.h"
#include "nsISupportsImpl.h"
class nsXULTemplateResultRDF;
class nsBindingValues;
/*
* Classes related to storing bindings for RDF handling.
*/
/*
* a <binding> descriptors
*/
class RDFBinding {
public:
RefPtr<nsAtom> mSubjectVariable;
nsCOMPtr<nsIRDFResource> mPredicate;
RefPtr<nsAtom> mTargetVariable;
// indicates whether a binding is dependant on the result from a
// previous binding
bool mHasDependency;
RDFBinding* mNext;
private:
friend class RDFBindingSet;
RDFBinding(nsAtom* aSubjectVariable,
nsIRDFResource* aPredicate,
nsAtom* aTargetVariable)
: mSubjectVariable(aSubjectVariable),
mPredicate(aPredicate),
mTargetVariable(aTargetVariable),
mHasDependency(false),
mNext(nullptr)
{
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 final
{
private:
// Private destructor, to discourage deletion outside of Release():
~RDFBindingSet();
// the number of bindings
int32_t mCount;
// pointer to the first binding in a linked list
RDFBinding* mFirst;
public:
RDFBindingSet()
: mCount(0),
mFirst(nullptr)
{
MOZ_COUNT_CTOR(RDFBindingSet);
}
NS_INLINE_DECL_REFCOUNTING(RDFBindingSet)
int32_t Count() const { return mCount; }
/*
* Add a binding (aRef -> aPredicate -> aVar) to the set
*/
nsresult
AddBinding(nsAtom* aVar, nsAtom* 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
*/
bool
SyncAssignments(nsIRDFResource* aSubject,
nsIRDFResource* aPredicate,
nsIRDFNode* aTarget,
nsAtom* 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.
*/
int32_t
LookupTargetIndex(nsAtom* 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
RefPtr<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(nullptr),
mValues(nullptr)
{
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,
nsAtom* aVar,
nsIRDFNode** aValue);
/*
* Remove depenedencies the bindings have on particular resources
*/
void
RemoveDependencies(nsIRDFResource* aSubject,
nsXULTemplateResultRDF* aResult);
};
#endif // nsRDFBinding_h__

View File

@ -1,281 +0,0 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsIComponentManager.h"
#include "nsIRDFContainer.h"
#include "nsIRDFContainerUtils.h"
#include "nsIServiceManager.h"
#include "nsRDFCID.h"
#include "nsRDFConInstanceTestNode.h"
#include "nsResourceSet.h"
#include "mozilla/Logging.h"
#include "nsXULContentUtils.h"
using mozilla::LogLevel;
extern mozilla::LazyLogModule gXULTemplateLog;
static const char*
TestToString(nsRDFConInstanceTestNode::Test aTest) {
switch (aTest) {
case nsRDFConInstanceTestNode::eFalse: return "false";
case nsRDFConInstanceTestNode::eTrue: return "true";
case nsRDFConInstanceTestNode::eDontCare: return "dontcare";
}
return "?";
}
nsRDFConInstanceTestNode::nsRDFConInstanceTestNode(TestNode* aParent,
nsXULTemplateQueryProcessorRDF* aProcessor,
nsAtom* aContainerVariable,
Test aContainer,
Test aEmpty)
: nsRDFTestNode(aParent),
mProcessor(aProcessor),
mContainerVariable(aContainerVariable),
mContainer(aContainer),
mEmpty(aEmpty)
{
if (MOZ_LOG_TEST(gXULTemplateLog, LogLevel::Debug)) {
nsAutoCString props;
nsResourceSet& containmentProps = aProcessor->ContainmentProperties();
nsResourceSet::ConstIterator last = containmentProps.Last();
nsResourceSet::ConstIterator first = containmentProps.First();
nsResourceSet::ConstIterator iter;
for (iter = first; iter != last; ++iter) {
if (iter != first)
props += " ";
const char* str;
iter->GetValueConst(&str);
props += str;
}
nsAutoString cvar(NS_LITERAL_STRING("(none)"));
if (mContainerVariable)
mContainerVariable->ToString(cvar);
MOZ_LOG(gXULTemplateLog, LogLevel::Debug,
("nsRDFConInstanceTestNode[%p]: parent=%p member-props=(%s) container-var=%s container=%s empty=%s",
this,
aParent,
props.get(),
NS_ConvertUTF16toUTF8(cvar).get(),
TestToString(aContainer),
TestToString(aEmpty)));
}
}
nsresult
nsRDFConInstanceTestNode::FilterInstantiations(InstantiationSet& aInstantiations,
bool* aCantHandleYet) const
{
nsresult rv;
if (aCantHandleYet)
*aCantHandleYet = false;
nsCOMPtr<nsIRDFContainerUtils> rdfc
= do_GetService("@mozilla.org/rdf/container-utils;1");
if (! rdfc)
return NS_ERROR_FAILURE;
nsIRDFDataSource* ds = mProcessor->GetDataSource();
InstantiationSet::Iterator last = aInstantiations.Last();
for (InstantiationSet::Iterator inst = aInstantiations.First(); inst != last; ++inst) {
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;
}
if (MOZ_LOG_TEST(gXULTemplateLog, LogLevel::Debug)) {
const char* container = "(unbound)";
valueres->GetValueConst(&container);
MOZ_LOG(gXULTemplateLog, LogLevel::Debug,
("nsRDFConInstanceTestNode[%p]::FilterInstantiations() container=[%s]",
this, container));
}
nsCOMPtr<nsIRDFContainer> rdfcontainer;
bool isRDFContainer;
rv = rdfc->IsContainer(ds, valueres, &isRDFContainer);
if (NS_FAILED(rv)) return rv;
if (mEmpty != eDontCare || mContainer != eDontCare) {
Test empty = eDontCare;
Test container = eDontCare;
if (isRDFContainer) {
// It's an RDF container. Use the container utilities
// to deduce what's in it.
container = eTrue;
// XXX should cache the factory
rdfcontainer = do_CreateInstance("@mozilla.org/rdf/container;1", &rv);
if (NS_FAILED(rv)) return rv;
rv = rdfcontainer->Init(ds, valueres);
if (NS_FAILED(rv)) return rv;
int32_t count;
rv = rdfcontainer->GetCount(&count);
if (NS_FAILED(rv)) return rv;
empty = (count == 0) ? eTrue : eFalse;
} else {
empty = eTrue;
container = eFalse;
// First do the simple check of finding some outward
// arcs; there should be only a few containment arcs, so this can
// save us time from dealing with an iterator later on
nsResourceSet& containmentProps = mProcessor->ContainmentProperties();
for (nsResourceSet::ConstIterator property = containmentProps.First();
property != containmentProps.Last();
++property) {
nsCOMPtr<nsIRDFNode> target;
rv = ds->GetTarget(valueres, *property, true, getter_AddRefs(target));
if (NS_FAILED(rv)) return rv;
if (target != nullptr) {
// bingo. we found one.
empty = eFalse;
container = eTrue;
break;
}
}
// if we still don't think its a container, but we
// want to know for sure whether it is or not, we need
// to check ArcLabelsOut for potential container arcs.
if (container == eFalse && mContainer != eDontCare) {
nsCOMPtr<nsISimpleEnumerator> arcsout;
rv = ds->ArcLabelsOut(valueres, getter_AddRefs(arcsout));
if (NS_FAILED(rv)) return rv;
while (1) {
bool hasmore;
rv = arcsout->HasMoreElements(&hasmore);
if (NS_FAILED(rv)) return rv;
if (! hasmore)
break;
nsCOMPtr<nsISupports> isupports;
rv = arcsout->GetNext(getter_AddRefs(isupports));
if (NS_FAILED(rv)) return rv;
nsCOMPtr<nsIRDFResource> property = do_QueryInterface(isupports);
NS_ASSERTION(property != nullptr, "not a property");
if (! property)
return NS_ERROR_UNEXPECTED;
if (mProcessor->ContainmentProperties().Contains(property)) {
container = eTrue;
break;
}
}
}
}
MOZ_LOG(gXULTemplateLog, LogLevel::Debug,
(" empty => %s",
(empty == mEmpty) ? "consistent" : "inconsistent"));
MOZ_LOG(gXULTemplateLog, LogLevel::Debug,
(" container => %s",
(container == mContainer) ? "consistent" : "inconsistent"));
if (((mEmpty == empty) && (mContainer == container)) ||
((mEmpty == eDontCare) && (mContainer == container)) ||
((mContainer == eDontCare) && (mEmpty == empty)))
{
Element* element =
new nsRDFConInstanceTestNode::Element(valueres, container, empty);
inst->AddSupportingElement(element);
}
else {
aInstantiations.Erase(inst--);
}
}
}
return NS_OK;
}
bool
nsRDFConInstanceTestNode::CanPropagate(nsIRDFResource* aSource,
nsIRDFResource* aProperty,
nsIRDFNode* aTarget,
Instantiation& aInitialBindings) const
{
nsresult rv;
bool canpropagate = false;
nsCOMPtr<nsIRDFContainerUtils> rdfc
= do_GetService("@mozilla.org/rdf/container-utils;1");
if (! rdfc)
return false;
// We can certainly propagate ordinal properties
rv = rdfc->IsOrdinalProperty(aProperty, &canpropagate);
if (NS_FAILED(rv)) return false;
if (! canpropagate) {
canpropagate = mProcessor->ContainmentProperties().Contains(aProperty);
}
if (MOZ_LOG_TEST(gXULTemplateLog, LogLevel::Debug)) {
const char* source;
aSource->GetValueConst(&source);
const char* property;
aProperty->GetValueConst(&property);
nsAutoString target;
nsXULContentUtils::GetTextForNode(aTarget, target);
MOZ_LOG(gXULTemplateLog, LogLevel::Debug,
("nsRDFConInstanceTestNode[%p]: CanPropagate([%s]==[%s]=>[%s]) => %s",
this, source, property, NS_ConvertUTF16toUTF8(target).get(),
canpropagate ? "true" : "false"));
}
if (canpropagate) {
aInitialBindings.AddAssignment(mContainerVariable, aSource);
return true;
}
return false;
}
void
nsRDFConInstanceTestNode::Retract(nsIRDFResource* aSource,
nsIRDFResource* aProperty,
nsIRDFNode* aTarget) const
{
// XXXwaterson oof. complicated. figure this out.
if (0) {
mProcessor->RetractElement(Element(aSource, mContainer, mEmpty));
}
}

View File

@ -1,88 +0,0 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef nsRDFConInstanceTestNode_h__
#define nsRDFConInstanceTestNode_h__
#include "mozilla/Attributes.h"
#include "nscore.h"
#include "nsRDFTestNode.h"
#include "nsIRDFResource.h"
#include "nsIRDFDataSource.h"
#include "nsXULTemplateQueryProcessorRDF.h"
/**
* Rule network node that tests if a resource is an RDF container, or
* uses multi-attributes to ``contain'' other elements.
*/
class nsRDFConInstanceTestNode : public nsRDFTestNode
{
public:
enum Test { eFalse, eTrue, eDontCare };
nsRDFConInstanceTestNode(TestNode* aParent,
nsXULTemplateQueryProcessorRDF* aProcessor,
nsAtom* aContainerVariable,
Test aContainer,
Test aEmpty);
virtual nsresult FilterInstantiations(InstantiationSet& aInstantiations,
bool* aCantHandleYet) const override;
virtual bool
CanPropagate(nsIRDFResource* aSource,
nsIRDFResource* aProperty,
nsIRDFNode* aTarget,
Instantiation& aInitialBindings) const override;
virtual void
Retract(nsIRDFResource* aSource,
nsIRDFResource* aProperty,
nsIRDFNode* aTarget) const override;
class Element : public MemoryElement {
public:
Element(nsIRDFResource* aContainer,
Test aContainerTest,
Test aEmptyTest)
: mContainer(aContainer),
mContainerTest(aContainerTest),
mEmptyTest(aEmptyTest) {
MOZ_COUNT_CTOR(nsRDFConInstanceTestNode::Element); }
virtual ~Element() { MOZ_COUNT_DTOR(nsRDFConInstanceTestNode::Element); }
virtual const char* Type() const override {
return "nsRDFConInstanceTestNode::Element"; }
virtual PLHashNumber Hash() const override {
return mozilla::HashGeneric(mContainerTest, mEmptyTest, mContainer.get());
}
virtual bool Equals(const MemoryElement& aElement) const override {
if (aElement.Type() == Type()) {
const Element& element = static_cast<const Element&>(aElement);
return mContainer == element.mContainer
&& mContainerTest == element.mContainerTest
&& mEmptyTest == element.mEmptyTest;
}
return false; }
protected:
nsCOMPtr<nsIRDFResource> mContainer;
Test mContainerTest;
Test mEmptyTest;
};
protected:
nsXULTemplateQueryProcessorRDF* mProcessor;
RefPtr<nsAtom> mContainerVariable;
Test mContainer;
Test mEmpty;
};
#endif // nsRDFConInstanceTestNode_h__

View File

@ -1,510 +0,0 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsRDFConMemberTestNode.h"
#include "nsIRDFContainer.h"
#include "nsIRDFContainerUtils.h"
#include "nsRDFCID.h"
#include "nsIServiceManager.h"
#include "nsResourceSet.h"
#include "nsString.h"
#include "nsXULContentUtils.h"
#include "mozilla/Logging.h"
using mozilla::LogLevel;
extern mozilla::LazyLogModule gXULTemplateLog;
nsRDFConMemberTestNode::nsRDFConMemberTestNode(TestNode* aParent,
nsXULTemplateQueryProcessorRDF* aProcessor,
nsAtom *aContainerVariable,
nsAtom *aMemberVariable)
: nsRDFTestNode(aParent),
mProcessor(aProcessor),
mContainerVariable(aContainerVariable),
mMemberVariable(aMemberVariable)
{
if (MOZ_LOG_TEST(gXULTemplateLog, LogLevel::Debug)) {
nsAutoCString props;
nsResourceSet& containmentProps = aProcessor->ContainmentProperties();
nsResourceSet::ConstIterator last = containmentProps.Last();
nsResourceSet::ConstIterator first = containmentProps.First();
nsResourceSet::ConstIterator iter;
for (iter = first; iter != last; ++iter) {
if (iter != first)
props += " ";
const char* str;
iter->GetValueConst(&str);
props += str;
}
nsAutoString cvar(NS_LITERAL_STRING("(none)"));
if (mContainerVariable)
mContainerVariable->ToString(cvar);
nsAutoString mvar(NS_LITERAL_STRING("(none)"));
if (mMemberVariable)
mMemberVariable->ToString(mvar);
MOZ_LOG(gXULTemplateLog, LogLevel::Debug,
("nsRDFConMemberTestNode[%p]: parent=%p member-props=(%s) container-var=%s member-var=%s",
this,
aParent,
props.get(),
NS_ConvertUTF16toUTF8(cvar).get(),
NS_ConvertUTF16toUTF8(mvar).get()));
}
}
nsresult
nsRDFConMemberTestNode::FilterInstantiations(InstantiationSet& aInstantiations,
bool* aCantHandleYet) const
{
// XXX Uh, factor me, please!
nsresult rv;
if (aCantHandleYet)
*aCantHandleYet = false;
nsCOMPtr<nsIRDFContainerUtils> rdfc =
do_GetService("@mozilla.org/rdf/container-utils;1");
if (! rdfc)
return NS_ERROR_FAILURE;
nsIRDFDataSource* ds = mProcessor->GetDataSource();
InstantiationSet::Iterator last = aInstantiations.Last();
for (InstantiationSet::Iterator inst = aInstantiations.First(); inst != last; ++inst) {
bool hasContainerBinding;
nsCOMPtr<nsIRDFNode> containerValue;
hasContainerBinding = inst->mAssignments.GetAssignmentFor(mContainerVariable,
getter_AddRefs(containerValue));
nsCOMPtr<nsIRDFResource> containerRes = do_QueryInterface(containerValue);
nsCOMPtr<nsIRDFContainer> rdfcontainer;
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.
bool 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(ds, containerRes);
if (NS_FAILED(rv)) return rv;
}
}
bool hasMemberBinding;
nsCOMPtr<nsIRDFNode> memberValue;
hasMemberBinding = inst->mAssignments.GetAssignmentFor(mMemberVariable,
getter_AddRefs(memberValue));
if (MOZ_LOG_TEST(gXULTemplateLog, LogLevel::Debug)) {
const char* container = "(unbound)";
if (hasContainerBinding)
containerRes->GetValueConst(&container);
nsAutoString member(NS_LITERAL_STRING("(unbound)"));
if (hasMemberBinding)
nsXULContentUtils::GetTextForNode(memberValue, member);
MOZ_LOG(gXULTemplateLog, LogLevel::Debug,
("nsRDFConMemberTestNode[%p]: FilterInstantiations() container=[%s] member=[%s]",
this, container, NS_ConvertUTF16toUTF8(member).get()));
}
if (hasContainerBinding && hasMemberBinding) {
// it's a consistency check. see if we have a assignment that is consistent
bool isconsistent = false;
if (rdfcontainer) {
// RDF containers are easy. Just use the container API.
int32_t index;
rv = rdfcontainer->IndexOf(memberValue, &index);
if (NS_FAILED(rv)) return rv;
if (index >= 0)
isconsistent = true;
}
// XXXwaterson oof. if we *are* an RDF container, why do
// we still need to grovel through all the containment
// properties if the thing we're looking for wasn't there?
if (! isconsistent) {
// Othewise, we'll need to grovel through the
// membership properties to see if we have an
// assertion that indicates membership.
nsResourceSet& containmentProps = mProcessor->ContainmentProperties();
for (nsResourceSet::ConstIterator property = containmentProps.First();
property != containmentProps.Last();
++property) {
bool hasAssertion;
rv = ds->HasAssertion(containerRes,
*property,
memberValue,
true,
&hasAssertion);
if (NS_FAILED(rv)) return rv;
if (hasAssertion) {
// it's consistent. leave it in the set and we'll
// run it up to our parent.
isconsistent = true;
break;
}
}
}
MOZ_LOG(gXULTemplateLog, LogLevel::Debug,
(" consistency check => %s", isconsistent ? "passed" : "failed"));
if (isconsistent) {
// Add a memory element to our set-of-support.
Element* element =
new nsRDFConMemberTestNode::Element(containerRes,
memberValue);
inst->AddSupportingElement(element);
}
else {
// it's inconsistent. remove it.
aInstantiations.Erase(inst--);
}
// We're done, go on to the next instantiation
continue;
}
if (hasContainerBinding && rdfcontainer) {
// We've got a container assignment, and the container is
// bound to an RDF container. Add each member as a new
// instantiation.
nsCOMPtr<nsISimpleEnumerator> elements;
rv = rdfcontainer->GetElements(getter_AddRefs(elements));
if (NS_FAILED(rv)) return rv;
while (1) {
bool hasmore;
rv = elements->HasMoreElements(&hasmore);
if (NS_FAILED(rv)) return rv;
if (! hasmore)
break;
nsCOMPtr<nsISupports> isupports;
rv = elements->GetNext(getter_AddRefs(isupports));
if (NS_FAILED(rv)) return rv;
nsCOMPtr<nsIRDFNode> node = do_QueryInterface(isupports);
if (! node)
return NS_ERROR_UNEXPECTED;
if (MOZ_LOG_TEST(gXULTemplateLog, LogLevel::Debug)) {
nsAutoString member;
nsXULContentUtils::GetTextForNode(node, member);
MOZ_LOG(gXULTemplateLog, LogLevel::Debug,
(" member => %s", NS_ConvertUTF16toUTF8(member).get()));
}
Instantiation newinst = *inst;
newinst.AddAssignment(mMemberVariable, node);
Element* element =
new nsRDFConMemberTestNode::Element(containerRes, node);
newinst.AddSupportingElement(element);
aInstantiations.Insert(inst, newinst);
}
}
if (hasMemberBinding) {
// Oh, this is so nasty. If we have a member assignment, then
// grovel through each one of our inbound arcs to see if
// any of them are ordinal properties (like an RDF
// container might have). If so, walk it backwards to get
// the container we're in.
nsCOMPtr<nsISimpleEnumerator> arcsin;
rv = ds->ArcLabelsIn(memberValue, getter_AddRefs(arcsin));
if (NS_FAILED(rv)) return rv;
while (1) {
nsCOMPtr<nsIRDFResource> property;
{
bool hasmore;
rv = arcsin->HasMoreElements(&hasmore);
if (NS_FAILED(rv)) return rv;
if (! hasmore)
break;
nsCOMPtr<nsISupports> isupports;
rv = arcsin->GetNext(getter_AddRefs(isupports));
if (NS_FAILED(rv)) return rv;
property = do_QueryInterface(isupports);
if (! property)
return NS_ERROR_UNEXPECTED;
}
// Ordinal properties automagically indicate container
// membership as far as we're concerned. Note that
// we're *only* concerned with ordinal properties
// here: the next block will worry about the other
// membership properties.
bool isordinal;
rv = rdfc->IsOrdinalProperty(property, &isordinal);
if (NS_FAILED(rv)) return rv;
if (isordinal) {
// If we get here, we've found a property that
// indicates container membership leading *into* a
// member node. Find all the people that point to
// it, and call them containers.
nsCOMPtr<nsISimpleEnumerator> sources;
rv = ds->GetSources(property, memberValue, true,
getter_AddRefs(sources));
if (NS_FAILED(rv)) return rv;
while (1) {
bool hasmore;
rv = sources->HasMoreElements(&hasmore);
if (NS_FAILED(rv)) return rv;
if (! hasmore)
break;
nsCOMPtr<nsISupports> isupports;
rv = sources->GetNext(getter_AddRefs(isupports));
if (NS_FAILED(rv)) return rv;
nsCOMPtr<nsIRDFResource> source = do_QueryInterface(isupports);
if (! source)
return NS_ERROR_UNEXPECTED;
if (MOZ_LOG_TEST(gXULTemplateLog, LogLevel::Debug)) {
const char* container;
source->GetValueConst(&container);
MOZ_LOG(gXULTemplateLog, LogLevel::Debug,
(" container => %s", container));
}
// Add a new instantiation
Instantiation newinst = *inst;
newinst.AddAssignment(mContainerVariable, source);
Element* element =
new nsRDFConMemberTestNode::Element(source,
memberValue);
newinst.AddSupportingElement(element);
aInstantiations.Insert(inst, newinst);
}
}
}
}
if ((hasContainerBinding && ! hasMemberBinding) ||
(! hasContainerBinding && hasMemberBinding)) {
// it's an open ended query on the container or member. go
// through our containment properties to see if anything
// applies.
nsResourceSet& containmentProps = mProcessor->ContainmentProperties();
for (nsResourceSet::ConstIterator property = containmentProps.First();
property != containmentProps.Last();
++property) {
nsCOMPtr<nsISimpleEnumerator> results;
if (hasContainerBinding) {
rv = ds->GetTargets(containerRes, *property, true,
getter_AddRefs(results));
}
else {
rv = ds->GetSources(*property, memberValue, true,
getter_AddRefs(results));
}
if (NS_FAILED(rv)) return rv;
while (1) {
bool hasmore;
rv = results->HasMoreElements(&hasmore);
if (NS_FAILED(rv)) return rv;
if (! hasmore)
break;
nsCOMPtr<nsISupports> isupports;
rv = results->GetNext(getter_AddRefs(isupports));
if (NS_FAILED(rv)) return rv;
nsAtom* variable;
nsCOMPtr<nsIRDFNode> value;
nsCOMPtr<nsIRDFResource> valueRes;
if (hasContainerBinding) {
variable = mMemberVariable;
value = do_QueryInterface(isupports);
NS_ASSERTION(value != nullptr, "member is not an nsIRDFNode");
if (! value) continue;
if (MOZ_LOG_TEST(gXULTemplateLog, LogLevel::Debug)) {
nsAutoString s;
nsXULContentUtils::GetTextForNode(value, s);
MOZ_LOG(gXULTemplateLog, LogLevel::Debug,
(" member => %s", NS_ConvertUTF16toUTF8(s).get()));
}
}
else {
variable = mContainerVariable;
valueRes = do_QueryInterface(isupports);
NS_ASSERTION(valueRes != nullptr, "container is not an nsIRDFResource");
if (! valueRes) continue;
value = valueRes;
if (MOZ_LOG_TEST(gXULTemplateLog, LogLevel::Debug)) {
const char* s;
valueRes->GetValueConst(&s);
MOZ_LOG(gXULTemplateLog, LogLevel::Debug,
(" container => %s", s));
}
}
// Copy the original instantiation, and add it to the
// instantiation set with the new assignment that we've
// introduced. Ownership will be transferred to the
Instantiation newinst = *inst;
newinst.AddAssignment(variable, value);
Element* element;
if (hasContainerBinding) {
element =
new nsRDFConMemberTestNode::Element(containerRes, value);
}
else {
element =
new nsRDFConMemberTestNode::Element(valueRes, memberValue);
}
if (! element)
return NS_ERROR_OUT_OF_MEMORY;
newinst.AddSupportingElement(element);
aInstantiations.Insert(inst, newinst);
}
}
}
if (! hasContainerBinding && ! hasMemberBinding) {
// Neither container nor member assignment!
if (!aCantHandleYet) {
nsXULContentUtils::LogTemplateError(ERROR_TEMPLATE_MEMBER_UNBOUND);
return NS_ERROR_UNEXPECTED;
}
*aCantHandleYet = true;
return NS_OK;
}
// finally, remove the "under specified" instantiation.
aInstantiations.Erase(inst--);
}
return NS_OK;
}
bool
nsRDFConMemberTestNode::CanPropagate(nsIRDFResource* aSource,
nsIRDFResource* aProperty,
nsIRDFNode* aTarget,
Instantiation& aInitialBindings) const
{
nsresult rv;
bool canpropagate = false;
nsCOMPtr<nsIRDFContainerUtils> rdfc =
do_GetService("@mozilla.org/rdf/container-utils;1");
if (! rdfc)
return false;
// We can certainly propagate ordinal properties
rv = rdfc->IsOrdinalProperty(aProperty, &canpropagate);
if (NS_FAILED(rv)) return false;
if (! canpropagate) {
canpropagate = mProcessor->ContainmentProperties().Contains(aProperty);
}
if (MOZ_LOG_TEST(gXULTemplateLog, LogLevel::Debug)) {
const char* source;
aSource->GetValueConst(&source);
const char* property;
aProperty->GetValueConst(&property);
nsAutoString target;
nsXULContentUtils::GetTextForNode(aTarget, target);
MOZ_LOG(gXULTemplateLog, LogLevel::Debug,
("nsRDFConMemberTestNode[%p]: CanPropagate([%s]==[%s]=>[%s]) => %s",
this, source, property, NS_ConvertUTF16toUTF8(target).get(),
canpropagate ? "true" : "false"));
}
if (canpropagate) {
aInitialBindings.AddAssignment(mContainerVariable, aSource);
aInitialBindings.AddAssignment(mMemberVariable, aTarget);
return true;
}
return false;
}
void
nsRDFConMemberTestNode::Retract(nsIRDFResource* aSource,
nsIRDFResource* aProperty,
nsIRDFNode* aTarget) const
{
bool canretract = false;
nsCOMPtr<nsIRDFContainerUtils> rdfc =
do_GetService("@mozilla.org/rdf/container-utils;1");
if (! rdfc)
return;
// We can certainly retract ordinal properties
nsresult rv;
rv = rdfc->IsOrdinalProperty(aProperty, &canretract);
if (NS_FAILED(rv)) return;
if (! canretract) {
canretract = mProcessor->ContainmentProperties().Contains(aProperty);
}
if (canretract) {
mProcessor->RetractElement(Element(aSource, aTarget));
}
}

View File

@ -1,77 +0,0 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef nsRDFConMemberTestNode_h__
#define nsRDFConMemberTestNode_h__
#include "mozilla/Attributes.h"
#include "nscore.h"
#include "nsRDFTestNode.h"
#include "nsIRDFDataSource.h"
#include "nsXULTemplateQueryProcessorRDF.h"
/**
* Rule network node that test if a resource is a member of an RDF
* container, or is ``contained'' by another resource that refers to
* it using a ``containment'' attribute.
*/
class nsRDFConMemberTestNode : public nsRDFTestNode
{
public:
nsRDFConMemberTestNode(TestNode* aParent,
nsXULTemplateQueryProcessorRDF* aProcessor,
nsAtom* aContainerVariable,
nsAtom* aMemberVariable);
virtual nsresult FilterInstantiations(InstantiationSet& aInstantiations,
bool* aCantHandleYet) const override;
virtual bool
CanPropagate(nsIRDFResource* aSource,
nsIRDFResource* aProperty,
nsIRDFNode* aTarget,
Instantiation& aInitialBindings) const override;
virtual void
Retract(nsIRDFResource* aSource,
nsIRDFResource* aProperty,
nsIRDFNode* aTarget) const override;
class Element : public MemoryElement {
public:
Element(nsIRDFResource* aContainer,
nsIRDFNode* aMember)
: mContainer(aContainer),
mMember(aMember) {
MOZ_COUNT_CTOR(nsRDFConMemberTestNode::Element); }
virtual ~Element() { MOZ_COUNT_DTOR(nsRDFConMemberTestNode::Element); }
virtual const char* Type() const override {
return "nsRDFConMemberTestNode::Element"; }
virtual PLHashNumber Hash() const override {
return PLHashNumber(NS_PTR_TO_INT32(mContainer.get())) ^
(PLHashNumber(NS_PTR_TO_INT32(mMember.get())) >> 12); }
virtual bool Equals(const MemoryElement& aElement) const override {
if (aElement.Type() == Type()) {
const Element& element = static_cast<const Element&>(aElement);
return mContainer == element.mContainer && mMember == element.mMember;
}
return false; }
protected:
nsCOMPtr<nsIRDFResource> mContainer;
nsCOMPtr<nsIRDFNode> mMember;
};
protected:
nsXULTemplateQueryProcessorRDF* mProcessor;
RefPtr<nsAtom> mContainerVariable;
RefPtr<nsAtom> mMemberVariable;
};
#endif // nsRDFConMemberTestNode_h__

View File

@ -1,362 +0,0 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsRDFPropertyTestNode.h"
#include "nsString.h"
#include "nsXULContentUtils.h"
#include "mozilla/Logging.h"
using mozilla::LogLevel;
extern mozilla::LazyLogModule gXULTemplateLog;
#include "nsIRDFLiteral.h"
nsRDFPropertyTestNode::nsRDFPropertyTestNode(TestNode* aParent,
nsXULTemplateQueryProcessorRDF* aProcessor,
nsAtom* aSourceVariable,
nsIRDFResource* aProperty,
nsAtom* aTargetVariable)
: nsRDFTestNode(aParent),
mProcessor(aProcessor),
mSourceVariable(aSourceVariable),
mSource(nullptr),
mProperty(aProperty),
mTargetVariable(aTargetVariable),
mTarget(nullptr)
{
if (MOZ_LOG_TEST(gXULTemplateLog, LogLevel::Debug)) {
const char* prop = "(null)";
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);
MOZ_LOG(gXULTemplateLog, LogLevel::Debug,
("nsRDFPropertyTestNode[%p]: parent=%p source=%s property=%s target=%s",
this, aParent, NS_ConvertUTF16toUTF8(svar).get(), prop, NS_ConvertUTF16toUTF8(tvar).get()));
}
}
nsRDFPropertyTestNode::nsRDFPropertyTestNode(TestNode* aParent,
nsXULTemplateQueryProcessorRDF* aProcessor,
nsIRDFResource* aSource,
nsIRDFResource* aProperty,
nsAtom* aTargetVariable)
: nsRDFTestNode(aParent),
mProcessor(aProcessor),
mSourceVariable(nullptr),
mSource(aSource),
mProperty(aProperty),
mTargetVariable(aTargetVariable),
mTarget(nullptr)
{
if (MOZ_LOG_TEST(gXULTemplateLog, LogLevel::Debug)) {
const char* source = "(null)";
if (aSource)
aSource->GetValueConst(&source);
const char* prop = "(null)";
if (aProperty)
aProperty->GetValueConst(&prop);
nsAutoString tvar(NS_LITERAL_STRING("(none)"));
if (mTargetVariable)
mTargetVariable->ToString(tvar);
MOZ_LOG(gXULTemplateLog, LogLevel::Debug,
("nsRDFPropertyTestNode[%p]: parent=%p source=%s property=%s target=%s",
this, aParent, source, prop, NS_ConvertUTF16toUTF8(tvar).get()));
}
}
nsRDFPropertyTestNode::nsRDFPropertyTestNode(TestNode* aParent,
nsXULTemplateQueryProcessorRDF* aProcessor,
nsAtom* aSourceVariable,
nsIRDFResource* aProperty,
nsIRDFNode* aTarget)
: nsRDFTestNode(aParent),
mProcessor(aProcessor),
mSourceVariable(aSourceVariable),
mSource(nullptr),
mProperty(aProperty),
mTargetVariable(nullptr),
mTarget(aTarget)
{
if (MOZ_LOG_TEST(gXULTemplateLog, LogLevel::Debug)) {
nsAutoString svar(NS_LITERAL_STRING("(none)"));
if (mSourceVariable)
mSourceVariable->ToString(svar);
const char* prop = "(null)";
if (aProperty)
aProperty->GetValueConst(&prop);
nsAutoString target;
nsXULContentUtils::GetTextForNode(aTarget, target);
MOZ_LOG(gXULTemplateLog, LogLevel::Debug,
("nsRDFPropertyTestNode[%p]: parent=%p source=%s property=%s target=%s",
this, aParent, NS_ConvertUTF16toUTF8(svar).get(), prop, NS_ConvertUTF16toUTF8(target).get()));
}
}
nsresult
nsRDFPropertyTestNode::FilterInstantiations(InstantiationSet& aInstantiations,
bool* aCantHandleYet) const
{
nsresult rv;
if (aCantHandleYet)
*aCantHandleYet = false;
nsIRDFDataSource* ds = mProcessor->GetDataSource();
InstantiationSet::Iterator last = aInstantiations.Last();
for (InstantiationSet::Iterator inst = aInstantiations.First(); inst != last; ++inst) {
bool hasSourceBinding;
nsCOMPtr<nsIRDFResource> sourceRes;
if (mSource) {
hasSourceBinding = true;
sourceRes = mSource;
}
else {
nsCOMPtr<nsIRDFNode> sourceValue;
hasSourceBinding = inst->mAssignments.GetAssignmentFor(mSourceVariable,
getter_AddRefs(sourceValue));
sourceRes = do_QueryInterface(sourceValue);
}
bool hasTargetBinding;
nsCOMPtr<nsIRDFNode> targetValue;
if (mTarget) {
hasTargetBinding = true;
targetValue = mTarget;
}
else {
hasTargetBinding = inst->mAssignments.GetAssignmentFor(mTargetVariable,
getter_AddRefs(targetValue));
}
if (MOZ_LOG_TEST(gXULTemplateLog, LogLevel::Debug)) {
const char* source = "(unbound)";
if (hasSourceBinding)
sourceRes->GetValueConst(&source);
nsAutoString target(NS_LITERAL_STRING("(unbound)"));
if (hasTargetBinding)
nsXULContentUtils::GetTextForNode(targetValue, target);
MOZ_LOG(gXULTemplateLog, LogLevel::Debug,
("nsRDFPropertyTestNode[%p]: FilterInstantiations() source=[%s] target=[%s]",
this, source, NS_ConvertUTF16toUTF8(target).get()));
}
if (hasSourceBinding && hasTargetBinding) {
// it's a consistency check. see if we have a assignment that is consistent
bool hasAssertion;
rv = ds->HasAssertion(sourceRes, mProperty, targetValue,
true, &hasAssertion);
if (NS_FAILED(rv)) return rv;
MOZ_LOG(gXULTemplateLog, LogLevel::Debug,
(" consistency check => %s", hasAssertion ? "passed" : "failed"));
if (hasAssertion) {
// it's consistent.
Element* element =
new nsRDFPropertyTestNode::Element(sourceRes, mProperty,
targetValue);
inst->AddSupportingElement(element);
}
else {
// it's inconsistent. remove it.
aInstantiations.Erase(inst--);
}
}
else if ((hasSourceBinding && ! hasTargetBinding) ||
(! hasSourceBinding && hasTargetBinding)) {
// it's an open ended query on the source or
// target. figure out what matches and add as a
// cross-product.
nsCOMPtr<nsISimpleEnumerator> results;
if (hasSourceBinding) {
rv = ds->GetTargets(sourceRes,
mProperty,
true,
getter_AddRefs(results));
}
else {
rv = ds->GetSources(mProperty,
targetValue,
true,
getter_AddRefs(results));
if (NS_FAILED(rv)) return rv;
}
while (1) {
bool hasMore;
rv = results->HasMoreElements(&hasMore);
if (NS_FAILED(rv)) return rv;
if (! hasMore)
break;
nsCOMPtr<nsISupports> isupports;
rv = results->GetNext(getter_AddRefs(isupports));
if (NS_FAILED(rv)) return rv;
nsAtom* variable;
nsCOMPtr<nsIRDFNode> value;
if (hasSourceBinding) {
variable = mTargetVariable;
value = do_QueryInterface(isupports);
NS_ASSERTION(value != nullptr, "target is not an nsIRDFNode");
if (MOZ_LOG_TEST(gXULTemplateLog, LogLevel::Debug)) {
nsAutoString s(NS_LITERAL_STRING("(none found)"));
if (value)
nsXULContentUtils::GetTextForNode(value, s);
MOZ_LOG(gXULTemplateLog, LogLevel::Debug,
(" target => %s", NS_ConvertUTF16toUTF8(s).get()));
}
if (! value) continue;
targetValue = value;
}
else {
variable = mSourceVariable;
nsCOMPtr<nsIRDFResource> source = do_QueryInterface(isupports);
NS_ASSERTION(source != nullptr, "source is not an nsIRDFResource");
if (MOZ_LOG_TEST(gXULTemplateLog, LogLevel::Debug)) {
const char* s = "(none found)";
if (source)
source->GetValueConst(&s);
MOZ_LOG(gXULTemplateLog, LogLevel::Debug,
(" source => %s", s));
}
if (! source) continue;
value = sourceRes = source;
}
// Copy the original instantiation, and add it to the
// instantiation set with the new assignment that we've
// introduced. Ownership will be transferred to the
Instantiation newinst = *inst;
newinst.AddAssignment(variable, value);
Element* element =
new nsRDFPropertyTestNode::Element(sourceRes, mProperty,
targetValue);
newinst.AddSupportingElement(element);
aInstantiations.Insert(inst, newinst);
}
// finally, remove the "under specified" instantiation.
aInstantiations.Erase(inst--);
}
else {
if (!aCantHandleYet) {
nsXULContentUtils::LogTemplateError(ERROR_TEMPLATE_TRIPLE_UNBOUND);
// Neither source nor target assignment!
return NS_ERROR_UNEXPECTED;
}
*aCantHandleYet = true;
return NS_OK;
}
}
return NS_OK;
}
bool
nsRDFPropertyTestNode::CanPropagate(nsIRDFResource* aSource,
nsIRDFResource* aProperty,
nsIRDFNode* aTarget,
Instantiation& aInitialBindings) const
{
bool result;
if ((mProperty.get() != aProperty) ||
(mSource && mSource.get() != aSource) ||
(mTarget && mTarget.get() != aTarget)) {
result = false;
}
else {
if (mSourceVariable)
aInitialBindings.AddAssignment(mSourceVariable, aSource);
if (mTargetVariable)
aInitialBindings.AddAssignment(mTargetVariable, aTarget);
result = true;
}
if (MOZ_LOG_TEST(gXULTemplateLog, LogLevel::Debug)) {
const char* source;
aSource->GetValueConst(&source);
const char* property;
aProperty->GetValueConst(&property);
nsAutoString target;
nsXULContentUtils::GetTextForNode(aTarget, target);
MOZ_LOG(gXULTemplateLog, LogLevel::Debug,
("nsRDFPropertyTestNode[%p]: CanPropagate([%s]==[%s]=>[%s]) => %s",
this, source, property, NS_ConvertUTF16toUTF8(target).get(),
result ? "true" : "false"));
}
return result;
}
void
nsRDFPropertyTestNode::Retract(nsIRDFResource* aSource,
nsIRDFResource* aProperty,
nsIRDFNode* aTarget) const
{
if (aProperty == mProperty.get()) {
if (MOZ_LOG_TEST(gXULTemplateLog, LogLevel::Debug)) {
const char* source;
aSource->GetValueConst(&source);
const char* property;
aProperty->GetValueConst(&property);
nsAutoString target;
nsXULContentUtils::GetTextForNode(aTarget, target);
MOZ_LOG(gXULTemplateLog, LogLevel::Debug,
("nsRDFPropertyTestNode[%p]: Retract([%s]==[%s]=>[%s])",
this, source, property, NS_ConvertUTF16toUTF8(target).get()));
}
mProcessor->RetractElement(Element(aSource, aProperty, aTarget));
}
}

View File

@ -1,104 +0,0 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef nsRDFPropertyTestNode_h__
#define nsRDFPropertyTestNode_h__
#include "mozilla/Attributes.h"
#include "nscore.h"
#include "nsRDFTestNode.h"
#include "nsIRDFDataSource.h"
#include "nsIRDFResource.h"
#include "nsXULTemplateQueryProcessorRDF.h"
class nsRDFPropertyTestNode : public nsRDFTestNode
{
public:
/**
* Both source and target unbound (?source ^property ?target)
*/
nsRDFPropertyTestNode(TestNode* aParent,
nsXULTemplateQueryProcessorRDF* aProcessor,
nsAtom* aSourceVariable,
nsIRDFResource* aProperty,
nsAtom* aTargetVariable);
/**
* Source bound, target unbound (source ^property ?target)
*/
nsRDFPropertyTestNode(TestNode* aParent,
nsXULTemplateQueryProcessorRDF* aProcessor,
nsIRDFResource* aSource,
nsIRDFResource* aProperty,
nsAtom* aTargetVariable);
/**
* Source unbound, target bound (?source ^property target)
*/
nsRDFPropertyTestNode(TestNode* aParent,
nsXULTemplateQueryProcessorRDF* aProcessor,
nsAtom* aSourceVariable,
nsIRDFResource* aProperty,
nsIRDFNode* aTarget);
virtual nsresult FilterInstantiations(InstantiationSet& aInstantiations,
bool* aCantHandleYet) const override;
virtual bool
CanPropagate(nsIRDFResource* aSource,
nsIRDFResource* aProperty,
nsIRDFNode* aTarget,
Instantiation& aInitialBindings) const override;
virtual void
Retract(nsIRDFResource* aSource,
nsIRDFResource* aProperty,
nsIRDFNode* aTarget) const override;
class Element : public MemoryElement {
public:
Element(nsIRDFResource* aSource,
nsIRDFResource* aProperty,
nsIRDFNode* aTarget)
: mSource(aSource),
mProperty(aProperty),
mTarget(aTarget) {
MOZ_COUNT_CTOR(nsRDFPropertyTestNode::Element); }
virtual ~Element() { MOZ_COUNT_DTOR(nsRDFPropertyTestNode::Element); }
virtual const char* Type() const override {
return "nsRDFPropertyTestNode::Element"; }
virtual PLHashNumber Hash() const override {
return mozilla::HashGeneric(mSource.get(), mProperty.get(), mTarget.get());
}
virtual bool Equals(const MemoryElement& aElement) const override {
if (aElement.Type() == Type()) {
const Element& element = static_cast<const Element&>(aElement);
return mSource == element.mSource
&& mProperty == element.mProperty
&& mTarget == element.mTarget;
}
return false; }
protected:
nsCOMPtr<nsIRDFResource> mSource;
nsCOMPtr<nsIRDFResource> mProperty;
nsCOMPtr<nsIRDFNode> mTarget;
};
protected:
nsXULTemplateQueryProcessorRDF* mProcessor;
RefPtr<nsAtom> mSourceVariable;
nsCOMPtr<nsIRDFResource> mSource;
nsCOMPtr<nsIRDFResource> mProperty;
RefPtr<nsAtom> mTargetVariable;
nsCOMPtr<nsIRDFNode> mTarget;
};
#endif // nsRDFPropertyTestNode_h__

View File

@ -1,47 +0,0 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nscore.h"
#include "nsCOMPtr.h"
#include "nsXULTemplateQueryProcessorRDF.h"
#include "nsRDFQuery.h"
NS_IMPL_CYCLE_COLLECTION(nsRDFQuery, mQueryNode)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsRDFQuery)
NS_INTERFACE_MAP_ENTRY(nsITemplateRDFQuery)
NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_INTERFACE_MAP_END
NS_IMPL_CYCLE_COLLECTING_ADDREF(nsRDFQuery)
NS_IMPL_CYCLE_COLLECTING_RELEASE(nsRDFQuery)
void
nsRDFQuery::Finish()
{
// the template builder is going away and the query processor likely as
// well. Clear the reference to avoid calling it.
mProcessor = nullptr;
mCachedResults = nullptr;
}
nsresult
nsRDFQuery::SetCachedResults(nsXULTemplateQueryProcessorRDF* aProcessor,
const InstantiationSet& aInstantiations)
{
mCachedResults = new nsXULTemplateResultSetRDF(aProcessor, this, &aInstantiations);
return NS_OK;
}
void
nsRDFQuery::UseCachedResults(nsISimpleEnumerator** aResults)
{
*aResults = mCachedResults;
NS_IF_ADDREF(*aResults);
mCachedResults = nullptr;
}

View File

@ -1,130 +0,0 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef nsRDFQuery_h__
#define nsRDFQuery_h__
#include "nsISimpleEnumerator.h"
#include "nsCycleCollectionParticipant.h"
#include "mozilla/Attributes.h"
#define NS_ITEMPLATERDFQUERY_IID \
{0x8929ff60, 0x1c9c, 0x4d87, \
{ 0xac, 0x02, 0x09, 0x14, 0x15, 0x3b, 0x48, 0xc4 }}
class nsXULTemplateQueryProcessorRDF;
/**
* 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 nsAtom* 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 final : public nsITemplateRDFQuery
{
~nsRDFQuery() { Finish(); }
public:
explicit nsRDFQuery(nsXULTemplateQueryProcessorRDF* aProcessor)
: mProcessor(aProcessor),
mSimple(false),
mRoot(nullptr),
mCachedResults(nullptr)
{ }
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_CLASS(nsRDFQuery)
/**
* 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) override
{
*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() override
{
mCachedResults = nullptr;
}
nsXULTemplateQueryProcessorRDF* Processor() override { return mProcessor; }
nsAtom* GetMemberVariable() override { return mMemberVariable; }
bool IsSimple() { return mSimple; }
void SetSimple() { mSimple = true; }
// the reference and member variables for the query
RefPtr<nsAtom> mRefVariable;
RefPtr<nsAtom> mMemberVariable;
protected:
nsXULTemplateQueryProcessorRDF* mProcessor;
// true if the query is a simple rule (one with a default query)
bool 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(nsITemplateRDFQuery, NS_ITEMPLATERDFQUERY_IID)
#endif // nsRDFQuery_h__

View File

@ -1,49 +0,0 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef nsRDFTestNode_h__
#define nsRDFTestNode_h__
#include "nsRuleNetwork.h"
class nsIRDFResource;
class nsIRDFNode;
/**
* An abstract base class for all of the RDF-related tests. This interface
* allows us to iterate over all of the RDF tests to find the one in the
* network that is apropos for a newly-added assertion.
*/
class nsRDFTestNode : public TestNode
{
public:
explicit nsRDFTestNode(TestNode* aParent)
: TestNode(aParent) {}
/**
* Determine whether the node can propagate an assertion
* with the specified source, property, and target. If the
* assertion can be propagated, aInitialBindings will be
* initialized with appropriate variable-to-value assignments
* to allow the rule network to start a constrain and propagate
* search from this node in the network.
*
* @return true if the node can propagate the specified
* assertion.
*/
virtual bool CanPropagate(nsIRDFResource* aSource,
nsIRDFResource* aProperty,
nsIRDFNode* aTarget,
Instantiation& aInitialBindings) const = 0;
/**
*
*/
virtual void Retract(nsIRDFResource* aSource,
nsIRDFResource* aProperty,
nsIRDFNode* aTarget) const = 0;
};
#endif // nsRDFTestNode_h__

View File

@ -1,105 +0,0 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsResourceSet.h"
nsResourceSet::nsResourceSet(const nsResourceSet& aResourceSet)
: mResources(nullptr),
mCount(0),
mCapacity(0)
{
ConstIterator last = aResourceSet.Last();
for (ConstIterator resource = aResourceSet.First(); resource != last; ++resource)
Add(*resource);
}
nsResourceSet&
nsResourceSet::operator=(const nsResourceSet& aResourceSet)
{
Clear();
ConstIterator last = aResourceSet.Last();
for (ConstIterator resource = aResourceSet.First(); resource != last; ++resource)
Add(*resource);
return *this;
}
nsResourceSet::~nsResourceSet()
{
MOZ_COUNT_DTOR(nsResourceSet);
Clear();
delete[] mResources;
}
nsresult
nsResourceSet::Clear()
{
while (--mCount >= 0) {
NS_RELEASE(mResources[mCount]);
}
mCount = 0;
return NS_OK;
}
nsresult
nsResourceSet::Add(nsIRDFResource* aResource)
{
NS_PRECONDITION(aResource != nullptr, "null ptr");
if (! aResource)
return NS_ERROR_NULL_POINTER;
if (Contains(aResource))
return NS_OK;
if (mCount >= mCapacity) {
int32_t capacity = mCapacity + 4;
nsIRDFResource** resources = new nsIRDFResource*[capacity];
for (int32_t i = mCount - 1; i >= 0; --i)
resources[i] = mResources[i];
delete[] mResources;
mResources = resources;
mCapacity = capacity;
}
mResources[mCount++] = aResource;
NS_ADDREF(aResource);
return NS_OK;
}
void
nsResourceSet::Remove(nsIRDFResource* aProperty)
{
bool found = false;
nsIRDFResource** res = mResources;
nsIRDFResource** limit = mResources + mCount;
while (res < limit) {
if (found) {
*(res - 1) = *res;
}
else if (*res == aProperty) {
NS_RELEASE(*res);
found = true;
}
++res;
}
if (found)
--mCount;
}
bool
nsResourceSet::Contains(nsIRDFResource* aResource) const
{
for (int32_t i = mCount - 1; i >= 0; --i) {
if (mResources[i] == aResource)
return true;
}
return false;
}

View File

@ -1,82 +0,0 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef nsResourceSet_h__
#define nsResourceSet_h__
#include "nsIRDFResource.h"
class nsResourceSet
{
public:
nsResourceSet()
: mResources(nullptr),
mCount(0),
mCapacity(0) {
MOZ_COUNT_CTOR(nsResourceSet); }
nsResourceSet(const nsResourceSet& aResourceSet);
nsResourceSet& operator=(const nsResourceSet& aResourceSet);
~nsResourceSet();
nsresult Clear();
nsresult Add(nsIRDFResource* aProperty);
void Remove(nsIRDFResource* aProperty);
bool Contains(nsIRDFResource* aProperty) const;
protected:
nsIRDFResource** mResources;
int32_t mCount;
int32_t mCapacity;
public:
class ConstIterator {
protected:
nsIRDFResource** mCurrent;
public:
ConstIterator() : mCurrent(nullptr) {}
ConstIterator(const ConstIterator& aConstIterator)
: mCurrent(aConstIterator.mCurrent) {}
ConstIterator& operator=(const ConstIterator& aConstIterator) {
mCurrent = aConstIterator.mCurrent;
return *this; }
ConstIterator& operator++() {
++mCurrent;
return *this; }
ConstIterator operator++(int) {
ConstIterator result(*this);
++mCurrent;
return result; }
/*const*/ nsIRDFResource* operator*() const {
return *mCurrent; }
/*const*/ nsIRDFResource* operator->() const MOZ_NO_ADDREF_RELEASE_ON_RETURN {
return *mCurrent; }
bool operator==(const ConstIterator& aConstIterator) const {
return mCurrent == aConstIterator.mCurrent; }
bool operator!=(const ConstIterator& aConstIterator) const {
return mCurrent != aConstIterator.mCurrent; }
protected:
explicit ConstIterator(nsIRDFResource** aProperty) : mCurrent(aProperty) {}
friend class nsResourceSet;
};
ConstIterator First() const { return ConstIterator(mResources); }
ConstIterator Last() const { return ConstIterator(mResources + mCount); }
};
#endif // nsResourceSet_h__

View File

@ -1,428 +0,0 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/*
Implementations for the rule network classes.
To Do.
- Constrain() & Propagate() still feel like they are poorly named.
- As do Instantiation and InstantiationSet.
- Make InstantiationSet share and do copy-on-write.
- Make things iterative, instead of recursive.
*/
#include "nscore.h"
#include "nsCOMPtr.h"
#include "plhash.h"
#include "mozilla/Logging.h"
#include "nsString.h"
#include "nsUnicharUtils.h"
#include "nsXULContentUtils.h"
#include "nsRuleNetwork.h"
#include "nsXULTemplateResultSetRDF.h"
#include "nsRDFConMemberTestNode.h"
#include "nsRDFPropertyTestNode.h"
using namespace mozilla;
extern LazyLogModule gXULTemplateLog;
//----------------------------------------------------------------------
//
// nsRuleNetwork
//
nsresult
MemoryElementSet::Add(MemoryElement* aElement)
{
for (ConstIterator element = First(); element != Last(); ++element) {
if (*element == *aElement) {
// We've already got this element covered. Since Add()
// assumes ownership, and we aren't going to need this,
// just nuke it.
delete aElement;
return NS_OK;
}
}
List* list = new List;
list->mElement = aElement;
list->mRefCnt = 1;
list->mNext = mElements;
mElements = list;
return NS_OK;
}
//----------------------------------------------------------------------
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;
List* list = new List(aAssignment);
list->mRefCnt = 1;
list->mNext = mAssignments;
mAssignments = list;
return NS_OK;
}
int32_t
nsAssignmentSet::Count() const
{
int32_t count = 0;
for (ConstIterator assignment = First(); assignment != Last(); ++assignment)
++count;
return count;
}
bool
nsAssignmentSet::HasAssignment(nsAtom* aVariable, nsIRDFNode* aValue) const
{
for (ConstIterator assignment = First(); assignment != Last(); ++assignment) {
if (assignment->mVariable == aVariable && assignment->mValue == aValue)
return true;
}
return false;
}
bool
nsAssignmentSet::HasAssignmentFor(nsAtom* aVariable) const
{
for (ConstIterator assignment = First(); assignment != Last(); ++assignment) {
if (assignment->mVariable == aVariable)
return true;
}
return false;
}
bool
nsAssignmentSet::GetAssignmentFor(nsAtom* aVariable, nsIRDFNode** aValue) const
{
for (ConstIterator assignment = First(); assignment != Last(); ++assignment) {
if (assignment->mVariable == aVariable) {
*aValue = assignment->mValue;
NS_IF_ADDREF(*aValue);
return true;
}
}
*aValue = nullptr;
return false;
}
bool
nsAssignmentSet::Equals(const nsAssignmentSet& aSet) const
{
if (aSet.mAssignments == mAssignments)
return true;
// If they have a different number of assignments, then they're different.
if (Count() != aSet.Count())
return false;
// XXX O(n^2)! Ugh!
nsCOMPtr<nsIRDFNode> value;
for (ConstIterator assignment = First(); assignment != Last(); ++assignment) {
if (! aSet.GetAssignmentFor(assignment->mVariable, getter_AddRefs(value)))
return false;
if (assignment->mValue != value)
return false;
}
return true;
}
//----------------------------------------------------------------------
PLHashNumber
Instantiation::Hash(const void* aKey)
{
const Instantiation* inst = static_cast<const Instantiation*>(aKey);
PLHashNumber result = 0;
nsAssignmentSet::ConstIterator last = inst->mAssignments.Last();
for (nsAssignmentSet::ConstIterator assignment = inst->mAssignments.First();
assignment != last; ++assignment)
result ^= assignment->Hash();
return result;
}
int
Instantiation::Compare(const void* aLeft, const void* aRight)
{
const Instantiation* left = static_cast<const Instantiation*>(aLeft);
const Instantiation* right = static_cast<const Instantiation*>(aRight);
return *left == *right;
}
//----------------------------------------------------------------------
//
// InstantiationSet
//
InstantiationSet::InstantiationSet()
{
mHead.mPrev = mHead.mNext = &mHead;
MOZ_COUNT_CTOR(InstantiationSet);
}
InstantiationSet::InstantiationSet(const InstantiationSet& aInstantiationSet)
{
mHead.mPrev = mHead.mNext = &mHead;
// XXX replace with copy-on-write foo
ConstIterator last = aInstantiationSet.Last();
for (ConstIterator inst = aInstantiationSet.First(); inst != last; ++inst)
Append(*inst);
MOZ_COUNT_CTOR(InstantiationSet);
}
InstantiationSet&
InstantiationSet::operator=(const InstantiationSet& aInstantiationSet)
{
// XXX replace with copy-on-write foo
Clear();
ConstIterator last = aInstantiationSet.Last();
for (ConstIterator inst = aInstantiationSet.First(); inst != last; ++inst)
Append(*inst);
return *this;
}
void
InstantiationSet::Clear()
{
Iterator inst = First();
while (inst != Last())
Erase(inst++);
}
InstantiationSet::Iterator
InstantiationSet::Insert(Iterator aIterator, const Instantiation& aInstantiation)
{
List* newelement = new List();
if (newelement) {
newelement->mInstantiation = aInstantiation;
aIterator.mCurrent->mPrev->mNext = newelement;
newelement->mNext = aIterator.mCurrent;
newelement->mPrev = aIterator.mCurrent->mPrev;
aIterator.mCurrent->mPrev = newelement;
}
return aIterator;
}
InstantiationSet::Iterator
InstantiationSet::Erase(Iterator aIterator)
{
Iterator result = aIterator;
++result;
aIterator.mCurrent->mNext->mPrev = aIterator.mCurrent->mPrev;
aIterator.mCurrent->mPrev->mNext = aIterator.mCurrent->mNext;
delete aIterator.mCurrent;
return result;
}
bool
InstantiationSet::HasAssignmentFor(nsAtom* aVariable) const
{
return !Empty() ? First()->mAssignments.HasAssignmentFor(aVariable) : false;
}
//----------------------------------------------------------------------
//
// ReteNode
//
// The basic node in the network.
//
//----------------------------------------------------------------------
//
// TestNode
//
// to do:
// - FilterInstantiations() is poorly named
//
TestNode::TestNode(TestNode* aParent)
: mParent(aParent)
{
}
nsresult
TestNode::Propagate(InstantiationSet& aInstantiations,
bool aIsUpdate, bool& aTakenInstantiations)
{
MOZ_LOG(gXULTemplateLog, LogLevel::Debug,
("TestNode[%p]: Propagate() begin", this));
aTakenInstantiations = false;
nsresult rv = FilterInstantiations(aInstantiations, nullptr);
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
bool 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) {
MOZ_LOG(gXULTemplateLog, LogLevel::Debug,
("TestNode[%p]: Propagate() passing to child %p", this, kid.operator->()));
// create a copy of the instantiations
if (shouldCopy) {
bool owned = false;
InstantiationSet* instantiations =
new InstantiationSet(aInstantiations);
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;
}
}
}
MOZ_LOG(gXULTemplateLog, LogLevel::Debug,
("TestNode[%p]: Propagate() end", this));
return NS_OK;
}
nsresult
TestNode::Constrain(InstantiationSet& aInstantiations)
{
nsresult rv;
MOZ_LOG(gXULTemplateLog, LogLevel::Debug,
("TestNode[%p]: Constrain() begin", this));
// if the cantHandleYet flag is set by FilterInstantiations,
// there isn't enough information yet available to fill in.
// For this, continue the constrain all the way to the top
// and then call FilterInstantiations again afterwards. This
// should fill in any missing information.
bool cantHandleYet = false;
rv = FilterInstantiations(aInstantiations, &cantHandleYet);
if (NS_FAILED(rv)) return rv;
if (mParent && (!aInstantiations.Empty() || cantHandleYet)) {
// if we still have instantiations, or if the instantiations
// could not be filled in yet, then ride 'em on up to the
// parent to narrow them.
MOZ_LOG(gXULTemplateLog, LogLevel::Debug,
("TestNode[%p]: Constrain() passing to parent %p", this, mParent));
rv = mParent->Constrain(aInstantiations);
if (NS_SUCCEEDED(rv) && cantHandleYet)
rv = FilterInstantiations(aInstantiations, nullptr);
}
else {
MOZ_LOG(gXULTemplateLog, LogLevel::Debug,
("TestNode[%p]: Constrain() failed", this));
rv = NS_OK;
}
MOZ_LOG(gXULTemplateLog, LogLevel::Debug,
("TestNode[%p]: Constrain() end", this));
return rv;
}
//----------------------------------------------------------------------
ReteNodeSet::ReteNodeSet()
: mNodes(nullptr), mCount(0), mCapacity(0)
{
}
ReteNodeSet::~ReteNodeSet()
{
Clear();
}
nsresult
ReteNodeSet::Add(ReteNode* aNode)
{
NS_PRECONDITION(aNode != nullptr, "null ptr");
if (! aNode)
return NS_ERROR_NULL_POINTER;
if (mCount >= mCapacity) {
int32_t capacity = mCapacity + 4;
ReteNode** nodes = new ReteNode*[capacity];
if (! nodes)
return NS_ERROR_OUT_OF_MEMORY;
for (int32_t i = mCount - 1; i >= 0; --i)
nodes[i] = mNodes[i];
delete[] mNodes;
mNodes = nodes;
mCapacity = capacity;
}
mNodes[mCount++] = aNode;
return NS_OK;
}
nsresult
ReteNodeSet::Clear()
{
delete[] mNodes;
mNodes = nullptr;
mCount = mCapacity = 0;
return NS_OK;
}

View File

@ -1,861 +0,0 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/*
A rule discrimination network implementation based on ideas from
RETE and TREAT.
RETE is described in Charles Forgy, "Rete: A Fast Algorithm for the
Many Patterns/Many Objects Match Problem", Artificial Intelligence
19(1): pp. 17-37, 1982.
TREAT is described in Daniel P. Miranker, "TREAT: A Better Match
Algorithm for AI Production System Matching", AAAI 1987: pp. 42-47.
--
TO DO:
. nsAssignmentSet::List objects are allocated by the gallon. We
should make it so that these are always allocated from a pool,
maybe owned by the nsRuleNetwork?
*/
#ifndef nsRuleNetwork_h__
#define nsRuleNetwork_h__
#include "mozilla/Attributes.h"
#include "mozilla/HashFunctions.h"
#include "nsCOMPtr.h"
#include "nsCOMArray.h"
#include "nsAtom.h"
#include "nsIDOMNode.h"
#include "plhash.h"
#include "PLDHashTable.h"
#include "nsIRDFNode.h"
class nsXULTemplateResultSetRDF;
//----------------------------------------------------------------------
/**
* 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 {
protected:
MemoryElement() { MOZ_COUNT_CTOR(MemoryElement); }
public:
virtual ~MemoryElement() { MOZ_COUNT_DTOR(MemoryElement); }
virtual const char* Type() const = 0;
virtual PLHashNumber Hash() const = 0;
virtual bool Equals(const MemoryElement& aElement) const = 0;
bool operator==(const MemoryElement& aMemoryElement) const {
return Equals(aMemoryElement);
}
bool operator!=(const MemoryElement& aMemoryElement) const {
return !Equals(aMemoryElement);
}
};
//----------------------------------------------------------------------
/**
* A collection of memory elements
*/
class MemoryElementSet {
public:
class ConstIterator;
friend class ConstIterator;
protected:
class List {
public:
List() { MOZ_COUNT_CTOR(MemoryElementSet::List); }
protected:
~List() {
MOZ_COUNT_DTOR(MemoryElementSet::List);
delete mElement;
NS_IF_RELEASE(mNext); }
public:
int32_t AddRef() { return ++mRefCnt; }
int32_t Release() {
int32_t refcnt = --mRefCnt;
if (refcnt == 0) delete this;
return refcnt; }
MemoryElement* mElement;
int32_t mRefCnt;
List* mNext;
};
List* mElements;
public:
MemoryElementSet() : mElements(nullptr) {
MOZ_COUNT_CTOR(MemoryElementSet); }
MemoryElementSet(const MemoryElementSet& aSet) : mElements(aSet.mElements) {
MOZ_COUNT_CTOR(MemoryElementSet);
NS_IF_ADDREF(mElements); }
MemoryElementSet& operator=(const MemoryElementSet& aSet) {
NS_IF_RELEASE(mElements);
mElements = aSet.mElements;
NS_IF_ADDREF(mElements);
return *this; }
~MemoryElementSet() {
MOZ_COUNT_DTOR(MemoryElementSet);
NS_IF_RELEASE(mElements); }
public:
class ConstIterator {
public:
explicit ConstIterator(List* aElementList) : mCurrent(aElementList) {
NS_IF_ADDREF(mCurrent); }
ConstIterator(const ConstIterator& aConstIterator)
: mCurrent(aConstIterator.mCurrent) {
NS_IF_ADDREF(mCurrent); }
ConstIterator& operator=(const ConstIterator& aConstIterator) {
NS_IF_RELEASE(mCurrent);
mCurrent = aConstIterator.mCurrent;
NS_IF_ADDREF(mCurrent);
return *this; }
~ConstIterator() { NS_IF_RELEASE(mCurrent); }
ConstIterator& operator++() {
List* next = mCurrent->mNext;
NS_RELEASE(mCurrent);
mCurrent = next;
NS_IF_ADDREF(mCurrent);
return *this; }
ConstIterator operator++(int) {
ConstIterator result(*this);
List* next = mCurrent->mNext;
NS_RELEASE(mCurrent);
mCurrent = next;
NS_IF_ADDREF(mCurrent);
return result; }
const MemoryElement& operator*() const {
return *mCurrent->mElement; }
const MemoryElement* operator->() const {
return mCurrent->mElement; }
bool operator==(const ConstIterator& aConstIterator) const {
return mCurrent == aConstIterator.mCurrent; }
bool operator!=(const ConstIterator& aConstIterator) const {
return mCurrent != aConstIterator.mCurrent; }
protected:
List* mCurrent;
};
ConstIterator First() const { return ConstIterator(mElements); }
ConstIterator Last() const { return ConstIterator(nullptr); }
// N.B. that the set assumes ownership of the element
nsresult Add(MemoryElement* aElement);
};
//----------------------------------------------------------------------
/**
* An assignment of a value to a variable
*/
class nsAssignment {
public:
const RefPtr<nsAtom> mVariable;
nsCOMPtr<nsIRDFNode> mValue;
nsAssignment(nsAtom* aVariable, nsIRDFNode* aValue)
: mVariable(aVariable),
mValue(aValue)
{ MOZ_COUNT_CTOR(nsAssignment); }
nsAssignment(const nsAssignment& aAssignment)
: mVariable(aAssignment.mVariable),
mValue(aAssignment.mValue)
{ MOZ_COUNT_CTOR(nsAssignment); }
~nsAssignment() { MOZ_COUNT_DTOR(nsAssignment); }
bool operator==(const nsAssignment& aAssignment) const {
return mVariable == aAssignment.mVariable && mValue == aAssignment.mValue; }
bool operator!=(const nsAssignment& aAssignment) const {
return mVariable != aAssignment.mVariable || mValue != aAssignment.mValue; }
PLHashNumber Hash() const {
using mozilla::HashGeneric;
return HashGeneric(mVariable.get()) ^ HashGeneric(mValue.get()); }
};
//----------------------------------------------------------------------
/**
* A collection of value-to-variable assignments that minimizes
* copying by sharing subsets when possible.
*/
class nsAssignmentSet {
public:
class ConstIterator;
friend class ConstIterator;
protected:
class List {
public:
explicit List(const nsAssignment& aAssignment) : mAssignment(aAssignment) {
MOZ_COUNT_CTOR(nsAssignmentSet::List); }
protected:
~List() {
MOZ_COUNT_DTOR(nsAssignmentSet::List);
NS_IF_RELEASE(mNext); }
public:
int32_t AddRef() { return ++mRefCnt; }
int32_t Release() {
int32_t refcnt = --mRefCnt;
if (refcnt == 0) delete this;
return refcnt; }
nsAssignment mAssignment;
int32_t mRefCnt;
List* mNext;
};
List* mAssignments;
public:
nsAssignmentSet()
: mAssignments(nullptr)
{ MOZ_COUNT_CTOR(nsAssignmentSet); }
nsAssignmentSet(const nsAssignmentSet& aSet)
: mAssignments(aSet.mAssignments) {
MOZ_COUNT_CTOR(nsAssignmentSet);
NS_IF_ADDREF(mAssignments); }
nsAssignmentSet& operator=(const nsAssignmentSet& aSet) {
NS_IF_RELEASE(mAssignments);
mAssignments = aSet.mAssignments;
NS_IF_ADDREF(mAssignments);
return *this; }
~nsAssignmentSet() {
MOZ_COUNT_DTOR(nsAssignmentSet);
NS_IF_RELEASE(mAssignments); }
public:
class ConstIterator {
public:
explicit ConstIterator(List* aAssignmentList) : mCurrent(aAssignmentList) {
NS_IF_ADDREF(mCurrent); }
ConstIterator(const ConstIterator& aConstIterator)
: mCurrent(aConstIterator.mCurrent) {
NS_IF_ADDREF(mCurrent); }
ConstIterator& operator=(const ConstIterator& aConstIterator) {
NS_IF_RELEASE(mCurrent);
mCurrent = aConstIterator.mCurrent;
NS_IF_ADDREF(mCurrent);
return *this; }
~ConstIterator() { NS_IF_RELEASE(mCurrent); }
ConstIterator& operator++() {
List* next = mCurrent->mNext;
NS_RELEASE(mCurrent);
mCurrent = next;
NS_IF_ADDREF(mCurrent);
return *this; }
ConstIterator operator++(int) {
ConstIterator result(*this);
List* next = mCurrent->mNext;
NS_RELEASE(mCurrent);
mCurrent = next;
NS_IF_ADDREF(mCurrent);
return result; }
const nsAssignment& operator*() const {
return mCurrent->mAssignment; }
const nsAssignment* operator->() const {
return &mCurrent->mAssignment; }
bool operator==(const ConstIterator& aConstIterator) const {
return mCurrent == aConstIterator.mCurrent; }
bool operator!=(const ConstIterator& aConstIterator) const {
return mCurrent != aConstIterator.mCurrent; }
protected:
List* mCurrent;
};
ConstIterator First() const { return ConstIterator(mAssignments); }
ConstIterator Last() const { return ConstIterator(nullptr); }
public:
/**
* Add an assignment to the set
* @param aElement the assigment to add
* @return NS_OK if all is well, NS_ERROR_OUT_OF_MEMORY if memory
* could not be allocated for the addition.
*/
nsresult Add(const nsAssignment& aElement);
/**
* Determine if the assignment set contains the specified variable
* to value assignment.
* @param aVariable the variable for which to lookup the binding
* @param aValue the value to query
* @return true if aVariable is bound to aValue; false otherwise.
*/
bool HasAssignment(nsAtom* aVariable, nsIRDFNode* aValue) const;
/**
* Determine if the assignment set contains the specified assignment
* @param aAssignment the assignment to search for
* @return true if the set contains the assignment, false otherwise.
*/
bool HasAssignment(const nsAssignment& aAssignment) const {
return HasAssignment(aAssignment.mVariable, aAssignment.mValue); }
/**
* Determine whether the assignment set has an assignment for the
* specified variable.
* @param aVariable the variable to query
* @return true if the assignment set has an assignment for the variable,
* false otherwise.
*/
bool HasAssignmentFor(nsAtom* aVariable) const;
/**
* Retrieve the assignment for the specified variable
* @param aVariable the variable to query
* @param aValue an out parameter that will receive the value assigned
* to the variable, if any.
* @return true if the variable has an assignment, false
* if there was no assignment for the variable.
*/
bool GetAssignmentFor(nsAtom* aVariable, nsIRDFNode** aValue) const;
/**
* Count the number of assignments in the set
* @return the number of assignments in the set
*/
int32_t Count() const;
/**
* Determine if the set is empty
* @return true if the assignment set is empty, false otherwise.
*/
bool IsEmpty() const { return mAssignments == nullptr; }
bool Equals(const nsAssignmentSet& aSet) const;
bool operator==(const nsAssignmentSet& aSet) const { return Equals(aSet); }
bool operator!=(const nsAssignmentSet& aSet) const { return !Equals(aSet); }
};
//----------------------------------------------------------------------
/**
* 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
* adding bindings and support to the instantiation.
*/
class Instantiation
{
public:
/**
* The variable-to-value bindings
*/
nsAssignmentSet mAssignments;
/**
* The memory elements that support the bindings.
*/
MemoryElementSet mSupport;
Instantiation() { MOZ_COUNT_CTOR(Instantiation); }
Instantiation(const Instantiation& aInstantiation)
: mAssignments(aInstantiation.mAssignments),
mSupport(aInstantiation.mSupport) {
MOZ_COUNT_CTOR(Instantiation); }
Instantiation& operator=(const Instantiation& aInstantiation) {
mAssignments = aInstantiation.mAssignments;
mSupport = aInstantiation.mSupport;
return *this; }
~Instantiation() { MOZ_COUNT_DTOR(Instantiation); }
/**
* Add the specified variable-to-value assignment to the instantiation's
* set of assignments.
* @param aVariable the variable to which is being assigned
* @param aValue the value that is being assigned
* @return NS_OK if no errors, NS_ERROR_OUT_OF_MEMORY if there
* is not enough memory to perform the operation
*/
nsresult AddAssignment(nsAtom* aVariable, nsIRDFNode* aValue) {
mAssignments.Add(nsAssignment(aVariable, aValue));
return NS_OK; }
/**
* Add a memory element to the set of memory elements that are
* supporting the instantiation
* @param aMemoryElement the memory element to add to the
* instantiation's set of support
* @return NS_OK if no errors occurred, NS_ERROR_OUT_OF_MEMORY
* if there is not enough memory to perform the operation.
*/
nsresult AddSupportingElement(MemoryElement* aMemoryElement) {
mSupport.Add(aMemoryElement);
return NS_OK; }
bool Equals(const Instantiation& aInstantiation) const {
return mAssignments == aInstantiation.mAssignments; }
bool operator==(const Instantiation& aInstantiation) const {
return Equals(aInstantiation); }
bool operator!=(const Instantiation& aInstantiation) const {
return !Equals(aInstantiation); }
static PLHashNumber Hash(const void* aKey);
static int Compare(const void* aLeft, const void* aRight);
};
//----------------------------------------------------------------------
/**
* A collection of intantiations
*/
class InstantiationSet
{
public:
InstantiationSet();
InstantiationSet(const InstantiationSet& aInstantiationSet);
InstantiationSet& operator=(const InstantiationSet& aInstantiationSet);
~InstantiationSet() {
MOZ_COUNT_DTOR(InstantiationSet);
Clear(); }
class ConstIterator;
friend class ConstIterator;
class Iterator;
friend class Iterator;
friend class nsXULTemplateResultSetRDF; // so it can get to the List
protected:
class List {
public:
Instantiation mInstantiation;
List* mNext;
List* mPrev;
List() { MOZ_COUNT_CTOR(InstantiationSet::List); }
~List() { MOZ_COUNT_DTOR(InstantiationSet::List); }
};
List mHead;
public:
class ConstIterator {
protected:
friend class Iterator; // XXXwaterson so broken.
List* mCurrent;
public:
explicit ConstIterator(List* aList) : mCurrent(aList) {}
ConstIterator(const ConstIterator& aConstIterator)
: mCurrent(aConstIterator.mCurrent) {}
ConstIterator& operator=(const ConstIterator& aConstIterator) {
mCurrent = aConstIterator.mCurrent;
return *this; }
ConstIterator& operator++() {
mCurrent = mCurrent->mNext;
return *this; }
ConstIterator operator++(int) {
ConstIterator result(*this);
mCurrent = mCurrent->mNext;
return result; }
ConstIterator& operator--() {
mCurrent = mCurrent->mPrev;
return *this; }
ConstIterator operator--(int) {
ConstIterator result(*this);
mCurrent = mCurrent->mPrev;
return result; }
const Instantiation& operator*() const {
return mCurrent->mInstantiation; }
const Instantiation* operator->() const {
return &mCurrent->mInstantiation; }
bool operator==(const ConstIterator& aConstIterator) const {
return mCurrent == aConstIterator.mCurrent; }
bool operator!=(const ConstIterator& aConstIterator) const {
return mCurrent != aConstIterator.mCurrent; }
};
ConstIterator First() const { return ConstIterator(mHead.mNext); }
ConstIterator Last() const { return ConstIterator(const_cast<List*>(&mHead)); }
class Iterator : public ConstIterator {
public:
explicit Iterator(List* aList) : ConstIterator(aList) {}
Iterator& operator++() {
mCurrent = mCurrent->mNext;
return *this; }
Iterator operator++(int) {
Iterator result(*this);
mCurrent = mCurrent->mNext;
return result; }
Iterator& operator--() {
mCurrent = mCurrent->mPrev;
return *this; }
Iterator operator--(int) {
Iterator result(*this);
mCurrent = mCurrent->mPrev;
return result; }
Instantiation& operator*() const {
return mCurrent->mInstantiation; }
Instantiation* operator->() const {
return &mCurrent->mInstantiation; }
bool operator==(const ConstIterator& aConstIterator) const {
return mCurrent == aConstIterator.mCurrent; }
bool operator!=(const ConstIterator& aConstIterator) const {
return mCurrent != aConstIterator.mCurrent; }
friend class InstantiationSet;
};
Iterator First() { return Iterator(mHead.mNext); }
Iterator Last() { return Iterator(&mHead); }
bool Empty() const { return First() == Last(); }
Iterator Append(const Instantiation& aInstantiation) {
return Insert(Last(), aInstantiation); }
Iterator Insert(Iterator aBefore, const Instantiation& aInstantiation);
Iterator Erase(Iterator aElement);
void Clear();
bool HasAssignmentFor(nsAtom* aVariable) const;
};
//----------------------------------------------------------------------
/**
* A abstract base class for all nodes in the rule network
*/
class ReteNode
{
public:
ReteNode() {}
virtual ~ReteNode() {}
/**
* Propagate a set of instantiations "down" through the
* network. Each instantiation is a partial set of
* variable-to-value assignments, along with the memory elements
* that support it.
*
* The node must evaluate each instantiation, and either 1)
* extend it with additional assignments and memory-element
* support, or 2) remove it from the set because it is
* inconsistent with the constraints that this node applies.
*
* The node must then pass the resulting instantiation set along
* to any of its children in the network. (In other words, the
* 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 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(InstantiationSet& aInstantiations,
bool aIsUpdate, bool& aTakenInstantiations) = 0;
};
//----------------------------------------------------------------------
/**
* A collection of nodes in the rule network
*/
class ReteNodeSet
{
public:
ReteNodeSet();
~ReteNodeSet();
nsresult Add(ReteNode* aNode);
nsresult Clear();
class Iterator;
class ConstIterator {
public:
explicit ConstIterator(ReteNode** aNode) : mCurrent(aNode) {}
ConstIterator(const ConstIterator& aConstIterator)
: mCurrent(aConstIterator.mCurrent) {}
ConstIterator& operator=(const ConstIterator& aConstIterator) {
mCurrent = aConstIterator.mCurrent;
return *this; }
ConstIterator& operator++() {
++mCurrent;
return *this; }
ConstIterator operator++(int) {
ConstIterator result(*this);
++mCurrent;
return result; }
const ReteNode* operator*() const {
return *mCurrent; }
const ReteNode* operator->() const {
return *mCurrent; }
bool operator==(const ConstIterator& aConstIterator) const {
return mCurrent == aConstIterator.mCurrent; }
bool operator!=(const ConstIterator& aConstIterator) const {
return mCurrent != aConstIterator.mCurrent; }
protected:
friend class Iterator; // XXXwaterson this is so wrong!
ReteNode** mCurrent;
};
ConstIterator First() const { return ConstIterator(mNodes); }
ConstIterator Last() const { return ConstIterator(mNodes + mCount); }
class Iterator : public ConstIterator {
public:
explicit Iterator(ReteNode** aNode) : ConstIterator(aNode) {}
Iterator& operator++() {
++mCurrent;
return *this; }
Iterator operator++(int) {
Iterator result(*this);
++mCurrent;
return result; }
ReteNode* operator*() const {
return *mCurrent; }
ReteNode* operator->() const {
return *mCurrent; }
bool operator==(const ConstIterator& aConstIterator) const {
return mCurrent == aConstIterator.mCurrent; }
bool operator!=(const ConstIterator& aConstIterator) const {
return mCurrent != aConstIterator.mCurrent; }
};
Iterator First() { return Iterator(mNodes); }
Iterator Last() { return Iterator(mNodes + mCount); }
int32_t Count() const { return mCount; }
protected:
ReteNode** mNodes;
int32_t mCount;
int32_t mCapacity;
};
//----------------------------------------------------------------------
/**
* 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 TestNode : public ReteNode
{
public:
explicit 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,
bool aIsUpdate, bool& aTakenInstantiations) override;
/**
* This is called by a child node on its parent to allow the
* parent's constraints to apply to the set of instantiations.
*
* A node must iterate through the set of instantiations, and for
* each instantiation, either 1) extend the instantiation by
* adding variable-to-value assignments and memory element support
* for those assignments, or 2) remove the instantiation because
* it is inconsistent.
*
* The node must then pass the resulting set of instantiations up
* to its parent (by recursive call; we should make this iterative
* & interruptable at some point.)
*
* @param aInstantiations the set of instantiations that must
* be constrained
* @return NS_OK if no errors occurred
*/
virtual nsresult Constrain(InstantiationSet& aInstantiations);
/**
* 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 aCantHandleYet [out] true if the instantiations do not contain
* enough information to constrain the data. May be null if this
* isn't important to the caller.
* @return NS_OK if no errors occurred.
*/
virtual nsresult FilterInstantiations(InstantiationSet& aInstantiations,
bool* aCantHandleYet) const = 0;
//XXX probably better named "ApplyConstraints" or "Discrminiate" or something
/**
* Add another node as a child of this node.
* @param aNode the node to add.
* @return NS_OK if no errors occur.
*/
nsresult AddChild(ReteNode* aNode) { return mKids.Add(aNode); }
/**
* Remove all the children of this node
* @return NS_OK if no errors occur.
*/
nsresult RemoveAllChildren() { return mKids.Clear(); }
protected:
TestNode* mParent;
ReteNodeSet mKids;
};
#endif // nsRuleNetwork_h__

View File

@ -1,64 +0,0 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef nsTemplateMap_h__
#define nsTemplateMap_h__
#include "PLDHashTable.h"
#include "nsXULElement.h"
class nsTemplateMap {
protected:
struct Entry : public PLDHashEntryHdr {
nsIContent* mContent;
nsIContent* mTemplate;
};
PLDHashTable mTable;
public:
nsTemplateMap() : mTable(PLDHashTable::StubOps(), sizeof(Entry)) { }
~nsTemplateMap() { }
void
Put(nsIContent* aContent, nsIContent* aTemplate) {
NS_ASSERTION(!mTable.Search(aContent), "aContent already in map");
auto entry = static_cast<Entry*>(mTable.Add(aContent, mozilla::fallible));
if (entry) {
entry->mContent = aContent;
entry->mTemplate = aTemplate;
}
}
void
Remove(nsIContent* aContent) {
mTable.Remove(aContent);
for (nsIContent* child = aContent->GetFirstChild();
child;
child = child->GetNextSibling()) {
Remove(child);
}
}
void
GetTemplateFor(nsIContent* aContent, nsIContent** aResult) {
auto entry = static_cast<Entry*>(mTable.Search(aContent));
if (entry)
NS_IF_ADDREF(*aResult = entry->mTemplate);
else
*aResult = nullptr;
}
void
Clear() { mTable.Clear(); }
};
#endif // nsTemplateMap_h__

View File

@ -1,35 +0,0 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsTemplateMatch.h"
#include "nsTemplateRule.h"
// static
void
nsTemplateMatch::Destroy(nsTemplateMatch*& aMatch, bool aRemoveResult)
{
if (aRemoveResult && aMatch->mResult)
aMatch->mResult->HasBeenRemoved();
::delete aMatch;
aMatch = nullptr;
}
nsresult
nsTemplateMatch::RuleMatched(nsTemplateQuerySet* aQuerySet,
nsTemplateRule* aRule,
int16_t aRuleIndex,
nsIXULTemplateResult* aResult)
{
// assign the rule index, used to indicate that a match is active, and
// so the tree builder can get the right action body to generate
mRuleIndex = aRuleIndex;
nsCOMPtr<nsIDOMNode> rulenode;
aRule->GetRuleNode(getter_AddRefs(rulenode));
if (rulenode)
return aResult->RuleMatched(aQuerySet->mCompiledQuery, rulenode);
return NS_OK;
}

View File

@ -1,139 +0,0 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef nsTemplateMatch_h__
#define nsTemplateMatch_h__
#include "mozilla/Attributes.h"
#include "nsIContent.h"
#include "nsIXULTemplateQueryProcessor.h"
#include "nsIXULTemplateResult.h"
#include "nsRuleNetwork.h"
/**
* 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.
* A match can be identified by the container and id. The id is retrievable
* from the result.
*
* Only one match per container and id pair 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.
*
* Matches are stored and owned by the mMatchToMap hash in the template
* builder.
*/
class nsTemplateRule;
class nsTemplateQuerySet;
class nsTemplateMatch {
private:
// Hide so that only Create() and Destroy() can be used to
// allocate and deallocate from the heap
void* operator new(size_t) CPP_THROW_NEW { MOZ_ASSERT(0); return nullptr; }
void operator delete(void*, size_t) { MOZ_ASSERT(0); }
public:
nsTemplateMatch(uint16_t aQuerySetPriority,
nsIXULTemplateResult* aResult,
nsIContent* aContainer)
: mRuleIndex(-1),
mQuerySetPriority(aQuerySetPriority),
mContainer(aContainer),
mResult(aResult),
mNext(nullptr)
{
MOZ_COUNT_CTOR(nsTemplateMatch);
}
~nsTemplateMatch()
{
MOZ_COUNT_DTOR(nsTemplateMatch);
}
static nsTemplateMatch*
Create(uint16_t aQuerySetPriority,
nsIXULTemplateResult* aResult,
nsIContent* aContainer) {
return ::new nsTemplateMatch(aQuerySetPriority, aResult, aContainer);
}
static void Destroy(nsTemplateMatch*& aMatch, bool aRemoveResult);
// return true if the the match is active, and has generated output
bool IsActive() {
return mRuleIndex >= 0;
}
// indicate that a rule is no longer active, used when a query with a
// lower priority has overriden the match
void SetInactive() {
mRuleIndex = -1;
}
// return matching rule index
int16_t RuleIndex() {
return mRuleIndex;
}
// return priority of query set
uint16_t QuerySetPriority() {
return mQuerySetPriority;
}
// return container, not addrefed. May be null.
nsIContent* GetContainer() {
return mContainer;
}
nsresult RuleMatched(nsTemplateQuerySet* aQuerySet,
nsTemplateRule* aRule,
int16_t aRuleIndex,
nsIXULTemplateResult* aResult);
private:
/**
* The index of the rule that matched, or -1 if the match is not active.
*/
int16_t mRuleIndex;
/**
* The priority of the queryset for this rule
*/
uint16_t mQuerySetPriority;
/**
* The container the content generated for the match is inside.
*/
nsCOMPtr<nsIContent> mContainer;
public:
/**
* The result associated with this match
*/
nsCOMPtr<nsIXULTemplateResult> mResult;
/**
* 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.
*/
nsTemplateMatch *mNext;
private:
nsTemplateMatch(const nsTemplateMatch& aMatch) = delete;
void operator=(const nsTemplateMatch& aMatch) = delete;
};
#endif // nsTemplateMatch_h__

View File

@ -1,422 +0,0 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsTemplateRule.h"
#include "nsTemplateMatch.h"
#include "nsXULContentUtils.h"
#include "nsUnicharUtils.h"
#include "nsReadableUtils.h"
#include "nsICollation.h"
nsTemplateCondition::nsTemplateCondition(nsAtom* aSourceVariable,
const nsAString& aRelation,
nsAtom* aTargetVariable,
bool aIgnoreCase,
bool aNegate)
: mSourceVariable(aSourceVariable),
mTargetVariable(aTargetVariable),
mIgnoreCase(aIgnoreCase),
mNegate(aNegate),
mNext(nullptr)
{
SetRelation(aRelation);
MOZ_COUNT_CTOR(nsTemplateCondition);
}
nsTemplateCondition::nsTemplateCondition(nsAtom* aSourceVariable,
const nsAString& aRelation,
const nsAString& aTargets,
bool aIgnoreCase,
bool aNegate,
bool aIsMultiple)
: mSourceVariable(aSourceVariable),
mIgnoreCase(aIgnoreCase),
mNegate(aNegate),
mNext(nullptr)
{
SetRelation(aRelation);
if (aIsMultiple) {
int32_t start = 0, end = 0;
while ((end = aTargets.FindChar(',',start)) >= 0) {
if (end > start) {
mTargetList.AppendElement(Substring(aTargets, start, end - start));
}
start = end + 1;
}
if (start < int32_t(aTargets.Length())) {
mTargetList.AppendElement(Substring(aTargets, start));
}
}
else {
mTargetList.AppendElement(aTargets);
}
MOZ_COUNT_CTOR(nsTemplateCondition);
}
nsTemplateCondition::nsTemplateCondition(const nsAString& aSource,
const nsAString& aRelation,
nsAtom* aTargetVariable,
bool aIgnoreCase,
bool aNegate)
: mSource(aSource),
mTargetVariable(aTargetVariable),
mIgnoreCase(aIgnoreCase),
mNegate(aNegate),
mNext(nullptr)
{
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;
}
bool
nsTemplateCondition::CheckMatch(nsIXULTemplateResult* aResult)
{
bool match = 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.
uint32_t length = mTargetList.Length();
for (uint32_t 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;
}
bool
nsTemplateCondition::CheckMatchStrings(const nsAString& aLeftString,
const nsAString& aRightString)
{
bool match = false;
if (aRightString.IsEmpty()) {
if ((mRelation == eEquals) && aLeftString.IsEmpty())
match = 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
nsresult err;
int32_t leftint = PromiseFlatString(aLeftString).ToInteger(&err);
if (NS_SUCCEEDED(err)) {
int32_t 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) {
int32_t sortOrder;
collation->CompareString((mIgnoreCase ?
static_cast<int32_t>(nsICollation::kCollationCaseInSensitive) :
static_cast<int32_t>(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) {
int32_t sortOrder;
collation->CompareString((mIgnoreCase ?
static_cast<int32_t>(nsICollation::kCollationCaseInSensitive) :
static_cast<int32_t>(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(nullptr),
mConditions(nullptr)
{
MOZ_COUNT_CTOR(nsTemplateRule);
mRuleNode = do_QueryInterface(aRuleNode);
}
nsTemplateRule::nsTemplateRule(const nsTemplateRule& aOtherRule)
: mQuerySet(aOtherRule.mQuerySet),
mRuleNode(aOtherRule.mRuleNode),
mAction(aOtherRule.mAction),
mBindings(nullptr),
mConditions(nullptr)
{
MOZ_COUNT_CTOR(nsTemplateRule);
}
nsTemplateRule::~nsTemplateRule()
{
MOZ_COUNT_DTOR(nsTemplateRule);
while (mBindings) {
Binding* doomed = mBindings;
mBindings = mBindings->mNext;
delete doomed;
}
while (mConditions) {
nsTemplateCondition* cdel = mConditions;
mConditions = mConditions->GetNext();
delete cdel;
}
}
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;
}
bool
nsTemplateRule::CheckMatch(nsIXULTemplateResult* aResult) const
{
// check the conditions in the rule first
nsTemplateCondition* condition = mConditions;
while (condition) {
if (!condition->CheckMatch(aResult))
return 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
bool match;
nsresult rv = mRuleFilter->Match(aResult, mRuleNode, &match);
return NS_FAILED(rv) || match;
}
return true;
}
bool
nsTemplateRule::HasBinding(nsAtom* aSourceVariable,
nsAString& aExpr,
nsAtom* aTargetVariable) const
{
for (Binding* binding = mBindings; binding != nullptr; binding = binding->mNext) {
if ((binding->mSourceVariable == aSourceVariable) &&
(binding->mExpr.Equals(aExpr)) &&
(binding->mTargetVariable == aTargetVariable))
return true;
}
return false;
}
nsresult
nsTemplateRule::AddBinding(nsAtom* aSourceVariable,
nsAString& aExpr,
nsAtom* aTargetVariable)
{
NS_PRECONDITION(aSourceVariable != 0, "no source variable!");
if (! aSourceVariable)
return NS_ERROR_INVALID_ARG;
NS_PRECONDITION(aTargetVariable != 0, "no target variable!");
if (! aTargetVariable)
return NS_ERROR_INVALID_ARG;
NS_ASSERTION(! HasBinding(aSourceVariable, aExpr, aTargetVariable),
"binding added twice");
Binding* newbinding = new Binding;
if (! newbinding)
return NS_ERROR_OUT_OF_MEMORY;
newbinding->mSourceVariable = aSourceVariable;
newbinding->mTargetVariable = aTargetVariable;
newbinding->mParent = nullptr;
newbinding->mExpr.Assign(aExpr);
Binding* binding = mBindings;
Binding** link = &mBindings;
// Insert it at the end, unless we detect that an existing
// binding's source is dependent on the newbinding's target.
//
// XXXwaterson this isn't enough to make sure that we get all of
// the dependencies worked out right, but it'll do for now. For
// example, if you have (ab, bc, cd), and insert them in the order
// (cd, ab, bc), you'll get (bc, cd, ab). The good news is, if the
// person uses a natural ordering when writing the XUL, it'll all
// work out ok.
while (binding) {
if (binding->mSourceVariable == newbinding->mTargetVariable) {
binding->mParent = newbinding;
break;
}
else if (binding->mTargetVariable == newbinding->mSourceVariable) {
newbinding->mParent = binding;
}
link = &binding->mNext;
binding = binding->mNext;
}
// Insert the newbinding
*link = newbinding;
newbinding->mNext = binding;
return NS_OK;
}
nsresult
nsTemplateRule::AddBindingsToQueryProcessor(nsIXULTemplateQueryProcessor* aProcessor)
{
Binding* binding = mBindings;
while (binding) {
nsresult rv = aProcessor->AddBinding(mRuleNode, binding->mTargetVariable,
binding->mSourceVariable, binding->mExpr);
if (NS_FAILED(rv)) return rv;
binding = binding->mNext;
}
return NS_OK;
}

View File

@ -1,328 +0,0 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef nsTemplateRule_h__
#define nsTemplateRule_h__
#include "nsCOMPtr.h"
#include "nsAtom.h"
#include "nsIRDFDataSource.h"
#include "nsIRDFResource.h"
#include "nsIContent.h"
#include "nsIDOMNode.h"
#include "nsTArray.h"
#include "nsString.h"
#include "nsIXULTemplateRuleFilter.h"
#include "nsCycleCollectionParticipant.h"
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(nsAtom* aSourceVariable,
const nsAString& aRelation,
nsAtom* aTargetVariable,
bool mIgnoreCase,
bool mNegate);
nsTemplateCondition(nsAtom* aSourceVariable,
const nsAString& aRelation,
const nsAString& aTargets,
bool mIgnoreCase,
bool mNegate,
bool aIsMultiple);
nsTemplateCondition(const nsAString& aSource,
const nsAString& aRelation,
nsAtom* aTargetVariable,
bool mIgnoreCase,
bool mNegate);
~nsTemplateCondition() { MOZ_COUNT_DTOR(nsTemplateCondition); }
nsTemplateCondition* GetNext() { return mNext; }
void SetNext(nsTemplateCondition* aNext) { mNext = aNext; }
void SetRelation(const nsAString& aRelation);
bool
CheckMatch(nsIXULTemplateResult* aResult);
bool
CheckMatchStrings(const nsAString& aLeftString,
const nsAString& aRightString);
protected:
RefPtr<nsAtom> mSourceVariable;
nsString mSource;
ConditionRelation mRelation;
RefPtr<nsAtom> mTargetVariable;
nsTArray<nsString> mTargetList;
bool mIgnoreCase;
bool mNegate;
nsTemplateCondition* mNext;
};
/**
* A rule consists of:
*
* - Conditions, a set of unbound variables with consistency
* constraints that specify the values that each variable can
* assume. The conditions must be completely and consistently
* "bound" for the rule to be considered "matched".
*
* - Bindings, a set of unbound variables with consistency constraints
* that specify the values that each variable can assume. Unlike the
* conditions, the bindings need not be bound for the rule to be
* considered matched.
*
* - Content that should be constructed when the rule is "activated".
*
*/
class nsTemplateRule
{
public:
nsTemplateRule(nsIContent* aRuleNode,
nsIContent* aAction,
nsTemplateQuerySet* aQuerySet);
/**
* The copy-constructor should only be called from nsTArray when appending
* a new rule, otherwise things break because the copy constructor expects
* mBindings and mConditions to be nullptr.
*/
nsTemplateRule(const nsTemplateRule& aOtherRule);
~nsTemplateRule();
/**
* 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.
*/
nsIContent* GetAction() const { return mAction; }
/**
* 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.
*/
nsresult GetRuleNode(nsIDOMNode** aResult) const;
void SetVars(nsAtom* aRefVariable, nsAtom* aMemberVariable)
{
mRefVariable = aRefVariable;
mMemberVariable = aMemberVariable;
}
void SetRuleFilter(nsIXULTemplateRuleFilter* aRuleFilter)
{
mRuleFilter = aRuleFilter;
}
nsAtom* GetTag() { return mTag; }
void SetTag(nsAtom* aTag) { mTag = aTag; }
nsAtom* GetMemberVariable() { return mMemberVariable; }
/**
* Set the first condition for the rule. Other conditions are linked
* to it using the condition's SetNext method.
*/
void SetCondition(nsTemplateCondition* aConditions);
/**
* 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.
*/
bool
CheckMatch(nsIXULTemplateResult* aResult) const;
/**
* Determine if the rule has the specified binding
*/
bool
HasBinding(nsAtom* aSourceVariable,
nsAString& aExpr,
nsAtom* aTargetVariable) const;
/**
* Add a binding to the rule. A binding consists of an already-bound
* source variable, and the RDF property that should be tested to
* generate a target value. The target value is bound to a target
* variable.
*
* @param aSourceVariable the source variable 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(nsAtom* aSourceVariable,
nsAString& aExpr,
nsAtom* aTargetVariable);
/**
* 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
AddBindingsToQueryProcessor(nsIXULTemplateQueryProcessor* aProcessor);
void Traverse(nsCycleCollectionTraversalCallback &cb) const
{
cb.NoteXPCOMChild(mRuleNode);
cb.NoteXPCOMChild(mAction);
}
protected:
struct Binding {
RefPtr<nsAtom> mSourceVariable;
RefPtr<nsAtom> 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
RefPtr<nsAtom> mTag;
// linked-list of the bindings for the rule, owned by the rule.
Binding* mBindings;
RefPtr<nsAtom> mRefVariable;
RefPtr<nsAtom> 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:
nsTArray<nsTemplateRule> mRules;
// 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.
int32_t mPriority;
public:
// <query> node
nsCOMPtr<nsIContent> mQueryNode;
// compiled opaque query object returned by the query processor's
// CompileQuery call
nsCOMPtr<nsISupports> mCompiledQuery;
// indicates that the query will only generate content to be inserted into
// a container with this tag
RefPtr<nsAtom> mTag;
explicit nsTemplateQuerySet(int32_t aPriority)
: mPriority(aPriority)
{
MOZ_COUNT_CTOR(nsTemplateQuerySet);
}
~nsTemplateQuerySet()
{
MOZ_COUNT_DTOR(nsTemplateQuerySet);
}
int32_t Priority() const
{
return mPriority;
}
nsAtom* GetTag() { return mTag; }
void SetTag(nsAtom* aTag) { mTag = aTag; }
nsTemplateRule* NewRule(nsIContent* aRuleNode,
nsIContent* aAction,
nsTemplateQuerySet* aQuerySet)
{
// nsTemplateMatch stores the index as a 16-bit value,
// so check to make sure for overflow
if (mRules.Length() == INT16_MAX)
return nullptr;
return mRules.AppendElement(nsTemplateRule(aRuleNode, aAction,
aQuerySet));
}
void RemoveRule(nsTemplateRule *aRule)
{
mRules.RemoveElementAt(aRule - mRules.Elements());
}
int16_t RuleCount() const
{
return mRules.Length();
}
nsTemplateRule* GetRuleAt(int16_t aIndex)
{
if (uint32_t(aIndex) < mRules.Length()) {
return &mRules[aIndex];
}
return nullptr;
}
void Clear()
{
mRules.Clear();
}
};
#endif // nsTemplateRule_h__

View File

@ -1,482 +0,0 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsString.h"
#include "nsTreeRows.h"
#include <algorithm>
nsTreeRows::Subtree*
nsTreeRows::EnsureSubtreeFor(Subtree* aParent,
int32_t aChildIndex)
{
Subtree* subtree = GetSubtreeFor(aParent, aChildIndex);
if (! subtree) {
subtree = aParent->mRows[aChildIndex].mSubtree = new Subtree(aParent);
InvalidateCachedRow();
}
return subtree;
}
nsTreeRows::Subtree*
nsTreeRows::GetSubtreeFor(const Subtree* aParent,
int32_t aChildIndex,
int32_t* aSubtreeSize)
{
NS_PRECONDITION(aParent, "no parent");
NS_PRECONDITION(aChildIndex >= 0, "bad child index");
Subtree* result = nullptr;
if (aChildIndex < aParent->mCount)
result = aParent->mRows[aChildIndex].mSubtree;
if (aSubtreeSize)
*aSubtreeSize = result ? result->mSubtreeSize : 0;
return result;
}
void
nsTreeRows::RemoveSubtreeFor(Subtree* aParent, int32_t aChildIndex)
{
NS_PRECONDITION(aParent, "no parent");
NS_PRECONDITION(aChildIndex >= 0 && aChildIndex < aParent->mCount, "bad child index");
Row& row = aParent->mRows[aChildIndex];
if (row.mSubtree) {
int32_t subtreeSize = row.mSubtree->GetSubtreeSize();
delete row.mSubtree;
row.mSubtree = nullptr;
for (Subtree* subtree = aParent; subtree != nullptr; subtree = subtree->mParent)
subtree->mSubtreeSize -= subtreeSize;
}
InvalidateCachedRow();
}
nsTreeRows::iterator
nsTreeRows::First()
{
iterator result;
result.Append(&mRoot, 0);
result.SetRowIndex(0);
return result;
}
nsTreeRows::iterator
nsTreeRows::Last()
{
iterator result;
// Build up a path along the rightmost edge of the tree
Subtree* current = &mRoot;
int32_t count = current->Count();
do {
int32_t last = count - 1;
result.Append(current, last);
current = count ? GetSubtreeFor(current, last) : nullptr;
} while (current && ((count = current->Count()) != 0));
// Now, at the bottom rightmost leaf, advance us one off the end.
result.GetTop().mChildIndex++;
// Our row index will be the size of the root subree, plus one.
result.SetRowIndex(mRoot.GetSubtreeSize() + 1);
return result;
}
nsTreeRows::iterator
nsTreeRows::operator[](int32_t aRow)
{
// See if we're just lucky, and end up with something
// nearby. (This tends to happen a lot due to the way that we get
// asked for rows n' stuff.)
int32_t last = mLastRow.GetRowIndex();
if (last != -1) {
if (aRow == last)
return mLastRow;
else if (last + 1 == aRow)
return ++mLastRow;
else if (last - 1 == aRow)
return --mLastRow;
}
// Nope. Construct a path to the specified index. This is a little
// bit better than O(n), because we can skip over subtrees. (So it
// ends up being approximately linear in the subtree size, instead
// of the entire view size. But, most of the time, big views are
// flat. Oh well.)
iterator result;
Subtree* current = &mRoot;
int32_t index = 0;
result.SetRowIndex(aRow);
do {
int32_t subtreeSize;
Subtree* subtree = GetSubtreeFor(current, index, &subtreeSize);
if (subtreeSize >= aRow) {
result.Append(current, index);
current = subtree;
index = 0;
--aRow;
}
else {
++index;
aRow -= subtreeSize + 1;
}
} while (aRow >= 0);
mLastRow = result;
return result;
}
nsTreeRows::iterator
nsTreeRows::FindByResource(nsIRDFResource* aResource)
{
// XXX Mmm, scan through the rows one-by-one...
iterator last = Last();
iterator iter;
nsresult rv;
nsAutoString resourceid;
bool stringmode = 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 = 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) {
if (aResult == iter->mMatch->mResult)
break;
}
return iter;
}
void
nsTreeRows::Clear()
{
mRoot.Clear();
InvalidateCachedRow();
}
//----------------------------------------------------------------------
//
// nsTreeRows::Subtree
//
nsTreeRows::Subtree::~Subtree()
{
Clear();
}
void
nsTreeRows::Subtree::Clear()
{
for (int32_t i = mCount - 1; i >= 0; --i)
delete mRows[i].mSubtree;
delete[] mRows;
mRows = nullptr;
mCount = mCapacity = mSubtreeSize = 0;
}
nsTreeRows::iterator
nsTreeRows::Subtree::InsertRowAt(nsTemplateMatch* aMatch, int32_t aIndex)
{
if (mCount >= mCapacity || aIndex >= mCapacity) {
int32_t newCapacity = std::max(mCapacity * 2, aIndex + 1);
Row* newRows = new Row[newCapacity];
if (! newRows)
return iterator();
for (int32_t i = mCount - 1; i >= 0; --i)
newRows[i] = mRows[i];
delete[] mRows;
mRows = newRows;
mCapacity = newCapacity;
}
for (int32_t i = mCount - 1; i >= aIndex; --i)
mRows[i + 1] = mRows[i];
mRows[aIndex].mMatch = aMatch;
mRows[aIndex].mContainerType = eContainerType_Unknown;
mRows[aIndex].mContainerState = eContainerState_Unknown;
mRows[aIndex].mContainerFill = eContainerFill_Unknown;
mRows[aIndex].mSubtree = nullptr;
++mCount;
// Now build an iterator that points to the newly inserted element.
int32_t rowIndex = 0;
iterator result;
result.Push(this, aIndex);
for ( ; --aIndex >= 0; ++rowIndex) {
// Account for open subtrees in the absolute row index.
const Subtree *subtree = mRows[aIndex].mSubtree;
if (subtree)
rowIndex += subtree->mSubtreeSize;
}
Subtree *subtree = this;
do {
// Note that the subtree's size has expanded.
++subtree->mSubtreeSize;
Subtree *parent = subtree->mParent;
if (! parent)
break;
// Account for open subtrees in the absolute row index.
int32_t count = parent->Count();
for (aIndex = 0; aIndex < count; ++aIndex, ++rowIndex) {
const Subtree *child = (*parent)[aIndex].mSubtree;
if (subtree == child)
break;
if (child)
rowIndex += child->mSubtreeSize;
}
NS_ASSERTION(aIndex < count, "couldn't find subtree in parent");
result.Push(parent, aIndex);
subtree = parent;
++rowIndex; // One for the parent row.
} while (1);
result.SetRowIndex(rowIndex);
return result;
}
void
nsTreeRows::Subtree::RemoveRowAt(int32_t aIndex)
{
NS_PRECONDITION(aIndex >= 0 && aIndex < Count(), "bad index");
if (aIndex < 0 || aIndex >= Count())
return;
// How big is the subtree we're going to be removing?
int32_t subtreeSize = mRows[aIndex].mSubtree
? mRows[aIndex].mSubtree->GetSubtreeSize()
: 0;
++subtreeSize;
delete mRows[aIndex].mSubtree;
for (int32_t i = aIndex + 1; i < mCount; ++i)
mRows[i - 1] = mRows[i];
--mCount;
for (Subtree* subtree = this; subtree != nullptr; subtree = subtree->mParent)
subtree->mSubtreeSize -= subtreeSize;
}
//----------------------------------------------------------------------
//
// nsTreeRows::iterator
//
nsTreeRows::iterator::iterator(const iterator& aIterator)
: mRowIndex(aIterator.mRowIndex),
mLink(aIterator.mLink)
{
}
nsTreeRows::iterator&
nsTreeRows::iterator::operator=(const iterator& aIterator)
{
mRowIndex = aIterator.mRowIndex;
mLink = aIterator.mLink;
return *this;
}
void
nsTreeRows::iterator::Append(Subtree* aParent, int32_t aChildIndex)
{
Link *link = mLink.AppendElement();
if (link) {
link->mParent = aParent;
link->mChildIndex = aChildIndex;
}
else
NS_ERROR("out of memory");
}
void
nsTreeRows::iterator::Push(Subtree *aParent, int32_t aChildIndex)
{
Link *link = mLink.InsertElementAt(0);
if (link) {
link->mParent = aParent;
link->mChildIndex = aChildIndex;
}
else
NS_ERROR("out of memory");
}
bool
nsTreeRows::iterator::operator==(const iterator& aIterator) const
{
if (GetDepth() != aIterator.GetDepth())
return false;
if (GetDepth() == 0)
return true;
return GetTop() == aIterator.GetTop();
}
void
nsTreeRows::iterator::Next()
{
NS_PRECONDITION(GetDepth() > 0, "cannot increment an uninitialized iterator");
// Increment the absolute row index
++mRowIndex;
Link& top = GetTop();
// Is there a child subtree? If so, descend into the child
// subtree.
Subtree* subtree = top.GetRow().mSubtree;
if (subtree && subtree->Count()) {
Append(subtree, 0);
return;
}
// Have we exhausted the current subtree?
if (top.mChildIndex >= top.mParent->Count() - 1) {
// Yep. See if we've just iterated path the last element in
// the tree, period. Walk back up the stack, looking for any
// unfinished subtrees.
int32_t unfinished;
for (unfinished = GetDepth() - 2; unfinished >= 0; --unfinished) {
const Link& link = mLink[unfinished];
if (link.mChildIndex < link.mParent->Count() - 1)
break;
}
// If there are no unfinished subtrees in the stack, then this
// iterator is exhausted. Leave it in the same state that
// Last() does.
if (unfinished < 0) {
top.mChildIndex++;
return;
}
// Otherwise, we ran off the end of one of the inner
// subtrees. Pop up to the next unfinished level in the stack.
mLink.SetLength(unfinished + 1);
}
// Advance to the next child in this subtree
++(GetTop().mChildIndex);
}
void
nsTreeRows::iterator::Prev()
{
NS_PRECONDITION(GetDepth() > 0, "cannot increment an uninitialized iterator");
// Decrement the absolute row index
--mRowIndex;
// Move to the previous child in this subtree
--(GetTop().mChildIndex);
// Have we exhausted the current subtree?
if (GetTop().mChildIndex < 0) {
// Yep. See if we've just iterated back to the first element
// in the tree, period. Walk back up the stack, looking for
// any unfinished subtrees.
int32_t unfinished;
for (unfinished = GetDepth() - 2; unfinished >= 0; --unfinished) {
const Link& link = mLink[unfinished];
if (link.mChildIndex >= 0)
break;
}
// If there are no unfinished subtrees in the stack, then this
// iterator is exhausted. Leave it in the same state that
// First() does.
if (unfinished < 0)
return;
// Otherwise, we ran off the end of one of the inner
// subtrees. Pop up to the next unfinished level in the stack.
mLink.SetLength(unfinished + 1);
return;
}
// Is there a child subtree immediately prior to our current
// position? If so, descend into it, grovelling down to the
// deepest, rightmost left edge.
Subtree* parent = GetTop().GetParent();
int32_t index = GetTop().GetChildIndex();
Subtree* subtree = (*parent)[index].mSubtree;
if (subtree && subtree->Count()) {
do {
index = subtree->Count() - 1;
Append(subtree, index);
parent = subtree;
subtree = (*parent)[index].mSubtree;
} while (subtree && subtree->Count());
}
}

View File

@ -1,437 +0,0 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef nsTreeRows_h__
#define nsTreeRows_h__
#include "nsCOMPtr.h"
#include "nsTArray.h"
#include "PLDHashTable.h"
#include "nsIXULTemplateResult.h"
#include "nsIRDFResource.h"
class nsTemplateMatch;
/**
* This class maintains the state of the XUL tree builder's
* rows. It maps a row number to the nsTemplateMatch object that
* populates the row.
*/
class nsTreeRows
{
public:
class iterator;
friend class iterator;
enum Direction { eDirection_Forwards = +1, eDirection_Backwards = -1 };
enum ContainerType {
eContainerType_Unknown = 0,
eContainerType_Noncontainer = 1,
eContainerType_Container = 2
};
enum ContainerState {
eContainerState_Unknown = 0,
eContainerState_Open = 1,
eContainerState_Closed = 2
};
enum ContainerFill {
eContainerFill_Unknown = 0,
eContainerFill_Empty = 1,
eContainerFill_Nonempty = 2
};
class Subtree;
/**
* A row in the tree. Contains the match that the row
* corresponds to, and a pointer to the row's subtree, if there
* are any.
*/
struct Row {
nsTemplateMatch* mMatch;
ContainerType mContainerType : 4;
ContainerState mContainerState : 4;
ContainerFill mContainerFill : 4;
Subtree* mSubtree; // XXX eventually move to hashtable
};
/**
* A subtree in the tree. A subtree contains rows, which may
* contain other subtrees.
*/
class Subtree {
protected:
friend class nsTreeRows; // so that it can access members, for now
/**
* The parent subtree; null if we're the root
*/
Subtree* mParent;
/**
* The number of immediate children in this subtree
*/
int32_t mCount;
/**
* The capacity of the subtree
*/
int32_t mCapacity;
/**
* The total number of rows in this subtree, recursively
* including child subtrees.
*/
int32_t mSubtreeSize;
/**
* The array of rows in the subtree
*/
Row* mRows;
public:
/**
* Creates a subtree with the specified parent.
*/
explicit Subtree(Subtree* aParent)
: mParent(aParent),
mCount(0),
mCapacity(0),
mSubtreeSize(0),
mRows(nullptr) {}
~Subtree();
/**
* Return the number of immediate child rows in the subtree
*/
int32_t Count() const { return mCount; }
/**
* Return the number of rows in this subtree, as well as all
* the subtrees it contains.
*/
int32_t GetSubtreeSize() const { return mSubtreeSize; }
/**
* Retrieve the immediate child row at the specified index.
*/
const Row& operator[](int32_t aIndex) const {
NS_PRECONDITION(aIndex >= 0 && aIndex < mCount, "bad index");
return mRows[aIndex]; }
/**
* Retrieve the immediate row at the specified index.
*/
Row& operator[](int32_t aIndex) {
NS_PRECONDITION(aIndex >= 0 && aIndex < mCount, "bad index");
return mRows[aIndex]; }
/**
* Remove all rows from the subtree.
*/
void Clear();
protected:
/**
* Insert an immediate child row at the specified index.
*/
iterator InsertRowAt(nsTemplateMatch* aMatch, int32_t aIndex);
/**
* Remove an immediate child row from the specified index.
*/
void RemoveRowAt(int32_t aChildIndex);
};
friend class Subtree;
protected:
/**
* A link in the path through the view's tree.
*/
struct Link {
Subtree* mParent;
int32_t mChildIndex;
Link&
operator=(const Link& aLink) {
mParent = aLink.mParent;
mChildIndex = aLink.mChildIndex;
return *this; }
bool
operator==(const Link& aLink) const {
return (mParent == aLink.mParent)
&& (mChildIndex == aLink.mChildIndex); }
Subtree* GetParent() { return mParent; }
const Subtree* GetParent() const { return mParent; }
int32_t GetChildIndex() const { return mChildIndex; }
Row& GetRow() { return (*mParent)[mChildIndex]; }
const Row& GetRow() const { return (*mParent)[mChildIndex]; }
};
public:
/**
* An iterator that can be used to traverse the tree view.
*/
class iterator {
protected:
int32_t mRowIndex;
AutoTArray<Link, 8> mLink;
void Next();
void Prev();
friend class Subtree; // so InsertRowAt can initialize us
friend class nsTreeRows; // so nsTreeRows can initialize us
/**
* Used by operator[]() to initialize an iterator.
*/
void Append(Subtree* aParent, int32_t aChildIndex);
/**
* Used by InsertRowAt() to initialize an iterator.
*/
void Push(Subtree *aParent, int32_t aChildIndex);
/**
* Used by operator[]() and InsertRowAt() to initialize an iterator.
*/
void SetRowIndex(int32_t aRowIndex) { mRowIndex = aRowIndex; }
/**
* Handy accessors to the top element.
*/
Link& GetTop() { return mLink[mLink.Length() - 1]; }
const Link& GetTop() const { return mLink[mLink.Length() - 1]; }
public:
iterator() : mRowIndex(-1) {}
iterator(const iterator& aIterator);
iterator& operator=(const iterator& aIterator);
bool operator==(const iterator& aIterator) const;
bool operator!=(const iterator& aIterator) const {
return !aIterator.operator==(*this); }
const Row& operator*() const { return GetTop().GetRow(); }
Row& operator*() { return GetTop().GetRow(); }
const Row* operator->() const { return &(GetTop().GetRow()); }
Row* operator->() { return &(GetTop().GetRow()); }
iterator& operator++() { Next(); return *this; }
iterator operator++(int) { iterator temp(*this); Next(); return temp; }
iterator& operator--() { Prev(); return *this; }
iterator operator--(int) { iterator temp(*this); Prev(); return temp; }
/**
* Return the current parent link
*/
Subtree* GetParent() { return GetTop().GetParent(); }
const Subtree* GetParent() const { return GetTop().GetParent(); }
/**
* Return the current child index
*/
int32_t GetChildIndex() const { return GetTop().GetChildIndex(); }
/**
* Return the depth of the path the iterator is maintaining
* into the tree.
*/
int32_t GetDepth() const { return mLink.Length(); }
/**
* Return the current row index of the iterator
*/
int32_t GetRowIndex() const { return mRowIndex; }
/**
* Pop the iterator up a level.
*/
iterator& Pop() { mLink.SetLength(GetDepth() - 1); return *this; }
};
/**
* Retrieve the first element in the view
*/
iterator First();
/**
* Retrieve (one past) the last element in the view
*/
iterator Last();
/**
* Find the row that contains the given resource
*/
iterator FindByResource(nsIRDFResource* aResource);
/**
* Find the row that contains the result
*/
iterator Find(nsIXULTemplateResult* aResult);
/**
* Retrieve the ith element in the view
*/
iterator operator[](int32_t aIndex);
nsTreeRows() : mRoot(nullptr) {}
~nsTreeRows() {}
/**
* Ensure that a child subtree exists within the specified parent
* at the specified child index within the parent. (In other
* words, create a subtree if one doesn't already exist.)
*/
Subtree*
EnsureSubtreeFor(Subtree* aParent, int32_t aChildIndex);
/**
* Ensure that a child subtree exists at the iterator's position.
*/
Subtree*
EnsureSubtreeFor(iterator& aIterator) {
return EnsureSubtreeFor(aIterator.GetParent(),
aIterator.GetChildIndex()); }
/**
* Get the child subtree for the specified parent at the specified
* child index. Optionally return the child subtree's size. Will
* return `null' if no subtree exists.
*/
Subtree*
GetSubtreeFor(const Subtree* aParent,
int32_t aChildIndex,
int32_t* aSubtreeSize = nullptr);
/**
* Retrieve the size of the subtree within the specified parent.
*/
int32_t
GetSubtreeSizeFor(const Subtree* aParent,
int32_t aChildIndex) {
int32_t size;
GetSubtreeFor(aParent, aChildIndex, &size);
return size; }
/**
* Retrieve the size of the subtree within the specified parent.
*/
int32_t
GetSubtreeSizeFor(const iterator& aIterator) {
int32_t size;
GetSubtreeFor(aIterator.GetParent(), aIterator.GetChildIndex(), &size);
return size; }
/**
* Remove the specified subtree for a row, leaving the row itself
* intact.
*/
void
RemoveSubtreeFor(Subtree* aParent, int32_t aChildIndex);
/**
* Remove the specified subtree for a row, leaving the row itself
* intact.
*/
void
RemoveSubtreeFor(iterator& aIterator) {
RemoveSubtreeFor(aIterator.GetParent(), aIterator.GetChildIndex()); }
/**
* Remove the specified row from the view
*/
int32_t
RemoveRowAt(iterator& aIterator) {
iterator temp = aIterator--;
Subtree* parent = temp.GetParent();
parent->RemoveRowAt(temp.GetChildIndex());
InvalidateCachedRow();
return parent->Count(); }
/**
* Insert a new match into the view
*/
iterator
InsertRowAt(nsTemplateMatch* aMatch, Subtree* aSubtree, int32_t aChildIndex) {
InvalidateCachedRow();
return aSubtree->InsertRowAt(aMatch, aChildIndex); }
/**
* Raw access to the rows; e.g., for sorting.
*/
Row*
GetRowsFor(Subtree* aSubtree) { return aSubtree->mRows; }
/**
* Remove all of the rows
*/
void Clear();
/**
* Return the total number of rows in the tree view.
*/
int32_t Count() const { return mRoot.GetSubtreeSize(); }
/**
* Retrieve the root subtree
*/
Subtree* GetRoot() { return &mRoot; }
/**
* Set the root resource for the view
*/
void SetRootResource(nsIRDFResource* aResource) {
mRootResource = aResource; }
/**
* Retrieve the root resource for the view
*/
nsIRDFResource* GetRootResource() {
return mRootResource.get(); }
/**
* Invalidate the cached row; e.g., because the view has changed
* in a way that would corrupt the iterator.
*/
void
InvalidateCachedRow() { mLastRow = iterator(); }
protected:
/**
* The root subtree.
*/
Subtree mRoot;
/**
* The root resource for the view
*/
nsCOMPtr<nsIRDFResource> mRootResource;
/**
* The last row that was asked for by operator[]. By remembering
* this, we can usually avoid the O(n) search through the row
* array to find the row at the specified index.
*/
iterator mLastRow;
};
#endif // nsTreeRows_h__

View File

@ -1,118 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsXULTemplateQueryProcessorXML.h"
#include "nsXULTemplateResultXML.h"
#include "nsXMLBinding.h"
#include "mozilla/ErrorResult.h"
#include "mozilla/dom/XPathResult.h"
using namespace mozilla;
using namespace mozilla::dom;
nsXMLBindingSet::~nsXMLBindingSet()
{}
void
nsXMLBindingSet::AddBinding(nsAtom* aVar, nsAutoPtr<XPathExpression>&& aExpr)
{
nsAutoPtr<nsXMLBinding> newbinding(new nsXMLBinding(aVar, Move(aExpr)));
if (mFirst) {
nsXMLBinding* binding = mFirst;
while (binding) {
// if the target variable is already used in a binding, ignore it
// since it won't be useful for anything
if (binding->mVar == aVar)
return;
// add the binding at the end of the list
if (!binding->mNext) {
binding->mNext = newbinding;
return;
}
binding = binding->mNext;
}
}
else {
mFirst = newbinding;
}
}
int32_t
nsXMLBindingSet::LookupTargetIndex(nsAtom* aTargetVariable,
nsXMLBinding** aBinding)
{
int32_t idx = 0;
nsXMLBinding* binding = mFirst;
while (binding) {
if (binding->mVar == aTargetVariable) {
*aBinding = binding;
return idx;
}
idx++;
binding = binding->mNext;
}
*aBinding = nullptr;
return -1;
}
XPathResult*
nsXMLBindingValues::GetAssignmentFor(nsXULTemplateResultXML* aResult,
nsXMLBinding* aBinding,
int32_t aIndex,
uint16_t aType)
{
XPathResult* value = mValues.SafeElementAt(aIndex);
if (value) {
return value;
}
nsINode* contextNode = aResult->Node();
if (!contextNode) {
return nullptr;
}
mValues.EnsureLengthAtLeast(aIndex + 1);
ErrorResult ignored;
mValues[aIndex] = aBinding->mExpr->Evaluate(*contextNode, aType, nullptr,
ignored);
return mValues[aIndex];
}
nsINode*
nsXMLBindingValues::GetNodeAssignmentFor(nsXULTemplateResultXML* aResult,
nsXMLBinding* aBinding,
int32_t aIndex)
{
XPathResult* result = GetAssignmentFor(aResult, aBinding, aIndex,
XPathResult::FIRST_ORDERED_NODE_TYPE);
ErrorResult rv;
return result ? result->GetSingleNodeValue(rv) : nullptr;
}
void
nsXMLBindingValues::GetStringAssignmentFor(nsXULTemplateResultXML* aResult,
nsXMLBinding* aBinding,
int32_t aIndex,
nsAString& aValue)
{
XPathResult* result = GetAssignmentFor(aResult, aBinding, aIndex,
XPathResult::STRING_TYPE);
if (result) {
ErrorResult rv;
result->GetStringValue(aValue, rv);
} else {
aValue.Truncate();
}
}

View File

@ -1,137 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef nsXMLBinding_h__
#define nsXMLBinding_h__
#include "nsAutoPtr.h"
#include "nsAtom.h"
#include "mozilla/Attributes.h"
#include "mozilla/dom/XPathExpression.h"
class nsINode;
class nsXULTemplateResultXML;
class nsXMLBindingValues;
namespace mozilla {
namespace dom {
class XPathResult;
} // namespace dom
} // namespace mozilla
/**
* Classes related to storing bindings for XML handling.
*/
/**
* a <binding> description
*/
struct nsXMLBinding {
RefPtr<nsAtom> mVar;
nsAutoPtr<mozilla::dom::XPathExpression> mExpr;
nsAutoPtr<nsXMLBinding> mNext;
nsXMLBinding(nsAtom* aVar, nsAutoPtr<mozilla::dom::XPathExpression>&& aExpr)
: mVar(aVar), mExpr(aExpr), mNext(nullptr)
{
MOZ_COUNT_CTOR(nsXMLBinding);
}
~nsXMLBinding()
{
MOZ_COUNT_DTOR(nsXMLBinding);
}
};
/**
* a collection of <binding> descriptors. This object is refcounted by
* nsXMLBindingValues objects and the query processor.
*/
class nsXMLBindingSet final
{
~nsXMLBindingSet();
public:
// pointer to the first binding in a linked list
nsAutoPtr<nsXMLBinding> mFirst;
NS_INLINE_DECL_REFCOUNTING(nsXMLBindingSet);
/**
* Add a binding to the set
*/
void
AddBinding(nsAtom* aVar, nsAutoPtr<mozilla::dom::XPathExpression>&& aExpr);
/**
* The nsXMLBindingValues class 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.
*/
int32_t
LookupTargetIndex(nsAtom* aTargetVariable, nsXMLBinding** aBinding);
};
/**
* a set of values of bindings. This object is used once per result.
*/
class nsXMLBindingValues
{
protected:
// the binding set
RefPtr<nsXMLBindingSet> 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.
*/
nsTArray<RefPtr<mozilla::dom::XPathResult> > mValues;
public:
nsXMLBindingValues() { MOZ_COUNT_CTOR(nsXMLBindingValues); }
~nsXMLBindingValues() { MOZ_COUNT_DTOR(nsXMLBindingValues); }
nsXMLBindingSet* GetBindingSet() { return mBindings; }
void SetBindingSet(nsXMLBindingSet* aBindings) { mBindings = aBindings; }
int32_t
LookupTargetIndex(nsAtom* aTargetVariable, nsXMLBinding** aBinding)
{
return mBindings ?
mBindings->LookupTargetIndex(aTargetVariable, aBinding) : -1;
}
/**
* Retrieve the assignment for a particular variable
*
* aResult the result generated from the template
* aBinding the binding looked up using LookupTargetIndex
* aIndex the index of the assignment to retrieve
* aType the type of result expected
*/
mozilla::dom::XPathResult*
GetAssignmentFor(nsXULTemplateResultXML* aResult,
nsXMLBinding* aBinding,
int32_t idx,
uint16_t type);
nsINode*
GetNodeAssignmentFor(nsXULTemplateResultXML* aResult,
nsXMLBinding* aBinding,
int32_t idx);
void
GetStringAssignmentFor(nsXULTemplateResultXML* aResult,
nsXMLBinding* aBinding,
int32_t idx,
nsAString& aValue);
};
#endif // nsXMLBinding_h__

File diff suppressed because it is too large Load Diff

View File

@ -1,327 +0,0 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/*
A package of routines shared by the XUL content code.
*/
#include "mozilla/ArrayUtils.h"
#include "DateTimeFormat.h"
#include "nsCOMPtr.h"
#include "nsIContent.h"
#include "nsIDocument.h"
#include "nsIDOMElement.h"
#include "nsIDOMXULCommandDispatcher.h"
#include "nsIDOMXULDocument.h"
#include "nsIRDFNode.h"
#include "nsIRDFService.h"
#include "nsIServiceManager.h"
#include "nsIURL.h"
#include "nsXULContentUtils.h"
#include "nsLayoutCID.h"
#include "nsNameSpaceManager.h"
#include "nsRDFCID.h"
#include "nsString.h"
#include "nsGkAtoms.h"
#include "mozilla/Logging.h"
#include "prtime.h"
#include "rdf.h"
#include "nsContentUtils.h"
#include "nsICollation.h"
#include "nsCollationCID.h"
#include "nsIConsoleService.h"
#include "nsEscape.h"
using namespace mozilla;
//------------------------------------------------------------------------
nsIRDFService* nsXULContentUtils::gRDF;
nsICollation *nsXULContentUtils::gCollation;
extern LazyLogModule gXULTemplateLog;
#define XUL_RESOURCE(ident, uri) nsIRDFResource* nsXULContentUtils::ident
#define XUL_LITERAL(ident, val) nsIRDFLiteral* nsXULContentUtils::ident
#include "nsXULResourceList.h"
#undef XUL_RESOURCE
#undef XUL_LITERAL
//------------------------------------------------------------------------
// Constructors n' stuff
//
nsresult
nsXULContentUtils::Init()
{
static NS_DEFINE_CID(kRDFServiceCID, NS_RDFSERVICE_CID);
nsresult rv = CallGetService(kRDFServiceCID, &gRDF);
if (NS_FAILED(rv)) {
return rv;
}
#define XUL_RESOURCE(ident, uri) \
PR_BEGIN_MACRO \
rv = gRDF->GetResource(NS_LITERAL_CSTRING(uri), &(ident)); \
if (NS_FAILED(rv)) return rv; \
PR_END_MACRO
#define XUL_LITERAL(ident, val) \
PR_BEGIN_MACRO \
rv = gRDF->GetLiteral(val, &(ident)); \
if (NS_FAILED(rv)) return rv; \
PR_END_MACRO
#include "nsXULResourceList.h"
#undef XUL_RESOURCE
#undef XUL_LITERAL
return NS_OK;
}
nsresult
nsXULContentUtils::Finish()
{
NS_IF_RELEASE(gRDF);
#define XUL_RESOURCE(ident, uri) NS_IF_RELEASE(ident)
#define XUL_LITERAL(ident, val) NS_IF_RELEASE(ident)
#include "nsXULResourceList.h"
#undef XUL_RESOURCE
#undef XUL_LITERAL
NS_IF_RELEASE(gCollation);
return NS_OK;
}
nsICollation*
nsXULContentUtils::GetCollation()
{
if (!gCollation) {
nsCOMPtr<nsICollationFactory> colFactory =
do_CreateInstance(NS_COLLATIONFACTORY_CONTRACTID);
if (colFactory) {
DebugOnly<nsresult> rv = colFactory->CreateCollation(&gCollation);
NS_ASSERTION(NS_SUCCEEDED(rv),
"couldn't create collation instance");
} else
NS_ERROR("couldn't create instance of collation factory");
}
return gCollation;
}
//------------------------------------------------------------------------
nsresult
nsXULContentUtils::FindChildByTag(nsIContent* aElement,
int32_t aNameSpaceID,
nsAtom* aTag,
Element** aResult)
{
for (nsIContent* child = aElement->GetFirstChild();
child;
child = child->GetNextSibling()) {
if (child->IsElement() &&
child->NodeInfo()->Equals(aTag, aNameSpaceID)) {
NS_ADDREF(*aResult = child->AsElement());
return NS_OK;
}
}
*aResult = nullptr;
return NS_RDF_NO_VALUE; // not found
}
/*
Note: this routine is similar, yet distinctly different from, nsBookmarksService::GetTextForNode
*/
nsresult
nsXULContentUtils::GetTextForNode(nsIRDFNode* aNode, nsAString& aResult)
{
if (! aNode) {
aResult.Truncate();
return NS_OK;
}
nsresult rv;
// Literals are the most common, so try these first.
nsCOMPtr<nsIRDFLiteral> literal = do_QueryInterface(aNode);
if (literal) {
const char16_t* p;
rv = literal->GetValueConst(&p);
if (NS_FAILED(rv)) return rv;
aResult = p;
return NS_OK;
}
nsCOMPtr<nsIRDFDate> dateLiteral = do_QueryInterface(aNode);
if (dateLiteral) {
PRTime value;
rv = dateLiteral->GetValue(&value);
if (NS_FAILED(rv)) return rv;
nsAutoString str;
rv = DateTimeFormat::FormatPRTime(kDateFormatShort,
kTimeFormatSeconds,
value,
str);
aResult.Assign(str);
if (NS_FAILED(rv)) return rv;
return NS_OK;
}
nsCOMPtr<nsIRDFInt> intLiteral = do_QueryInterface(aNode);
if (intLiteral) {
int32_t value;
rv = intLiteral->GetValue(&value);
if (NS_FAILED(rv)) return rv;
aResult.Truncate();
nsAutoString intStr;
intStr.AppendInt(value, 10);
aResult.Append(intStr);
return NS_OK;
}
nsCOMPtr<nsIRDFResource> resource = do_QueryInterface(aNode);
if (resource) {
const char* p;
rv = resource->GetValueConst(&p);
if (NS_FAILED(rv)) return rv;
CopyUTF8toUTF16(p, aResult);
return NS_OK;
}
NS_ERROR("not a resource or a literal");
return NS_ERROR_UNEXPECTED;
}
nsresult
nsXULContentUtils::GetResource(int32_t aNameSpaceID, nsAtom* aAttribute, nsIRDFResource** aResult)
{
// construct a fully-qualified URI from the namespace/tag pair.
NS_PRECONDITION(aAttribute != nullptr, "null ptr");
if (! aAttribute)
return NS_ERROR_NULL_POINTER;
return GetResource(aNameSpaceID, nsDependentAtomString(aAttribute),
aResult);
}
nsresult
nsXULContentUtils::GetResource(int32_t aNameSpaceID, const nsAString& aAttribute, nsIRDFResource** aResult)
{
// construct a fully-qualified URI from the namespace/tag pair.
// XXX should we allow nodes with no namespace???
//NS_PRECONDITION(aNameSpaceID != kNameSpaceID_Unknown, "no namespace");
//if (aNameSpaceID == kNameSpaceID_Unknown)
// return NS_ERROR_UNEXPECTED;
nsresult rv;
nsAutoStringN<256> uri;
if (aNameSpaceID != kNameSpaceID_Unknown && aNameSpaceID != kNameSpaceID_None) {
rv = nsContentUtils::NameSpaceManager()->GetNameSpaceURI(aNameSpaceID, uri);
// XXX ignore failure; treat as "no namespace"
}
// XXX check to see if we need to insert a '/' or a '#'. Oy.
if (!uri.IsEmpty() && uri.Last() != '#' && uri.Last() != '/' && aAttribute.First() != '#')
uri.Append(char16_t('#'));
uri.Append(aAttribute);
rv = gRDF->GetUnicodeResource(uri, aResult);
NS_ASSERTION(NS_SUCCEEDED(rv), "unable to get resource");
if (NS_FAILED(rv)) return rv;
return NS_OK;
}
nsresult
nsXULContentUtils::SetCommandUpdater(nsIDocument* aDocument, Element* aElement)
{
// Deal with setting up a 'commandupdater'. Pulls the 'events' and
// 'targets' attributes off of aElement, and adds it to the
// document's command dispatcher.
NS_PRECONDITION(aDocument != nullptr, "null ptr");
if (! aDocument)
return NS_ERROR_NULL_POINTER;
NS_PRECONDITION(aElement != nullptr, "null ptr");
if (! aElement)
return NS_ERROR_NULL_POINTER;
nsresult rv;
nsCOMPtr<nsIDOMXULDocument> xuldoc = do_QueryInterface(aDocument);
NS_ASSERTION(xuldoc != nullptr, "not a xul document");
if (! xuldoc)
return NS_ERROR_UNEXPECTED;
nsCOMPtr<nsIDOMXULCommandDispatcher> dispatcher;
rv = xuldoc->GetCommandDispatcher(getter_AddRefs(dispatcher));
NS_ASSERTION(NS_SUCCEEDED(rv), "unable to get dispatcher");
if (NS_FAILED(rv)) return rv;
NS_ASSERTION(dispatcher != nullptr, "no dispatcher");
if (! dispatcher)
return NS_ERROR_UNEXPECTED;
nsAutoString events;
aElement->GetAttr(kNameSpaceID_None, nsGkAtoms::events, events);
if (events.IsEmpty())
events.Assign('*');
nsAutoString targets;
aElement->GetAttr(kNameSpaceID_None, nsGkAtoms::targets, targets);
if (targets.IsEmpty())
targets.Assign('*');
nsCOMPtr<nsIDOMElement> domelement = do_QueryInterface(aElement);
NS_ASSERTION(domelement != nullptr, "not a DOM element");
if (! domelement)
return NS_ERROR_UNEXPECTED;
rv = dispatcher->AddCommandUpdater(domelement, events, targets);
if (NS_FAILED(rv)) return rv;
return NS_OK;
}
void
nsXULContentUtils::LogTemplateError(const char* aStr)
{
nsAutoString message;
message.AssignLiteral("Error parsing template: ");
message.Append(NS_ConvertUTF8toUTF16(aStr).get());
nsCOMPtr<nsIConsoleService> cs = do_GetService(NS_CONSOLESERVICE_CONTRACTID);
if (cs) {
cs->LogStringMessage(message.get());
MOZ_LOG(gXULTemplateLog, LogLevel::Info, ("Error parsing template: %s", aStr));
}
}

View File

@ -1,153 +0,0 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/*
A package of routines shared by the XUL content code.
*/
#ifndef nsXULContentUtils_h__
#define nsXULContentUtils_h__
#include "nsISupports.h"
class nsAtom;
class nsIContent;
class nsIDocument;
class nsIRDFNode;
class nsIRDFResource;
class nsIRDFLiteral;
class nsIRDFService;
class nsICollation;
namespace mozilla {
namespace dom {
class Element;
}
}
// errors to pass to LogTemplateError
#define ERROR_TEMPLATE_INVALID_QUERYPROCESSOR \
"querytype attribute doesn't specify a valid query processor"
#define ERROR_TEMPLATE_INVALID_QUERYSET \
"unexpected <queryset> element"
#define ERROR_TEMPLATE_NO_MEMBERVAR \
"no member variable found. Action body should have an element with uri attribute"
#define ERROR_TEMPLATE_WHERE_NO_SUBJECT \
"<where> element is missing a subject attribute"
#define ERROR_TEMPLATE_WHERE_NO_RELATION \
"<where> element is missing a rel attribute"
#define ERROR_TEMPLATE_WHERE_NO_VALUE \
"<where> element is missing a value attribute"
#define ERROR_TEMPLATE_WHERE_NO_VAR \
"<where> element must have at least one variable as a subject or value"
#define ERROR_TEMPLATE_BINDING_BAD_SUBJECT \
"<binding> requires a variable for its subject attribute"
#define ERROR_TEMPLATE_BINDING_BAD_PREDICATE \
"<binding> element is missing a predicate attribute"
#define ERROR_TEMPLATE_BINDING_BAD_OBJECT \
"<binding> requires a variable for its object attribute"
#define ERROR_TEMPLATE_CONTENT_NOT_FIRST \
"expected <content> to be first"
#define ERROR_TEMPLATE_MEMBER_NOCONTAINERVAR \
"<member> requires a variable for its container attribute"
#define ERROR_TEMPLATE_MEMBER_NOCHILDVAR \
"<member> requires a variable for its child attribute"
#define ERROR_TEMPLATE_TRIPLE_NO_VAR \
"<triple> should have at least one variable as a subject or object"
#define ERROR_TEMPLATE_TRIPLE_BAD_SUBJECT \
"<triple> requires a variable for its subject attribute"
#define ERROR_TEMPLATE_TRIPLE_BAD_PREDICATE \
"<triple> should have a non-variable value as a predicate"
#define ERROR_TEMPLATE_TRIPLE_BAD_OBJECT \
"<triple> requires a variable for its object attribute"
#define ERROR_TEMPLATE_MEMBER_UNBOUND \
"neither container or child variables of <member> has a value"
#define ERROR_TEMPLATE_TRIPLE_UNBOUND \
"neither subject or object variables of <triple> has a value"
#define ERROR_TEMPLATE_BAD_XPATH \
"XPath expression in query could not be parsed"
#define ERROR_TEMPLATE_BAD_ASSIGN_XPATH \
"XPath expression in <assign> could not be parsed"
#define ERROR_TEMPLATE_BAD_BINDING_XPATH \
"XPath expression in <binding> could not be parsed"
#define ERROR_TEMPLATE_STORAGE_BAD_URI \
"only profile: or file URI are allowed"
#define ERROR_TEMPLATE_STORAGE_CANNOT_OPEN_DATABASE \
"cannot open given database"
#define ERROR_TEMPLATE_STORAGE_BAD_QUERY \
"syntax error in the SQL query"
#define ERROR_TEMPLATE_STORAGE_UNKNOWN_QUERY_PARAMETER \
"the given named parameter is unknown in the SQL query"
#define ERROR_TEMPLATE_STORAGE_WRONG_TYPE_QUERY_PARAMETER \
"the type of a query parameter is wrong"
#define ERROR_TEMPLATE_STORAGE_QUERY_PARAMETER_NOT_BOUND \
"a query parameter cannot be bound to the SQL query"
class nsXULContentUtils
{
protected:
static nsIRDFService* gRDF;
static nsICollation *gCollation;
static bool gDisableXULCache;
static int
DisableXULCacheChangedCallback(const char* aPrefName, void* aClosure);
public:
static nsresult
Init();
static nsresult
Finish();
static nsresult
FindChildByTag(nsIContent *aElement,
int32_t aNameSpaceID,
nsAtom* aTag,
mozilla::dom::Element** aResult);
static nsresult
FindChildByResource(nsIContent* aElement,
nsIRDFResource* aResource,
nsIContent** aResult);
static nsresult
GetTextForNode(nsIRDFNode* aNode, nsAString& aResult);
static nsresult
GetResource(int32_t aNameSpaceID, nsAtom* aAttribute, nsIRDFResource** aResult);
static nsresult
GetResource(int32_t aNameSpaceID, const nsAString& aAttribute, nsIRDFResource** aResult);
static nsresult
SetCommandUpdater(nsIDocument* aDocument, mozilla::dom::Element* aElement);
/**
* Log a message to the error console
*/
static void
LogTemplateError(const char* aMsg);
static nsIRDFService*
RDFService()
{
return gRDF;
}
static nsICollation*
GetCollation();
#define XUL_RESOURCE(ident, uri) static nsIRDFResource* ident
#define XUL_LITERAL(ident, val) static nsIRDFLiteral* ident
#include "nsXULResourceList.h"
#undef XUL_RESOURCE
#undef XUL_LITERAL
};
#endif // nsXULContentUtils_h__

View File

@ -1,13 +0,0 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
// N.B., no include guard! We'll include this multiple times in some
// files.
XUL_RESOURCE(NC_child, NC_NAMESPACE_URI "child");
XUL_RESOURCE(NC_Folder, NC_NAMESPACE_URI "Folder");
XUL_RESOURCE(NC_open, NC_NAMESPACE_URI "open");
XUL_LITERAL(true_, u"true");

File diff suppressed because it is too large Load Diff

View File

@ -1,561 +0,0 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef nsXULTemplateBuilder_h__
#define nsXULTemplateBuilder_h__
#include "mozilla/dom/Element.h"
#include "nsStubDocumentObserver.h"
#include "nsIObserver.h"
#include "nsIXULTemplateBuilder.h"
#include "nsCOMArray.h"
#include "nsTArray.h"
#include "nsDataHashtable.h"
#include "nsCycleCollectionParticipant.h"
#include "mozilla/Logging.h"
extern mozilla::LazyLogModule gXULTemplateLog;
class nsIObserverService;
class nsIRDFCompositeDataSource;
class nsIRDFContainerUtils;
class nsIRDFDataSource;
class nsIRDFService;
class nsIScriptSecurityManager;
class nsIXULTemplateQueryProcessor;
class nsTemplateCondition;
class nsTemplateRule;
class nsTemplateMatch;
class nsTemplateQuerySet;
namespace mozilla {
namespace dom {
class XULBuilderListener;
} // namespace dom
} // namespace mozilla
/**
* An object that translates an RDF graph into a presentation using a
* set of rules.
*/
class nsXULTemplateBuilder : public nsIXULTemplateBuilder,
public nsIObserver,
public nsStubDocumentObserver,
public nsWrapperCache
{
void CleanUp(bool aIsFinal);
void DestroyMatchMap();
public:
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(bool aIsFinal);
// nsISupports interface
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_AMBIGUOUS(nsXULTemplateBuilder,
nsIXULTemplateBuilder)
virtual JSObject* WrapObject(JSContext* aCx,
JS::Handle<JSObject*> aGivenProto) override;
Element* GetParentObject()
{
return mRoot;
}
Element* GetRoot()
{
return mRoot;
}
nsISupports* GetDatasource();
void SetDatasource(nsISupports* aDatasource, mozilla::ErrorResult& aError);
nsIRDFCompositeDataSource* GetDatabase()
{
return mCompDB;
}
nsIXULTemplateResult* GetRootResult()
{
return mRootResult;
}
void Rebuild(mozilla::ErrorResult& aError);
void Refresh(mozilla::ErrorResult& aError);
void AddResult(nsIXULTemplateResult* aResult, nsINode& aQueryNode,
mozilla::ErrorResult& aError);
void RemoveResult(nsIXULTemplateResult* aResult,
mozilla::ErrorResult& aError);
void ReplaceResult(nsIXULTemplateResult* aOldResult,
nsIXULTemplateResult* aNewResult,
nsINode& aQueryNode,
mozilla::ErrorResult& aError);
void ResultBindingChanged(nsIXULTemplateResult* aResult,
mozilla::ErrorResult& aError);
nsIXULTemplateResult* GetResultForId(const nsAString& aId,
mozilla::ErrorResult& aError);
virtual nsIXULTemplateResult* GetResultForContent(Element& aElement)
{
return nullptr;
}
virtual bool HasGeneratedContent(nsIRDFResource* aResource,
const nsAString& aTag,
mozilla::ErrorResult& aError)
{
return false;
}
void AddRuleFilter(nsINode& aRule, nsIXULTemplateRuleFilter* aFilter,
mozilla::ErrorResult& aError);
void AddListener(mozilla::dom::XULBuilderListener& aListener);
void RemoveListener(mozilla::dom::XULBuilderListener& aListener);
// nsIXULTemplateBuilder interface
NS_DECL_NSIXULTEMPLATEBUILDER
// nsIObserver Interface
NS_DECL_NSIOBSERVER
// nsIMutationObserver
NS_DECL_NSIMUTATIONOBSERVER_ATTRIBUTECHANGED
NS_DECL_NSIMUTATIONOBSERVER_CONTENTREMOVED
NS_DECL_NSIMUTATIONOBSERVER_NODEWILLBEDESTROYED
/**
* Remove an old result and/or add a new result. This method will retrieve
* the set of containers where the result could be inserted and either add
* the new result to those containers, or remove the result from those
* containers. UpdateResultInContainer is called for each container.
*
* @param aOldResult result to remove
* @param aNewResult result to add
* @param aQueryNode query node for new result
*/
nsresult
UpdateResult(nsIXULTemplateResult* aOldResult,
nsIXULTemplateResult* aNewResult,
nsINode* aQueryNode);
/**
* Remove an old result and/or add a new result from a specific container.
*
* @param aOldResult result to remove
* @param aNewResult result to add
* @param aQueryNode queryset for the new result
* @param aOldId id of old result
* @param aNewId id of new result
* @param aInsertionPoint container to remove or add result inside
*/
nsresult
UpdateResultInContainer(nsIXULTemplateResult* aOldResult,
nsIXULTemplateResult* aNewResult,
nsTemplateQuerySet* aQuerySet,
nsIRDFResource* aOldId,
nsIRDFResource* aNewId,
Element* aInsertionPoint);
nsresult
ComputeContainmentProperties();
static bool
IsTemplateElement(nsIContent* aContent);
virtual nsresult
RebuildAll() = 0; // must be implemented by subclasses
void RunnableRebuild() { Rebuild(); }
void RunnableLoadAndRebuild() {
Uninit(false); // Reset results
nsCOMPtr<nsIDocument> doc = mRoot ? mRoot->GetComposedDoc() : nullptr;
if (doc) {
bool shouldDelay;
LoadDataSources(doc, &shouldDelay);
if (!shouldDelay) {
Rebuild();
}
}
}
// mRoot should not be cleared until after Uninit is finished so that
// generated content can be removed during uninitialization.
void UninitFalse() { Uninit(false); mRoot = nullptr; }
void UninitTrue() { Uninit(true); mRoot = nullptr; }
/**
* Find the <template> tag that applies for this builder
*/
nsresult
GetTemplateRoot(Element** aResult);
/**
* Compile the template's queries
*/
nsresult
CompileQueries();
/**
* 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
CompileTemplate(Element* aTemplate,
nsTemplateQuerySet* aQuerySet,
bool aIsQuerySet,
int32_t* aPriority,
bool* aCanUseTemplate);
/**
* 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 aQuerySet the queryset
*/
nsresult
CompileExtendedQuery(Element* aRuleElement,
nsIContent* aActionElement,
nsAtom* aMemberVariable,
nsTemplateQuerySet* aQuerySet);
/**
* Determine the ref variable and tag from inside a RDF query.
*/
void DetermineRDFQueryRef(nsIContent* aQueryElement, nsAtom** tag);
/**
* Determine the member variable from inside an action body. It will be
* the value of the uri attribute on a node.
*/
already_AddRefed<nsAtom> DetermineMemberVariable(nsIContent* aElement);
/**
* 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
*/
nsresult
CompileSimpleQuery(Element* aRuleElement,
nsTemplateQuerySet* aQuerySet,
bool* aCanUseTemplate);
/**
* Compile the <conditions> tag in a rule
*
* @param aRule template rule
* @param aConditions <conditions> element
*/
nsresult
CompileConditions(nsTemplateRule* aRule, Element* aConditions);
/**
* 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
CompileWhereCondition(nsTemplateRule* aRule,
Element* aCondition,
nsTemplateCondition** aCurrentCondition);
/**
* Compile the <bindings> for an extended template syntax rule.
*/
nsresult
CompileBindings(nsTemplateRule* aRule, nsIContent* aBindings);
/**
* Compile a single binding for an extended template syntax rule.
*/
nsresult
CompileBinding(nsTemplateRule* aRule, Element* aBinding);
/**
* Add automatic bindings for simple rules
*/
nsresult
AddSimpleRuleBindings(nsTemplateRule* aRule, Element* aElement);
static void
AddBindingsFor(nsXULTemplateBuilder* aSelf,
const nsAString& aVariable,
void* aClosure);
/**
* Load the datasources for the template. shouldDelayBuilding is an out
* parameter which will be set to true to indicate that content building
* should not be performed yet as the datasource has not yet loaded. If
* false, the datasource has already loaded so building can proceed
* immediately. In the former case, the datasource or query processor
* should either rebuild the template or update results when the
* datasource is loaded as needed.
*/
nsresult
LoadDataSources(nsIDocument* aDoc, bool* shouldDelayBuilding);
/**
* Called by LoadDataSources to load a datasource given a uri list
* in aDataSource. The list is a set of uris separated by spaces.
* If aIsRDFQuery is true, then this is for an RDF datasource which
* causes the method to check for additional flags specific to the
* RDF processor.
*/
nsresult
LoadDataSourceUrls(nsIDocument* aDocument,
const nsAString& aDataSources,
bool aIsRDFQuery,
bool* aShouldDelayBuilding);
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 where 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.
* @param aRuleIndex [out] index of the rule
*/
nsresult
DetermineMatchedRule(nsIContent* aContainer,
nsIXULTemplateResult* aResult,
nsTemplateQuerySet* aQuerySet,
nsTemplateRule** aMatchedRule,
int16_t *aRuleIndex);
// 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.
void
ParseAttribute(const nsAString& aAttributeValue,
void (*aVariableCallback)(nsXULTemplateBuilder* aThis, const nsAString&, void*),
void (*aTextCallback)(nsXULTemplateBuilder* aThis, const nsAString&, void*),
void* aClosure);
nsresult
SubstituteText(nsIXULTemplateResult* aMatch,
const nsAString& aAttributeValue,
nsAString& aResult);
static void
SubstituteTextAppendText(nsXULTemplateBuilder* aThis, const nsAString& aText, void* aClosure);
static void
SubstituteTextReplaceVariable(nsXULTemplateBuilder* aThis, const nsAString& aVariable, void* aClosure);
/**
* 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:
explicit nsXULTemplateBuilder(Element* aElement);
virtual ~nsXULTemplateBuilder();
nsCOMPtr<nsISupports> mDataSource;
nsCOMPtr<nsIRDFDataSource> mDB;
nsCOMPtr<nsIRDFCompositeDataSource> mCompDB;
/**
* Circular reference, broken when the document is destroyed.
*/
nsCOMPtr<Element> mRoot;
/**
* The root result, translated from the root element's ref
*/
nsCOMPtr<nsIXULTemplateResult> mRootResult;
nsTArray<nsCOMPtr<nsIXULBuilderListener>> mListeners;
/**
* The query processor which generates results
*/
nsCOMPtr<nsIXULTemplateQueryProcessor> mQueryProcessor;
/**
* The list of querysets
*/
nsTArray<nsTemplateQuerySet *> mQuerySets;
/**
* Set to true if the rules have already been compiled
*/
bool mQueriesCompiled;
/**
* The default reference and member variables.
*/
RefPtr<nsAtom> mRefVariable;
RefPtr<nsAtom> 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;
// pseudo-constants
static nsrefcnt gRefCnt;
static nsIRDFService* gRDFService;
static nsIRDFContainerUtils* gRDFContainerUtils;
static nsIScriptSecurityManager* gScriptSecurityManager;
static nsIPrincipal* gSystemPrincipal;
static nsIObserverService* gObserverService;
enum {
eDontTestEmpty = (1 << 0),
eDontRecurse = (1 << 1),
eLoggingEnabled = (1 << 2)
};
int32_t mFlags;
/**
* Stack-based helper class to maintain a list of ``activated''
* resources; i.e., resources for which we are currently building
* content.
*/
class ActivationEntry {
public:
nsIRDFResource *mResource;
ActivationEntry *mPrevious;
ActivationEntry **mLink;
ActivationEntry(nsIRDFResource *aResource, ActivationEntry **aLink)
: mResource(aResource),
mPrevious(*aLink),
mLink(aLink) { *mLink = this; }
~ActivationEntry() { *mLink = mPrevious; }
};
/**
* The top of the stack of resources that we're currently building
* content for.
*/
ActivationEntry *mTop;
/**
* Determine if a resource is currently on the activation stack.
*/
bool
IsActivated(nsIRDFResource *aResource);
/**
* 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. Possible
* insertion locations may optionally be set for new content, depending on
* the builder being used. Note that *aLocations or some items within
* aLocations may be null.
*/
virtual bool
GetInsertionLocations(nsIXULTemplateResult* aResult,
nsCOMArray<Element>** aLocations) = 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(nsIXULTemplateResult* aOldResult,
nsTemplateMatch* aNewMatch,
nsTemplateRule* aNewMatchRule,
Element* aContext) = 0;
/**
* Must be implemented by subclasses. Handle change in bound
* variable values for aResult. aModifiedVars contains the set
* of variables that have 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
SynchronizeResult(nsIXULTemplateResult* aResult) = 0;
/**
* Output a new match or removed match to the console.
*
* @param aId id of the result
* @param aMatch new or removed match
* @param aIsNew true for new matched, false for removed matches
*/
void
OutputMatchToLog(nsIRDFResource* aId,
nsTemplateMatch* aMatch,
bool aIsNew);
virtual void Traverse(nsCycleCollectionTraversalCallback &cb) const
{
}
/**
* Start observing events from the observer service and the given
* document.
*
* @param aDocument the document to observe
*/
void StartObserving(nsIDocument* aDocument);
/**
* Stop observing events from the observer service and any associated
* document.
*/
void StopObserving();
/**
* Document that we're observing. Weak ref!
*/
nsIDocument* mObservedDocument;
};
nsresult NS_NewXULContentBuilder(Element* aElement,
nsIXULTemplateBuilder** aBuilder);
#endif // nsXULTemplateBuilder_h__

File diff suppressed because it is too large Load Diff

View File

@ -1,355 +0,0 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef nsXULTemplateQueryProcessorRDF_h__
#define nsXULTemplateQueryProcessorRDF_h__
#include "nsIRDFContainer.h"
#include "nsIRDFContainerUtils.h"
#include "nsIRDFDataSource.h"
#include "nsIRDFObserver.h"
#include "nsIRDFService.h"
#include "nsIXULTemplateBuilder.h"
#include "nsIXULTemplateQueryProcessor.h"
#include "nsCollationCID.h"
#include "nsResourceSet.h"
#include "nsRuleNetwork.h"
#include "nsRDFQuery.h"
#include "nsRDFBinding.h"
#include "nsXULTemplateResultSetRDF.h"
#include "nsCOMArray.h"
#include "nsString.h"
#include "nsClassHashtable.h"
#include "nsRefPtrHashtable.h"
#include "nsCycleCollectionParticipant.h"
#include "mozilla/Attributes.h"
#include "mozilla/Logging.h"
extern mozilla::LazyLogModule gXULTemplateLog;
class nsIContent;
class nsXULTemplateResultRDF;
namespace mozilla {
namespace dom {
class Element;
}
}
/**
* An object that generates results from a query on an RDF graph
*/
class nsXULTemplateQueryProcessorRDF final : public nsIXULTemplateQueryProcessor,
public nsIRDFObserver
{
public:
typedef nsTArray<RefPtr<nsXULTemplateResultRDF> > ResultArray;
nsXULTemplateQueryProcessorRDF();
nsresult InitGlobals();
// nsISupports interface
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsXULTemplateQueryProcessorRDF,
nsIXULTemplateQueryProcessor)
// 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,
bool* aIsContainer);
/*
* Check if a resource does not have any children
*/
nsresult
CheckEmpty(nsIRDFResource* aTargetResource,
bool* aIsEmpty);
/**
* Check if a resource is a separator
*/
nsresult
CheckIsSeparator(nsIRDFResource* aResource, bool* aIsSeparator);
/*
* 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(nsAtom* 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,
Element* 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,
Element* 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 returned as aLastNode. All nodes will have been added to mAllTests
* which owns the nodes.
*/
nsresult
CompileSimpleQuery(nsRDFQuery* aQuery,
mozilla::dom::Element* 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.
*/
void
AddBindingDependency(nsXULTemplateResultRDF* aResult,
nsIRDFResource* aResource);
/**
* Remove a dependency a result has on a particular resource.
*/
void
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);
/**
* Return the index of a result's resource in its RDF container
*/
int32_t
GetContainerIndexOf(nsIXULTemplateResult* aResult);
/**
* Given a result and a predicate to sort on, get the target value of
* the triple to use for sorting. The sort predicate is the predicate
* with '?sort=true' appended.
*/
nsresult
GetSortValue(nsIXULTemplateResult* aResult,
nsIRDFResource* aPredicate,
nsIRDFResource* aSortPredicate,
nsISupports** aResultNode);
nsIRDFDataSource* GetDataSource() { return mDB; }
nsIXULTemplateBuilder* GetBuilder() { return mBuilder; }
nsResourceSet& ContainmentProperties() { return mContainmentProperties; }
nsresult
Log(const char* aOperation,
nsIRDFResource* aSource,
nsIRDFResource* aProperty,
nsIRDFNode* aTarget);
#define LOG(_op, _src, _prop, _targ) \
Log(_op, _src, _prop, _targ)
protected:
~nsXULTemplateQueryProcessorRDF();
// 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
bool 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
bool mGenerationStarted;
// nesting level for RDF batch notifications
int32_t 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;
// the reference variable
RefPtr<nsAtom> mRefVariable;
// 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, ResultArray> 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
*/
nsTArray<nsCOMPtr<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;
static nsIRDFResource* kNC_BookmarkSeparator;
static nsIRDFResource* kRDF_type;
};
#endif // nsXULTemplateQueryProcessorRDF_h__

View File

@ -1,507 +0,0 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "prprf.h"
#include "nsIDOMNodeList.h"
#include "nsUnicharUtils.h"
#include "nsArrayUtils.h"
#include "nsVariant.h"
#include "nsAppDirectoryServiceDefs.h"
#include "nsIURI.h"
#include "nsIFileChannel.h"
#include "nsIFile.h"
#include "nsGkAtoms.h"
#include "nsContentUtils.h"
#include "nsXULTemplateBuilder.h"
#include "nsXULTemplateResultStorage.h"
#include "nsXULContentUtils.h"
#include "nsXULSortService.h"
#include "mozIStorageService.h"
#include "nsIChannel.h"
#include "nsIDocument.h"
#include "nsNetUtil.h"
#include "nsTemplateMatch.h"
//----------------------------------------------------------------------
//
// nsXULTemplateResultSetStorage
//
NS_IMPL_ISUPPORTS(nsXULTemplateResultSetStorage, nsISimpleEnumerator)
nsXULTemplateResultSetStorage::nsXULTemplateResultSetStorage(mozIStorageStatement* aStatement)
: mStatement(aStatement)
{
uint32_t count;
nsresult rv = aStatement->GetColumnCount(&count);
if (NS_FAILED(rv)) {
mStatement = nullptr;
return;
}
for (uint32_t c = 0; c < count; c++) {
nsAutoCString name;
rv = aStatement->GetColumnName(c, name);
if (NS_SUCCEEDED(rv)) {
RefPtr<nsAtom> columnName = NS_Atomize(NS_LITERAL_CSTRING("?") + name);
mColumnNames.AppendElement(columnName);
}
}
}
NS_IMETHODIMP
nsXULTemplateResultSetStorage::HasMoreElements(bool *aResult)
{
if (!mStatement) {
*aResult = false;
return NS_OK;
}
nsresult rv = mStatement->ExecuteStep(aResult);
NS_ENSURE_SUCCESS(rv, rv);
// Because the nsXULTemplateResultSetStorage is owned by many nsXULTemplateResultStorage objects,
// it could live longer than it needed to get results.
// So we destroy the statement to free resources when all results are fetched
if (!*aResult) {
mStatement = nullptr;
}
return NS_OK;
}
NS_IMETHODIMP
nsXULTemplateResultSetStorage::GetNext(nsISupports **aResult)
{
nsXULTemplateResultStorage* result =
new nsXULTemplateResultStorage(this);
*aResult = result;
NS_ADDREF(result);
return NS_OK;
}
int32_t
nsXULTemplateResultSetStorage::GetColumnIndex(nsAtom* aColumnName)
{
int32_t count = mColumnNames.Length();
for (int32_t c = 0; c < count; c++) {
if (mColumnNames[c] == aColumnName)
return c;
}
return -1;
}
void
nsXULTemplateResultSetStorage::FillColumnValues(nsCOMArray<nsIVariant>& aArray)
{
if (!mStatement)
return;
int32_t count = mColumnNames.Length();
for (int32_t c = 0; c < count; c++) {
RefPtr<nsVariant> value = new nsVariant();
int32_t type;
mStatement->GetTypeOfIndex(c, &type);
if (type == mStatement->VALUE_TYPE_INTEGER) {
int64_t val = mStatement->AsInt64(c);
value->SetAsInt64(val);
}
else if (type == mStatement->VALUE_TYPE_FLOAT) {
double val = mStatement->AsDouble(c);
value->SetAsDouble(val);
}
else {
nsAutoString val;
nsresult rv = mStatement->GetString(c, val);
if (NS_FAILED(rv))
value->SetAsAString(EmptyString());
else
value->SetAsAString(val);
}
aArray.AppendObject(value);
}
}
//----------------------------------------------------------------------
//
// nsXULTemplateQueryProcessorStorage
//
NS_IMPL_ISUPPORTS(nsXULTemplateQueryProcessorStorage,
nsIXULTemplateQueryProcessor)
nsXULTemplateQueryProcessorStorage::nsXULTemplateQueryProcessorStorage()
: mGenerationStarted(false)
{
}
NS_IMETHODIMP
nsXULTemplateQueryProcessorStorage::GetDatasource(nsIArray* aDataSources,
nsIDOMNode* aRootNode,
bool aIsTrusted,
nsIXULTemplateBuilder* aBuilder,
bool* aShouldDelayBuilding,
nsISupports** aReturn)
{
*aReturn = nullptr;
*aShouldDelayBuilding = false;
if (!aIsTrusted) {
return NS_OK;
}
uint32_t length;
nsresult rv = aDataSources->GetLength(&length);
NS_ENSURE_SUCCESS(rv, rv);
if (length == 0) {
return NS_OK;
}
// We get only the first uri. This query processor supports
// only one database at a time.
nsCOMPtr<nsIURI> uri;
uri = do_QueryElementAt(aDataSources, 0);
if (!uri) {
// No uri in the list of datasources
return NS_OK;
}
nsCOMPtr<mozIStorageService> storage =
do_GetService("@mozilla.org/storage/service;1", &rv);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIFile> databaseFile;
nsAutoCString scheme;
rv = uri->GetScheme(scheme);
NS_ENSURE_SUCCESS(rv, rv);
if (scheme.EqualsLiteral("profile")) {
nsAutoCString path;
rv = uri->GetPathQueryRef(path);
NS_ENSURE_SUCCESS(rv, rv);
if (path.IsEmpty()) {
return NS_ERROR_FAILURE;
}
rv = NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR,
getter_AddRefs(databaseFile));
NS_ENSURE_SUCCESS(rv, rv);
rv = databaseFile->AppendNative(path);
NS_ENSURE_SUCCESS(rv, rv);
}
else {
nsCOMPtr<nsIChannel> channel;
nsCOMPtr<nsINode> node = do_QueryInterface(aRootNode);
// The following channel is never openend, so it does not matter what
// securityFlags we pass; let's follow the principle of least privilege.
rv = NS_NewChannel(getter_AddRefs(channel),
uri,
node,
nsILoadInfo::SEC_REQUIRE_SAME_ORIGIN_DATA_IS_BLOCKED,
nsIContentPolicy::TYPE_OTHER);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIFileChannel> fileChannel = do_QueryInterface(channel, &rv);
if (NS_FAILED(rv)) { // if it fails, not a file url
nsXULContentUtils::LogTemplateError(ERROR_TEMPLATE_STORAGE_BAD_URI);
return rv;
}
rv = fileChannel->GetFile(getter_AddRefs(databaseFile));
NS_ENSURE_SUCCESS(rv, rv);
}
// ok now we have an URI of a sqlite file
nsCOMPtr<mozIStorageConnection> connection;
rv = storage->OpenDatabase(databaseFile, getter_AddRefs(connection));
if (NS_FAILED(rv)) {
nsXULContentUtils::LogTemplateError(ERROR_TEMPLATE_STORAGE_CANNOT_OPEN_DATABASE);
return rv;
}
connection.forget(aReturn);
return NS_OK;
}
NS_IMETHODIMP
nsXULTemplateQueryProcessorStorage::InitializeForBuilding(nsISupports* aDatasource,
nsIXULTemplateBuilder* aBuilder,
nsIDOMNode* aRootNode)
{
NS_ENSURE_STATE(!mGenerationStarted);
mStorageConnection = do_QueryInterface(aDatasource);
if (!mStorageConnection)
return NS_ERROR_INVALID_ARG;
bool ready;
mStorageConnection->GetConnectionReady(&ready);
if (!ready)
return NS_ERROR_UNEXPECTED;
return NS_OK;
}
NS_IMETHODIMP
nsXULTemplateQueryProcessorStorage::Done()
{
mGenerationStarted = false;
return NS_OK;
}
NS_IMETHODIMP
nsXULTemplateQueryProcessorStorage::CompileQuery(nsIXULTemplateBuilder* aBuilder,
nsIDOMNode* aQueryNode,
nsAtom* aRefVariable,
nsAtom* aMemberVariable,
nsISupports** aReturn)
{
nsCOMPtr<nsIDOMNodeList> childNodes;
aQueryNode->GetChildNodes(getter_AddRefs(childNodes));
uint32_t length;
childNodes->GetLength(&length);
nsCOMPtr<mozIStorageStatement> statement;
nsCOMPtr<nsIContent> queryContent = do_QueryInterface(aQueryNode);
nsAutoString sqlQuery;
// Let's get all text nodes (which should be the query)
if (!nsContentUtils::GetNodeTextContent(queryContent, false, sqlQuery, fallible)) {
return NS_ERROR_OUT_OF_MEMORY;
}
nsresult rv = mStorageConnection->CreateStatement(NS_ConvertUTF16toUTF8(sqlQuery),
getter_AddRefs(statement));
if (NS_FAILED(rv)) {
nsXULContentUtils::LogTemplateError(ERROR_TEMPLATE_STORAGE_BAD_QUERY);
return rv;
}
uint32_t parameterCount = 0;
for (nsIContent* child = queryContent->GetFirstChild();
child;
child = child->GetNextSibling()) {
if (child->NodeInfo()->Equals(nsGkAtoms::param, kNameSpaceID_XUL)) {
nsAutoString value;
if (!nsContentUtils::GetNodeTextContent(child, false, value, fallible)) {
return NS_ERROR_OUT_OF_MEMORY;
}
uint32_t index = parameterCount;
nsAutoString name, indexValue;
if (child->AsElement()->GetAttr(kNameSpaceID_None,
nsGkAtoms::name,
name)) {
rv = statement->GetParameterIndex(NS_ConvertUTF16toUTF8(name),
&index);
if (NS_FAILED(rv)) {
nsXULContentUtils::LogTemplateError(ERROR_TEMPLATE_STORAGE_UNKNOWN_QUERY_PARAMETER);
return rv;
}
parameterCount++;
} else if (child->AsElement()->GetAttr(kNameSpaceID_None,
nsGkAtoms::index,
indexValue)) {
PR_sscanf(NS_ConvertUTF16toUTF8(indexValue).get(),"%d",&index);
if (index > 0)
index--;
}
else {
parameterCount++;
}
static Element::AttrValuesArray sTypeValues[] =
{ &nsGkAtoms::int32, &nsGkAtoms::integer, &nsGkAtoms::int64,
&nsGkAtoms::null, &nsGkAtoms::double_, &nsGkAtoms::string, nullptr };
int32_t typeError = 1;
int32_t typeValue = child->AsElement()->
FindAttrValueIn(kNameSpaceID_None, nsGkAtoms::type, sTypeValues,
eCaseMatters);
rv = NS_ERROR_ILLEGAL_VALUE;
int32_t valInt32 = 0;
int64_t valInt64 = 0;
double valFloat = 0;
switch (typeValue) {
case 0:
case 1:
typeError = PR_sscanf(NS_ConvertUTF16toUTF8(value).get(),"%d",&valInt32);
if (typeError > 0)
rv = statement->BindInt32ByIndex(index, valInt32);
break;
case 2:
typeError = PR_sscanf(NS_ConvertUTF16toUTF8(value).get(),"%lld",&valInt64);
if (typeError > 0)
rv = statement->BindInt64ByIndex(index, valInt64);
break;
case 3:
rv = statement->BindNullByIndex(index);
break;
case 4:
typeError = PR_sscanf(NS_ConvertUTF16toUTF8(value).get(),"%lf",&valFloat);
if (typeError > 0)
rv = statement->BindDoubleByIndex(index, valFloat);
break;
case 5:
case Element::ATTR_MISSING:
rv = statement->BindStringByIndex(index, value);
break;
default:
typeError = 0;
}
if (typeError <= 0) {
nsXULContentUtils::LogTemplateError(ERROR_TEMPLATE_STORAGE_WRONG_TYPE_QUERY_PARAMETER);
return rv;
}
if (NS_FAILED(rv)) {
nsXULContentUtils::LogTemplateError(ERROR_TEMPLATE_STORAGE_QUERY_PARAMETER_NOT_BOUND);
return rv;
}
}
}
*aReturn = statement;
NS_IF_ADDREF(*aReturn);
return NS_OK;
}
NS_IMETHODIMP
nsXULTemplateQueryProcessorStorage::GenerateResults(nsISupports* aDatasource,
nsIXULTemplateResult* aRef,
nsISupports* aQuery,
nsISimpleEnumerator** aResults)
{
mGenerationStarted = true;
nsCOMPtr<mozIStorageStatement> statement = do_QueryInterface(aQuery);
if (!statement)
return NS_ERROR_FAILURE;
nsXULTemplateResultSetStorage* results =
new nsXULTemplateResultSetStorage(statement);
*aResults = results;
NS_ADDREF(*aResults);
return NS_OK;
}
NS_IMETHODIMP
nsXULTemplateQueryProcessorStorage::AddBinding(nsIDOMNode* aRuleNode,
nsAtom* aVar,
nsAtom* aRef,
const nsAString& aExpr)
{
return NS_OK;
}
NS_IMETHODIMP
nsXULTemplateQueryProcessorStorage::TranslateRef(nsISupports* aDatasource,
const nsAString& aRefString,
nsIXULTemplateResult** aRef)
{
nsXULTemplateResultStorage* result =
new nsXULTemplateResultStorage(nullptr);
*aRef = result;
NS_ADDREF(*aRef);
return NS_OK;
}
NS_IMETHODIMP
nsXULTemplateQueryProcessorStorage::CompareResults(nsIXULTemplateResult* aLeft,
nsIXULTemplateResult* aRight,
nsAtom* aVar,
uint32_t aSortHints,
int32_t* aResult)
{
*aResult = 0;
if (!aVar)
return NS_OK;
// We're going to see if values are integers or float, to perform
// a suitable comparison
nsCOMPtr<nsISupports> leftValue, rightValue;
if (aLeft)
aLeft->GetBindingObjectFor(aVar, getter_AddRefs(leftValue));
if (aRight)
aRight->GetBindingObjectFor(aVar, getter_AddRefs(rightValue));
if (leftValue && rightValue) {
nsCOMPtr<nsIVariant> vLeftValue = do_QueryInterface(leftValue);
nsCOMPtr<nsIVariant> vRightValue = do_QueryInterface(rightValue);
if (vLeftValue && vRightValue) {
nsresult rv1, rv2;
uint16_t vtypeL, vtypeR;
vLeftValue->GetDataType(&vtypeL);
vRightValue->GetDataType(&vtypeR);
if (vtypeL == vtypeR) {
if (vtypeL == nsIDataType::VTYPE_INT64) {
int64_t leftValue, rightValue;
rv1 = vLeftValue->GetAsInt64(&leftValue);
rv2 = vRightValue->GetAsInt64(&rightValue);
if (NS_SUCCEEDED(rv1) && NS_SUCCEEDED(rv2)) {
if (leftValue > rightValue)
*aResult = 1;
else if (leftValue < rightValue)
*aResult = -1;
return NS_OK;
}
}
else if (vtypeL == nsIDataType::VTYPE_DOUBLE) {
double leftValue, rightValue;
rv1 = vLeftValue->GetAsDouble(&leftValue);
rv2 = vRightValue->GetAsDouble(&rightValue);
if (NS_SUCCEEDED(rv1) && NS_SUCCEEDED(rv2)) {
if (leftValue > rightValue)
*aResult = 1;
else if (leftValue < rightValue)
*aResult = -1;
return NS_OK;
}
}
}
}
}
// Values are not integers or floats, so we just compare them as simple strings
nsAutoString leftVal;
if (aLeft)
aLeft->GetBindingFor(aVar, leftVal);
nsAutoString rightVal;
if (aRight)
aRight->GetBindingFor(aVar, rightVal);
*aResult = XULSortServiceImpl::CompareValues(leftVal, rightVal, aSortHints);
return NS_OK;
}

View File

@ -1,69 +0,0 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef nsXULTemplateQueryProcessorStorage_h__
#define nsXULTemplateQueryProcessorStorage_h__
#include "nsIXULTemplateBuilder.h"
#include "nsIXULTemplateQueryProcessor.h"
#include "nsISimpleEnumerator.h"
#include "nsCOMArray.h"
#include "nsIVariant.h"
#include "mozIStorageValueArray.h"
#include "mozIStorageStatement.h"
#include "mozIStorageConnection.h"
#include "mozilla/Attributes.h"
class nsXULTemplateQueryProcessorStorage;
class nsXULTemplateResultSetStorage final : public nsISimpleEnumerator
{
private:
nsCOMPtr<mozIStorageStatement> mStatement;
nsTArray<RefPtr<nsAtom>> mColumnNames;
~nsXULTemplateResultSetStorage() {}
public:
// nsISupports interface
NS_DECL_ISUPPORTS
// nsISimpleEnumerator interface
NS_DECL_NSISIMPLEENUMERATOR
explicit nsXULTemplateResultSetStorage(mozIStorageStatement* aStatement);
int32_t GetColumnIndex(nsAtom* aColumnName);
void FillColumnValues(nsCOMArray<nsIVariant>& aArray);
};
class nsXULTemplateQueryProcessorStorage final : public nsIXULTemplateQueryProcessor
{
public:
nsXULTemplateQueryProcessorStorage();
// nsISupports interface
NS_DECL_ISUPPORTS
// nsIXULTemplateQueryProcessor interface
NS_DECL_NSIXULTEMPLATEQUERYPROCESSOR
private:
~nsXULTemplateQueryProcessorStorage() {}
nsCOMPtr<mozIStorageConnection> mStorageConnection;
bool mGenerationStarted;
};
#endif // nsXULTemplateQueryProcessorStorage_h__

View File

@ -1,451 +0,0 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsCOMPtr.h"
#include "nsAutoPtr.h"
#include "nsIDOMDocument.h"
#include "nsIDOMNode.h"
#include "nsIDOMElement.h"
#include "nsIDOMEvent.h"
#include "nsIDocument.h"
#include "nsIContent.h"
#include "nsComponentManagerUtils.h"
#include "nsGkAtoms.h"
#include "nsIURI.h"
#include "nsIArray.h"
#include "nsIScriptContext.h"
#include "nsArrayUtils.h"
#include "nsPIDOMWindow.h"
#include "nsXULContentUtils.h"
#include "mozilla/dom/XPathEvaluator.h"
#include "nsXULTemplateQueryProcessorXML.h"
#include "nsXULTemplateResultXML.h"
#include "nsXULSortService.h"
#include "mozilla/dom/Element.h"
#include "mozilla/dom/XMLHttpRequest.h"
using namespace mozilla;
using namespace mozilla::dom;
NS_IMPL_ISUPPORTS(nsXMLQuery, nsXMLQuery)
//----------------------------------------------------------------------
//
// nsXULTemplateResultSetXML
//
NS_IMPL_ISUPPORTS(nsXULTemplateResultSetXML, nsISimpleEnumerator)
NS_IMETHODIMP
nsXULTemplateResultSetXML::HasMoreElements(bool *aResult)
{
// if GetSnapshotLength failed, then the return type was not a set of
// nodes, so just return false in this case.
ErrorResult rv;
uint32_t length = mResults->GetSnapshotLength(rv);
if (NS_WARN_IF(rv.Failed())) {
rv.SuppressException();
*aResult = false;
return NS_OK;
}
*aResult = mPosition < length;
return NS_OK;
}
NS_IMETHODIMP
nsXULTemplateResultSetXML::GetNext(nsISupports **aResult)
{
ErrorResult rv;
nsINode* node = mResults->SnapshotItem(mPosition, rv);
if (rv.Failed()) {
return rv.StealNSResult();
}
nsXULTemplateResultXML* result =
new nsXULTemplateResultXML(mQuery, node->AsContent(), mBindingSet);
++mPosition;
*aResult = result;
NS_ADDREF(result);
return NS_OK;
}
//----------------------------------------------------------------------
//
// nsXULTemplateQueryProcessorXML
//
NS_IMPL_CYCLE_COLLECTION_CLASS(nsXULTemplateQueryProcessorXML)
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsXULTemplateQueryProcessorXML)
tmp->mRuleToBindingsMap.Clear();
NS_IMPL_CYCLE_COLLECTION_UNLINK(mRoot)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mEvaluator)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mTemplateBuilder)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mRequest)
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsXULTemplateQueryProcessorXML)
for (auto it = tmp->mRuleToBindingsMap.Iter(); !it.Done(); it.Next()) {
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mRuleToBindingsMap key");
cb.NoteXPCOMChild(it.Key());
}
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mRoot)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mEvaluator)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mTemplateBuilder)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mRequest)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_IMPL_CYCLE_COLLECTING_ADDREF(nsXULTemplateQueryProcessorXML)
NS_IMPL_CYCLE_COLLECTING_RELEASE(nsXULTemplateQueryProcessorXML)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsXULTemplateQueryProcessorXML)
NS_INTERFACE_MAP_ENTRY(nsIXULTemplateQueryProcessor)
NS_INTERFACE_MAP_ENTRY(nsIDOMEventListener)
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIXULTemplateQueryProcessor)
NS_INTERFACE_MAP_END
/*
* Only the first datasource in aDataSource is used, which should be either an
* nsIURI of an XML document, or a DOM node. If the former, GetDatasource will
* load the document asynchronously and return null in aResult. Once the
* document has loaded, the builder's datasource will be set to the XML
* document. If the datasource is a DOM node, the node will be returned in
* aResult.
*/
NS_IMETHODIMP
nsXULTemplateQueryProcessorXML::GetDatasource(nsIArray* aDataSources,
nsIDOMNode* aRootNode,
bool aIsTrusted,
nsIXULTemplateBuilder* aBuilder,
bool* aShouldDelayBuilding,
nsISupports** aResult)
{
*aResult = nullptr;
*aShouldDelayBuilding = false;
nsresult rv;
uint32_t length;
aDataSources->GetLength(&length);
if (length == 0)
return NS_OK;
// we get only the first item, because the query processor supports only
// one document as a datasource
nsCOMPtr<nsIDOMNode> node = do_QueryElementAt(aDataSources, 0);
if (node) {
return CallQueryInterface(node, aResult);
}
nsCOMPtr<nsIURI> uri = do_QueryElementAt(aDataSources, 0);
if (!uri)
return NS_ERROR_UNEXPECTED;
nsAutoCString uriStr;
rv = uri->GetSpec(uriStr);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIContent> root = do_QueryInterface(aRootNode);
if (!root)
return NS_ERROR_UNEXPECTED;
nsCOMPtr<nsIDocument> doc = root->GetUncomposedDoc();
if (!doc)
return NS_ERROR_UNEXPECTED;
nsIPrincipal *docPrincipal = doc->NodePrincipal();
bool hasHadScriptObject = true;
nsIScriptGlobalObject* scriptObject =
doc->GetScriptHandlingObject(hasHadScriptObject);
NS_ENSURE_STATE(scriptObject);
nsCOMPtr<nsIXMLHttpRequest> req =
do_CreateInstance(NS_XMLHTTPREQUEST_CONTRACTID, &rv);
NS_ENSURE_SUCCESS(rv, rv);
rv = req->Init(docPrincipal, scriptObject, nullptr, nullptr);
NS_ENSURE_SUCCESS(rv, rv);
rv = req->Open(NS_LITERAL_CSTRING("GET"), uriStr, true,
EmptyString(), EmptyString());
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<EventTarget> target(do_QueryInterface(req));
rv = target->AddEventListener(NS_LITERAL_STRING("load"), this, false);
NS_ENSURE_SUCCESS(rv, rv);
rv = target->AddEventListener(NS_LITERAL_STRING("error"), this, false);
NS_ENSURE_SUCCESS(rv, rv);
rv = req->Send(nullptr);
NS_ENSURE_SUCCESS(rv, rv);
mTemplateBuilder = aBuilder;
mRequest = req;
*aShouldDelayBuilding = true;
return NS_OK;
}
NS_IMETHODIMP
nsXULTemplateQueryProcessorXML::InitializeForBuilding(nsISupports* aDatasource,
nsIXULTemplateBuilder* aBuilder,
nsIDOMNode* aRootNode)
{
if (mGenerationStarted)
return NS_ERROR_UNEXPECTED;
// the datasource is either a document or a DOM element
nsCOMPtr<nsIDocument> doc = do_QueryInterface(aDatasource);
if (doc)
mRoot = doc->GetDocumentElement();
else
mRoot = do_QueryInterface(aDatasource);
NS_ENSURE_STATE(mRoot);
mEvaluator = new XPathEvaluator();
return NS_OK;
}
NS_IMETHODIMP
nsXULTemplateQueryProcessorXML::Done()
{
mGenerationStarted = false;
mRuleToBindingsMap.Clear();
return NS_OK;
}
NS_IMETHODIMP
nsXULTemplateQueryProcessorXML::CompileQuery(nsIXULTemplateBuilder* aBuilder,
nsIDOMNode* aQueryNode,
nsAtom* aRefVariable,
nsAtom* aMemberVariable,
nsISupports** _retval)
{
*_retval = nullptr;
nsCOMPtr<nsIContent> content = do_QueryInterface(aQueryNode);
nsAutoString expr;
if (content->IsElement()) {
content->AsElement()->GetAttr(kNameSpaceID_None, nsGkAtoms::expr, expr);
}
// if an expression is not specified, then the default is to
// just take all of the children
if (expr.IsEmpty())
expr.Assign('*');
ErrorResult rv;
nsAutoPtr<XPathExpression> compiledexpr;
compiledexpr = CreateExpression(expr, content, rv);
if (rv.Failed()) {
nsXULContentUtils::LogTemplateError(ERROR_TEMPLATE_BAD_XPATH);
return rv.StealNSResult();
}
RefPtr<nsXMLQuery> query =
new nsXMLQuery(this, aMemberVariable, Move(compiledexpr));
for (nsIContent* condition = content->GetFirstChild();
condition;
condition = condition->GetNextSibling()) {
if (condition->NodeInfo()->Equals(nsGkAtoms::assign,
kNameSpaceID_XUL)) {
nsAutoString var;
condition->AsElement()->GetAttr(kNameSpaceID_None, nsGkAtoms::var, var);
nsAutoString expr;
condition->AsElement()->GetAttr(kNameSpaceID_None, nsGkAtoms::expr, expr);
// ignore assignments without a variable or an expression
if (!var.IsEmpty() && !expr.IsEmpty()) {
compiledexpr = CreateExpression(expr, condition, rv);
if (rv.Failed()) {
nsXULContentUtils::LogTemplateError(ERROR_TEMPLATE_BAD_ASSIGN_XPATH);
return rv.StealNSResult();
}
RefPtr<nsAtom> varatom = NS_Atomize(var);
query->AddBinding(varatom, Move(compiledexpr));
}
}
}
query.forget(_retval);
return NS_OK;
}
NS_IMETHODIMP
nsXULTemplateQueryProcessorXML::GenerateResults(nsISupports* aDatasource,
nsIXULTemplateResult* aRef,
nsISupports* aQuery,
nsISimpleEnumerator** aResults)
{
if (!aQuery)
return NS_ERROR_INVALID_ARG;
mGenerationStarted = true;
nsCOMPtr<nsXMLQuery> xmlquery = do_QueryInterface(aQuery);
if (!xmlquery)
return NS_ERROR_INVALID_ARG;
nsCOMPtr<nsISupports> supports;
nsCOMPtr<nsINode> context;
if (aRef)
aRef->GetBindingObjectFor(xmlquery->GetMemberVariable(),
getter_AddRefs(supports));
context = do_QueryInterface(supports);
if (!context)
context = mRoot;
XPathExpression* expr = xmlquery->GetResultsExpression();
if (!expr)
return NS_ERROR_FAILURE;
ErrorResult rv;
RefPtr<XPathResult> exprresults =
expr->Evaluate(*context, XPathResult::ORDERED_NODE_SNAPSHOT_TYPE,
nullptr, rv);
if (rv.Failed()) {
return rv.StealNSResult();
}
RefPtr<nsXULTemplateResultSetXML> results =
new nsXULTemplateResultSetXML(xmlquery, exprresults.forget(),
xmlquery->GetBindingSet());
results.forget(aResults);
return NS_OK;
}
NS_IMETHODIMP
nsXULTemplateQueryProcessorXML::AddBinding(nsIDOMNode* aRuleNode,
nsAtom* aVar,
nsAtom* aRef,
const nsAString& aExpr)
{
if (mGenerationStarted)
return NS_ERROR_FAILURE;
RefPtr<nsXMLBindingSet> bindings = mRuleToBindingsMap.GetWeak(aRuleNode);
if (!bindings) {
bindings = new nsXMLBindingSet();
mRuleToBindingsMap.Put(aRuleNode, bindings);
}
nsCOMPtr<nsINode> ruleNode = do_QueryInterface(aRuleNode);
ErrorResult rv;
nsAutoPtr<XPathExpression> compiledexpr;
compiledexpr = CreateExpression(aExpr, ruleNode, rv);
if (rv.Failed()) {
rv.SuppressException();
nsXULContentUtils::LogTemplateError(ERROR_TEMPLATE_BAD_BINDING_XPATH);
return NS_OK;
}
// aRef isn't currently used for XML query processors
bindings->AddBinding(aVar, Move(compiledexpr));
return NS_OK;
}
NS_IMETHODIMP
nsXULTemplateQueryProcessorXML::TranslateRef(nsISupports* aDatasource,
const nsAString& aRefString,
nsIXULTemplateResult** aRef)
{
*aRef = nullptr;
// the datasource is either a document or a DOM element
nsCOMPtr<Element> rootElement;
nsCOMPtr<nsIDocument> doc = do_QueryInterface(aDatasource);
if (doc)
rootElement = doc->GetRootElement();
else
rootElement = do_QueryInterface(aDatasource);
// if no root element, just return. The document may not have loaded yet
if (!rootElement)
return NS_OK;
RefPtr<nsXULTemplateResultXML> result = new nsXULTemplateResultXML(nullptr, rootElement, nullptr);
result.forget(aRef);
return NS_OK;
}
NS_IMETHODIMP
nsXULTemplateQueryProcessorXML::CompareResults(nsIXULTemplateResult* aLeft,
nsIXULTemplateResult* aRight,
nsAtom* aVar,
uint32_t aSortHints,
int32_t* aResult)
{
*aResult = 0;
if (!aVar)
return NS_OK;
nsAutoString leftVal;
if (aLeft)
aLeft->GetBindingFor(aVar, leftVal);
nsAutoString rightVal;
if (aRight)
aRight->GetBindingFor(aVar, rightVal);
*aResult = XULSortServiceImpl::CompareValues(leftVal, rightVal, aSortHints);
return NS_OK;
}
nsXMLBindingSet*
nsXULTemplateQueryProcessorXML::GetOptionalBindingsForRule(nsIDOMNode* aRuleNode)
{
return mRuleToBindingsMap.GetWeak(aRuleNode);
}
XPathExpression*
nsXULTemplateQueryProcessorXML::CreateExpression(const nsAString& aExpr,
nsINode* aNode,
ErrorResult& aRv)
{
return mEvaluator->CreateExpression(aExpr, aNode, aRv);
}
NS_IMETHODIMP
nsXULTemplateQueryProcessorXML::HandleEvent(nsIDOMEvent* aEvent)
{
NS_PRECONDITION(aEvent, "aEvent null");
nsAutoString eventType;
aEvent->GetType(eventType);
if (eventType.EqualsLiteral("load") && mTemplateBuilder) {
NS_ASSERTION(mRequest, "request was not set");
nsCOMPtr<nsIDOMDocument> doc;
if (NS_SUCCEEDED(mRequest->GetResponseXML(getter_AddRefs(doc))))
mTemplateBuilder->SetDatasource(doc);
// to avoid leak. we don't need it after...
mTemplateBuilder = nullptr;
mRequest = nullptr;
}
else if (eventType.EqualsLiteral("error")) {
mTemplateBuilder = nullptr;
mRequest = nullptr;
}
return NS_OK;
}

View File

@ -1,170 +0,0 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef nsXULTemplateQueryProcessorXML_h__
#define nsXULTemplateQueryProcessorXML_h__
#include "nsIXULTemplateBuilder.h"
#include "nsIXULTemplateQueryProcessor.h"
#include "nsAutoPtr.h"
#include "nsISimpleEnumerator.h"
#include "nsString.h"
#include "nsCOMArray.h"
#include "nsRefPtrHashtable.h"
#include "nsIDOMEventListener.h"
#include "nsIDOMXPathEvaluator.h"
#include "nsXMLBinding.h"
#include "nsCycleCollectionParticipant.h"
#include "nsIXMLHttpRequest.h"
#include "mozilla/Attributes.h"
#include "mozilla/dom/Element.h"
#include "mozilla/dom/XPathEvaluator.h"
#include "mozilla/dom/XPathResult.h"
class nsXULTemplateQueryProcessorXML;
#define NS_IXMLQUERY_IID \
{0x0358d692, 0xccce, 0x4a97, \
{ 0xb2, 0x51, 0xba, 0x8f, 0x17, 0x0f, 0x3b, 0x6f }}
class nsXMLQuery final : public nsISupports
{
public:
NS_DECLARE_STATIC_IID_ACCESSOR(NS_IXMLQUERY_IID)
NS_DECL_ISUPPORTS
// return a weak reference to the processor the query was created from
nsXULTemplateQueryProcessorXML* Processor() { return mProcessor; }
// return a weak reference t the member variable for the query
nsAtom* GetMemberVariable() { return mMemberVariable; }
// return a weak reference to the expression used to generate results
mozilla::dom::XPathExpression* GetResultsExpression()
{ return mResultsExpr; }
// return a weak reference to the additional required bindings
nsXMLBindingSet* GetBindingSet() { return mRequiredBindings; }
// add a required binding for the query
void
AddBinding(nsAtom* aVar, nsAutoPtr<mozilla::dom::XPathExpression>&& aExpr)
{
if (!mRequiredBindings) {
mRequiredBindings = new nsXMLBindingSet();
}
mRequiredBindings->AddBinding(aVar, mozilla::Move(aExpr));
}
nsXMLQuery(nsXULTemplateQueryProcessorXML* aProcessor,
nsAtom* aMemberVariable,
nsAutoPtr<mozilla::dom::XPathExpression>&& aResultsExpr)
: mProcessor(aProcessor),
mMemberVariable(aMemberVariable),
mResultsExpr(aResultsExpr)
{ }
protected:
~nsXMLQuery() {}
nsXULTemplateQueryProcessorXML* mProcessor;
RefPtr<nsAtom> mMemberVariable;
nsAutoPtr<mozilla::dom::XPathExpression> mResultsExpr;
RefPtr<nsXMLBindingSet> mRequiredBindings;
};
NS_DEFINE_STATIC_IID_ACCESSOR(nsXMLQuery, NS_IXMLQUERY_IID)
class nsXULTemplateResultSetXML final : public nsISimpleEnumerator
{
private:
// reference back to the query
nsCOMPtr<nsXMLQuery> mQuery;
// the binding set created from <assign> nodes
RefPtr<nsXMLBindingSet> mBindingSet;
// set of results contained in this enumerator
RefPtr<mozilla::dom::XPathResult> mResults;
// current position within the list of results
uint32_t mPosition;
~nsXULTemplateResultSetXML() {}
public:
// nsISupports interface
NS_DECL_ISUPPORTS
// nsISimpleEnumerator interface
NS_DECL_NSISIMPLEENUMERATOR
nsXULTemplateResultSetXML(nsXMLQuery* aQuery,
already_AddRefed<mozilla::dom::XPathResult> aResults,
nsXMLBindingSet* aBindingSet)
: mQuery(aQuery),
mBindingSet(aBindingSet),
mResults(aResults),
mPosition(0)
{}
};
class nsXULTemplateQueryProcessorXML final : public nsIXULTemplateQueryProcessor,
public nsIDOMEventListener
{
public:
nsXULTemplateQueryProcessorXML()
: mGenerationStarted(false)
{}
// nsISupports interface
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsXULTemplateQueryProcessorXML,
nsIXULTemplateQueryProcessor)
// nsIXULTemplateQueryProcessor interface
NS_DECL_NSIXULTEMPLATEQUERYPROCESSOR
// nsIDOMEventListener interface
NS_DECL_NSIDOMEVENTLISTENER
nsXMLBindingSet*
GetOptionalBindingsForRule(nsIDOMNode* aRuleNode);
// create an XPath expression from aExpr, using aNode for
// resolving namespaces
mozilla::dom::XPathExpression*
CreateExpression(const nsAString& aExpr,
nsINode* aNode,
mozilla::ErrorResult& aRv);
private:
~nsXULTemplateQueryProcessorXML() {}
bool mGenerationStarted;
nsRefPtrHashtable<nsISupportsHashKey, nsXMLBindingSet> mRuleToBindingsMap;
nsCOMPtr<mozilla::dom::Element> mRoot;
RefPtr<mozilla::dom::XPathEvaluator> mEvaluator;
nsCOMPtr<nsIXULTemplateBuilder> mTemplateBuilder;
nsCOMPtr<nsIXMLHttpRequest> mRequest;
};
#endif // nsXULTemplateQueryProcessorXML_h__

View File

@ -1,208 +0,0 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsXULTemplateResultRDF.h"
#include "nsXULContentUtils.h"
// XXXndeakin for some reason, making this class have classinfo breaks trees.
//#include "nsIDOMClassInfo.h"
NS_IMPL_CYCLE_COLLECTION(nsXULTemplateResultRDF, mQuery)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsXULTemplateResultRDF)
NS_INTERFACE_MAP_ENTRY(nsIXULTemplateResult)
NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_INTERFACE_MAP_END
NS_IMPL_CYCLE_COLLECTING_ADDREF(nsXULTemplateResultRDF)
NS_IMPL_CYCLE_COLLECTING_RELEASE(nsXULTemplateResultRDF)
nsXULTemplateResultRDF::nsXULTemplateResultRDF(nsIRDFResource* aNode)
: mQuery(nullptr),
mNode(aNode)
{
}
nsXULTemplateResultRDF::nsXULTemplateResultRDF(nsRDFQuery* aQuery,
const Instantiation& aInst,
nsIRDFResource *aNode)
: mQuery(aQuery),
mNode(aNode),
mInst(aInst)
{
}
nsXULTemplateResultRDF::~nsXULTemplateResultRDF()
{
}
NS_IMETHODIMP
nsXULTemplateResultRDF::GetIsContainer(bool* aIsContainer)
{
*aIsContainer = false;
if (mNode) {
nsXULTemplateQueryProcessorRDF* processor = GetProcessor();
if (processor)
return processor->CheckContainer(mNode, aIsContainer);
}
return NS_OK;
}
NS_IMETHODIMP
nsXULTemplateResultRDF::GetIsEmpty(bool* aIsEmpty)
{
*aIsEmpty = true;
if (mNode) {
nsXULTemplateQueryProcessorRDF* processor = GetProcessor();
if (processor)
return processor->CheckEmpty(mNode, aIsEmpty);
}
return NS_OK;
}
NS_IMETHODIMP
nsXULTemplateResultRDF::GetMayProcessChildren(bool* aMayProcessChildren)
{
// RDF always allows recursion
*aMayProcessChildren = 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::GetType(nsAString& aType)
{
aType.Truncate();
nsresult rv = NS_OK;
nsXULTemplateQueryProcessorRDF* processor = GetProcessor();
if (processor) {
bool found;
rv = processor->CheckIsSeparator(mNode, &found);
if (NS_SUCCEEDED(rv) && found)
aType.AssignLiteral("separator");
}
return rv;
}
NS_IMETHODIMP
nsXULTemplateResultRDF::GetBindingFor(nsAtom* aVar, nsAString& aValue)
{
nsCOMPtr<nsIRDFNode> val;
GetAssignment(aVar, getter_AddRefs(val));
return nsXULContentUtils::GetTextForNode(val, aValue);
}
NS_IMETHODIMP
nsXULTemplateResultRDF::GetBindingObjectFor(nsAtom* 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(nsAtom* aVar, nsIRDFNode** aValue)
{
// look up a variable in the assignments map
*aValue = nullptr;
mInst.mAssignments.GetAssignmentFor(aVar, aValue);
// if not found, look up the variable in the bindings
if (! *aValue)
mBindingValues.GetAssignmentFor(this, aVar, aValue);
}
bool
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() : nullptr,
this, mBindingValues);
}
return false;
}
bool
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 true;
}
return false;
}

View File

@ -1,81 +0,0 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#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"
#include "mozilla/Attributes.h"
/**
* A single result of a query on an RDF graph
*/
class nsXULTemplateResultRDF final : public nsIXULTemplateResult
{
public:
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_CLASS(nsXULTemplateResultRDF)
NS_DECL_NSIXULTEMPLATERESULT
explicit nsXULTemplateResultRDF(nsIRDFResource* aNode);
nsXULTemplateResultRDF(nsRDFQuery* aQuery,
const Instantiation& aInst,
nsIRDFResource* aNode);
nsITemplateRDFQuery* Query() { return mQuery; }
nsXULTemplateQueryProcessorRDF* GetProcessor()
{
return (mQuery ? mQuery->Processor() : nullptr);
}
/**
* Get the value of a variable, first by looking in the assignments and
* then the bindings
*/
void
GetAssignment(nsAtom* 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.
*/
bool
SyncAssignments(nsIRDFResource* aSubject,
nsIRDFResource* aPredicate,
nsIRDFNode* aTarget);
/**
* Return true if the result has an instantiation involving a particular
* memory element.
*/
bool
HasMemoryElement(const MemoryElement& aMemoryElement);
protected:
~nsXULTemplateResultRDF();
// 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__

View File

@ -1,82 +0,0 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsXULTemplateResultSetRDF.h"
#include "nsXULTemplateQueryProcessorRDF.h"
NS_IMPL_ISUPPORTS(nsXULTemplateResultSetRDF, nsISimpleEnumerator)
NS_IMETHODIMP
nsXULTemplateResultSetRDF::HasMoreElements(bool *aResult)
{
*aResult = true;
nsCOMPtr<nsIRDFNode> node;
if (! mInstantiations || ! mQuery) {
*aResult = false;
return NS_OK;
}
if (mCheckedNext) {
if (!mCurrent || mCurrent == &(mInstantiations->mHead))
*aResult = false;
return NS_OK;
}
mCheckedNext = true;
do {
if (mCurrent) {
mCurrent = mCurrent->mNext;
if (mCurrent == &(mInstantiations->mHead)) {
*aResult = 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;
RefPtr<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 = false;
nextresult.forget(aResult);
return NS_OK;
}

View File

@ -1,60 +0,0 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef nsXULTemplateResultSetRDF_h__
#define nsXULTemplateResultSetRDF_h__
#include "nsISimpleEnumerator.h"
#include "nsRuleNetwork.h"
#include "nsRDFQuery.h"
#include "nsXULTemplateResultRDF.h"
#include "mozilla/Attributes.h"
class nsXULTemplateQueryProcessorRDF;
class nsXULTemplateResultRDF;
/**
* An enumerator used to iterate over a set of results.
*/
class nsXULTemplateResultSetRDF final : public nsISimpleEnumerator
{
private:
nsXULTemplateQueryProcessorRDF* mProcessor;
nsRDFQuery* mQuery;
const InstantiationSet* mInstantiations;
nsCOMPtr<nsIRDFResource> mResource;
InstantiationSet::List *mCurrent;
bool mCheckedNext;
~nsXULTemplateResultSetRDF()
{
delete mInstantiations;
}
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(nullptr),
mCheckedNext(false)
{ }
};
#endif // nsXULTemplateResultSetRDF_h__

View File

@ -1,126 +0,0 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsIServiceManager.h"
#include "nsRDFCID.h"
#include "nsIRDFService.h"
#include "nsString.h"
#include "nsXULTemplateResultStorage.h"
NS_IMPL_ISUPPORTS(nsXULTemplateResultStorage, nsIXULTemplateResult)
nsXULTemplateResultStorage::nsXULTemplateResultStorage(nsXULTemplateResultSetStorage* aResultSet)
{
static NS_DEFINE_CID(kRDFServiceCID, NS_RDFSERVICE_CID);
nsCOMPtr<nsIRDFService> rdfService = do_GetService(kRDFServiceCID);
rdfService->GetAnonymousResource(getter_AddRefs(mNode));
mResultSet = aResultSet;
if (aResultSet) {
mResultSet->FillColumnValues(mValues);
}
}
nsXULTemplateResultStorage::~nsXULTemplateResultStorage()
{
}
NS_IMETHODIMP
nsXULTemplateResultStorage::GetIsContainer(bool* aIsContainer)
{
*aIsContainer = false;
return NS_OK;
}
NS_IMETHODIMP
nsXULTemplateResultStorage::GetIsEmpty(bool* aIsEmpty)
{
*aIsEmpty = true;
return NS_OK;
}
NS_IMETHODIMP
nsXULTemplateResultStorage::GetMayProcessChildren(bool* aMayProcessChildren)
{
*aMayProcessChildren = false;
return NS_OK;
}
NS_IMETHODIMP
nsXULTemplateResultStorage::GetId(nsAString& aId)
{
const char* uri = nullptr;
mNode->GetValueConst(&uri);
aId.Assign(NS_ConvertUTF8toUTF16(uri));
return NS_OK;
}
NS_IMETHODIMP
nsXULTemplateResultStorage::GetResource(nsIRDFResource** aResource)
{
*aResource = mNode;
NS_IF_ADDREF(*aResource);
return NS_OK;
}
NS_IMETHODIMP
nsXULTemplateResultStorage::GetType(nsAString& aType)
{
aType.Truncate();
return NS_OK;
}
NS_IMETHODIMP
nsXULTemplateResultStorage::GetBindingFor(nsAtom* aVar, nsAString& aValue)
{
NS_ENSURE_ARG_POINTER(aVar);
aValue.Truncate();
if (!mResultSet) {
return NS_OK;
}
int32_t idx = mResultSet->GetColumnIndex(aVar);
if (idx < 0) {
return NS_OK;
}
nsIVariant * value = mValues[idx];
if (value) {
value->GetAsAString(aValue);
}
return NS_OK;
}
NS_IMETHODIMP
nsXULTemplateResultStorage::GetBindingObjectFor(nsAtom* aVar, nsISupports** aValue)
{
NS_ENSURE_ARG_POINTER(aVar);
if (mResultSet) {
int32_t idx = mResultSet->GetColumnIndex(aVar);
if (idx >= 0) {
*aValue = mValues[idx];
NS_IF_ADDREF(*aValue);
return NS_OK;
}
}
*aValue = nullptr;
return NS_OK;
}
NS_IMETHODIMP
nsXULTemplateResultStorage::RuleMatched(nsISupports* aQuery, nsIDOMNode* aRuleNode)
{
return NS_OK;
}
NS_IMETHODIMP
nsXULTemplateResultStorage::HasBeenRemoved()
{
return NS_OK;
}

View File

@ -1,37 +0,0 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef nsXULTemplateResultStorage_h__
#define nsXULTemplateResultStorage_h__
#include "nsXULTemplateQueryProcessorStorage.h"
#include "nsIRDFResource.h"
#include "nsIXULTemplateResult.h"
#include "mozilla/Attributes.h"
/**
* A single result of a query from mozstorage
*/
class nsXULTemplateResultStorage final : public nsIXULTemplateResult
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIXULTEMPLATERESULT
explicit nsXULTemplateResultStorage(nsXULTemplateResultSetStorage* aResultSet);
protected:
~nsXULTemplateResultStorage();
RefPtr<nsXULTemplateResultSetStorage> mResultSet;
nsCOMArray<nsIVariant> mValues;
nsCOMPtr<nsIRDFResource> mNode;
};
#endif // nsXULTemplateResultStorage_h__

View File

@ -1,189 +0,0 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsIServiceManager.h"
#include "nsIDOMNode.h"
#include "nsIDOMElement.h"
#include "nsIContent.h"
#include "nsIRDFService.h"
#include "nsXULTemplateResultXML.h"
#include "nsXMLBinding.h"
static uint32_t sTemplateId = 0;
NS_IMPL_ISUPPORTS(nsXULTemplateResultXML, nsIXULTemplateResult)
nsXULTemplateResultXML::nsXULTemplateResultXML(nsXMLQuery* aQuery,
nsIContent* aNode,
nsXMLBindingSet* aBindings)
: mQuery(aQuery), mNode(aNode)
{
// If the node has an id, create the uri from it. Otherwise, there isn't
// anything to identify the node with so just use a somewhat random number.
RefPtr<nsAtom> id = mNode->GetID();
if (id) {
nsCOMPtr<nsIURI> uri = mNode->GetBaseURI();
nsAutoCString spec;
uri->GetSpec(spec);
mId = NS_ConvertUTF8toUTF16(spec);
nsAutoString idstr;
id->ToString(idstr);
mId += NS_LITERAL_STRING("#") + idstr;
}
else {
nsAutoString rowid(NS_LITERAL_STRING("row"));
rowid.AppendInt(++sTemplateId);
mId.Assign(rowid);
}
if (aBindings)
mRequiredValues.SetBindingSet(aBindings);
}
NS_IMETHODIMP
nsXULTemplateResultXML::GetIsContainer(bool* aIsContainer)
{
// a node is considered a container if it has children
*aIsContainer = mNode && mNode->HasChildNodes();
return NS_OK;
}
NS_IMETHODIMP
nsXULTemplateResultXML::GetIsEmpty(bool* aIsEmpty)
{
// a node is considered empty if it has no elements as children
nsCOMPtr<nsIContent> content = do_QueryInterface(mNode);
if (content) {
for (nsIContent* child = content->GetFirstChild();
child;
child = child->GetNextSibling()) {
if (child->IsElement()) {
*aIsEmpty = false;
return NS_OK;
}
}
}
*aIsEmpty = true;
return NS_OK;
}
NS_IMETHODIMP
nsXULTemplateResultXML::GetMayProcessChildren(bool* aMayProcessChildren)
{
*aMayProcessChildren = true;
return NS_OK;
}
NS_IMETHODIMP
nsXULTemplateResultXML::GetId(nsAString& aId)
{
aId = mId;
return NS_OK;
}
NS_IMETHODIMP
nsXULTemplateResultXML::GetResource(nsIRDFResource** aResource)
{
*aResource = nullptr;
return NS_OK;
}
NS_IMETHODIMP
nsXULTemplateResultXML::GetType(nsAString& aType)
{
aType.Truncate();
return NS_OK;
}
NS_IMETHODIMP
nsXULTemplateResultXML::GetBindingFor(nsAtom* aVar, nsAString& aValue)
{
NS_ENSURE_ARG_POINTER(aVar);
// get the position of the atom in the variables table
nsXMLBinding* binding;
int32_t idx = mRequiredValues.LookupTargetIndex(aVar, &binding);
if (idx >= 0) {
mRequiredValues.GetStringAssignmentFor(this, binding, idx, aValue);
return NS_OK;
}
idx = mOptionalValues.LookupTargetIndex(aVar, &binding);
if (idx >= 0) {
mOptionalValues.GetStringAssignmentFor(this, binding, idx, aValue);
return NS_OK;
}
// if the variable is not bound, just use the variable name as the name of
// an attribute to retrieve
nsAutoString attr;
aVar->ToString(attr);
if (attr.Length() > 1) {
nsCOMPtr<nsIDOMElement> element = do_QueryInterface(mNode);
if (element)
return element->GetAttribute(Substring(attr, 1), aValue);
}
aValue.Truncate();
return NS_OK;
}
NS_IMETHODIMP
nsXULTemplateResultXML::GetBindingObjectFor(nsAtom* aVar, nsISupports** aValue)
{
NS_ENSURE_ARG_POINTER(aVar);
nsXMLBinding* binding;
nsCOMPtr<nsISupports> node;
if (mQuery && aVar == mQuery->GetMemberVariable()) {
node = mNode;
}
else {
int32_t idx = mRequiredValues.LookupTargetIndex(aVar, &binding);
if (idx > 0) {
node = mRequiredValues.GetNodeAssignmentFor(this, binding, idx);
}
else {
idx = mOptionalValues.LookupTargetIndex(aVar, &binding);
if (idx > 0) {
node = mOptionalValues.GetNodeAssignmentFor(this, binding, idx);
}
}
}
node.forget(aValue);
return NS_OK;
}
NS_IMETHODIMP
nsXULTemplateResultXML::RuleMatched(nsISupports* aQueryNode,
nsIDOMNode* aRuleNode)
{
// when a rule matches, set the bindings that must be used.
nsXULTemplateQueryProcessorXML* processor = mQuery ? mQuery->Processor() :
nullptr;
if (processor) {
nsXMLBindingSet* bindings =
processor->GetOptionalBindingsForRule(aRuleNode);
if (bindings)
mOptionalValues.SetBindingSet(bindings);
}
return NS_OK;
}
NS_IMETHODIMP
nsXULTemplateResultXML::HasBeenRemoved()
{
return NS_OK;
}

View File

@ -1,59 +0,0 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef nsXULTemplateResultXML_h__
#define nsXULTemplateResultXML_h__
#include "nsCOMPtr.h"
#include "nsIContent.h"
#include "nsIURI.h"
#include "nsIRDFResource.h"
#include "nsXULTemplateQueryProcessorXML.h"
#include "nsIXULTemplateResult.h"
#include "mozilla/Attributes.h"
/**
* An single result of an query
*/
class nsXULTemplateResultXML final : public nsIXULTemplateResult
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIXULTEMPLATERESULT
nsXULTemplateResultXML(nsXMLQuery* aQuery,
nsIContent* aNode,
nsXMLBindingSet* aBindings);
nsIContent* Node()
{
return mNode;
}
protected:
~nsXULTemplateResultXML() {}
// ID used for persisting data. It is constructed using the mNode's
// base uri plus the node's id to form 'baseuri#id'. If the node has no
// id, then an id of the form 'row<some number>' is generated. In the
// latter case, persistence will not work as there won't be a unique id.
nsAutoString mId;
// query that generated the result
nsCOMPtr<nsXMLQuery> mQuery;
// context node in datasource
nsCOMPtr<nsIContent> mNode;
// assignments in query
nsXMLBindingValues mRequiredValues;
// extra assignments made by rules (<binding> tags)
nsXMLBindingValues mOptionalValues;
};
#endif // nsXULTemplateResultXML_h__

File diff suppressed because it is too large Load Diff

View File

@ -1,322 +0,0 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef nsXULTreeBuilder_h__
#define nsXULTreeBuilder_h__
#include "nsCOMPtr.h"
#include "nsITreeView.h"
#include "nsTreeRows.h"
#include "nsXULTemplateBuilder.h"
class nsIContent;
class nsIRDFResource;
class nsITreeSelection;
class nsIXULStore;
class nsIXULTemplateResult;
class nsTreeColumn;
namespace mozilla {
namespace dom {
class DataTransfer;
class TreeBoxObject;
class XULTreeBuilderObserver;
} // namespace dom
} // namespace mozilla
/**
* A XUL template builder that serves as an tree view, allowing
* (pretty much) arbitrary RDF to be presented in an tree.
*/
class nsXULTreeBuilder : public nsXULTemplateBuilder,
public nsIXULTreeBuilder,
public nsINativeTreeView
{
public:
explicit nsXULTreeBuilder(Element* aElement);
// nsISupports
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(nsXULTreeBuilder,
nsXULTemplateBuilder)
virtual JSObject* WrapObject(JSContext* aCx,
JS::Handle<JSObject*> aGivenProto) override;
already_AddRefed<nsIRDFResource>
GetResourceAtIndex(int32_t aIndex, mozilla::ErrorResult& aError);
int32_t GetIndexOfResource(nsIRDFResource* aResource,
mozilla::ErrorResult& aError);
void AddObserver(mozilla::dom::XULTreeBuilderObserver& aObserver);
void RemoveObserver(mozilla::dom::XULTreeBuilderObserver& aObserver);
void Sort(Element&);
int32_t RowCount()
{
return mRows.Count();
}
nsITreeSelection* GetSelection()
{
return mSelection;
}
void SetSelection(nsITreeSelection* aSelection,
mozilla::ErrorResult& aError);
void GetRowProperties(int32_t aRow, nsAString& aProperties,
mozilla::ErrorResult& aError);
void GetCellProperties(int32_t aRow, nsTreeColumn& aColumn,
nsAString& aProperties, mozilla::ErrorResult& aError);
void GetColumnProperties(nsTreeColumn& aColumn, nsAString& aProperties)
{
}
bool IsContainer(int32_t aRow, mozilla::ErrorResult& aError);
bool IsContainerOpen(int32_t aRow, mozilla::ErrorResult& aError);
bool IsContainerEmpty(int32_t aRow, mozilla::ErrorResult& aError);
bool IsSeparator(int32_t aRow, mozilla::ErrorResult& aError);
bool IsSorted()
{
return mSortVariable != nullptr;
}
bool CanDrop(int32_t aRow, int32_t aOrientation,
mozilla::dom::DataTransfer* aDataTransfer,
mozilla::ErrorResult& aError);
void Drop(int32_t aRow, int32_t aOrientation,
mozilla::dom::DataTransfer* aDataTransfer,
mozilla::ErrorResult& aError);
int32_t GetParentIndex(int32_t aRow, mozilla::ErrorResult& aError);
bool HasNextSibling(int32_t aRow, int32_t aAfterIndex,
mozilla::ErrorResult& aError);
int32_t GetLevel(int32_t aRow, mozilla::ErrorResult& aError);
void GetImageSrc(int32_t aRow, nsTreeColumn& aColumn, nsAString& aSrc,
mozilla::ErrorResult& aError);
int32_t GetProgressMode(int32_t aRow, nsTreeColumn& aColumn,
mozilla::ErrorResult& aError);
void GetCellValue(int32_t aRow, nsTreeColumn& aColumn, nsAString& aValue,
mozilla::ErrorResult& aError);
void GetCellText(int32_t aRow, nsTreeColumn& aColumn, nsAString& aText,
mozilla::ErrorResult& aError);
void SetTree(mozilla::dom::TreeBoxObject* aTree,
mozilla::ErrorResult& aError);
void ToggleOpenState(int32_t aRow, mozilla::ErrorResult& aError);
void CycleHeader(nsTreeColumn& aColumn, mozilla::ErrorResult& aError);
// XPCOM SelectionChanged() is OK
void CycleCell(int32_t aRow, nsTreeColumn& aColumn);
bool IsEditable(int32_t aRow, nsTreeColumn& aColumn,
mozilla::ErrorResult& aError);
bool IsSelectable(int32_t aRow, nsTreeColumn& aColumn,
mozilla::ErrorResult& aError);
void SetCellValue(int32_t aRow, nsTreeColumn& aColumn,
const nsAString& aValue, mozilla::ErrorResult& aError)
{
}
void SetCellText(int32_t aRow, nsTreeColumn& aColumn,
const nsAString& aText, mozilla::ErrorResult& aError)
{
}
void PerformAction(const nsAString& aAction);
void PerformActionOnRow(const nsAString& aAction, int32_t aRow);
void PerformActionOnCell(const nsAString& aAction, int32_t aRow,
nsTreeColumn& aColumn);
using nsIXULTemplateBuilder::HasGeneratedContent;
virtual bool HasGeneratedContent(nsIRDFResource* aResource,
const nsAString& aTag,
mozilla::ErrorResult& aError) override;
// nsIXULTreeBuilder
NS_DECL_NSIXULTREEBUILDER
// nsITreeView
NS_DECL_NSITREEVIEW
// nsINativeTreeView: Untrusted code can use us
NS_IMETHOD EnsureNative() override { return NS_OK; }
// nsIMutationObserver
NS_DECL_NSIMUTATIONOBSERVER_NODEWILLBEDESTROYED
protected:
friend struct ResultComparator;
~nsXULTreeBuilder();
/**
* Uninitialize the template builder
*/
virtual void Uninit(bool aIsFinal) override;
/**
* Get sort variables from the active <treecol>
*/
nsresult
EnsureSortVariables();
virtual nsresult
RebuildAll() override;
/**
* Given a row, use the row's match to figure out the appropriate
* <treerow> in the rule's <action>.
*/
nsresult
GetTemplateActionRowFor(int32_t aRow, mozilla::dom::Element** aResult);
/**
* Given a row and a column ID, use the row's match to figure out
* the appropriate <treecell> in the rule's <action>.
*/
mozilla::dom::Element*
GetTemplateActionCellFor(int32_t aRow, nsTreeColumn& aCol);
/**
* Return the resource corresponding to a row in the tree.
*/
nsresult
GetResourceFor(int32_t aRow, nsIRDFResource** aResource);
/**
* Open a container row, inserting the container's children into
* the view.
*/
nsresult
OpenContainer(int32_t aIndex, nsIXULTemplateResult* aResult);
/**
* Helper for OpenContainer, recursively open subtrees, remembering
* persisted ``open'' state
*/
nsresult
OpenSubtreeOf(nsTreeRows::Subtree* aSubtree,
int32_t aIndex,
nsIXULTemplateResult *aResult,
int32_t* aDelta);
nsresult
OpenSubtreeForQuerySet(nsTreeRows::Subtree* aSubtree,
int32_t aIndex,
nsIXULTemplateResult *aResult,
nsTemplateQuerySet* aQuerySet,
int32_t* aDelta,
nsTArray<int32_t>& open);
/**
* Close a container row, removing the container's childrem from
* the view.
*/
nsresult
CloseContainer(int32_t aIndex);
/**
* Remove the matches for the rows in a subtree
*/
nsresult
RemoveMatchesFor(nsTreeRows::Subtree& subtree);
/**
* Helper method that determines if the specified container is open.
*/
bool
IsContainerOpen(nsIXULTemplateResult* aResource);
/**
* A sorting callback for NS_QuickSort().
*/
static int
Compare(const void* aLeft, const void* aRight, void* aClosure);
/**
* The real sort routine
*/
int32_t
CompareResults(nsIXULTemplateResult* aLeft, nsIXULTemplateResult* aRight);
/**
* Sort the specified subtree, and recursively sort any subtrees
* beneath it.
*/
nsresult
SortSubtree(nsTreeRows::Subtree* aSubtree);
// GetInsertionLocations, ReplaceMatch and SynchronizeResult are inherited
// from nsXULTemplateBuilder
/**
* Return true if the result can be inserted into the template as a new
* row.
*/
bool
GetInsertionLocations(nsIXULTemplateResult* aResult,
nsCOMArray<Element>** aLocations) override;
/**
* Implement result replacement
*/
virtual nsresult
ReplaceMatch(nsIXULTemplateResult* aOldResult,
nsTemplateMatch* aNewMatch,
nsTemplateRule* aNewMatchRule,
Element* aContext) override;
/**
* Implement match synchronization
*/
virtual nsresult
SynchronizeResult(nsIXULTemplateResult* aResult) override;
bool IsValidRowIndex(int32_t aRowIndex);
/**
* The tree's box object, used to communicate with the front-end.
*/
nsCOMPtr<nsITreeBoxObject> mBoxObject;
/**
* The tree's selection object.
*/
nsCOMPtr<nsITreeSelection> mSelection;
/**
* The datasource that's used to persist open folder information
*/
nsCOMPtr<nsIRDFDataSource> mPersistStateStore;
/**
* The rows in the view
*/
nsTreeRows mRows;
/**
* The currently active sort variable
*/
RefPtr<nsAtom> mSortVariable;
enum Direction {
eDirection_Descending = -1,
eDirection_Natural = 0,
eDirection_Ascending = +1
};
/**
* The currently active sort order
*/
Direction mSortDirection;
/*
* Sort hints (compare case, etc)
*/
uint32_t mSortHints;
/**
* The builder observers.
*/
nsTArray<nsCOMPtr<nsIXULTreeBuilderObserver>> mObservers;
/*
* XUL store for holding open container state
*/
nsCOMPtr<nsIXULStore> mLocalStore;
};
#endif // nsXULTreeBuilder_h__

View File

@ -1,224 +0,0 @@
<?xml version="1.0"?>
<RDF:RDF xmlns:RDF="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:NC="http://home.netscape.com/NC-rdf#"
xmlns:ANIMALS="http://www.some-fictitious-zoo.com/rdf#">
<ANIMALS:Class RDF:about="http://www.some-fictitious-zoo.com/arachnids">
<ANIMALS:name>Arachnids</ANIMALS:name>
</ANIMALS:Class>
<RDF:Description RDF:about="http://www.some-fictitious-zoo.com/arachnids/tarantula" ANIMALS:specimens="3">
<ANIMALS:name>Tarantula</ANIMALS:name>
<ANIMALS:species>Avicularia avicularia</ANIMALS:species>
</RDF:Description>
<ANIMALS:Class RDF:about="http://www.some-fictitious-zoo.com/birds">
<ANIMALS:name>Birds</ANIMALS:name>
<ANIMALS:keeper resource="http://www.some-fictitious-zoo.com/humans/sarah"/>
</ANIMALS:Class>
<RDF:Description RDF:about="http://www.some-fictitious-zoo.com/birds/emu" ANIMALS:specimens="12">
<ANIMALS:name>Emu</ANIMALS:name>
<ANIMALS:species>Dromaius novaehollandiae</ANIMALS:species>
</RDF:Description>
<RDF:Description RDF:about="http://www.some-fictitious-zoo.com/birds/barnowl" ANIMALS:specimens="4">
<ANIMALS:name>Barn Owl</ANIMALS:name>
<ANIMALS:species>Tyto alba</ANIMALS:species>
</RDF:Description>
<RDF:Description RDF:about="http://www.some-fictitious-zoo.com/birds/raven" ANIMALS:specimens="0">
<ANIMALS:name>Raven</ANIMALS:name>
<ANIMALS:species>Corvus corax</ANIMALS:species>
</RDF:Description>
<ANIMALS:Class RDF:about="http://www.some-fictitious-zoo.com/crustaceans">
<ANIMALS:name>Crustaceans</ANIMALS:name>
<ANIMALS:keeper resource="http://www.some-fictitious-zoo.com/humans/robert"/>
</ANIMALS:Class>
<ANIMALS:Class RDF:about="http://www.some-fictitious-zoo.com/fish">
<ANIMALS:name>Fish</ANIMALS:name>
</ANIMALS:Class>
<RDF:Description RDF:about="http://www.some-fictitious-zoo.com/fish/cod" ANIMALS:specimens="0">
<ANIMALS:name>Cod</ANIMALS:name>
<ANIMALS:species>Gadus morhua</ANIMALS:species>
</RDF:Description>
<RDF:Description RDF:about="http://www.some-fictitious-zoo.com/fish/swordfish" ANIMALS:specimens="3">
<ANIMALS:name>Swordfish</ANIMALS:name>
<ANIMALS:species>Xiphias gladius</ANIMALS:species>
</RDF:Description>
<ANIMALS:Class RDF:about="http://www.some-fictitious-zoo.com/mammals">
<ANIMALS:name>Mammals</ANIMALS:name>
</ANIMALS:Class>
<RDF:Description RDF:about="http://www.some-fictitious-zoo.com/mammals/lion">
<ANIMALS:name>Lion</ANIMALS:name>
<ANIMALS:species>Panthera leo</ANIMALS:species>
<ANIMALS:specimens NC:parseType="Integer">4</ANIMALS:specimens>
<ANIMALS:specimensAsString>4</ANIMALS:specimensAsString>
</RDF:Description>
<RDF:Description RDF:about="http://www.some-fictitious-zoo.com/mammals/hippopotamus">
<ANIMALS:name>HIPPOPOTAMUS</ANIMALS:name>
<ANIMALS:species>Hippopotamus amphibius</ANIMALS:species>
<ANIMALS:specimens NC:parseType="Integer">2</ANIMALS:specimens>
<ANIMALS:specimensAsString>2</ANIMALS:specimensAsString>
</RDF:Description>
<RDF:Description RDF:about="http://www.some-fictitious-zoo.com/mammals/africanelephant">
<ANIMALS:name>African Elephant</ANIMALS:name>
<ANIMALS:species>Loxodonta africana</ANIMALS:species>
<ANIMALS:specimens NC:parseType="Integer">14</ANIMALS:specimens>
<ANIMALS:specimensAsString>14</ANIMALS:specimensAsString>
</RDF:Description>
<RDF:Description RDF:about="http://www.some-fictitious-zoo.com/mammals/llama">
<ANIMALS:name>LLAMA</ANIMALS:name>
<ANIMALS:species>Lama glama</ANIMALS:species>
<ANIMALS:specimens NC:parseType="Integer">5</ANIMALS:specimens>
<ANIMALS:specimensAsString>5</ANIMALS:specimensAsString>
</RDF:Description>
<RDF:Description RDF:about="http://www.some-fictitious-zoo.com/mammals/polarbear">
<ANIMALS:name>Polar Bear</ANIMALS:name>
<ANIMALS:species>Thalarctos maritimus</ANIMALS:species>
<ANIMALS:specimens NC:parseType="Integer">20</ANIMALS:specimens>
<ANIMALS:specimensAsString>20</ANIMALS:specimensAsString>
</RDF:Description>
<RDF:Description RDF:about="http://www.some-fictitious-zoo.com/mammals/aardvark">
<ANIMALS:name>aardvark</ANIMALS:name>
<ANIMALS:species>Orycteropus afer</ANIMALS:species>
<ANIMALS:specimens NC:parseType="Integer">2</ANIMALS:specimens>
<ANIMALS:specimensAsString>2</ANIMALS:specimensAsString>
</RDF:Description>
<RDF:Description RDF:about="http://www.some-fictitious-zoo.com/mammals/ninebandedarmadillo">
<ANIMALS:name>Nine-banded Armadillo</ANIMALS:name>
<ANIMALS:species>Dasypus novemcinctus</ANIMALS:species>
<ANIMALS:specimens NC:parseType="Integer">1</ANIMALS:specimens>
<ANIMALS:specimensAsString>1</ANIMALS:specimensAsString>
</RDF:Description>
<RDF:Description RDF:about="http://www.some-fictitious-zoo.com/mammals/gorilla">
<ANIMALS:name>Gorilla</ANIMALS:name>
<ANIMALS:species>Gorilla gorilla</ANIMALS:species>
<ANIMALS:specimens NC:parseType="Integer">7</ANIMALS:specimens>
<ANIMALS:specimensAsString>7</ANIMALS:specimensAsString>
</RDF:Description>
<ANIMALS:Class RDF:about="http://www.some-fictitious-zoo.com/reptiles">
<ANIMALS:name>Reptiles</ANIMALS:name>
<ANIMALS:keeper resource="http://www.some-fictitious-zoo.com/humans/robert"/>
</ANIMALS:Class>
<RDF:Description RDF:about="http://www.some-fictitious-zoo.com/reptiles/anaconda" ANIMALS:specimens="1">
<ANIMALS:name>Anaconda</ANIMALS:name>
<ANIMALS:species>Eunectes murinus</ANIMALS:species>
</RDF:Description>
<RDF:Description RDF:about="http://www.some-fictitious-zoo.com/reptiles/chameleon" ANIMALS:specimens="2">
<ANIMALS:name>Chameleon</ANIMALS:name>
<ANIMALS:species>Chamaeleo chamaelon</ANIMALS:species>
</RDF:Description>
<RDF:Seq RDF:about="http://www.some-fictitious-zoo.com/some-animals" ANIMALS:name="Zoo Animals">
<RDF:li RDF:resource="http://www.some-fictitious-zoo.com/arachnids"/>
<RDF:li RDF:resource="http://www.some-fictitious-zoo.com/birds"/>
</RDF:Seq>
<RDF:Seq RDF:about="http://www.some-fictitious-zoo.com/all-animals" ANIMALS:name="Zoo Animals">
<RDF:li>
<RDF:Seq RDF:about="http://www.some-fictitious-zoo.com/arachnids">
<RDF:li RDF:resource="http://www.some-fictitious-zoo.com/arachnids/tarantula"/>
</RDF:Seq>
</RDF:li>
<RDF:li>
<RDF:Seq RDF:about="http://www.some-fictitious-zoo.com/birds">
<RDF:li RDF:resource="http://www.some-fictitious-zoo.com/birds/emu"/>
<RDF:li RDF:resource="http://www.some-fictitious-zoo.com/birds/barnowl"/>
<RDF:li RDF:resource="http://www.some-fictitious-zoo.com/birds/raven"/>
</RDF:Seq>
</RDF:li>
<RDF:li>
<RDF:Seq RDF:about="http://www.some-fictitious-zoo.com/crustaceans"/>
</RDF:li>
<RDF:li>
<RDF:Seq RDF:about="http://www.some-fictitious-zoo.com/fish">
<RDF:li RDF:resource="http://www.some-fictitious-zoo.com/fish/cod"/>
<RDF:li RDF:resource="http://www.some-fictitious-zoo.com/fish/swordfish"/>
</RDF:Seq>
</RDF:li>
<RDF:li>
<RDF:Seq RDF:about="http://www.some-fictitious-zoo.com/mammals">
<RDF:li RDF:resource="http://www.some-fictitious-zoo.com/mammals/lion"/>
<RDF:li RDF:resource="http://www.some-fictitious-zoo.com/mammals/hippopotamus"/>
<RDF:li RDF:resource="http://www.some-fictitious-zoo.com/mammals/africanelephant"/>
<RDF:li RDF:resource="http://www.some-fictitious-zoo.com/mammals/llama"/>
<RDF:li RDF:resource="http://www.some-fictitious-zoo.com/mammals/polarbear"/>
<RDF:li RDF:resource="http://www.some-fictitious-zoo.com/mammals/aardvark"/>
<RDF:li RDF:resource="http://www.some-fictitious-zoo.com/mammals/ninebandedarmadillo"/>
<RDF:li RDF:resource="http://www.some-fictitious-zoo.com/mammals/gorilla"/>
</RDF:Seq>
</RDF:li>
<RDF:li>
<RDF:Seq RDF:about="http://www.some-fictitious-zoo.com/reptiles">
<RDF:li RDF:resource="http://www.some-fictitious-zoo.com/reptiles/anaconda"/>
<RDF:li RDF:resource="http://www.some-fictitious-zoo.com/reptiles/chameleon"/>
</RDF:Seq>
</RDF:li>
</RDF:Seq>
<RDF:Seq RDF:about="http://www.some-fictitious-zoo.com/humans" ANIMALS:name="Humans">
<RDF:li RDF:resource="http://www.some-fictitious-zoo.com/humans/sarah"/>
<RDF:li RDF:resource="http://www.some-fictitious-zoo.com/humans/robert"/>
</RDF:Seq>
<RDF:Seq RDF:about="http://www.some-fictitious-zoo.com/sarahs-pets" ANIMALS:name="Sarah's Pets">
<RDF:li RDF:resource="http://www.some-fictitious-zoo.com/birds/emu"/>
<RDF:li RDF:resource="http://www.some-fictitious-zoo.com/arachnids/tarantula"/>
</RDF:Seq>
<RDF:Seq RDF:about="http://www.some-fictitious-zoo.com/roberts-pets" ANIMALS:name="Robert's Pets">
<RDF:li RDF:resource="http://www.some-fictitious-zoo.com/reptiles/chameleon"/>
<RDF:li RDF:resource="http://www.some-fictitious-zoo.com/arachnids/tarantula"/>
<RDF:li RDF:resource="http://www.some-fictitious-zoo.com/mammals/llama"/>
</RDF:Seq>
<RDF:Description RDF:about="http://www.some-fictitious-zoo.com/humans/sarah" ANIMALS:name="Sarah">
<ANIMALS:pets resource="http://www.some-fictitious-zoo.com/sarahs-pets"/>
<ANIMALS:favoriteAnimal resource="http://www.some-fictitious-zoo.com/birds/emu"/>
<ANIMALS:favoriteAnimal resource="http://www.some-fictitious-zoo.com/mammals/polarbear"/>
<ANIMALS:favoriteAnimal resource="http://www.some-fictitious-zoo.com/arachnids/tarantula"/>
<ANIMALS:description>
Sarah became caretaker of the Fictitious Zoo's emu exhibit in 2001. With so
many emus living there, she has a lot to do!
</ANIMALS:description>
</RDF:Description>
<RDF:Description RDF:about="http://www.some-fictitious-zoo.com/humans/robert" ANIMALS:name="Robert">
<ANIMALS:pets resource="http://www.some-fictitious-zoo.com/roberts-pets"/>
<ANIMALS:favoriteAnimal resource="http://www.some-fictitious-zoo.com/arachnids/tarantula"/>
<ANIMALS:favoriteAnimal resource="http://www.some-fictitious-zoo.com/reptiles/anaconda"/>
<ANIMALS:favoriteAnimal resource="http://www.some-fictitious-zoo.com/reptiles/chameleon"/>
<ANIMALS:favoriteAnimal resource="http://www.some-fictitious-zoo.com/mammals/africanelephant"/>
<ANIMALS:description>
Robert helps visitors to the Fictitious Zoo's reptile pavilion learn
more about some of the more unusual creatures that live there.
</ANIMALS:description>
<ANIMALS:lastName>Sanderson</ANIMALS:lastName>
</RDF:Description>
<RDF:Seq RDF:about="http://www.some-fictitious-zoo.com/marked" ANIMALS:name="Marked">
<RDF:li RDF:resource="http://www.some-fictitious-zoo.com/humans/sarah"/>
<RDF:li RDF:resource="http://www.some-fictitious-zoo.com/mammals"/>
<RDF:li RDF:resource="http://www.some-fictitious-zoo.com/crustaceans"/>
<RDF:li RDF:resource="http://www.some-fictitious-zoo.com/birds/emu"/>
</RDF:Seq>
</RDF:RDF>

View File

@ -1,19 +0,0 @@
<?xml version="1.0"?>
<!DOCTYPE zoo [
<!ATTLIST species id ID #REQUIRED>
]>
<zoo>
<class>
<name>Reptiles</name>
<species id="Chamaeleo-chamaelon" name="Chameleon" specimens="2"/>
</class>
<class>
<name>Birds</name>
<species id="Dromaius-novaehollandiae" name="Emu" specimens="12"/>
<species id="Tyto-alba" name="Barn Owl" specimens="4"/>
<species id="Corvus-corax" name="Raven" specimens="0"/>
<location>Aviary</location>
</class>
</zoo>

View File

@ -1,263 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<RDF:RDF xmlns:RDF="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:row="http://dummy/rdf#" xmlns:NC="http://home.netscape.com/NC-rdf#">
<RDF:Bag about="urn:data:row">
<RDF:li>
<RDF:Description>
<row:id NC:parseType="Integer">111110</row:id>
<row:title>FILE 1 -- A</row:title>
</RDF:Description>
</RDF:li>
<RDF:li>
<RDF:Description>
<row:id NC:parseType="Integer">111111</row:id>
<row:title>FILE 1 -- B</row:title>
</RDF:Description>
</RDF:li>
<RDF:li>
<RDF:Description>
<row:id NC:parseType="Integer">111110</row:id>
<row:title>FILE 1 -- C</row:title>
</RDF:Description>
</RDF:li>
<RDF:li>
<RDF:Description>
<row:id NC:parseType="Integer">111111</row:id>
<row:title>FILE 1 -- D</row:title>
</RDF:Description>
</RDF:li>
<RDF:li>
<RDF:Description>
<row:id NC:parseType="Integer">111112</row:id>
<row:title>FILE 1 -- E</row:title>
</RDF:Description>
</RDF:li>
<RDF:li>
<RDF:Description>
<row:id NC:parseType="Integer">111110</row:id>
<row:title>FILE 1 -- F</row:title>
</RDF:Description>
</RDF:li>
<RDF:li>
<RDF:Description>
<row:id NC:parseType="Integer">111114</row:id>
<row:title>FILE 1 -- G</row:title>
</RDF:Description>
</RDF:li>
<RDF:li>
<RDF:Description>
<row:id NC:parseType="Integer">111111</row:id>
<row:title>FILE 1 -- H</row:title>
</RDF:Description>
</RDF:li>
<RDF:li>
<RDF:Description>
<row:id NC:parseType="Integer">111118</row:id>
<row:title>FILE 1 -- I</row:title>
</RDF:Description>
</RDF:li>
<RDF:li>
<RDF:Description>
<row:id NC:parseType="Integer">111116</row:id>
<row:title>FILE 1 -- J</row:title>
</RDF:Description>
</RDF:li>
<RDF:li>
<RDF:Description>
<row:id NC:parseType="Integer">111110</row:id>
<row:title>FILE 1 -- K</row:title>
</RDF:Description>
</RDF:li>
<RDF:li>
<RDF:Description>
<row:id NC:parseType="Integer">111119</row:id>
<row:title>FILE 1 -- L</row:title>
</RDF:Description>
</RDF:li>
<RDF:li>
<RDF:Description>
<row:id NC:parseType="Integer">111116</row:id>
<row:title>FILE 1 -- M</row:title>
</RDF:Description>
</RDF:li>
<RDF:li>
<RDF:Description>
<row:id NC:parseType="Integer">1111111</row:id>
<row:title>FILE 1 -- N</row:title>
</RDF:Description>
</RDF:li>
<RDF:li>
<RDF:Description>
<row:id NC:parseType="Integer">111113</row:id>
<row:title>FILE 1 -- O</row:title>
</RDF:Description>
</RDF:li>
<RDF:li>
<RDF:Description>
<row:id NC:parseType="Integer">111111</row:id>
<row:title>FILE 1 -- P</row:title>
</RDF:Description>
</RDF:li>
<RDF:li>
<RDF:Description>
<row:id NC:parseType="Integer">111117</row:id>
<row:title>FILE 1 -- Q</row:title>
</RDF:Description>
</RDF:li>
<RDF:li>
<RDF:Description>
<row:id NC:parseType="Integer">1111110</row:id>
<row:title>FILE 1 -- R</row:title>
</RDF:Description>
</RDF:li>
<RDF:li>
<RDF:Description>
<row:id NC:parseType="Integer">111113</row:id>
<row:title>FILE 1 -- S</row:title>
</RDF:Description>
</RDF:li>
<RDF:li>
<RDF:Description>
<row:id NC:parseType="Integer">1111112</row:id>
<row:title>FILE 1 -- T</row:title>
</RDF:Description>
</RDF:li>
<RDF:li>
<RDF:Description>
<row:id NC:parseType="Integer">111116</row:id>
<row:title>FILE 1 -- U</row:title>
</RDF:Description>
</RDF:li>
<RDF:li>
<RDF:Description>
<row:id NC:parseType="Integer">1111111</row:id>
<row:title>FILE 1 -- V</row:title>
</RDF:Description>
</RDF:li>
<RDF:li>
<RDF:Description>
<row:id NC:parseType="Integer">1111121</row:id>
<row:title>FILE 1 -- W</row:title>
</RDF:Description>
</RDF:li>
<RDF:li>
<RDF:Description>
<row:id NC:parseType="Integer">111114</row:id>
<row:title>FILE 1 -- X</row:title>
</RDF:Description>
</RDF:li>
<RDF:li>
<RDF:Description>
<row:id NC:parseType="Integer">1111122</row:id>
<row:title>FILE 1 -- Y</row:title>
</RDF:Description>
</RDF:li>
<RDF:li>
<RDF:Description>
<row:id NC:parseType="Integer">1111113</row:id>
<row:title>FILE 1 -- Z</row:title>
</RDF:Description>
</RDF:li>
<RDF:li>
<RDF:Description>
<row:id NC:parseType="Integer">1111119</row:id>
<row:title>FILE 1 -- AA</row:title>
</RDF:Description>
</RDF:li>
<RDF:li>
<RDF:Description>
<row:id NC:parseType="Integer">1111117</row:id>
<row:title>FILE 1 -- BB</row:title>
</RDF:Description>
</RDF:li>
<RDF:li>
<RDF:Description>
<row:id NC:parseType="Integer">111117</row:id>
<row:title>FILE 1 -- CC</row:title>
</RDF:Description>
</RDF:li>
<RDF:li>
<RDF:Description>
<row:id NC:parseType="Integer">111117</row:id>
<row:title>FILE 1 -- DD</row:title>
</RDF:Description>
</RDF:li>
<RDF:li>
<RDF:Description>
<row:id NC:parseType="Integer">111116</row:id>
<row:title>FILE 1 -- EE</row:title>
</RDF:Description>
</RDF:li>
<RDF:li>
<RDF:Description>
<row:id NC:parseType="Integer">1111124</row:id>
<row:title>FILE 1 -- FF</row:title>
</RDF:Description>
</RDF:li>
<RDF:li>
<RDF:Description>
<row:id NC:parseType="Integer">111118</row:id>
<row:title>FILE 1 -- GG</row:title>
</RDF:Description>
</RDF:li>
<RDF:li>
<RDF:Description>
<row:id NC:parseType="Integer">1111117</row:id>
<row:title>FILE 1 -- HH</row:title>
</RDF:Description>
</RDF:li>
<RDF:li>
<RDF:Description>
<row:id NC:parseType="Integer">111118</row:id>
<row:title>FILE 1 -- II</row:title>
</RDF:Description>
</RDF:li>
<RDF:li>
<RDF:Description>
<row:id NC:parseType="Integer">1111125</row:id>
<row:title>FILE 1 -- JJ</row:title>
</RDF:Description>
</RDF:li>
<RDF:li>
<RDF:Description>
<row:id NC:parseType="Integer">1111124</row:id>
<row:title>FILE 1 -- KK</row:title>
</RDF:Description>
</RDF:li>
<RDF:li>
<RDF:Description>
<row:id NC:parseType="Integer">1111132</row:id>
<row:title>FILE 1 -- LL</row:title>
</RDF:Description>
</RDF:li>
<RDF:li>
<RDF:Description>
<row:id NC:parseType="Integer">1111136</row:id>
<row:title>FILE 1 -- MM</row:title>
</RDF:Description>
</RDF:li>
<RDF:li>
<RDF:Description>
<row:id NC:parseType="Integer">1111123</row:id>
<row:title>FILE 1 -- NN</row:title>
</RDF:Description>
</RDF:li>
<RDF:li>
<RDF:Description>
<row:id NC:parseType="Integer">1111122</row:id>
<row:title>FILE 1 -- OO</row:title>
</RDF:Description>
</RDF:li>
<RDF:li>
<RDF:Description>
<row:id NC:parseType="Integer">111110</row:id>
<row:title>FILE 1 -- PP</row:title>
</RDF:Description>
</RDF:li>
<RDF:li>
<RDF:Description>
<row:id NC:parseType="Integer">1111116</row:id>
<row:title>FILE 1 -- QQ</row:title>
</RDF:Description>
</RDF:li>
</RDF:Bag>
</RDF:RDF>

View File

@ -1,11 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<RDF:RDF xmlns:RDF="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:row="http://dummy/rdf#" xmlns:NC="http://home.netscape.com/NC-rdf#">
<RDF:Bag about="urn:data:row">
<RDF:li>
<RDF:Description>
<row:id NC:parseType="Integer">222220</row:id>
<row:title>FILE 2 -- A</row:title>
</RDF:Description>
</RDF:li>
</RDF:Bag>
</RDF:RDF>

View File

@ -1,225 +0,0 @@
[DEFAULT]
skip-if = os == 'android'
support-files =
animals.rdf
animals.sqlite
animals.xml
bug441785-1.rdf
bug441785-2.rdf
templates_shared.js
[test_bug329335.xul]
[test_bug330010.xul]
skip-if = os == "win"
support-files = file_bug330010.rdf
[test_bug397148.xul]
skip-if = true # Bug 879531
[test_bug441785.xul]
[test_bug476634.xul]
[test_sortservice.xul]
[test_tmpl_bindingsextendedsyntax.xul]
[test_tmpl_bindingsmultiple.xul]
[test_tmpl_bindingsquerysyntax.xul]
[test_tmpl_bindingsreversed.xul]
[test_tmpl_bindingssameastriple.xul]
[test_tmpl_containerandmembervariablechanged.xul]
[test_tmpl_containervariablechanged.xul]
[test_tmpl_containmentattribute.xul]
[test_tmpl_defaultcontainervariableisuri.xul]
[test_tmpl_errors.xul]
[test_tmpl_extendedsyntax.xul]
[test_tmpl_extendedsyntaxemptyconditions.xul]
[test_tmpl_extendedsyntaxotherrefvariable.xul]
[test_tmpl_extendedsyntaxremoveunmatched.xul]
[test_tmpl_extendedsyntaxsimplevariablesubstitution.xul]
[test_tmpl_extendedsyntaxtworulesrecurse.xul]
[test_tmpl_extendedsyntaxusinganinterveningcontainer.xul]
[test_tmpl_extendedvariablesubstitution.xul]
[test_tmpl_gridelement.xul]
[test_tmpl_htmlelementextendedsyntaxwithbinding.xul]
[test_tmpl_htmlelementquerysyntaxrecursive.xul]
[test_tmpl_htmlelementquerysyntaxwithmultiplerules.xul]
[test_tmpl_htmlelementsimplesyntax.xul]
[test_tmpl_htmlelementsimplesyntaxusingatextnode.xul]
[test_tmpl_invalidqp.xul]
[test_tmpl_listboxelement.xul]
[test_tmpl_literalasmember.xul]
[test_tmpl_membervariablechanged.xul]
[test_tmpl_membervariablesubstitution.xul]
[test_tmpl_menuelement.xul]
[test_tmpl_menuelementrecursive.xul]
[test_tmpl_menulistelement.xul]
[test_tmpl_mixedsyntaxiscontainer.xul]
[test_tmpl_mixedsyntaxiscontainerisempty.xul]
[test_tmpl_mixedsyntaxisempty.xul]
[test_tmpl_noaction.xul]
[test_tmpl_noactionuriattribute.xul]
[test_tmpl_parentconditions.xul]
[test_tmpl_parentcontenttag.xul]
[test_tmpl_parentsimplesyntax.xul]
[test_tmpl_query3triples.xul]
[test_tmpl_query3tripleswherecontains.xul]
[test_tmpl_querymember3tripleswhereequals.xul]
[test_tmpl_querymemberandtwotriples.xul]
[test_tmpl_querymembertriplemembertriple.xul]
[test_tmpl_queryresourcematch.xul]
[test_tmpl_queryreversetriple.xul]
[test_tmpl_queryselfwithtriple.xul]
[test_tmpl_querysetone.xul]
[test_tmpl_querysettwo.xul]
[test_tmpl_querysettwowithcondition.xul]
[test_tmpl_querysyntax.xul]
[test_tmpl_querysyntaxmultiplerules.xul]
[test_tmpl_querysyntaxmultiplerulesfirstconditionall.xul]
[test_tmpl_querysyntaxmultiplerulestwoconditions.xul]
[test_tmpl_querytripleandmembermerge.xul]
[test_tmpl_querytripleobjecttosubject.xul]
[test_tmpl_querytwomembers.xul]
[test_tmpl_querytwomembersfiltered.xul]
[test_tmpl_querytwotriples.xul]
[test_tmpl_queryupwardsmember.xul]
[test_tmpl_queryupwardsmembertripleandfilteringtriple.xul]
[test_tmpl_querywithemptyconditions.xul]
[test_tmpl_referenceasmember.xul]
[test_tmpl_regenerate.xul]
[test_tmpl_selfgenerationextendedsyntax.xul]
[test_tmpl_selfgenerationsimplesyntax.xul]
[test_tmpl_simplesyntaxenclosedinacontainer.xul]
[test_tmpl_simplesyntaxenclosedinacontainerwitharule.xul]
[test_tmpl_simplesyntaxfilter.xul]
[test_tmpl_simplesyntaxfilterwithmultiplerules.xul]
[test_tmpl_simplesyntaxfilterwithrule.xul]
[test_tmpl_simplesyntaxiteratingoverasinglevalue.xul]
[test_tmpl_simplesyntaxusinganinterveningcontainer.xul]
[test_tmpl_simplesyntaxusingatextnode.xul]
[test_tmpl_simplesyntaxusingcontainerasthegenerationelement.xul]
[test_tmpl_simplesyntaxusingdontrecurse.xul]
[test_tmpl_simplesyntaxusingrecursivegeneration.xul]
[test_tmpl_simplesyntaxusingrecursivegenerationagain.xul]
[test_tmpl_simplesyntaxwithtwovariablesused.xul]
[test_tmpl_simplevariablesubstitutioncaretsatbeginningandend.xul]
[test_tmpl_simplevariablesubstitutioncaretsubstitution.xul]
[test_tmpl_simplevariablesubstitutionnovariable.xul]
[test_tmpl_simplevariablesubstitutionquestionmarkaspartofvariable.xul]
[test_tmpl_simplevariablesubstitutionquestionmarksubstitution.xul]
[test_tmpl_simplevariablesubstitutiontextandvariable.xul]
[test_tmpl_simplevariablesubstitutionvariableandtextconcatenated.xul]
[test_tmpl_simplevariablesubstitutionvariablesconcatenated.xul]
[test_tmpl_sortascendinginteger.xul]
[test_tmpl_sortascendingquerysyntax.xul]
[test_tmpl_sortascendingtworulesquerysyntax.xul]
[test_tmpl_sortascendingtworuleswithcontainerquerysyntax.xul]
[test_tmpl_sortascendingtworuleswithdifferentcontainerquerysyntax.xul]
[test_tmpl_sortdescendingquerysyntax.xul]
[test_tmpl_sortquerymemberandtwotriples.xul]
[test_tmpl_sortresource2descendingsimplesyntax.xul]
[test_tmpl_sortresource2settopredicateascendingquerysyntax.xul]
[test_tmpl_sortresource2settopredicatedescendingquerysyntax.xul]
[test_tmpl_sortresourceascendingquerysyntax.xul]
[test_tmpl_sortresourcedescendingquerysyntax.xul]
[test_tmpl_sortresourcesettopredicateascendingquerysyntax.xul]
[test_tmpl_sortresourcesettopredicatedescendingquerysyntax.xul]
[test_tmpl_sorttworesourcesasstringsettopredicatedescendingquerysyntax.xul]
[test_tmpl_sorttworesourcessettopredicateascendingquerysyntax.xul]
[test_tmpl_sorttwovariablesascendingquerysyntax.xul]
[test_tmpl_sorttwovariablesascendingsimplesyntax.xul]
[test_tmpl_sorttwovariablesdescendingquerysyntax.xul]
[test_tmpl_sortunknownascendingquerysyntax.xul]
[test_tmpl_storage_bad_parameters.xul]
[test_tmpl_storage_bad_parameters_2.xul]
[test_tmpl_storage_bad_parameters_3.xul]
[test_tmpl_storage_baddatasource.xul]
[test_tmpl_storage_badquery.xul]
[test_tmpl_storage_dynamicparameters.xul]
[test_tmpl_storage_listbox.xul]
[test_tmpl_storage_multiqueries.xul]
[test_tmpl_storage_parameters.xul]
[test_tmpl_storage_rule.xul]
[test_tmpl_storage_simple.xul]
[test_tmpl_storage_sortintegerasc.xul]
[test_tmpl_storage_sortintegerdesc.xul]
[test_tmpl_storage_sortstringasc.xul]
[test_tmpl_storage_sortstringdesc.xul]
[test_tmpl_storage_tree.xul]
[test_tmpl_treeelementquerysyntax.xul]
[test_tmpl_treeelementquerysyntaxnotrecursive.xul]
[test_tmpl_treeelementquerysyntaxnotrecursivetreebuilder.xul]
[test_tmpl_treeelementquerysyntaxrecursive.xul]
[test_tmpl_treeelementquerysyntaxrecursivemultiplerules.xul]
[test_tmpl_treeelementquerysyntaxrecursivemultiplerulestreebuilder.xul]
[test_tmpl_treeelementquerysyntaxrecursivetreebuilder.xul]
[test_tmpl_treeelementquerysyntaxtreebuilder.xul]
[test_tmpl_treeelementsimplesyntaxnotrecursive.xul]
[test_tmpl_treeelementsimplesyntaxnotrecursivetreebuilder.xul]
[test_tmpl_treeelementsimplesyntaxrecursive.xul]
[test_tmpl_treeelementsimplesyntaxrecursivetreebuilder.xul]
[test_tmpl_treeelementtreecell.xul]
[test_tmpl_treeelementtreecellsortascending.xul]
[test_tmpl_treeelementtreecellsortascendingtreebuilder.xul]
[test_tmpl_treeelementtreecelltreebuilder.xul]
[test_tmpl_treeelementtreeitemonly.xul]
[test_tmpl_treeelementtreeitemsortascending.xul]
[test_tmpl_twogenerationnodes.xul]
[test_tmpl_whereafterignorecase.xul]
[test_tmpl_whereafterlowercase.xul]
[test_tmpl_whereafternegation.xul]
[test_tmpl_whereafteruppercase.xul]
[test_tmpl_wherebeforeignorecase.xul]
[test_tmpl_wherebeforelowercase.xul]
[test_tmpl_wherebeforenegation.xul]
[test_tmpl_wherebeforeuppercase.xul]
[test_tmpl_wherecontains.xul]
[test_tmpl_wherecontainsignorecase.xul]
[test_tmpl_wherecontainsnegation.xul]
[test_tmpl_wherecontainsnumber.xul]
[test_tmpl_wherecontainsnumberstring.xul]
[test_tmpl_wherecontainsresource.xul]
[test_tmpl_wherecontainstwo.xul]
[test_tmpl_whereendswith.xul]
[test_tmpl_whereendswithignorecase.xul]
[test_tmpl_whereendswithnegation.xul]
[test_tmpl_whereequals.xul]
[test_tmpl_whereequalsignorecase.xul]
[test_tmpl_whereequalsmultiple.xul]
[test_tmpl_whereequalsmultiplenegation.xul]
[test_tmpl_whereequalsmultiplenegationignorecase.xul]
[test_tmpl_whereequalsnegation.xul]
[test_tmpl_whereequalsnegationignorecase.xul]
[test_tmpl_whereequalsnegationwrongcase.xul]
[test_tmpl_whereequalsnumber.xul]
[test_tmpl_whereequalsothervariable.xul]
[test_tmpl_whereequalsresource.xul]
[test_tmpl_whereequalssamevariable.xul]
[test_tmpl_whereequalswrongcase.xul]
[test_tmpl_wheregreater.xul]
[test_tmpl_wheregreaternegation.xul]
[test_tmpl_wheregreaternegationstring.xul]
[test_tmpl_wheregreaterstring.xul]
[test_tmpl_whereless.xul]
[test_tmpl_wherelessnegation.xul]
[test_tmpl_wherelessnegationstring.xul]
[test_tmpl_wherelessstring.xul]
[test_tmpl_wherenorel.xul]
[test_tmpl_wherenosubject.xul]
[test_tmpl_wherenovalue.xul]
[test_tmpl_wherestartswith.xul]
[test_tmpl_wherestartswithignorecase.xul]
[test_tmpl_wherestartswithmultiple.xul]
[test_tmpl_wherestartswithnegation.xul]
[test_tmpl_wherestartswithunknownvariable.xul]
[test_tmpl_wherestartswithvariable.xul]
[test_tmpl_wheresubjectequalsvariable.xul]
[test_tmpl_wheresubjectstartswithvariable.xul]
[test_tmpl_xmlquerysimple.xul]
[test_tmpl_xmlquerywithassign.xul]
[test_tmpl_xmlquerywithassignmentandcondition.xul]
[test_tmpl_xmlquerywithassignmentandconditiondontrecurse.xul]
[test_tmpl_xmlquerywithbindinginbindings.xul]
[test_tmpl_xmlquerywithbindinginrule.xul]
[test_tmpl_xmlquerywithdifferentmember.xul]
[test_tmpl_xmlquerywithinlinedata.xul]
[test_tmpl_xmlquerywithinlinedatawithmultiplequeries.xul]
[test_tmpl_xmlquerywithmultiplequeries.xul]
[test_tmpl_xmlquerywithothertypes.xul]
[test_tmpl_xmlquerywithsort.xul]
[test_tmpl_xmlquerywithsortotherfield.xul]

View File

@ -1,13 +0,0 @@
<?xml version="1.0"?>
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:s="urn:croczilla:xulsvg1:">
<rdf:Description about="urn:root">
<s:shapes>
<rdf:Bag>
<rdf:li>
<rdf:Description />
</rdf:li>
</rdf:Bag>
</s:shapes>
</rdf:Description>
</rdf:RDF>

View File

@ -1,488 +0,0 @@
/**
* This script is used for testing XUL templates. Call test_template within
* a load event handler.
*
* A test should have a root node with the datasources attribute with the
* id 'root', and a few global variables defined in the test's XUL file:
*
* testid: the testid, used when outputting test results
* expectedOutput: e4x data containing the expected output. It can optionally
* be enclosed in an <output> element as most tests generate
* more than one node of output.
* isTreeBuilder: true for dont-build-content trees, false otherwise
* queryType: 'rdf', 'xml', etc.
* needsOpen: true for menu tests where the root menu must be opened before
* comparing results
* notWorkingYet: true if this test isn't working yet, outputs todo results
* notWorkingYetDynamic: true if the dynamic changes portion of the test
* isn't working yet, outputs todo results
* changes: an array of functions to perform in sequence to test dynamic changes
* to the datasource.
*
* If the <output> element has an unordered attribute set to true, the
* children within it must all appear to match, but may appear in any order.
* If the unordered attribute is not set, the children must appear in the same
* order.
*
* If the 'changes' array is used, it should be an array of functions. Each
* function will be called in order and a comparison of the output will be
* performed. This allows changes to be made to the datasource to ensure that
* the generated template output has been updated. Within the expected output
* XML, the step attribute may be set to a number on an element to indicate
* that an element only applies before or after a particular change. If step
* is set to a positive number, that element will only exist after that step in
* the list of changes made. If step is set to a negative number, that element
* will only exist until that step. Steps are numbered starting at 1. For
* example:
* <label value="Cat"/>
* <label step="2" value="Dog"/>
* <label step="-5" value="Mouse"/>
* The first element will always exist. The second element will only appear
* after the second change is made. The third element will only appear until
* the fifth change and it will no longer be present at later steps.
*
* If the anyid attribute is set to true on an element in the expected output,
* then the value of the id attribute on that element is not compared for a
* match. This is used, for example, for xml datasources, where the ids set on
* the generated output are pseudo-random.
*/
const ZOO_NS = "http://www.some-fictitious-zoo.com/";
const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
const debug = false;
var expectedConsoleMessages = [];
var expectLoggedMessages = null;
function get_RDF() {
try {
return Components.classes["@mozilla.org/rdf/rdf-service;1"].
getService(Components.interfaces.nsIRDFService);
} catch (ex) { }
}
function get_ContainerUtils()
{
try {
return Components.classes["@mozilla.org/rdf/container-utils;1"].
getService(Components.interfaces.nsIRDFContainerUtils);
} catch(ex) { }
}
const RDF = get_RDF();
const ContainerUtils = get_ContainerUtils();
var xmlDoc;
function test_template()
{
var root = document.getElementById("root");
var ds;
if (queryType == "rdf" && RDF) {
var ioService = Components.classes["@mozilla.org/network/io-service;1"].
getService(Components.interfaces.nsIIOService);
var src = window.location.href.replace(/test_tmpl.*xul/, "animals.rdf");
ds = RDF.GetDataSourceBlocking(src);
if (expectLoggedMessages) {
Components.classes["@mozilla.org/consoleservice;1"].
getService(Components.interfaces.nsIConsoleService).reset();
}
if (root.getAttribute("datasources") == "rdf:null")
root.setAttribute("datasources", "animals.rdf");
}
else if (queryType == "xml") {
var src = window.location.href.replace(/test_tmpl.*xul/, "animals.xml");
xmlDoc = new XMLHttpRequest();
xmlDoc.open("get", src, false);
xmlDoc.send(null);
}
// open menus if necessary
if (needsOpen)
root.open = true;
if (expectLoggedMessages)
expectLoggedMessages();
checkResults(root, 0);
if (changes.length) {
var usedds = ds;
// within these chrome tests, RDF datasources won't be modifiable unless
// an in-memory datasource is used instead. Call copyRDFDataSource to
// copy the datasource.
if (queryType == "rdf")
usedds = copyRDFDataSource(root, ds);
if (needsOpen)
root.open = true;
setTimeout(iterateChanged, 0, root, usedds);
}
else {
if (needsOpen)
root.open = false;
if (expectedConsoleMessages.length)
compareConsoleMessages();
SimpleTest.finish();
}
}
function iterateChanged(root, ds)
{
Components.classes["@mozilla.org/consoleservice;1"].
getService(Components.interfaces.nsIConsoleService).reset();
for (var c = 0; c < changes.length; c++) {
changes[c](ds, root);
checkResults(root, c + 1);
}
if (needsOpen)
root.open = false;
if (expectedConsoleMessages.length)
compareConsoleMessages();
SimpleTest.finish();
}
function checkResults(root, step)
{
var output = expectedOutput.cloneNode(true);
setForCurrentStep(output, step);
var error;
var actualoutput = root;
if (isTreeBuilder) {
// convert the tree's view data into the equivalent DOM structure
// for easier comparison
actualoutput = treeViewToDOM(root);
var treechildrenElements = [...output.children].filter((e) => e.localName === "treechildren");
error = compareOutput(actualoutput, treechildrenElements[0], false);
}
else {
error = compareOutput(actualoutput, output, true);
}
var adjtestid = testid;
if (step > 0)
adjtestid += " dynamic step " + step;
var stilltodo = ((step == 0 && notWorkingYet) || (step > 0 && notWorkingYetDynamic));
if (stilltodo)
todo(false, adjtestid);
else
ok(!error, adjtestid);
if ((!stilltodo && error) || debug) {
// for debugging, serialize the XML output
var serializedXML = "";
var rootNodes = actualoutput.childNodes;
for (var n = 0; n < rootNodes.length; n++) {
var node = rootNodes[n];
if (node.localName != "template")
serializedXML += ((new XMLSerializer()).serializeToString(node));
}
// remove the XUL namespace declarations to make the output more readable
const nsrepl = new RegExp("xmlns=\"" + XUL_NS + "\" ", "g");
serializedXML = serializedXML.replace(nsrepl, "");
if (debug)
dump("-------- " + adjtestid + " " + error + ":\n" + serializedXML + "\n");
if (!stilltodo && error)
is(serializedXML, "Same", "Error is: " + error);
}
}
/**
* Adjust the expected output to acccount for any step attributes.
*/
function setForCurrentStep(content, currentStep)
{
var todelete = [];
for (var child of content.childNodes) {
if (child.nodeType === Node.ELEMENT_NODE) {
var stepstr = child.getAttribute("step") || "";
var stepsarr = stepstr.split(",");
for (var s = 0; s < stepsarr.length; s++) {
var step = parseInt(stepsarr[s]);
if ((step > 0 && step > currentStep) ||
(step < 0 && -step <= currentStep)) {
todelete.push(child);
}
}
} else if (child.nodeType === Node.TEXT_NODE) {
// Drop empty text nodes.
if (child.nodeValue.trim() === "")
todelete.push(child);
}
}
for (var e of todelete)
content.removeChild(e);
for (var child of content.children) {
child.removeAttribute("step");
setForCurrentStep(child, currentStep);
}
}
/**
* Compares the 'actual' DOM output with the 'expected' output. This function
* is called recursively, with isroot true if actual refers to the root of the
* template. Returns a null string if they are equal and an error string if
* they are not equal. This function is called recursively as it iterates
* through each node in the DOM tree.
*/
function compareOutput(actual, expected, isroot)
{
if (isroot && expected.localName != "data")
return "expected must be a <data> element";
var t;
// compare text nodes
if (expected.nodeType == Node.TEXT_NODE) {
if (actual.nodeValue !== expected.nodeValue.trim())
return "Text " + actual.nodeValue + " doesn't match " + expected.nodeValue;
return "";
}
if (!isroot) {
var anyid = false;
// make sure that the tags match
if (actual.localName != expected.localName)
return "Tag name " + expected.localName + " not found";
// loop through the attributes in the expected node and compare their
// values with the corresponding attribute on the actual node
var expectedAttrs = expected.attributes;
for (var a = 0; a < expectedAttrs.length; a++) {
var attr = expectedAttrs[a];
var expectval = attr.value;
// skip checking the id when anyid="true", however make sure to
// ensure that the id is actually present.
if (attr.name == "anyid" && expectval == "true") {
anyid = true;
if (!actual.hasAttribute("id"))
return "expected id attribute";
}
else if (actual.getAttribute(attr.name) != expectval) {
return "attribute " + attr.name + " is '" +
actual.getAttribute(attr.name) + "' instead of '" + expectval + "'";
}
}
// now loop through the actual attributes and make sure that there aren't
// any extra attributes that weren't expected
var length = actual.attributes.length;
for (t = 0; t < length; t++) {
var aattr = actual.attributes[t];
var expectval = expected.getAttribute(aattr.name);
// ignore some attributes that don't matter
if (expectval != actual.getAttribute(aattr.name) &&
aattr.name != "staticHint" && aattr.name != "xmlns" &&
(aattr.name != "id" || !anyid))
return "extra attribute " + aattr.name;
}
}
// ensure that the node has the right number of children. Subtract one for
// the root node to account for the <template> node.
length = actual.childNodes.length - (isroot ? 1 : 0);
if (length != expected.childNodes.length)
return "incorrect child node count of " + actual.localName + " " + length +
" expected " + expected.childNodes.length;
// if <data unordered="true"> is used, then the child nodes may be in any order
var unordered = (expected.localName == "data" && expected.getAttribute("unordered") == "true");
// next, loop over the children and call compareOutput recursively on each one
var adj = 0;
for (t = 0; t < actual.childNodes.length; t++) {
var actualnode = actual.childNodes[t];
// skip the <template> element, and add one to the indices when looking
// at the later nodes to account for it
if (isroot && actualnode.localName == "template") {
adj++;
}
else {
var output = "unexpected";
if (unordered) {
var expectedChildren = expected.childNodes;
for (var e = 0; e < expectedChildren.length; e++) {
output = compareOutput(actualnode, expectedChildren[e], false);
if (!output)
break;
}
}
else {
output = compareOutput(actualnode, expected.childNodes[t - adj], false);
}
// an error was returned, so return early
if (output)
return output;
}
}
return "";
}
/*
* copy the datasource into an in-memory datasource so that it can be modified
*/
function copyRDFDataSource(root, sourceds)
{
var dsourcesArr = [];
var composite = root.database;
var dsources = composite.GetDataSources();
while (dsources.hasMoreElements()) {
sourceds = dsources.getNext().QueryInterface(Components.interfaces.nsIRDFDataSource);
dsourcesArr.push(sourceds);
}
for (var d = 0; d < dsourcesArr.length; d++)
composite.RemoveDataSource(dsourcesArr[d]);
var newds = Components.classes["@mozilla.org/rdf/datasource;1?name=in-memory-datasource"].
createInstance(Components.interfaces.nsIRDFDataSource);
var sourcelist = sourceds.GetAllResources();
while (sourcelist.hasMoreElements()) {
var source = sourcelist.getNext();
var props = sourceds.ArcLabelsOut(source);
while (props.hasMoreElements()) {
var prop = props.getNext();
if (prop instanceof Components.interfaces.nsIRDFResource) {
var targets = sourceds.GetTargets(source, prop, true);
while (targets.hasMoreElements())
newds.Assert(source, prop, targets.getNext(), true);
}
}
}
composite.AddDataSource(newds);
root.builder.rebuild();
return newds;
}
/**
* Converts a tree view (nsITreeView) into the equivalent DOM tree.
* Returns the treechildren
*/
function treeViewToDOM(tree)
{
var treechildren = document.createElement("treechildren");
if (tree.view)
treeViewToDOMInner(tree.columns, treechildren, tree.view, tree.builder, 0, 0);
return treechildren;
}
function treeViewToDOMInner(columns, treechildren, view, builder, start, level)
{
var end = view.rowCount;
for (var i = start; i < end; i++) {
if (view.getLevel(i) < level)
return i - 1;
var id = builder ? builder.getResourceAtIndex(i).Value : "id" + i;
var item = document.createElement("treeitem");
item.setAttribute("id", id);
treechildren.appendChild(item);
var row = document.createElement("treerow");
item.appendChild(row);
for (var c = 0; c < columns.length; c++) {
var cell = document.createElement("treecell");
var label = view.getCellText(i, columns[c]);
if (label)
cell.setAttribute("label", label);
row.appendChild(cell);
}
if (view.isContainer(i)) {
item.setAttribute("container", "true");
item.setAttribute("empty", view.isContainerEmpty(i) ? "true" : "false");
if (!view.isContainerEmpty(i) && view.isContainerOpen(i)) {
item.setAttribute("open", "true");
var innertreechildren = document.createElement("treechildren");
item.appendChild(innertreechildren);
i = treeViewToDOMInner(columns, innertreechildren, view, builder, i + 1, level + 1);
}
}
}
return i;
}
function expectConsoleMessage(ref, id, isNew, isActive, extra)
{
var message = "In template with id root" +
(ref ? " using ref " + ref : "") + "\n " +
(isNew ? "New " : "Removed ") + (isActive ? "active" : "inactive") +
" result for query " + extra + ": " + id;
expectedConsoleMessages.push(message);
}
function compareConsoleMessages()
{
var consoleService = Components.classes["@mozilla.org/consoleservice;1"].
getService(Components.interfaces.nsIConsoleService);
var messages = consoleService.getMessageArray() || [];
messages = messages.map(m => m.message);
// Copy to avoid modifying expectedConsoleMessages
var expect = expectedConsoleMessages.concat();
for (var m = 0; m < messages.length; m++) {
if (messages[m] == expect[0]) {
ok(true, "found message " + expect.shift());
}
}
if (expect.length != 0) {
ok(false, "failed to find expected console messages: " + expect);
}
}
function copyToProfile(filename)
{
if (Cc === undefined) {
var Cc = Components.classes;
var Ci = Components.interfaces;
}
var loader = Cc["@mozilla.org/moz/jssubscript-loader;1"]
.getService(Ci.mozIJSSubScriptLoader);
loader.loadSubScript("chrome://mochikit/content/chrome-harness.js");
var file = Cc["@mozilla.org/file/directory_service;1"]
.getService(Ci.nsIProperties)
.get("ProfD", Ci.nsIFile);
file.append(filename);
var parentURI = getResolvedURI(getRootDirectory(window.location.href));
if (parentURI.JARFile) {
parentURI = extractJarToTmp(parentURI);
} else {
var fileHandler = Cc["@mozilla.org/network/protocol;1?name=file"].
getService(Ci.nsIFileProtocolHandler);
parentURI = fileHandler.getFileFromURLSpec(parentURI.spec);
}
parentURI = parentURI.QueryInterface(Ci.nsIFile);
parentURI.append(filename);
try {
var retVal = parentURI.copyToFollowingLinks(file.parent, filename);
} catch (ex) {
//ignore this error as the file could exist already
}
}

View File

@ -1,28 +0,0 @@
<?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
<?xml-stylesheet type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"?>
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
xmlns:svg="http://www.w3.org/2000/svg">
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
<script>
SimpleTest.waitForExplicitFinish();
function init()
{
document.documentElement.appendChild(document.getElementById("svg"));
ok(true, "Didn't crash");
SimpleTest.finish();
}
window.addEventListener("load", init, false);
</script>
<svg:svg datasources="" id="svg"/>
</window>

View File

@ -1,51 +0,0 @@
<?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
<?xml-stylesheet type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"?>
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns:html="http://www.w3.org/1999/xhtml"
onload="boom();">
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
<script type="text/javascript">
<![CDATA[
SimpleTest.waitForExplicitFinish();
function boom()
{
const RDF = Components.classes["@mozilla.org/rdf/rdf-service;1"].
getService(Components.interfaces.nsIRDFService);
var src = window.location.href.replace(/test_bug330010.xul/, "file_bug330010.rdf");
var ds = RDF.GetDataSourceBlocking(src);
var s = document.getElementById("s");
s.setAttribute("datasources", "file_bug330010.rdf");
var x = document.createElementNS("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul", "hbox");
var generatedShape = s.childNodes[3];
generatedShape.appendChild(x);
document.documentElement.removeChild(document.getElementById("s"));
ok(true, "Didn't crash");
SimpleTest.finish();
}
]]>
</script>
<html:div datasources="rdf:null" ref="urn:root" flex="1" id="s">
<template>
<rule>
<conditions>
<content uri="?root"/>
<triple subject="?root"
predicate="urn:croczilla:xulsvg1:shapes"
object="?shapes"/>
<member container="?shapes" child="?shape" id="m"/>
</conditions>
<action>
<hbox id="p" uri="?shape" />
</action>
</rule>
</template>
</html:div>
</window>

View File

@ -1,19 +0,0 @@
<?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
<?xml-stylesheet type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"?>
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" xmlns:html="http://www.w3.org/1999/xhtml" onload="boom();">
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
<script type="text/javascript">
SimpleTest.waitForExplicitFinish();
function boom() {
ok(true, "Didn't crash");
SimpleTest.finish();
}
</script>
<html:span datasources="0" />
</window>

View File

@ -1,148 +0,0 @@
<?xml version="1.0" ?>
<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?>
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<tree flex="20" id="t" ref="urn:data:row" datasources="rdf:null" seltype="single">
<treecols>
<treecol flex="1" id="id" label="id" sort="rdf:http://dummy/rdf#id" />
<splitter class="tree-splitter"/>
<treecol flex="1" id="title" label="title" sort="rdf:http://dummy/rdf#title" sortActive="true" sortDirection="ascending" /><splitter class="tree-splitter"/>
</treecols>
<template>
<treechildren>
<treeitem uri="rdf:*" seltype="single">
<treerow >
<treecell label="rdf:http://dummy/rdf#id"/>
<treecell label="rdf:http://dummy/rdf#title"/>
</treerow>
</treeitem>
</treechildren>
</template>
</tree>
<tree flex="20" id="tc" ref="urn:data:row" datasources="rdf:null" seltype="single" flags="dont-build-content">
<treecols>
<treecol flex="1" id="idc" label="id" sort="rdf:http://dummy/rdf#id" />
<splitter class="tree-splitter"/>
<treecol flex="1" id="titlec" label="title" sort="rdf:http://dummy/rdf#title" sortActive="true" sortDirection="ascending" /><splitter class="tree-splitter"/>
</treecols>
<template>
<treechildren>
<treeitem uri="rdf:*" seltype="single">
<treerow >
<treecell label="rdf:http://dummy/rdf#id"/>
<treecell label="rdf:http://dummy/rdf#title"/>
</treerow>
</treeitem>
</treechildren>
</template>
</tree>
<body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/>
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/x-javascript">
<![CDATA[
var buildCount = 0;
SimpleTest.waitForExplicitFinish();
var TemplateBuilderListener = {
willRebuild: function(aBuilder) {
},
didRebuild: function(aBuilder) {
++buildCount;
var remove = false;
if (buildCount == 2) {
remove =true;
setTimeout(nextDataSource, 0);
} else if (buildCount == 4) {
remove = true;
setTimeout(continueTest, 0);
}
if (remove) {
var tree = document.getElementById('t');
var treec = document.getElementById('tc');
tree.builder.removeListener(TemplateBuilderListener);
treec.builder.removeListener(TemplateBuilderListener);
}
},
QueryInterface: function (aIID)
{
if (!aIID.equals(Components.interfaces.nsIXULBuilderListener) &&
!aIID.equals(Components.interfaces.nsISupports))
throw Components.results.NS_ERROR_NO_INTERFACE;
return this;
}
};
function runTest() {
var tree = document.getElementById('t');
var treec = document.getElementById('tc');
try {
var rdfService = Components.classes["@mozilla.org/rdf/rdf-service;1"].
getService(Components.interfaces.nsIRDFService);
var s1 = window.location.href.replace(/test_bug441785.xul/, "bug441785-1.rdf");
var ds1 = rdfService.GetDataSourceBlocking(s1);
var s2 = window.location.href.replace(/test_bug441785.xul/, "bug441785-2.rdf");
var ds2 = rdfService.GetDataSourceBlocking(s2);
} catch (ex) { }
tree.builder.addListener(TemplateBuilderListener);
treec.builder.addListener(TemplateBuilderListener);
tree.setAttribute('datasources', 'bug441785-1.rdf');
treec.setAttribute('datasources', 'bug441785-1.rdf');
}
var oldtreefirstrow, oldtreecfirstrow;
function nextDataSource()
{
var tree = document.getElementById('t');
var treec = document.getElementById('tc');
tree.treeBoxObject.scrollToRow(10);
treec.treeBoxObject.scrollToRow(10);
is(tree.treeBoxObject.getFirstVisibleRow(), 10, "first tree row count datasource 1");
is(treec.treeBoxObject.getFirstVisibleRow(), 10, "second tree row count datasource 1");
tree.builder.addListener(TemplateBuilderListener);
treec.builder.addListener(TemplateBuilderListener);
tree.setAttribute('datasources', 'bug441785-2.rdf');
treec.setAttribute('datasources', 'bug441785-2.rdf');
}
function continueTest() {
var tree = document.getElementById('t');
var treec = document.getElementById('tc');
is(tree.treeBoxObject.getFirstVisibleRow(), 0, "first tree row count datasource 2");
is(treec.treeBoxObject.getFirstVisibleRow(), 0, "second tree row count datasource 2");
try {
window.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
.getInterface(Components.interfaces.nsIDOMWindowUtils)
.garbageCollect();
}
catch (e) { }
// Hit the bug, crash
// (not exactly the same kind of crash as 441785, but from the same cause)
tree.remove();
treec.remove();
SimpleTest.finish();
}
window.addEventListener("load", runTest, false);
]]>
</script>
</window>

View File

@ -1,76 +0,0 @@
<?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
<?xml-stylesheet
href="chrome://mochikit/content/tests/SimpleTest/test.css"
type="text/css"?>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=476634
-->
<window title="Mozilla Bug 476634" onload="startup()"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<script type="application/javascript"
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<body xmlns="http://www.w3.org/1999/xhtml">
<a target="_blank"
href="https://bugzilla.mozilla.org/show_bug.cgi?id=304188">Mozilla Bug 476634</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
</pre>
</body>
<template id="test-template">
<query>SELECT id,value FROM test</query>
<action>
<label uri="?" id="?id" value="?value"/>
</action>
</template>
<vbox id="results-list" datasources="rdf:null" querytype="storage" ref="*"
template="test-template"/>
<script class="testbody" type="application/javascript">
<![CDATA[
function startup() {
var ss = Components.classes["@mozilla.org/storage/service;1"]
.getService(Components.interfaces.mozIStorageService);
var db = ss.openSpecialDatabase("memory");
db.createTable("test", "id TEXT, value INTEGER");
var stmt = db.createStatement("INSERT INTO test (id, value) VALUES (?,?)");
stmt.bindByIndex(0, "test1");
stmt.bindByIndex(1, 0);
stmt.execute();
stmt.bindByIndex(0, "test2");
stmt.bindByIndex(1, 2147483647);
stmt.execute();
stmt.bindByIndex(0, "test3");
stmt.bindByIndex(1, -2147483648);
stmt.execute();
stmt.bindByIndex(0, "test4");
stmt.bindByIndex(1, 0);
stmt.execute();
stmt.bindByIndex(0, "test5");
stmt.bindByIndex(1, 3147483647);
stmt.execute();
stmt.bindByIndex(0, "test6");
stmt.bindByIndex(1, -3147483648);
stmt.execute();
stmt.finalize();
var list = document.getElementById("results-list");
list.builder.datasource = db;
is(list.childNodes.length, 6, "Should be 6 generated elements");
is(list.childNodes[0].value, "0", "Should have seen the correct value");
is(list.childNodes[1].value, "2147483647", "Should have seen the correct value");
is(list.childNodes[2].value, "-2147483648", "Should have seen the correct value");
is(list.childNodes[3].value, "0", "Should have seen the correct value");
is(list.childNodes[4].value, "3147483647", "Should have seen the correct value");
is(list.childNodes[5].value, "-3147483648", "Should have seen the correct value");
}
]]>
</script>
</window>

View File

@ -1,70 +0,0 @@
<?xml version="1.0" ?>
<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?>
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<vbox id="box"/>
<body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/>
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/x-javascript">
<![CDATA[
var tests = [
[["One", "Two", "Three", "Four"], "", "Four One Three Two"],
[["One", "Two", "Three", "Four"], "integer", "Four One Three Two"],
[["One", "Two", "Three", "Four"], "descending", "Two Three One Four"],
[["One", "Two", "Three", "Four"], "descending integer", "Two Three One Four"],
[["One", "Two", "Three", "Four"], "integer cat descending", "Two Three One Four"],
[["1", "13", "2", "7", "12", "240", "2", "170", "222", "98"], "", "1 12 13 170 2 2 222 240 7 98"],
[["1", "13", "2", "7", "12", "240", "2", "170", "222", "98"], "integer", "1 2 2 7 12 13 98 170 222 240"],
[["1", "13", "2", "7", "12", "240", "2", "170", "222", "98"], "ascending integer", "1 2 2 7 12 13 98 170 222 240"],
[["1", "13", "2", "7", "12", "240", "2", "170", "222", "98"], "integer descending", "240 222 170 98 13 12 7 2 2 1"],
[["Cat", "cat", "Candy", "candy"], "comparecase", "Candy Cat candy cat"],
[["1", "102", "22", "One", "40", "Two"], "integer", "1 22 40 102 One Two"],
];
SimpleTest.waitForExplicitFinish();
function doTests()
{
var box = document.getElementById("box");
const sortService = Components.classes["@mozilla.org/xul/xul-sort-service;1"].
getService(Components.interfaces.nsIXULSortService);
for (let t = 0; t < tests.length; t++) {
var test = tests[t];
for (let e = 0; e < test[0].length; e++) {
var label = document.createElement("label");
label.setAttribute("value", test[0][e]);
box.appendChild(label);
}
sortService.sort(box, "value", test[1]);
var actual = "";
for (let e = 0; e < box.childNodes.length; e++) {
if (actual)
actual += " ";
actual += box.childNodes[e].getAttribute("value");
}
is(actual, test[2], "sorted step " + (t + 1));
while(box.hasChildNodes())
box.firstChild.remove();
box.removeAttribute("sortDirection");
}
SimpleTest.finish();
}
window.addEventListener("load", doTests, false);
]]>
</script>
</window>

View File

@ -1,73 +0,0 @@
<?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?>
<!--
bindings - extended syntax
-->
<window title="XUL Template Tests" width="500" height="600"
onload="test_template();"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<script type="application/javascript"
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/>
<data id="output">
<label step="-2" id="http://www.some-fictitious-zoo.com/humans/sarah" value="Sarah "/>
<label step="2" id="http://www.some-fictitious-zoo.com/humans/sarah" value="Sarah Yarmouth"/>
<label step="-1" id="http://www.some-fictitious-zoo.com/humans/robert" value="Robert Sanderson"/>
<label step="1" id="http://www.some-fictitious-zoo.com/humans/robert" value="Robert "/>
</data>
<script src="templates_shared.js"/>
<script>
<![CDATA[
SimpleTest.waitForExplicitFinish();
var testid ="bindings - extended syntax";
var queryType = "rdf";
var isTreeBuilder = false;
var needsOpen = false;
var notWorkingYet = false;
var notWorkingYetDynamic = false;
var expectedOutput = document.getElementById("output");
var changes = [
// step 1
function(targetds, root) {
targetds.Unassert(RDF.GetResource(ZOO_NS + 'humans/robert'),
RDF.GetResource(ZOO_NS + 'rdf#lastName'),
RDF.GetLiteral('Sanderson'), true);
},
// step 2
function(targetds, root) {
targetds.Assert(RDF.GetResource(ZOO_NS + 'humans/sarah'),
RDF.GetResource(ZOO_NS + 'rdf#lastName'),
RDF.GetLiteral('Yarmouth'), true);
}
];
]]>
</script>
<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="root" datasources="rdf:null" ref="http://www.some-fictitious-zoo.com/humans">
<template id="template">
<rule>
<conditions>
<content uri="?uri"/>
<member container="?uri" child="?child"/>
<triple subject="?child" predicate="http://www.some-fictitious-zoo.com/rdf#name" object="?name"/>
</conditions>
<bindings>
<binding subject="?child" predicate="http://www.some-fictitious-zoo.com/rdf#lastName" object="?lastname"/>
</bindings>
<action>
<label uri="?child" value="?name ?lastname"/>
</action>
</rule>
</template>
</vbox>
</window>

Some files were not shown because too many files have changed in this diff Show More