Back to index

lightning-sunbird  0.9+nobinonly
inDOMView.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
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.org 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) 2001
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *   Joe Hewitt <hewitt@netscape.com> (original author)
00024  *
00025  * Alternatively, the contents of this file may be used under the terms of
00026  * either the GNU General Public License Version 2 or later (the "GPL"), or
00027  * 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 "inDOMView.h"
00040 #include "inIDOMUtils.h"
00041 
00042 #include "inLayoutUtils.h"
00043 
00044 #include "nsString.h"
00045 #include "nsReadableUtils.h"
00046 #include "nsISupportsArray.h"
00047 #include "nsIDOMNode.h"
00048 #include "nsIDOMNodeFilter.h"
00049 #include "nsIDOMNodeList.h"
00050 #include "nsIDOMCharacterData.h"
00051 #include "nsIDOMAttr.h"
00052 #include "nsIDOMDocument.h"
00053 #include "nsIDOMNamedNodeMap.h"
00054 #include "nsIDOMMutationEvent.h"
00055 #include "nsIBindingManager.h"
00056 #include "nsIDocument.h"
00057 #include "nsIServiceManager.h"
00058 #include "nsITreeColumns.h"
00059 
00061 // inDOMViewNode
00062 
00063 class inDOMViewNode
00064 {
00065 public:
00066   inDOMViewNode() {};
00067   inDOMViewNode(nsIDOMNode* aNode);
00068   ~inDOMViewNode();
00069 
00070   nsCOMPtr<nsIDOMNode> node;
00071 
00072   inDOMViewNode* parent;
00073   inDOMViewNode* next;
00074   inDOMViewNode* previous;
00075 
00076   PRInt32 level;
00077   PRBool isOpen;
00078   PRBool isContainer;
00079   PRBool hasAnonymous;
00080   PRBool hasSubDocument;
00081 };
00082 
00083 inDOMViewNode::inDOMViewNode(nsIDOMNode* aNode) :
00084   node(aNode),
00085   parent(nsnull),
00086   next(nsnull),
00087   previous(nsnull),
00088   level(0),
00089   isOpen(PR_FALSE),
00090   isContainer(PR_FALSE),
00091   hasAnonymous(PR_FALSE),
00092   hasSubDocument(PR_FALSE)
00093 {
00094 
00095 }
00096 
00097 inDOMViewNode::~inDOMViewNode()
00098 {
00099 }
00100 
00102 
00103 nsIAtom* inDOMView::kAnonymousAtom = nsnull;
00104 nsIAtom* inDOMView::kElementNodeAtom = nsnull;
00105 nsIAtom* inDOMView::kAttributeNodeAtom = nsnull;
00106 nsIAtom* inDOMView::kTextNodeAtom = nsnull;
00107 nsIAtom* inDOMView::kCDataSectionNodeAtom = nsnull;
00108 nsIAtom* inDOMView::kEntityReferenceNodeAtom = nsnull;
00109 nsIAtom* inDOMView::kEntityNodeAtom = nsnull;
00110 nsIAtom* inDOMView::kProcessingInstructionNodeAtom = nsnull;
00111 nsIAtom* inDOMView::kCommentNodeAtom = nsnull;
00112 nsIAtom* inDOMView::kDocumentNodeAtom = nsnull;
00113 nsIAtom* inDOMView::kDocumentTypeNodeAtom = nsnull;
00114 nsIAtom* inDOMView::kDocumentFragmentNodeAtom = nsnull;
00115 nsIAtom* inDOMView::kNotationNodeAtom = nsnull;
00116 
00117 inDOMView::inDOMView() :
00118   mShowAnonymous(PR_FALSE),
00119   mShowSubDocuments(PR_FALSE),
00120   mShowWhitespaceNodes(PR_TRUE),
00121   mWhatToShow(nsIDOMNodeFilter::SHOW_ALL)
00122 {
00123 }
00124 
00125 inDOMView::~inDOMView()
00126 {
00127   SetRootNode(nsnull);
00128 }
00129 
00130 /* static */ const nsStaticAtom inDOMView::Atoms_info[] = {
00131   {"anonymous", &inDOMView::kAnonymousAtom},
00132   {"ELEMENT_NODE", &inDOMView::kElementNodeAtom},
00133   {"ATTRIBUTE_NODE", &inDOMView::kAttributeNodeAtom},
00134   {"TEXT_NODE", &inDOMView::kTextNodeAtom},
00135   {"CDATA_SECTION_NODE", &inDOMView::kCDataSectionNodeAtom},
00136   {"ENTITY_REFERENCE_NODE", &inDOMView::kEntityReferenceNodeAtom},
00137   {"ENTITY_NODE", &inDOMView::kEntityNodeAtom},
00138   {"PROCESSING_INSTRUCTION_NODE", &inDOMView::kProcessingInstructionNodeAtom},
00139   {"COMMENT_NODE", &inDOMView::kCommentNodeAtom},
00140   {"DOCUMENT_NODE", &inDOMView::kDocumentNodeAtom},
00141   {"DOCUMENT_TYPE_NODE", &inDOMView::kDocumentTypeNodeAtom},
00142   {"DOCUMENT_FRAGMENT_NODE", &inDOMView::kDocumentFragmentNodeAtom},
00143   {"NOTATION_NODE", &inDOMView::kNotationNodeAtom}
00144 };
00145 
00146 /* static */ void
00147 inDOMView::InitAtoms()
00148 {
00149   NS_RegisterStaticAtoms(Atoms_info, NS_ARRAY_LENGTH(Atoms_info));
00150 }
00151 
00153 // nsISupports
00154 
00155 NS_IMPL_ISUPPORTS3(inDOMView,
00156                    inIDOMView,
00157                    nsITreeView,
00158                    nsIDocumentObserver)
00159 
00160 
00161 // inIDOMView
00162 
00163 NS_IMETHODIMP
00164 inDOMView::GetRootNode(nsIDOMNode** aNode)
00165 {
00166   *aNode = mRootNode;
00167   NS_IF_ADDREF(*aNode);
00168   return NS_OK;
00169 }
00170 
00171 NS_IMETHODIMP
00172 inDOMView::SetRootNode(nsIDOMNode* aNode)
00173 {
00174   if (mTree)
00175     mTree->BeginUpdateBatch();
00176 
00177   if (mRootDocument) {
00178     // remove previous document observer
00179     nsCOMPtr<nsIDocument> doc(do_QueryInterface(mRootDocument));
00180     if (doc)
00181       doc->RemoveObserver(this);
00182   }
00183 
00184   RemoveAllNodes();
00185 
00186   mRootNode = aNode;
00187 
00188   if (aNode) {
00189     // If we are able to show element nodes, then start with the root node
00190     // as the first node in the buffer
00191     if (mWhatToShow & nsIDOMNodeFilter::SHOW_ELEMENT) {
00192       // allocate new node array
00193       AppendNode(CreateNode(aNode, nsnull));
00194     } else {
00195       // place only the children of the root node in the buffer
00196       ExpandNode(-1);
00197     }
00198 
00199     // store an owning reference to document so that it isn't
00200     // destroyed before we are
00201     mRootDocument = do_QueryInterface(aNode);
00202     if (!mRootDocument) {
00203       aNode->GetOwnerDocument(getter_AddRefs(mRootDocument));
00204     }
00205 
00206     // add document observer
00207     nsCOMPtr<nsIDocument> doc(do_QueryInterface(mRootDocument));
00208     if (doc)
00209       doc->AddObserver(this);
00210   } else {
00211     mRootDocument = nsnull;
00212   }
00213 
00214   if (mTree)
00215     mTree->EndUpdateBatch();
00216 
00217   return NS_OK;
00218 }
00219 
00220 NS_IMETHODIMP
00221 inDOMView::GetNodeFromRowIndex(PRInt32 rowIndex, nsIDOMNode **_retval)
00222 {
00223   inDOMViewNode* viewNode = nsnull;
00224   RowToNode(rowIndex, &viewNode);
00225   if (!viewNode) return NS_ERROR_FAILURE;
00226   *_retval = viewNode->node;
00227   NS_IF_ADDREF(*_retval);
00228 
00229   return NS_OK;
00230 }
00231 
00232 NS_IMETHODIMP
00233 inDOMView::GetRowIndexFromNode(nsIDOMNode *node, PRInt32 *_retval)
00234 {
00235   NodeToRow(node, _retval);
00236   return NS_OK;
00237 }
00238 
00239 
00240 NS_IMETHODIMP
00241 inDOMView::GetShowAnonymousContent(PRBool *aShowAnonymousContent)
00242 {
00243   *aShowAnonymousContent = mShowAnonymous;
00244   return NS_OK;
00245 }
00246 
00247 NS_IMETHODIMP
00248 inDOMView::SetShowAnonymousContent(PRBool aShowAnonymousContent)
00249 {
00250   mShowAnonymous = aShowAnonymousContent;
00251   return NS_OK;
00252 }
00253 
00254 NS_IMETHODIMP
00255 inDOMView::GetShowSubDocuments(PRBool *aShowSubDocuments)
00256 {
00257   *aShowSubDocuments = mShowSubDocuments;
00258   return NS_OK;
00259 }
00260 
00261 NS_IMETHODIMP
00262 inDOMView::SetShowSubDocuments(PRBool aShowSubDocuments)
00263 {
00264   mShowSubDocuments = aShowSubDocuments;
00265   return NS_OK;
00266 }
00267 
00268 NS_IMETHODIMP
00269 inDOMView::GetShowWhitespaceNodes(PRBool *aShowWhitespaceNodes)
00270 {
00271   *aShowWhitespaceNodes = mShowWhitespaceNodes;
00272   return NS_OK;
00273 }
00274 
00275 NS_IMETHODIMP
00276 inDOMView::SetShowWhitespaceNodes(PRBool aShowWhitespaceNodes)
00277 {
00278   mShowWhitespaceNodes = aShowWhitespaceNodes;
00279   return NS_OK;
00280 }
00281 
00282 NS_IMETHODIMP
00283 inDOMView::GetWhatToShow(PRUint32 *aWhatToShow)
00284 {
00285   *aWhatToShow = mWhatToShow;
00286   return NS_OK;
00287 }
00288 
00289 NS_IMETHODIMP
00290 inDOMView::SetWhatToShow(PRUint32 aWhatToShow)
00291 {
00292   mWhatToShow = aWhatToShow;
00293   return NS_OK;
00294 }
00295 
00296 NS_IMETHODIMP
00297 inDOMView::Rebuild()
00298 {
00299   nsCOMPtr<nsIDOMNode> root;
00300   GetRootNode(getter_AddRefs(root));
00301   SetRootNode(root);
00302   return NS_OK;
00303 }
00304 
00306 // nsITreeView
00307 
00308 NS_IMETHODIMP
00309 inDOMView::GetRowCount(PRInt32 *aRowCount)
00310 {
00311   *aRowCount = GetRowCount();
00312   return NS_OK;
00313 }
00314 
00315 NS_IMETHODIMP
00316 inDOMView::GetRowProperties(PRInt32 index, nsISupportsArray *properties)
00317 {
00318   return NS_OK;
00319 }
00320 
00321 NS_IMETHODIMP
00322 inDOMView::GetCellProperties(PRInt32 row, nsITreeColumn* col, nsISupportsArray *properties)
00323 {
00324   inDOMViewNode* node = nsnull;
00325   RowToNode(row, &node);
00326   if (!node) return NS_ERROR_FAILURE;
00327 
00328   nsCOMPtr<nsIContent> content = do_QueryInterface(node->node);
00329   if (content && content->GetBindingParent()) {
00330     properties->AppendElement(kAnonymousAtom);
00331   }
00332 
00333   PRUint16 nodeType;
00334   node->node->GetNodeType(&nodeType);
00335   switch (nodeType) {
00336     case nsIDOMNode::ELEMENT_NODE:
00337       properties->AppendElement(kElementNodeAtom);
00338       break;
00339     case nsIDOMNode::ATTRIBUTE_NODE:
00340       properties->AppendElement(kAttributeNodeAtom);
00341       break;
00342     case nsIDOMNode::TEXT_NODE:
00343       properties->AppendElement(kTextNodeAtom);
00344       break;
00345     case nsIDOMNode::CDATA_SECTION_NODE:
00346       properties->AppendElement(kCDataSectionNodeAtom);
00347       break;
00348     case nsIDOMNode::ENTITY_REFERENCE_NODE:
00349       properties->AppendElement(kEntityReferenceNodeAtom);
00350       break;
00351     case nsIDOMNode::ENTITY_NODE:
00352       properties->AppendElement(kEntityNodeAtom);
00353       break;
00354     case nsIDOMNode::PROCESSING_INSTRUCTION_NODE:
00355       properties->AppendElement(kProcessingInstructionNodeAtom);
00356       break;
00357     case nsIDOMNode::COMMENT_NODE:
00358       properties->AppendElement(kCommentNodeAtom);
00359       break;
00360     case nsIDOMNode::DOCUMENT_NODE:
00361       properties->AppendElement(kDocumentNodeAtom);
00362       break;
00363     case nsIDOMNode::DOCUMENT_TYPE_NODE:
00364       properties->AppendElement(kDocumentTypeNodeAtom);
00365       break;
00366     case nsIDOMNode::DOCUMENT_FRAGMENT_NODE:
00367       properties->AppendElement(kDocumentFragmentNodeAtom);
00368       break;
00369     case nsIDOMNode::NOTATION_NODE:
00370       properties->AppendElement(kNotationNodeAtom);
00371       break;
00372   }
00373   return NS_OK;
00374 }
00375 
00376 NS_IMETHODIMP
00377 inDOMView::GetColumnProperties(nsITreeColumn* col, nsISupportsArray *properties)
00378 {
00379   return NS_OK;
00380 }
00381 
00382 NS_IMETHODIMP
00383 inDOMView::GetImageSrc(PRInt32 row, nsITreeColumn* col, nsAString& _retval)
00384 {
00385   return NS_OK;
00386 }
00387 
00388 NS_IMETHODIMP
00389 inDOMView::GetProgressMode(PRInt32 row, nsITreeColumn* col, PRInt32* _retval)
00390 {
00391   return NS_OK;
00392 }
00393 
00394 NS_IMETHODIMP
00395 inDOMView::GetCellValue(PRInt32 row, nsITreeColumn* col, nsAString& _retval)
00396 {
00397   return NS_OK;
00398 }
00399 
00400 NS_IMETHODIMP
00401 inDOMView::GetCellText(PRInt32 row, nsITreeColumn* col, nsAString& _retval)
00402 {
00403   inDOMViewNode* node = nsnull;
00404   RowToNode(row, &node);
00405   if (!node) return NS_ERROR_FAILURE;
00406 
00407   nsIDOMNode* domNode = node->node;
00408 
00409   nsAutoString colID;
00410   col->GetId(colID);
00411   if (colID.EqualsLiteral("colNodeName"))
00412     domNode->GetNodeName(_retval);
00413   else if (colID.EqualsLiteral("colLocalName"))
00414     domNode->GetLocalName(_retval);
00415   else if (colID.EqualsLiteral("colPrefix"))
00416     domNode->GetPrefix(_retval);
00417   else if (colID.EqualsLiteral("colNamespaceURI"))
00418     domNode->GetNamespaceURI(_retval);
00419   else if (colID.EqualsLiteral("colNodeType")) {
00420     PRUint16 nodeType;
00421     domNode->GetNodeType(&nodeType);
00422     nsAutoString temp;
00423     temp.AppendInt(PRInt32(nodeType));
00424     _retval = temp;
00425   } else if (colID.EqualsLiteral("colNodeValue"))
00426     domNode->GetNodeValue(_retval);
00427   else {
00428     if (StringBeginsWith(colID, NS_LITERAL_STRING("col@"))) {
00429       nsCOMPtr<nsIDOMElement> el = do_QueryInterface(node->node);
00430       if (el) {
00431         nsAutoString attr;
00432         colID.Right(attr, colID.Length()-4); // have to use this because Substring is crashing on me!
00433         el->GetAttribute(attr, _retval);
00434       }
00435     }
00436   }
00437 
00438   return NS_OK;
00439 }
00440 
00441 NS_IMETHODIMP
00442 inDOMView::IsContainer(PRInt32 index, PRBool *_retval)
00443 {
00444   inDOMViewNode* node = nsnull;
00445   RowToNode(index, &node);
00446   if (!node) return NS_ERROR_FAILURE;
00447 
00448   *_retval = node->isContainer;
00449   return NS_OK;
00450 }
00451 
00452 NS_IMETHODIMP
00453 inDOMView::IsContainerOpen(PRInt32 index, PRBool *_retval)
00454 {
00455   inDOMViewNode* node = nsnull;
00456   RowToNode(index, &node);
00457   if (!node) return NS_ERROR_FAILURE;
00458 
00459   *_retval = node->isOpen;
00460   return NS_OK;
00461 }
00462 
00463 NS_IMETHODIMP
00464 inDOMView::IsContainerEmpty(PRInt32 index, PRBool *_retval)
00465 {
00466   inDOMViewNode* node = nsnull;
00467   RowToNode(index, &node);
00468   if (!node) return NS_ERROR_FAILURE;
00469 
00470   *_retval = node->isContainer ? PR_FALSE : PR_TRUE;
00471   return NS_OK;
00472 }
00473 
00474 NS_IMETHODIMP
00475 inDOMView::GetLevel(PRInt32 index, PRInt32 *_retval)
00476 {
00477   inDOMViewNode* node = nsnull;
00478   RowToNode(index, &node);
00479   if (!node) return NS_ERROR_FAILURE;
00480 
00481   *_retval = node->level;
00482   return NS_OK;
00483 }
00484 
00485 NS_IMETHODIMP
00486 inDOMView::GetParentIndex(PRInt32 rowIndex, PRInt32 *_retval)
00487 {
00488   inDOMViewNode* node = nsnull;
00489   RowToNode(rowIndex, &node);
00490   if (!node) return NS_ERROR_FAILURE;
00491 
00492   inDOMViewNode* checkNode = nsnull;
00493   PRUint32 i = rowIndex - 1;
00494   do {
00495     RowToNode(i, &checkNode);
00496     if (checkNode == node->parent) {
00497       *_retval = i;
00498       return NS_OK;
00499     }
00500     --i;
00501   } while (checkNode);
00502 
00503   return NS_OK;
00504 }
00505 
00506 NS_IMETHODIMP
00507 inDOMView::HasNextSibling(PRInt32 rowIndex, PRInt32 afterIndex, PRBool *_retval)
00508 {
00509   inDOMViewNode* node = nsnull;
00510   RowToNode(rowIndex, &node);
00511   if (!node) return NS_ERROR_FAILURE;
00512 
00513   *_retval = node->next != nsnull;
00514 
00515   return NS_OK;
00516 }
00517 
00518 NS_IMETHODIMP
00519 inDOMView::ToggleOpenState(PRInt32 index)
00520 {
00521   inDOMViewNode* node = nsnull;
00522   RowToNode(index, &node);
00523   if (!node) return NS_ERROR_FAILURE;
00524 
00525   PRInt32 oldCount = GetRowCount();
00526   if (node->isOpen)
00527     CollapseNode(index);
00528   else
00529     ExpandNode(index);
00530 
00531   // Update the twisty.
00532   mTree->InvalidateRow(index);
00533 
00534   mTree->RowCountChanged(index+1, GetRowCount() - oldCount);
00535 
00536   return NS_OK;
00537 }
00538 
00539 NS_IMETHODIMP
00540 inDOMView::SetTree(nsITreeBoxObject *tree)
00541 {
00542   mTree = tree;
00543   return NS_OK;
00544 }
00545 
00546 NS_IMETHODIMP
00547 inDOMView::GetSelection(nsITreeSelection * *aSelection)
00548 {
00549   *aSelection = mSelection;
00550   NS_IF_ADDREF(*aSelection);
00551   return NS_OK;
00552 }
00553 
00554 NS_IMETHODIMP inDOMView::SetSelection(nsITreeSelection * aSelection)
00555 {
00556   mSelection = aSelection;
00557   return NS_OK;
00558 }
00559 
00560 NS_IMETHODIMP
00561 inDOMView::SelectionChanged()
00562 {
00563   return NS_OK;
00564 }
00565 
00566 NS_IMETHODIMP
00567 inDOMView::SetCellValue(PRInt32 row, nsITreeColumn* col, const nsAString& value)
00568 {
00569   return NS_OK;
00570 }
00571 
00572 NS_IMETHODIMP
00573 inDOMView::SetCellText(PRInt32 row, nsITreeColumn* col, const nsAString& value)
00574 {
00575   return NS_OK;
00576 }
00577 
00578 NS_IMETHODIMP
00579 inDOMView::CycleHeader(nsITreeColumn* col)
00580 {
00581   return NS_OK;
00582 }
00583 
00584 NS_IMETHODIMP
00585 inDOMView::CycleCell(PRInt32 row, nsITreeColumn* col)
00586 {
00587   return NS_OK;
00588 }
00589 
00590 NS_IMETHODIMP
00591 inDOMView::IsEditable(PRInt32 row, nsITreeColumn* col, PRBool *_retval)
00592 {
00593   return NS_OK;
00594 }
00595 
00596 NS_IMETHODIMP
00597 inDOMView::IsSeparator(PRInt32 index, PRBool *_retval)
00598 {
00599   return NS_OK;
00600 }
00601 
00602 NS_IMETHODIMP
00603 inDOMView::IsSorted(PRBool *_retval)
00604 {
00605   return NS_OK;
00606 }
00607 
00608 NS_IMETHODIMP
00609 inDOMView::CanDrop(PRInt32 index, PRInt32 orientation, PRBool *_retval)
00610 {
00611   *_retval = PR_FALSE;
00612   return NS_OK;
00613 }
00614 
00615 NS_IMETHODIMP
00616 inDOMView::Drop(PRInt32 row, PRInt32 orientation)
00617 {
00618   return NS_OK;
00619 }
00620 
00621 NS_IMETHODIMP
00622 inDOMView::PerformAction(const PRUnichar *action)
00623 {
00624   return NS_OK;
00625 }
00626 
00627 NS_IMETHODIMP
00628 inDOMView::PerformActionOnRow(const PRUnichar *action, PRInt32 row)
00629 {
00630   return NS_OK;
00631 }
00632 
00633 NS_IMETHODIMP
00634 inDOMView::PerformActionOnCell(const PRUnichar* action, PRInt32 row, nsITreeColumn* col)
00635 {
00636   return NS_OK;
00637 }
00638 
00640 // nsIDocumentObserver
00641 
00642 NS_IMPL_NSIDOCUMENTOBSERVER_CORE_STUB(inDOMView)
00643 NS_IMPL_NSIDOCUMENTOBSERVER_LOAD_STUB(inDOMView)
00644 NS_IMPL_NSIDOCUMENTOBSERVER_REFLOW_STUB(inDOMView)
00645 NS_IMPL_NSIDOCUMENTOBSERVER_STATE_STUB(inDOMView)
00646 NS_IMPL_NSIDOCUMENTOBSERVER_STYLE_STUB(inDOMView)
00647 
00648 void
00649 inDOMView::AttributeChanged(nsIDocument *aDocument, nsIContent* aContent, PRInt32 aNameSpaceID,
00650                             nsIAtom* aAttribute, PRInt32 aModType)
00651 {
00652   if (!mTree) {
00653     return;
00654   }
00655 
00656   if (!(mWhatToShow & nsIDOMNodeFilter::SHOW_ATTRIBUTE)) {
00657     return;
00658   }
00659 
00660   // get the dom attribute node, if there is any
00661   nsCOMPtr<nsIDOMNode> content(do_QueryInterface(aContent));
00662   nsCOMPtr<nsIDOMElement> el(do_QueryInterface(aContent));
00663   nsCOMPtr<nsIDOMAttr> domAttr;
00664   nsAutoString attrStr;
00665   aAttribute->ToString(attrStr);
00666   el->GetAttributeNode(attrStr, getter_AddRefs(domAttr));
00667 
00668   if (aModType == nsIDOMMutationEvent::MODIFICATION) {
00669     // No fancy stuff here, just invalidate the changed row
00670     PRInt32 row = 0;
00671     NodeToRow(domAttr, &row);
00672     mTree->InvalidateRange(row, row);
00673   } else if (aModType == nsIDOMMutationEvent::ADDITION) {
00674     // get the number of attributes on this content node
00675     nsCOMPtr<nsIDOMNamedNodeMap> attrs;
00676     content->GetAttributes(getter_AddRefs(attrs));
00677     PRUint32 attrCount;
00678     attrs->GetLength(&attrCount);
00679 
00680     inDOMViewNode* contentNode = nsnull;
00681     PRInt32 contentRow;
00682     PRInt32 attrRow;
00683     if (NS_FAILED(NodeToRow(content, &contentRow))) {
00684       return;
00685     }
00686     RowToNode(contentRow, &contentNode);
00687     if (!contentRow || !contentNode->isOpen) {
00688       return;
00689     }
00690     if (mRootNode == content) {
00691       // if this view has a root node but is not displaying it,
00692       // it is ok to act as if the changed attribute is on the root.
00693       attrRow = attrCount - 1;
00694     } else {
00695       attrRow = contentRow + attrCount;
00696     }
00697 
00698     inDOMViewNode* newNode = CreateNode(domAttr, contentNode);
00699     inDOMViewNode* insertNode = nsnull;
00700     RowToNode(attrRow, &insertNode);
00701     if (insertNode) {
00702       if (insertNode->level <= contentNode->level) {
00703         RowToNode(attrRow-1, &insertNode);
00704         InsertLinkAfter(newNode, insertNode);
00705       } else
00706         InsertLinkBefore(newNode, insertNode);
00707     }
00708     InsertNode(newNode, attrRow);
00709     mTree->RowCountChanged(attrRow, 1);
00710   } else if (aModType == nsIDOMMutationEvent::REMOVAL) {
00711     // At this point, the attribute is already gone from the DOM, but is still represented
00712     // in our mRows array.  Search through the content node's children for the corresponding
00713     // node and remove it.
00714 
00715     // get the row of the content node
00716     inDOMViewNode* contentNode = nsnull;
00717     PRInt32 contentRow;
00718     PRInt32 baseLevel;
00719     if (NS_SUCCEEDED(NodeToRow(content, &contentRow))) {
00720       RowToNode(contentRow, &contentNode);
00721       baseLevel = contentNode->level;
00722     } else {
00723       if (mRootNode == content) {
00724         contentRow = -1;
00725         baseLevel = -1;
00726       } else
00727         return;
00728     }
00729 
00730     // search for the attribute node that was removed
00731     inDOMViewNode* checkNode = nsnull;
00732     PRInt32 row = 0;
00733     for (row = contentRow+1; row < GetRowCount(); ++row) {
00734       checkNode = GetNodeAt(row);
00735       if (checkNode->level == baseLevel+1) {
00736         domAttr = do_QueryInterface(checkNode->node);
00737         if (domAttr) {
00738           nsAutoString attrName;
00739           domAttr->GetNodeName(attrName);
00740           if (attrName.Equals(attrStr)) {
00741             // we have found the row for the attribute that was removed
00742             RemoveLink(checkNode);
00743             RemoveNode(row);
00744             mTree->RowCountChanged(row, -1);
00745             break;
00746           }
00747         }
00748       }
00749       if (checkNode->level <= baseLevel)
00750         break;
00751     }
00752 
00753  }
00754 }
00755 
00756 void
00757 inDOMView::ContentAppended(nsIDocument *aDocument,
00758                            nsIContent* aContainer,
00759                            PRInt32 aNewIndexInContainer)
00760 {
00761   if (!mTree) {
00762     return;
00763   }
00764 
00765   nsIContent *child = aContainer->GetChildAt(aNewIndexInContainer);
00766 
00767   ContentInserted(aDocument, aContainer, child, aNewIndexInContainer);
00768 }
00769 
00770 void
00771 inDOMView::CharacterDataChanged(nsIDocument *aDocument,
00772                                 nsIContent* aContent,
00773                                 PRBool aAppend)
00774 {
00775 }
00776 
00777 void
00778 inDOMView::ContentInserted(nsIDocument *aDocument, nsIContent* aContainer,
00779                            nsIContent* aChild, PRInt32 aIndexInContainer)
00780 {
00781   if (!mTree)
00782     return;
00783 
00784   nsresult rv;
00785   nsCOMPtr<nsIDOMNode> childDOMNode(do_QueryInterface(aChild));
00786   nsCOMPtr<nsIDOMNode> parent;
00787   if (!mDOMUtils) {
00788     mDOMUtils = do_GetService("@mozilla.org/inspector/dom-utils;1");
00789     if (!mDOMUtils) {
00790       return;
00791     }
00792   }
00793   mDOMUtils->GetParentForNode(childDOMNode, mShowAnonymous,
00794                               getter_AddRefs(parent));
00795 
00796   // find the inDOMViewNode for the parent of the inserted content
00797   PRInt32 parentRow = 0;
00798   if (NS_FAILED(rv = NodeToRow(parent, &parentRow)))
00799     return;
00800   inDOMViewNode* parentNode = nsnull;
00801   if (NS_FAILED(rv = RowToNode(parentRow, &parentNode)))
00802     return;
00803 
00804   // get the previous sibling of the inserted content
00805   nsCOMPtr<nsIDOMNode> previous;
00806   GetRealPreviousSibling(childDOMNode, parent, getter_AddRefs(previous));
00807   inDOMViewNode* previousNode = nsnull;
00808 
00809   PRInt32 row = 0;
00810   if (previous) {
00811     // find the inDOMViewNode for the previous sibling of the inserted content
00812     PRInt32 previousRow = 0;
00813     if (NS_FAILED(rv = NodeToRow(previous, &previousRow)))
00814       return;
00815     if (NS_FAILED(rv = RowToNode(previousRow, &previousNode)))
00816       return;
00817 
00818     // get the last descendant of the previous row, which is the row
00819     // after which to insert this new row
00820     GetLastDescendantOf(previousNode, previousRow, &row);
00821     ++row;
00822   } else {
00823     // there is no previous sibling, so the new row will be inserted after the parent
00824     row = parentRow+1;
00825   }
00826 
00827   inDOMViewNode* newNode = CreateNode(childDOMNode, parentNode);
00828 
00829   if (previous) {
00830     InsertLinkAfter(newNode, previousNode);
00831   } else {
00832     PRInt32 firstChildRow;
00833     if (NS_SUCCEEDED(GetFirstDescendantOf(parentNode, parentRow, &firstChildRow))) {
00834       inDOMViewNode* firstChild;
00835       RowToNode(firstChildRow, &firstChild);
00836       InsertLinkBefore(newNode, firstChild);
00837     }
00838   }
00839 
00840   // insert new node
00841   InsertNode(newNode, row);
00842 
00843   mTree->RowCountChanged(row, 1);
00844 }
00845 
00846 void
00847 inDOMView::ContentRemoved(nsIDocument *aDocument, nsIContent* aContainer, nsIContent* aChild, PRInt32 aIndexInContainer)
00848 {
00849   if (!mTree)
00850     return;
00851 
00852   nsresult rv;
00853 
00854   // find the inDOMViewNode for the old child
00855   nsCOMPtr<nsIDOMNode> oldDOMNode(do_QueryInterface(aChild));
00856   PRInt32 row = 0;
00857   if (NS_FAILED(rv = NodeToRow(oldDOMNode, &row)))
00858     return;
00859   inDOMViewNode* oldNode;
00860   if (NS_FAILED(rv = RowToNode(row, &oldNode)))
00861     return;
00862 
00863   if (oldNode->isOpen)
00864     CollapseNode(row);
00865 
00866   RemoveLink(oldNode);
00867   RemoveNode(row);
00868 
00869   mTree->RowCountChanged(row, -1);
00870 }
00871 
00873 // inDOMView
00874 
00876 
00877 inDOMViewNode*
00878 inDOMView::GetNodeAt(PRInt32 aRow)
00879 {
00880   return (inDOMViewNode*)mNodes.ElementAt(aRow);
00881 }
00882 
00883 PRInt32
00884 inDOMView::GetRowCount()
00885 {
00886   return mNodes.Count();
00887 }
00888 
00889 inDOMViewNode*
00890 inDOMView::CreateNode(nsIDOMNode* aNode, inDOMViewNode* aParent)
00891 {
00892   inDOMViewNode* viewNode = new inDOMViewNode(aNode);
00893   viewNode->level = aParent ? aParent->level+1 : 0;
00894   viewNode->parent = aParent;
00895 
00896   nsCOMArray<nsIDOMNode> grandKids;
00897   GetChildNodesFor(aNode, grandKids);
00898   viewNode->isContainer = (grandKids.Count() > 0);
00899   return viewNode;
00900 }
00901 
00902 PRBool
00903 inDOMView::RowOutOfBounds(PRInt32 aRow, PRInt32 aCount)
00904 {
00905   return aRow < 0 || aRow >= GetRowCount() || aCount+aRow > GetRowCount();
00906 }
00907 
00908 void
00909 inDOMView::AppendNode(inDOMViewNode* aNode)
00910 {
00911   mNodes.AppendElement(aNode);
00912 }
00913 
00914 void
00915 inDOMView::InsertNode(inDOMViewNode* aNode, PRInt32 aRow)
00916 {
00917   if (RowOutOfBounds(aRow, 1))
00918     AppendNode(aNode);
00919   else
00920     mNodes.InsertElementAt(aNode, aRow);
00921 }
00922 
00923 void
00924 inDOMView::RemoveNode(PRInt32 aRow)
00925 {
00926   if (RowOutOfBounds(aRow, 1))
00927     return;
00928 
00929   delete GetNodeAt(aRow);
00930   mNodes.RemoveElementAt(aRow);
00931 }
00932 
00933 void
00934 inDOMView::ReplaceNode(inDOMViewNode* aNode, PRInt32 aRow)
00935 {
00936   if (RowOutOfBounds(aRow, 1))
00937     return;
00938 
00939   delete GetNodeAt(aRow);
00940   mNodes.ReplaceElementAt(aNode, aRow);
00941 }
00942 
00943 void
00944 inDOMView::InsertNodes(nsVoidArray& aNodes, PRInt32 aRow)
00945 {
00946   if (aRow < 0 || aRow > GetRowCount())
00947     return;
00948 
00949   mNodes.InsertElementsAt(aNodes, aRow);
00950 }
00951 
00952 void
00953 inDOMView::RemoveNodes(PRInt32 aRow, PRInt32 aCount)
00954 {
00955   if (aRow < 0)
00956     return;
00957 
00958   PRInt32 rowCount = GetRowCount();
00959   for (PRInt32 i = aRow; i < aRow+aCount && i < rowCount; ++i) {
00960     delete GetNodeAt(i);
00961   }
00962 
00963   mNodes.RemoveElementsAt(aRow, aCount);
00964 }
00965 
00966 void
00967 inDOMView::RemoveAllNodes()
00968 {
00969   PRInt32 rowCount = GetRowCount();
00970   for (PRInt32 i = 0; i < rowCount; ++i) {
00971     delete GetNodeAt(i);
00972   }
00973 
00974   mNodes.Clear();
00975 }
00976 
00977 void
00978 inDOMView::ExpandNode(PRInt32 aRow)
00979 {
00980   inDOMViewNode* node = nsnull;
00981   RowToNode(aRow, &node);
00982 
00983   nsCOMArray<nsIDOMNode> kids;
00984   GetChildNodesFor(node ? node->node : mRootNode,
00985                    kids);
00986   PRInt32 kidCount = kids.Count();
00987 
00988   nsVoidArray list(kidCount);
00989 
00990   inDOMViewNode* newNode = nsnull;
00991   inDOMViewNode* prevNode = nsnull;
00992 
00993   for (PRInt32 i = 0; i < kidCount; ++i) {
00994     newNode = CreateNode(kids[i], node);
00995     list.ReplaceElementAt(newNode, i);
00996 
00997     if (prevNode)
00998       prevNode->next = newNode;
00999     newNode->previous = prevNode;
01000     prevNode = newNode;
01001   }
01002 
01003   InsertNodes(list, aRow+1);
01004 
01005   if (node)
01006     node->isOpen = PR_TRUE;
01007 }
01008 
01009 void
01010 inDOMView::CollapseNode(PRInt32 aRow)
01011 {
01012   inDOMViewNode* node = nsnull;
01013   RowToNode(aRow, &node);
01014 
01015   PRInt32 row = 0;
01016   GetLastDescendantOf(node, aRow, &row);
01017 
01018   RemoveNodes(aRow+1, row-aRow);
01019 
01020   node->isOpen = PR_FALSE;
01021 }
01022 
01024 
01025 nsresult
01026 inDOMView::RowToNode(PRInt32 aRow, inDOMViewNode** aNode)
01027 {
01028   if (aRow < 0 || aRow >= GetRowCount())
01029     return NS_ERROR_FAILURE;
01030 
01031   *aNode = GetNodeAt(aRow);
01032   return NS_OK;
01033 }
01034 
01035 nsresult
01036 inDOMView::NodeToRow(nsIDOMNode* aNode, PRInt32* aRow)
01037 {
01038   PRInt32 rowCount = GetRowCount();
01039   for (PRInt32 i = 0; i < rowCount; ++i) {
01040     if (GetNodeAt(i)->node == aNode) {
01041       *aRow = i;
01042       return NS_OK;
01043     }
01044   }
01045 
01046   *aRow = -1;
01047   return NS_ERROR_FAILURE;
01048 }
01049 
01051 
01052 void
01053 inDOMView::InsertLinkAfter(inDOMViewNode* aNode, inDOMViewNode* aInsertAfter)
01054 {
01055   if (aInsertAfter->next)
01056     aInsertAfter->next->previous = aNode;
01057   aNode->next = aInsertAfter->next;
01058   aInsertAfter->next = aNode;
01059   aNode->previous = aInsertAfter;
01060 }
01061 
01062 void
01063 inDOMView::InsertLinkBefore(inDOMViewNode* aNode, inDOMViewNode* aInsertBefore)
01064 {
01065   if (aInsertBefore->previous)
01066     aInsertBefore->previous->next = aNode;
01067   aNode->previous = aInsertBefore->previous;
01068   aInsertBefore->previous = aNode;
01069   aNode->next = aInsertBefore;
01070 }
01071 
01072 void
01073 inDOMView::RemoveLink(inDOMViewNode* aNode)
01074 {
01075   if (aNode->previous)
01076     aNode->previous->next = aNode->next;
01077   if (aNode->next)
01078     aNode->next->previous = aNode->previous;
01079 }
01080 
01081 void
01082 inDOMView::ReplaceLink(inDOMViewNode* aNewNode, inDOMViewNode* aOldNode)
01083 {
01084   if (aOldNode->previous)
01085     aOldNode->previous->next = aNewNode;
01086   if (aOldNode->next)
01087     aOldNode->next->previous = aNewNode;
01088   aNewNode->next = aOldNode->next;
01089   aNewNode->previous = aOldNode->previous;
01090 }
01091 
01093 
01094 nsresult
01095 inDOMView::GetFirstDescendantOf(inDOMViewNode* aNode, PRInt32 aRow, PRInt32* aResult)
01096 {
01097   // get the first node that is a descendant of the previous sibling
01098   PRInt32 row = 0;
01099   inDOMViewNode* node;
01100   for (row = aRow+1; row < GetRowCount(); ++row) {
01101     node = GetNodeAt(row);
01102     if (node->parent == aNode) {
01103       *aResult = row;
01104       return NS_OK;
01105     }
01106     if (node->level <= aNode->level)
01107       break;
01108   }
01109   return NS_ERROR_FAILURE;
01110 }
01111 
01112 nsresult
01113 inDOMView::GetLastDescendantOf(inDOMViewNode* aNode, PRInt32 aRow, PRInt32* aResult)
01114 {
01115   // get the last node that is a descendant of the previous sibling
01116   PRInt32 row = 0;
01117   for (row = aRow+1; row < GetRowCount(); ++row) {
01118     if (GetNodeAt(row)->level <= aNode->level)
01119       break;
01120   }
01121   *aResult = row-1;
01122   return NS_OK;
01123 }
01124 
01126 
01127 nsresult
01128 inDOMView::GetChildNodesFor(nsIDOMNode* aNode, nsCOMArray<nsIDOMNode>& aResult)
01129 {
01130   // Need to do this test to prevent unfortunate NYI assertion
01131   // on nsXULAttribute::GetChildNodes
01132   nsCOMPtr<nsIDOMAttr> attr = do_QueryInterface(aNode);
01133   if (!attr) {
01134     // attribute nodes
01135     if (mWhatToShow & nsIDOMNodeFilter::SHOW_ATTRIBUTE) {
01136       nsCOMPtr<nsIDOMNamedNodeMap> attrs;
01137       aNode->GetAttributes(getter_AddRefs(attrs));
01138       if (attrs) {
01139         AppendAttrsToArray(attrs, aResult);
01140       }
01141     }
01142 
01143     if (mWhatToShow & nsIDOMNodeFilter::SHOW_ELEMENT) {
01144       // try to get the anonymous content
01145       nsCOMPtr<nsIDOMNodeList> kids;
01146       if (mShowAnonymous) {
01147         nsCOMPtr<nsIContent> content = do_QueryInterface(aNode);
01148         if (content) {
01149           nsCOMPtr<nsIBindingManager> bindingManager = inLayoutUtils::GetBindingManagerFor(aNode);
01150           if (bindingManager) {
01151             bindingManager->GetAnonymousNodesFor(content, getter_AddRefs(kids));
01152             if (!kids) {
01153               bindingManager->GetContentListFor(content, getter_AddRefs(kids));
01154             }
01155           }
01156         }
01157       }
01158 
01159       if (!kids) {
01160         aNode->GetChildNodes(getter_AddRefs(kids));
01161       }
01162       if (kids) {
01163         AppendKidsToArray(kids, aResult);
01164       }
01165     }
01166 
01167     if (mShowSubDocuments) {
01168       nsCOMPtr<nsIDOMNode> domdoc =
01169         do_QueryInterface(inLayoutUtils::GetSubDocumentFor(aNode));
01170       if (domdoc) {
01171         aResult.AppendObject(domdoc);
01172       }
01173     }
01174   }
01175 
01176   return NS_OK;
01177 }
01178 
01179 nsresult
01180 inDOMView::GetRealPreviousSibling(nsIDOMNode* aNode, nsIDOMNode* aRealParent, nsIDOMNode** aSibling)
01181 {
01182   // XXXjrh: This won't work for some cases during some situations where XBL insertion points
01183   // are involved.  Fix me!
01184   aNode->GetPreviousSibling(aSibling);
01185   return NS_OK;
01186 }
01187 
01188 nsresult
01189 inDOMView::AppendKidsToArray(nsIDOMNodeList* aKids,
01190                              nsCOMArray<nsIDOMNode>& aArray)
01191 {
01192   PRUint32 l = 0;
01193   aKids->GetLength(&l);
01194   nsCOMPtr<nsIDOMNode> kid;
01195   PRUint16 nodeType = 0;
01196 
01197   // Try and get DOM Utils in case we don't have one yet.
01198   if (mShowWhitespaceNodes && !mDOMUtils) {
01199     mDOMUtils = do_CreateInstance("@mozilla.org/inspector/dom-utils;1");
01200   }
01201 
01202   for (PRUint32 i = 0; i < l; ++i) {
01203     aKids->Item(i, getter_AddRefs(kid));
01204     kid->GetNodeType(&nodeType);
01205 
01206     NS_ASSERTION(nodeType && nodeType <= nsIDOMNode::NOTATION_NODE,
01207                  "Unknown node type. "
01208                  "Were new types added to the spec?");
01209     // As of DOM Level 2 Core and Traversal, each NodeFilter constant
01210     // is defined as the lower nth bit in the NodeFilter bitmask,
01211     // where n is the numeric constant of the nodeType it represents.
01212     // If this invariant ever changes, we will need to update the
01213     // following line.
01214     PRUint32 filterForNodeType = 1 << (nodeType - 1);
01215 
01216     if (mWhatToShow & filterForNodeType) {
01217       if ((nodeType == nsIDOMNode::TEXT_NODE ||
01218            nodeType == nsIDOMNode::COMMENT_NODE) &&
01219           !mShowWhitespaceNodes && mDOMUtils) {
01220         nsCOMPtr<nsIDOMCharacterData> data = do_QueryInterface(kid);
01221         NS_ASSERTION(data, "Does not implement nsIDOMCharacterData!");
01222         PRBool ignore;
01223         mDOMUtils->IsIgnorableWhitespace(data, &ignore);
01224         if (ignore) {
01225           continue;
01226         }
01227       }
01228 
01229       aArray.AppendObject(kid);
01230     }
01231   }
01232 
01233   return NS_OK;
01234 }
01235 
01236 nsresult
01237 inDOMView::AppendAttrsToArray(nsIDOMNamedNodeMap* aKids,
01238                               nsCOMArray<nsIDOMNode>& aArray)
01239 {
01240   PRUint32 l = 0;
01241   aKids->GetLength(&l);
01242   nsCOMPtr<nsIDOMNode> kid;
01243   for (PRUint32 i = 0; i < l; ++i) {
01244     aKids->Item(i, getter_AddRefs(kid));
01245     aArray.AppendObject(kid);
01246   }
01247   return NS_OK;
01248 }