1 /* 2 * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. 3 * Distributed under the terms of the MIT License. 4 */ 5 6 #include "table/TreeTable.h" 7 8 #include <new> 9 10 11 // #pragma mark - TreeTableField 12 13 14 class TreeTableField : public BField { 15 public: 16 TreeTableField(void* object) 17 : 18 fObject(object) 19 { 20 } 21 22 void* Object() const 23 { 24 return fObject; 25 } 26 27 private: 28 void* fObject; 29 }; 30 31 32 // #pragma mark - TreeTablePath 33 34 35 TreeTablePath::TreeTablePath() 36 { 37 } 38 39 40 TreeTablePath::TreeTablePath(const TreeTablePath& other) 41 { 42 *this = other; 43 } 44 45 46 TreeTablePath::TreeTablePath(const TreeTablePath& other, int32 childIndex) 47 { 48 *this = other; 49 AddComponent(childIndex); 50 } 51 52 53 TreeTablePath::~TreeTablePath() 54 { 55 } 56 57 58 bool 59 TreeTablePath::AddComponent(int32 childIndex) 60 { 61 try { 62 fComponents.push_back(childIndex); 63 return true; 64 } catch (...) { 65 return false; 66 } 67 } 68 69 70 int32 71 TreeTablePath::RemoveLastComponent() 72 { 73 if (fComponents.empty()) 74 return -1; 75 76 int32 index = fComponents.back(); 77 fComponents.pop_back(); 78 return index; 79 } 80 81 void 82 TreeTablePath::Clear() 83 { 84 fComponents.clear(); 85 } 86 87 88 int32 89 TreeTablePath::CountComponents() const 90 { 91 return fComponents.size(); 92 } 93 94 95 int32 96 TreeTablePath::ComponentAt(int32 index) const 97 { 98 if (index < 0 || (size_t)index >= fComponents.size()) 99 return -1; 100 return fComponents[index]; 101 } 102 103 104 TreeTablePath& 105 TreeTablePath::operator=(const TreeTablePath& other) 106 { 107 try { 108 fComponents = other.fComponents; 109 } catch (...) { 110 } 111 return *this; 112 } 113 114 115 bool 116 TreeTablePath::operator==(const TreeTablePath& other) const 117 { 118 return fComponents == other.fComponents; 119 } 120 121 122 bool 123 TreeTablePath::operator!=(const TreeTablePath& other) const 124 { 125 return fComponents != other.fComponents; 126 } 127 128 129 // #pragma mark - TreeTableModelListener 130 131 132 TreeTableModelListener::~TreeTableModelListener() 133 { 134 } 135 136 137 void 138 TreeTableModelListener::TableNodesAdded(TreeTableModel* model, 139 const TreeTablePath& path, int32 childIndex, int32 count) 140 { 141 } 142 143 144 void 145 TreeTableModelListener::TableNodesRemoved(TreeTableModel* model, 146 const TreeTablePath& path, int32 childIndex, int32 count) 147 { 148 } 149 150 151 void 152 TreeTableModelListener::TableNodesChanged(TreeTableModel* model, 153 const TreeTablePath& path, int32 childIndex, int32 count) 154 { 155 } 156 157 158 // #pragma mark - TreeTableModel 159 160 161 TreeTableModel::~TreeTableModel() 162 { 163 } 164 165 166 void* 167 TreeTableModel::NodeForPath(const TreeTablePath& path) const 168 { 169 void* node = Root(); 170 171 int32 count = path.CountComponents(); 172 for (int32 i = 0; node != NULL && i < count; i++) 173 node = ChildAt(node, path.ComponentAt(i)); 174 175 return node; 176 } 177 178 179 bool 180 TreeTableModel::AddListener(TreeTableModelListener* listener) 181 { 182 return fListeners.AddItem(listener); 183 } 184 185 186 void 187 TreeTableModel::RemoveListener(TreeTableModelListener* listener) 188 { 189 fListeners.RemoveItem(listener); 190 } 191 192 193 void 194 TreeTableModel::NotifyNodesAdded(const TreeTablePath& path, int32 childIndex, 195 int32 count) 196 { 197 int32 listenerCount = fListeners.CountItems(); 198 for (int32 i = listenerCount - 1; i >= 0; i--) { 199 TreeTableModelListener* listener = fListeners.ItemAt(i); 200 listener->TableNodesAdded(this, path, childIndex, count); 201 } 202 } 203 204 205 void 206 TreeTableModel::NotifyNodesRemoved(const TreeTablePath& path, int32 childIndex, 207 int32 count) 208 { 209 int32 listenerCount = fListeners.CountItems(); 210 for (int32 i = listenerCount - 1; i >= 0; i--) { 211 TreeTableModelListener* listener = fListeners.ItemAt(i); 212 listener->TableNodesRemoved(this, path, childIndex, count); 213 } 214 } 215 216 217 void 218 TreeTableModel::NotifyNodesChanged(const TreeTablePath& path, int32 childIndex, 219 int32 count) 220 { 221 int32 listenerCount = fListeners.CountItems(); 222 for (int32 i = listenerCount - 1; i >= 0; i--) { 223 TreeTableModelListener* listener = fListeners.ItemAt(i); 224 listener->TableNodesChanged(this, path, childIndex, count); 225 } 226 } 227 228 229 // #pragma mark - TreeTableListener 230 231 232 TreeTableListener::~TreeTableListener() 233 { 234 } 235 236 237 void 238 TreeTableListener::TreeTableSelectionChanged(TreeTable* table) 239 { 240 } 241 242 243 void 244 TreeTableListener::TreeTableNodeInvoked(TreeTable* table, 245 const TreeTablePath& path) 246 { 247 } 248 249 250 void 251 TreeTableListener::TreeTableNodeExpandedChanged(TreeTable* table, 252 const TreeTablePath& path, bool expanded) 253 { 254 } 255 256 257 void 258 TreeTableListener::TreeTableCellMouseDown(TreeTable* table, 259 const TreeTablePath& path, int32 columnIndex, BPoint screenWhere, 260 uint32 buttons) 261 { 262 } 263 264 265 void 266 TreeTableListener::TreeTableCellMouseUp(TreeTable* table, 267 const TreeTablePath& path, int32 columnIndex, BPoint screenWhere, 268 uint32 buttons) 269 { 270 } 271 272 273 // #pragma mark - Column 274 275 276 class TreeTable::Column : public AbstractColumn { 277 public: 278 Column(TreeTableModel* model, 279 TableColumn* tableColumn); 280 virtual ~Column(); 281 282 virtual void SetModel(AbstractTableModelBase* model); 283 284 protected: 285 virtual void DrawTitle(BRect rect, BView* targetView); 286 virtual void DrawField(BField* field, BRect rect, 287 BView* targetView); 288 virtual int CompareFields(BField* field1, BField* field2); 289 290 virtual void GetColumnName(BString* into) const; 291 virtual float GetPreferredWidth(BField* field, 292 BView* parent) const; 293 294 private: 295 TreeTableModel* fModel; 296 }; 297 298 299 TreeTable::Column::Column(TreeTableModel* model, TableColumn* tableColumn) 300 : 301 AbstractColumn(tableColumn), 302 fModel(model) 303 { 304 } 305 306 307 TreeTable::Column::~Column() 308 { 309 } 310 311 312 void 313 TreeTable::Column::SetModel(AbstractTableModelBase* model) 314 { 315 fModel = dynamic_cast<TreeTableModel*>(model); 316 } 317 318 319 void 320 TreeTable::Column::DrawTitle(BRect rect, BView* targetView) 321 { 322 fTableColumn->DrawTitle(rect, targetView); 323 } 324 325 326 void 327 TreeTable::Column::DrawField(BField* _field, BRect rect, BView* targetView) 328 { 329 TreeTableField* field = dynamic_cast<TreeTableField*>(_field); 330 if (field == NULL) 331 return; 332 333 int32 modelIndex = fTableColumn->ModelIndex(); 334 BVariant value; 335 if (!fModel->GetValueAt(field->Object(), modelIndex, value)) 336 return; 337 fTableColumn->DrawValue(value, rect, targetView); 338 } 339 340 341 int 342 TreeTable::Column::CompareFields(BField* _field1, BField* _field2) 343 { 344 TreeTableField* field1 = dynamic_cast<TreeTableField*>(_field1); 345 TreeTableField* field2 = dynamic_cast<TreeTableField*>(_field2); 346 347 if (field1 == field2) 348 return 0; 349 350 if (field1 == NULL) 351 return -1; 352 if (field2 == NULL) 353 return 1; 354 355 int32 modelIndex = fTableColumn->ModelIndex(); 356 BVariant value1; 357 bool valid1 = fModel->GetValueAt(field1->Object(), modelIndex, value1); 358 BVariant value2; 359 bool valid2 = fModel->GetValueAt(field2->Object(), modelIndex, value2); 360 361 if (!valid1) 362 return valid2 ? -1 : 0; 363 if (!valid2) 364 return 1; 365 366 return fTableColumn->CompareValues(value1, value2); 367 } 368 369 370 void 371 TreeTable::Column::GetColumnName(BString* into) const 372 { 373 fTableColumn->GetColumnName(into); 374 } 375 376 377 float 378 TreeTable::Column::GetPreferredWidth(BField* _field, BView* parent) const 379 { 380 TreeTableField* field = dynamic_cast<TreeTableField*>(_field); 381 if (field == NULL) 382 return Width(); 383 384 int32 modelIndex = fTableColumn->ModelIndex(); 385 BVariant value; 386 if (!fModel->GetValueAt(field->Object(), modelIndex, value)) 387 return Width(); 388 return fTableColumn->GetPreferredWidth(value, parent); 389 } 390 391 392 // #pragma mark - TreeTableRow 393 394 395 class TreeTableRow : public BRow { 396 public: 397 TreeTableRow(TreeTableNode* node) 398 : 399 fNode(node) 400 { 401 } 402 403 TreeTableNode* Node() 404 { 405 return fNode; 406 } 407 408 private: 409 TreeTableNode* fNode; 410 }; 411 412 413 // #pragma mark - TreeTableNode 414 415 416 class TreeTableNode { 417 public: 418 TreeTableNode(TreeTableNode* parent); 419 ~TreeTableNode(); 420 421 status_t Init(void* modelObject, int32 columnCount); 422 void DetachRow(); 423 424 TreeTableNode* Parent() const { return fParent; } 425 TreeTableRow* Row() const { return fRow; } 426 void* ModelObject() const; 427 428 bool AddChild(TreeTableNode* child, int32 index); 429 TreeTableNode* RemoveChild(int32 index); 430 431 int32 CountChildren() const; 432 TreeTableNode* ChildAt(int32 index); 433 int32 IndexOf(TreeTableNode* child); 434 435 private: 436 typedef BObjectList<TreeTableNode> NodeList; 437 438 private: 439 TreeTableNode* fParent; 440 TreeTableRow* fRow; 441 NodeList* fChildren; 442 }; 443 444 445 TreeTableNode::TreeTableNode(TreeTableNode* parent) 446 : 447 fParent(parent), 448 fRow(NULL), 449 fChildren(NULL) 450 { 451 } 452 453 454 TreeTableNode::~TreeTableNode() 455 { 456 delete fChildren; 457 delete fRow; 458 } 459 460 461 status_t 462 TreeTableNode::Init(void* modelObject, int32 columnCount) 463 { 464 // create row 465 fRow = new(std::nothrow) TreeTableRow(this); 466 if (fRow == NULL) 467 return B_NO_MEMORY; 468 469 // add dummy fields to row 470 for (int32 columnIndex = 0; columnIndex < columnCount; columnIndex++) { 471 // It would be nice to create only a single field and set it for all 472 // columns, but the row takes ultimate ownership, so it have to be 473 // individual objects. 474 TreeTableField* field = new(std::nothrow) TreeTableField(modelObject); 475 if (field == NULL) 476 return B_NO_MEMORY; 477 478 fRow->SetField(field, columnIndex); 479 } 480 481 return B_OK; 482 } 483 484 485 void 486 TreeTableNode::DetachRow() 487 { 488 489 fRow = NULL; 490 491 if (fChildren != NULL) { 492 for (int32 i = 0; TreeTableNode* child = fChildren->ItemAt(i); i++) 493 child->DetachRow(); 494 } 495 } 496 497 498 void* 499 TreeTableNode::ModelObject() const 500 { 501 TreeTableField* field = dynamic_cast<TreeTableField*>(fRow->GetField(0)); 502 return field->Object(); 503 } 504 505 506 bool 507 TreeTableNode::AddChild(TreeTableNode* child, int32 index) 508 { 509 if (fChildren == NULL) { 510 fChildren = new(std::nothrow) NodeList(10, true); 511 if (fChildren == NULL) 512 return false; 513 } 514 515 return fChildren->AddItem(child, index); 516 } 517 518 519 TreeTableNode* 520 TreeTableNode::RemoveChild(int32 index) 521 { 522 return fChildren != NULL ? fChildren->RemoveItemAt(index) : NULL; 523 } 524 525 526 int32 527 TreeTableNode::CountChildren() const 528 { 529 return fChildren != NULL ? fChildren->CountItems() : 0; 530 } 531 532 533 TreeTableNode* 534 TreeTableNode::ChildAt(int32 index) 535 { 536 return fChildren != NULL ? fChildren->ItemAt(index) : NULL; 537 } 538 539 540 int32 541 TreeTableNode::IndexOf(TreeTableNode* child) 542 { 543 return fChildren != NULL ? fChildren->IndexOf(child) : -1; 544 } 545 546 547 // #pragma mark - TreeTableSelectionModel 548 549 550 TreeTableSelectionModel::TreeTableSelectionModel(TreeTable* table) 551 : 552 fTreeTable(table), 553 fNodes(NULL), 554 fNodeCount(-1) 555 { 556 } 557 558 559 TreeTableSelectionModel::~TreeTableSelectionModel() 560 { 561 delete[] fNodes; 562 } 563 564 565 int32 566 TreeTableSelectionModel::CountNodes() 567 { 568 _Update(); 569 570 return fNodeCount; 571 } 572 573 574 void* 575 TreeTableSelectionModel::NodeAt(int32 index) 576 { 577 if (TreeTableNode* node = _NodeAt(index)) 578 return node->ModelObject(); 579 return NULL; 580 } 581 582 583 bool 584 TreeTableSelectionModel::GetPathAt(int32 index, TreeTablePath& _path) 585 { 586 if (TreeTableNode* node = _NodeAt(index)) { 587 fTreeTable->_GetPathForNode(node, _path); 588 return true; 589 } 590 591 return false; 592 } 593 594 595 void 596 TreeTableSelectionModel::_SelectionChanged() 597 { 598 if (fNodeCount >= 0) { 599 fNodeCount = -1; 600 delete[] fNodes; 601 fNodes = NULL; 602 } 603 } 604 605 606 void 607 TreeTableSelectionModel::_Update() 608 { 609 if (fNodeCount >= 0) 610 return; 611 612 // count the nodes 613 fNodeCount = 0; 614 BRow* row = NULL; 615 while ((row = fTreeTable->CurrentSelection(row)) != NULL) 616 fNodeCount++; 617 618 if (fNodeCount == 0) 619 return; 620 621 // allocate node array 622 fNodes = new(std::nothrow) TreeTableNode*[fNodeCount]; 623 if (fNodes == NULL) { 624 fNodeCount = 0; 625 return; 626 } 627 628 // get the nodes 629 row = NULL; 630 int32 index = 0; 631 while ((row = fTreeTable->CurrentSelection(row)) != NULL) 632 fNodes[index++] = dynamic_cast<TreeTableRow*>(row)->Node(); 633 } 634 635 636 TreeTableNode* 637 TreeTableSelectionModel::_NodeAt(int32 index) 638 { 639 _Update(); 640 641 return index >= 0 && index < fNodeCount ? fNodes[index] : NULL; 642 } 643 644 645 // #pragma mark - Table 646 647 648 TreeTable::TreeTable(const char* name, uint32 flags, border_style borderStyle, 649 bool showHorizontalScrollbar) 650 : 651 AbstractTable(name, flags, borderStyle, showHorizontalScrollbar), 652 fModel(NULL), 653 fRootNode(NULL), 654 fSelectionModel(this), 655 fIgnoreSelectionChange(0) 656 { 657 } 658 659 660 TreeTable::TreeTable(TreeTableModel* model, const char* name, uint32 flags, 661 border_style borderStyle, bool showHorizontalScrollbar) 662 : 663 AbstractTable(name, flags, borderStyle, showHorizontalScrollbar), 664 fModel(NULL), 665 fRootNode(NULL), 666 fSelectionModel(this), 667 fIgnoreSelectionChange(0) 668 { 669 SetTreeTableModel(model); 670 } 671 672 673 TreeTable::~TreeTable() 674 { 675 SetTreeTableModel(NULL); 676 677 for (int32 i = CountColumns() - 1; i >= 0; i--) 678 RemoveColumn(ColumnAt(i)); 679 } 680 681 682 bool 683 TreeTable::SetTreeTableModel(TreeTableModel* model) 684 { 685 if (model == fModel) 686 return true; 687 688 if (fModel != NULL) { 689 fModel->RemoveListener(this); 690 691 if (fRootNode != NULL) { 692 fRootNode->DetachRow(); 693 delete fRootNode; 694 fRootNode = NULL; 695 } 696 697 Clear(); 698 699 for (int32 i = 0; AbstractColumn* column = fColumns.ItemAt(i); i++) 700 column->SetModel(NULL); 701 } 702 703 fModel = model; 704 705 if (fModel == NULL) 706 return true; 707 708 fRootNode = new(std::nothrow) TreeTableNode(NULL); 709 if (fRootNode == NULL) 710 return false; 711 712 if (fRootNode->Init(fModel->Root(), fModel->CountColumns()) != B_OK) { 713 delete fRootNode; 714 fRootNode = NULL; 715 return false; 716 } 717 718 fModel->AddListener(this); 719 720 for (int32 i = 0; AbstractColumn* column = fColumns.ItemAt(i); i++) 721 column->SetModel(fModel); 722 723 // recursively create the rows 724 if (!_AddChildRows(fRootNode, 0, fModel->CountChildren(fModel->Root()), 725 fModel->CountColumns())) { 726 SetTreeTableModel(NULL); 727 return false; 728 } 729 730 return true; 731 } 732 733 734 TreeTableSelectionModel* 735 TreeTable::SelectionModel() 736 { 737 return &fSelectionModel; 738 } 739 740 741 void 742 TreeTable::SelectNode(const TreeTablePath& path, bool extendSelection) 743 { 744 TreeTableNode* node = _NodeForPath(path); 745 if (node == NULL) 746 return; 747 748 if (!extendSelection) { 749 fIgnoreSelectionChange++; 750 DeselectAll(); 751 fIgnoreSelectionChange--; 752 } 753 754 AddToSelection(node->Row()); 755 } 756 757 758 void 759 TreeTable::DeselectNode(const TreeTablePath& path) 760 { 761 if (TreeTableNode* node = _NodeForPath(path)) 762 Deselect(node->Row()); 763 } 764 765 766 void 767 TreeTable::DeselectAllNodes() 768 { 769 DeselectAll(); 770 } 771 772 773 bool 774 TreeTable::IsNodeExpanded(const TreeTablePath& path) const 775 { 776 if (TreeTableNode* node = _NodeForPath(path)) 777 return node->Row()->IsExpanded(); 778 return false; 779 } 780 781 782 void 783 TreeTable::SetNodeExpanded(const TreeTablePath& path, bool expanded, 784 bool expandAncestors) 785 { 786 if (TreeTableNode* node = _NodeForPath(path)) 787 _SetNodeExpanded(node, expanded, expandAncestors); 788 } 789 790 791 void 792 TreeTable::ScrollToNode(const TreeTablePath& path) 793 { 794 if (TreeTableNode* node = _NodeForPath(path)) 795 BColumnListView::ScrollTo(node->Row()); 796 } 797 798 799 bool 800 TreeTable::AddTreeTableListener(TreeTableListener* listener) 801 { 802 return fListeners.AddItem(listener); 803 } 804 805 806 void 807 TreeTable::RemoveTreeTableListener(TreeTableListener* listener) 808 { 809 fListeners.RemoveItem(listener); 810 } 811 812 813 void 814 TreeTable::SelectionChanged() 815 { 816 if (fIgnoreSelectionChange > 0) 817 return; 818 819 fSelectionModel._SelectionChanged(); 820 821 if (!fListeners.IsEmpty()) { 822 int32 listenerCount = fListeners.CountItems(); 823 for (int32 i = listenerCount - 1; i >= 0; i--) 824 fListeners.ItemAt(i)->TreeTableSelectionChanged(this); 825 } 826 } 827 828 829 AbstractTable::AbstractColumn* 830 TreeTable::CreateColumn(TableColumn* column) 831 { 832 return new Column(fModel, column); 833 } 834 835 836 void 837 TreeTable::ColumnMouseDown(AbstractColumn* column, BRow* _row, BField* field, 838 BPoint screenWhere, uint32 buttons) 839 { 840 if (!fListeners.IsEmpty()) { 841 // get the table node and the column index 842 TreeTableRow* row = dynamic_cast<TreeTableRow*>(_row); 843 int32 columnIndex = column->LogicalFieldNum(); 844 if (row == NULL || columnIndex < 0) 845 return; 846 847 // get the node path 848 TreeTablePath path; 849 _GetPathForNode(row->Node(), path); 850 851 // notify listeners 852 int32 listenerCount = fListeners.CountItems(); 853 for (int32 i = listenerCount - 1; i >= 0; i--) { 854 fListeners.ItemAt(i)->TreeTableCellMouseDown(this, path, 855 columnIndex, screenWhere, buttons); 856 } 857 } 858 } 859 860 861 void 862 TreeTable::ColumnMouseUp(AbstractColumn* column, BRow* _row, BField* field, 863 BPoint screenWhere, uint32 buttons) 864 { 865 if (!fListeners.IsEmpty()) { 866 // get the table node and the column index 867 TreeTableRow* row = dynamic_cast<TreeTableRow*>(_row); 868 int32 columnIndex = column->LogicalFieldNum(); 869 if (row == NULL || columnIndex < 0) 870 return; 871 872 // get the node path 873 TreeTablePath path; 874 _GetPathForNode(row->Node(), path); 875 876 // notify listeners 877 int32 listenerCount = fListeners.CountItems(); 878 for (int32 i = listenerCount - 1; i >= 0; i--) { 879 fListeners.ItemAt(i)->TreeTableCellMouseUp(this, path, columnIndex, 880 screenWhere, buttons); 881 } 882 } 883 } 884 885 886 void 887 TreeTable::TableNodesAdded(TreeTableModel* model, const TreeTablePath& path, 888 int32 childIndex, int32 count) 889 { 890 TreeTableNode* node = _NodeForPath(path); 891 if (node == NULL) 892 return; 893 894 _AddChildRows(node, childIndex, count, fModel->CountColumns()); 895 } 896 897 898 void 899 TreeTable::TableNodesRemoved(TreeTableModel* model, const TreeTablePath& path, 900 int32 childIndex, int32 count) 901 { 902 TreeTableNode* node = _NodeForPath(path); 903 if (node == NULL) 904 return; 905 906 _RemoveChildRows(node, childIndex, count); 907 } 908 909 910 void 911 TreeTable::TableNodesChanged(TreeTableModel* model, const TreeTablePath& path, 912 int32 childIndex, int32 count) 913 { 914 TreeTableNode* node = _NodeForPath(path); 915 if (node == NULL) 916 return; 917 918 int32 endIndex = childIndex + count; 919 for (int32 i = childIndex; i < endIndex; i++) { 920 if (TreeTableNode* child = node->ChildAt(i)) 921 UpdateRow(child->Row()); 922 } 923 } 924 925 926 void 927 TreeTable::ExpandOrCollapse(BRow* _row, bool expand) 928 { 929 TreeTableRow* row = dynamic_cast<TreeTableRow*>(_row); 930 if (row == NULL || row->IsExpanded() == expand) 931 return; 932 933 AbstractTable::ExpandOrCollapse(row, expand); 934 935 if (row->IsExpanded() != expand) 936 return; 937 938 TreeTablePath path; 939 _GetPathForNode(row->Node(), path); 940 941 int32 listenerCount = fListeners.CountItems(); 942 for (int32 i = listenerCount - 1; i >= 0; i--) 943 fListeners.ItemAt(i)->TreeTableNodeExpandedChanged(this, path, expand); 944 } 945 946 947 void 948 TreeTable::ItemInvoked() 949 { 950 if (fListeners.IsEmpty()) 951 return; 952 953 TreeTableRow* row = dynamic_cast<TreeTableRow*>(CurrentSelection()); 954 if (row == NULL) 955 return; 956 957 TreeTablePath path; 958 _GetPathForNode(row->Node(), path); 959 960 int32 listenerCount = fListeners.CountItems(); 961 for (int32 i = listenerCount - 1; i >= 0; i--) 962 fListeners.ItemAt(i)->TreeTableNodeInvoked(this, path); 963 } 964 965 966 bool 967 TreeTable::_AddChildRows(TreeTableNode* parentNode, int32 childIndex, 968 int32 count, int32 columnCount) 969 { 970 int32 childEndIndex = childIndex + count; 971 for (int32 i = childIndex; i < childEndIndex; i++) { 972 void* child = fModel->ChildAt(parentNode->ModelObject(), i); 973 974 // create node 975 TreeTableNode* node = new(std::nothrow) TreeTableNode(parentNode); 976 if (node == NULL || node->Init(child, columnCount) != B_OK 977 || !parentNode->AddChild(node, i)) { 978 delete node; 979 return false; 980 } 981 982 // add row 983 AddRow(node->Row(), i, 984 parentNode != fRootNode ? parentNode->Row() : NULL); 985 986 // recursively create children 987 if (!_AddChildRows(node, 0, fModel->CountChildren(child), columnCount)) 988 return false; 989 } 990 991 return true; 992 } 993 994 995 void 996 TreeTable::_RemoveChildRows(TreeTableNode* parentNode, int32 childIndex, 997 int32 count) 998 { 999 for (int32 i = childIndex + count - 1; i >= childIndex; i--) { 1000 if (TreeTableNode* child = parentNode->RemoveChild(i)) { 1001 int32 childCount = child->CountChildren(); 1002 if (childCount > 0) 1003 _RemoveChildRows(child, 0, childCount); 1004 1005 RemoveRow(child->Row()); 1006 delete child; 1007 } 1008 } 1009 } 1010 1011 1012 void 1013 TreeTable::_SetNodeExpanded(TreeTableNode* node, bool expanded, 1014 bool expandAncestors) 1015 { 1016 if (expanded && expandAncestors && node != fRootNode) 1017 _SetNodeExpanded(node->Parent(), true, true); 1018 1019 ExpandOrCollapse(node->Row(), expanded); 1020 } 1021 1022 1023 TreeTableNode* 1024 TreeTable::_NodeForPath(const TreeTablePath& path) const 1025 { 1026 TreeTableNode* node = fRootNode; 1027 1028 int32 count = path.CountComponents(); 1029 for (int32 i = 0; node != NULL && i < count; i++) 1030 node = node->ChildAt(path.ComponentAt(i)); 1031 1032 return node; 1033 } 1034 1035 1036 void 1037 TreeTable::_GetPathForNode(TreeTableNode* node, TreeTablePath& _path) const 1038 { 1039 if (node == fRootNode) { 1040 _path.Clear(); 1041 return; 1042 } 1043 1044 _GetPathForNode(node->Parent(), _path); 1045 _path.AddComponent(node->Parent()->IndexOf(node)); 1046 } 1047