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