Back to index

lightning-sunbird  0.9+nobinonly
nsContentTestNode.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 "nsContentTestNode.h"
00041 #include "nsISupportsArray.h"
00042 #include "nsIXULDocument.h"
00043 #include "nsIRDFResource.h"
00044 #include "nsIAtom.h"
00045 #include "nsXULContentUtils.h"
00046 #include "nsPrintfCString.h"
00047 
00048 #include "prlog.h"
00049 #ifdef PR_LOGGING
00050 extern PRLogModuleInfo* gXULTemplateLog;
00051 #endif
00052 
00053 PRBool
00054 IsElementInBuilder(nsIContent *aContent, nsIXULTemplateBuilder *aBuilder);
00055 
00056 nsContentTestNode::nsContentTestNode(InnerNode* aParent,
00057                                      nsConflictSet& aConflictSet,
00058                                      nsIXULDocument* aDocument,
00059                                      nsIXULTemplateBuilder* aBuilder,
00060                                      PRInt32 aContentVariable,
00061                                      PRInt32 aIdVariable,
00062                                      nsIAtom* aTag)
00063     : TestNode(aParent),
00064       mConflictSet(aConflictSet),
00065       mDocument(aDocument),
00066       mBuilder(aBuilder),
00067       mContentVariable(aContentVariable),
00068       mIdVariable(aIdVariable),
00069       mTag(aTag)
00070 {
00071 #ifdef PR_LOGGING
00072     if (PR_LOG_TEST(gXULTemplateLog, PR_LOG_DEBUG)) {
00073         nsAutoString tag(NS_LITERAL_STRING("(none)"));
00074         if (mTag)
00075             mTag->ToString(tag);
00076 
00077         PR_LOG(gXULTemplateLog, PR_LOG_DEBUG,
00078                ("nsContentTestNode[%p]: parent=%p content-var=%d id-var=%d tag=%s",
00079                 this, aParent, mContentVariable, mIdVariable,
00080                 NS_ConvertUCS2toUTF8(tag).get()));
00081     }
00082 #endif
00083 }
00084 
00085 #ifdef PR_LOGGING
00086 static void
00087 ElementToString(nsIContent *aContent, nsString &aResult)
00088 {
00089     aContent->Tag()->ToString(aResult);
00090 
00091     AppendASCIItoUTF16(nsPrintfCString(18, "@%p", aContent), aResult);
00092 }
00093 #endif
00094 
00095 nsresult
00096 nsContentTestNode::FilterInstantiations(InstantiationSet& aInstantiations, void* aClosure) const
00097 {
00098     nsresult rv;
00099 
00100     nsCOMPtr<nsISupportsArray> elements;
00101     rv = NS_NewISupportsArray(getter_AddRefs(elements));
00102     if (NS_FAILED(rv)) return rv;
00103 
00104     InstantiationSet::Iterator last = aInstantiations.Last();
00105     for (InstantiationSet::Iterator inst = aInstantiations.First(); inst != last; ++inst) {
00106         Value contentValue;
00107         PRBool hasContentBinding = inst->mAssignments.GetAssignmentFor(mContentVariable, &contentValue);
00108 
00109         Value idValue;
00110         PRBool hasIdBinding = inst->mAssignments.GetAssignmentFor(mIdVariable, &idValue);
00111 
00112 #ifdef PR_LOGGING
00113         if (PR_LOG_TEST(gXULTemplateLog, PR_LOG_DEBUG)) {
00114             nsAutoString content(NS_LITERAL_STRING("(unbound)"));
00115             if (hasContentBinding)
00116                 ElementToString(VALUE_TO_ICONTENT(contentValue), content);
00117 
00118             const char *id = "(unbound)";
00119             if (hasIdBinding)
00120                 VALUE_TO_IRDFRESOURCE(idValue)->GetValueConst(&id);
00121 
00122             PR_LOG(gXULTemplateLog, PR_LOG_DEBUG,
00123                    ("nsContentTestNode[%p]: FilterInstantiations() content=%s id=%s",
00124                     this, NS_LossyConvertUCS2toASCII(content).get(), id));
00125         }
00126 #endif
00127 
00128         if (hasContentBinding && hasIdBinding) {
00129             // both are bound, consistency check
00130             PRBool consistent = PR_TRUE;
00131 
00132             nsIContent* content = VALUE_TO_ICONTENT(contentValue);
00133 
00134             if (mTag) {
00135                 // If we're supposed to be checking the tag, do it now.
00136                 if (content->Tag() != mTag)
00137                     consistent = PR_FALSE;
00138             }
00139 
00140             if (consistent) {
00141                 nsCOMPtr<nsIRDFResource> resource;
00142                 nsXULContentUtils::GetElementRefResource(content, getter_AddRefs(resource));
00143             
00144                 if (resource.get() != VALUE_TO_IRDFRESOURCE(idValue))
00145                     consistent = PR_FALSE;
00146             }
00147 
00148             PR_LOG(gXULTemplateLog, PR_LOG_DEBUG,
00149                    ("    consistency check => %s", consistent ? "passed" : "failed"));
00150 
00151             if (consistent) {
00152                 Element* element =
00153                     nsContentTestNode::Element::Create(mConflictSet.GetPool(),
00154                                     VALUE_TO_ICONTENT(contentValue));
00155 
00156                 if (! element)
00157                     return NS_ERROR_OUT_OF_MEMORY;
00158 
00159                 inst->AddSupportingElement(element);
00160             }
00161             else {
00162                 aInstantiations.Erase(inst--);
00163             }
00164         }
00165         else if (hasContentBinding) {
00166             // the content node is bound, get its id
00167             PRBool consistent = PR_TRUE;
00168 
00169             nsIContent* content = VALUE_TO_ICONTENT(contentValue);
00170 
00171             if (mTag) {
00172                 // If we're supposed to be checking the tag, do it now.
00173                 nsIAtom *tag = content->Tag();
00174 
00175                 if (tag != mTag) {
00176                     consistent = PR_FALSE;
00177 
00178                     const char *expected, *actual;
00179                     mTag->GetUTF8String(&expected);
00180                     tag->GetUTF8String(&actual);
00181 
00182                     PR_LOG(gXULTemplateLog, PR_LOG_DEBUG,
00183                            ("    => tag mismatch; expected %s, actual %s",
00184                             expected,
00185                             actual));
00186                 }
00187             }
00188 
00189             if (consistent) {
00190                 nsCOMPtr<nsIRDFResource> resource;
00191                 nsXULContentUtils::GetElementRefResource(content, getter_AddRefs(resource));
00192 
00193                 if (resource) {
00194 #ifdef PR_LOGGING
00195                     if (PR_LOG_TEST(gXULTemplateLog, PR_LOG_DEBUG)) {
00196                         const char *str;
00197                         resource->GetValueConst(&str);
00198                         PR_LOG(gXULTemplateLog, PR_LOG_DEBUG,
00199                                ("    => [%s]", str));
00200                     }
00201 #endif
00202 
00203                     Instantiation newinst = *inst;
00204                     newinst.AddAssignment(mIdVariable, Value(resource.get()));
00205 
00206                     Element* element =
00207                         nsContentTestNode::Element::Create(mConflictSet.GetPool(), content);
00208 
00209                     if (! element)
00210                         return NS_ERROR_OUT_OF_MEMORY;
00211 
00212                     newinst.AddSupportingElement(element);
00213 
00214                     aInstantiations.Insert(inst, newinst);
00215                 }
00216                 else {
00217                     PR_LOG(gXULTemplateLog, PR_LOG_DEBUG,
00218                            ("    => element has no resource"));
00219                 }
00220             }
00221 
00222             aInstantiations.Erase(inst--);
00223         }
00224         else if (hasIdBinding) {
00225             // the 'id' is bound, find elements in the content tree that match
00226             const char* uri;
00227             VALUE_TO_IRDFRESOURCE(idValue)->GetValueConst(&uri);
00228 
00229             mDocument->GetElementsForID(NS_ConvertUTF8toUCS2(uri), elements);
00230 
00231             PRUint32 count;
00232             elements->Count(&count);
00233 
00234             for (PRInt32 j = PRInt32(count) - 1; j >= 0; --j) {
00235                 nsISupports* isupports = elements->ElementAt(j);
00236                 nsCOMPtr<nsIContent> content = do_QueryInterface(isupports);
00237                 NS_IF_RELEASE(isupports);
00238 
00239                 if (IsElementInBuilder(content, mBuilder)) {
00240                     if (mTag) {
00241                         // If we've got a tag, check it to ensure
00242                         // we're consistent.
00243                         if (content->Tag() != mTag)
00244                             continue;
00245                     }
00246 
00247 #ifdef PR_LOGGING
00248                     if (PR_LOG_TEST(gXULTemplateLog, PR_LOG_DEBUG)) {
00249                         nsAutoString str;
00250                         ElementToString(content, str);
00251 
00252                         PR_LOG(gXULTemplateLog, PR_LOG_DEBUG,
00253                                ("    => %s", NS_LossyConvertUCS2toASCII(str).get()));
00254                     }
00255 #endif                    
00256 
00257                     Instantiation newinst = *inst;
00258                     newinst.AddAssignment(mContentVariable, Value(content.get()));
00259 
00260                     Element* element =
00261                         nsContentTestNode::Element::Create(mConflictSet.GetPool(), content);
00262 
00263                     if (! element)
00264                         return NS_ERROR_OUT_OF_MEMORY;
00265 
00266                     newinst.AddSupportingElement(element);
00267 
00268                     aInstantiations.Insert(inst, newinst);
00269                 }
00270             }
00271 
00272             aInstantiations.Erase(inst--);
00273         }
00274     }
00275 
00276     return NS_OK;
00277 }
00278 
00279 nsresult
00280 nsContentTestNode::GetAncestorVariables(VariableSet& aVariables) const
00281 {
00282     aVariables.Add(mContentVariable);
00283     aVariables.Add(mIdVariable);
00284 
00285     return TestNode::GetAncestorVariables(aVariables);
00286 }
00287