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