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:
TreeTableField(void * object)17 TreeTableField(void* object)
18 :
19 fObject(object)
20 {
21 }
22
Object() const23 void* Object() const
24 {
25 return fObject;
26 }
27
28 private:
29 void* fObject;
30 };
31
32
33 // #pragma mark - TreeTablePath
34
35
TreeTablePath()36 TreeTablePath::TreeTablePath()
37 {
38 }
39
40
TreeTablePath(const TreeTablePath & other)41 TreeTablePath::TreeTablePath(const TreeTablePath& other)
42 {
43 *this = other;
44 }
45
46
TreeTablePath(const TreeTablePath & other,int32 childIndex)47 TreeTablePath::TreeTablePath(const TreeTablePath& other, int32 childIndex)
48 {
49 *this = other;
50 AddComponent(childIndex);
51 }
52
53
~TreeTablePath()54 TreeTablePath::~TreeTablePath()
55 {
56 }
57
58
59 bool
AddComponent(int32 childIndex)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
RemoveLastComponent()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
Clear()83 TreeTablePath::Clear()
84 {
85 fComponents.clear();
86 }
87
88
89 int32
CountComponents() const90 TreeTablePath::CountComponents() const
91 {
92 return fComponents.size();
93 }
94
95
96 int32
ComponentAt(int32 index) const97 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&
operator =(const TreeTablePath & other)106 TreeTablePath::operator=(const TreeTablePath& other)
107 {
108 try {
109 fComponents = other.fComponents;
110 } catch (...) {
111 }
112 return *this;
113 }
114
115
116 bool
operator ==(const TreeTablePath & other) const117 TreeTablePath::operator==(const TreeTablePath& other) const
118 {
119 return fComponents == other.fComponents;
120 }
121
122
123 bool
operator !=(const TreeTablePath & other) const124 TreeTablePath::operator!=(const TreeTablePath& other) const
125 {
126 return fComponents != other.fComponents;
127 }
128
129
130 // #pragma mark - TreeTableModelListener
131
132
~TreeTableModelListener()133 TreeTableModelListener::~TreeTableModelListener()
134 {
135 }
136
137
138 void
TableNodesAdded(TreeTableModel * model,const TreeTablePath & path,int32 childIndex,int32 count)139 TreeTableModelListener::TableNodesAdded(TreeTableModel* model,
140 const TreeTablePath& path, int32 childIndex, int32 count)
141 {
142 }
143
144
145 void
TableNodesRemoved(TreeTableModel * model,const TreeTablePath & path,int32 childIndex,int32 count)146 TreeTableModelListener::TableNodesRemoved(TreeTableModel* model,
147 const TreeTablePath& path, int32 childIndex, int32 count)
148 {
149 }
150
151
152 void
TableNodesChanged(TreeTableModel * model,const TreeTablePath & path,int32 childIndex,int32 count)153 TreeTableModelListener::TableNodesChanged(TreeTableModel* model,
154 const TreeTablePath& path, int32 childIndex, int32 count)
155 {
156 }
157
158
159 void
TableModelReset(TreeTableModel * model)160 TreeTableModelListener::TableModelReset(TreeTableModel* model)
161 {
162 }
163
164
165 // #pragma mark - TreeTableModel
166
167
~TreeTableModel()168 TreeTableModel::~TreeTableModel()
169 {
170 }
171
172
173 void*
NodeForPath(const TreeTablePath & path) const174 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
AddListener(TreeTableModelListener * listener)187 TreeTableModel::AddListener(TreeTableModelListener* listener)
188 {
189 return fListeners.AddItem(listener);
190 }
191
192
193 void
RemoveListener(TreeTableModelListener * listener)194 TreeTableModel::RemoveListener(TreeTableModelListener* listener)
195 {
196 fListeners.RemoveItem(listener);
197 }
198
199
200 void
NotifyNodesAdded(const TreeTablePath & path,int32 childIndex,int32 count)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
NotifyNodesRemoved(const TreeTablePath & path,int32 childIndex,int32 count)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
NotifyNodesChanged(const TreeTablePath & path,int32 childIndex,int32 count)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
NotifyTableModelReset()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
~TreeTableToolTipProvider()249 TreeTableToolTipProvider::~TreeTableToolTipProvider()
250 {
251 }
252
253
254 // #pragma mark - TreeTableListener
255
256
~TreeTableListener()257 TreeTableListener::~TreeTableListener()
258 {
259 }
260
261
262 void
TreeTableSelectionChanged(TreeTable * table)263 TreeTableListener::TreeTableSelectionChanged(TreeTable* table)
264 {
265 }
266
267
268 void
TreeTableNodeInvoked(TreeTable * table,const TreeTablePath & path)269 TreeTableListener::TreeTableNodeInvoked(TreeTable* table,
270 const TreeTablePath& path)
271 {
272 }
273
274
275 void
TreeTableNodeExpandedChanged(TreeTable * table,const TreeTablePath & path,bool expanded)276 TreeTableListener::TreeTableNodeExpandedChanged(TreeTable* table,
277 const TreeTablePath& path, bool expanded)
278 {
279 }
280
281
282 void
TreeTableCellMouseDown(TreeTable * table,const TreeTablePath & path,int32 columnIndex,BPoint screenWhere,uint32 buttons)283 TreeTableListener::TreeTableCellMouseDown(TreeTable* table,
284 const TreeTablePath& path, int32 columnIndex, BPoint screenWhere,
285 uint32 buttons)
286 {
287 }
288
289
290 void
TreeTableCellMouseUp(TreeTable * table,const TreeTablePath & path,int32 columnIndex,BPoint screenWhere,uint32 buttons)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
Column(TreeTableModel * model,TableColumn * tableColumn)324 TreeTable::Column::Column(TreeTableModel* model, TableColumn* tableColumn)
325 :
326 AbstractColumn(tableColumn),
327 fModel(model)
328 {
329 }
330
331
~Column()332 TreeTable::Column::~Column()
333 {
334 }
335
336
337 void
SetModel(AbstractTableModelBase * model)338 TreeTable::Column::SetModel(AbstractTableModelBase* model)
339 {
340 fModel = dynamic_cast<TreeTableModel*>(model);
341 }
342
343
344 void
DrawTitle(BRect rect,BView * targetView)345 TreeTable::Column::DrawTitle(BRect rect, BView* targetView)
346 {
347 fTableColumn->DrawTitle(rect, targetView);
348 }
349
350
351 void
DrawField(BField * _field,BRect rect,BView * targetView)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
CompareFields(BField * _field1,BField * _field2)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
GetColumnName(BString * into) const396 TreeTable::Column::GetColumnName(BString* into) const
397 {
398 fTableColumn->GetColumnName(into);
399 }
400
401
402 float
GetPreferredWidth(BField * _field,BView * parent) const403 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:
TreeTableRow(TreeTableNode * node)422 TreeTableRow(TreeTableNode* node)
423 :
424 fNode(node)
425 {
426 }
427
Node()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
Parent() const449 TreeTableNode* Parent() const { return fParent; }
Row() const450 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
TreeTableNode(TreeTableNode * parent)470 TreeTableNode::TreeTableNode(TreeTableNode* parent)
471 :
472 fParent(parent),
473 fRow(NULL),
474 fChildren(NULL)
475 {
476 }
477
478
~TreeTableNode()479 TreeTableNode::~TreeTableNode()
480 {
481 delete fChildren;
482 delete fRow;
483 }
484
485
486 status_t
Init(void * modelObject,int32 columnCount)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
DetachRow()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*
ModelObject() const524 TreeTableNode::ModelObject() const
525 {
526 TreeTableField* field = dynamic_cast<TreeTableField*>(fRow->GetField(0));
527 return field->Object();
528 }
529
530
531 bool
AddChild(TreeTableNode * child,int32 index)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*
RemoveChild(int32 index)545 TreeTableNode::RemoveChild(int32 index)
546 {
547 return fChildren != NULL ? fChildren->RemoveItemAt(index) : NULL;
548 }
549
550
551 int32
CountChildren() const552 TreeTableNode::CountChildren() const
553 {
554 return fChildren != NULL ? fChildren->CountItems() : 0;
555 }
556
557
558 TreeTableNode*
ChildAt(int32 index)559 TreeTableNode::ChildAt(int32 index)
560 {
561 return fChildren != NULL ? fChildren->ItemAt(index) : NULL;
562 }
563
564
565 int32
IndexOf(TreeTableNode * child)566 TreeTableNode::IndexOf(TreeTableNode* child)
567 {
568 return fChildren != NULL ? fChildren->IndexOf(child) : -1;
569 }
570
571
572 // #pragma mark - TreeTableSelectionModel
573
574
TreeTableSelectionModel(TreeTable * table)575 TreeTableSelectionModel::TreeTableSelectionModel(TreeTable* table)
576 :
577 fTreeTable(table),
578 fNodes(NULL),
579 fNodeCount(-1)
580 {
581 }
582
583
~TreeTableSelectionModel()584 TreeTableSelectionModel::~TreeTableSelectionModel()
585 {
586 delete[] fNodes;
587 }
588
589
590 int32
CountNodes()591 TreeTableSelectionModel::CountNodes()
592 {
593 _Update();
594
595 return fNodeCount;
596 }
597
598
599 void*
NodeAt(int32 index)600 TreeTableSelectionModel::NodeAt(int32 index)
601 {
602 if (TreeTableNode* node = _NodeAt(index))
603 return node->ModelObject();
604 return NULL;
605 }
606
607
608 bool
GetPathAt(int32 index,TreeTablePath & _path)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
_SelectionChanged()621 TreeTableSelectionModel::_SelectionChanged()
622 {
623 if (fNodeCount >= 0) {
624 fNodeCount = -1;
625 delete[] fNodes;
626 fNodes = NULL;
627 }
628 }
629
630
631 void
_Update()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*
_NodeAt(int32 index)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
TreeTable(const char * name,uint32 flags,border_style borderStyle,bool showHorizontalScrollbar)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
TreeTable(TreeTableModel * model,const char * name,uint32 flags,border_style borderStyle,bool showHorizontalScrollbar)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
~TreeTable()700 TreeTable::~TreeTable()
701 {
702 SetTreeTableModel(NULL);
703 }
704
705
706 bool
SetTreeTableModel(TreeTableModel * model)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
SetToolTipProvider(TreeTableToolTipProvider * toolTipProvider)759 TreeTable::SetToolTipProvider(TreeTableToolTipProvider* toolTipProvider)
760 {
761 fToolTipProvider = toolTipProvider;
762 }
763
764
765 TreeTableSelectionModel*
SelectionModel()766 TreeTable::SelectionModel()
767 {
768 return &fSelectionModel;
769 }
770
771
772 void
SelectNode(const TreeTablePath & path,bool extendSelection)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
DeselectNode(const TreeTablePath & path)790 TreeTable::DeselectNode(const TreeTablePath& path)
791 {
792 if (TreeTableNode* node = _NodeForPath(path))
793 Deselect(node->Row());
794 }
795
796
797 void
DeselectAllNodes()798 TreeTable::DeselectAllNodes()
799 {
800 DeselectAll();
801 }
802
803
804 bool
IsNodeExpanded(const TreeTablePath & path) const805 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
SetNodeExpanded(const TreeTablePath & path,bool expanded,bool expandAncestors)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
ScrollToNode(const TreeTablePath & path)823 TreeTable::ScrollToNode(const TreeTablePath& path)
824 {
825 if (TreeTableNode* node = _NodeForPath(path))
826 BColumnListView::ScrollTo(node->Row());
827 }
828
829
830 bool
AddTreeTableListener(TreeTableListener * listener)831 TreeTable::AddTreeTableListener(TreeTableListener* listener)
832 {
833 return fListeners.AddItem(listener);
834 }
835
836
837 void
RemoveTreeTableListener(TreeTableListener * listener)838 TreeTable::RemoveTreeTableListener(TreeTableListener* listener)
839 {
840 fListeners.RemoveItem(listener);
841 }
842
843
844 status_t
GetCellRectAt(const TreeTablePath & path,int32 colIndex,BRect & _output) const845 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
GetToolTipAt(BPoint point,BToolTip ** _tip)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
SelectionChanged()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*
CreateColumn(TableColumn * column)904 TreeTable::CreateColumn(TableColumn* column)
905 {
906 return new Column(fModel, column);
907 }
908
909
910 void
ColumnMouseDown(AbstractColumn * column,BRow * _row,BField * field,BPoint screenWhere,uint32 buttons)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
ColumnMouseUp(AbstractColumn * column,BRow * _row,BField * field,BPoint screenWhere,uint32 buttons)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
TableNodesAdded(TreeTableModel * model,const TreeTablePath & path,int32 childIndex,int32 count)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
TableNodesRemoved(TreeTableModel * model,const TreeTablePath & path,int32 childIndex,int32 count)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
TableNodesChanged(TreeTableModel * model,const TreeTablePath & path,int32 childIndex,int32 count)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
TableModelReset(TreeTableModel * model)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
ExpandOrCollapse(BRow * _row,bool expand)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
ItemInvoked()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
_AddChildRows(TreeTableNode * parentNode,int32 childIndex,int32 count,int32 columnCount)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
_RemoveChildRows(TreeTableNode * parentNode,int32 childIndex,int32 count)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
_SetNodeExpanded(TreeTableNode * node,bool expanded,bool expandAncestors)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*
_NodeForPath(const TreeTablePath & path) const1115 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
_GetPathForNode(TreeTableNode * node,TreeTablePath & _path) const1128 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