xref: /haiku/src/apps/debuganalyzer/gui/table/TreeTable.cpp (revision b57470a2179ca208ea910422db1ab2881575b69d)
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