Back to index

lightning-sunbird  0.9+nobinonly
nsRDFPropertyTestNode.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 "nsRDFPropertyTestNode.h"
00040 #include "nsConflictSet.h"
00041 #include "nsString.h"
00042 
00043 #include "prlog.h"
00044 #ifdef PR_LOGGING
00045 extern PRLogModuleInfo* gXULTemplateLog;
00046 #include "nsIRDFLiteral.h"
00047 #include "nsXULContentUtils.h"
00048 #endif
00049 
00050 nsRDFPropertyTestNode::nsRDFPropertyTestNode(InnerNode* aParent,
00051                                              nsConflictSet& aConflictSet,
00052                                              nsIRDFDataSource* aDataSource,
00053                                              PRInt32 aSourceVariable,
00054                                              nsIRDFResource* aProperty,
00055                                              PRInt32 aTargetVariable)
00056     : nsRDFTestNode(aParent),
00057       mConflictSet(aConflictSet),
00058       mDataSource(aDataSource),
00059       mSourceVariable(aSourceVariable),
00060       mSource(nsnull),
00061       mProperty(aProperty),
00062       mTargetVariable(aTargetVariable),
00063       mTarget(nsnull)
00064 {
00065 #ifdef PR_LOGGING
00066     if (PR_LOG_TEST(gXULTemplateLog, PR_LOG_DEBUG)) {
00067         const char* prop = "(null)";
00068         if (aProperty)
00069             aProperty->GetValueConst(&prop);
00070 
00071         PR_LOG(gXULTemplateLog, PR_LOG_DEBUG,
00072                ("nsRDFPropertyTestNode[%p]: parent=%p source=%d property=%s target=%d",
00073                 this, aParent, aSourceVariable, prop, aTargetVariable));
00074     }
00075 #endif
00076 }
00077 
00078 
00079 nsRDFPropertyTestNode::nsRDFPropertyTestNode(InnerNode* aParent,
00080                                              nsConflictSet& aConflictSet,
00081                                              nsIRDFDataSource* aDataSource,
00082                                              nsIRDFResource* aSource,
00083                                              nsIRDFResource* aProperty,
00084                                              PRInt32 aTargetVariable)
00085     : nsRDFTestNode(aParent),
00086       mConflictSet(aConflictSet),
00087       mDataSource(aDataSource),
00088       mSourceVariable(0),
00089       mSource(aSource),
00090       mProperty(aProperty),
00091       mTargetVariable(aTargetVariable),
00092       mTarget(nsnull)
00093 {
00094 #ifdef PR_LOGGING
00095     if (PR_LOG_TEST(gXULTemplateLog, PR_LOG_DEBUG)) {
00096         const char* source = "(null)";
00097         if (aSource)
00098             aSource->GetValueConst(&source);
00099 
00100         const char* prop = "(null)";
00101         if (aProperty)
00102             aProperty->GetValueConst(&prop);
00103 
00104         PR_LOG(gXULTemplateLog, PR_LOG_DEBUG,
00105                ("nsRDFPropertyTestNode[%p]: parent=%p source=%s property=%s target=%d",
00106                 this, source, prop, aTargetVariable));
00107     }
00108 #endif
00109 }
00110 
00111 
00112 nsRDFPropertyTestNode::nsRDFPropertyTestNode(InnerNode* aParent,
00113                                              nsConflictSet& aConflictSet,
00114                                              nsIRDFDataSource* aDataSource,
00115                                              PRInt32 aSourceVariable,
00116                                              nsIRDFResource* aProperty,
00117                                              nsIRDFNode* aTarget)
00118     : nsRDFTestNode(aParent),
00119       mConflictSet(aConflictSet),
00120       mDataSource(aDataSource),
00121       mSourceVariable(aSourceVariable),
00122       mSource(nsnull),
00123       mProperty(aProperty),
00124       mTargetVariable(0),
00125       mTarget(aTarget)
00126 {
00127 #ifdef PR_LOGGING
00128     if (PR_LOG_TEST(gXULTemplateLog, PR_LOG_DEBUG)) {
00129         const char* prop = "(null)";
00130         if (aProperty)
00131             aProperty->GetValueConst(&prop);
00132 
00133         nsAutoString target;
00134         nsXULContentUtils::GetTextForNode(aTarget, target);
00135 
00136         PR_LOG(gXULTemplateLog, PR_LOG_DEBUG,
00137                ("nsRDFPropertyTestNode[%p]: parent=%p source=%s property=%s target=%d",
00138                 this, aSourceVariable, prop, NS_ConvertUCS2toUTF8(target).get()));
00139     }
00140 #endif
00141 }
00142 
00143 
00144 nsresult
00145 nsRDFPropertyTestNode::FilterInstantiations(InstantiationSet& aInstantiations, void* aClosure) const
00146 {
00147     nsresult rv;
00148 
00149     InstantiationSet::Iterator last = aInstantiations.Last();
00150     for (InstantiationSet::Iterator inst = aInstantiations.First(); inst != last; ++inst) {
00151         PRBool hasSourceBinding;
00152         Value sourceValue;
00153 
00154         if (mSource) {
00155             hasSourceBinding = PR_TRUE;
00156             sourceValue = mSource;
00157         }
00158         else {
00159             hasSourceBinding = inst->mAssignments.GetAssignmentFor(mSourceVariable, &sourceValue);
00160         }
00161 
00162         PRBool hasTargetBinding;
00163         Value targetValue;
00164 
00165         if (mTarget) {
00166             hasTargetBinding = PR_TRUE;
00167             targetValue = mTarget;
00168         }
00169         else {
00170             hasTargetBinding = inst->mAssignments.GetAssignmentFor(mTargetVariable, &targetValue);
00171         }
00172 
00173 #ifdef PR_LOGGING
00174         if (PR_LOG_TEST(gXULTemplateLog, PR_LOG_DEBUG)) {
00175             const char* source = "(unbound)";
00176             if (hasSourceBinding)
00177                 VALUE_TO_IRDFRESOURCE(sourceValue)->GetValueConst(&source);
00178 
00179             nsAutoString target(NS_LITERAL_STRING("(unbound)"));
00180             if (hasTargetBinding)
00181                 nsXULContentUtils::GetTextForNode(VALUE_TO_IRDFNODE(targetValue), target);
00182 
00183             PR_LOG(gXULTemplateLog, PR_LOG_DEBUG,
00184                    ("nsRDFPropertyTestNode[%p]: FilterInstantiations() source=[%s] target=[%s]",
00185                     this, source, NS_ConvertUCS2toUTF8(target).get()));
00186         }
00187 #endif
00188 
00189         if (hasSourceBinding && hasTargetBinding) {
00190             // it's a consistency check. see if we have a assignment that is consistent
00191             PRBool hasAssertion;
00192             rv = mDataSource->HasAssertion(VALUE_TO_IRDFRESOURCE(sourceValue),
00193                                            mProperty,
00194                                            VALUE_TO_IRDFNODE(targetValue),
00195                                            PR_TRUE,
00196                                            &hasAssertion);
00197             if (NS_FAILED(rv)) return rv;
00198 
00199 #ifdef PR_LOGGING
00200             PR_LOG(gXULTemplateLog, PR_LOG_DEBUG,
00201                    ("    consistency check => %s", hasAssertion ? "passed" : "failed"));
00202 #endif
00203 
00204             if (hasAssertion) {
00205                 // it's consistent.
00206                 Element* element =
00207                     nsRDFPropertyTestNode::Element::Create(mConflictSet.GetPool(),
00208                                                            VALUE_TO_IRDFRESOURCE(sourceValue),
00209                                                            mProperty,
00210                                                            VALUE_TO_IRDFNODE(targetValue));
00211 
00212                 if (! element)
00213                     return NS_ERROR_OUT_OF_MEMORY;
00214 
00215                 inst->AddSupportingElement(element);
00216             }
00217             else {
00218                 // it's inconsistent. remove it.
00219                 aInstantiations.Erase(inst--);
00220             }
00221         }
00222         else if ((hasSourceBinding && ! hasTargetBinding) ||
00223                  (! hasSourceBinding && hasTargetBinding)) {
00224             // it's an open ended query on the source or
00225             // target. figure out what matches and add as a
00226             // cross-product.
00227             nsCOMPtr<nsISimpleEnumerator> results;
00228             if (hasSourceBinding) {
00229                 rv = mDataSource->GetTargets(VALUE_TO_IRDFRESOURCE(sourceValue),
00230                                              mProperty,
00231                                              PR_TRUE,
00232                                              getter_AddRefs(results));
00233             }
00234             else {
00235                 rv = mDataSource->GetSources(mProperty,
00236                                              VALUE_TO_IRDFNODE(targetValue),
00237                                              PR_TRUE,
00238                                              getter_AddRefs(results));
00239                 if (NS_FAILED(rv)) return rv;
00240             }
00241 
00242             while (1) {
00243                 PRBool hasMore;
00244                 rv = results->HasMoreElements(&hasMore);
00245                 if (NS_FAILED(rv)) return rv;
00246 
00247                 if (! hasMore)
00248                     break;
00249 
00250                 nsCOMPtr<nsISupports> isupports;
00251                 rv = results->GetNext(getter_AddRefs(isupports));
00252                 if (NS_FAILED(rv)) return rv;
00253 
00254                 PRInt32 variable;
00255                 Value value;
00256 
00257                 if (hasSourceBinding) {
00258                     variable = mTargetVariable;
00259 
00260                     nsCOMPtr<nsIRDFNode> target = do_QueryInterface(isupports);
00261                     NS_ASSERTION(target != nsnull, "target is not an nsIRDFNode");
00262 
00263 #ifdef PR_LOGGING
00264                     if (PR_LOG_TEST(gXULTemplateLog, PR_LOG_DEBUG)) {
00265                         nsAutoString s(NS_LITERAL_STRING("(none found)"));
00266                         if (target)
00267                             nsXULContentUtils::GetTextForNode(target, s);
00268 
00269                         PR_LOG(gXULTemplateLog, PR_LOG_DEBUG,
00270                                ("    target => %s", NS_ConvertUCS2toUTF8(s).get()));
00271                     }
00272 #endif
00273 
00274                     if (! target) continue;
00275 
00276                     targetValue = value = target.get();
00277                 }
00278                 else {
00279                     variable = mSourceVariable;
00280 
00281                     nsCOMPtr<nsIRDFResource> source = do_QueryInterface(isupports);
00282                     NS_ASSERTION(source != nsnull, "source is not an nsIRDFResource");
00283 
00284 #ifdef PR_LOGGING
00285                     if (PR_LOG_TEST(gXULTemplateLog, PR_LOG_DEBUG)) {
00286                         const char* s = "(none found)";
00287                         if (source)
00288                             source->GetValueConst(&s);
00289 
00290                         PR_LOG(gXULTemplateLog, PR_LOG_DEBUG,
00291                                ("    source => %s", s));
00292                     }
00293 #endif
00294 
00295                     if (! source) continue;
00296 
00297                     sourceValue = value = source.get();
00298                 }
00299 
00300                 // Copy the original instantiation, and add it to the
00301                 // instantiation set with the new assignment that we've
00302                 // introduced. Ownership will be transferred to the
00303                 Instantiation newinst = *inst;
00304                 newinst.AddAssignment(variable, value);
00305 
00306                 Element* element =
00307                     nsRDFPropertyTestNode::Element::Create(mConflictSet.GetPool(),
00308                                                            VALUE_TO_IRDFRESOURCE(sourceValue),
00309                                                            mProperty,
00310                                                            VALUE_TO_IRDFNODE(targetValue));
00311 
00312                 if (! element)
00313                     return NS_ERROR_OUT_OF_MEMORY;
00314 
00315                 newinst.AddSupportingElement(element);
00316 
00317                 aInstantiations.Insert(inst, newinst);
00318             }
00319 
00320             // finally, remove the "under specified" instantiation.
00321             aInstantiations.Erase(inst--);
00322         }
00323         else {
00324             // Neither source nor target assignment!
00325             NS_ERROR("can't do open ended queries like that!");
00326             return NS_ERROR_UNEXPECTED;
00327         }
00328     }
00329 
00330     return NS_OK;
00331 }
00332 
00333 
00334 nsresult
00335 nsRDFPropertyTestNode::GetAncestorVariables(VariableSet& aVariables) const
00336 {
00337     nsresult rv;
00338 
00339     if (mSourceVariable) {
00340         rv = aVariables.Add(mSourceVariable);
00341         if (NS_FAILED(rv)) return rv;
00342     }
00343 
00344     if (mTargetVariable) {
00345         rv = aVariables.Add(mTargetVariable);
00346         if (NS_FAILED(rv)) return rv;
00347     }
00348 
00349     return TestNode::GetAncestorVariables(aVariables);
00350 }
00351 
00352 PRBool
00353 nsRDFPropertyTestNode::CanPropagate(nsIRDFResource* aSource,
00354                                     nsIRDFResource* aProperty,
00355                                     nsIRDFNode* aTarget,
00356                                     Instantiation& aInitialBindings) const
00357 {
00358     PRBool result;
00359 
00360     if ((mProperty.get() != aProperty) ||
00361         (mSource && mSource.get() != aSource) ||
00362         (mTarget && mTarget.get() != aTarget)) {
00363         result = PR_FALSE;
00364     }
00365     else {
00366         if (mSourceVariable)
00367             aInitialBindings.AddAssignment(mSourceVariable, Value(aSource));
00368 
00369         if (mTargetVariable)
00370             aInitialBindings.AddAssignment(mTargetVariable, Value(aTarget));
00371 
00372         result = PR_TRUE;
00373     }
00374 
00375 #ifdef PR_LOGGING
00376     if (PR_LOG_TEST(gXULTemplateLog, PR_LOG_DEBUG)) {
00377         const char* source;
00378         aSource->GetValueConst(&source);
00379 
00380         const char* property;
00381         aProperty->GetValueConst(&property);
00382 
00383         nsAutoString target;
00384         nsXULContentUtils::GetTextForNode(aTarget, target);
00385 
00386         PR_LOG(gXULTemplateLog, PR_LOG_DEBUG,
00387                ("nsRDFPropertyTestNode[%p]: CanPropagate([%s]==[%s]=>[%s]) => %s",
00388                 this, source, property, NS_ConvertUCS2toUTF8(target).get(),
00389                 result ? "true" : "false"));
00390     }
00391 #endif
00392 
00393     return result;
00394 }
00395 
00396 void
00397 nsRDFPropertyTestNode::Retract(nsIRDFResource* aSource,
00398                                nsIRDFResource* aProperty,
00399                                nsIRDFNode* aTarget,
00400                                nsTemplateMatchSet& aFirings,
00401                                nsTemplateMatchSet& aRetractions) const
00402 {
00403     if (aProperty == mProperty.get()) {
00404 #ifdef PR_LOGGING
00405         if (PR_LOG_TEST(gXULTemplateLog, PR_LOG_DEBUG)) {
00406             const char* source;
00407             aSource->GetValueConst(&source);
00408 
00409             const char* property;
00410             aProperty->GetValueConst(&property);
00411 
00412             nsAutoString target;
00413             nsXULContentUtils::GetTextForNode(aTarget, target);
00414 
00415             PR_LOG(gXULTemplateLog, PR_LOG_DEBUG,
00416                    ("nsRDFPropertyTestNode[%p]: Retract([%s]==[%s]=>[%s])",
00417                     this, source, property, NS_ConvertUCS2toUTF8(target).get()));
00418         }
00419 #endif
00420 
00421         mConflictSet.Remove(Element(aSource, aProperty, aTarget), aFirings, aRetractions);
00422     }
00423 }
00424