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