123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284 |
- /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
- /* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
- #include "inDOMView.h"
- #include "inIDOMUtils.h"
- #include "inLayoutUtils.h"
- #include "nsString.h"
- #include "nsReadableUtils.h"
- #include "nsIDOMNode.h"
- #include "nsIDOMNodeFilter.h"
- #include "nsIDOMNodeList.h"
- #include "nsIDOMCharacterData.h"
- #include "nsIDOMAttr.h"
- #include "nsIDOMMozNamedAttrMap.h"
- #include "nsIDOMMutationEvent.h"
- #include "nsBindingManager.h"
- #include "nsNameSpaceManager.h"
- #include "nsIDocument.h"
- #include "nsIServiceManager.h"
- #include "nsITreeColumns.h"
- #include "nsITreeBoxObject.h"
- #include "mozilla/dom/Element.h"
- #include "mozilla/Services.h"
- #ifdef ACCESSIBILITY
- #include "nsAccessibilityService.h"
- #endif
- using namespace mozilla;
- ////////////////////////////////////////////////////////////////////////
- // inDOMViewNode
- class inDOMViewNode
- {
- public:
- inDOMViewNode() {}
- explicit inDOMViewNode(nsIDOMNode* aNode);
- ~inDOMViewNode();
- nsCOMPtr<nsIDOMNode> node;
- inDOMViewNode* parent;
- inDOMViewNode* next;
- inDOMViewNode* previous;
- int32_t level;
- bool isOpen;
- bool isContainer;
- bool hasAnonymous;
- bool hasSubDocument;
- };
- inDOMViewNode::inDOMViewNode(nsIDOMNode* aNode) :
- node(aNode),
- parent(nullptr),
- next(nullptr),
- previous(nullptr),
- level(0),
- isOpen(false),
- isContainer(false),
- hasAnonymous(false),
- hasSubDocument(false)
- {
- }
- inDOMViewNode::~inDOMViewNode()
- {
- }
- ////////////////////////////////////////////////////////////////////////
- inDOMView::inDOMView() :
- mShowAnonymous(false),
- mShowSubDocuments(false),
- mShowWhitespaceNodes(true),
- mShowAccessibleNodes(false),
- mWhatToShow(nsIDOMNodeFilter::SHOW_ALL)
- {
- }
- inDOMView::~inDOMView()
- {
- SetRootNode(nullptr);
- }
- ////////////////////////////////////////////////////////////////////////
- // nsISupports
- NS_IMPL_ISUPPORTS(inDOMView,
- inIDOMView,
- nsITreeView,
- nsIMutationObserver)
- ////////////////////////////////////////////////////////////////////////
- // inIDOMView
- NS_IMETHODIMP
- inDOMView::GetRootNode(nsIDOMNode** aNode)
- {
- *aNode = mRootNode;
- NS_IF_ADDREF(*aNode);
- return NS_OK;
- }
- NS_IMETHODIMP
- inDOMView::SetRootNode(nsIDOMNode* aNode)
- {
- if (mTree)
- mTree->BeginUpdateBatch();
- if (mRootDocument) {
- // remove previous document observer
- nsCOMPtr<nsINode> doc(do_QueryInterface(mRootDocument));
- if (doc)
- doc->RemoveMutationObserver(this);
- }
- RemoveAllNodes();
- mRootNode = aNode;
- if (aNode) {
- // If we are able to show element nodes, then start with the root node
- // as the first node in the buffer
- if (mWhatToShow & nsIDOMNodeFilter::SHOW_ELEMENT) {
- // allocate new node array
- AppendNode(CreateNode(aNode, nullptr));
- } else {
- // place only the children of the root node in the buffer
- ExpandNode(-1);
- }
- // store an owning reference to document so that it isn't
- // destroyed before we are
- mRootDocument = do_QueryInterface(aNode);
- if (!mRootDocument) {
- aNode->GetOwnerDocument(getter_AddRefs(mRootDocument));
- }
- // add document observer
- nsCOMPtr<nsINode> doc(do_QueryInterface(mRootDocument));
- if (doc)
- doc->AddMutationObserver(this);
- } else {
- mRootDocument = nullptr;
- }
- if (mTree)
- mTree->EndUpdateBatch();
- return NS_OK;
- }
- NS_IMETHODIMP
- inDOMView::GetNodeFromRowIndex(int32_t rowIndex, nsIDOMNode **_retval)
- {
- inDOMViewNode* viewNode = nullptr;
- RowToNode(rowIndex, &viewNode);
- if (!viewNode) return NS_ERROR_FAILURE;
- *_retval = viewNode->node;
- NS_IF_ADDREF(*_retval);
- return NS_OK;
- }
- NS_IMETHODIMP
- inDOMView::GetRowIndexFromNode(nsIDOMNode *node, int32_t *_retval)
- {
- NodeToRow(node, _retval);
- return NS_OK;
- }
- NS_IMETHODIMP
- inDOMView::GetShowAnonymousContent(bool *aShowAnonymousContent)
- {
- *aShowAnonymousContent = mShowAnonymous;
- return NS_OK;
- }
- NS_IMETHODIMP
- inDOMView::SetShowAnonymousContent(bool aShowAnonymousContent)
- {
- mShowAnonymous = aShowAnonymousContent;
- return NS_OK;
- }
- NS_IMETHODIMP
- inDOMView::GetShowSubDocuments(bool *aShowSubDocuments)
- {
- *aShowSubDocuments = mShowSubDocuments;
- return NS_OK;
- }
- NS_IMETHODIMP
- inDOMView::SetShowSubDocuments(bool aShowSubDocuments)
- {
- mShowSubDocuments = aShowSubDocuments;
- return NS_OK;
- }
- NS_IMETHODIMP
- inDOMView::GetShowWhitespaceNodes(bool *aShowWhitespaceNodes)
- {
- *aShowWhitespaceNodes = mShowWhitespaceNodes;
- return NS_OK;
- }
- NS_IMETHODIMP
- inDOMView::SetShowWhitespaceNodes(bool aShowWhitespaceNodes)
- {
- mShowWhitespaceNodes = aShowWhitespaceNodes;
- return NS_OK;
- }
- NS_IMETHODIMP
- inDOMView::GetShowAccessibleNodes(bool *aShowAccessibleNodes)
- {
- *aShowAccessibleNodes = mShowAccessibleNodes;
- return NS_OK;
- }
- NS_IMETHODIMP
- inDOMView::SetShowAccessibleNodes(bool aShowAccessibleNodes)
- {
- mShowAccessibleNodes = aShowAccessibleNodes;
- return NS_OK;
- }
- NS_IMETHODIMP
- inDOMView::GetWhatToShow(uint32_t *aWhatToShow)
- {
- *aWhatToShow = mWhatToShow;
- return NS_OK;
- }
- NS_IMETHODIMP
- inDOMView::SetWhatToShow(uint32_t aWhatToShow)
- {
- mWhatToShow = aWhatToShow;
- return NS_OK;
- }
- NS_IMETHODIMP
- inDOMView::Rebuild()
- {
- nsCOMPtr<nsIDOMNode> root;
- GetRootNode(getter_AddRefs(root));
- SetRootNode(root);
- return NS_OK;
- }
- ////////////////////////////////////////////////////////////////////////
- // nsITreeView
- NS_IMETHODIMP
- inDOMView::GetRowCount(int32_t *aRowCount)
- {
- *aRowCount = GetRowCount();
- return NS_OK;
- }
- NS_IMETHODIMP
- inDOMView::GetRowProperties(int32_t index, nsAString& aProps)
- {
- return NS_OK;
- }
- NS_IMETHODIMP
- inDOMView::GetCellProperties(int32_t row, nsITreeColumn* col,
- nsAString& aProps)
- {
- inDOMViewNode* node = nullptr;
- RowToNode(row, &node);
- if (!node) return NS_ERROR_FAILURE;
- nsCOMPtr<nsIContent> content = do_QueryInterface(node->node);
- if (content && content->IsInAnonymousSubtree()) {
- aProps.AppendLiteral("anonymous ");
- }
- uint16_t nodeType;
- node->node->GetNodeType(&nodeType);
- switch (nodeType) {
- case nsIDOMNode::ELEMENT_NODE:
- aProps.AppendLiteral("ELEMENT_NODE");
- break;
- case nsIDOMNode::ATTRIBUTE_NODE:
- aProps.AppendLiteral("ATTRIBUTE_NODE");
- break;
- case nsIDOMNode::TEXT_NODE:
- aProps.AppendLiteral("TEXT_NODE");
- break;
- case nsIDOMNode::CDATA_SECTION_NODE:
- aProps.AppendLiteral("CDATA_SECTION_NODE");
- break;
- case nsIDOMNode::ENTITY_REFERENCE_NODE:
- aProps.AppendLiteral("ENTITY_REFERENCE_NODE");
- break;
- case nsIDOMNode::ENTITY_NODE:
- aProps.AppendLiteral("ENTITY_NODE");
- break;
- case nsIDOMNode::PROCESSING_INSTRUCTION_NODE:
- aProps.AppendLiteral("PROCESSING_INSTRUCTION_NODE");
- break;
- case nsIDOMNode::COMMENT_NODE:
- aProps.AppendLiteral("COMMENT_NODE");
- break;
- case nsIDOMNode::DOCUMENT_NODE:
- aProps.AppendLiteral("DOCUMENT_NODE");
- break;
- case nsIDOMNode::DOCUMENT_TYPE_NODE:
- aProps.AppendLiteral("DOCUMENT_TYPE_NODE");
- break;
- case nsIDOMNode::DOCUMENT_FRAGMENT_NODE:
- aProps.AppendLiteral("DOCUMENT_FRAGMENT_NODE");
- break;
- case nsIDOMNode::NOTATION_NODE:
- aProps.AppendLiteral("NOTATION_NODE");
- break;
- }
- #ifdef ACCESSIBILITY
- if (mShowAccessibleNodes) {
- nsAccessibilityService* accService = GetOrCreateAccService();
- NS_ENSURE_TRUE(accService, NS_ERROR_FAILURE);
- if (accService->HasAccessible(node->node))
- aProps.AppendLiteral(" ACCESSIBLE_NODE");
- }
- #endif
- return NS_OK;
- }
- NS_IMETHODIMP
- inDOMView::GetColumnProperties(nsITreeColumn* col, nsAString& aProps)
- {
- return NS_OK;
- }
- NS_IMETHODIMP
- inDOMView::GetImageSrc(int32_t row, nsITreeColumn* col, nsAString& _retval)
- {
- return NS_OK;
- }
- NS_IMETHODIMP
- inDOMView::GetProgressMode(int32_t row, nsITreeColumn* col, int32_t* _retval)
- {
- return NS_OK;
- }
- NS_IMETHODIMP
- inDOMView::GetCellValue(int32_t row, nsITreeColumn* col, nsAString& _retval)
- {
- return NS_OK;
- }
- NS_IMETHODIMP
- inDOMView::GetCellText(int32_t row, nsITreeColumn* col, nsAString& _retval)
- {
- inDOMViewNode* node = nullptr;
- RowToNode(row, &node);
- if (!node) return NS_ERROR_FAILURE;
- nsIDOMNode* domNode = node->node;
- nsAutoString colID;
- col->GetId(colID);
- if (colID.EqualsLiteral("colNodeName"))
- domNode->GetNodeName(_retval);
- else if (colID.EqualsLiteral("colLocalName"))
- domNode->GetLocalName(_retval);
- else if (colID.EqualsLiteral("colPrefix"))
- domNode->GetPrefix(_retval);
- else if (colID.EqualsLiteral("colNamespaceURI"))
- domNode->GetNamespaceURI(_retval);
- else if (colID.EqualsLiteral("colNodeType")) {
- uint16_t nodeType;
- domNode->GetNodeType(&nodeType);
- nsAutoString temp;
- temp.AppendInt(int32_t(nodeType));
- _retval = temp;
- } else if (colID.EqualsLiteral("colNodeValue"))
- domNode->GetNodeValue(_retval);
- else {
- if (StringBeginsWith(colID, NS_LITERAL_STRING("col@"))) {
- nsCOMPtr<nsIDOMElement> el = do_QueryInterface(node->node);
- if (el) {
- nsAutoString attr;
- colID.Right(attr, colID.Length()-4); // have to use this because Substring is crashing on me!
- el->GetAttribute(attr, _retval);
- }
- }
- }
- return NS_OK;
- }
- NS_IMETHODIMP
- inDOMView::IsContainer(int32_t index, bool *_retval)
- {
- inDOMViewNode* node = nullptr;
- RowToNode(index, &node);
- if (!node) return NS_ERROR_FAILURE;
- *_retval = node->isContainer;
- return NS_OK;
- }
- NS_IMETHODIMP
- inDOMView::IsContainerOpen(int32_t index, bool *_retval)
- {
- inDOMViewNode* node = nullptr;
- RowToNode(index, &node);
- if (!node) return NS_ERROR_FAILURE;
- *_retval = node->isOpen;
- return NS_OK;
- }
- NS_IMETHODIMP
- inDOMView::IsContainerEmpty(int32_t index, bool *_retval)
- {
- inDOMViewNode* node = nullptr;
- RowToNode(index, &node);
- if (!node) return NS_ERROR_FAILURE;
- *_retval = node->isContainer ? false : true;
- return NS_OK;
- }
- NS_IMETHODIMP
- inDOMView::GetLevel(int32_t index, int32_t *_retval)
- {
- inDOMViewNode* node = nullptr;
- RowToNode(index, &node);
- if (!node) return NS_ERROR_FAILURE;
- *_retval = node->level;
- return NS_OK;
- }
- NS_IMETHODIMP
- inDOMView::GetParentIndex(int32_t rowIndex, int32_t *_retval)
- {
- inDOMViewNode* node = nullptr;
- RowToNode(rowIndex, &node);
- if (!node) return NS_ERROR_FAILURE;
- // GetParentIndex returns -1 if there is no parent
- *_retval = -1;
-
- inDOMViewNode* checkNode = nullptr;
- int32_t i = rowIndex - 1;
- do {
- nsresult rv = RowToNode(i, &checkNode);
- if (NS_FAILED(rv)) {
- // No parent. Just break out.
- break;
- }
-
- if (checkNode == node->parent) {
- *_retval = i;
- return NS_OK;
- }
- --i;
- } while (checkNode);
- return NS_OK;
- }
- NS_IMETHODIMP
- inDOMView::HasNextSibling(int32_t rowIndex, int32_t afterIndex, bool *_retval)
- {
- inDOMViewNode* node = nullptr;
- RowToNode(rowIndex, &node);
- if (!node) return NS_ERROR_FAILURE;
- *_retval = node->next != nullptr;
- return NS_OK;
- }
- NS_IMETHODIMP
- inDOMView::ToggleOpenState(int32_t index)
- {
- inDOMViewNode* node = nullptr;
- RowToNode(index, &node);
- if (!node) return NS_ERROR_FAILURE;
- int32_t oldCount = GetRowCount();
- if (node->isOpen)
- CollapseNode(index);
- else
- ExpandNode(index);
- // Update the twisty.
- mTree->InvalidateRow(index);
- mTree->RowCountChanged(index+1, GetRowCount() - oldCount);
- return NS_OK;
- }
- NS_IMETHODIMP
- inDOMView::SetTree(nsITreeBoxObject *tree)
- {
- mTree = tree;
- return NS_OK;
- }
- NS_IMETHODIMP
- inDOMView::GetSelection(nsITreeSelection * *aSelection)
- {
- *aSelection = mSelection;
- NS_IF_ADDREF(*aSelection);
- return NS_OK;
- }
- NS_IMETHODIMP inDOMView::SetSelection(nsITreeSelection * aSelection)
- {
- mSelection = aSelection;
- return NS_OK;
- }
- NS_IMETHODIMP
- inDOMView::SelectionChanged()
- {
- return NS_OK;
- }
- NS_IMETHODIMP
- inDOMView::SetCellValue(int32_t row, nsITreeColumn* col, const nsAString& value)
- {
- return NS_OK;
- }
- NS_IMETHODIMP
- inDOMView::SetCellText(int32_t row, nsITreeColumn* col, const nsAString& value)
- {
- return NS_OK;
- }
- NS_IMETHODIMP
- inDOMView::CycleHeader(nsITreeColumn* col)
- {
- return NS_OK;
- }
- NS_IMETHODIMP
- inDOMView::CycleCell(int32_t row, nsITreeColumn* col)
- {
- return NS_OK;
- }
- NS_IMETHODIMP
- inDOMView::IsEditable(int32_t row, nsITreeColumn* col, bool *_retval)
- {
- return NS_OK;
- }
- NS_IMETHODIMP
- inDOMView::IsSelectable(int32_t row, nsITreeColumn* col, bool *_retval)
- {
- return NS_OK;
- }
- NS_IMETHODIMP
- inDOMView::IsSeparator(int32_t index, bool *_retval)
- {
- return NS_OK;
- }
- NS_IMETHODIMP
- inDOMView::IsSorted(bool *_retval)
- {
- return NS_OK;
- }
- NS_IMETHODIMP
- inDOMView::CanDrop(int32_t index, int32_t orientation,
- nsIDOMDataTransfer* aDataTransfer, bool *_retval)
- {
- *_retval = false;
- return NS_OK;
- }
- NS_IMETHODIMP
- inDOMView::Drop(int32_t row, int32_t orientation, nsIDOMDataTransfer* aDataTransfer)
- {
- return NS_OK;
- }
- NS_IMETHODIMP
- inDOMView::PerformAction(const char16_t *action)
- {
- return NS_OK;
- }
- NS_IMETHODIMP
- inDOMView::PerformActionOnRow(const char16_t *action, int32_t row)
- {
- return NS_OK;
- }
- NS_IMETHODIMP
- inDOMView::PerformActionOnCell(const char16_t* action, int32_t row, nsITreeColumn* col)
- {
- return NS_OK;
- }
- ///////////////////////////////////////////////////////////////////////
- // nsIMutationObserver
- void
- inDOMView::NodeWillBeDestroyed(const nsINode* aNode)
- {
- NS_NOTREACHED("Document destroyed while we're holding a strong ref to it");
- }
- void
- inDOMView::AttributeChanged(nsIDocument* aDocument, dom::Element* aElement,
- int32_t aNameSpaceID, nsIAtom* aAttribute,
- int32_t aModType,
- const nsAttrValue* aOldValue)
- {
- if (!mTree) {
- return;
- }
- if (!(mWhatToShow & nsIDOMNodeFilter::SHOW_ATTRIBUTE)) {
- return;
- }
- nsCOMPtr<nsIMutationObserver> kungFuDeathGrip(this);
-
- // get the dom attribute node, if there is any
- nsCOMPtr<nsIDOMElement> el(do_QueryInterface(aElement));
- nsCOMPtr<nsIDOMAttr> domAttr;
- nsDependentAtomString attrStr(aAttribute);
- if (aNameSpaceID) {
- nsNameSpaceManager* nsm = nsNameSpaceManager::GetInstance();
- if (!nsm) {
- // we can't find out which attribute we want :(
- return;
- }
- nsString attrNS;
- nsresult rv = nsm->GetNameSpaceURI(aNameSpaceID, attrNS);
- if (NS_FAILED(rv)) {
- return;
- }
- (void)el->GetAttributeNodeNS(attrNS, attrStr, getter_AddRefs(domAttr));
- } else {
- (void)el->GetAttributeNode(attrStr, getter_AddRefs(domAttr));
- }
- if (aModType == nsIDOMMutationEvent::MODIFICATION) {
- // No fancy stuff here, just invalidate the changed row
- if (!domAttr) {
- return;
- }
- int32_t row = 0;
- NodeToRow(domAttr, &row);
- mTree->InvalidateRange(row, row);
- } else if (aModType == nsIDOMMutationEvent::ADDITION) {
- if (!domAttr) {
- return;
- }
- // get the number of attributes on this content node
- nsCOMPtr<nsIDOMMozNamedAttrMap> attrs;
- el->GetAttributes(getter_AddRefs(attrs));
- uint32_t attrCount;
- attrs->GetLength(&attrCount);
- inDOMViewNode* contentNode = nullptr;
- int32_t contentRow;
- int32_t attrRow;
- if (mRootNode == el &&
- !(mWhatToShow & nsIDOMNodeFilter::SHOW_ELEMENT)) {
- // if this view has a root node but is not displaying it,
- // it is ok to act as if the changed attribute is on the root.
- attrRow = attrCount - 1;
- } else {
- if (NS_FAILED(NodeToRow(el, &contentRow))) {
- return;
- }
- RowToNode(contentRow, &contentNode);
- if (!contentNode->isOpen) {
- return;
- }
- attrRow = contentRow + attrCount;
- }
- inDOMViewNode* newNode = CreateNode(domAttr, contentNode);
- inDOMViewNode* insertNode = nullptr;
- RowToNode(attrRow, &insertNode);
- if (insertNode) {
- if (contentNode &&
- insertNode->level <= contentNode->level) {
- RowToNode(attrRow-1, &insertNode);
- InsertLinkAfter(newNode, insertNode);
- } else
- InsertLinkBefore(newNode, insertNode);
- }
- InsertNode(newNode, attrRow);
- mTree->RowCountChanged(attrRow, 1);
- } else if (aModType == nsIDOMMutationEvent::REMOVAL) {
- // At this point, the attribute is already gone from the DOM, but is still represented
- // in our mRows array. Search through the content node's children for the corresponding
- // node and remove it.
- // get the row of the content node
- inDOMViewNode* contentNode = nullptr;
- int32_t contentRow;
- int32_t baseLevel;
- if (NS_SUCCEEDED(NodeToRow(el, &contentRow))) {
- RowToNode(contentRow, &contentNode);
- baseLevel = contentNode->level;
- } else {
- if (mRootNode == el) {
- contentRow = -1;
- baseLevel = -1;
- } else
- return;
- }
- // search for the attribute node that was removed
- inDOMViewNode* checkNode = nullptr;
- int32_t row = 0;
- for (row = contentRow+1; row < GetRowCount(); ++row) {
- checkNode = GetNodeAt(row);
- if (checkNode->level == baseLevel+1) {
- domAttr = do_QueryInterface(checkNode->node);
- if (domAttr) {
- nsAutoString attrName;
- domAttr->GetNodeName(attrName);
- if (attrName.Equals(attrStr)) {
- // we have found the row for the attribute that was removed
- RemoveLink(checkNode);
- RemoveNode(row);
- mTree->RowCountChanged(row, -1);
- break;
- }
- }
- }
- if (checkNode->level <= baseLevel)
- break;
- }
- }
- }
- void
- inDOMView::ContentAppended(nsIDocument *aDocument,
- nsIContent* aContainer,
- nsIContent* aFirstNewContent,
- int32_t /* unused */)
- {
- if (!mTree) {
- return;
- }
- for (nsIContent* cur = aFirstNewContent; cur; cur = cur->GetNextSibling()) {
- // Our ContentInserted impl doesn't use the index
- ContentInserted(aDocument, aContainer, cur, 0);
- }
- }
- void
- inDOMView::ContentInserted(nsIDocument *aDocument, nsIContent* aContainer,
- nsIContent* aChild, int32_t /* unused */)
- {
- if (!mTree)
- return;
- nsresult rv;
- nsCOMPtr<nsIDOMNode> childDOMNode(do_QueryInterface(aChild));
- nsCOMPtr<nsIDOMNode> parent;
- if (!mDOMUtils) {
- mDOMUtils = services::GetInDOMUtils();
- if (!mDOMUtils) {
- return;
- }
- }
- mDOMUtils->GetParentForNode(childDOMNode, mShowAnonymous,
- getter_AddRefs(parent));
- // find the inDOMViewNode for the parent of the inserted content
- int32_t parentRow = 0;
- if (NS_FAILED(rv = NodeToRow(parent, &parentRow)))
- return;
- inDOMViewNode* parentNode = nullptr;
- if (NS_FAILED(rv = RowToNode(parentRow, &parentNode)))
- return;
- nsCOMPtr<nsIMutationObserver> kungFuDeathGrip(this);
-
- if (!parentNode->isOpen) {
- // Parent is not open, so don't bother creating tree rows for the
- // kids. But do indicate that it's now a container, if needed.
- if (!parentNode->isContainer) {
- parentNode->isContainer = true;
- mTree->InvalidateRow(parentRow);
- }
- return;
- }
- // get the previous sibling of the inserted content
- nsCOMPtr<nsIDOMNode> previous;
- GetRealPreviousSibling(childDOMNode, parent, getter_AddRefs(previous));
- inDOMViewNode* previousNode = nullptr;
- int32_t row = 0;
- if (previous) {
- // find the inDOMViewNode for the previous sibling of the inserted content
- int32_t previousRow = 0;
- if (NS_FAILED(rv = NodeToRow(previous, &previousRow)))
- return;
- if (NS_FAILED(rv = RowToNode(previousRow, &previousNode)))
- return;
- // get the last descendant of the previous row, which is the row
- // after which to insert this new row
- GetLastDescendantOf(previousNode, previousRow, &row);
- ++row;
- } else {
- // there is no previous sibling, so the new row will be inserted after the parent
- row = parentRow+1;
- }
- inDOMViewNode* newNode = CreateNode(childDOMNode, parentNode);
- if (previous) {
- InsertLinkAfter(newNode, previousNode);
- } else {
- int32_t firstChildRow;
- if (NS_SUCCEEDED(GetFirstDescendantOf(parentNode, parentRow, &firstChildRow))) {
- inDOMViewNode* firstChild;
- RowToNode(firstChildRow, &firstChild);
- InsertLinkBefore(newNode, firstChild);
- }
- }
- // insert new node
- InsertNode(newNode, row);
- mTree->RowCountChanged(row, 1);
- }
- void
- inDOMView::ContentRemoved(nsIDocument *aDocument, nsIContent* aContainer,
- nsIContent* aChild, int32_t aIndexInContainer,
- nsIContent* aPreviousSibling)
- {
- if (!mTree)
- return;
- nsresult rv;
- // find the inDOMViewNode for the old child
- nsCOMPtr<nsIDOMNode> oldDOMNode(do_QueryInterface(aChild));
- int32_t row = 0;
- if (NS_FAILED(rv = NodeToRow(oldDOMNode, &row)))
- return;
- inDOMViewNode* oldNode;
- if (NS_FAILED(rv = RowToNode(row, &oldNode)))
- return;
- nsCOMPtr<nsIMutationObserver> kungFuDeathGrip(this);
-
- // The parent may no longer be a container. Note that we don't want
- // to access oldNode after calling RemoveNode, so do this now.
- inDOMViewNode* parentNode = oldNode->parent;
- bool isOnlyChild = oldNode->previous == nullptr && oldNode->next == nullptr;
-
- // Keep track of how many rows we are removing. It's at least one,
- // but if we're open it's more.
- int32_t oldCount = GetRowCount();
-
- if (oldNode->isOpen)
- CollapseNode(row);
- RemoveLink(oldNode);
- RemoveNode(row);
- if (isOnlyChild) {
- // Fix up the parent
- parentNode->isContainer = false;
- parentNode->isOpen = false;
- mTree->InvalidateRow(NodeToRow(parentNode));
- }
-
- mTree->RowCountChanged(row, GetRowCount() - oldCount);
- }
- ///////////////////////////////////////////////////////////////////////
- // inDOMView
- //////// NODE MANAGEMENT
- inDOMViewNode*
- inDOMView::GetNodeAt(int32_t aRow)
- {
- return mNodes.ElementAt(aRow);
- }
- int32_t
- inDOMView::GetRowCount()
- {
- return mNodes.Length();
- }
- int32_t
- inDOMView::NodeToRow(inDOMViewNode* aNode)
- {
- return mNodes.IndexOf(aNode);
- }
- inDOMViewNode*
- inDOMView::CreateNode(nsIDOMNode* aNode, inDOMViewNode* aParent)
- {
- inDOMViewNode* viewNode = new inDOMViewNode(aNode);
- viewNode->level = aParent ? aParent->level+1 : 0;
- viewNode->parent = aParent;
- nsCOMArray<nsIDOMNode> grandKids;
- GetChildNodesFor(aNode, grandKids);
- viewNode->isContainer = (grandKids.Count() > 0);
- return viewNode;
- }
- bool
- inDOMView::RowOutOfBounds(int32_t aRow, int32_t aCount)
- {
- return aRow < 0 || aRow >= GetRowCount() || aCount+aRow > GetRowCount();
- }
- void
- inDOMView::AppendNode(inDOMViewNode* aNode)
- {
- mNodes.AppendElement(aNode);
- }
- void
- inDOMView::InsertNode(inDOMViewNode* aNode, int32_t aRow)
- {
- if (RowOutOfBounds(aRow, 1))
- AppendNode(aNode);
- else
- mNodes.InsertElementAt(aRow, aNode);
- }
- void
- inDOMView::RemoveNode(int32_t aRow)
- {
- if (RowOutOfBounds(aRow, 1))
- return;
- delete GetNodeAt(aRow);
- mNodes.RemoveElementAt(aRow);
- }
- void
- inDOMView::ReplaceNode(inDOMViewNode* aNode, int32_t aRow)
- {
- if (RowOutOfBounds(aRow, 1))
- return;
- delete GetNodeAt(aRow);
- mNodes.ElementAt(aRow) = aNode;
- }
- void
- inDOMView::InsertNodes(nsTArray<inDOMViewNode*>& aNodes, int32_t aRow)
- {
- if (aRow < 0 || aRow > GetRowCount())
- return;
- mNodes.InsertElementsAt(aRow, aNodes);
- }
- void
- inDOMView::RemoveNodes(int32_t aRow, int32_t aCount)
- {
- if (aRow < 0)
- return;
- int32_t rowCount = GetRowCount();
- for (int32_t i = aRow; i < aRow+aCount && i < rowCount; ++i) {
- delete GetNodeAt(i);
- }
- mNodes.RemoveElementsAt(aRow, aCount);
- }
- void
- inDOMView::RemoveAllNodes()
- {
- int32_t rowCount = GetRowCount();
- for (int32_t i = 0; i < rowCount; ++i) {
- delete GetNodeAt(i);
- }
- mNodes.Clear();
- }
- void
- inDOMView::ExpandNode(int32_t aRow)
- {
- inDOMViewNode* node = nullptr;
- RowToNode(aRow, &node);
- nsCOMArray<nsIDOMNode> kids;
- GetChildNodesFor(node ? node->node : mRootNode,
- kids);
- int32_t kidCount = kids.Count();
- nsTArray<inDOMViewNode*> list(kidCount);
- inDOMViewNode* newNode = nullptr;
- inDOMViewNode* prevNode = nullptr;
- for (int32_t i = 0; i < kidCount; ++i) {
- newNode = CreateNode(kids[i], node);
- list.AppendElement(newNode);
- if (prevNode)
- prevNode->next = newNode;
- newNode->previous = prevNode;
- prevNode = newNode;
- }
- InsertNodes(list, aRow+1);
- if (node)
- node->isOpen = true;
- }
- void
- inDOMView::CollapseNode(int32_t aRow)
- {
- inDOMViewNode* node = nullptr;
- nsresult rv = RowToNode(aRow, &node);
- if (NS_FAILED(rv)) {
- return;
- }
- int32_t row = 0;
- GetLastDescendantOf(node, aRow, &row);
- RemoveNodes(aRow+1, row-aRow);
- node->isOpen = false;
- }
- //////// NODE AND ROW CONVERSION
- nsresult
- inDOMView::RowToNode(int32_t aRow, inDOMViewNode** aNode)
- {
- if (aRow < 0 || aRow >= GetRowCount())
- return NS_ERROR_FAILURE;
- *aNode = GetNodeAt(aRow);
- return NS_OK;
- }
- nsresult
- inDOMView::NodeToRow(nsIDOMNode* aNode, int32_t* aRow)
- {
- int32_t rowCount = GetRowCount();
- for (int32_t i = 0; i < rowCount; ++i) {
- if (GetNodeAt(i)->node == aNode) {
- *aRow = i;
- return NS_OK;
- }
- }
- *aRow = -1;
- return NS_ERROR_FAILURE;
- }
- //////// NODE HIERARCHY MUTATION
- void
- inDOMView::InsertLinkAfter(inDOMViewNode* aNode, inDOMViewNode* aInsertAfter)
- {
- if (aInsertAfter->next)
- aInsertAfter->next->previous = aNode;
- aNode->next = aInsertAfter->next;
- aInsertAfter->next = aNode;
- aNode->previous = aInsertAfter;
- }
- void
- inDOMView::InsertLinkBefore(inDOMViewNode* aNode, inDOMViewNode* aInsertBefore)
- {
- if (aInsertBefore->previous)
- aInsertBefore->previous->next = aNode;
- aNode->previous = aInsertBefore->previous;
- aInsertBefore->previous = aNode;
- aNode->next = aInsertBefore;
- }
- void
- inDOMView::RemoveLink(inDOMViewNode* aNode)
- {
- if (aNode->previous)
- aNode->previous->next = aNode->next;
- if (aNode->next)
- aNode->next->previous = aNode->previous;
- }
- void
- inDOMView::ReplaceLink(inDOMViewNode* aNewNode, inDOMViewNode* aOldNode)
- {
- if (aOldNode->previous)
- aOldNode->previous->next = aNewNode;
- if (aOldNode->next)
- aOldNode->next->previous = aNewNode;
- aNewNode->next = aOldNode->next;
- aNewNode->previous = aOldNode->previous;
- }
- //////// NODE HIERARCHY UTILITIES
- nsresult
- inDOMView::GetFirstDescendantOf(inDOMViewNode* aNode, int32_t aRow, int32_t* aResult)
- {
- // get the first node that is a descendant of the previous sibling
- int32_t row = 0;
- inDOMViewNode* node;
- for (row = aRow+1; row < GetRowCount(); ++row) {
- node = GetNodeAt(row);
- if (node->parent == aNode) {
- *aResult = row;
- return NS_OK;
- }
- if (node->level <= aNode->level)
- break;
- }
- return NS_ERROR_FAILURE;
- }
- nsresult
- inDOMView::GetLastDescendantOf(inDOMViewNode* aNode, int32_t aRow, int32_t* aResult)
- {
- // get the last node that is a descendant of the previous sibling
- int32_t row = 0;
- for (row = aRow+1; row < GetRowCount(); ++row) {
- if (GetNodeAt(row)->level <= aNode->level)
- break;
- }
- *aResult = row-1;
- return NS_OK;
- }
- //////// DOM UTILITIES
- nsresult
- inDOMView::GetChildNodesFor(nsIDOMNode* aNode, nsCOMArray<nsIDOMNode>& aResult)
- {
- NS_ENSURE_ARG(aNode);
- // attribute nodes
- if (mWhatToShow & nsIDOMNodeFilter::SHOW_ATTRIBUTE) {
- nsCOMPtr<nsIDOMElement> element = do_QueryInterface(aNode);
- if (element) {
- nsCOMPtr<nsIDOMMozNamedAttrMap> attrs;
- element->GetAttributes(getter_AddRefs(attrs));
- if (attrs) {
- AppendAttrsToArray(attrs, aResult);
- }
- }
- }
- if (mWhatToShow & nsIDOMNodeFilter::SHOW_ELEMENT) {
- nsCOMPtr<nsIDOMNodeList> kids;
- if (!mDOMUtils) {
- mDOMUtils = services::GetInDOMUtils();
- if (!mDOMUtils) {
- return NS_ERROR_FAILURE;
- }
- }
- mDOMUtils->GetChildrenForNode(aNode, mShowAnonymous,
- getter_AddRefs(kids));
- if (kids) {
- AppendKidsToArray(kids, aResult);
- }
- }
- if (mShowSubDocuments) {
- nsCOMPtr<nsIDOMNode> domdoc =
- do_QueryInterface(inLayoutUtils::GetSubDocumentFor(aNode));
- if (domdoc) {
- aResult.AppendObject(domdoc);
- }
- }
- return NS_OK;
- }
- nsresult
- inDOMView::GetRealPreviousSibling(nsIDOMNode* aNode, nsIDOMNode* aRealParent, nsIDOMNode** aSibling)
- {
- // XXXjrh: This won't work for some cases during some situations where XBL insertion points
- // are involved. Fix me!
- aNode->GetPreviousSibling(aSibling);
- return NS_OK;
- }
- nsresult
- inDOMView::AppendKidsToArray(nsIDOMNodeList* aKids,
- nsCOMArray<nsIDOMNode>& aArray)
- {
- uint32_t l = 0;
- aKids->GetLength(&l);
- nsCOMPtr<nsIDOMNode> kid;
- uint16_t nodeType = 0;
- // Try and get DOM Utils in case we don't have one yet.
- if (!mShowWhitespaceNodes && !mDOMUtils) {
- mDOMUtils = services::GetInDOMUtils();
- }
- for (uint32_t i = 0; i < l; ++i) {
- aKids->Item(i, getter_AddRefs(kid));
- kid->GetNodeType(&nodeType);
- NS_ASSERTION(nodeType && nodeType <= nsIDOMNode::NOTATION_NODE,
- "Unknown node type. "
- "Were new types added to the spec?");
- // As of DOM Level 2 Core and Traversal, each NodeFilter constant
- // is defined as the lower nth bit in the NodeFilter bitmask,
- // where n is the numeric constant of the nodeType it represents.
- // If this invariant ever changes, we will need to update the
- // following line.
- uint32_t filterForNodeType = 1 << (nodeType - 1);
- if (mWhatToShow & filterForNodeType) {
- if ((nodeType == nsIDOMNode::TEXT_NODE ||
- nodeType == nsIDOMNode::COMMENT_NODE) &&
- !mShowWhitespaceNodes && mDOMUtils) {
- nsCOMPtr<nsIDOMCharacterData> data = do_QueryInterface(kid);
- NS_ASSERTION(data, "Does not implement nsIDOMCharacterData!");
- bool ignore;
- mDOMUtils->IsIgnorableWhitespace(data, &ignore);
- if (ignore) {
- continue;
- }
- }
- aArray.AppendElement(kid.forget());
- }
- }
- return NS_OK;
- }
- nsresult
- inDOMView::AppendAttrsToArray(nsIDOMMozNamedAttrMap* aAttributes,
- nsCOMArray<nsIDOMNode>& aArray)
- {
- uint32_t l = 0;
- aAttributes->GetLength(&l);
- nsCOMPtr<nsIDOMAttr> attribute;
- for (uint32_t i = 0; i < l; ++i) {
- aAttributes->Item(i, getter_AddRefs(attribute));
- aArray.AppendElement(attribute.forget());
- }
- return NS_OK;
- }
|