LCOV - code coverage report
Current view: directory - content/xul/templates/src - nsXULTemplateQueryProcessorRDF.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 898 2 0.2 %
Date: 2012-06-02 Functions: 51 2 3.9 %

       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
       4                 :  *
       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/
       9                 :  *
      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
      13                 :  * License.
      14                 :  *
      15                 :  * The Original Code is Mozilla Communicator client code.
      16                 :  *
      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.
      21                 :  *
      22                 :  * Contributor(s):
      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                 :  *   Joe Hewitt <hewitt@netscape.com>
      28                 :  *   Neil Deakin <enndeakin@sympatico.ca>
      29                 :  *   Laurent Jouanneau <laurent.jouanneau@disruptive-innovations.com>
      30                 :  *
      31                 :  * Alternatively, the contents of this file may be used under the terms of
      32                 :  * either of the GNU General Public License Version 2 or later (the "GPL"),
      33                 :  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      34                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      35                 :  * of those above. If you wish to allow use of your version of this file only
      36                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      37                 :  * use your version of this file under the terms of the MPL, indicate your
      38                 :  * decision by deleting the provisions above and replace them with the notice
      39                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      40                 :  * the provisions above, a recipient may use your version of this file under
      41                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      42                 :  *
      43                 :  * ***** END LICENSE BLOCK ***** */
      44                 : 
      45                 : #include "nsCOMPtr.h"
      46                 : #include "nsIDOMNode.h"
      47                 : #include "nsIRDFNode.h"
      48                 : #include "nsIRDFObserver.h"
      49                 : #include "nsIRDFRemoteDataSource.h"
      50                 : #include "nsIRDFInferDataSource.h"
      51                 : #include "nsIRDFService.h"
      52                 : #include "nsRDFCID.h"
      53                 : #include "nsIServiceManager.h"
      54                 : #include "nsINameSpaceManager.h"
      55                 : #include "nsGkAtoms.h"
      56                 : #include "nsIDocument.h"
      57                 : #include "nsIXULDocument.h"
      58                 : #include "nsAttrName.h"
      59                 : #include "rdf.h"
      60                 : #include "nsArrayUtils.h"
      61                 : 
      62                 : #include "nsContentTestNode.h"
      63                 : #include "nsRDFConInstanceTestNode.h"
      64                 : #include "nsRDFConMemberTestNode.h"
      65                 : #include "nsRDFPropertyTestNode.h"
      66                 : #include "nsInstantiationNode.h"
      67                 : #include "nsRDFTestNode.h"
      68                 : #include "nsXULContentUtils.h"
      69                 : #include "nsXULTemplateBuilder.h"
      70                 : #include "nsXULTemplateResultRDF.h"
      71                 : #include "nsXULTemplateResultSetRDF.h"
      72                 : #include "nsXULTemplateQueryProcessorRDF.h"
      73                 : #include "nsXULSortService.h"
      74                 : 
      75                 : //----------------------------------------------------------------------
      76                 : 
      77                 : static NS_DEFINE_CID(kRDFContainerUtilsCID,      NS_RDFCONTAINERUTILS_CID);
      78                 : static NS_DEFINE_CID(kRDFServiceCID,             NS_RDFSERVICE_CID);
      79                 : 
      80                 : #define PARSE_TYPE_INTEGER  "Integer"
      81                 : 
      82                 : nsrefcnt                  nsXULTemplateQueryProcessorRDF::gRefCnt = 0;
      83                 : nsIRDFService*            nsXULTemplateQueryProcessorRDF::gRDFService;
      84                 : nsIRDFContainerUtils*     nsXULTemplateQueryProcessorRDF::gRDFContainerUtils;
      85                 : nsIRDFResource*           nsXULTemplateQueryProcessorRDF::kNC_BookmarkSeparator;
      86                 : nsIRDFResource*           nsXULTemplateQueryProcessorRDF::kRDF_type;
      87                 : 
      88            1464 : NS_IMPL_CYCLE_COLLECTION_CLASS(nsXULTemplateQueryProcessorRDF)
      89               0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsXULTemplateQueryProcessorRDF)
      90               0 :     tmp->Done();
      91               0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_END
      92                 : 
      93                 : static PLDHashOperator
      94               0 : BindingDependenciesTraverser(nsISupports* key,
      95                 :                              nsCOMArray<nsXULTemplateResultRDF>* array,
      96                 :                              void* userArg)
      97                 : {
      98                 :     nsCycleCollectionTraversalCallback *cb = 
      99               0 :         static_cast<nsCycleCollectionTraversalCallback*>(userArg);
     100                 : 
     101               0 :     PRInt32 i, count = array->Count();
     102               0 :     for (i = 0; i < count; ++i) {
     103               0 :         cb->NoteXPCOMChild(array->ObjectAt(i));
     104                 :     }
     105                 : 
     106               0 :     return PL_DHASH_NEXT;
     107                 : }
     108                 : 
     109                 : static PLDHashOperator
     110               0 : MemoryElementTraverser(const PRUint32& key,
     111                 :                        nsCOMArray<nsXULTemplateResultRDF>* array,
     112                 :                        void* userArg)
     113                 : {
     114                 :     nsCycleCollectionTraversalCallback *cb = 
     115               0 :         static_cast<nsCycleCollectionTraversalCallback*>(userArg);
     116                 : 
     117               0 :     PRInt32 i, count = array->Count();
     118               0 :     for (i = 0; i < count; ++i) {
     119               0 :         cb->NoteXPCOMChild(array->ObjectAt(i));
     120                 :     }
     121                 : 
     122               0 :     return PL_DHASH_NEXT;
     123                 : }
     124                 : 
     125                 : static PLDHashOperator
     126               0 : RuleToBindingTraverser(nsISupports* key, RDFBindingSet* binding, void* userArg)
     127                 : {
     128                 :     nsCycleCollectionTraversalCallback *cb = 
     129               0 :         static_cast<nsCycleCollectionTraversalCallback*>(userArg);
     130                 : 
     131               0 :     cb->NoteXPCOMChild(key);
     132                 : 
     133               0 :     return PL_DHASH_NEXT;
     134                 : }
     135                 : 
     136               0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsXULTemplateQueryProcessorRDF)
     137               0 :     NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mDB)
     138               0 :     NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mLastRef)
     139               0 :     if (tmp->mBindingDependencies.IsInitialized()) {
     140                 :         tmp->mBindingDependencies.EnumerateRead(BindingDependenciesTraverser,
     141               0 :                                                 &cb);
     142                 :     }
     143               0 :     if (tmp->mMemoryElementToResultMap.IsInitialized()) {
     144                 :         tmp->mMemoryElementToResultMap.EnumerateRead(MemoryElementTraverser,
     145               0 :                                                      &cb);
     146                 :     }
     147               0 :     if (tmp->mRuleToBindingsMap.IsInitialized()) {
     148               0 :         tmp->mRuleToBindingsMap.EnumerateRead(RuleToBindingTraverser, &cb);
     149                 :     }
     150               0 :     NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMARRAY(mQueries)
     151               0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
     152                 : 
     153               0 : NS_IMPL_CYCLE_COLLECTING_ADDREF(nsXULTemplateQueryProcessorRDF)
     154               0 : NS_IMPL_CYCLE_COLLECTING_RELEASE(nsXULTemplateQueryProcessorRDF)
     155               0 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsXULTemplateQueryProcessorRDF)
     156               0 :     NS_INTERFACE_MAP_ENTRY(nsIXULTemplateQueryProcessor)
     157               0 :     NS_INTERFACE_MAP_ENTRY(nsIRDFObserver)
     158               0 :     NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIXULTemplateQueryProcessor)
     159               0 : NS_INTERFACE_MAP_END
     160                 : 
     161               0 : nsXULTemplateQueryProcessorRDF::nsXULTemplateQueryProcessorRDF(void)
     162                 :     : mDB(nsnull),
     163                 :       mBuilder(nsnull),
     164                 :       mQueryProcessorRDFInited(false),
     165                 :       mGenerationStarted(false),
     166                 :       mUpdateBatchNest(0),
     167               0 :       mSimpleRuleMemberTest(nsnull)
     168                 : {
     169               0 :     gRefCnt++;
     170               0 : }
     171                 : 
     172               0 : nsXULTemplateQueryProcessorRDF::~nsXULTemplateQueryProcessorRDF(void)
     173                 : {
     174               0 :     if (--gRefCnt == 0) {
     175               0 :         NS_IF_RELEASE(gRDFService);
     176               0 :         NS_IF_RELEASE(gRDFContainerUtils);
     177               0 :         NS_IF_RELEASE(kNC_BookmarkSeparator);
     178               0 :         NS_IF_RELEASE(kRDF_type);
     179                 :     }
     180               0 : }
     181                 : 
     182                 : nsresult
     183               0 : nsXULTemplateQueryProcessorRDF::InitGlobals()
     184                 : {
     185                 :     nsresult rv;
     186                 : 
     187                 :     // Initialize the global shared reference to the service
     188                 :     // manager and get some shared resource objects.
     189               0 :     if (!gRDFService) {
     190               0 :         rv = CallGetService(kRDFServiceCID, &gRDFService);
     191               0 :         if (NS_FAILED(rv))
     192               0 :             return rv;
     193                 :     }
     194                 : 
     195               0 :     if (!gRDFContainerUtils) {
     196               0 :         rv = CallGetService(kRDFContainerUtilsCID, &gRDFContainerUtils);
     197               0 :         if (NS_FAILED(rv))
     198               0 :             return rv;
     199                 :     }
     200                 :   
     201               0 :     if (!kNC_BookmarkSeparator) {
     202                 :         gRDFService->GetResource(
     203               0 :           NS_LITERAL_CSTRING(NC_NAMESPACE_URI "BookmarkSeparator"),
     204               0 :                              &kNC_BookmarkSeparator);
     205                 :     }
     206                 : 
     207               0 :     if (!kRDF_type) {
     208                 :         gRDFService->GetResource(
     209               0 :           NS_LITERAL_CSTRING(RDF_NAMESPACE_URI "type"),
     210               0 :                              &kRDF_type);
     211                 :     }
     212                 : 
     213               0 :     return MemoryElement::Init() ? NS_OK : NS_ERROR_FAILURE;
     214                 : }
     215                 : 
     216                 : //----------------------------------------------------------------------
     217                 : //
     218                 : // nsIXULTemplateQueryProcessor interface
     219                 : //
     220                 : 
     221                 : NS_IMETHODIMP
     222               0 : nsXULTemplateQueryProcessorRDF::GetDatasource(nsIArray* aDataSources,
     223                 :                                               nsIDOMNode* aRootNode,
     224                 :                                               bool aIsTrusted,
     225                 :                                               nsIXULTemplateBuilder* aBuilder,
     226                 :                                               bool* aShouldDelayBuilding,
     227                 :                                               nsISupports** aResult)
     228                 : {
     229               0 :     nsCOMPtr<nsIRDFCompositeDataSource> compDB;
     230               0 :     nsCOMPtr<nsIContent> root = do_QueryInterface(aRootNode);
     231                 :     nsresult rv;
     232                 : 
     233               0 :     *aResult = nsnull;
     234               0 :     *aShouldDelayBuilding = false;
     235                 : 
     236               0 :     NS_ENSURE_TRUE(root, NS_ERROR_UNEXPECTED);
     237                 : 
     238                 :     // make sure the RDF service is set up
     239               0 :     rv = InitGlobals();
     240               0 :     NS_ENSURE_SUCCESS(rv, rv);
     241                 : 
     242                 :     // create a database for the builder
     243                 :     compDB = do_CreateInstance(NS_RDF_DATASOURCE_CONTRACTID_PREFIX 
     244               0 :                                "composite-datasource");
     245               0 :     if (!compDB) {
     246               0 :         NS_ERROR("unable to construct new composite data source");
     247               0 :         return NS_ERROR_UNEXPECTED;
     248                 :     }
     249                 : 
     250                 :     // check for magical attributes. XXX move to ``flags''?
     251               0 :     if (root->AttrValueIs(kNameSpaceID_None,
     252                 :                           nsGkAtoms::coalesceduplicatearcs,
     253               0 :                           nsGkAtoms::_false, eCaseMatters))
     254               0 :         compDB->SetCoalesceDuplicateArcs(false);
     255                 : 
     256               0 :     if (root->AttrValueIs(kNameSpaceID_None,
     257                 :                           nsGkAtoms::allownegativeassertions,
     258               0 :                           nsGkAtoms::_false, eCaseMatters))
     259               0 :         compDB->SetAllowNegativeAssertions(false);
     260                 : 
     261               0 :     if (aIsTrusted) {
     262                 :         // If we're a privileged (e.g., chrome) document, then add the
     263                 :         // local store as the first data source in the db. Note that
     264                 :         // we _might_ not be able to get a local store if we haven't
     265                 :         // got a profile to read from yet.
     266               0 :         nsCOMPtr<nsIRDFDataSource> localstore;
     267                 :         rv = gRDFService->GetDataSource("rdf:local-store",
     268               0 :                                         getter_AddRefs(localstore));
     269               0 :         NS_ENSURE_SUCCESS(rv, rv);
     270                 : 
     271               0 :         rv = compDB->AddDataSource(localstore);
     272               0 :         NS_ASSERTION(NS_SUCCEEDED(rv), "unable to add local store to db");
     273               0 :         NS_ENSURE_SUCCESS(rv, rv);
     274                 :     }
     275                 : 
     276                 :     PRUint32 length, index;
     277               0 :     rv = aDataSources->GetLength(&length);
     278               0 :     NS_ENSURE_SUCCESS(rv,rv);
     279                 : 
     280               0 :     for (index = 0; index < length; index++) {
     281                 : 
     282               0 :         nsCOMPtr<nsIURI> uri = do_QueryElementAt(aDataSources, index);
     283               0 :         if (!uri) // we ignore other datasources than uri
     284               0 :             continue;
     285                 : 
     286               0 :         nsCOMPtr<nsIRDFDataSource> ds;
     287               0 :         nsCAutoString uristrC;
     288               0 :         uri->GetSpec(uristrC);
     289                 : 
     290               0 :         rv = gRDFService->GetDataSource(uristrC.get(), getter_AddRefs(ds));
     291                 : 
     292               0 :         if (NS_FAILED(rv)) {
     293                 :             // This is only a warning because the data source may not
     294                 :             // be accessible for any number of reasons, including
     295                 :             // security, a bad URL, etc.
     296                 :   #ifdef DEBUG
     297               0 :             nsCAutoString msg;
     298               0 :             msg.Append("unable to load datasource '");
     299               0 :             msg.Append(uristrC);
     300               0 :             msg.Append('\'');
     301               0 :             NS_WARNING(msg.get());
     302                 :   #endif
     303               0 :             continue;
     304                 :         }
     305                 : 
     306               0 :         compDB->AddDataSource(ds);
     307                 :     }
     308                 : 
     309                 : 
     310                 :     // check if we were given an inference engine type
     311               0 :     nsAutoString infer;
     312               0 :     nsCOMPtr<nsIRDFDataSource> db;
     313               0 :     root->GetAttr(kNameSpaceID_None, nsGkAtoms::infer, infer);
     314               0 :     if (!infer.IsEmpty()) {
     315               0 :         nsCString inferCID(NS_RDF_INFER_DATASOURCE_CONTRACTID_PREFIX);
     316               0 :         AppendUTF16toUTF8(infer, inferCID);
     317                 :         nsCOMPtr<nsIRDFInferDataSource> inferDB =
     318               0 :             do_CreateInstance(inferCID.get());
     319                 : 
     320               0 :         if (inferDB) {
     321               0 :             inferDB->SetBaseDataSource(compDB);
     322               0 :             db = do_QueryInterface(inferDB);
     323                 :         }
     324                 :         else {
     325               0 :             NS_WARNING("failed to construct inference engine specified on template");
     326                 :         }
     327                 :     }
     328                 : 
     329               0 :     if (!db)
     330               0 :         db = compDB;
     331                 : 
     332               0 :     return CallQueryInterface(db, aResult);
     333                 : }
     334                 : 
     335                 : NS_IMETHODIMP
     336               0 : nsXULTemplateQueryProcessorRDF::InitializeForBuilding(nsISupports* aDatasource,
     337                 :                                                       nsIXULTemplateBuilder* aBuilder,
     338                 :                                                       nsIDOMNode* aRootNode)
     339                 : {
     340               0 :     if (!mQueryProcessorRDFInited) {
     341               0 :         nsresult rv = InitGlobals();
     342               0 :         if (NS_FAILED(rv))
     343               0 :             return rv;
     344                 : 
     345               0 :         if (!mMemoryElementToResultMap.IsInitialized() &&
     346               0 :             !mMemoryElementToResultMap.Init())
     347               0 :             return NS_ERROR_OUT_OF_MEMORY;
     348               0 :         if (!mBindingDependencies.IsInitialized() &&
     349               0 :             !mBindingDependencies.Init())
     350               0 :             return NS_ERROR_OUT_OF_MEMORY;
     351               0 :         if (!mRuleToBindingsMap.IsInitialized() &&
     352               0 :             !mRuleToBindingsMap.Init())
     353               0 :             return NS_ERROR_OUT_OF_MEMORY;
     354                 : 
     355               0 :         mQueryProcessorRDFInited = true;
     356                 :     }
     357                 : 
     358                 :     // don't do anything if generation has already been done
     359               0 :     if (mGenerationStarted)
     360               0 :         return NS_ERROR_UNEXPECTED;
     361                 : 
     362               0 :     mDB = do_QueryInterface(aDatasource);
     363               0 :     mBuilder = aBuilder;
     364                 : 
     365               0 :     ComputeContainmentProperties(aRootNode);
     366                 : 
     367                 :     // Add ourselves as a datasource observer
     368               0 :     if (mDB)
     369               0 :         mDB->AddObserver(this);
     370                 : 
     371               0 :     return NS_OK;
     372                 : }
     373                 : 
     374                 : NS_IMETHODIMP
     375               0 : nsXULTemplateQueryProcessorRDF::Done()
     376                 : {
     377               0 :     if (!mQueryProcessorRDFInited)
     378               0 :         return NS_OK;
     379                 : 
     380               0 :     if (mDB)
     381               0 :         mDB->RemoveObserver(this);
     382                 : 
     383               0 :     mDB = nsnull;
     384               0 :     mBuilder = nsnull;
     385               0 :     mRefVariable = nsnull;
     386               0 :     mLastRef = nsnull;
     387                 : 
     388               0 :     mGenerationStarted = false;
     389               0 :     mUpdateBatchNest = 0;
     390                 : 
     391               0 :     mContainmentProperties.Clear();
     392                 : 
     393               0 :     for (ReteNodeSet::Iterator node = mAllTests.First();
     394               0 :          node != mAllTests.Last(); ++node)
     395               0 :         delete *node;
     396                 : 
     397               0 :     mAllTests.Clear();
     398               0 :     mRDFTests.Clear();
     399               0 :     mQueries.Clear();
     400                 : 
     401               0 :     mSimpleRuleMemberTest = nsnull;
     402                 : 
     403               0 :     mBindingDependencies.Clear();
     404                 : 
     405               0 :     mMemoryElementToResultMap.Clear();
     406                 : 
     407               0 :     mRuleToBindingsMap.Clear();
     408                 : 
     409               0 :     return NS_OK;
     410                 : }
     411                 : 
     412                 : NS_IMETHODIMP
     413               0 : nsXULTemplateQueryProcessorRDF::CompileQuery(nsIXULTemplateBuilder* aBuilder,
     414                 :                                              nsIDOMNode* aQueryNode,
     415                 :                                              nsIAtom* aRefVariable,
     416                 :                                              nsIAtom* aMemberVariable,
     417                 :                                              nsISupports** _retval)
     418                 : {
     419               0 :     nsRefPtr<nsRDFQuery> query = new nsRDFQuery(this);
     420               0 :     if (!query)
     421               0 :         return NS_ERROR_OUT_OF_MEMORY;
     422                 : 
     423               0 :     query->mRefVariable = aRefVariable;
     424               0 :     if (!mRefVariable)
     425               0 :       mRefVariable = aRefVariable;
     426                 : 
     427               0 :     if (!aMemberVariable)
     428               0 :         query->mMemberVariable = do_GetAtom("?");
     429                 :     else
     430               0 :         query->mMemberVariable = aMemberVariable;
     431                 : 
     432                 :     nsresult rv;
     433               0 :     TestNode *lastnode = nsnull;
     434                 : 
     435               0 :     nsCOMPtr<nsIContent> content = do_QueryInterface(aQueryNode);
     436                 : 
     437               0 :     if (content->NodeInfo()->Equals(nsGkAtoms::_template, kNameSpaceID_XUL)) {
     438                 :         // simplified syntax with no rules
     439                 : 
     440               0 :         query->SetSimple();
     441               0 :         NS_ASSERTION(!mSimpleRuleMemberTest,
     442                 :                      "CompileQuery called twice with the same template");
     443               0 :         if (!mSimpleRuleMemberTest)
     444               0 :             rv = CompileSimpleQuery(query, content, &lastnode);
     445                 :         else
     446               0 :             rv = NS_ERROR_FAILURE;
     447                 :     }
     448               0 :     else if (content->NodeInfo()->Equals(nsGkAtoms::rule, kNameSpaceID_XUL)) {
     449                 :         // simplified syntax with at least one rule
     450               0 :         query->SetSimple();
     451               0 :         rv = CompileSimpleQuery(query, content, &lastnode);
     452                 :     }
     453                 :     else {
     454               0 :         rv = CompileExtendedQuery(query, content, &lastnode);
     455                 :     }
     456                 : 
     457               0 :     if (NS_FAILED(rv))
     458               0 :         return rv;
     459                 : 
     460               0 :     query->SetQueryNode(aQueryNode);
     461                 : 
     462               0 :     nsInstantiationNode* instnode = new nsInstantiationNode(this, query);
     463               0 :     if (!instnode)
     464               0 :         return NS_ERROR_OUT_OF_MEMORY;
     465                 : 
     466                 :     // this and other functions always add nodes to mAllTests first. That
     467                 :     // way if something fails, the node will just sit harmlessly in mAllTests
     468                 :     // where it can be deleted later. 
     469               0 :     rv = mAllTests.Add(instnode);
     470               0 :     if (NS_FAILED(rv)) {
     471               0 :         delete instnode;
     472               0 :         return rv;
     473                 :     }
     474                 : 
     475               0 :     rv = lastnode->AddChild(instnode);
     476               0 :     if (NS_FAILED(rv))
     477               0 :         return rv;
     478                 : 
     479               0 :     rv = mQueries.AppendObject(query);
     480               0 :     if (NS_FAILED(rv))
     481               0 :         return rv;
     482                 : 
     483               0 :     *_retval = query;
     484               0 :     NS_ADDREF(*_retval);
     485                 : 
     486               0 :     return NS_OK;
     487                 : }
     488                 : 
     489                 : NS_IMETHODIMP
     490               0 : nsXULTemplateQueryProcessorRDF::GenerateResults(nsISupports* aDatasource,
     491                 :                                                 nsIXULTemplateResult* aRef,
     492                 :                                                 nsISupports* aQuery,
     493                 :                                                 nsISimpleEnumerator** aResults)
     494                 : {
     495               0 :     nsCOMPtr<nsITemplateRDFQuery> rdfquery = do_QueryInterface(aQuery);
     496               0 :     if (! rdfquery)
     497               0 :         return NS_ERROR_INVALID_ARG;
     498                 : 
     499               0 :     mGenerationStarted = true;
     500                 : 
     501                 :     // should be safe to cast here since the query is a
     502                 :     // non-scriptable nsITemplateRDFQuery
     503               0 :     nsRDFQuery* query = static_cast<nsRDFQuery *>(aQuery);
     504                 : 
     505               0 :     *aResults = nsnull;
     506                 : 
     507               0 :     nsCOMPtr<nsISimpleEnumerator> results;
     508                 : 
     509               0 :     if (aRef) {
     510                 :         // make sure that cached results were generated for this ref, and if not,
     511                 :         // regenerate them. Otherwise, things will go wrong for templates bound to
     512                 :         // an HTML element as they are not generated lazily.
     513               0 :         if (aRef == mLastRef) {
     514               0 :             query->UseCachedResults(getter_AddRefs(results));
     515                 :         }
     516                 :         else {
     517                 :             // clear the cached results
     518               0 :             PRInt32 count = mQueries.Count();
     519               0 :             for (PRInt32 r = 0; r < count; r++) {
     520               0 :                 mQueries[r]->ClearCachedResults();
     521                 :             }
     522                 :         }
     523                 : 
     524               0 :         if (! results) {
     525               0 :             if (! query->mRefVariable)
     526               0 :                 query->mRefVariable = do_GetAtom("?uri");
     527                 : 
     528               0 :             nsCOMPtr<nsIRDFResource> refResource;
     529               0 :             aRef->GetResource(getter_AddRefs(refResource));
     530               0 :             if (! refResource)
     531               0 :                 return NS_ERROR_FAILURE;
     532                 : 
     533                 :             // Propagate the assignments through the network
     534               0 :             TestNode* root = query->GetRoot();
     535                 : 
     536               0 :             if (query->IsSimple() && mSimpleRuleMemberTest) {
     537                 :                 // get the top node in the simple rule tree
     538               0 :                 root = mSimpleRuleMemberTest->GetParent();
     539               0 :                 mLastRef = aRef;
     540                 :             }
     541                 : 
     542                 : #ifdef PR_LOGGING
     543               0 :             if (PR_LOG_TEST(gXULTemplateLog, PR_LOG_DEBUG)) {
     544               0 :                 nsAutoString id;
     545               0 :                 aRef->GetId(id);
     546                 : 
     547               0 :                 nsAutoString rvar;
     548               0 :                 query->mRefVariable->ToString(rvar);
     549               0 :                 nsAutoString mvar;
     550               0 :                 query->mMemberVariable->ToString(mvar);
     551                 : 
     552               0 :                 PR_LOG(gXULTemplateLog, PR_LOG_ALWAYS,
     553                 :                        ("QueryProcessor::GenerateResults using ref %s and vars [ ref: %s  member: %s]",
     554                 :                        NS_ConvertUTF16toUTF8(id).get(),
     555                 :                        NS_ConvertUTF16toUTF8(rvar).get(),
     556                 :                        NS_ConvertUTF16toUTF8(mvar).get()));
     557                 :             }
     558                 : #endif
     559                 : 
     560               0 :             if (root) {
     561                 :                 // the seed is the initial instantiation, which has a single
     562                 :                 // assignment holding the reference point
     563               0 :                 Instantiation seed;
     564               0 :                 seed.AddAssignment(query->mRefVariable, refResource);
     565                 : 
     566               0 :                 InstantiationSet* instantiations = new InstantiationSet();
     567               0 :                 if (!instantiations)
     568               0 :                     return NS_ERROR_OUT_OF_MEMORY;
     569               0 :                 instantiations->Append(seed);
     570                 : 
     571                 :                 // if the propagation caused a match, then the results will be
     572                 :                 // cached in the query, retrieved below by calling
     573                 :                 // UseCachedResults. The matching result set owns the
     574                 :                 // instantiations and will delete them when results have been
     575                 :                 // iterated over. If the propagation did not match, the
     576                 :                 // instantiations need to be deleted.
     577               0 :                 bool owned = false;
     578               0 :                 nsresult rv = root->Propagate(*instantiations, false, owned);
     579               0 :                 if (! owned)
     580               0 :                     delete instantiations;
     581               0 :                 if (NS_FAILED(rv))
     582               0 :                     return rv;
     583                 : 
     584               0 :                 query->UseCachedResults(getter_AddRefs(results));
     585                 :             }
     586                 :         }
     587                 :     }
     588                 : 
     589               0 :     if (! results) {
     590                 :         // no results were found so create an empty set
     591               0 :         results = new nsXULTemplateResultSetRDF(this, query, nsnull);
     592               0 :         if (! results)
     593               0 :             return NS_ERROR_OUT_OF_MEMORY;
     594                 :     }
     595                 : 
     596               0 :     results.swap(*aResults);
     597                 : 
     598               0 :     return NS_OK;
     599                 : }
     600                 : 
     601                 : NS_IMETHODIMP
     602               0 : nsXULTemplateQueryProcessorRDF::AddBinding(nsIDOMNode* aRuleNode,
     603                 :                                            nsIAtom* aVar,
     604                 :                                            nsIAtom* aRef,
     605                 :                                            const nsAString& aExpr)
     606                 : {
     607                 :     // add a <binding> to a rule. When a result is matched, the bindings are
     608                 :     // examined to add additional variable assignments
     609                 : 
     610                 :     // bindings can't be added once result generation has started, otherwise
     611                 :     // the array sizes will get out of sync
     612               0 :     if (mGenerationStarted)
     613               0 :         return NS_ERROR_UNEXPECTED;
     614                 : 
     615               0 :     nsCOMPtr<nsIRDFResource> property;
     616               0 :     nsresult rv = gRDFService->GetUnicodeResource(aExpr, getter_AddRefs(property));
     617               0 :     if (NS_FAILED(rv))
     618               0 :         return rv;
     619                 : 
     620               0 :     nsRefPtr<RDFBindingSet> bindings = mRuleToBindingsMap.GetWeak(aRuleNode);
     621               0 :     if (!bindings) {
     622               0 :         bindings = new RDFBindingSet();
     623               0 :         if (!bindings || !mRuleToBindingsMap.Put(aRuleNode, bindings))
     624               0 :             return NS_ERROR_OUT_OF_MEMORY;
     625                 :     }
     626                 : 
     627               0 :     return bindings->AddBinding(aVar, aRef, property);
     628                 : }
     629                 : 
     630                 : NS_IMETHODIMP
     631               0 : nsXULTemplateQueryProcessorRDF::TranslateRef(nsISupports* aDatasource,
     632                 :                                                            const nsAString& aRefString,
     633                 :                                                            nsIXULTemplateResult** aRef)
     634                 : {
     635                 :     // make sure the RDF service is set up
     636               0 :     nsresult rv = InitGlobals();
     637               0 :     if (NS_FAILED(rv))
     638               0 :         return rv;
     639                 : 
     640               0 :     nsCOMPtr<nsIRDFResource> uri;
     641               0 :     gRDFService->GetUnicodeResource(aRefString, getter_AddRefs(uri));
     642                 : 
     643               0 :     nsXULTemplateResultRDF* refresult = new nsXULTemplateResultRDF(uri);
     644               0 :     if (! refresult)
     645               0 :         return NS_ERROR_OUT_OF_MEMORY;
     646                 : 
     647               0 :     *aRef = refresult;
     648               0 :     NS_ADDREF(*aRef);
     649                 : 
     650               0 :     return NS_OK;
     651                 : }
     652                 : 
     653                 : NS_IMETHODIMP
     654               0 : nsXULTemplateQueryProcessorRDF::CompareResults(nsIXULTemplateResult* aLeft,
     655                 :                                                nsIXULTemplateResult* aRight,
     656                 :                                                nsIAtom* aVar,
     657                 :                                                PRUint32 aSortHints,
     658                 :                                                PRInt32* aResult)
     659                 : {
     660               0 :     NS_ENSURE_ARG_POINTER(aLeft);
     661               0 :     NS_ENSURE_ARG_POINTER(aRight);
     662                 : 
     663               0 :     *aResult = 0;
     664                 : 
     665                 :     // for natural order sorting, use the index in the RDF container for the
     666                 :     // order. If there is no container, just sort them arbitrarily.
     667               0 :     if (!aVar) {
     668                 :         // if a result has a negative index, just sort it first
     669               0 :         PRInt32 leftindex = GetContainerIndexOf(aLeft);
     670               0 :         PRInt32 rightindex = GetContainerIndexOf(aRight);
     671                 :         *aResult = leftindex == rightindex ? 0 :
     672                 :                    leftindex > rightindex ? 1 :
     673               0 :                    -1;
     674               0 :         return NS_OK;
     675                 :     }
     676                 : 
     677               0 :     nsDependentAtomString sortkey(aVar);
     678                 : 
     679               0 :     nsCOMPtr<nsISupports> leftNode, rightNode;
     680                 : 
     681               0 :     if (!sortkey.IsEmpty() && sortkey[0] != '?' &&
     682               0 :         !StringBeginsWith(sortkey, NS_LITERAL_STRING("rdf:")) &&
     683               0 :         mDB) {
     684                 :         // if the sort key is not a template variable, it should be an RDF
     685                 :         // predicate. Get the targets and compare those instead.
     686               0 :         nsCOMPtr<nsIRDFResource> predicate;
     687               0 :         nsresult rv = gRDFService->GetUnicodeResource(sortkey, getter_AddRefs(predicate));
     688               0 :         NS_ENSURE_SUCCESS(rv, rv);
     689                 : 
     690                 :         // create a predicate with '?sort=true' appended. This special
     691                 :         // predicate may be used to have a different sort value than the
     692                 :         // displayed value
     693               0 :         sortkey.AppendLiteral("?sort=true");
     694                 : 
     695               0 :         nsCOMPtr<nsIRDFResource> sortPredicate;
     696               0 :         rv = gRDFService->GetUnicodeResource(sortkey, getter_AddRefs(sortPredicate));
     697               0 :         NS_ENSURE_SUCCESS(rv, rv);
     698                 : 
     699               0 :         rv = GetSortValue(aLeft, predicate, sortPredicate, getter_AddRefs(leftNode));
     700               0 :         NS_ENSURE_SUCCESS(rv, rv);
     701                 : 
     702               0 :         rv = GetSortValue(aRight, predicate, sortPredicate, getter_AddRefs(rightNode));
     703               0 :         NS_ENSURE_SUCCESS(rv, rv);
     704                 :     }
     705                 :     else {
     706                 :         // get the values for the sort key from the results
     707               0 :         aLeft->GetBindingObjectFor(aVar, getter_AddRefs(leftNode));
     708               0 :         aRight->GetBindingObjectFor(aVar, getter_AddRefs(rightNode));
     709                 :     }
     710                 : 
     711                 :     {
     712                 :         // Literals?
     713               0 :         nsCOMPtr<nsIRDFLiteral> l = do_QueryInterface(leftNode);
     714               0 :         if (l) {
     715               0 :             nsCOMPtr<nsIRDFLiteral> r = do_QueryInterface(rightNode);
     716               0 :             if (r) {
     717                 :                 const PRUnichar *lstr, *rstr;
     718               0 :                 l->GetValueConst(&lstr);
     719               0 :                 r->GetValueConst(&rstr);
     720                 : 
     721                 :                 *aResult = XULSortServiceImpl::CompareValues(
     722               0 :                                nsDependentString(lstr),
     723               0 :                                nsDependentString(rstr), aSortHints);
     724                 :             }
     725                 : 
     726               0 :             return NS_OK;
     727                 :         }
     728                 :     }
     729                 : 
     730                 :     {
     731                 :         // Dates?
     732               0 :         nsCOMPtr<nsIRDFDate> l = do_QueryInterface(leftNode);
     733               0 :         if (l) {
     734               0 :             nsCOMPtr<nsIRDFDate> r = do_QueryInterface(rightNode);
     735               0 :             if (r) {
     736                 :                 PRTime ldate, rdate;
     737               0 :                 l->GetValue(&ldate);
     738               0 :                 r->GetValue(&rdate);
     739                 : 
     740                 :                 PRInt64 delta;
     741               0 :                 LL_SUB(delta, ldate, rdate);
     742                 : 
     743               0 :                 if (LL_IS_ZERO(delta))
     744               0 :                     *aResult = 0;
     745               0 :                 else if (LL_GE_ZERO(delta))
     746               0 :                     *aResult = 1;
     747                 :                 else
     748               0 :                     *aResult = -1;
     749                 :             }
     750                 : 
     751               0 :             return NS_OK;
     752                 :         }
     753                 :     }
     754                 : 
     755                 :     {
     756                 :         // Integers?
     757               0 :         nsCOMPtr<nsIRDFInt> l = do_QueryInterface(leftNode);
     758               0 :         if (l) {
     759               0 :             nsCOMPtr<nsIRDFInt> r = do_QueryInterface(rightNode);
     760               0 :             if (r) {
     761                 :                 PRInt32 lval, rval;
     762               0 :                 l->GetValue(&lval);
     763               0 :                 r->GetValue(&rval);
     764                 : 
     765               0 :                 *aResult = lval - rval;
     766                 :             }
     767                 : 
     768               0 :             return NS_OK;
     769                 :         }
     770                 :     }
     771                 : 
     772               0 :     nsICollation* collation = nsXULContentUtils::GetCollation();
     773               0 :     if (collation) {
     774                 :         // Blobs? (We can only compare these reasonably if we have a
     775                 :         // collation object.)
     776               0 :         nsCOMPtr<nsIRDFBlob> l = do_QueryInterface(leftNode);
     777               0 :         if (l) {
     778               0 :             nsCOMPtr<nsIRDFBlob> r = do_QueryInterface(rightNode);
     779               0 :             if (r) {
     780                 :                 const PRUint8 *lval, *rval;
     781                 :                 PRInt32 llen, rlen;
     782               0 :                 l->GetValue(&lval);
     783               0 :                 l->GetLength(&llen);
     784               0 :                 r->GetValue(&rval);
     785               0 :                 r->GetLength(&rlen);
     786                 :                 
     787               0 :                 collation->CompareRawSortKey(lval, llen, rval, rlen, aResult);
     788                 :             }
     789                 :         }
     790                 :     }
     791                 : 
     792                 :     // if the results are none of the above, just pretend that they are equal
     793               0 :     return NS_OK;
     794                 : }
     795                 : 
     796                 : //----------------------------------------------------------------------
     797                 : //
     798                 : // nsIRDFObserver interface
     799                 : //
     800                 : 
     801                 : 
     802                 : NS_IMETHODIMP
     803               0 : nsXULTemplateQueryProcessorRDF::OnAssert(nsIRDFDataSource* aDataSource,
     804                 :                                          nsIRDFResource* aSource,
     805                 :                                          nsIRDFResource* aProperty,
     806                 :                                          nsIRDFNode* aTarget)
     807                 : {
     808                 :     // Ignore updates if we're batching
     809               0 :     if (mUpdateBatchNest)
     810               0 :         return(NS_OK);
     811                 : 
     812               0 :     if (! mBuilder)
     813               0 :         return NS_OK;
     814                 : 
     815               0 :     LOG("onassert", aSource, aProperty, aTarget);
     816                 : 
     817               0 :     Propagate(aSource, aProperty, aTarget);
     818               0 :     SynchronizeAll(aSource, aProperty, nsnull, aTarget);
     819               0 :     return NS_OK;
     820                 : }
     821                 : 
     822                 : 
     823                 : 
     824                 : NS_IMETHODIMP
     825               0 : nsXULTemplateQueryProcessorRDF::OnUnassert(nsIRDFDataSource* aDataSource,
     826                 :                                            nsIRDFResource* aSource,
     827                 :                                            nsIRDFResource* aProperty,
     828                 :                                            nsIRDFNode* aTarget)
     829                 : {
     830                 :     // Ignore updates if we're batching
     831               0 :     if (mUpdateBatchNest)
     832               0 :         return NS_OK;
     833                 : 
     834               0 :     if (! mBuilder)
     835               0 :         return NS_OK;
     836                 : 
     837               0 :     LOG("onunassert", aSource, aProperty, aTarget);
     838                 : 
     839               0 :     Retract(aSource, aProperty, aTarget);
     840               0 :     SynchronizeAll(aSource, aProperty, aTarget, nsnull);
     841               0 :     return NS_OK;
     842                 : }
     843                 : 
     844                 : 
     845                 : NS_IMETHODIMP
     846               0 : nsXULTemplateQueryProcessorRDF::OnChange(nsIRDFDataSource* aDataSource,
     847                 :                                          nsIRDFResource* aSource,
     848                 :                                          nsIRDFResource* aProperty,
     849                 :                                          nsIRDFNode* aOldTarget,
     850                 :                                          nsIRDFNode* aNewTarget)
     851                 : {
     852                 :     // Ignore updates if we're batching
     853               0 :     if (mUpdateBatchNest)
     854               0 :         return NS_OK;
     855                 : 
     856               0 :     if (! mBuilder)
     857               0 :         return NS_OK;
     858                 : 
     859               0 :     LOG("onchange", aSource, aProperty, aNewTarget);
     860                 : 
     861               0 :     if (aOldTarget) {
     862                 :         // Pull any old results that were relying on aOldTarget
     863               0 :         Retract(aSource, aProperty, aOldTarget);
     864                 :     }
     865                 : 
     866               0 :     if (aNewTarget) {
     867                 :         // Fire any new results that are activated by aNewTarget
     868               0 :         Propagate(aSource, aProperty, aNewTarget);
     869                 :     }
     870                 : 
     871                 :     // Synchronize any of the content model that may have changed.
     872               0 :     SynchronizeAll(aSource, aProperty, aOldTarget, aNewTarget);
     873               0 :     return NS_OK;
     874                 : }
     875                 : 
     876                 : 
     877                 : NS_IMETHODIMP
     878               0 : nsXULTemplateQueryProcessorRDF::OnMove(nsIRDFDataSource* aDataSource,
     879                 :                                        nsIRDFResource* aOldSource,
     880                 :                                        nsIRDFResource* aNewSource,
     881                 :                                        nsIRDFResource* aProperty,
     882                 :                                        nsIRDFNode* aTarget)
     883                 : {
     884                 :     // Ignore updates if we're batching
     885               0 :     if (mUpdateBatchNest)
     886               0 :         return NS_OK;
     887                 : 
     888               0 :     NS_NOTYETIMPLEMENTED("write me");
     889               0 :     return NS_ERROR_NOT_IMPLEMENTED;
     890                 : }
     891                 : 
     892                 : 
     893                 : NS_IMETHODIMP
     894               0 : nsXULTemplateQueryProcessorRDF::OnBeginUpdateBatch(nsIRDFDataSource* aDataSource)
     895                 : {
     896               0 :     mUpdateBatchNest++;
     897               0 :     return NS_OK;
     898                 : }
     899                 : 
     900                 : 
     901                 : NS_IMETHODIMP
     902               0 : nsXULTemplateQueryProcessorRDF::OnEndUpdateBatch(nsIRDFDataSource* aDataSource)
     903                 : {
     904               0 :     NS_ASSERTION(mUpdateBatchNest > 0, "badly nested update batch");
     905               0 :     if (--mUpdateBatchNest <= 0) {
     906               0 :         mUpdateBatchNest = 0;
     907                 : 
     908               0 :         if (mBuilder)
     909               0 :             mBuilder->Rebuild();
     910                 :     }
     911                 : 
     912               0 :     return NS_OK;
     913                 : }
     914                 : 
     915                 : nsresult
     916               0 : nsXULTemplateQueryProcessorRDF::Propagate(nsIRDFResource* aSource,
     917                 :                                           nsIRDFResource* aProperty,
     918                 :                                           nsIRDFNode* aTarget)
     919                 : {
     920                 :     // When a new assertion is added to the graph, determine any new matches
     921                 :     // that must be added to the template builder. First, iterate through all
     922                 :     // the RDF tests (<member> and <triple> tests), and find the topmost test
     923                 :     // that would be affected by the new assertion.
     924                 :     nsresult rv;
     925                 : 
     926               0 :     ReteNodeSet livenodes;
     927                 : 
     928                 : #ifdef PR_LOGGING
     929               0 :     if (PR_LOG_TEST(gXULTemplateLog, PR_LOG_DEBUG)) {
     930                 :         const char* sourceStr;
     931               0 :         aSource->GetValueConst(&sourceStr);
     932                 :         const char* propertyStr;
     933               0 :         aProperty->GetValueConst(&propertyStr);
     934               0 :         nsAutoString targetStr;
     935               0 :         nsXULContentUtils::GetTextForNode(aTarget, targetStr);
     936                 : 
     937               0 :         PR_LOG(gXULTemplateLog, PR_LOG_ALWAYS,
     938                 :                ("nsXULTemplateQueryProcessorRDF::Propagate: [%s] -> [%s] -> [%s]\n",
     939                 :                sourceStr, propertyStr, NS_ConvertUTF16toUTF8(targetStr).get()));
     940                 :     }
     941                 : #endif
     942                 : 
     943                 :     {
     944               0 :         ReteNodeSet::Iterator last = mRDFTests.Last();
     945               0 :         for (ReteNodeSet::Iterator i = mRDFTests.First(); i != last; ++i) {
     946               0 :             nsRDFTestNode* rdftestnode = static_cast<nsRDFTestNode*>(*i);
     947                 : 
     948               0 :             Instantiation seed;
     949               0 :             if (rdftestnode->CanPropagate(aSource, aProperty, aTarget, seed)) {
     950               0 :                 rv = livenodes.Add(rdftestnode);
     951               0 :                 if (NS_FAILED(rv))
     952               0 :                     return rv;
     953                 :             }
     954                 :         }
     955                 :     }
     956                 : 
     957                 :     // Now, we'll go through each, and any that aren't dominated by
     958                 :     // another live node will be used to propagate the assertion
     959                 :     // through the rule network
     960                 :     {
     961               0 :         ReteNodeSet::Iterator last = livenodes.Last();
     962               0 :         for (ReteNodeSet::Iterator i = livenodes.First(); i != last; ++i) {
     963               0 :             nsRDFTestNode* rdftestnode = static_cast<nsRDFTestNode*>(*i);
     964                 : 
     965                 :             // What happens here is we create an instantiation as if we were
     966                 :             // at the found test in the rule network. For example, if the
     967                 :             // found test was a member test (parent => child), the parent
     968                 :             // and child variables are assigned the values provided by the new
     969                 :             // RDF assertion in the graph. The Constrain call is used to go
     970                 :             // up to earlier RDF tests, filling in variables as it goes.
     971                 :             // Constrain will eventually get up to the top node, an
     972                 :             // nsContentTestNode, which takes the value of the reference
     973                 :             // variable and calls the template builder to see if a result has
     974                 :             // been generated already for the reference value. If it hasn't,
     975                 :             // the new assertion couldn't cause a new match. If the result
     976                 :             // exists, call Propagate to continue to the later RDF tests to
     977                 :             // fill in the rest of the variable assignments.
     978                 : 
     979                 :             // Bogus, to get the seed instantiation
     980               0 :             Instantiation seed;
     981               0 :             rdftestnode->CanPropagate(aSource, aProperty, aTarget, seed);
     982                 : 
     983               0 :             InstantiationSet* instantiations = new InstantiationSet();
     984               0 :             if (!instantiations)
     985               0 :                 return NS_ERROR_OUT_OF_MEMORY;
     986               0 :             instantiations->Append(seed);
     987                 : 
     988               0 :             rv = rdftestnode->Constrain(*instantiations);
     989               0 :             if (NS_FAILED(rv)) {
     990               0 :                 delete instantiations;
     991               0 :                 return rv;
     992                 :             }
     993                 : 
     994               0 :             bool owned = false;
     995               0 :             if (!instantiations->Empty())
     996               0 :                 rv = rdftestnode->Propagate(*instantiations, true, owned);
     997                 : 
     998                 :             // owned should always be false in update mode, but check just
     999                 :             // to be sure
    1000               0 :             if (!owned)
    1001               0 :                 delete instantiations;
    1002               0 :             if (NS_FAILED(rv))
    1003               0 :                 return rv;
    1004                 :         }
    1005                 :     }
    1006                 : 
    1007               0 :     return NS_OK;
    1008                 : }
    1009                 : 
    1010                 : 
    1011                 : nsresult
    1012               0 : nsXULTemplateQueryProcessorRDF::Retract(nsIRDFResource* aSource,
    1013                 :                                         nsIRDFResource* aProperty,
    1014                 :                                         nsIRDFNode* aTarget)
    1015                 : {
    1016                 : 
    1017                 : #ifdef PR_LOGGING
    1018               0 :     if (PR_LOG_TEST(gXULTemplateLog, PR_LOG_DEBUG)) {
    1019                 :         const char* sourceStr;
    1020               0 :         aSource->GetValueConst(&sourceStr);
    1021                 :         const char* propertyStr;
    1022               0 :         aProperty->GetValueConst(&propertyStr);
    1023               0 :         nsAutoString targetStr;
    1024               0 :         nsXULContentUtils::GetTextForNode(aTarget, targetStr);
    1025                 : 
    1026               0 :         PR_LOG(gXULTemplateLog, PR_LOG_ALWAYS,
    1027                 :                ("nsXULTemplateQueryProcessorRDF::Retract: [%s] -> [%s] -> [%s]\n",
    1028                 :                sourceStr, propertyStr, NS_ConvertUTF16toUTF8(targetStr).get()));
    1029                 :     }
    1030                 : #endif
    1031                 : 
    1032                 :     // Retract any currently active rules that will no longer be matched.
    1033               0 :     ReteNodeSet::ConstIterator lastnode = mRDFTests.Last();
    1034               0 :     for (ReteNodeSet::ConstIterator node = mRDFTests.First(); node != lastnode; ++node) {
    1035               0 :         const nsRDFTestNode* rdftestnode = static_cast<const nsRDFTestNode*>(*node);
    1036                 : 
    1037               0 :         rdftestnode->Retract(aSource, aProperty, aTarget);
    1038                 : 
    1039                 :         // Now fire any newly revealed rules
    1040                 :         // XXXwaterson yo. write me.
    1041                 :         // The intent here is to handle any rules that might be
    1042                 :         // "revealed" by the removal of an assertion from the datasource.
    1043                 :         // Waterson doesn't think we support negated conditions in a rule.
    1044                 :         // Nor is he sure that this is currently useful.
    1045                 :     }
    1046                 : 
    1047               0 :     return NS_OK;
    1048                 : }
    1049                 : 
    1050                 : nsresult
    1051               0 : nsXULTemplateQueryProcessorRDF::SynchronizeAll(nsIRDFResource* aSource,
    1052                 :                                                nsIRDFResource* aProperty,
    1053                 :                                                nsIRDFNode* aOldTarget,
    1054                 :                                                nsIRDFNode* aNewTarget)
    1055                 : {
    1056                 :     // Update each match that contains <aSource, aProperty, aOldTarget>.
    1057                 : 
    1058                 :     // Get all the matches whose assignments are currently supported
    1059                 :     // by aSource and aProperty: we'll need to recompute them.
    1060                 :     nsCOMArray<nsXULTemplateResultRDF>* results;
    1061               0 :     if (!mBindingDependencies.Get(aSource, &results) || !mBuilder)
    1062               0 :         return NS_OK;
    1063                 : 
    1064               0 :     PRUint32 length = results->Count();
    1065                 : 
    1066               0 :     for (PRUint32 r = 0; r < length; r++) {
    1067               0 :         nsXULTemplateResultRDF* result = (*results)[r];
    1068               0 :         if (result) {
    1069                 :             // synchronize the result's bindings and then update the builder
    1070                 :             // so that content can be updated
    1071               0 :             if (result->SyncAssignments(aSource, aProperty, aNewTarget)) {
    1072               0 :                 nsITemplateRDFQuery* query = result->Query();
    1073               0 :                 if (query) {
    1074               0 :                     nsCOMPtr<nsIDOMNode> querynode;
    1075               0 :                     query->GetQueryNode(getter_AddRefs(querynode));
    1076                 : 
    1077               0 :                     mBuilder->ResultBindingChanged(result);
    1078                 :                 }
    1079                 :             }
    1080                 :         }
    1081                 :     }
    1082                 : 
    1083               0 :     return NS_OK;
    1084                 : }
    1085                 : 
    1086                 : #ifdef PR_LOGGING
    1087                 : nsresult
    1088               0 : nsXULTemplateQueryProcessorRDF::Log(const char* aOperation,
    1089                 :                                     nsIRDFResource* aSource,
    1090                 :                                     nsIRDFResource* aProperty,
    1091                 :                                     nsIRDFNode* aTarget)
    1092                 : {
    1093               0 :     if (PR_LOG_TEST(gXULTemplateLog, PR_LOG_DEBUG)) {
    1094                 :         nsresult rv;
    1095                 : 
    1096                 :         const char* sourceStr;
    1097               0 :         rv = aSource->GetValueConst(&sourceStr);
    1098               0 :         if (NS_FAILED(rv))
    1099               0 :             return rv;
    1100                 : 
    1101               0 :         PR_LOG(gXULTemplateLog, PR_LOG_DEBUG,
    1102                 :                ("xultemplate[%p] %8s [%s]--", this, aOperation, sourceStr));
    1103                 : 
    1104                 :         const char* propertyStr;
    1105               0 :         rv = aProperty->GetValueConst(&propertyStr);
    1106               0 :         if (NS_FAILED(rv))
    1107               0 :             return rv;
    1108                 : 
    1109               0 :         nsAutoString targetStr;
    1110               0 :         rv = nsXULContentUtils::GetTextForNode(aTarget, targetStr);
    1111               0 :         if (NS_FAILED(rv))
    1112               0 :             return rv;
    1113                 : 
    1114               0 :         nsCAutoString targetstrC;
    1115               0 :         targetstrC.AssignWithConversion(targetStr);
    1116               0 :         PR_LOG(gXULTemplateLog, PR_LOG_DEBUG,
    1117                 :                ("                        --[%s]-->[%s]",
    1118                 :                 propertyStr,
    1119                 :                 targetstrC.get()));
    1120                 :     }
    1121               0 :     return NS_OK;
    1122                 : }
    1123                 : #endif
    1124                 : 
    1125                 : nsresult
    1126               0 : nsXULTemplateQueryProcessorRDF::CheckContainer(nsIRDFResource* aResource,
    1127                 :                                                bool* aIsContainer)
    1128                 : {
    1129               0 :     NS_ENSURE_ARG_POINTER(aIsContainer);
    1130               0 :     NS_ENSURE_STATE(mDB);
    1131                 : 
    1132                 :     // We have to look at all of the arcs extending out of the
    1133                 :     // resource: if any of them are that "containment" property, then
    1134                 :     // we know we'll have children.
    1135               0 :     bool isContainer = false;
    1136                 : 
    1137               0 :     for (nsResourceSet::ConstIterator property = mContainmentProperties.First();
    1138               0 :          property != mContainmentProperties.Last();
    1139                 :          property++) {
    1140               0 :         bool hasArc = false;
    1141               0 :         mDB->HasArcOut(aResource, *property, &hasArc);
    1142                 : 
    1143               0 :         if (hasArc) {
    1144                 :             // Well, it's a container...
    1145               0 :             isContainer = true;
    1146               0 :             break;
    1147                 :         }
    1148                 :     }
    1149                 : 
    1150                 :     // If we get here, and we're still not sure if it's a container,
    1151                 :     // then see if it's an RDF container
    1152               0 :     if (! isContainer) {
    1153               0 :         gRDFContainerUtils->IsContainer(mDB, aResource, &isContainer);
    1154                 :     }
    1155                 : 
    1156               0 :     *aIsContainer = isContainer;
    1157                 : 
    1158               0 :     return NS_OK;
    1159                 : }
    1160                 : 
    1161                 : nsresult
    1162               0 : nsXULTemplateQueryProcessorRDF::CheckEmpty(nsIRDFResource* aResource,
    1163                 :                                            bool* aIsEmpty)
    1164                 : {
    1165               0 :     NS_ENSURE_STATE(mDB);
    1166               0 :     *aIsEmpty = true;
    1167                 : 
    1168               0 :     for (nsResourceSet::ConstIterator property = mContainmentProperties.First();
    1169               0 :          property != mContainmentProperties.Last();
    1170                 :          property++) {
    1171                 : 
    1172               0 :         nsCOMPtr<nsIRDFNode> dummy;
    1173               0 :         mDB->GetTarget(aResource, *property, true, getter_AddRefs(dummy));
    1174                 : 
    1175               0 :         if (dummy) {
    1176               0 :             *aIsEmpty = false;
    1177                 :             break;
    1178                 :         }
    1179                 :     }
    1180                 : 
    1181               0 :     if (*aIsEmpty){
    1182                 :         return nsXULTemplateQueryProcessorRDF::gRDFContainerUtils->
    1183               0 :                    IsEmpty(mDB, aResource, aIsEmpty);
    1184                 :     }
    1185                 : 
    1186               0 :     return NS_OK;
    1187                 : }
    1188                 : 
    1189                 : nsresult
    1190               0 : nsXULTemplateQueryProcessorRDF::CheckIsSeparator(nsIRDFResource* aResource,
    1191                 :                                                  bool* aIsSeparator)
    1192                 : {
    1193               0 :     NS_ENSURE_STATE(mDB);
    1194               0 :     return mDB->HasAssertion(aResource, kRDF_type, kNC_BookmarkSeparator,
    1195               0 :                              true, aIsSeparator);
    1196                 : }
    1197                 : 
    1198                 : //----------------------------------------------------------------------
    1199                 : 
    1200                 : nsresult
    1201               0 : nsXULTemplateQueryProcessorRDF::ComputeContainmentProperties(nsIDOMNode* aRootNode)
    1202                 : {
    1203                 :     // The 'containment' attribute on the root node is a
    1204                 :     // whitespace-separated list that tells us which properties we
    1205                 :     // should use to test for containment.
    1206                 :     nsresult rv;
    1207                 : 
    1208               0 :     mContainmentProperties.Clear();
    1209                 : 
    1210               0 :     nsCOMPtr<nsIContent> content = do_QueryInterface(aRootNode);
    1211                 : 
    1212               0 :     nsAutoString containment;
    1213               0 :     content->GetAttr(kNameSpaceID_None, nsGkAtoms::containment, containment);
    1214                 : 
    1215               0 :     PRUint32 len = containment.Length();
    1216               0 :     PRUint32 offset = 0;
    1217               0 :     while (offset < len) {
    1218               0 :         while (offset < len && nsCRT::IsAsciiSpace(containment[offset]))
    1219               0 :             ++offset;
    1220                 : 
    1221               0 :         if (offset >= len)
    1222               0 :             break;
    1223                 : 
    1224               0 :         PRUint32 end = offset;
    1225               0 :         while (end < len && !nsCRT::IsAsciiSpace(containment[end]))
    1226               0 :             ++end;
    1227                 : 
    1228               0 :         nsAutoString propertyStr;
    1229               0 :         containment.Mid(propertyStr, offset, end - offset);
    1230                 : 
    1231               0 :         nsCOMPtr<nsIRDFResource> property;
    1232               0 :         rv = gRDFService->GetUnicodeResource(propertyStr, getter_AddRefs(property));
    1233               0 :         if (NS_FAILED(rv))
    1234               0 :             return rv;
    1235                 : 
    1236               0 :         rv = mContainmentProperties.Add(property);
    1237               0 :         if (NS_FAILED(rv))
    1238               0 :             return rv;
    1239                 : 
    1240               0 :         offset = end;
    1241                 :     }
    1242                 : 
    1243                 : #define TREE_PROPERTY_HACK 1
    1244                 : #if defined(TREE_PROPERTY_HACK)
    1245               0 :     if (! len) {
    1246                 :         // Some ever-present membership tests.
    1247               0 :         mContainmentProperties.Add(nsXULContentUtils::NC_child);
    1248               0 :         mContainmentProperties.Add(nsXULContentUtils::NC_Folder);
    1249                 :     }
    1250                 : #endif
    1251                 : 
    1252               0 :     return NS_OK;
    1253                 : }
    1254                 : 
    1255                 : nsresult
    1256               0 : nsXULTemplateQueryProcessorRDF::CompileExtendedQuery(nsRDFQuery* aQuery,
    1257                 :                                                      nsIContent* aConditions,
    1258                 :                                                      TestNode** aLastNode)
    1259                 : {
    1260                 :     // Compile an extended query's children
    1261                 : 
    1262                 :     nsContentTestNode* idnode =
    1263               0 :         new nsContentTestNode(this, aQuery->mRefVariable);
    1264               0 :     if (! idnode)
    1265               0 :         return NS_ERROR_OUT_OF_MEMORY;
    1266                 : 
    1267               0 :     aQuery->SetRoot(idnode);
    1268               0 :     nsresult rv = mAllTests.Add(idnode);
    1269               0 :     if (NS_FAILED(rv)) {
    1270               0 :         delete idnode;
    1271               0 :         return rv;
    1272                 :     }
    1273                 : 
    1274               0 :     TestNode* prevnode = idnode;
    1275                 : 
    1276               0 :     for (nsIContent* condition = aConditions->GetFirstChild();
    1277                 :          condition;
    1278               0 :          condition = condition->GetNextSibling()) {
    1279                 : 
    1280                 :         // the <content> condition should always be the first child
    1281               0 :         if (condition->Tag() == nsGkAtoms::content) {
    1282               0 :             if (condition != aConditions->GetFirstChild()) {
    1283               0 :                 nsXULContentUtils::LogTemplateError(ERROR_TEMPLATE_CONTENT_NOT_FIRST);
    1284               0 :                 continue;
    1285                 :             }
    1286                 : 
    1287                 :             // check for <content tag='tag'/> which indicates that matches
    1288                 :             // should only be generated for items inside content with that tag
    1289               0 :             nsAutoString tagstr;
    1290               0 :             condition->GetAttr(kNameSpaceID_None, nsGkAtoms::tag, tagstr);
    1291                 : 
    1292               0 :             nsCOMPtr<nsIAtom> tag;
    1293               0 :             if (! tagstr.IsEmpty()) {
    1294               0 :                 tag = do_GetAtom(tagstr);
    1295                 :             }
    1296                 : 
    1297               0 :             nsCOMPtr<nsIDOMDocument> doc = do_QueryInterface(condition->GetDocument());
    1298               0 :             if (! doc)
    1299               0 :                 return NS_ERROR_FAILURE;
    1300                 : 
    1301               0 :             idnode->SetTag(tag, doc);
    1302               0 :             continue;
    1303                 :         }
    1304                 : 
    1305               0 :         TestNode* testnode = nsnull;
    1306                 :         nsresult rv = CompileQueryChild(condition->Tag(), aQuery, condition,
    1307               0 :                                         prevnode, &testnode);
    1308               0 :         if (NS_FAILED(rv))
    1309               0 :             return rv;
    1310                 : 
    1311               0 :         if (testnode) {
    1312               0 :             rv = prevnode->AddChild(testnode);
    1313               0 :             if (NS_FAILED(rv))
    1314               0 :                 return rv;
    1315                 : 
    1316               0 :             prevnode = testnode;
    1317                 :         }
    1318                 :     }
    1319                 : 
    1320               0 :     *aLastNode = prevnode;
    1321                 : 
    1322               0 :     return NS_OK;
    1323                 : }
    1324                 : 
    1325                 : nsresult
    1326               0 : nsXULTemplateQueryProcessorRDF::CompileQueryChild(nsIAtom* aTag,
    1327                 :                                                   nsRDFQuery* aQuery,
    1328                 :                                                   nsIContent* aCondition,
    1329                 :                                                   TestNode* aParentNode,
    1330                 :                                                   TestNode** aResult)
    1331                 : {
    1332                 :     nsresult rv;
    1333                 : 
    1334               0 :     if (aTag == nsGkAtoms::triple) {
    1335               0 :         rv = CompileTripleCondition(aQuery, aCondition, aParentNode, aResult);
    1336                 :     }
    1337               0 :     else if (aTag == nsGkAtoms::member) {
    1338               0 :         rv = CompileMemberCondition(aQuery, aCondition, aParentNode, aResult);
    1339                 :     }
    1340                 :     else {
    1341                 : #ifdef PR_LOGGING
    1342               0 :         nsAutoString tagstr;
    1343               0 :         aTag->ToString(tagstr);
    1344                 : 
    1345               0 :         nsCAutoString tagstrC;
    1346               0 :         tagstrC.AssignWithConversion(tagstr);
    1347               0 :         PR_LOG(gXULTemplateLog, PR_LOG_ALWAYS,
    1348                 :                ("xultemplate[%p] unrecognized condition test <%s>",
    1349                 :                 this, tagstrC.get()));
    1350                 : #endif
    1351                 : 
    1352               0 :         rv = NS_OK;
    1353                 :     }
    1354                 : 
    1355               0 :     return rv;
    1356                 : }
    1357                 : 
    1358                 : nsresult
    1359               0 : nsXULTemplateQueryProcessorRDF::ParseLiteral(const nsString& aParseType, 
    1360                 :                                              const nsString& aValue,
    1361                 :                                              nsIRDFNode** aResult)
    1362                 : {
    1363               0 :     nsresult rv = NS_OK;
    1364               0 :     *aResult = nsnull;
    1365                 : 
    1366               0 :     if (aParseType.EqualsLiteral(PARSE_TYPE_INTEGER)) {
    1367               0 :         nsCOMPtr<nsIRDFInt> intLiteral;
    1368                 :         PRInt32 errorCode;
    1369               0 :         PRInt32 intValue = aValue.ToInteger(&errorCode);
    1370               0 :         if (NS_FAILED(errorCode))
    1371               0 :             return NS_ERROR_FAILURE;
    1372               0 :         rv = gRDFService->GetIntLiteral(intValue, getter_AddRefs(intLiteral));
    1373               0 :         if (NS_FAILED(rv)) 
    1374               0 :             return rv;
    1375               0 :         rv = CallQueryInterface(intLiteral, aResult);
    1376                 :     }
    1377                 :     else {
    1378               0 :         nsCOMPtr<nsIRDFLiteral> literal;
    1379               0 :         rv = gRDFService->GetLiteral(aValue.get(), getter_AddRefs(literal));
    1380               0 :         if (NS_FAILED(rv)) 
    1381               0 :             return rv;
    1382               0 :         rv = CallQueryInterface(literal, aResult);
    1383                 :     }
    1384               0 :     return rv;
    1385                 : }
    1386                 : 
    1387                 : nsresult
    1388               0 : nsXULTemplateQueryProcessorRDF::CompileTripleCondition(nsRDFQuery* aQuery,
    1389                 :                                                        nsIContent* aCondition,
    1390                 :                                                        TestNode* aParentNode,
    1391                 :                                                        TestNode** aResult)
    1392                 : {
    1393                 :     // Compile a <triple> condition, which must be of the form:
    1394                 :     //
    1395                 :     //   <triple subject="?var1|resource"
    1396                 :     //           predicate="resource"
    1397                 :     //           object="?var2|resource|literal" />
    1398                 :     //
    1399                 :     // XXXwaterson Some day it would be cool to allow the 'predicate'
    1400                 :     // to be bound to a variable.
    1401                 : 
    1402                 :     // subject
    1403               0 :     nsAutoString subject;
    1404               0 :     aCondition->GetAttr(kNameSpaceID_None, nsGkAtoms::subject, subject);
    1405                 : 
    1406               0 :     nsCOMPtr<nsIAtom> svar;
    1407               0 :     nsCOMPtr<nsIRDFResource> sres;
    1408               0 :     if (subject.IsEmpty()) {
    1409               0 :         nsXULContentUtils::LogTemplateError(ERROR_TEMPLATE_TRIPLE_BAD_SUBJECT);
    1410               0 :         return NS_OK;
    1411                 :     }
    1412               0 :     if (subject[0] == PRUnichar('?'))
    1413               0 :         svar = do_GetAtom(subject);
    1414                 :     else
    1415               0 :         gRDFService->GetUnicodeResource(subject, getter_AddRefs(sres));
    1416                 : 
    1417                 :     // predicate
    1418               0 :     nsAutoString predicate;
    1419               0 :     aCondition->GetAttr(kNameSpaceID_None, nsGkAtoms::predicate, predicate);
    1420                 : 
    1421               0 :     nsCOMPtr<nsIRDFResource> pres;
    1422               0 :     if (predicate.IsEmpty() || predicate[0] == PRUnichar('?')) {
    1423               0 :         nsXULContentUtils::LogTemplateError(ERROR_TEMPLATE_TRIPLE_BAD_PREDICATE);
    1424               0 :         return NS_OK;
    1425                 :     }
    1426               0 :     gRDFService->GetUnicodeResource(predicate, getter_AddRefs(pres));
    1427                 : 
    1428                 :     // object
    1429               0 :     nsAutoString object;
    1430               0 :     aCondition->GetAttr(kNameSpaceID_None, nsGkAtoms::object, object);
    1431                 : 
    1432               0 :     nsCOMPtr<nsIAtom> ovar;
    1433               0 :     nsCOMPtr<nsIRDFNode> onode;
    1434               0 :     if (object.IsEmpty()) {
    1435               0 :         nsXULContentUtils::LogTemplateError(ERROR_TEMPLATE_TRIPLE_BAD_OBJECT);
    1436               0 :         return NS_OK;
    1437                 :     }
    1438                 : 
    1439               0 :     if (object[0] == PRUnichar('?')) {
    1440               0 :         ovar = do_GetAtom(object);
    1441                 :     }
    1442               0 :     else if (object.FindChar(':') != -1) { // XXXwaterson evil.
    1443                 :         // treat as resource
    1444               0 :         nsCOMPtr<nsIRDFResource> resource;
    1445               0 :         gRDFService->GetUnicodeResource(object, getter_AddRefs(resource));
    1446               0 :         onode = do_QueryInterface(resource);
    1447                 :     }
    1448                 :     else {
    1449               0 :         nsAutoString parseType;
    1450               0 :         aCondition->GetAttr(kNameSpaceID_None, nsGkAtoms::parsetype, parseType);
    1451               0 :         nsresult rv = ParseLiteral(parseType, object, getter_AddRefs(onode));
    1452               0 :         if (NS_FAILED(rv))
    1453               0 :             return rv;
    1454                 :     }
    1455                 : 
    1456               0 :     nsRDFPropertyTestNode* testnode = nsnull;
    1457                 : 
    1458               0 :     if (svar && ovar) {
    1459               0 :         testnode = new nsRDFPropertyTestNode(aParentNode, this, svar, pres, ovar);
    1460                 :     }
    1461               0 :     else if (svar) {
    1462               0 :         testnode = new nsRDFPropertyTestNode(aParentNode, this, svar, pres, onode);
    1463                 :     }
    1464               0 :     else if (ovar) {
    1465               0 :         testnode = new nsRDFPropertyTestNode(aParentNode, this, sres, pres, ovar);
    1466                 :     }
    1467                 :     else {
    1468               0 :         nsXULContentUtils::LogTemplateError(ERROR_TEMPLATE_TRIPLE_NO_VAR);
    1469               0 :         return NS_OK;
    1470                 :     }
    1471                 : 
    1472               0 :     if (! testnode)
    1473               0 :         return NS_ERROR_OUT_OF_MEMORY;
    1474                 : 
    1475                 :     // add testnode to mAllTests first. If adding to mRDFTests fails, just
    1476                 :     // leave it in the list so that it can be deleted later.
    1477               0 :     nsresult rv = mAllTests.Add(testnode);
    1478               0 :     if (NS_FAILED(rv)) {
    1479               0 :         delete testnode;
    1480               0 :         return rv;
    1481                 :     }
    1482                 : 
    1483               0 :     rv = mRDFTests.Add(testnode);
    1484               0 :     if (NS_FAILED(rv))
    1485               0 :         return rv;
    1486                 : 
    1487               0 :     *aResult = testnode;
    1488               0 :     return NS_OK;
    1489                 : }
    1490                 : 
    1491                 : nsresult
    1492               0 : nsXULTemplateQueryProcessorRDF::CompileMemberCondition(nsRDFQuery* aQuery,
    1493                 :                                                        nsIContent* aCondition,
    1494                 :                                                        TestNode* aParentNode,
    1495                 :                                                        TestNode** aResult)
    1496                 : {
    1497                 :     // Compile a <member> condition, which must be of the form:
    1498                 :     //
    1499                 :     //   <member container="?var1" child="?var2" />
    1500                 :     //
    1501                 : 
    1502                 :     // container
    1503               0 :     nsAutoString container;
    1504               0 :     aCondition->GetAttr(kNameSpaceID_None, nsGkAtoms::container, container);
    1505                 : 
    1506               0 :     if (!container.IsEmpty() && container[0] != PRUnichar('?')) {
    1507               0 :         nsXULContentUtils::LogTemplateError(ERROR_TEMPLATE_MEMBER_NOCONTAINERVAR);
    1508               0 :         return NS_OK;
    1509                 :     }
    1510                 : 
    1511               0 :     nsCOMPtr<nsIAtom> containervar = do_GetAtom(container);
    1512                 : 
    1513                 :     // child
    1514               0 :     nsAutoString child;
    1515               0 :     aCondition->GetAttr(kNameSpaceID_None, nsGkAtoms::child, child);
    1516                 : 
    1517               0 :     if (!child.IsEmpty() && child[0] != PRUnichar('?')) {
    1518               0 :         nsXULContentUtils::LogTemplateError(ERROR_TEMPLATE_MEMBER_NOCHILDVAR);
    1519               0 :         return NS_OK;
    1520                 :     }
    1521                 : 
    1522               0 :     nsCOMPtr<nsIAtom> childvar = do_GetAtom(child);
    1523                 : 
    1524                 :     TestNode* testnode =
    1525                 :         new nsRDFConMemberTestNode(aParentNode,
    1526                 :                                    this,
    1527                 :                                    containervar,
    1528               0 :                                    childvar);
    1529                 : 
    1530               0 :     if (! testnode)
    1531               0 :         return NS_ERROR_OUT_OF_MEMORY;
    1532                 : 
    1533                 :     // add testnode to mAllTests first. If adding to mRDFTests fails, just
    1534                 :     // leave it in the list so that it can be deleted later.
    1535               0 :     nsresult rv = mAllTests.Add(testnode);
    1536               0 :     if (NS_FAILED(rv)) {
    1537               0 :         delete testnode;
    1538               0 :         return rv;
    1539                 :     }
    1540                 : 
    1541               0 :     rv = mRDFTests.Add(testnode);
    1542               0 :     if (NS_FAILED(rv))
    1543               0 :         return rv;
    1544                 : 
    1545               0 :     *aResult = testnode;
    1546               0 :     return NS_OK;
    1547                 : }
    1548                 : 
    1549                 : nsresult
    1550               0 : nsXULTemplateQueryProcessorRDF::AddDefaultSimpleRules(nsRDFQuery* aQuery,
    1551                 :                                                       TestNode** aChildNode)
    1552                 : {
    1553                 :     // XXXndeakin should check for tag in query processor instead of builder?
    1554                 :     nsContentTestNode* idnode =
    1555                 :         new nsContentTestNode(this,
    1556               0 :                               aQuery->mRefVariable);
    1557               0 :     if (! idnode)
    1558               0 :         return NS_ERROR_OUT_OF_MEMORY;
    1559                 : 
    1560                 :     // Create (?container ^member ?member)
    1561                 :     nsRDFConMemberTestNode* membernode =
    1562                 :         new nsRDFConMemberTestNode(idnode,
    1563                 :                                    this,
    1564                 :                                    aQuery->mRefVariable,
    1565               0 :                                    aQuery->mMemberVariable);
    1566                 : 
    1567               0 :     if (! membernode) {
    1568               0 :         delete idnode;
    1569               0 :         return NS_ERROR_OUT_OF_MEMORY;
    1570                 :     }
    1571                 : 
    1572                 :     // add nodes to mAllTests first. If later calls fail, just leave them in
    1573                 :     // the list so that they can be deleted later.
    1574               0 :     nsresult rv = mAllTests.Add(idnode);
    1575               0 :     if (NS_FAILED(rv)) {
    1576               0 :         delete idnode;
    1577               0 :         delete membernode;
    1578               0 :         return rv;
    1579                 :     }
    1580                 : 
    1581               0 :     rv = mAllTests.Add(membernode);
    1582               0 :     if (NS_FAILED(rv)) {
    1583               0 :         delete membernode;
    1584               0 :         return rv;
    1585                 :     }
    1586                 : 
    1587               0 :     rv = mRDFTests.Add(membernode);
    1588               0 :     if (NS_FAILED(rv))
    1589               0 :         return rv;
    1590                 : 
    1591               0 :     rv = idnode->AddChild(membernode);
    1592               0 :     if (NS_FAILED(rv))
    1593               0 :         return rv;
    1594                 : 
    1595               0 :     mSimpleRuleMemberTest = membernode;
    1596               0 :     *aChildNode = membernode;
    1597                 : 
    1598               0 :     return NS_OK;
    1599                 : }
    1600                 : 
    1601                 : nsresult
    1602               0 : nsXULTemplateQueryProcessorRDF::CompileSimpleQuery(nsRDFQuery* aQuery,
    1603                 :                                                    nsIContent* aQueryElement,
    1604                 :                                                    TestNode** aLastNode)
    1605                 : {
    1606                 :     // Compile a "simple" (or old-school style) <template> query.
    1607                 :     nsresult rv;
    1608                 : 
    1609                 :     TestNode* parentNode;
    1610                 : 
    1611               0 :     if (! mSimpleRuleMemberTest) {
    1612               0 :         rv = AddDefaultSimpleRules(aQuery, &parentNode);
    1613               0 :         if (NS_FAILED(rv))
    1614               0 :             return rv;
    1615                 :     }
    1616                 : 
    1617               0 :     bool hasContainerTest = false;
    1618                 : 
    1619               0 :     TestNode* prevnode = mSimpleRuleMemberTest;
    1620                 : 
    1621                 :     // Add constraints for the LHS
    1622                 :     const nsAttrName* name;
    1623               0 :     for (PRUint32 i = 0; (name = aQueryElement->GetAttrNameAt(i)); ++i) {
    1624                 :         // Note: some attributes must be skipped on XUL template query subtree
    1625                 : 
    1626                 :         // never compare against rdf:property, rdf:instanceOf, {}:id or {}:parsetype attribute
    1627               0 :         if (name->Equals(nsGkAtoms::property, kNameSpaceID_RDF) ||
    1628               0 :             name->Equals(nsGkAtoms::instanceOf, kNameSpaceID_RDF) ||
    1629               0 :             name->Equals(nsGkAtoms::id, kNameSpaceID_None) ||
    1630               0 :             name->Equals(nsGkAtoms::parsetype, kNameSpaceID_None)) {
    1631               0 :             continue;
    1632                 :         }
    1633                 : 
    1634               0 :         PRInt32 attrNameSpaceID = name->NamespaceID();
    1635               0 :         if (attrNameSpaceID == kNameSpaceID_XMLNS)
    1636               0 :           continue;
    1637               0 :         nsIAtom* attr = name->LocalName();
    1638                 : 
    1639               0 :         nsAutoString value;
    1640               0 :         aQueryElement->GetAttr(attrNameSpaceID, attr, value);
    1641                 : 
    1642               0 :         TestNode* testnode = nsnull;
    1643                 : 
    1644               0 :         if (name->Equals(nsGkAtoms::iscontainer, kNameSpaceID_None) ||
    1645               0 :             name->Equals(nsGkAtoms::isempty, kNameSpaceID_None)) {
    1646                 :             // Tests about containerhood and emptiness. These can be
    1647                 :             // globbed together, mostly. Check to see if we've already
    1648                 :             // added a container test: we only need one.
    1649               0 :             if (hasContainerTest)
    1650               0 :                 continue;
    1651                 : 
    1652                 :             nsRDFConInstanceTestNode::Test iscontainer =
    1653               0 :                 nsRDFConInstanceTestNode::eDontCare;
    1654                 : 
    1655                 :             static nsIContent::AttrValuesArray strings[] =
    1656                 :               {&nsGkAtoms::_true, &nsGkAtoms::_false, nsnull};
    1657               0 :             switch (aQueryElement->FindAttrValueIn(kNameSpaceID_None,
    1658                 :                                                    nsGkAtoms::iscontainer,
    1659               0 :                                                    strings, eCaseMatters)) {
    1660               0 :                 case 0: iscontainer = nsRDFConInstanceTestNode::eTrue; break;
    1661               0 :                 case 1: iscontainer = nsRDFConInstanceTestNode::eFalse; break;
    1662                 :             }
    1663                 : 
    1664                 :             nsRDFConInstanceTestNode::Test isempty =
    1665               0 :                 nsRDFConInstanceTestNode::eDontCare;
    1666                 : 
    1667               0 :             switch (aQueryElement->FindAttrValueIn(kNameSpaceID_None,
    1668                 :                                                    nsGkAtoms::isempty,
    1669               0 :                                                    strings, eCaseMatters)) {
    1670               0 :                 case 0: isempty = nsRDFConInstanceTestNode::eTrue; break;
    1671               0 :                 case 1: isempty = nsRDFConInstanceTestNode::eFalse; break;
    1672                 :             }
    1673                 : 
    1674                 :             testnode = new nsRDFConInstanceTestNode(prevnode,
    1675                 :                                                     this,
    1676                 :                                                     aQuery->mMemberVariable,
    1677                 :                                                     iscontainer,
    1678               0 :                                                     isempty);
    1679                 : 
    1680               0 :             if (! testnode)
    1681               0 :                 return NS_ERROR_OUT_OF_MEMORY;
    1682                 : 
    1683               0 :             rv = mAllTests.Add(testnode);
    1684               0 :             if (NS_FAILED(rv)) {
    1685               0 :                 delete testnode;
    1686               0 :                 return rv;
    1687                 :             }
    1688                 : 
    1689               0 :             rv = mRDFTests.Add(testnode);
    1690               0 :             if (NS_FAILED(rv))
    1691               0 :                 return rv;
    1692                 :         }
    1693               0 :         else if (attrNameSpaceID != kNameSpaceID_None || attr != nsGkAtoms::parent) {
    1694                 :             // It's a simple RDF test
    1695               0 :             nsCOMPtr<nsIRDFResource> property;
    1696               0 :             rv = nsXULContentUtils::GetResource(attrNameSpaceID, attr, getter_AddRefs(property));
    1697               0 :             if (NS_FAILED(rv))
    1698               0 :                 return rv;
    1699                 : 
    1700                 :             // XXXwaterson this is so manky
    1701               0 :             nsCOMPtr<nsIRDFNode> target;
    1702               0 :             if (value.FindChar(':') != -1) { // XXXwaterson WRONG WRONG WRONG!
    1703               0 :                 nsCOMPtr<nsIRDFResource> resource;
    1704               0 :                 rv = gRDFService->GetUnicodeResource(value, getter_AddRefs(resource));
    1705               0 :                 if (NS_FAILED(rv))
    1706               0 :                     return rv;
    1707                 : 
    1708               0 :                 target = do_QueryInterface(resource);
    1709                 :             }
    1710                 :             else {                
    1711               0 :               nsAutoString parseType;
    1712               0 :               aQueryElement->GetAttr(kNameSpaceID_None, nsGkAtoms::parsetype, parseType);
    1713               0 :               rv = ParseLiteral(parseType, value, getter_AddRefs(target));
    1714               0 :               if (NS_FAILED(rv))
    1715               0 :                   return rv;
    1716                 :             }
    1717                 : 
    1718                 :             testnode = new nsRDFPropertyTestNode(prevnode, this,
    1719               0 :                                                  aQuery->mMemberVariable, property, target);
    1720               0 :             if (! testnode)
    1721               0 :                 return NS_ERROR_OUT_OF_MEMORY;
    1722                 : 
    1723               0 :             rv = mAllTests.Add(testnode);
    1724               0 :             if (NS_FAILED(rv)) {
    1725               0 :                 delete testnode;
    1726               0 :                 return rv;
    1727                 :             }
    1728                 : 
    1729               0 :             rv = mRDFTests.Add(testnode);
    1730               0 :             if (NS_FAILED(rv))
    1731               0 :                 return rv;
    1732                 :         }
    1733                 : 
    1734               0 :         if (testnode) {
    1735               0 :             if (prevnode) {
    1736               0 :                 rv = prevnode->AddChild(testnode);
    1737               0 :                 if (NS_FAILED(rv))
    1738               0 :                     return rv;
    1739                 :             }                
    1740                 :             else {
    1741               0 :                 aQuery->SetRoot(testnode);
    1742                 :             }
    1743                 : 
    1744               0 :             prevnode = testnode;
    1745                 :         }
    1746                 :     }
    1747                 : 
    1748               0 :     *aLastNode = prevnode;
    1749                 : 
    1750               0 :     return NS_OK;
    1751                 : }
    1752                 : 
    1753                 : RDFBindingSet*
    1754               0 : nsXULTemplateQueryProcessorRDF::GetBindingsForRule(nsIDOMNode* aRuleNode)
    1755                 : {
    1756               0 :     return mRuleToBindingsMap.GetWeak(aRuleNode);
    1757                 : }
    1758                 : 
    1759                 : nsresult
    1760               0 : nsXULTemplateQueryProcessorRDF::AddBindingDependency(nsXULTemplateResultRDF* aResult,
    1761                 :                                                      nsIRDFResource* aResource)
    1762                 : {
    1763                 :     nsCOMArray<nsXULTemplateResultRDF>* arr;
    1764               0 :     if (!mBindingDependencies.Get(aResource, &arr)) {
    1765               0 :         arr = new nsCOMArray<nsXULTemplateResultRDF>();
    1766               0 :         if (!arr)
    1767               0 :             return NS_ERROR_OUT_OF_MEMORY;
    1768                 : 
    1769               0 :         if (!mBindingDependencies.Put(aResource, arr)) {
    1770               0 :             delete arr;
    1771               0 :             return NS_ERROR_OUT_OF_MEMORY;
    1772                 :         }
    1773                 :     }
    1774                 : 
    1775               0 :     PRInt32 index = arr->IndexOf(aResult);
    1776               0 :     if (index == -1)
    1777               0 :         return arr->AppendObject(aResult);
    1778                 : 
    1779               0 :     return NS_OK;
    1780                 : }
    1781                 : 
    1782                 : nsresult
    1783               0 : nsXULTemplateQueryProcessorRDF::RemoveBindingDependency(nsXULTemplateResultRDF* aResult,
    1784                 :                                                         nsIRDFResource* aResource)
    1785                 : {
    1786                 :     nsCOMArray<nsXULTemplateResultRDF>* arr;
    1787               0 :     if (mBindingDependencies.Get(aResource, &arr)) {
    1788               0 :         PRInt32 index = arr->IndexOf(aResult);
    1789               0 :         if (index >= 0)
    1790               0 :             return arr->RemoveObjectAt(index);
    1791                 :     }
    1792                 : 
    1793               0 :     return NS_OK;
    1794                 : }
    1795                 : 
    1796                 : 
    1797                 : nsresult
    1798               0 : nsXULTemplateQueryProcessorRDF::AddMemoryElements(const Instantiation& aInst,
    1799                 :                                                   nsXULTemplateResultRDF* aResult)
    1800                 : {
    1801                 :     // Add the result to a table indexed by supporting MemoryElement
    1802               0 :     MemoryElementSet::ConstIterator last = aInst.mSupport.Last();
    1803               0 :     for (MemoryElementSet::ConstIterator element = aInst.mSupport.First();
    1804                 :                                          element != last; ++element) {
    1805                 : 
    1806               0 :         PLHashNumber hash = (element.operator->())->Hash();
    1807                 : 
    1808                 :         nsCOMArray<nsXULTemplateResultRDF>* arr;
    1809               0 :         if (!mMemoryElementToResultMap.Get(hash, &arr)) {
    1810               0 :             arr = new nsCOMArray<nsXULTemplateResultRDF>();
    1811               0 :             if (!arr)
    1812               0 :                 return NS_ERROR_OUT_OF_MEMORY;
    1813                 : 
    1814               0 :             if (!mMemoryElementToResultMap.Put(hash, arr)) {
    1815               0 :                 delete arr;
    1816               0 :                 return NS_ERROR_OUT_OF_MEMORY;
    1817                 :             }
    1818                 :         }
    1819                 : 
    1820                 :         // results may be added more than once so they will all get deleted properly
    1821               0 :         arr->AppendObject(aResult);
    1822                 :     }
    1823                 : 
    1824               0 :     return NS_OK;
    1825                 : }
    1826                 : 
    1827                 : nsresult
    1828               0 : nsXULTemplateQueryProcessorRDF::RemoveMemoryElements(const Instantiation& aInst,
    1829                 :                                                      nsXULTemplateResultRDF* aResult)
    1830                 : {
    1831                 :     // Remove the results mapped by the supporting MemoryElement
    1832               0 :     MemoryElementSet::ConstIterator last = aInst.mSupport.Last();
    1833               0 :     for (MemoryElementSet::ConstIterator element = aInst.mSupport.First();
    1834                 :                                          element != last; ++element) {
    1835                 : 
    1836               0 :         PLHashNumber hash = (element.operator->())->Hash();
    1837                 : 
    1838                 :         nsCOMArray<nsXULTemplateResultRDF>* arr;
    1839               0 :         if (mMemoryElementToResultMap.Get(hash, &arr)) {
    1840               0 :             PRInt32 index = arr->IndexOf(aResult);
    1841               0 :             if (index >= 0)
    1842               0 :                 arr->RemoveObjectAt(index);
    1843                 : 
    1844               0 :             PRUint32 length = arr->Count();
    1845               0 :             if (! length)
    1846               0 :                 mMemoryElementToResultMap.Remove(hash);
    1847                 :         }
    1848                 :     }
    1849                 : 
    1850               0 :     return NS_OK;
    1851                 : }
    1852                 : 
    1853                 : void
    1854               0 : nsXULTemplateQueryProcessorRDF::RetractElement(const MemoryElement& aMemoryElement)
    1855                 : {
    1856               0 :     if (! mBuilder)
    1857               0 :         return;
    1858                 : 
    1859                 :     // when an assertion is removed, look through the memory elements and
    1860                 :     // find results that are associated with them. Those results will need
    1861                 :     // to be removed because they no longer match.
    1862               0 :     PLHashNumber hash = aMemoryElement.Hash();
    1863                 : 
    1864                 :     nsCOMArray<nsXULTemplateResultRDF>* arr;
    1865               0 :     if (mMemoryElementToResultMap.Get(hash, &arr)) {
    1866               0 :         PRUint32 length = arr->Count();
    1867                 : 
    1868               0 :         for (PRInt32 r = length - 1; r >= 0; r--) {
    1869               0 :             nsXULTemplateResultRDF* result = (*arr)[r];
    1870               0 :             if (result) {
    1871                 :                 // because the memory elements are hashed by an integer,
    1872                 :                 // sometimes two different memory elements will have the same
    1873                 :                 // hash code. In this case we check the result to make sure
    1874                 :                 // and only remove those that refer to that memory element.
    1875               0 :                 if (result->HasMemoryElement(aMemoryElement)) {
    1876               0 :                     nsITemplateRDFQuery* query = result->Query();
    1877               0 :                     if (query) {
    1878               0 :                         nsCOMPtr<nsIDOMNode> querynode;
    1879               0 :                         query->GetQueryNode(getter_AddRefs(querynode));
    1880                 : 
    1881               0 :                         mBuilder->RemoveResult(result);
    1882                 :                     }
    1883                 : 
    1884                 :                     // a call to RemoveMemoryElements may have removed it
    1885               0 :                     if (!mMemoryElementToResultMap.Get(hash, nsnull))
    1886               0 :                         return;
    1887                 : 
    1888                 :                     // the array should have been reduced by one, but check
    1889                 :                     // just to make sure
    1890               0 :                     PRUint32 newlength = arr->Count();
    1891               0 :                     if (r > (PRInt32)newlength)
    1892               0 :                         r = newlength;
    1893                 :                 }
    1894                 :             }
    1895                 :         }
    1896                 : 
    1897                 :         // if there are no items left, remove the memory element from the hashtable
    1898               0 :         if (!arr->Count())
    1899               0 :             mMemoryElementToResultMap.Remove(hash);
    1900                 :     }
    1901                 : }
    1902                 : 
    1903                 : PRInt32
    1904               0 : nsXULTemplateQueryProcessorRDF::GetContainerIndexOf(nsIXULTemplateResult* aResult)
    1905                 : {
    1906                 :     // get the reference variable and look up the container in the result
    1907               0 :     nsCOMPtr<nsISupports> ref;
    1908                 :     nsresult rv = aResult->GetBindingObjectFor(mRefVariable,
    1909               0 :                                                getter_AddRefs(ref));
    1910               0 :     if (NS_FAILED(rv) || !mDB)
    1911               0 :         return -1;
    1912                 : 
    1913               0 :     nsCOMPtr<nsIRDFResource> container = do_QueryInterface(ref);
    1914               0 :     if (container) {
    1915                 :         // if the container is an RDF Seq, return the index of the result
    1916                 :         // in the container.
    1917               0 :         bool isSequence = false;
    1918               0 :         gRDFContainerUtils->IsSeq(mDB, container, &isSequence);
    1919               0 :         if (isSequence) {
    1920               0 :             nsCOMPtr<nsIRDFResource> resource;
    1921               0 :             aResult->GetResource(getter_AddRefs(resource));
    1922               0 :             if (resource) {
    1923                 :                 PRInt32 index;
    1924               0 :                 gRDFContainerUtils->IndexOf(mDB, container, resource, &index);
    1925               0 :                 return index;
    1926                 :             }
    1927                 :         }
    1928                 :     }
    1929                 : 
    1930                 :     // if the container isn't a Seq, or the result isn't in the container,
    1931                 :     // return -1 indicating no index.
    1932               0 :     return -1;
    1933                 : }
    1934                 : 
    1935                 : nsresult
    1936               0 : nsXULTemplateQueryProcessorRDF::GetSortValue(nsIXULTemplateResult* aResult,
    1937                 :                                              nsIRDFResource* aPredicate,
    1938                 :                                              nsIRDFResource* aSortPredicate,
    1939                 :                                              nsISupports** aResultNode)
    1940                 : {
    1941               0 :     nsCOMPtr<nsIRDFResource> source;
    1942               0 :     nsresult rv = aResult->GetResource(getter_AddRefs(source));
    1943               0 :     if (NS_FAILED(rv))
    1944               0 :         return rv;
    1945                 :     
    1946               0 :     nsCOMPtr<nsIRDFNode> value;
    1947               0 :     if (source && mDB) {
    1948                 :         // first check predicate?sort=true so that datasources may use a
    1949                 :         // custom value for sorting
    1950               0 :         rv = mDB->GetTarget(source, aSortPredicate, true,
    1951               0 :                             getter_AddRefs(value));
    1952               0 :         if (NS_FAILED(rv))
    1953               0 :             return rv;
    1954                 : 
    1955               0 :         if (!value) {
    1956               0 :             rv = mDB->GetTarget(source, aPredicate, true,
    1957               0 :                                 getter_AddRefs(value));
    1958               0 :             if (NS_FAILED(rv))
    1959               0 :                 return rv;
    1960                 :         }
    1961                 :     }
    1962                 : 
    1963               0 :     *aResultNode = value;
    1964               0 :     NS_IF_ADDREF(*aResultNode);
    1965               0 :     return NS_OK;
    1966            4392 : }

Generated by: LCOV version 1.7