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 fToolTipProvider(NULL), 692 fRootNode(NULL), 693 fSelectionModel(this), 694 fIgnoreSelectionChange(0) 695 { 696 SetTreeTableModel(model); 697 } 698 699 700 TreeTable::~TreeTable() 701 { 702 SetTreeTableModel(NULL); 703 } 704 705 706 bool 707 TreeTable::SetTreeTableModel(TreeTableModel* model) 708 { 709 if (model == fModel) 710 return true; 711 712 if (fModel != NULL) { 713 fModel->RemoveListener(this); 714 715 if (fRootNode != NULL) { 716 fRootNode->DetachRow(); 717 delete fRootNode; 718 fRootNode = NULL; 719 } 720 721 Clear(); 722 723 for (int32 i = 0; AbstractColumn* column = fColumns.ItemAt(i); i++) 724 column->SetModel(NULL); 725 } 726 727 fModel = model; 728 729 if (fModel == NULL) 730 return true; 731 732 fRootNode = new(std::nothrow) TreeTableNode(NULL); 733 if (fRootNode == NULL) 734 return false; 735 736 if (fRootNode->Init(fModel->Root(), fModel->CountColumns()) != B_OK) { 737 delete fRootNode; 738 fRootNode = NULL; 739 return false; 740 } 741 742 fModel->AddListener(this); 743 744 for (int32 i = 0; AbstractColumn* column = fColumns.ItemAt(i); i++) 745 column->SetModel(fModel); 746 747 // recursively create the rows 748 if (!_AddChildRows(fRootNode, 0, fModel->CountChildren(fModel->Root()), 749 fModel->CountColumns())) { 750 SetTreeTableModel(NULL); 751 return false; 752 } 753 754 return true; 755 } 756 757 758 void 759 TreeTable::SetToolTipProvider(TreeTableToolTipProvider* toolTipProvider) 760 { 761 fToolTipProvider = toolTipProvider; 762 } 763 764 765 TreeTableSelectionModel* 766 TreeTable::SelectionModel() 767 { 768 return &fSelectionModel; 769 } 770 771 772 void 773 TreeTable::SelectNode(const TreeTablePath& path, bool extendSelection) 774 { 775 TreeTableNode* node = _NodeForPath(path); 776 if (node == NULL) 777 return; 778 779 if (!extendSelection) { 780 fIgnoreSelectionChange++; 781 DeselectAll(); 782 fIgnoreSelectionChange--; 783 } 784 785 AddToSelection(node->Row()); 786 } 787 788 789 void 790 TreeTable::DeselectNode(const TreeTablePath& path) 791 { 792 if (TreeTableNode* node = _NodeForPath(path)) 793 Deselect(node->Row()); 794 } 795 796 797 void 798 TreeTable::DeselectAllNodes() 799 { 800 DeselectAll(); 801 } 802 803 804 bool 805 TreeTable::IsNodeExpanded(const TreeTablePath& path) const 806 { 807 if (TreeTableNode* node = _NodeForPath(path)) 808 return node->Row()->IsExpanded(); 809 return false; 810 } 811 812 813 void 814 TreeTable::SetNodeExpanded(const TreeTablePath& path, bool expanded, 815 bool expandAncestors) 816 { 817 if (TreeTableNode* node = _NodeForPath(path)) 818 _SetNodeExpanded(node, expanded, expandAncestors); 819 } 820 821 822 void 823 TreeTable::ScrollToNode(const TreeTablePath& path) 824 { 825 if (TreeTableNode* node = _NodeForPath(path)) 826 BColumnListView::ScrollTo(node->Row()); 827 } 828 829 830 bool 831 TreeTable::AddTreeTableListener(TreeTableListener* listener) 832 { 833 return fListeners.AddItem(listener); 834 } 835 836 837 void 838 TreeTable::RemoveTreeTableListener(TreeTableListener* listener) 839 { 840 fListeners.RemoveItem(listener); 841 } 842 843 844 status_t 845 TreeTable::GetCellRectAt(const TreeTablePath& path, int32 colIndex, 846 BRect& _output) const 847 { 848 TreeTableNode* node = _NodeForPath(path); 849 if (node == NULL) 850 return B_ENTRY_NOT_FOUND; 851 852 AbstractColumn* column = fColumns.ItemAt(colIndex); 853 if (column == NULL) 854 return B_ENTRY_NOT_FOUND; 855 856 _output = GetFieldRect(node->Row(), column); 857 858 return B_OK; 859 } 860 861 862 bool 863 TreeTable::GetToolTipAt(BPoint point, BToolTip** _tip) 864 { 865 if (fToolTipProvider == NULL) 866 return AbstractTable::GetToolTipAt(point, _tip); 867 868 // get the table row 869 BRow* row = RowAt(point); 870 if (row == NULL) 871 return AbstractTable::GetToolTipAt(point, _tip); 872 873 TreeTableRow* treeRow = dynamic_cast<TreeTableRow*>(row); 874 // get the table column 875 BColumn* column = ColumnAt(point); 876 877 int32 columnIndex = column != NULL ? column->LogicalFieldNum() : -1; 878 879 TreeTablePath path; 880 _GetPathForNode(treeRow->Node(), path); 881 882 return fToolTipProvider->GetToolTipForTablePath(path, columnIndex, 883 _tip); 884 } 885 886 887 void 888 TreeTable::SelectionChanged() 889 { 890 if (fIgnoreSelectionChange > 0) 891 return; 892 893 fSelectionModel._SelectionChanged(); 894 895 if (!fListeners.IsEmpty()) { 896 int32 listenerCount = fListeners.CountItems(); 897 for (int32 i = listenerCount - 1; i >= 0; i--) 898 fListeners.ItemAt(i)->TreeTableSelectionChanged(this); 899 } 900 } 901 902 903 AbstractTable::AbstractColumn* 904 TreeTable::CreateColumn(TableColumn* column) 905 { 906 return new Column(fModel, column); 907 } 908 909 910 void 911 TreeTable::ColumnMouseDown(AbstractColumn* column, BRow* _row, BField* field, 912 BPoint screenWhere, uint32 buttons) 913 { 914 if (!fListeners.IsEmpty()) { 915 // get the table node and the column index 916 TreeTableRow* row = dynamic_cast<TreeTableRow*>(_row); 917 int32 columnIndex = column->LogicalFieldNum(); 918 if (row == NULL || columnIndex < 0) 919 return; 920 921 // get the node path 922 TreeTablePath path; 923 _GetPathForNode(row->Node(), path); 924 925 // notify listeners 926 int32 listenerCount = fListeners.CountItems(); 927 for (int32 i = listenerCount - 1; i >= 0; i--) { 928 fListeners.ItemAt(i)->TreeTableCellMouseDown(this, path, 929 columnIndex, screenWhere, buttons); 930 } 931 } 932 } 933 934 935 void 936 TreeTable::ColumnMouseUp(AbstractColumn* column, BRow* _row, BField* field, 937 BPoint screenWhere, uint32 buttons) 938 { 939 if (!fListeners.IsEmpty()) { 940 // get the table node and the column index 941 TreeTableRow* row = dynamic_cast<TreeTableRow*>(_row); 942 int32 columnIndex = column->LogicalFieldNum(); 943 if (row == NULL || columnIndex < 0) 944 return; 945 946 // get the node path 947 TreeTablePath path; 948 _GetPathForNode(row->Node(), path); 949 950 // notify listeners 951 int32 listenerCount = fListeners.CountItems(); 952 for (int32 i = listenerCount - 1; i >= 0; i--) { 953 fListeners.ItemAt(i)->TreeTableCellMouseUp(this, path, columnIndex, 954 screenWhere, buttons); 955 } 956 } 957 } 958 959 960 void 961 TreeTable::TableNodesAdded(TreeTableModel* model, const TreeTablePath& path, 962 int32 childIndex, int32 count) 963 { 964 TreeTableNode* node = _NodeForPath(path); 965 if (node == NULL) 966 return; 967 968 _AddChildRows(node, childIndex, count, fModel->CountColumns()); 969 } 970 971 972 void 973 TreeTable::TableNodesRemoved(TreeTableModel* model, const TreeTablePath& path, 974 int32 childIndex, int32 count) 975 { 976 TreeTableNode* node = _NodeForPath(path); 977 if (node == NULL) 978 return; 979 980 _RemoveChildRows(node, childIndex, count); 981 } 982 983 984 void 985 TreeTable::TableNodesChanged(TreeTableModel* model, const TreeTablePath& path, 986 int32 childIndex, int32 count) 987 { 988 TreeTableNode* node = _NodeForPath(path); 989 if (node == NULL) 990 return; 991 992 int32 endIndex = childIndex + count; 993 for (int32 i = childIndex; i < endIndex; i++) { 994 if (TreeTableNode* child = node->ChildAt(i)) 995 UpdateRow(child->Row()); 996 } 997 } 998 999 1000 void 1001 TreeTable::TableModelReset(TreeTableModel* model) 1002 { 1003 _RemoveChildRows(fRootNode, 0, fRootNode->CountChildren()); 1004 _AddChildRows(fRootNode, 0, fModel->CountChildren( 1005 fModel->Root()), fModel->CountColumns()); 1006 } 1007 1008 1009 void 1010 TreeTable::ExpandOrCollapse(BRow* _row, bool expand) 1011 { 1012 TreeTableRow* row = dynamic_cast<TreeTableRow*>(_row); 1013 if (row == NULL || row->IsExpanded() == expand) 1014 return; 1015 1016 AbstractTable::ExpandOrCollapse(row, expand); 1017 1018 if (row->IsExpanded() != expand) 1019 return; 1020 1021 TreeTablePath path; 1022 _GetPathForNode(row->Node(), path); 1023 1024 int32 listenerCount = fListeners.CountItems(); 1025 for (int32 i = listenerCount - 1; i >= 0; i--) 1026 fListeners.ItemAt(i)->TreeTableNodeExpandedChanged(this, path, expand); 1027 } 1028 1029 1030 void 1031 TreeTable::ItemInvoked() 1032 { 1033 if (fListeners.IsEmpty()) 1034 return; 1035 1036 TreeTableRow* row = dynamic_cast<TreeTableRow*>(CurrentSelection()); 1037 if (row == NULL) 1038 return; 1039 1040 TreeTablePath path; 1041 _GetPathForNode(row->Node(), path); 1042 1043 int32 listenerCount = fListeners.CountItems(); 1044 for (int32 i = listenerCount - 1; i >= 0; i--) 1045 fListeners.ItemAt(i)->TreeTableNodeInvoked(this, path); 1046 } 1047 1048 1049 bool 1050 TreeTable::_AddChildRows(TreeTableNode* parentNode, int32 childIndex, 1051 int32 count, int32 columnCount) 1052 { 1053 int32 childEndIndex = childIndex + count; 1054 for (int32 i = childIndex; i < childEndIndex; i++) { 1055 void* child = fModel->ChildAt(parentNode->ModelObject(), i); 1056 1057 // create node 1058 TreeTableNode* node = new(std::nothrow) TreeTableNode(parentNode); 1059 if (node == NULL || node->Init(child, columnCount) != B_OK 1060 || !parentNode->AddChild(node, i)) { 1061 delete node; 1062 return false; 1063 } 1064 1065 // add row 1066 AddRow(node->Row(), i, 1067 parentNode != fRootNode ? parentNode->Row() : NULL); 1068 1069 // recursively create children 1070 if (!_AddChildRows(node, 0, fModel->CountChildren(child), columnCount)) 1071 return false; 1072 } 1073 1074 return true; 1075 } 1076 1077 1078 void 1079 TreeTable::_RemoveChildRows(TreeTableNode* parentNode, int32 childIndex, 1080 int32 count) 1081 { 1082 // check if the removal request would in effect remove all 1083 // existing nodes. 1084 if (parentNode == fRootNode && childIndex == 0 1085 && count == parentNode->CountChildren()) { 1086 Clear(); 1087 return; 1088 } 1089 1090 for (int32 i = childIndex + count - 1; i >= childIndex; i--) { 1091 if (TreeTableNode* child = parentNode->RemoveChild(i)) { 1092 int32 childCount = child->CountChildren(); 1093 if (childCount > 0) 1094 _RemoveChildRows(child, 0, childCount); 1095 1096 RemoveRow(child->Row()); 1097 delete child; 1098 } 1099 } 1100 } 1101 1102 1103 void 1104 TreeTable::_SetNodeExpanded(TreeTableNode* node, bool expanded, 1105 bool expandAncestors) 1106 { 1107 if (expanded && expandAncestors && node != fRootNode) 1108 _SetNodeExpanded(node->Parent(), true, true); 1109 1110 ExpandOrCollapse(node->Row(), expanded); 1111 } 1112 1113 1114 TreeTableNode* 1115 TreeTable::_NodeForPath(const TreeTablePath& path) const 1116 { 1117 TreeTableNode* node = fRootNode; 1118 1119 int32 count = path.CountComponents(); 1120 for (int32 i = 0; node != NULL && i < count; i++) 1121 node = node->ChildAt(path.ComponentAt(i)); 1122 1123 return node; 1124 } 1125 1126 1127 void 1128 TreeTable::_GetPathForNode(TreeTableNode* node, TreeTablePath& _path) const 1129 { 1130 if (node == fRootNode) { 1131 _path.Clear(); 1132 return; 1133 } 1134 1135 _GetPathForNode(node->Parent(), _path); 1136 _path.AddComponent(node->Parent()->IndexOf(node)); 1137 } 1138