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 15class TreeTableField : public BField { 16public: 17 TreeTableField(void* object) 18 : 19 fObject(object) 20 { 21 } 22 23 void* Object() const 24 { 25 return fObject; 26 } 27 28private: 29 void* fObject; 30}; 31 32 33// #pragma mark - TreeTablePath 34 35 36TreeTablePath::TreeTablePath() 37{ 38} 39 40 41TreeTablePath::TreeTablePath(const TreeTablePath& other) 42{ 43 *this = other; 44} 45 46 47TreeTablePath::TreeTablePath(const TreeTablePath& other, int32 childIndex) 48{ 49 *this = other; 50 AddComponent(childIndex); 51} 52 53 54TreeTablePath::~TreeTablePath() 55{ 56} 57 58 59bool 60TreeTablePath::AddComponent(int32 childIndex) 61{ 62 try { 63 fComponents.push_back(childIndex); 64 return true; 65 } catch (...) { 66 return false; 67 } 68} 69 70 71int32 72TreeTablePath::RemoveLastComponent() 73{ 74 if (fComponents.empty()) 75 return -1; 76 77 int32 index = fComponents.back(); 78 fComponents.pop_back(); 79 return index; 80} 81 82void 83TreeTablePath::Clear() 84{ 85 fComponents.clear(); 86} 87 88 89int32 90TreeTablePath::CountComponents() const 91{ 92 return fComponents.size(); 93} 94 95 96int32 97TreeTablePath::ComponentAt(int32 index) const 98{ 99 if (index < 0 || (size_t)index >= fComponents.size()) 100 return -1; 101 return fComponents[index]; 102} 103 104 105TreeTablePath& 106TreeTablePath::operator=(const TreeTablePath& other) 107{ 108 try { 109 fComponents = other.fComponents; 110 } catch (...) { 111 } 112 return *this; 113} 114 115 116bool 117TreeTablePath::operator==(const TreeTablePath& other) const 118{ 119 return fComponents == other.fComponents; 120} 121 122 123bool 124TreeTablePath::operator!=(const TreeTablePath& other) const 125{ 126 return fComponents != other.fComponents; 127} 128 129 130// #pragma mark - TreeTableModelListener 131 132 133TreeTableModelListener::~TreeTableModelListener() 134{ 135} 136 137 138void 139TreeTableModelListener::TableNodesAdded(TreeTableModel* model, 140 const TreeTablePath& path, int32 childIndex, int32 count) 141{ 142} 143 144 145void 146TreeTableModelListener::TableNodesRemoved(TreeTableModel* model, 147 const TreeTablePath& path, int32 childIndex, int32 count) 148{ 149} 150 151 152void 153TreeTableModelListener::TableNodesChanged(TreeTableModel* model, 154 const TreeTablePath& path, int32 childIndex, int32 count) 155{ 156} 157 158 159void 160TreeTableModelListener::TableModelReset(TreeTableModel* model) 161{ 162} 163 164 165// #pragma mark - TreeTableModel 166 167 168TreeTableModel::~TreeTableModel() 169{ 170} 171 172 173void* 174TreeTableModel::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 186bool 187TreeTableModel::AddListener(TreeTableModelListener* listener) 188{ 189 return fListeners.AddItem(listener); 190} 191 192 193void 194TreeTableModel::RemoveListener(TreeTableModelListener* listener) 195{ 196 fListeners.RemoveItem(listener); 197} 198 199 200void 201TreeTableModel::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 212void 213TreeTableModel::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 224void 225TreeTableModel::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 236void 237TreeTableModel::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 249TreeTableToolTipProvider::~TreeTableToolTipProvider() 250{ 251} 252 253 254// #pragma mark - TreeTableListener 255 256 257TreeTableListener::~TreeTableListener() 258{ 259} 260 261 262void 263TreeTableListener::TreeTableSelectionChanged(TreeTable* table) 264{ 265} 266 267 268void 269TreeTableListener::TreeTableNodeInvoked(TreeTable* table, 270 const TreeTablePath& path) 271{ 272} 273 274 275void 276TreeTableListener::TreeTableNodeExpandedChanged(TreeTable* table, 277 const TreeTablePath& path, bool expanded) 278{ 279} 280 281 282void 283TreeTableListener::TreeTableCellMouseDown(TreeTable* table, 284 const TreeTablePath& path, int32 columnIndex, BPoint screenWhere, 285 uint32 buttons) 286{ 287} 288 289 290void 291TreeTableListener::TreeTableCellMouseUp(TreeTable* table, 292 const TreeTablePath& path, int32 columnIndex, BPoint screenWhere, 293 uint32 buttons) 294{ 295} 296 297 298// #pragma mark - Column 299 300 301class TreeTable::Column : public AbstractColumn { 302public: 303 Column(TreeTableModel* model, 304 TableColumn* tableColumn); 305 virtual ~Column(); 306 307 virtual void SetModel(AbstractTableModelBase* model); 308 309protected: 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 319private: 320 TreeTableModel* fModel; 321}; 322 323 324TreeTable::Column::Column(TreeTableModel* model, TableColumn* tableColumn) 325 : 326 AbstractColumn(tableColumn), 327 fModel(model) 328{ 329} 330 331 332TreeTable::Column::~Column() 333{ 334} 335 336 337void 338TreeTable::Column::SetModel(AbstractTableModelBase* model) 339{ 340 fModel = dynamic_cast<TreeTableModel*>(model); 341} 342 343 344void 345TreeTable::Column::DrawTitle(BRect rect, BView* targetView) 346{ 347 fTableColumn->DrawTitle(rect, targetView); 348} 349 350 351void 352TreeTable::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 366int 367TreeTable::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 395void 396TreeTable::Column::GetColumnName(BString* into) const 397{ 398 fTableColumn->GetColumnName(into); 399} 400 401 402float 403TreeTable::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 420class TreeTableRow : public BRow { 421public: 422 TreeTableRow(TreeTableNode* node) 423 : 424 fNode(node) 425 { 426 } 427 428 TreeTableNode* Node() 429 { 430 return fNode; 431 } 432 433private: 434 TreeTableNode* fNode; 435}; 436 437 438// #pragma mark - TreeTableNode 439 440 441class TreeTableNode { 442public: 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 460private: 461 typedef BObjectList<TreeTableNode> NodeList; 462 463private: 464 TreeTableNode* fParent; 465 TreeTableRow* fRow; 466 NodeList* fChildren; 467}; 468 469 470TreeTableNode::TreeTableNode(TreeTableNode* parent) 471 : 472 fParent(parent), 473 fRow(NULL), 474 fChildren(NULL) 475{ 476} 477 478 479TreeTableNode::~TreeTableNode() 480{ 481 delete fChildren; 482 delete fRow; 483} 484 485 486status_t 487TreeTableNode::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 510void 511TreeTableNode::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 523void* 524TreeTableNode::ModelObject() const 525{ 526 TreeTableField* field = dynamic_cast<TreeTableField*>(fRow->GetField(0)); 527 return field->Object(); 528} 529 530 531bool 532TreeTableNode::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 544TreeTableNode* 545TreeTableNode::RemoveChild(int32 index) 546{ 547 return fChildren != NULL ? fChildren->RemoveItemAt(index) : NULL; 548} 549 550 551int32 552TreeTableNode::CountChildren() const 553{ 554 return fChildren != NULL ? fChildren->CountItems() : 0; 555} 556 557 558TreeTableNode* 559TreeTableNode::ChildAt(int32 index) 560{ 561 return fChildren != NULL ? fChildren->ItemAt(index) : NULL; 562} 563 564 565int32 566TreeTableNode::IndexOf(TreeTableNode* child) 567{ 568 return fChildren != NULL ? fChildren->IndexOf(child) : -1; 569} 570 571 572// #pragma mark - TreeTableSelectionModel 573 574 575TreeTableSelectionModel::TreeTableSelectionModel(TreeTable* table) 576 : 577 fTreeTable(table), 578 fNodes(NULL), 579 fNodeCount(-1) 580{ 581} 582 583 584TreeTableSelectionModel::~TreeTableSelectionModel() 585{ 586 delete[] fNodes; 587} 588 589 590int32 591TreeTableSelectionModel::CountNodes() 592{ 593 _Update(); 594 595 return fNodeCount; 596} 597 598 599void* 600TreeTableSelectionModel::NodeAt(int32 index) 601{ 602 if (TreeTableNode* node = _NodeAt(index)) 603 return node->ModelObject(); 604 return NULL; 605} 606 607 608bool 609TreeTableSelectionModel::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 620void 621TreeTableSelectionModel::_SelectionChanged() 622{ 623 if (fNodeCount >= 0) { 624 fNodeCount = -1; 625 delete[] fNodes; 626 fNodes = NULL; 627 } 628} 629 630 631void 632TreeTableSelectionModel::_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 661TreeTableNode* 662TreeTableSelectionModel::_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 673TreeTable::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 686TreeTable::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 700TreeTable::~TreeTable() 701{ 702 SetTreeTableModel(NULL); 703} 704 705 706bool 707TreeTable::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 758void 759TreeTable::SetToolTipProvider(TreeTableToolTipProvider* toolTipProvider) 760{ 761 fToolTipProvider = toolTipProvider; 762} 763 764 765TreeTableSelectionModel* 766TreeTable::SelectionModel() 767{ 768 return &fSelectionModel; 769} 770 771 772void 773TreeTable::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 789void 790TreeTable::DeselectNode(const TreeTablePath& path) 791{ 792 if (TreeTableNode* node = _NodeForPath(path)) 793 Deselect(node->Row()); 794} 795 796 797void 798TreeTable::DeselectAllNodes() 799{ 800 DeselectAll(); 801} 802 803 804bool 805TreeTable::IsNodeExpanded(const TreeTablePath& path) const 806{ 807 if (TreeTableNode* node = _NodeForPath(path)) 808 return node->Row()->IsExpanded(); 809 return false; 810} 811 812 813void 814TreeTable::SetNodeExpanded(const TreeTablePath& path, bool expanded, 815 bool expandAncestors) 816{ 817 if (TreeTableNode* node = _NodeForPath(path)) 818 _SetNodeExpanded(node, expanded, expandAncestors); 819} 820 821 822void 823TreeTable::ScrollToNode(const TreeTablePath& path) 824{ 825 if (TreeTableNode* node = _NodeForPath(path)) 826 BColumnListView::ScrollTo(node->Row()); 827} 828 829 830bool 831TreeTable::AddTreeTableListener(TreeTableListener* listener) 832{ 833 return fListeners.AddItem(listener); 834} 835 836 837void 838TreeTable::RemoveTreeTableListener(TreeTableListener* listener) 839{ 840 fListeners.RemoveItem(listener); 841} 842 843 844status_t 845TreeTable::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 862bool 863TreeTable::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 887void 888TreeTable::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 903AbstractTable::AbstractColumn* 904TreeTable::CreateColumn(TableColumn* column) 905{ 906 return new Column(fModel, column); 907} 908 909 910void 911TreeTable::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 935void 936TreeTable::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 960void 961TreeTable::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 972void 973TreeTable::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 984void 985TreeTable::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 1000void 1001TreeTable::TableModelReset(TreeTableModel* model) 1002{ 1003 _RemoveChildRows(fRootNode, 0, fRootNode->CountChildren()); 1004 _AddChildRows(fRootNode, 0, fModel->CountChildren( 1005 fModel->Root()), fModel->CountColumns()); 1006} 1007 1008 1009void 1010TreeTable::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 1030void 1031TreeTable::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 1049bool 1050TreeTable::_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 1078void 1079TreeTable::_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 1103void 1104TreeTable::_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 1114TreeTableNode* 1115TreeTable::_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 1127void 1128TreeTable::_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