Back to index

lightning-sunbird  0.9+nobinonly
inDeepTreeWalker.cpp
Go to the documentation of this file.
00001 /* ***** BEGIN LICENSE BLOCK *****
00002  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00003  *
00004  * The contents of this file are subject to the Mozilla Public License Version
00005  * 1.1 (the "License"); you may not use this file except in compliance with
00006  * the License. You may obtain a copy of the License at
00007  * http://www.mozilla.org/MPL/
00008  *
00009  * Software distributed under the License is distributed on an "AS IS" basis,
00010  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00011  * for the specific language governing rights and limitations under the
00012  * License.
00013  *
00014  * The Original Code is mozilla.org code.
00015  *
00016  * The Initial Developer of the Original Code is
00017  * Netscape Communications Corporation.
00018  * Portions created by the Initial Developer are Copyright (C) 2001
00019  * the Initial Developer. All Rights Reserved.
00020  *
00021  * Contributor(s):
00022  *   Joe Hewitt <hewitt@netscape.com> (original author)
00023  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either the GNU General Public License Version 2 or later (the "GPL"), or
00026  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027  * in which case the provisions of the GPL or the LGPL are applicable instead
00028  * of those above. If you wish to allow use of your version of this file only
00029  * under the terms of either the GPL or the LGPL, and not to allow others to
00030  * use your version of this file under the terms of the MPL, indicate your
00031  * decision by deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL or the LGPL. If you do not delete
00033  * the provisions above, a recipient may use your version of this file under
00034  * the terms of any one of the MPL, the GPL or the LGPL.
00035  *
00036  * ***** END LICENSE BLOCK ***** */
00037 
00038 #include "inDeepTreeWalker.h"
00039 #include "inLayoutUtils.h"
00040 
00041 #include "nsString.h"
00042 #include "nsIDOMDocument.h"
00043 #include "nsIDOMNodeFilter.h"
00044 #include "nsIDOMNodeList.h"
00045 #include "nsServiceManagerUtils.h"
00046 #include "inIDOMUtils.h"
00047 
00048 /*****************************************************************************
00049  * This implementation does not currently operaate according to the W3C spec.
00050  * So far, only parentNode() and nextNode() are implemented, and are not
00051  * interoperable.  
00052  *****************************************************************************/
00053 
00055 
00056 MOZ_DECL_CTOR_COUNTER(DeepTreeStackItem)
00057 
00058 struct DeepTreeStackItem 
00059 {
00060   DeepTreeStackItem()  { MOZ_COUNT_CTOR(DeepTreeStackItem); }
00061   ~DeepTreeStackItem() { MOZ_COUNT_DTOR(DeepTreeStackItem); }
00062 
00063   nsCOMPtr<nsIDOMNode> node;
00064   nsCOMPtr<nsIDOMNodeList> kids;
00065   PRUint32 lastIndex;
00066 };
00067 
00069 
00070 inDeepTreeWalker::inDeepTreeWalker() 
00071   : mShowAnonymousContent(PR_FALSE),
00072     mShowSubDocuments(PR_FALSE),
00073     mWhatToShow(nsIDOMNodeFilter::SHOW_ALL)
00074 {
00075 }
00076 
00077 inDeepTreeWalker::~inDeepTreeWalker() 
00078 { 
00079   for (PRInt32 i = mStack.Count() - 1; i >= 0; --i) {
00080     delete NS_STATIC_CAST(DeepTreeStackItem*, mStack[i]);
00081   }
00082 }
00083 
00084 NS_IMPL_ISUPPORTS1(inDeepTreeWalker, inIDeepTreeWalker)
00085 
00086 
00087 // inIDeepTreeWalker
00088 
00089 NS_IMETHODIMP
00090 inDeepTreeWalker::GetShowAnonymousContent(PRBool *aShowAnonymousContent)
00091 {
00092   *aShowAnonymousContent = mShowAnonymousContent;
00093   return NS_OK;
00094 }
00095 
00096 NS_IMETHODIMP
00097 inDeepTreeWalker::SetShowAnonymousContent(PRBool aShowAnonymousContent)
00098 {
00099   mShowAnonymousContent = aShowAnonymousContent;
00100   return NS_OK;
00101 }
00102 
00103 NS_IMETHODIMP
00104 inDeepTreeWalker::GetShowSubDocuments(PRBool *aShowSubDocuments)
00105 {
00106   *aShowSubDocuments = mShowSubDocuments;
00107   return NS_OK;
00108 }
00109 
00110 NS_IMETHODIMP
00111 inDeepTreeWalker::SetShowSubDocuments(PRBool aShowSubDocuments)
00112 {
00113   mShowSubDocuments = aShowSubDocuments;
00114   return NS_OK;
00115 }
00116 
00117 NS_IMETHODIMP
00118 inDeepTreeWalker::Init(nsIDOMNode* aRoot, PRUint32 aWhatToShow)
00119 {
00120   mRoot = aRoot;
00121   mWhatToShow = aWhatToShow;
00122   
00123   PushNode(aRoot);
00124 
00125   return NS_OK;
00126 }
00127 
00129 // nsIDOMTreeWalker
00130 
00131 NS_IMETHODIMP
00132 inDeepTreeWalker::GetRoot(nsIDOMNode** aRoot)
00133 {
00134   *aRoot = mRoot;
00135   NS_IF_ADDREF(*aRoot);
00136   
00137   return NS_OK;
00138 }
00139 
00140 NS_IMETHODIMP 
00141 inDeepTreeWalker::GetWhatToShow(PRUint32* aWhatToShow)
00142 {
00143   *aWhatToShow = mWhatToShow;
00144   return NS_OK;
00145 }
00146 
00147 NS_IMETHODIMP
00148 inDeepTreeWalker::GetFilter(nsIDOMNodeFilter** aFilter)
00149 {
00150   return NS_ERROR_NOT_IMPLEMENTED;
00151 }
00152 
00153 NS_IMETHODIMP
00154 inDeepTreeWalker::GetExpandEntityReferences(PRBool* aExpandEntityReferences)
00155 {
00156   return NS_ERROR_NOT_IMPLEMENTED;
00157 }
00158 
00159 NS_IMETHODIMP
00160 inDeepTreeWalker::GetCurrentNode(nsIDOMNode** aCurrentNode)
00161 {
00162   *aCurrentNode = mCurrentNode;
00163   NS_IF_ADDREF(*aCurrentNode);
00164   
00165   return NS_OK;
00166 }
00167 
00168 NS_IMETHODIMP
00169 inDeepTreeWalker::SetCurrentNode(nsIDOMNode* aCurrentNode)
00170 {
00171   return NS_ERROR_NOT_IMPLEMENTED;
00172 }
00173 
00174 NS_IMETHODIMP
00175 inDeepTreeWalker::ParentNode(nsIDOMNode** _retval)
00176 {
00177   *_retval = nsnull;
00178   if (!mCurrentNode) return NS_OK;
00179 
00180   if (!mDOMUtils) {
00181     mDOMUtils = do_GetService("@mozilla.org/inspector/dom-utils;1");
00182     if (!mDOMUtils) {
00183       return NS_ERROR_OUT_OF_MEMORY;
00184     }
00185   }
00186 
00187   nsresult rv = mDOMUtils->GetParentForNode(mCurrentNode, mShowAnonymousContent,
00188                                        _retval);
00189   mCurrentNode = *_retval;
00190   return rv;
00191 }
00192 
00193 NS_IMETHODIMP
00194 inDeepTreeWalker::FirstChild(nsIDOMNode **_retval)
00195 {
00196   return NS_ERROR_NOT_IMPLEMENTED;
00197 }
00198 
00199 NS_IMETHODIMP
00200 inDeepTreeWalker::LastChild(nsIDOMNode **_retval)
00201 {
00202   return NS_ERROR_NOT_IMPLEMENTED;
00203 }
00204 
00205 NS_IMETHODIMP
00206 inDeepTreeWalker::PreviousSibling(nsIDOMNode **_retval)
00207 {
00208   return NS_ERROR_NOT_IMPLEMENTED;
00209 }
00210 
00211 NS_IMETHODIMP
00212 inDeepTreeWalker::NextSibling(nsIDOMNode **_retval)
00213 {
00214   return NS_ERROR_NOT_IMPLEMENTED;
00215 }
00216 
00217 NS_IMETHODIMP
00218 inDeepTreeWalker::PreviousNode(nsIDOMNode **_retval)
00219 {
00220   return NS_ERROR_NOT_IMPLEMENTED;
00221 }
00222 
00223 NS_IMETHODIMP
00224 inDeepTreeWalker::NextNode(nsIDOMNode **_retval)
00225 {
00226   if (!mCurrentNode) return NS_OK;
00227   
00228   nsCOMPtr<nsIDOMNode> next;
00229   
00230   while (1) {
00231     DeepTreeStackItem* top = (DeepTreeStackItem*)mStack.ElementAt(mStack.Count()-1);
00232     nsCOMPtr<nsIDOMNodeList> kids = top->kids;
00233     PRUint32 childCount;
00234     kids->GetLength(&childCount);
00235 
00236     if (top->lastIndex == childCount) {
00237       mStack.RemoveElementAt(mStack.Count()-1);
00238       delete top;
00239       if (mStack.Count() == 0) {
00240         mCurrentNode = nsnull;
00241         break;
00242       }
00243     } else {
00244       kids->Item(top->lastIndex++, getter_AddRefs(next));
00245       PushNode(next);
00246       break;      
00247     }
00248   } 
00249   
00250   *_retval = next;
00251   NS_IF_ADDREF(*_retval);
00252   
00253   return NS_OK;
00254 }
00255 
00256 void
00257 inDeepTreeWalker::PushNode(nsIDOMNode* aNode)
00258 {
00259   mCurrentNode = aNode;
00260   if (!aNode) return;
00261 
00262   DeepTreeStackItem* item = new DeepTreeStackItem();
00263   item->node = aNode;
00264 
00265   nsCOMPtr<nsIDOMNodeList> kids;
00266   if (mShowSubDocuments) {
00267     nsCOMPtr<nsIDOMDocument> domdoc = inLayoutUtils::GetSubDocumentFor(aNode);
00268     if (domdoc) {
00269       domdoc->GetChildNodes(getter_AddRefs(kids));
00270     }
00271   }
00272   
00273   if (!kids) {
00274     if (mShowAnonymousContent) {
00275       nsCOMPtr<nsIContent> content = do_QueryInterface(aNode);
00276       nsCOMPtr<nsIBindingManager> bindingManager;
00277       if (content &&
00278           (bindingManager = inLayoutUtils::GetBindingManagerFor(aNode))) {
00279         bindingManager->GetAnonymousNodesFor(content, getter_AddRefs(kids));
00280         if (!kids)
00281           bindingManager->GetContentListFor(content, getter_AddRefs(kids));
00282       } else {
00283         aNode->GetChildNodes(getter_AddRefs(kids));
00284       }
00285     } else
00286       aNode->GetChildNodes(getter_AddRefs(kids));
00287   }
00288   
00289   item->kids = kids;
00290   item->lastIndex = 0;
00291   mStack.AppendElement((void*)item);
00292 }
00293 
00294 /*
00295 // This NextNode implementation does not require the use of stacks, 
00296 // as does the one above. However, it does not handle anonymous 
00297 // content and sub-documents.
00298 NS_IMETHODIMP
00299 inDeepTreeWalker::NextNode(nsIDOMNode **_retval)
00300 {
00301   if (!mCurrentNode) return NS_OK;
00302   
00303   // walk down the tree first
00304   nsCOMPtr<nsIDOMNode> next;
00305   mCurrentNode->GetFirstChild(getter_AddRefs(next));
00306   if (!next) {
00307     mCurrentNode->GetNextSibling(getter_AddRefs(next));
00308     if (!next) { 
00309       // we've hit the end, so walk back up the tree until another
00310       // downward opening is found, or the top of the tree
00311       nsCOMPtr<nsIDOMNode> subject = mCurrentNode;
00312       nsCOMPtr<nsIDOMNode> parent;
00313       while (1) {
00314         subject->GetParentNode(getter_AddRefs(parent));
00315         if (!parent) // hit the top of the tree
00316           break;
00317         parent->GetNextSibling(getter_AddRefs(subject));
00318         if (subject) { // found a downward opening
00319           next = subject;
00320           break;
00321         } else // walk up another level
00322           subject = parent;
00323       } 
00324     }
00325   }
00326   
00327   mCurrentNode = next;
00328   
00329   *_retval = next;
00330   NS_IF_ADDREF(*_retval);
00331   
00332   return NS_OK;
00333 }
00334 
00335 
00336 char* getURL(nsIDOMDocument* aDoc)
00337 {
00338   nsCOMPtr<nsIDocument> doc = do_QueryInterface(aDoc);
00339   nsIURI *uri = doc->GetDocumentURI();
00340   char* s;
00341   uri->GetSpec(&s);
00342   return s;
00343 }
00344 */