layout/inspector/inDOMView.cpp

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

michael@0 1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
michael@0 2 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 3 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 5
michael@0 6 #include "inDOMView.h"
michael@0 7 #include "inIDOMUtils.h"
michael@0 8
michael@0 9 #include "inLayoutUtils.h"
michael@0 10
michael@0 11 #include "nsString.h"
michael@0 12 #include "nsReadableUtils.h"
michael@0 13 #include "nsIDOMNode.h"
michael@0 14 #include "nsIDOMNodeFilter.h"
michael@0 15 #include "nsIDOMNodeList.h"
michael@0 16 #include "nsIDOMCharacterData.h"
michael@0 17 #include "nsIDOMAttr.h"
michael@0 18 #include "nsIDOMMozNamedAttrMap.h"
michael@0 19 #include "nsIDOMMutationEvent.h"
michael@0 20 #include "nsBindingManager.h"
michael@0 21 #include "nsNameSpaceManager.h"
michael@0 22 #include "nsIDocument.h"
michael@0 23 #include "nsIServiceManager.h"
michael@0 24 #include "nsITreeColumns.h"
michael@0 25 #include "nsITreeBoxObject.h"
michael@0 26 #include "mozilla/dom/Element.h"
michael@0 27 #include "mozilla/Services.h"
michael@0 28
michael@0 29 #ifdef ACCESSIBILITY
michael@0 30 #include "nsIAccessible.h"
michael@0 31 #include "nsIAccessibilityService.h"
michael@0 32 #endif
michael@0 33
michael@0 34 using namespace mozilla;
michael@0 35
michael@0 36 ////////////////////////////////////////////////////////////////////////
michael@0 37 // inDOMViewNode
michael@0 38
michael@0 39 class inDOMViewNode
michael@0 40 {
michael@0 41 public:
michael@0 42 inDOMViewNode() {}
michael@0 43 inDOMViewNode(nsIDOMNode* aNode);
michael@0 44 ~inDOMViewNode();
michael@0 45
michael@0 46 nsCOMPtr<nsIDOMNode> node;
michael@0 47
michael@0 48 inDOMViewNode* parent;
michael@0 49 inDOMViewNode* next;
michael@0 50 inDOMViewNode* previous;
michael@0 51
michael@0 52 int32_t level;
michael@0 53 bool isOpen;
michael@0 54 bool isContainer;
michael@0 55 bool hasAnonymous;
michael@0 56 bool hasSubDocument;
michael@0 57 };
michael@0 58
michael@0 59 inDOMViewNode::inDOMViewNode(nsIDOMNode* aNode) :
michael@0 60 node(aNode),
michael@0 61 parent(nullptr),
michael@0 62 next(nullptr),
michael@0 63 previous(nullptr),
michael@0 64 level(0),
michael@0 65 isOpen(false),
michael@0 66 isContainer(false),
michael@0 67 hasAnonymous(false),
michael@0 68 hasSubDocument(false)
michael@0 69 {
michael@0 70
michael@0 71 }
michael@0 72
michael@0 73 inDOMViewNode::~inDOMViewNode()
michael@0 74 {
michael@0 75 }
michael@0 76
michael@0 77 ////////////////////////////////////////////////////////////////////////
michael@0 78
michael@0 79 inDOMView::inDOMView() :
michael@0 80 mShowAnonymous(false),
michael@0 81 mShowSubDocuments(false),
michael@0 82 mShowWhitespaceNodes(true),
michael@0 83 mShowAccessibleNodes(false),
michael@0 84 mWhatToShow(nsIDOMNodeFilter::SHOW_ALL)
michael@0 85 {
michael@0 86 }
michael@0 87
michael@0 88 inDOMView::~inDOMView()
michael@0 89 {
michael@0 90 SetRootNode(nullptr);
michael@0 91 }
michael@0 92
michael@0 93
michael@0 94 ////////////////////////////////////////////////////////////////////////
michael@0 95 // nsISupports
michael@0 96
michael@0 97 NS_IMPL_ISUPPORTS(inDOMView,
michael@0 98 inIDOMView,
michael@0 99 nsITreeView,
michael@0 100 nsIMutationObserver)
michael@0 101
michael@0 102 ////////////////////////////////////////////////////////////////////////
michael@0 103 // inIDOMView
michael@0 104
michael@0 105 NS_IMETHODIMP
michael@0 106 inDOMView::GetRootNode(nsIDOMNode** aNode)
michael@0 107 {
michael@0 108 *aNode = mRootNode;
michael@0 109 NS_IF_ADDREF(*aNode);
michael@0 110 return NS_OK;
michael@0 111 }
michael@0 112
michael@0 113 NS_IMETHODIMP
michael@0 114 inDOMView::SetRootNode(nsIDOMNode* aNode)
michael@0 115 {
michael@0 116 if (mTree)
michael@0 117 mTree->BeginUpdateBatch();
michael@0 118
michael@0 119 if (mRootDocument) {
michael@0 120 // remove previous document observer
michael@0 121 nsCOMPtr<nsINode> doc(do_QueryInterface(mRootDocument));
michael@0 122 if (doc)
michael@0 123 doc->RemoveMutationObserver(this);
michael@0 124 }
michael@0 125
michael@0 126 RemoveAllNodes();
michael@0 127
michael@0 128 mRootNode = aNode;
michael@0 129
michael@0 130 if (aNode) {
michael@0 131 // If we are able to show element nodes, then start with the root node
michael@0 132 // as the first node in the buffer
michael@0 133 if (mWhatToShow & nsIDOMNodeFilter::SHOW_ELEMENT) {
michael@0 134 // allocate new node array
michael@0 135 AppendNode(CreateNode(aNode, nullptr));
michael@0 136 } else {
michael@0 137 // place only the children of the root node in the buffer
michael@0 138 ExpandNode(-1);
michael@0 139 }
michael@0 140
michael@0 141 // store an owning reference to document so that it isn't
michael@0 142 // destroyed before we are
michael@0 143 mRootDocument = do_QueryInterface(aNode);
michael@0 144 if (!mRootDocument) {
michael@0 145 aNode->GetOwnerDocument(getter_AddRefs(mRootDocument));
michael@0 146 }
michael@0 147
michael@0 148 // add document observer
michael@0 149 nsCOMPtr<nsINode> doc(do_QueryInterface(mRootDocument));
michael@0 150 if (doc)
michael@0 151 doc->AddMutationObserver(this);
michael@0 152 } else {
michael@0 153 mRootDocument = nullptr;
michael@0 154 }
michael@0 155
michael@0 156 if (mTree)
michael@0 157 mTree->EndUpdateBatch();
michael@0 158
michael@0 159 return NS_OK;
michael@0 160 }
michael@0 161
michael@0 162 NS_IMETHODIMP
michael@0 163 inDOMView::GetNodeFromRowIndex(int32_t rowIndex, nsIDOMNode **_retval)
michael@0 164 {
michael@0 165 inDOMViewNode* viewNode = nullptr;
michael@0 166 RowToNode(rowIndex, &viewNode);
michael@0 167 if (!viewNode) return NS_ERROR_FAILURE;
michael@0 168 *_retval = viewNode->node;
michael@0 169 NS_IF_ADDREF(*_retval);
michael@0 170
michael@0 171 return NS_OK;
michael@0 172 }
michael@0 173
michael@0 174 NS_IMETHODIMP
michael@0 175 inDOMView::GetRowIndexFromNode(nsIDOMNode *node, int32_t *_retval)
michael@0 176 {
michael@0 177 NodeToRow(node, _retval);
michael@0 178 return NS_OK;
michael@0 179 }
michael@0 180
michael@0 181
michael@0 182 NS_IMETHODIMP
michael@0 183 inDOMView::GetShowAnonymousContent(bool *aShowAnonymousContent)
michael@0 184 {
michael@0 185 *aShowAnonymousContent = mShowAnonymous;
michael@0 186 return NS_OK;
michael@0 187 }
michael@0 188
michael@0 189 NS_IMETHODIMP
michael@0 190 inDOMView::SetShowAnonymousContent(bool aShowAnonymousContent)
michael@0 191 {
michael@0 192 mShowAnonymous = aShowAnonymousContent;
michael@0 193 return NS_OK;
michael@0 194 }
michael@0 195
michael@0 196 NS_IMETHODIMP
michael@0 197 inDOMView::GetShowSubDocuments(bool *aShowSubDocuments)
michael@0 198 {
michael@0 199 *aShowSubDocuments = mShowSubDocuments;
michael@0 200 return NS_OK;
michael@0 201 }
michael@0 202
michael@0 203 NS_IMETHODIMP
michael@0 204 inDOMView::SetShowSubDocuments(bool aShowSubDocuments)
michael@0 205 {
michael@0 206 mShowSubDocuments = aShowSubDocuments;
michael@0 207 return NS_OK;
michael@0 208 }
michael@0 209
michael@0 210 NS_IMETHODIMP
michael@0 211 inDOMView::GetShowWhitespaceNodes(bool *aShowWhitespaceNodes)
michael@0 212 {
michael@0 213 *aShowWhitespaceNodes = mShowWhitespaceNodes;
michael@0 214 return NS_OK;
michael@0 215 }
michael@0 216
michael@0 217 NS_IMETHODIMP
michael@0 218 inDOMView::SetShowWhitespaceNodes(bool aShowWhitespaceNodes)
michael@0 219 {
michael@0 220 mShowWhitespaceNodes = aShowWhitespaceNodes;
michael@0 221 return NS_OK;
michael@0 222 }
michael@0 223
michael@0 224 NS_IMETHODIMP
michael@0 225 inDOMView::GetShowAccessibleNodes(bool *aShowAccessibleNodes)
michael@0 226 {
michael@0 227 *aShowAccessibleNodes = mShowAccessibleNodes;
michael@0 228 return NS_OK;
michael@0 229 }
michael@0 230
michael@0 231 NS_IMETHODIMP
michael@0 232 inDOMView::SetShowAccessibleNodes(bool aShowAccessibleNodes)
michael@0 233 {
michael@0 234 mShowAccessibleNodes = aShowAccessibleNodes;
michael@0 235 return NS_OK;
michael@0 236 }
michael@0 237
michael@0 238 NS_IMETHODIMP
michael@0 239 inDOMView::GetWhatToShow(uint32_t *aWhatToShow)
michael@0 240 {
michael@0 241 *aWhatToShow = mWhatToShow;
michael@0 242 return NS_OK;
michael@0 243 }
michael@0 244
michael@0 245 NS_IMETHODIMP
michael@0 246 inDOMView::SetWhatToShow(uint32_t aWhatToShow)
michael@0 247 {
michael@0 248 mWhatToShow = aWhatToShow;
michael@0 249 return NS_OK;
michael@0 250 }
michael@0 251
michael@0 252 NS_IMETHODIMP
michael@0 253 inDOMView::Rebuild()
michael@0 254 {
michael@0 255 nsCOMPtr<nsIDOMNode> root;
michael@0 256 GetRootNode(getter_AddRefs(root));
michael@0 257 SetRootNode(root);
michael@0 258 return NS_OK;
michael@0 259 }
michael@0 260
michael@0 261 ////////////////////////////////////////////////////////////////////////
michael@0 262 // nsITreeView
michael@0 263
michael@0 264 NS_IMETHODIMP
michael@0 265 inDOMView::GetRowCount(int32_t *aRowCount)
michael@0 266 {
michael@0 267 *aRowCount = GetRowCount();
michael@0 268 return NS_OK;
michael@0 269 }
michael@0 270
michael@0 271 NS_IMETHODIMP
michael@0 272 inDOMView::GetRowProperties(int32_t index, nsAString& aProps)
michael@0 273 {
michael@0 274 return NS_OK;
michael@0 275 }
michael@0 276
michael@0 277 NS_IMETHODIMP
michael@0 278 inDOMView::GetCellProperties(int32_t row, nsITreeColumn* col,
michael@0 279 nsAString& aProps)
michael@0 280 {
michael@0 281 inDOMViewNode* node = nullptr;
michael@0 282 RowToNode(row, &node);
michael@0 283 if (!node) return NS_ERROR_FAILURE;
michael@0 284
michael@0 285 nsCOMPtr<nsIContent> content = do_QueryInterface(node->node);
michael@0 286 if (content && content->IsInAnonymousSubtree()) {
michael@0 287 aProps.AppendLiteral("anonymous ");
michael@0 288 }
michael@0 289
michael@0 290 uint16_t nodeType;
michael@0 291 node->node->GetNodeType(&nodeType);
michael@0 292 switch (nodeType) {
michael@0 293 case nsIDOMNode::ELEMENT_NODE:
michael@0 294 aProps.AppendLiteral("ELEMENT_NODE");
michael@0 295 break;
michael@0 296 case nsIDOMNode::ATTRIBUTE_NODE:
michael@0 297 aProps.AppendLiteral("ATTRIBUTE_NODE");
michael@0 298 break;
michael@0 299 case nsIDOMNode::TEXT_NODE:
michael@0 300 aProps.AppendLiteral("TEXT_NODE");
michael@0 301 break;
michael@0 302 case nsIDOMNode::CDATA_SECTION_NODE:
michael@0 303 aProps.AppendLiteral("CDATA_SECTION_NODE");
michael@0 304 break;
michael@0 305 case nsIDOMNode::ENTITY_REFERENCE_NODE:
michael@0 306 aProps.AppendLiteral("ENTITY_REFERENCE_NODE");
michael@0 307 break;
michael@0 308 case nsIDOMNode::ENTITY_NODE:
michael@0 309 aProps.AppendLiteral("ENTITY_NODE");
michael@0 310 break;
michael@0 311 case nsIDOMNode::PROCESSING_INSTRUCTION_NODE:
michael@0 312 aProps.AppendLiteral("PROCESSING_INSTRUCTION_NODE");
michael@0 313 break;
michael@0 314 case nsIDOMNode::COMMENT_NODE:
michael@0 315 aProps.AppendLiteral("COMMENT_NODE");
michael@0 316 break;
michael@0 317 case nsIDOMNode::DOCUMENT_NODE:
michael@0 318 aProps.AppendLiteral("DOCUMENT_NODE");
michael@0 319 break;
michael@0 320 case nsIDOMNode::DOCUMENT_TYPE_NODE:
michael@0 321 aProps.AppendLiteral("DOCUMENT_TYPE_NODE");
michael@0 322 break;
michael@0 323 case nsIDOMNode::DOCUMENT_FRAGMENT_NODE:
michael@0 324 aProps.AppendLiteral("DOCUMENT_FRAGMENT_NODE");
michael@0 325 break;
michael@0 326 case nsIDOMNode::NOTATION_NODE:
michael@0 327 aProps.AppendLiteral("NOTATION_NODE");
michael@0 328 break;
michael@0 329 }
michael@0 330
michael@0 331 #ifdef ACCESSIBILITY
michael@0 332 if (mShowAccessibleNodes) {
michael@0 333 nsCOMPtr<nsIAccessibilityService> accService(
michael@0 334 do_GetService("@mozilla.org/accessibilityService;1"));
michael@0 335 NS_ENSURE_TRUE(accService, NS_ERROR_FAILURE);
michael@0 336
michael@0 337 nsCOMPtr<nsIAccessible> accessible;
michael@0 338 nsresult rv =
michael@0 339 accService->GetAccessibleFor(node->node, getter_AddRefs(accessible));
michael@0 340 if (NS_SUCCEEDED(rv) && accessible)
michael@0 341 aProps.AppendLiteral(" ACCESSIBLE_NODE");
michael@0 342 }
michael@0 343 #endif
michael@0 344
michael@0 345 return NS_OK;
michael@0 346 }
michael@0 347
michael@0 348 NS_IMETHODIMP
michael@0 349 inDOMView::GetColumnProperties(nsITreeColumn* col, nsAString& aProps)
michael@0 350 {
michael@0 351 return NS_OK;
michael@0 352 }
michael@0 353
michael@0 354 NS_IMETHODIMP
michael@0 355 inDOMView::GetImageSrc(int32_t row, nsITreeColumn* col, nsAString& _retval)
michael@0 356 {
michael@0 357 return NS_OK;
michael@0 358 }
michael@0 359
michael@0 360 NS_IMETHODIMP
michael@0 361 inDOMView::GetProgressMode(int32_t row, nsITreeColumn* col, int32_t* _retval)
michael@0 362 {
michael@0 363 return NS_OK;
michael@0 364 }
michael@0 365
michael@0 366 NS_IMETHODIMP
michael@0 367 inDOMView::GetCellValue(int32_t row, nsITreeColumn* col, nsAString& _retval)
michael@0 368 {
michael@0 369 return NS_OK;
michael@0 370 }
michael@0 371
michael@0 372 NS_IMETHODIMP
michael@0 373 inDOMView::GetCellText(int32_t row, nsITreeColumn* col, nsAString& _retval)
michael@0 374 {
michael@0 375 inDOMViewNode* node = nullptr;
michael@0 376 RowToNode(row, &node);
michael@0 377 if (!node) return NS_ERROR_FAILURE;
michael@0 378
michael@0 379 nsIDOMNode* domNode = node->node;
michael@0 380
michael@0 381 nsAutoString colID;
michael@0 382 col->GetId(colID);
michael@0 383 if (colID.EqualsLiteral("colNodeName"))
michael@0 384 domNode->GetNodeName(_retval);
michael@0 385 else if (colID.EqualsLiteral("colLocalName"))
michael@0 386 domNode->GetLocalName(_retval);
michael@0 387 else if (colID.EqualsLiteral("colPrefix"))
michael@0 388 domNode->GetPrefix(_retval);
michael@0 389 else if (colID.EqualsLiteral("colNamespaceURI"))
michael@0 390 domNode->GetNamespaceURI(_retval);
michael@0 391 else if (colID.EqualsLiteral("colNodeType")) {
michael@0 392 uint16_t nodeType;
michael@0 393 domNode->GetNodeType(&nodeType);
michael@0 394 nsAutoString temp;
michael@0 395 temp.AppendInt(int32_t(nodeType));
michael@0 396 _retval = temp;
michael@0 397 } else if (colID.EqualsLiteral("colNodeValue"))
michael@0 398 domNode->GetNodeValue(_retval);
michael@0 399 else {
michael@0 400 if (StringBeginsWith(colID, NS_LITERAL_STRING("col@"))) {
michael@0 401 nsCOMPtr<nsIDOMElement> el = do_QueryInterface(node->node);
michael@0 402 if (el) {
michael@0 403 nsAutoString attr;
michael@0 404 colID.Right(attr, colID.Length()-4); // have to use this because Substring is crashing on me!
michael@0 405 el->GetAttribute(attr, _retval);
michael@0 406 }
michael@0 407 }
michael@0 408 }
michael@0 409
michael@0 410 return NS_OK;
michael@0 411 }
michael@0 412
michael@0 413 NS_IMETHODIMP
michael@0 414 inDOMView::IsContainer(int32_t index, bool *_retval)
michael@0 415 {
michael@0 416 inDOMViewNode* node = nullptr;
michael@0 417 RowToNode(index, &node);
michael@0 418 if (!node) return NS_ERROR_FAILURE;
michael@0 419
michael@0 420 *_retval = node->isContainer;
michael@0 421 return NS_OK;
michael@0 422 }
michael@0 423
michael@0 424 NS_IMETHODIMP
michael@0 425 inDOMView::IsContainerOpen(int32_t index, bool *_retval)
michael@0 426 {
michael@0 427 inDOMViewNode* node = nullptr;
michael@0 428 RowToNode(index, &node);
michael@0 429 if (!node) return NS_ERROR_FAILURE;
michael@0 430
michael@0 431 *_retval = node->isOpen;
michael@0 432 return NS_OK;
michael@0 433 }
michael@0 434
michael@0 435 NS_IMETHODIMP
michael@0 436 inDOMView::IsContainerEmpty(int32_t index, bool *_retval)
michael@0 437 {
michael@0 438 inDOMViewNode* node = nullptr;
michael@0 439 RowToNode(index, &node);
michael@0 440 if (!node) return NS_ERROR_FAILURE;
michael@0 441
michael@0 442 *_retval = node->isContainer ? false : true;
michael@0 443 return NS_OK;
michael@0 444 }
michael@0 445
michael@0 446 NS_IMETHODIMP
michael@0 447 inDOMView::GetLevel(int32_t index, int32_t *_retval)
michael@0 448 {
michael@0 449 inDOMViewNode* node = nullptr;
michael@0 450 RowToNode(index, &node);
michael@0 451 if (!node) return NS_ERROR_FAILURE;
michael@0 452
michael@0 453 *_retval = node->level;
michael@0 454 return NS_OK;
michael@0 455 }
michael@0 456
michael@0 457 NS_IMETHODIMP
michael@0 458 inDOMView::GetParentIndex(int32_t rowIndex, int32_t *_retval)
michael@0 459 {
michael@0 460 inDOMViewNode* node = nullptr;
michael@0 461 RowToNode(rowIndex, &node);
michael@0 462 if (!node) return NS_ERROR_FAILURE;
michael@0 463
michael@0 464 // GetParentIndex returns -1 if there is no parent
michael@0 465 *_retval = -1;
michael@0 466
michael@0 467 inDOMViewNode* checkNode = nullptr;
michael@0 468 int32_t i = rowIndex - 1;
michael@0 469 do {
michael@0 470 nsresult rv = RowToNode(i, &checkNode);
michael@0 471 if (NS_FAILED(rv)) {
michael@0 472 // No parent. Just break out.
michael@0 473 break;
michael@0 474 }
michael@0 475
michael@0 476 if (checkNode == node->parent) {
michael@0 477 *_retval = i;
michael@0 478 return NS_OK;
michael@0 479 }
michael@0 480 --i;
michael@0 481 } while (checkNode);
michael@0 482
michael@0 483 return NS_OK;
michael@0 484 }
michael@0 485
michael@0 486 NS_IMETHODIMP
michael@0 487 inDOMView::HasNextSibling(int32_t rowIndex, int32_t afterIndex, bool *_retval)
michael@0 488 {
michael@0 489 inDOMViewNode* node = nullptr;
michael@0 490 RowToNode(rowIndex, &node);
michael@0 491 if (!node) return NS_ERROR_FAILURE;
michael@0 492
michael@0 493 *_retval = node->next != nullptr;
michael@0 494
michael@0 495 return NS_OK;
michael@0 496 }
michael@0 497
michael@0 498 NS_IMETHODIMP
michael@0 499 inDOMView::ToggleOpenState(int32_t index)
michael@0 500 {
michael@0 501 inDOMViewNode* node = nullptr;
michael@0 502 RowToNode(index, &node);
michael@0 503 if (!node) return NS_ERROR_FAILURE;
michael@0 504
michael@0 505 int32_t oldCount = GetRowCount();
michael@0 506 if (node->isOpen)
michael@0 507 CollapseNode(index);
michael@0 508 else
michael@0 509 ExpandNode(index);
michael@0 510
michael@0 511 // Update the twisty.
michael@0 512 mTree->InvalidateRow(index);
michael@0 513
michael@0 514 mTree->RowCountChanged(index+1, GetRowCount() - oldCount);
michael@0 515
michael@0 516 return NS_OK;
michael@0 517 }
michael@0 518
michael@0 519 NS_IMETHODIMP
michael@0 520 inDOMView::SetTree(nsITreeBoxObject *tree)
michael@0 521 {
michael@0 522 mTree = tree;
michael@0 523 return NS_OK;
michael@0 524 }
michael@0 525
michael@0 526 NS_IMETHODIMP
michael@0 527 inDOMView::GetSelection(nsITreeSelection * *aSelection)
michael@0 528 {
michael@0 529 *aSelection = mSelection;
michael@0 530 NS_IF_ADDREF(*aSelection);
michael@0 531 return NS_OK;
michael@0 532 }
michael@0 533
michael@0 534 NS_IMETHODIMP inDOMView::SetSelection(nsITreeSelection * aSelection)
michael@0 535 {
michael@0 536 mSelection = aSelection;
michael@0 537 return NS_OK;
michael@0 538 }
michael@0 539
michael@0 540 NS_IMETHODIMP
michael@0 541 inDOMView::SelectionChanged()
michael@0 542 {
michael@0 543 return NS_OK;
michael@0 544 }
michael@0 545
michael@0 546 NS_IMETHODIMP
michael@0 547 inDOMView::SetCellValue(int32_t row, nsITreeColumn* col, const nsAString& value)
michael@0 548 {
michael@0 549 return NS_OK;
michael@0 550 }
michael@0 551
michael@0 552 NS_IMETHODIMP
michael@0 553 inDOMView::SetCellText(int32_t row, nsITreeColumn* col, const nsAString& value)
michael@0 554 {
michael@0 555 return NS_OK;
michael@0 556 }
michael@0 557
michael@0 558 NS_IMETHODIMP
michael@0 559 inDOMView::CycleHeader(nsITreeColumn* col)
michael@0 560 {
michael@0 561 return NS_OK;
michael@0 562 }
michael@0 563
michael@0 564 NS_IMETHODIMP
michael@0 565 inDOMView::CycleCell(int32_t row, nsITreeColumn* col)
michael@0 566 {
michael@0 567 return NS_OK;
michael@0 568 }
michael@0 569
michael@0 570 NS_IMETHODIMP
michael@0 571 inDOMView::IsEditable(int32_t row, nsITreeColumn* col, bool *_retval)
michael@0 572 {
michael@0 573 return NS_OK;
michael@0 574 }
michael@0 575
michael@0 576
michael@0 577 NS_IMETHODIMP
michael@0 578 inDOMView::IsSelectable(int32_t row, nsITreeColumn* col, bool *_retval)
michael@0 579 {
michael@0 580 return NS_OK;
michael@0 581 }
michael@0 582
michael@0 583 NS_IMETHODIMP
michael@0 584 inDOMView::IsSeparator(int32_t index, bool *_retval)
michael@0 585 {
michael@0 586 return NS_OK;
michael@0 587 }
michael@0 588
michael@0 589 NS_IMETHODIMP
michael@0 590 inDOMView::IsSorted(bool *_retval)
michael@0 591 {
michael@0 592 return NS_OK;
michael@0 593 }
michael@0 594
michael@0 595 NS_IMETHODIMP
michael@0 596 inDOMView::CanDrop(int32_t index, int32_t orientation,
michael@0 597 nsIDOMDataTransfer* aDataTransfer, bool *_retval)
michael@0 598 {
michael@0 599 *_retval = false;
michael@0 600 return NS_OK;
michael@0 601 }
michael@0 602
michael@0 603 NS_IMETHODIMP
michael@0 604 inDOMView::Drop(int32_t row, int32_t orientation, nsIDOMDataTransfer* aDataTransfer)
michael@0 605 {
michael@0 606 return NS_OK;
michael@0 607 }
michael@0 608
michael@0 609 NS_IMETHODIMP
michael@0 610 inDOMView::PerformAction(const char16_t *action)
michael@0 611 {
michael@0 612 return NS_OK;
michael@0 613 }
michael@0 614
michael@0 615 NS_IMETHODIMP
michael@0 616 inDOMView::PerformActionOnRow(const char16_t *action, int32_t row)
michael@0 617 {
michael@0 618 return NS_OK;
michael@0 619 }
michael@0 620
michael@0 621 NS_IMETHODIMP
michael@0 622 inDOMView::PerformActionOnCell(const char16_t* action, int32_t row, nsITreeColumn* col)
michael@0 623 {
michael@0 624 return NS_OK;
michael@0 625 }
michael@0 626
michael@0 627 ///////////////////////////////////////////////////////////////////////
michael@0 628 // nsIMutationObserver
michael@0 629
michael@0 630 void
michael@0 631 inDOMView::NodeWillBeDestroyed(const nsINode* aNode)
michael@0 632 {
michael@0 633 NS_NOTREACHED("Document destroyed while we're holding a strong ref to it");
michael@0 634 }
michael@0 635
michael@0 636 void
michael@0 637 inDOMView::AttributeChanged(nsIDocument* aDocument, dom::Element* aElement,
michael@0 638 int32_t aNameSpaceID, nsIAtom* aAttribute,
michael@0 639 int32_t aModType)
michael@0 640 {
michael@0 641 if (!mTree) {
michael@0 642 return;
michael@0 643 }
michael@0 644
michael@0 645 if (!(mWhatToShow & nsIDOMNodeFilter::SHOW_ATTRIBUTE)) {
michael@0 646 return;
michael@0 647 }
michael@0 648
michael@0 649 nsCOMPtr<nsIMutationObserver> kungFuDeathGrip(this);
michael@0 650
michael@0 651 // get the dom attribute node, if there is any
michael@0 652 nsCOMPtr<nsIDOMElement> el(do_QueryInterface(aElement));
michael@0 653 nsCOMPtr<nsIDOMAttr> domAttr;
michael@0 654 nsDependentAtomString attrStr(aAttribute);
michael@0 655 if (aNameSpaceID) {
michael@0 656 nsNameSpaceManager* nsm = nsNameSpaceManager::GetInstance();
michael@0 657 if (!nsm) {
michael@0 658 // we can't find out which attribute we want :(
michael@0 659 return;
michael@0 660 }
michael@0 661 nsString attrNS;
michael@0 662 nsresult rv = nsm->GetNameSpaceURI(aNameSpaceID, attrNS);
michael@0 663 if (NS_FAILED(rv)) {
michael@0 664 return;
michael@0 665 }
michael@0 666 (void)el->GetAttributeNodeNS(attrNS, attrStr, getter_AddRefs(domAttr));
michael@0 667 } else {
michael@0 668 (void)el->GetAttributeNode(attrStr, getter_AddRefs(domAttr));
michael@0 669 }
michael@0 670
michael@0 671 if (aModType == nsIDOMMutationEvent::MODIFICATION) {
michael@0 672 // No fancy stuff here, just invalidate the changed row
michael@0 673 if (!domAttr) {
michael@0 674 return;
michael@0 675 }
michael@0 676 int32_t row = 0;
michael@0 677 NodeToRow(domAttr, &row);
michael@0 678 mTree->InvalidateRange(row, row);
michael@0 679 } else if (aModType == nsIDOMMutationEvent::ADDITION) {
michael@0 680 if (!domAttr) {
michael@0 681 return;
michael@0 682 }
michael@0 683 // get the number of attributes on this content node
michael@0 684 nsCOMPtr<nsIDOMMozNamedAttrMap> attrs;
michael@0 685 el->GetAttributes(getter_AddRefs(attrs));
michael@0 686 uint32_t attrCount;
michael@0 687 attrs->GetLength(&attrCount);
michael@0 688
michael@0 689 inDOMViewNode* contentNode = nullptr;
michael@0 690 int32_t contentRow;
michael@0 691 int32_t attrRow;
michael@0 692 if (mRootNode == el &&
michael@0 693 !(mWhatToShow & nsIDOMNodeFilter::SHOW_ELEMENT)) {
michael@0 694 // if this view has a root node but is not displaying it,
michael@0 695 // it is ok to act as if the changed attribute is on the root.
michael@0 696 attrRow = attrCount - 1;
michael@0 697 } else {
michael@0 698 if (NS_FAILED(NodeToRow(el, &contentRow))) {
michael@0 699 return;
michael@0 700 }
michael@0 701 RowToNode(contentRow, &contentNode);
michael@0 702 if (!contentNode->isOpen) {
michael@0 703 return;
michael@0 704 }
michael@0 705 attrRow = contentRow + attrCount;
michael@0 706 }
michael@0 707
michael@0 708 inDOMViewNode* newNode = CreateNode(domAttr, contentNode);
michael@0 709 inDOMViewNode* insertNode = nullptr;
michael@0 710 RowToNode(attrRow, &insertNode);
michael@0 711 if (insertNode) {
michael@0 712 if (contentNode &&
michael@0 713 insertNode->level <= contentNode->level) {
michael@0 714 RowToNode(attrRow-1, &insertNode);
michael@0 715 InsertLinkAfter(newNode, insertNode);
michael@0 716 } else
michael@0 717 InsertLinkBefore(newNode, insertNode);
michael@0 718 }
michael@0 719 InsertNode(newNode, attrRow);
michael@0 720 mTree->RowCountChanged(attrRow, 1);
michael@0 721 } else if (aModType == nsIDOMMutationEvent::REMOVAL) {
michael@0 722 // At this point, the attribute is already gone from the DOM, but is still represented
michael@0 723 // in our mRows array. Search through the content node's children for the corresponding
michael@0 724 // node and remove it.
michael@0 725
michael@0 726 // get the row of the content node
michael@0 727 inDOMViewNode* contentNode = nullptr;
michael@0 728 int32_t contentRow;
michael@0 729 int32_t baseLevel;
michael@0 730 if (NS_SUCCEEDED(NodeToRow(el, &contentRow))) {
michael@0 731 RowToNode(contentRow, &contentNode);
michael@0 732 baseLevel = contentNode->level;
michael@0 733 } else {
michael@0 734 if (mRootNode == el) {
michael@0 735 contentRow = -1;
michael@0 736 baseLevel = -1;
michael@0 737 } else
michael@0 738 return;
michael@0 739 }
michael@0 740
michael@0 741 // search for the attribute node that was removed
michael@0 742 inDOMViewNode* checkNode = nullptr;
michael@0 743 int32_t row = 0;
michael@0 744 for (row = contentRow+1; row < GetRowCount(); ++row) {
michael@0 745 checkNode = GetNodeAt(row);
michael@0 746 if (checkNode->level == baseLevel+1) {
michael@0 747 domAttr = do_QueryInterface(checkNode->node);
michael@0 748 if (domAttr) {
michael@0 749 nsAutoString attrName;
michael@0 750 domAttr->GetNodeName(attrName);
michael@0 751 if (attrName.Equals(attrStr)) {
michael@0 752 // we have found the row for the attribute that was removed
michael@0 753 RemoveLink(checkNode);
michael@0 754 RemoveNode(row);
michael@0 755 mTree->RowCountChanged(row, -1);
michael@0 756 break;
michael@0 757 }
michael@0 758 }
michael@0 759 }
michael@0 760 if (checkNode->level <= baseLevel)
michael@0 761 break;
michael@0 762 }
michael@0 763
michael@0 764 }
michael@0 765 }
michael@0 766
michael@0 767 void
michael@0 768 inDOMView::ContentAppended(nsIDocument *aDocument,
michael@0 769 nsIContent* aContainer,
michael@0 770 nsIContent* aFirstNewContent,
michael@0 771 int32_t /* unused */)
michael@0 772 {
michael@0 773 if (!mTree) {
michael@0 774 return;
michael@0 775 }
michael@0 776
michael@0 777 for (nsIContent* cur = aFirstNewContent; cur; cur = cur->GetNextSibling()) {
michael@0 778 // Our ContentInserted impl doesn't use the index
michael@0 779 ContentInserted(aDocument, aContainer, cur, 0);
michael@0 780 }
michael@0 781 }
michael@0 782
michael@0 783 void
michael@0 784 inDOMView::ContentInserted(nsIDocument *aDocument, nsIContent* aContainer,
michael@0 785 nsIContent* aChild, int32_t /* unused */)
michael@0 786 {
michael@0 787 if (!mTree)
michael@0 788 return;
michael@0 789
michael@0 790 nsresult rv;
michael@0 791 nsCOMPtr<nsIDOMNode> childDOMNode(do_QueryInterface(aChild));
michael@0 792 nsCOMPtr<nsIDOMNode> parent;
michael@0 793 if (!mDOMUtils) {
michael@0 794 mDOMUtils = services::GetInDOMUtils();
michael@0 795 if (!mDOMUtils) {
michael@0 796 return;
michael@0 797 }
michael@0 798 }
michael@0 799 mDOMUtils->GetParentForNode(childDOMNode, mShowAnonymous,
michael@0 800 getter_AddRefs(parent));
michael@0 801
michael@0 802 // find the inDOMViewNode for the parent of the inserted content
michael@0 803 int32_t parentRow = 0;
michael@0 804 if (NS_FAILED(rv = NodeToRow(parent, &parentRow)))
michael@0 805 return;
michael@0 806 inDOMViewNode* parentNode = nullptr;
michael@0 807 if (NS_FAILED(rv = RowToNode(parentRow, &parentNode)))
michael@0 808 return;
michael@0 809
michael@0 810 nsCOMPtr<nsIMutationObserver> kungFuDeathGrip(this);
michael@0 811
michael@0 812 if (!parentNode->isOpen) {
michael@0 813 // Parent is not open, so don't bother creating tree rows for the
michael@0 814 // kids. But do indicate that it's now a container, if needed.
michael@0 815 if (!parentNode->isContainer) {
michael@0 816 parentNode->isContainer = true;
michael@0 817 mTree->InvalidateRow(parentRow);
michael@0 818 }
michael@0 819 return;
michael@0 820 }
michael@0 821
michael@0 822 // get the previous sibling of the inserted content
michael@0 823 nsCOMPtr<nsIDOMNode> previous;
michael@0 824 GetRealPreviousSibling(childDOMNode, parent, getter_AddRefs(previous));
michael@0 825 inDOMViewNode* previousNode = nullptr;
michael@0 826
michael@0 827 int32_t row = 0;
michael@0 828 if (previous) {
michael@0 829 // find the inDOMViewNode for the previous sibling of the inserted content
michael@0 830 int32_t previousRow = 0;
michael@0 831 if (NS_FAILED(rv = NodeToRow(previous, &previousRow)))
michael@0 832 return;
michael@0 833 if (NS_FAILED(rv = RowToNode(previousRow, &previousNode)))
michael@0 834 return;
michael@0 835
michael@0 836 // get the last descendant of the previous row, which is the row
michael@0 837 // after which to insert this new row
michael@0 838 GetLastDescendantOf(previousNode, previousRow, &row);
michael@0 839 ++row;
michael@0 840 } else {
michael@0 841 // there is no previous sibling, so the new row will be inserted after the parent
michael@0 842 row = parentRow+1;
michael@0 843 }
michael@0 844
michael@0 845 inDOMViewNode* newNode = CreateNode(childDOMNode, parentNode);
michael@0 846
michael@0 847 if (previous) {
michael@0 848 InsertLinkAfter(newNode, previousNode);
michael@0 849 } else {
michael@0 850 int32_t firstChildRow;
michael@0 851 if (NS_SUCCEEDED(GetFirstDescendantOf(parentNode, parentRow, &firstChildRow))) {
michael@0 852 inDOMViewNode* firstChild;
michael@0 853 RowToNode(firstChildRow, &firstChild);
michael@0 854 InsertLinkBefore(newNode, firstChild);
michael@0 855 }
michael@0 856 }
michael@0 857
michael@0 858 // insert new node
michael@0 859 InsertNode(newNode, row);
michael@0 860
michael@0 861 mTree->RowCountChanged(row, 1);
michael@0 862 }
michael@0 863
michael@0 864 void
michael@0 865 inDOMView::ContentRemoved(nsIDocument *aDocument, nsIContent* aContainer,
michael@0 866 nsIContent* aChild, int32_t aIndexInContainer,
michael@0 867 nsIContent* aPreviousSibling)
michael@0 868 {
michael@0 869 if (!mTree)
michael@0 870 return;
michael@0 871
michael@0 872 nsresult rv;
michael@0 873
michael@0 874 // find the inDOMViewNode for the old child
michael@0 875 nsCOMPtr<nsIDOMNode> oldDOMNode(do_QueryInterface(aChild));
michael@0 876 int32_t row = 0;
michael@0 877 if (NS_FAILED(rv = NodeToRow(oldDOMNode, &row)))
michael@0 878 return;
michael@0 879 inDOMViewNode* oldNode;
michael@0 880 if (NS_FAILED(rv = RowToNode(row, &oldNode)))
michael@0 881 return;
michael@0 882
michael@0 883 nsCOMPtr<nsIMutationObserver> kungFuDeathGrip(this);
michael@0 884
michael@0 885 // The parent may no longer be a container. Note that we don't want
michael@0 886 // to access oldNode after calling RemoveNode, so do this now.
michael@0 887 inDOMViewNode* parentNode = oldNode->parent;
michael@0 888 bool isOnlyChild = oldNode->previous == nullptr && oldNode->next == nullptr;
michael@0 889
michael@0 890 // Keep track of how many rows we are removing. It's at least one,
michael@0 891 // but if we're open it's more.
michael@0 892 int32_t oldCount = GetRowCount();
michael@0 893
michael@0 894 if (oldNode->isOpen)
michael@0 895 CollapseNode(row);
michael@0 896
michael@0 897 RemoveLink(oldNode);
michael@0 898 RemoveNode(row);
michael@0 899
michael@0 900 if (isOnlyChild) {
michael@0 901 // Fix up the parent
michael@0 902 parentNode->isContainer = false;
michael@0 903 parentNode->isOpen = false;
michael@0 904 mTree->InvalidateRow(NodeToRow(parentNode));
michael@0 905 }
michael@0 906
michael@0 907 mTree->RowCountChanged(row, GetRowCount() - oldCount);
michael@0 908 }
michael@0 909
michael@0 910 ///////////////////////////////////////////////////////////////////////
michael@0 911 // inDOMView
michael@0 912
michael@0 913 //////// NODE MANAGEMENT
michael@0 914
michael@0 915 inDOMViewNode*
michael@0 916 inDOMView::GetNodeAt(int32_t aRow)
michael@0 917 {
michael@0 918 return mNodes.ElementAt(aRow);
michael@0 919 }
michael@0 920
michael@0 921 int32_t
michael@0 922 inDOMView::GetRowCount()
michael@0 923 {
michael@0 924 return mNodes.Length();
michael@0 925 }
michael@0 926
michael@0 927 int32_t
michael@0 928 inDOMView::NodeToRow(inDOMViewNode* aNode)
michael@0 929 {
michael@0 930 return mNodes.IndexOf(aNode);
michael@0 931 }
michael@0 932
michael@0 933 inDOMViewNode*
michael@0 934 inDOMView::CreateNode(nsIDOMNode* aNode, inDOMViewNode* aParent)
michael@0 935 {
michael@0 936 inDOMViewNode* viewNode = new inDOMViewNode(aNode);
michael@0 937 viewNode->level = aParent ? aParent->level+1 : 0;
michael@0 938 viewNode->parent = aParent;
michael@0 939
michael@0 940 nsCOMArray<nsIDOMNode> grandKids;
michael@0 941 GetChildNodesFor(aNode, grandKids);
michael@0 942 viewNode->isContainer = (grandKids.Count() > 0);
michael@0 943 return viewNode;
michael@0 944 }
michael@0 945
michael@0 946 bool
michael@0 947 inDOMView::RowOutOfBounds(int32_t aRow, int32_t aCount)
michael@0 948 {
michael@0 949 return aRow < 0 || aRow >= GetRowCount() || aCount+aRow > GetRowCount();
michael@0 950 }
michael@0 951
michael@0 952 void
michael@0 953 inDOMView::AppendNode(inDOMViewNode* aNode)
michael@0 954 {
michael@0 955 mNodes.AppendElement(aNode);
michael@0 956 }
michael@0 957
michael@0 958 void
michael@0 959 inDOMView::InsertNode(inDOMViewNode* aNode, int32_t aRow)
michael@0 960 {
michael@0 961 if (RowOutOfBounds(aRow, 1))
michael@0 962 AppendNode(aNode);
michael@0 963 else
michael@0 964 mNodes.InsertElementAt(aRow, aNode);
michael@0 965 }
michael@0 966
michael@0 967 void
michael@0 968 inDOMView::RemoveNode(int32_t aRow)
michael@0 969 {
michael@0 970 if (RowOutOfBounds(aRow, 1))
michael@0 971 return;
michael@0 972
michael@0 973 delete GetNodeAt(aRow);
michael@0 974 mNodes.RemoveElementAt(aRow);
michael@0 975 }
michael@0 976
michael@0 977 void
michael@0 978 inDOMView::ReplaceNode(inDOMViewNode* aNode, int32_t aRow)
michael@0 979 {
michael@0 980 if (RowOutOfBounds(aRow, 1))
michael@0 981 return;
michael@0 982
michael@0 983 delete GetNodeAt(aRow);
michael@0 984 mNodes.ElementAt(aRow) = aNode;
michael@0 985 }
michael@0 986
michael@0 987 void
michael@0 988 inDOMView::InsertNodes(nsTArray<inDOMViewNode*>& aNodes, int32_t aRow)
michael@0 989 {
michael@0 990 if (aRow < 0 || aRow > GetRowCount())
michael@0 991 return;
michael@0 992
michael@0 993 mNodes.InsertElementsAt(aRow, aNodes);
michael@0 994 }
michael@0 995
michael@0 996 void
michael@0 997 inDOMView::RemoveNodes(int32_t aRow, int32_t aCount)
michael@0 998 {
michael@0 999 if (aRow < 0)
michael@0 1000 return;
michael@0 1001
michael@0 1002 int32_t rowCount = GetRowCount();
michael@0 1003 for (int32_t i = aRow; i < aRow+aCount && i < rowCount; ++i) {
michael@0 1004 delete GetNodeAt(i);
michael@0 1005 }
michael@0 1006
michael@0 1007 mNodes.RemoveElementsAt(aRow, aCount);
michael@0 1008 }
michael@0 1009
michael@0 1010 void
michael@0 1011 inDOMView::RemoveAllNodes()
michael@0 1012 {
michael@0 1013 int32_t rowCount = GetRowCount();
michael@0 1014 for (int32_t i = 0; i < rowCount; ++i) {
michael@0 1015 delete GetNodeAt(i);
michael@0 1016 }
michael@0 1017
michael@0 1018 mNodes.Clear();
michael@0 1019 }
michael@0 1020
michael@0 1021 void
michael@0 1022 inDOMView::ExpandNode(int32_t aRow)
michael@0 1023 {
michael@0 1024 inDOMViewNode* node = nullptr;
michael@0 1025 RowToNode(aRow, &node);
michael@0 1026
michael@0 1027 nsCOMArray<nsIDOMNode> kids;
michael@0 1028 GetChildNodesFor(node ? node->node : mRootNode,
michael@0 1029 kids);
michael@0 1030 int32_t kidCount = kids.Count();
michael@0 1031
michael@0 1032 nsTArray<inDOMViewNode*> list(kidCount);
michael@0 1033
michael@0 1034 inDOMViewNode* newNode = nullptr;
michael@0 1035 inDOMViewNode* prevNode = nullptr;
michael@0 1036
michael@0 1037 for (int32_t i = 0; i < kidCount; ++i) {
michael@0 1038 newNode = CreateNode(kids[i], node);
michael@0 1039 list.AppendElement(newNode);
michael@0 1040
michael@0 1041 if (prevNode)
michael@0 1042 prevNode->next = newNode;
michael@0 1043 newNode->previous = prevNode;
michael@0 1044 prevNode = newNode;
michael@0 1045 }
michael@0 1046
michael@0 1047 InsertNodes(list, aRow+1);
michael@0 1048
michael@0 1049 if (node)
michael@0 1050 node->isOpen = true;
michael@0 1051 }
michael@0 1052
michael@0 1053 void
michael@0 1054 inDOMView::CollapseNode(int32_t aRow)
michael@0 1055 {
michael@0 1056 inDOMViewNode* node = nullptr;
michael@0 1057 nsresult rv = RowToNode(aRow, &node);
michael@0 1058 if (NS_FAILED(rv)) {
michael@0 1059 return;
michael@0 1060 }
michael@0 1061
michael@0 1062 int32_t row = 0;
michael@0 1063 GetLastDescendantOf(node, aRow, &row);
michael@0 1064
michael@0 1065 RemoveNodes(aRow+1, row-aRow);
michael@0 1066
michael@0 1067 node->isOpen = false;
michael@0 1068 }
michael@0 1069
michael@0 1070 //////// NODE AND ROW CONVERSION
michael@0 1071
michael@0 1072 nsresult
michael@0 1073 inDOMView::RowToNode(int32_t aRow, inDOMViewNode** aNode)
michael@0 1074 {
michael@0 1075 if (aRow < 0 || aRow >= GetRowCount())
michael@0 1076 return NS_ERROR_FAILURE;
michael@0 1077
michael@0 1078 *aNode = GetNodeAt(aRow);
michael@0 1079 return NS_OK;
michael@0 1080 }
michael@0 1081
michael@0 1082 nsresult
michael@0 1083 inDOMView::NodeToRow(nsIDOMNode* aNode, int32_t* aRow)
michael@0 1084 {
michael@0 1085 int32_t rowCount = GetRowCount();
michael@0 1086 for (int32_t i = 0; i < rowCount; ++i) {
michael@0 1087 if (GetNodeAt(i)->node == aNode) {
michael@0 1088 *aRow = i;
michael@0 1089 return NS_OK;
michael@0 1090 }
michael@0 1091 }
michael@0 1092
michael@0 1093 *aRow = -1;
michael@0 1094 return NS_ERROR_FAILURE;
michael@0 1095 }
michael@0 1096
michael@0 1097 //////// NODE HIERARCHY MUTATION
michael@0 1098
michael@0 1099 void
michael@0 1100 inDOMView::InsertLinkAfter(inDOMViewNode* aNode, inDOMViewNode* aInsertAfter)
michael@0 1101 {
michael@0 1102 if (aInsertAfter->next)
michael@0 1103 aInsertAfter->next->previous = aNode;
michael@0 1104 aNode->next = aInsertAfter->next;
michael@0 1105 aInsertAfter->next = aNode;
michael@0 1106 aNode->previous = aInsertAfter;
michael@0 1107 }
michael@0 1108
michael@0 1109 void
michael@0 1110 inDOMView::InsertLinkBefore(inDOMViewNode* aNode, inDOMViewNode* aInsertBefore)
michael@0 1111 {
michael@0 1112 if (aInsertBefore->previous)
michael@0 1113 aInsertBefore->previous->next = aNode;
michael@0 1114 aNode->previous = aInsertBefore->previous;
michael@0 1115 aInsertBefore->previous = aNode;
michael@0 1116 aNode->next = aInsertBefore;
michael@0 1117 }
michael@0 1118
michael@0 1119 void
michael@0 1120 inDOMView::RemoveLink(inDOMViewNode* aNode)
michael@0 1121 {
michael@0 1122 if (aNode->previous)
michael@0 1123 aNode->previous->next = aNode->next;
michael@0 1124 if (aNode->next)
michael@0 1125 aNode->next->previous = aNode->previous;
michael@0 1126 }
michael@0 1127
michael@0 1128 void
michael@0 1129 inDOMView::ReplaceLink(inDOMViewNode* aNewNode, inDOMViewNode* aOldNode)
michael@0 1130 {
michael@0 1131 if (aOldNode->previous)
michael@0 1132 aOldNode->previous->next = aNewNode;
michael@0 1133 if (aOldNode->next)
michael@0 1134 aOldNode->next->previous = aNewNode;
michael@0 1135 aNewNode->next = aOldNode->next;
michael@0 1136 aNewNode->previous = aOldNode->previous;
michael@0 1137 }
michael@0 1138
michael@0 1139 //////// NODE HIERARCHY UTILITIES
michael@0 1140
michael@0 1141 nsresult
michael@0 1142 inDOMView::GetFirstDescendantOf(inDOMViewNode* aNode, int32_t aRow, int32_t* aResult)
michael@0 1143 {
michael@0 1144 // get the first node that is a descendant of the previous sibling
michael@0 1145 int32_t row = 0;
michael@0 1146 inDOMViewNode* node;
michael@0 1147 for (row = aRow+1; row < GetRowCount(); ++row) {
michael@0 1148 node = GetNodeAt(row);
michael@0 1149 if (node->parent == aNode) {
michael@0 1150 *aResult = row;
michael@0 1151 return NS_OK;
michael@0 1152 }
michael@0 1153 if (node->level <= aNode->level)
michael@0 1154 break;
michael@0 1155 }
michael@0 1156 return NS_ERROR_FAILURE;
michael@0 1157 }
michael@0 1158
michael@0 1159 nsresult
michael@0 1160 inDOMView::GetLastDescendantOf(inDOMViewNode* aNode, int32_t aRow, int32_t* aResult)
michael@0 1161 {
michael@0 1162 // get the last node that is a descendant of the previous sibling
michael@0 1163 int32_t row = 0;
michael@0 1164 for (row = aRow+1; row < GetRowCount(); ++row) {
michael@0 1165 if (GetNodeAt(row)->level <= aNode->level)
michael@0 1166 break;
michael@0 1167 }
michael@0 1168 *aResult = row-1;
michael@0 1169 return NS_OK;
michael@0 1170 }
michael@0 1171
michael@0 1172 //////// DOM UTILITIES
michael@0 1173
michael@0 1174 nsresult
michael@0 1175 inDOMView::GetChildNodesFor(nsIDOMNode* aNode, nsCOMArray<nsIDOMNode>& aResult)
michael@0 1176 {
michael@0 1177 NS_ENSURE_ARG(aNode);
michael@0 1178 // attribute nodes
michael@0 1179 if (mWhatToShow & nsIDOMNodeFilter::SHOW_ATTRIBUTE) {
michael@0 1180 nsCOMPtr<nsIDOMElement> element = do_QueryInterface(aNode);
michael@0 1181 if (element) {
michael@0 1182 nsCOMPtr<nsIDOMMozNamedAttrMap> attrs;
michael@0 1183 element->GetAttributes(getter_AddRefs(attrs));
michael@0 1184 if (attrs) {
michael@0 1185 AppendAttrsToArray(attrs, aResult);
michael@0 1186 }
michael@0 1187 }
michael@0 1188 }
michael@0 1189
michael@0 1190 if (mWhatToShow & nsIDOMNodeFilter::SHOW_ELEMENT) {
michael@0 1191 nsCOMPtr<nsIDOMNodeList> kids;
michael@0 1192 if (!mDOMUtils) {
michael@0 1193 mDOMUtils = services::GetInDOMUtils();
michael@0 1194 if (!mDOMUtils) {
michael@0 1195 return NS_ERROR_FAILURE;
michael@0 1196 }
michael@0 1197 }
michael@0 1198
michael@0 1199 mDOMUtils->GetChildrenForNode(aNode, mShowAnonymous,
michael@0 1200 getter_AddRefs(kids));
michael@0 1201
michael@0 1202 if (kids) {
michael@0 1203 AppendKidsToArray(kids, aResult);
michael@0 1204 }
michael@0 1205 }
michael@0 1206
michael@0 1207 if (mShowSubDocuments) {
michael@0 1208 nsCOMPtr<nsIDOMNode> domdoc =
michael@0 1209 do_QueryInterface(inLayoutUtils::GetSubDocumentFor(aNode));
michael@0 1210 if (domdoc) {
michael@0 1211 aResult.AppendObject(domdoc);
michael@0 1212 }
michael@0 1213 }
michael@0 1214
michael@0 1215 return NS_OK;
michael@0 1216 }
michael@0 1217
michael@0 1218 nsresult
michael@0 1219 inDOMView::GetRealPreviousSibling(nsIDOMNode* aNode, nsIDOMNode* aRealParent, nsIDOMNode** aSibling)
michael@0 1220 {
michael@0 1221 // XXXjrh: This won't work for some cases during some situations where XBL insertion points
michael@0 1222 // are involved. Fix me!
michael@0 1223 aNode->GetPreviousSibling(aSibling);
michael@0 1224 return NS_OK;
michael@0 1225 }
michael@0 1226
michael@0 1227 nsresult
michael@0 1228 inDOMView::AppendKidsToArray(nsIDOMNodeList* aKids,
michael@0 1229 nsCOMArray<nsIDOMNode>& aArray)
michael@0 1230 {
michael@0 1231 uint32_t l = 0;
michael@0 1232 aKids->GetLength(&l);
michael@0 1233 nsCOMPtr<nsIDOMNode> kid;
michael@0 1234 uint16_t nodeType = 0;
michael@0 1235
michael@0 1236 // Try and get DOM Utils in case we don't have one yet.
michael@0 1237 if (!mShowWhitespaceNodes && !mDOMUtils) {
michael@0 1238 mDOMUtils = services::GetInDOMUtils();
michael@0 1239 }
michael@0 1240
michael@0 1241 for (uint32_t i = 0; i < l; ++i) {
michael@0 1242 aKids->Item(i, getter_AddRefs(kid));
michael@0 1243 kid->GetNodeType(&nodeType);
michael@0 1244
michael@0 1245 NS_ASSERTION(nodeType && nodeType <= nsIDOMNode::NOTATION_NODE,
michael@0 1246 "Unknown node type. "
michael@0 1247 "Were new types added to the spec?");
michael@0 1248 // As of DOM Level 2 Core and Traversal, each NodeFilter constant
michael@0 1249 // is defined as the lower nth bit in the NodeFilter bitmask,
michael@0 1250 // where n is the numeric constant of the nodeType it represents.
michael@0 1251 // If this invariant ever changes, we will need to update the
michael@0 1252 // following line.
michael@0 1253 uint32_t filterForNodeType = 1 << (nodeType - 1);
michael@0 1254
michael@0 1255 if (mWhatToShow & filterForNodeType) {
michael@0 1256 if ((nodeType == nsIDOMNode::TEXT_NODE ||
michael@0 1257 nodeType == nsIDOMNode::COMMENT_NODE) &&
michael@0 1258 !mShowWhitespaceNodes && mDOMUtils) {
michael@0 1259 nsCOMPtr<nsIDOMCharacterData> data = do_QueryInterface(kid);
michael@0 1260 NS_ASSERTION(data, "Does not implement nsIDOMCharacterData!");
michael@0 1261 bool ignore;
michael@0 1262 mDOMUtils->IsIgnorableWhitespace(data, &ignore);
michael@0 1263 if (ignore) {
michael@0 1264 continue;
michael@0 1265 }
michael@0 1266 }
michael@0 1267
michael@0 1268 aArray.AppendObject(kid);
michael@0 1269 }
michael@0 1270 }
michael@0 1271
michael@0 1272 return NS_OK;
michael@0 1273 }
michael@0 1274
michael@0 1275 nsresult
michael@0 1276 inDOMView::AppendAttrsToArray(nsIDOMMozNamedAttrMap* aAttributes,
michael@0 1277 nsCOMArray<nsIDOMNode>& aArray)
michael@0 1278 {
michael@0 1279 uint32_t l = 0;
michael@0 1280 aAttributes->GetLength(&l);
michael@0 1281 nsCOMPtr<nsIDOMAttr> attribute;
michael@0 1282 for (uint32_t i = 0; i < l; ++i) {
michael@0 1283 aAttributes->Item(i, getter_AddRefs(attribute));
michael@0 1284 aArray.AppendObject(attribute);
michael@0 1285 }
michael@0 1286 return NS_OK;
michael@0 1287 }

mercurial