Back to index

lightning-sunbird  0.9+nobinonly
nsRDFConInstanceTestNode.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is Mozilla Communicator client code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *   Chris Waterson <waterson@netscape.com>
00024  *
00025  * Alternatively, the contents of this file may be used under the terms of
00026  * either of the GNU General Public License Version 2 or later (the "GPL"),
00027  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00028  * in which case the provisions of the GPL or the LGPL are applicable instead
00029  * of those above. If you wish to allow use of your version of this file only
00030  * under the terms of either the GPL or the LGPL, and not to allow others to
00031  * use your version of this file under the terms of the MPL, indicate your
00032  * decision by deleting the provisions above and replace them with the notice
00033  * and other provisions required by the GPL or the LGPL. If you do not delete
00034  * the provisions above, a recipient may use your version of this file under
00035  * the terms of any one of the MPL, the GPL or the LGPL.
00036  *
00037  * ***** END LICENSE BLOCK ***** */
00038 
00039 #include "nsConflictSet.h"
00040 #include "nsIComponentManager.h"
00041 #include "nsIRDFContainer.h"
00042 #include "nsIRDFContainerUtils.h"
00043 #include "nsIServiceManager.h"
00044 #include "nsRDFCID.h"
00045 #include "nsRDFConInstanceTestNode.h"
00046 #include "nsResourceSet.h"
00047 #include "nsString.h"
00048 
00049 #include "prlog.h"
00050 #ifdef PR_LOGGING
00051 #include "nsXULContentUtils.h"
00052 extern PRLogModuleInfo* gXULTemplateLog;
00053 
00054 static const char*
00055 TestToString(nsRDFConInstanceTestNode::Test aTest) {
00056     switch (aTest) {
00057     case nsRDFConInstanceTestNode::eFalse:    return "false";
00058     case nsRDFConInstanceTestNode::eTrue:     return "true";
00059     case nsRDFConInstanceTestNode::eDontCare: return "dontcare";
00060     }
00061     return "?";
00062 }
00063 #endif
00064 
00065 nsRDFConInstanceTestNode::nsRDFConInstanceTestNode(InnerNode* aParent,
00066                                                    nsConflictSet& aConflictSet,
00067                                                    nsIRDFDataSource* aDataSource,
00068                                                    const nsResourceSet& aMembershipProperties,
00069                                                    PRInt32 aContainerVariable,
00070                                                    Test aContainer,
00071                                                    Test aEmpty)
00072     : nsRDFTestNode(aParent),
00073       mConflictSet(aConflictSet),
00074       mDataSource(aDataSource),
00075       mMembershipProperties(aMembershipProperties),
00076       mContainerVariable(aContainerVariable),
00077       mContainer(aContainer),
00078       mEmpty(aEmpty)
00079 {
00080 #ifdef PR_LOGGING
00081     if (PR_LOG_TEST(gXULTemplateLog, PR_LOG_DEBUG)) {
00082         nsCAutoString props;
00083 
00084         nsResourceSet::ConstIterator last = aMembershipProperties.Last();
00085         nsResourceSet::ConstIterator first = aMembershipProperties.First();
00086         nsResourceSet::ConstIterator iter;
00087 
00088         for (iter = first; iter != last; ++iter) {
00089             if (iter != first)
00090                 props += " ";
00091 
00092             const char* str;
00093             iter->GetValueConst(&str);
00094 
00095             props += str;
00096         }
00097 
00098         PR_LOG(gXULTemplateLog, PR_LOG_DEBUG,
00099                ("nsRDFConInstanceTestNode[%p]: parent=%p member-props=(%s) container-var=%d container=%s empty=%s",
00100                 this,
00101                 aParent,
00102                 props.get(),
00103                 mContainerVariable,
00104                 TestToString(aContainer),
00105                 TestToString(aEmpty)));
00106     }
00107 #endif
00108 }
00109 
00110 nsresult
00111 nsRDFConInstanceTestNode::FilterInstantiations(InstantiationSet& aInstantiations, void* aClosure) const
00112 {
00113     nsresult rv;
00114 
00115     nsCOMPtr<nsIRDFContainerUtils> rdfc
00116         = do_GetService("@mozilla.org/rdf/container-utils;1");
00117 
00118     if (! rdfc)
00119         return NS_ERROR_FAILURE;
00120 
00121     InstantiationSet::Iterator last = aInstantiations.Last();
00122     for (InstantiationSet::Iterator inst = aInstantiations.First(); inst != last; ++inst) {
00123         Value value;
00124         if (! inst->mAssignments.GetAssignmentFor(mContainerVariable, &value)) {
00125             NS_ERROR("can't do unbounded container testing");
00126             return NS_ERROR_UNEXPECTED;
00127         }
00128 
00129 #ifdef PR_LOGGING
00130         if (PR_LOG_TEST(gXULTemplateLog, PR_LOG_DEBUG)) {
00131             const char* container;
00132             VALUE_TO_IRDFRESOURCE(value)->GetValueConst(&container);
00133 
00134             PR_LOG(gXULTemplateLog, PR_LOG_DEBUG,
00135                    ("nsRDFConInstanceTestNode[%p]::FilterInstantiations() container=[%s]",
00136                     this, container));
00137         }
00138 #endif
00139 
00140         nsCOMPtr<nsIRDFContainer> rdfcontainer;
00141 
00142         PRBool isRDFContainer;
00143         rv = rdfc->IsContainer(mDataSource, VALUE_TO_IRDFRESOURCE(value), &isRDFContainer);
00144         if (NS_FAILED(rv)) return rv;
00145 
00146         if (mEmpty != eDontCare || mContainer != eDontCare) {
00147             Test empty = eDontCare;
00148             Test container = eDontCare;
00149 
00150             if (isRDFContainer) {
00151                 // It's an RDF container. Use the container utilities
00152                 // to deduce what's in it.
00153                 container = eTrue;
00154 
00155                 // XXX should cache the factory
00156                 rdfcontainer = do_CreateInstance("@mozilla.org/rdf/container;1", &rv);
00157                 if (NS_FAILED(rv)) return rv;
00158 
00159                 rv = rdfcontainer->Init(mDataSource, VALUE_TO_IRDFRESOURCE(value));
00160                 if (NS_FAILED(rv)) return rv;
00161 
00162                 PRInt32 count;
00163                 rv = rdfcontainer->GetCount(&count);
00164                 if (NS_FAILED(rv)) return rv;
00165 
00166                 empty = (count == 0) ? eTrue : eFalse;
00167             } else {
00168                 empty = eTrue;
00169                 container = eFalse;
00170 
00171                 // First do the simple check of finding some outward
00172                 // arcs; mMembershipProperties should be short, so this can
00173                 // save us time from dealing with an iterator later on
00174                 for (nsResourceSet::ConstIterator property = mMembershipProperties.First();
00175                      property != mMembershipProperties.Last();
00176                      ++property) {
00177                     nsCOMPtr<nsIRDFNode> target;
00178                     rv = mDataSource->GetTarget(VALUE_TO_IRDFRESOURCE(value), *property, PR_TRUE, getter_AddRefs(target));
00179                     if (NS_FAILED(rv)) return rv;
00180 
00181                     if (target != nsnull) {
00182                         // bingo. we found one.
00183                         empty = eFalse;
00184                         container = eTrue;
00185                         break;
00186                     }
00187                 }
00188 
00189                 // if we still don't think its a container, but we
00190                 // want to know for sure whether it is or not, we need
00191                 // to check ArcLabelsOut for potential container arcs.
00192                 if (container == eFalse && mContainer != eDontCare) {
00193                     nsCOMPtr<nsISimpleEnumerator> arcsout;
00194                     rv = mDataSource->ArcLabelsOut(VALUE_TO_IRDFRESOURCE(value), getter_AddRefs(arcsout));
00195                     if (NS_FAILED(rv)) return rv;
00196 
00197                     while (1) {
00198                         PRBool hasmore;
00199                         rv = arcsout->HasMoreElements(&hasmore);
00200                         if (NS_FAILED(rv)) return rv;
00201 
00202                         if (! hasmore)
00203                             break;
00204 
00205                         nsCOMPtr<nsISupports> isupports;
00206                         rv = arcsout->GetNext(getter_AddRefs(isupports));
00207                         if (NS_FAILED(rv)) return rv;
00208 
00209                         nsCOMPtr<nsIRDFResource> property = do_QueryInterface(isupports);
00210                         NS_ASSERTION(property != nsnull, "not a property");
00211                         if (! property)
00212                             return NS_ERROR_UNEXPECTED;
00213 
00214                         if (mMembershipProperties.Contains(property)) {
00215                             container = eTrue;
00216                             break;
00217                         }
00218                     }
00219                 }
00220             }
00221 
00222             PR_LOG(gXULTemplateLog, PR_LOG_DEBUG,
00223                    ("    empty => %s",
00224                     (empty == mEmpty) ? "consistent" : "inconsistent"));
00225 
00226             PR_LOG(gXULTemplateLog, PR_LOG_DEBUG,
00227                    ("    container => %s",
00228                     (container == mContainer) ? "consistent" : "inconsistent"));
00229 
00230             if (((mEmpty == empty) && (mContainer == container)) ||
00231                 ((mEmpty == eDontCare) && (mContainer == container)) ||
00232                 ((mContainer == eDontCare) && (mEmpty == empty)))
00233             {
00234                 Element* element =
00235                     nsRDFConInstanceTestNode::Element::Create(mConflictSet.GetPool(),
00236                                                               VALUE_TO_IRDFRESOURCE(value),
00237                                                               container, empty);
00238 
00239                 if (! element)
00240                     return NS_ERROR_OUT_OF_MEMORY;
00241 
00242                 inst->AddSupportingElement(element);
00243             }
00244             else {
00245                 aInstantiations.Erase(inst--);
00246             }
00247         }
00248     }
00249 
00250     return NS_OK;
00251 }
00252 
00253 nsresult
00254 nsRDFConInstanceTestNode::GetAncestorVariables(VariableSet& aVariables) const
00255 {
00256     nsresult rv;
00257 
00258     rv = aVariables.Add(mContainerVariable);
00259     if (NS_FAILED(rv)) return rv;
00260 
00261     return TestNode::GetAncestorVariables(aVariables);
00262 }
00263 
00264 PRBool
00265 nsRDFConInstanceTestNode::CanPropagate(nsIRDFResource* aSource,
00266                                        nsIRDFResource* aProperty,
00267                                        nsIRDFNode* aTarget,
00268                                        Instantiation& aInitialBindings) const
00269 {
00270     nsresult rv;
00271 
00272     PRBool canpropagate = PR_FALSE;
00273 
00274     nsCOMPtr<nsIRDFContainerUtils> rdfc
00275         = do_GetService("@mozilla.org/rdf/container-utils;1");
00276 
00277     if (! rdfc)
00278         return NS_ERROR_FAILURE;
00279 
00280     // We can certainly propagate ordinal properties
00281     rv = rdfc->IsOrdinalProperty(aProperty, &canpropagate);
00282     if (NS_FAILED(rv)) return PR_FALSE;
00283 
00284     if (! canpropagate) {
00285         canpropagate = mMembershipProperties.Contains(aProperty);
00286     }
00287 
00288 #ifdef PR_LOGGING
00289     if (PR_LOG_TEST(gXULTemplateLog, PR_LOG_DEBUG)) {
00290         const char* source;
00291         aSource->GetValueConst(&source);
00292 
00293         const char* property;
00294         aProperty->GetValueConst(&property);
00295 
00296         nsAutoString target;
00297         nsXULContentUtils::GetTextForNode(aTarget, target);
00298 
00299         PR_LOG(gXULTemplateLog, PR_LOG_DEBUG,
00300                ("nsRDFConInstanceTestNode[%p]: CanPropagate([%s]==[%s]=>[%s]) => %s",
00301                 this, source, property, NS_ConvertUCS2toUTF8(target).get(),
00302                 canpropagate ? "true" : "false"));
00303     }
00304 #endif
00305 
00306     if (canpropagate) {
00307         aInitialBindings.AddAssignment(mContainerVariable, Value(aSource));
00308         return PR_TRUE;
00309     }
00310 
00311     return PR_FALSE;
00312 }
00313 
00314 void
00315 nsRDFConInstanceTestNode::Retract(nsIRDFResource* aSource,
00316                                   nsIRDFResource* aProperty,
00317                                   nsIRDFNode* aTarget,
00318                                   nsTemplateMatchSet& aFirings,
00319                                   nsTemplateMatchSet& aRetractions) const
00320 {
00321     // XXXwaterson oof. complicated. figure this out.
00322     if (0) {
00323         mConflictSet.Remove(Element(aSource, mContainer, mEmpty), aFirings, aRetractions);
00324     }
00325 }
00326