1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /* ***** BEGIN LICENSE BLOCK *****
3 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 * The contents of this file are subject to the Mozilla Public License Version
6 * 1.1 (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 * http://www.mozilla.org/MPL/
10 * Software distributed under the License is distributed on an "AS IS" basis,
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 * for the specific language governing rights and limitations under the
15 * The Original Code is Mozilla Communicator client code.
17 * The Initial Developer of the Original Code is
18 * Netscape Communications Corporation.
19 * Portions created by the Initial Developer are Copyright (C) 1998
20 * the Initial Developer. All Rights Reserved.
23 * Robert Churchill <rjc@netscape.com>
24 * David Hyatt <hyatt@netscape.com>
25 * Chris Waterson <waterson@netscape.com>
26 * Pierre Phaneuf <pp@ludusdesign.com>
27 * Neil Deakin <enndeakin@sympatico.ca>
29 * Alternatively, the contents of this file may be used under the terms of
30 * either of the GNU General Public License Version 2 or later (the "GPL"),
31 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
32 * in which case the provisions of the GPL or the LGPL are applicable instead
33 * of those above. If you wish to allow use of your version of this file only
34 * under the terms of either the GPL or the LGPL, and not to allow others to
35 * use your version of this file under the terms of the MPL, indicate your
36 * decision by deleting the provisions above and replace them with the notice
37 * and other provisions required by the GPL or the LGPL. If you do not delete
38 * the provisions above, a recipient may use your version of this file under
39 * the terms of any one of the MPL, the GPL or the LGPL.
41 * ***** END LICENSE BLOCK ***** */
43 #ifndef nsXULTemplateBuilder_h__
44 #define nsXULTemplateBuilder_h__
46 #include "nsStubDocumentObserver.h"
47 #include "nsIScriptSecurityManager.h"
48 #include "nsIContent.h"
49 #include "nsIObserver.h"
50 #include "nsIRDFCompositeDataSource.h"
51 #include "nsIRDFContainer.h"
52 #include "nsIRDFContainerUtils.h"
53 #include "nsIRDFDataSource.h"
54 #include "nsIRDFObserver.h"
55 #include "nsIRDFService.h"
56 #include "nsIXULTemplateBuilder.h"
58 #include "nsFixedSizeAllocator.h"
59 #include "nsVoidArray.h"
60 #include "nsCOMArray.h"
62 #include "nsDataHashtable.h"
63 #include "nsTemplateRule.h"
64 #include "nsTemplateMatch.h"
65 #include "nsIXULTemplateQueryProcessor.h"
66 #include "nsCycleCollectionParticipant.h"
70 extern PRLogModuleInfo
* gXULTemplateLog
;
74 class nsIRDFCompositeDataSource
;
75 class nsIObserverService
;
78 * An object that translates an RDF graph into a presentation using a
81 class nsXULTemplateBuilder
: public nsIXULTemplateBuilder
,
83 public nsStubDocumentObserver
86 nsXULTemplateBuilder();
87 virtual ~nsXULTemplateBuilder();
89 nsresult
InitGlobals();
92 * Clear the template builder structures. The aIsFinal flag is set to true
93 * when the template is going away.
95 virtual void Uninit(PRBool aIsFinal
);
97 // nsISupports interface
98 NS_DECL_CYCLE_COLLECTING_ISUPPORTS
99 NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsXULTemplateBuilder
,
100 nsIXULTemplateBuilder
)
102 // nsIXULTemplateBuilder interface
103 NS_DECL_NSIXULTEMPLATEBUILDER
105 // nsIObserver Interface
108 // nsIMutationObserver
109 NS_DECL_NSIMUTATIONOBSERVER_ATTRIBUTECHANGED
110 NS_DECL_NSIMUTATIONOBSERVER_CONTENTREMOVED
111 NS_DECL_NSIMUTATIONOBSERVER_NODEWILLBEDESTROYED
114 * Remove an old result and/or add a new result. This method will retrieve
115 * the set of containers where the result could be inserted and either add
116 * the new result to those containers, or remove the result from those
117 * containers. UpdateResultInContainer is called for each container.
119 * @param aOldResult result to remove
120 * @param aNewResult result to add
121 * @param aQueryNode query node for new result
124 UpdateResult(nsIXULTemplateResult
* aOldResult
,
125 nsIXULTemplateResult
* aNewResult
,
126 nsIDOMNode
* aQueryNode
);
129 * Remove an old result and/or add a new result from a specific container.
131 * @param aOldResult result to remove
132 * @param aNewResult result to add
133 * @param aQueryNode queryset for the new result
134 * @param aOldId id of old result
135 * @param aNewId id of new result
136 * @param aInsertionPoint container to remove or add result inside
139 UpdateResultInContainer(nsIXULTemplateResult
* aOldResult
,
140 nsIXULTemplateResult
* aNewResult
,
141 nsTemplateQuerySet
* aQuerySet
,
142 nsIRDFResource
* aOldId
,
143 nsIRDFResource
* aNewId
,
144 nsIContent
* aInsertionPoint
);
147 ComputeContainmentProperties();
150 IsTemplateElement(nsIContent
* aContent
);
153 RebuildAll() = 0; // must be implemented by subclasses
156 * Find the <template> tag that applies for this builder
159 GetTemplateRoot(nsIContent
** aResult
);
162 * Compile the template's queries
168 * Compile the template given a <template> in aTemplate. This function
169 * is called recursively to handle queries inside a queryset. For the
170 * outer pass, aIsQuerySet will be false, while the inner pass this will
173 * aCanUseTemplate will be set to true if the template's queries could be
174 * compiled, and false otherwise. If false, the entire template is
177 * @param aTemplate <template> to compile
178 * @param aQuerySet first queryset
179 * @param aIsQuerySet true if
180 * @param aPriority the queryset index, incremented when a new one is added
181 * @param aCanUseTemplate true if template is valid
184 CompileTemplate(nsIContent
* aTemplate
,
185 nsTemplateQuerySet
* aQuerySet
,
188 PRBool
* aCanUseTemplate
);
191 * Compile a query using the extended syntax. For backwards compatible RDF
192 * syntax where there is no <query>, the <conditions> becomes the query.
194 * @param aRuleElement <rule> element
195 * @param aActionElement <action> element
196 * @param aMemberVariable member variable for the query
197 * @param aQuerySet the queryset
200 CompileExtendedQuery(nsIContent
* aRuleElement
,
201 nsIContent
* aActionElement
,
202 nsIAtom
* aMemberVariable
,
203 nsTemplateQuerySet
* aQuerySet
);
206 * Determine the ref variable and tag from inside a RDF query.
208 void DetermineRDFQueryRef(nsIContent
* aQueryElement
, nsIAtom
** tag
);
211 * Determine the member variable from inside an action body. It will be
212 * the value of the uri attribute on a node.
215 DetermineMemberVariable(nsIContent
* aActionElement
, nsIAtom
** aMemberVariable
);
218 * Compile a simple query. A simple query is one that doesn't have a
219 * <query> and should use a default query which would normally just return
220 * a list of children of the reference point.
222 * @param aRuleElement the <rule>
223 * @param aQuerySet the query set
224 * @param aCanUseTemplate true if the query is valid
227 CompileSimpleQuery(nsIContent
* aRuleElement
,
228 nsTemplateQuerySet
* aQuerySet
,
229 PRBool
* aCanUseTemplate
);
232 * Compile the <conditions> tag in a rule
234 * @param aRule template rule
235 * @param aConditions <conditions> element
238 CompileConditions(nsTemplateRule
* aRule
, nsIContent
* aConditions
);
241 * Compile a <where> tag in a condition. The caller should set
242 * *aCurrentCondition to null for the first condition. This value will be
243 * updated to point to the new condition before returning. The conditions
244 * will be added to the rule aRule by this method.
246 * @param aRule template rule
247 * @param aCondition <where> element
248 * @param aCurrentCondition compiled condition
251 CompileWhereCondition(nsTemplateRule
* aRule
,
252 nsIContent
* aCondition
,
253 nsTemplateCondition
** aCurrentCondition
);
256 * Compile the <bindings> for an extended template syntax rule.
259 CompileBindings(nsTemplateRule
* aRule
, nsIContent
* aBindings
);
262 * Compile a single binding for an extended template syntax rule.
265 CompileBinding(nsTemplateRule
* aRule
, nsIContent
* aBinding
);
268 * Add automatic bindings for simple rules
271 AddSimpleRuleBindings(nsTemplateRule
* aRule
, nsIContent
* aElement
);
274 AddBindingsFor(nsXULTemplateBuilder
* aSelf
,
275 const nsAString
& aVariable
,
279 * Load the datasources for the template. shouldDelayBuilding is an out
280 * parameter which will be set to true to indicate that content building
281 * should not be performed yet as the datasource has not yet loaded. If
282 * false, the datasource has already loaded so building can proceed
283 * immediately. In the former case, the datasource or query processor
284 * should either rebuild the template or update results when the
285 * datasource is loaded as needed.
288 LoadDataSources(nsIDocument
* aDoc
, PRBool
* shouldDelayBuilding
);
291 * Called by LoadDataSources to load a datasource given a uri list
292 * in aDataSource. The list is a set of uris separated by spaces.
293 * If aIsRDFQuery is true, then this is for an RDF datasource which
294 * causes the method to check for additional flags specific to the
298 LoadDataSourceUrls(nsIDocument
* aDocument
,
299 const nsAString
& aDataSources
,
301 PRBool
* aShouldDelayBuilding
);
304 InitHTMLTemplateRoot();
307 * Determine which rule matches a given result. aContainer is used for
308 * tag matching and is optional for non-content generating builders.
309 * The returned matched rule is always one of the rules owned by the
310 * query set aQuerySet.
312 * @param aContainer parent where generated content will be inserted
313 * @param aResult result to match
314 * @param aQuerySet query set to examine the rules of
315 * @param aMatchedRule [out] rule that has matched, or null if any.
316 * @param aRuleIndex [out] index of the rule
319 DetermineMatchedRule(nsIContent
* aContainer
,
320 nsIXULTemplateResult
* aResult
,
321 nsTemplateQuerySet
* aQuerySet
,
322 nsTemplateRule
** aMatchedRule
,
323 PRInt16
*aRuleIndex
);
325 // XXX sigh, the string template foo doesn't mix with
326 // operator->*() on egcs-1.1.2, so we'll need to explicitly pass
327 // "this" and use good ol' fashioned static callbacks.
329 ParseAttribute(const nsAString
& aAttributeValue
,
330 void (*aVariableCallback
)(nsXULTemplateBuilder
* aThis
, const nsAString
&, void*),
331 void (*aTextCallback
)(nsXULTemplateBuilder
* aThis
, const nsAString
&, void*),
335 SubstituteText(nsIXULTemplateResult
* aMatch
,
336 const nsAString
& aAttributeValue
,
340 SubstituteTextAppendText(nsXULTemplateBuilder
* aThis
, const nsAString
& aText
, void* aClosure
);
343 SubstituteTextReplaceVariable(nsXULTemplateBuilder
* aThis
, const nsAString
& aVariable
, void* aClosure
);
346 IsSystemPrincipal(nsIPrincipal
*principal
, PRBool
*result
);
349 * Convenience method which gets a resource for a result. If a result
350 * doesn't have a resource set, it will create one from the result's id.
352 nsresult
GetResultResource(nsIXULTemplateResult
* aResult
,
353 nsIRDFResource
** aResource
);
356 nsCOMPtr
<nsISupports
> mDataSource
;
357 nsCOMPtr
<nsIRDFDataSource
> mDB
;
358 nsCOMPtr
<nsIRDFCompositeDataSource
> mCompDB
;
361 * Circular reference, broken when the document is destroyed.
363 nsCOMPtr
<nsIContent
> mRoot
;
366 * The root result, translated from the root element's ref
368 nsCOMPtr
<nsIXULTemplateResult
> mRootResult
;
370 nsCOMArray
<nsIXULBuilderListener
> mListeners
;
373 * The query processor which generates results
375 nsCOMPtr
<nsIXULTemplateQueryProcessor
> mQueryProcessor
;
378 * The list of querysets
380 nsTArray
<nsTemplateQuerySet
*> mQuerySets
;
383 * Set to true if the rules have already been compiled
385 PRBool mQueriesCompiled
;
388 * The default reference and member variables.
390 nsCOMPtr
<nsIAtom
> mRefVariable
;
391 nsCOMPtr
<nsIAtom
> mMemberVariable
;
394 * The match map contains nsTemplateMatch objects, one for each unique
395 * match found, keyed by the resource for that match. A particular match
396 * will contain a linked list of all of the matches for that unique result
397 * id. Only one is active at a time. When a match is retracted, look in
398 * the match map, remove it, and apply the next valid match in sequence to
401 nsDataHashtable
<nsISupportsHashKey
, nsTemplateMatch
*> mMatchMap
;
404 * Fixed size allocator used to allocate matches
406 nsFixedSizeAllocator mPool
;
410 nsFixedSizeAllocator
& GetPool() { return mPool
; }
414 static nsrefcnt gRefCnt
;
415 static nsIRDFService
* gRDFService
;
416 static nsIRDFContainerUtils
* gRDFContainerUtils
;
417 static nsIScriptSecurityManager
* gScriptSecurityManager
;
418 static nsIPrincipal
* gSystemPrincipal
;
419 static nsIObserverService
* gObserverService
;
422 eDontTestEmpty
= (1 << 0),
423 eDontRecurse
= (2 << 0)
429 * Stack-based helper class to maintain a list of ``activated''
430 * resources; i.e., resources for which we are currently building
433 class ActivationEntry
{
435 nsIRDFResource
*mResource
;
436 ActivationEntry
*mPrevious
;
437 ActivationEntry
**mLink
;
439 ActivationEntry(nsIRDFResource
*aResource
, ActivationEntry
**aLink
)
440 : mResource(aResource
),
442 mLink(aLink
) { *mLink
= this; }
444 ~ActivationEntry() { *mLink
= mPrevious
; }
448 * The top of the stack of resources that we're currently building
451 ActivationEntry
*mTop
;
454 * Determine if a resource is currently on the activation stack.
457 IsActivated(nsIRDFResource
*aResource
);
460 * Returns true if content may be generated for a result, or false if it
461 * cannot, for example, if it would be created inside a closed container.
462 * Those results will be generated when the container is opened.
463 * If false is returned, no content should be generated. Possible
464 * insertion locations may optionally be set for new content, depending on
465 * the builder being used. Note that *aLocations or some items within
466 * aLocations may be null.
469 GetInsertionLocations(nsIXULTemplateResult
* aResult
,
470 nsCOMArray
<nsIContent
>** aLocations
) = 0;
473 * Must be implemented by subclasses. Handle removing the generated
474 * output for aOldMatch and adding new output for aNewMatch. Either
475 * aOldMatch or aNewMatch may be null. aContext is the location returned
476 * from the call to MayGenerateResult.
479 ReplaceMatch(nsIXULTemplateResult
* aOldResult
,
480 nsTemplateMatch
* aNewMatch
,
481 nsTemplateRule
* aNewMatchRule
,
485 * Must be implemented by subclasses. Handle change in bound
486 * variable values for aResult. aModifiedVars contains the set
487 * of variables that have changed.
488 * @param aResult the ersult for which variable bindings has changed.
489 * @param aModifiedVars the set of variables for which the bindings
493 SynchronizeResult(nsIXULTemplateResult
* aResult
) = 0;
495 virtual void Traverse(nsCycleCollectionTraversalCallback
&cb
) const
500 * Document that we're observing. Weak ref!
502 nsIDocument
* mObservedDocument
;
505 #endif // nsXULTemplateBuilder_h__