xref: /haiku/src/kits/interface/OutlineListView.cpp (revision 51978af14a173e7fae0563b562be5603bc652aeb)
1 //------------------------------------------------------------------------------
2 //	Copyright (c) 2001-2002, OpenBeOS
3 //
4 //	Permission is hereby granted, free of charge, to any person obtaining a
5 //	copy of this software and associated documentation files (the "Software"),
6 //	to deal in the Software without restriction, including without limitation
7 //	the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 //	and/or sell copies of the Software, and to permit persons to whom the
9 //	Software is furnished to do so, subject to the following conditions:
10 //
11 //	The above copyright notice and this permission notice shall be included in
12 //	all copies or substantial portions of the Software.
13 //
14 //	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 //	IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 //	FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 //	AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 //	LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19 //	FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
20 //	DEALINGS IN THE SOFTWARE.
21 //
22 //	File Name:		OutlineListView.cpp
23 //	Author:			Marc Flerackers (mflerackers@androme.be)
24 //	Description:	BOutlineListView represents a "nestable" list view.
25 //------------------------------------------------------------------------------
26 
27 // Standard Includes -----------------------------------------------------------
28 
29 // System Includes -------------------------------------------------------------
30 #include <OutlineListView.h>
31 
32 // Project Includes ------------------------------------------------------------
33 
34 // Local Includes --------------------------------------------------------------
35 
36 // Local Defines ---------------------------------------------------------------
37 
38 // Globals ---------------------------------------------------------------------
39 
40 //------------------------------------------------------------------------------
41 BOutlineListView::BOutlineListView(BRect frame, const char * name,
42 								   list_view_type type, uint32 resizeMask,
43 								   uint32 flags)
44 	:	BListView(frame, name, type, resizeMask, flags)
45 {
46 }
47 //------------------------------------------------------------------------------
48 BOutlineListView::BOutlineListView(BMessage *archive)
49 	:	BListView(archive)
50 {
51 }
52 //------------------------------------------------------------------------------
53 BOutlineListView::~BOutlineListView()
54 {
55 	fullList.MakeEmpty();
56 }
57 //------------------------------------------------------------------------------
58 BArchivable *BOutlineListView::Instantiate(BMessage *archive)
59 {
60 	if (validate_instantiation(archive, "BOutlineListView"))
61 		return new BOutlineListView(archive);
62 	else
63 		return NULL;
64 }
65 //------------------------------------------------------------------------------
66 status_t BOutlineListView::Archive(BMessage *data, bool deep) const
67 {
68 	return BListView::Archive(data, deep);
69 }
70 //------------------------------------------------------------------------------
71 void BOutlineListView::MouseDown(BPoint point)
72 {
73 	MakeFocus();
74 
75 	int32 index = IndexOf(point);
76 
77 	if (index != -1)
78 	{
79 		BListItem *item = ItemAt(index);
80 
81 		if (item->fHasSubitems &&
82 			LatchRect (ItemFrame(index ), item->fLevel).Contains(point))
83 		{
84 			if (item->IsExpanded())
85 				Collapse(item);
86 			else
87 				Expand(item);
88 		}
89 		else BListView::MouseDown(point);
90 	}
91 }
92 //------------------------------------------------------------------------------
93 void BOutlineListView::KeyDown(const char *bytes, int32 numBytes)
94 {
95 	if (numBytes == 1)
96 	{
97 		switch (bytes[0])
98 		{
99 			case '+':
100 			{
101 				BListItem *item = ItemAt(CurrentSelection());
102 
103 				if ( item && item->fHasSubitems)
104 					Expand(item);
105 
106 				break;
107 			}
108 			case '-':
109 			{
110 				BListItem *item = ItemAt(CurrentSelection());
111 
112 				if (item && item->fHasSubitems)
113 					Collapse(item);
114 
115 				break;
116 			}
117 			default:
118 				BListView::KeyDown(bytes, numBytes);
119 		}
120 	}
121 	else
122 		BListView::KeyDown(bytes, numBytes);
123 }
124 //------------------------------------------------------------------------------
125 void BOutlineListView::FrameMoved(BPoint new_position)
126 {
127 	BListView::FrameMoved(new_position);
128 }
129 //------------------------------------------------------------------------------
130 void BOutlineListView::FrameResized(float new_width, float new_height)
131 {
132 	BListView::FrameResized(new_width, new_height);
133 }
134 //------------------------------------------------------------------------------
135 void BOutlineListView::MouseUp(BPoint where)
136 {
137 	BListView::MouseUp(where);
138 }
139 //------------------------------------------------------------------------------
140 bool BOutlineListView::AddUnder(BListItem *item, BListItem *superitem)
141 {
142 	fullList.AddItem(item, FullListIndexOf(superitem) + 1);
143 
144 	item->fLevel = superitem->OutlineLevel() + 1;
145 	superitem->fHasSubitems = true;
146 
147 	if (superitem->IsItemVisible() && superitem->IsExpanded())
148 	{
149 		item->SetItemVisible(true);
150 
151 		int32 index = BListView::IndexOf(superitem);
152 
153 		BListView::AddItem(item, index + 1);
154 		Invalidate(LatchRect(ItemFrame(index), superitem->OutlineLevel()));
155 	}
156 	else
157 		item->SetItemVisible(false);
158 
159 	return true;
160 }
161 //------------------------------------------------------------------------------
162 bool BOutlineListView::AddItem(BListItem *item)
163 {
164 	bool result = fullList.AddItem(item);
165 
166 	if (!result)
167 		return false;
168 
169 	return BListView::AddItem(item);
170 }
171 //------------------------------------------------------------------------------
172 bool BOutlineListView::AddItem(BListItem *item, int32 fullListIndex)
173 {
174 	if (fullListIndex < 0)
175 		fullListIndex = 0;
176 	else if (fullListIndex > CountItems())
177 		fullListIndex = CountItems();
178 
179 	fullList.AddItem(item, fullListIndex);
180 
181 	if (item->fLevel > 0)
182 	{
183 		BListItem *super = SuperitemForIndex(fullListIndex, item->fLevel);
184 
185 		if (!super->IsItemVisible() || !super->IsExpanded())
186 			return true;
187 	}
188 
189 	int32 list_index = FindPreviousVisibleIndex(fullListIndex);
190 
191 	return BListView::AddItem(item, IndexOf(FullListItemAt(list_index)) + 1);
192 }
193 //------------------------------------------------------------------------------
194 bool BOutlineListView::AddList(BList *newItems)
195 {
196 	printf("BOutlineListView::AddList Not implemented\n");
197 	return false;
198 }
199 //------------------------------------------------------------------------------
200 bool BOutlineListView::AddList(BList *newItems, int32 fullListIndex)
201 {
202 	printf("BOutlineListView::AddList Not implemented\n");
203 	return false;
204 }
205 //------------------------------------------------------------------------------
206 bool BOutlineListView::RemoveItem(BListItem *item)
207 {
208 	if (!FullListHasItem(item))
209 		return false;
210 
211 	fullList.RemoveItem(item);
212 	if (item->fVisible)
213 		BListView::RemoveItem(item);
214 
215 	// TODO: remove children
216 
217 	return true;
218 }
219 //------------------------------------------------------------------------------
220 BListItem *BOutlineListView::RemoveItem(int32 fullListIndex)
221 {
222 	BListItem *item = FullListItemAt(fullListIndex);
223 
224 	if (item == NULL)
225 		return NULL;
226 
227 	fullList.RemoveItem(fullListIndex);
228 	if (item->fVisible)
229 		BListView::RemoveItem(item);
230 
231 	// TODO: remove children
232 
233 	return item;
234 }
235 //------------------------------------------------------------------------------
236 bool BOutlineListView::RemoveItems(int32 fullListIndex, int32 count)
237 {
238 	printf("BOutlineListView::RemoveItems Not implemented\n");
239 
240 	return false;
241 }
242 //------------------------------------------------------------------------------
243 BListItem *BOutlineListView::FullListItemAt(int32 fullListIndex) const
244 {
245 	return (BListItem*)fullList.ItemAt(fullListIndex);
246 }
247 //------------------------------------------------------------------------------
248 int32 BOutlineListView::FullListIndexOf(BPoint point) const
249 {
250 	return BListView::IndexOf(point);
251 }
252 //------------------------------------------------------------------------------
253 int32 BOutlineListView::FullListIndexOf(BListItem *item) const
254 {
255 	return fullList.IndexOf(item);
256 }
257 //------------------------------------------------------------------------------
258 BListItem *BOutlineListView::FullListFirstItem() const
259 {
260 	return (BListItem*)fullList.FirstItem();
261 }
262 //------------------------------------------------------------------------------
263 BListItem *BOutlineListView::FullListLastItem() const
264 {
265 	return (BListItem*)fullList.LastItem();
266 }
267 //------------------------------------------------------------------------------
268 bool BOutlineListView::FullListHasItem(BListItem *item) const
269 {
270 	return fullList.HasItem(item);
271 }
272 //------------------------------------------------------------------------------
273 int32 BOutlineListView::FullListCountItems() const
274 {
275 	return fullList.CountItems();
276 }
277 //------------------------------------------------------------------------------
278 int32 BOutlineListView::FullListCurrentSelection(int32 index) const
279 {
280 	int32 i = BListView::CurrentSelection(index);
281 	BListItem *item = BListView::ItemAt(i);
282 
283 	if (item)
284 		return fullList.IndexOf(item);
285 	else
286 		return -1;
287 }
288 //------------------------------------------------------------------------------
289 void BOutlineListView::MakeEmpty()
290 {
291 	fullList.MakeEmpty();
292 	BListView::MakeEmpty();
293 }
294 //------------------------------------------------------------------------------
295 bool BOutlineListView::FullListIsEmpty() const
296 {
297 	return fullList.IsEmpty();
298 }
299 //------------------------------------------------------------------------------
300 void BOutlineListView::FullListDoForEach(bool(*func)(BListItem *))
301 {
302 	printf("BOutlineListView::fullListDoForEach Not implemented\n");
303 	//fullList.DoForEach(func);
304 }
305 //------------------------------------------------------------------------------
306 void BOutlineListView::FullListDoForEach(bool (*func)(BListItem *, void *),
307 										 void *data)
308 {
309 	printf("BOutlineListView::fullListDoForEach Not implemented\n");
310 	//fullList.DoForEach(func, data);
311 }
312 //------------------------------------------------------------------------------
313 BListItem *BOutlineListView::Superitem(const BListItem *item)
314 {
315 	int32 index = FullListIndexOf((BListItem*)item);
316 
317 	if (index == -1)
318 		return NULL;
319 	else
320 		return SuperitemForIndex(index, item->OutlineLevel());
321 }
322 //------------------------------------------------------------------------------
323 void BOutlineListView::Expand(BListItem *item)
324 {
325 	if (!FullListHasItem(item))
326 		return;
327 
328 	if (item->fExpanded)
329 		return;
330 
331 	item->fExpanded = true;
332 
333 	uint32 level = item->fLevel, full_index = FullListIndexOf(item),
334 		index = IndexOf(item) + 1, count = FullListCountItems() - full_index - 1;
335 	BListItem **items = (BListItem**)fullList.Items() + full_index + 1;
336 
337 	BFont font;
338 	GetFont(&font);
339 
340 	while (count-- > 0 && (*items)->fLevel > level)
341 	{
342 		if (!(*items)->IsItemVisible())
343 		{
344 			//BListView::AddItem((*items), index++);
345 			fList.AddItem((*items), index++);
346 			(*items)->Update(this,&font);
347 			(*items)->SetItemVisible(true);
348 		}
349 
350 		// Skip hidden children
351 		if ((*items)->HasSubitems() && !(*items)->IsExpanded())
352 		{
353 			uint32 level = (*items)->fLevel;
354 			items++;
355 
356 			while (--count > 0 && (*items)->fLevel > level)
357 				items++;
358 		}
359 		else
360 			items++;
361 	}
362 
363 	FixupScrollBar();
364 	Invalidate();
365 }
366 //------------------------------------------------------------------------------
367 void BOutlineListView::Collapse(BListItem *item)
368 {
369 	if (!FullListHasItem(item))
370 		return;
371 
372 	if (!item->fExpanded)
373 		return;
374 
375 	item->fExpanded = false;
376 
377 	uint32 level = item->fLevel, full_index = FullListIndexOf(item),
378 		index = IndexOf(item) + 1, count = FullListCountItems() - full_index - 1;
379 	BListItem **items = (BListItem**)fullList.Items() + full_index + 1;
380 
381 	while (count-- > 0 && (*items)->fLevel > level)
382 	{
383 		if ((*items)->IsItemVisible())
384 		{
385 			//BListView::RemoveItem ((*items));
386 			fList.RemoveItem((*items));
387 			(*items)->SetItemVisible(false);
388 		}
389 
390 		items++;
391 	}
392 
393 	FixupScrollBar();
394 	Invalidate();
395 }
396 //------------------------------------------------------------------------------
397 bool BOutlineListView::IsExpanded(int32 fullListIndex)
398 {
399 	BListItem *item = FullListItemAt(fullListIndex);
400 
401 	if (!item)
402 		return false;
403 
404 	return item->IsExpanded();
405 }
406 //------------------------------------------------------------------------------
407 BHandler *BOutlineListView::ResolveSpecifier(BMessage *msg, int32 index,
408 											 BMessage *specifier, int32 form,
409 											 const char *property)
410 {
411 	return BListView::ResolveSpecifier(msg, index, specifier, form, property);
412 }
413 //------------------------------------------------------------------------------
414 status_t BOutlineListView::GetSupportedSuites(BMessage *data)
415 {
416 	return BListView::GetSupportedSuites(data);
417 }
418 //------------------------------------------------------------------------------
419 status_t BOutlineListView::Perform(perform_code d, void *arg)
420 {
421 	return BListView::Perform(d, arg);
422 }
423 //------------------------------------------------------------------------------
424 void BOutlineListView::ResizeToPreferred()
425 {
426 	BListView::ResizeToPreferred();
427 }
428 //------------------------------------------------------------------------------
429 void BOutlineListView::GetPreferredSize(float *width, float *height)
430 {
431 	BListView::GetPreferredSize(width, height);
432 }
433 //------------------------------------------------------------------------------
434 void BOutlineListView::MakeFocus(bool state)
435 {
436 	BListView::MakeFocus(state);
437 }
438 //------------------------------------------------------------------------------
439 void BOutlineListView::AllAttached()
440 {
441 	BListView::AllAttached();
442 }
443 //------------------------------------------------------------------------------
444 void BOutlineListView::AllDetached()
445 {
446 	BListView::AllDetached();
447 }
448 //------------------------------------------------------------------------------
449 void BOutlineListView::DetachedFromWindow()
450 {
451 	BListView::DetachedFromWindow();
452 }
453 //------------------------------------------------------------------------------
454 void BOutlineListView::FullListSortItems(int (*compareFunc)(const BListItem *,
455 										 const BListItem *))
456 {
457 	//fullList.SortItems(compareFunc);
458 	printf("BOutlineListView::FullListSortItems not implemented\n");
459 }
460 //------------------------------------------------------------------------------
461 void BOutlineListView::SortItemsUnder(BListItem *underItem, bool oneLevelOnly,
462 		int (*compareFunc)(const BListItem *, const BListItem*))
463 {
464 	printf("BOutlineListView::SortItemsUnder not implemented\n");
465 }
466 //------------------------------------------------------------------------------
467 int32 BOutlineListView::CountItemsUnder(BListItem *underItem,
468 									  bool oneLevelOnly) const
469 {
470 	int32 i = IndexOf(underItem);
471 
472 	if (i == -1)
473 		return 0;
474 
475 	int32 count = 0;
476 
477 	if (oneLevelOnly)
478 	{
479 		while (i < FullListCountItems())
480 		{
481 			BListItem *item = FullListItemAt(i);
482 
483 			// If we jump out of the subtree, return count
484 			if (item->fLevel < underItem->OutlineLevel())
485 				return count;
486 
487 			// If the level matches, increase count
488 			if (item->fLevel == underItem->OutlineLevel() + 1)
489 				count++;
490 
491 			i++;
492 		}
493 	}
494 	else
495 	{
496 		while (i < FullListCountItems())
497 		{
498 			BListItem *item = FullListItemAt(i);
499 
500 			// If we jump out of the subtree, return count
501 			if (item->fLevel < underItem->OutlineLevel())
502 				return count;
503 
504 			// Increase count
505 			count++;
506 
507 			i++;
508 		}
509 	}
510 
511 	return count;
512 }
513 //------------------------------------------------------------------------------
514 BListItem *BOutlineListView::EachItemUnder(BListItem *underItem,
515 										   bool oneLevelOnly,
516 										   BListItem *(*eachFunc)(BListItem *,
517 										   void *), void *)
518 {
519 	printf("BOutlineListView::EachItemUnder Not implemented\n");
520 
521 	return NULL;
522 }
523 //------------------------------------------------------------------------------
524 BListItem *BOutlineListView::ItemUnderAt(BListItem *underItem,
525 										 bool oneLevelOnly, int32 index) const
526 {
527 	int32 i = IndexOf(underItem);
528 
529 	if (i == -1)
530 		return NULL;
531 
532 	if (oneLevelOnly)
533 	{
534 		while (i < FullListCountItems())
535 		{
536 			BListItem *item = FullListItemAt(i);
537 
538 			// If we jump out of the subtree, return NULL
539 			if (item->fLevel < underItem->OutlineLevel())
540 				return NULL;
541 
542 			// If the level matches, check the index
543 			if (item->fLevel == underItem->OutlineLevel() + 1)
544 			{
545 				if (index == 0)
546 					return item;
547 				else
548 					index--;
549 			}
550 
551 			i++;
552 		}
553 	}
554 	else
555 	{
556 		while (i < FullListCountItems())
557 		{
558 			BListItem *item = FullListItemAt(i);
559 
560 			// If we jump out of the subtree, return NULL
561 			if (item->fLevel < underItem->OutlineLevel())
562 				return NULL;
563 
564 			// Check the index
565 			if (index == 0)
566 				return item;
567 			else
568 				index--;
569 
570 			i++;
571 		}
572 	}
573 
574 	return NULL;
575 }
576 //------------------------------------------------------------------------------
577 bool BOutlineListView::DoMiscellaneous(MiscCode code, MiscData * data)
578 {
579 	return BListView::DoMiscellaneous(code, data);
580 }
581 //------------------------------------------------------------------------------
582 void BOutlineListView::MessageReceived(BMessage *msg)
583 {
584 	BListView::MessageReceived(msg);
585 }
586 //------------------------------------------------------------------------------
587 void BOutlineListView::_ReservedOutlineListView1() {}
588 void BOutlineListView::_ReservedOutlineListView2() {}
589 void BOutlineListView::_ReservedOutlineListView3() {}
590 void BOutlineListView::_ReservedOutlineListView4() {}
591 //------------------------------------------------------------------------------
592 int32 BOutlineListView::FullListIndex(int32 index) const
593 {
594 	BListItem *item = ItemAt(index);
595 
596 	if (item == NULL)
597 		return -1;
598 	else
599 		return FullListIndexOf(item);
600 }
601 //------------------------------------------------------------------------------
602 int32 BOutlineListView::ListViewIndex(int32 index) const
603 {
604 	BListItem *item = ItemAt(index);
605 
606 	if (item == NULL)
607 		return -1;
608 	else
609 		return BListView::IndexOf(item);
610 }
611 //------------------------------------------------------------------------------
612 void BOutlineListView::ExpandOrCollapse(BListItem *underItem, bool expand)
613 {
614 }
615 //------------------------------------------------------------------------------
616 BRect BOutlineListView::LatchRect(BRect itemRect, int32 level) const
617 {
618 	return BRect(itemRect.left, itemRect.top, itemRect.left +
619 		(level * 10.0f + 15.0f), itemRect.bottom);
620 }
621 //------------------------------------------------------------------------------
622 void BOutlineListView::DrawLatch(BRect itemRect, int32 level, bool collapsed,
623 								 bool highlighted, bool misTracked)
624 {
625 	float left = level * 10.0f;
626 
627 	if (collapsed)
628 	{
629 		SetHighColor(192, 192, 192);
630 
631 		FillTriangle(itemRect.LeftTop() + BPoint(left + 4.0f, 2.0f),
632 			itemRect.LeftTop() + BPoint(left + 4.0f, 10.0f),
633 			itemRect.LeftTop() + BPoint(left + 8.0f, 6.0f));
634 
635 		SetHighColor(0, 0, 0);
636 
637 		StrokeTriangle(itemRect.LeftTop() + BPoint(left + 4.0f, 2.0f),
638 			itemRect.LeftTop() + BPoint(left + 4.0f, 10.0f),
639 			itemRect.LeftTop() + BPoint(left + 8.0f, 6.0f));
640 	}
641 	else
642 	{
643 		SetHighColor(192, 192, 192);
644 
645 		FillTriangle(itemRect.LeftTop() + BPoint(left + 2.0f, 4.0f),
646 			itemRect.LeftTop() + BPoint(left + 10.0f, 4.0f),
647 			itemRect.LeftTop() + BPoint(left + 6.0f, 8.0f));
648 
649 		SetHighColor(0, 0, 0);
650 
651 		StrokeTriangle(itemRect.LeftTop() + BPoint(left + 2.0f, 4.0f),
652 			itemRect.LeftTop() + BPoint(left + 10.0f, 4.0f),
653 			itemRect.LeftTop() + BPoint(left + 6.0f, 8.0f));
654 	}
655 }
656 //------------------------------------------------------------------------------
657 void BOutlineListView::DrawItem(BListItem *item, BRect itemRect, bool complete)
658 {
659 	if (item->fHasSubitems)
660 		DrawLatch(itemRect, item->fLevel, !item->IsExpanded(), false, false);
661 
662 	itemRect.left += (item->fLevel) * 10.0f + 15.0f;
663 
664 	item->DrawItem(this, itemRect, complete);
665 }
666 //------------------------------------------------------------------------------
667 BListItem *BOutlineListView::RemoveCommon(int32 fullListIndex)
668 {
669 	return NULL;
670 }
671 //------------------------------------------------------------------------------
672 BListItem *BOutlineListView::RemoveOne(int32 fullListIndex)
673 {
674 	return NULL;
675 }
676 //------------------------------------------------------------------------------
677 void BOutlineListView::TrackInLatchItem(void *)
678 {
679 }
680 //------------------------------------------------------------------------------
681 void BOutlineListView::TrackOutLatchItem(void *)
682 {
683 }
684 //------------------------------------------------------------------------------
685 bool BOutlineListView::OutlineSwapItems(int32 a, int32 b)
686 {
687 	return false;
688 }
689 //------------------------------------------------------------------------------
690 bool BOutlineListView::OutlineMoveItem(int32 from, int32 to)
691 {
692 	return false;
693 }
694 //------------------------------------------------------------------------------
695 bool BOutlineListView::OutlineReplaceItem(int32 index, BListItem *item)
696 {
697 	return false;
698 }
699 //------------------------------------------------------------------------------
700 void BOutlineListView::CommonMoveItems(int32 from, int32 count, int32 to)
701 {
702 }
703 //------------------------------------------------------------------------------
704 BListItem *BOutlineListView::SuperitemForIndex(int32 fullListIndex, int32 level)
705 {
706 	BListItem *item;
707 	fullListIndex--;
708 
709 	while (fullListIndex >= 0)
710 	{
711 		if ((item = FullListItemAt(fullListIndex))->OutlineLevel() <
712 			(uint32)level)
713 			return item;
714 
715 		fullListIndex--;
716 	}
717 
718 	return NULL;
719 }
720 //------------------------------------------------------------------------------
721 int32 BOutlineListView::FindPreviousVisibleIndex(int32 fullListIndex)
722 {
723 	fullListIndex--;
724 
725 	while (fullListIndex >= 0)
726 	{
727 		if (FullListItemAt(fullListIndex)->fVisible)
728 			return fullListIndex;
729 
730 		fullListIndex--;
731 	}
732 
733 	return -1;
734 }
735 //------------------------------------------------------------------------------
736 
737 /*
738  * $Log $
739  *
740  * $Id  $
741  *
742  */
743