2 * Copyright 2001-2013 Haiku, Inc. All rights reserved.
3 * Distributed under the terms of the MIT License.
6 * Marc Flerackers (mflerackers@androme.be)
7 * Axel Dörfler, axeld@pinc-software.de
8 * Rene Gollent (rene@gollent.com)
9 * Philippe Saint-Pierre, stpere@gmail.com
10 * John Scipione, jscipione@gmail.com
14 //! BOutlineListView represents a "nestable" list view.
17 #include <OutlineListView.h>
24 #include <ControlLook.h>
27 #include <binary_compatibility/Interface.h>
30 typedef int (*compare_func
)(const BListItem
* a
, const BListItem
* b
);
33 struct ListItemComparator
{
34 ListItemComparator(compare_func compareFunc
)
36 fCompareFunc(compareFunc
)
40 bool operator()(const BListItem
* a
, const BListItem
* b
) const
42 return fCompareFunc(a
, b
) < 0;
46 compare_func fCompareFunc
;
51 _GetSubItems(BList
& sourceList
, BList
& destList
, BListItem
* parent
, int32 start
)
53 for (int32 i
= start
; i
< sourceList
.CountItems(); i
++) {
54 BListItem
* item
= (BListItem
*)sourceList
.ItemAt(i
);
55 if (item
->OutlineLevel() <= parent
->OutlineLevel())
57 destList
.AddItem(item
);
63 _DoSwap(BList
& list
, int32 firstIndex
, int32 secondIndex
, BList
* firstItems
,
66 BListItem
* item
= (BListItem
*)list
.ItemAt(firstIndex
);
67 list
.SwapItems(firstIndex
, secondIndex
);
68 list
.RemoveItems(secondIndex
+ 1, secondItems
->CountItems());
69 list
.RemoveItems(firstIndex
+ 1, firstItems
->CountItems());
70 list
.AddList(secondItems
, firstIndex
+ 1);
71 int32 newIndex
= list
.IndexOf(item
);
72 if (newIndex
+ 1 < list
.CountItems())
73 list
.AddList(firstItems
, newIndex
+ 1);
75 list
.AddList(firstItems
);
79 // #pragma mark - BOutlineListView
82 BOutlineListView::BOutlineListView(BRect frame
, const char* name
,
83 list_view_type type
, uint32 resizingMode
, uint32 flags
)
85 BListView(frame
, name
, type
, resizingMode
, flags
)
90 BOutlineListView::BOutlineListView(const char* name
, list_view_type type
,
93 BListView(name
, type
, flags
)
98 BOutlineListView::BOutlineListView(BMessage
* archive
)
104 while (archive
->FindMessage("_l_full_items", i
++, &subData
) == B_OK
) {
105 BArchivable
* object
= instantiate_object(&subData
);
109 BListItem
* item
= dynamic_cast<BListItem
*>(object
);
116 BOutlineListView::~BOutlineListView()
118 fFullList
.MakeEmpty();
123 BOutlineListView::Instantiate(BMessage
* archive
)
125 if (validate_instantiation(archive
, "BOutlineListView"))
126 return new BOutlineListView(archive
);
133 BOutlineListView::Archive(BMessage
* archive
, bool deep
) const
135 // Note: We can't call the BListView Archive function here, as we are also
136 // interested in subitems BOutlineListView can have. They are even stored
137 // with a different field name (_l_full_items vs. _l_items).
139 status_t status
= BView::Archive(archive
, deep
);
143 status
= archive
->AddInt32("_lv_type", fListType
);
144 if (status
== B_OK
&& deep
) {
146 BListItem
* item
= NULL
;
147 while ((item
= static_cast<BListItem
*>(fFullList
.ItemAt(i
++)))) {
149 status
= item
->Archive(&subData
, true);
151 status
= archive
->AddMessage("_l_full_items", &subData
);
158 if (status
>= B_OK
&& InvocationMessage() != NULL
)
159 status
= archive
->AddMessage("_msg", InvocationMessage());
161 if (status
== B_OK
&& fSelectMessage
!= NULL
)
162 status
= archive
->AddMessage("_2nd_msg", fSelectMessage
);
169 BOutlineListView::MouseDown(BPoint where
)
173 int32 index
= IndexOf(where
);
176 BListItem
* item
= ItemAt(index
);
178 if (item
->fHasSubitems
179 && LatchRect(ItemFrame(index
), item
->fLevel
).Contains(where
)) {
180 if (item
->IsExpanded())
185 BListView::MouseDown(where
);
191 BOutlineListView::KeyDown(const char* bytes
, int32 numBytes
)
194 int32 currentSel
= CurrentSelection();
198 BListItem
* item
= ItemAt(currentSel
);
199 if (item
&& item
->fHasSubitems
) {
200 if (!item
->IsExpanded())
203 Select(currentSel
+ 1);
210 BListItem
* item
= ItemAt(currentSel
);
212 if (item
->fHasSubitems
)
215 item
= Superitem(item
);
217 Select(IndexOf(item
));
225 BListView::KeyDown(bytes
, numBytes
);
230 BOutlineListView::FrameMoved(BPoint newPosition
)
232 BListView::FrameMoved(newPosition
);
237 BOutlineListView::FrameResized(float newWidth
, float newHeight
)
239 BListView::FrameResized(newWidth
, newHeight
);
244 BOutlineListView::MouseUp(BPoint where
)
246 BListView::MouseUp(where
);
251 BOutlineListView::AddUnder(BListItem
* item
, BListItem
* superItem
)
253 if (superItem
== NULL
)
254 return AddItem(item
);
256 fFullList
.AddItem(item
, FullListIndexOf(superItem
) + 1);
258 item
->fLevel
= superItem
->OutlineLevel() + 1;
259 superItem
->fHasSubitems
= true;
261 if (superItem
->IsItemVisible() && superItem
->IsExpanded()) {
262 item
->SetItemVisible(true);
264 int32 index
= BListView::IndexOf(superItem
);
266 BListView::AddItem(item
, index
+ 1);
267 Invalidate(LatchRect(ItemFrame(index
), superItem
->OutlineLevel()));
269 item
->SetItemVisible(false);
276 BOutlineListView::AddItem(BListItem
* item
)
278 return AddItem(item
, FullListCountItems());
283 BOutlineListView::AddItem(BListItem
* item
, int32 fullListIndex
)
285 if (fullListIndex
< 0)
287 else if (fullListIndex
> FullListCountItems())
288 fullListIndex
= FullListCountItems();
290 if (!fFullList
.AddItem(item
, fullListIndex
))
293 // Check if this item is visible, and if it is, add it to the
296 if (item
->fLevel
> 0) {
297 BListItem
* super
= _SuperitemForIndex(fullListIndex
, item
->fLevel
);
301 bool hadSubitems
= super
->fHasSubitems
;
302 super
->fHasSubitems
= true;
304 if (!super
->IsItemVisible() || !super
->IsExpanded()) {
305 item
->SetItemVisible(false);
310 Invalidate(LatchRect(ItemFrame(IndexOf(super
)),
311 super
->OutlineLevel()));
315 int32 listIndex
= _FindPreviousVisibleIndex(fullListIndex
);
317 if (!BListView::AddItem(item
, IndexOf(FullListItemAt(listIndex
)) + 1)) {
318 // adding didn't work out, we need to remove it from the main list again
319 fFullList
.RemoveItem(fullListIndex
);
328 BOutlineListView::AddList(BList
* newItems
)
330 return AddList(newItems
, FullListCountItems());
335 BOutlineListView::AddList(BList
* newItems
, int32 fullListIndex
)
337 if ((newItems
== NULL
) || (newItems
->CountItems() == 0))
340 for (int32 i
= 0; i
< newItems
->CountItems(); i
++)
341 AddItem((BListItem
*)newItems
->ItemAt(i
), fullListIndex
+ i
);
348 BOutlineListView::RemoveItem(BListItem
* item
)
350 return _RemoveItem(item
, FullListIndexOf(item
)) != NULL
;
355 BOutlineListView::RemoveItem(int32 fullListIndex
)
357 return _RemoveItem(FullListItemAt(fullListIndex
), fullListIndex
);
362 BOutlineListView::RemoveItems(int32 fullListIndex
, int32 count
)
364 if (fullListIndex
>= FullListCountItems())
366 if (fullListIndex
< 0)
369 // TODO: very bad for performance!!
371 BOutlineListView::RemoveItem(fullListIndex
);
378 BOutlineListView::FullListItemAt(int32 fullListIndex
) const
380 return (BListItem
*)fFullList
.ItemAt(fullListIndex
);
385 BOutlineListView::FullListIndexOf(BPoint where
) const
387 int32 index
= BListView::IndexOf(where
);
390 index
= _FullListIndex(index
);
397 BOutlineListView::FullListIndexOf(BListItem
* item
) const
399 return fFullList
.IndexOf(item
);
404 BOutlineListView::FullListFirstItem() const
406 return (BListItem
*)fFullList
.FirstItem();
411 BOutlineListView::FullListLastItem() const
413 return (BListItem
*)fFullList
.LastItem();
418 BOutlineListView::FullListHasItem(BListItem
* item
) const
420 return fFullList
.HasItem(item
);
425 BOutlineListView::FullListCountItems() const
427 return fFullList
.CountItems();
432 BOutlineListView::FullListCurrentSelection(int32 index
) const
434 int32 i
= BListView::CurrentSelection(index
);
436 BListItem
* item
= BListView::ItemAt(i
);
438 return fFullList
.IndexOf(item
);
445 BOutlineListView::MakeEmpty()
447 fFullList
.MakeEmpty();
448 BListView::MakeEmpty();
453 BOutlineListView::FullListIsEmpty() const
455 return fFullList
.IsEmpty();
460 BOutlineListView::FullListDoForEach(bool(*func
)(BListItem
* item
))
462 fFullList
.DoForEach(reinterpret_cast<bool (*)(void*)>(func
));
467 BOutlineListView::FullListDoForEach(bool (*func
)(BListItem
* item
, void* arg
),
470 fFullList
.DoForEach(reinterpret_cast<bool (*)(void*, void*)>(func
), arg
);
475 BOutlineListView::Superitem(const BListItem
* item
)
477 int32 index
= FullListIndexOf((BListItem
*)item
);
481 return _SuperitemForIndex(index
, item
->OutlineLevel());
486 BOutlineListView::Expand(BListItem
* item
)
488 ExpandOrCollapse(item
, true);
493 BOutlineListView::Collapse(BListItem
* item
)
495 ExpandOrCollapse(item
, false);
500 BOutlineListView::IsExpanded(int32 fullListIndex
)
502 BListItem
* item
= FullListItemAt(fullListIndex
);
506 return item
->IsExpanded();
511 BOutlineListView::ResolveSpecifier(BMessage
* message
, int32 index
,
512 BMessage
* specifier
, int32 what
, const char* property
)
514 return BListView::ResolveSpecifier(message
, index
, specifier
, what
,
520 BOutlineListView::GetSupportedSuites(BMessage
* data
)
522 return BListView::GetSupportedSuites(data
);
527 BOutlineListView::Perform(perform_code code
, void* _data
)
530 case PERFORM_CODE_MIN_SIZE
:
531 ((perform_data_min_size
*)_data
)->return_value
532 = BOutlineListView::MinSize();
534 case PERFORM_CODE_MAX_SIZE
:
535 ((perform_data_max_size
*)_data
)->return_value
536 = BOutlineListView::MaxSize();
538 case PERFORM_CODE_PREFERRED_SIZE
:
539 ((perform_data_preferred_size
*)_data
)->return_value
540 = BOutlineListView::PreferredSize();
542 case PERFORM_CODE_LAYOUT_ALIGNMENT
:
543 ((perform_data_layout_alignment
*)_data
)->return_value
544 = BOutlineListView::LayoutAlignment();
546 case PERFORM_CODE_HAS_HEIGHT_FOR_WIDTH
:
547 ((perform_data_has_height_for_width
*)_data
)->return_value
548 = BOutlineListView::HasHeightForWidth();
550 case PERFORM_CODE_GET_HEIGHT_FOR_WIDTH
:
552 perform_data_get_height_for_width
* data
553 = (perform_data_get_height_for_width
*)_data
;
554 BOutlineListView::GetHeightForWidth(data
->width
, &data
->min
,
555 &data
->max
, &data
->preferred
);
558 case PERFORM_CODE_SET_LAYOUT
:
560 perform_data_set_layout
* data
= (perform_data_set_layout
*)_data
;
561 BOutlineListView::SetLayout(data
->layout
);
564 case PERFORM_CODE_LAYOUT_INVALIDATED
:
566 perform_data_layout_invalidated
* data
567 = (perform_data_layout_invalidated
*)_data
;
568 BOutlineListView::LayoutInvalidated(data
->descendants
);
571 case PERFORM_CODE_DO_LAYOUT
:
573 BOutlineListView::DoLayout();
578 return BListView::Perform(code
, _data
);
583 BOutlineListView::ResizeToPreferred()
585 BListView::ResizeToPreferred();
590 BOutlineListView::GetPreferredSize(float* _width
, float* _height
)
592 int32 count
= CountItems();
595 float maxWidth
= 0.0;
596 for (int32 i
= 0; i
< count
; i
++) {
597 // The item itself does not take his OutlineLevel into account, so
598 // we must make up for that. Also add space for the latch.
599 float itemWidth
= ItemAt(i
)->Width() + be_plain_font
->Size()
600 + (ItemAt(i
)->OutlineLevel() + 1)
601 * be_control_look
->DefaultItemSpacing();
602 if (itemWidth
> maxWidth
)
603 maxWidth
= itemWidth
;
609 *_height
= ItemAt(count
- 1)->Bottom();
611 BView::GetPreferredSize(_width
, _height
);
616 BOutlineListView::MakeFocus(bool state
)
618 BListView::MakeFocus(state
);
623 BOutlineListView::AllAttached()
625 BListView::AllAttached();
630 BOutlineListView::AllDetached()
632 BListView::AllDetached();
637 BOutlineListView::DetachedFromWindow()
639 BListView::DetachedFromWindow();
644 BOutlineListView::FullListSortItems(int (*compareFunc
)(const BListItem
* a
,
647 SortItemsUnder(NULL
, false, compareFunc
);
652 BOutlineListView::SortItemsUnder(BListItem
* superItem
, bool oneLevelOnly
,
653 int (*compareFunc
)(const BListItem
* a
, const BListItem
* b
))
655 // This method is quite complicated: basically, it creates a real tree
656 // from the items of the full list, sorts them as needed, and then
657 // populates the entries back into the full and display lists
659 int32 firstIndex
= FullListIndexOf(superItem
) + 1;
660 int32 lastIndex
= firstIndex
;
661 BList
* tree
= _BuildTree(superItem
, lastIndex
);
663 _SortTree(tree
, oneLevelOnly
, compareFunc
);
665 // Populate to the full list
666 _PopulateTree(tree
, fFullList
, firstIndex
, false);
668 if (superItem
== NULL
669 || (superItem
->IsItemVisible() && superItem
->IsExpanded())) {
670 // Populate to BListView's list
671 firstIndex
= fList
.IndexOf(superItem
) + 1;
672 lastIndex
= firstIndex
;
673 _PopulateTree(tree
, fList
, lastIndex
, true);
675 if (fFirstSelected
!= -1) {
676 // update selection hints
677 fFirstSelected
= _CalcFirstSelected(0);
678 fLastSelected
= _CalcLastSelected(CountItems());
681 // only invalidate what may have changed
682 _RecalcItemTops(firstIndex
);
683 BRect top
= ItemFrame(firstIndex
);
684 BRect bottom
= ItemFrame(lastIndex
- 1);
685 BRect
update(top
.left
, top
.top
, bottom
.right
, bottom
.bottom
);
694 BOutlineListView::CountItemsUnder(BListItem
* superItem
, bool oneLevelOnly
) const
696 int32 i
= FullListIndexOf(superItem
);
702 uint32 baseLevel
= superItem
->OutlineLevel();
704 for (; i
< FullListCountItems(); i
++) {
705 BListItem
* item
= FullListItemAt(i
);
707 // If we jump out of the subtree, return count
708 if (item
->fLevel
<= baseLevel
)
711 // If the level matches, increase count
712 if (!oneLevelOnly
|| item
->fLevel
== baseLevel
+ 1)
721 BOutlineListView::EachItemUnder(BListItem
* superItem
, bool oneLevelOnly
,
722 BListItem
* (*eachFunc
)(BListItem
* item
, void* arg
), void* arg
)
724 int32 i
= IndexOf(superItem
);
728 while (i
< FullListCountItems()) {
729 BListItem
* item
= FullListItemAt(i
);
731 // If we jump out of the subtree, return NULL
732 if (item
->fLevel
< superItem
->OutlineLevel())
735 // If the level matches, check the index
736 if (!oneLevelOnly
|| item
->fLevel
== superItem
->OutlineLevel() + 1) {
737 item
= eachFunc(item
, arg
);
750 BOutlineListView::ItemUnderAt(BListItem
* superItem
, bool oneLevelOnly
,
753 int32 i
= FullListIndexOf(superItem
);
757 while (i
< FullListCountItems()) {
758 BListItem
* item
= FullListItemAt(i
);
760 // If we jump out of the subtree, return NULL
761 if (item
->fLevel
< superItem
->OutlineLevel())
764 // If the level matches, check the index
765 if (!oneLevelOnly
|| item
->fLevel
== superItem
->OutlineLevel() + 1) {
780 BOutlineListView::DoMiscellaneous(MiscCode code
, MiscData
* data
)
782 if (code
== B_SWAP_OP
)
783 return _SwapItems(data
->swap
.a
, data
->swap
.b
);
785 return BListView::DoMiscellaneous(code
, data
);
790 BOutlineListView::MessageReceived(BMessage
* msg
)
792 BListView::MessageReceived(msg
);
796 void BOutlineListView::_ReservedOutlineListView1() {}
797 void BOutlineListView::_ReservedOutlineListView2() {}
798 void BOutlineListView::_ReservedOutlineListView3() {}
799 void BOutlineListView::_ReservedOutlineListView4() {}
803 BOutlineListView::ExpandOrCollapse(BListItem
* item
, bool expand
)
805 if (item
->IsExpanded() == expand
|| !FullListHasItem(item
))
808 item
->fExpanded
= expand
;
810 // TODO: merge these cases together, they are pretty similar
813 uint32 level
= item
->fLevel
;
814 int32 fullListIndex
= FullListIndexOf(item
);
815 int32 index
= IndexOf(item
) + 1;
816 int32 startIndex
= index
;
817 int32 count
= FullListCountItems() - fullListIndex
- 1;
818 BListItem
** items
= (BListItem
**)fFullList
.Items() + fullListIndex
+ 1;
822 while (count
-- > 0) {
824 if (item
->fLevel
<= level
)
827 if (!item
->IsItemVisible()) {
828 // fix selection hints
829 if (index
<= fFirstSelected
)
831 if (index
<= fLastSelected
)
834 fList
.AddItem(item
, index
++);
835 item
->Update(this, &font
);
836 item
->SetItemVisible(true);
839 if (item
->HasSubitems() && !item
->IsExpanded()) {
840 // Skip hidden children
841 uint32 subLevel
= item
->fLevel
;
844 while (--count
> 0 && items
[0]->fLevel
> subLevel
)
849 _RecalcItemTops(startIndex
);
852 uint32 level
= item
->fLevel
;
853 int32 fullListIndex
= FullListIndexOf(item
);
854 int32 index
= IndexOf(item
);
855 int32 startIndex
= index
;
856 int32 max
= FullListCountItems() - fullListIndex
- 1;
858 bool selectionChanged
= false;
860 BListItem
** items
= (BListItem
**)fFullList
.Items() + fullListIndex
+ 1;
864 if (item
->fLevel
<= level
)
867 if (item
->IsItemVisible()) {
868 fList
.RemoveItem(item
);
869 item
->SetItemVisible(false);
870 if (item
->IsSelected()) {
871 selectionChanged
= true;
880 _RecalcItemTops(startIndex
);
881 // fix selection hints
882 // if the selected item was just removed by collapsing, select its
884 if (ListType() == B_SINGLE_SELECTION_LIST
&& selectionChanged
)
885 fFirstSelected
= fLastSelected
= index
;
887 if (index
< fFirstSelected
&& index
+ count
< fFirstSelected
) {
888 // all items removed were higher than the selection range,
889 // adjust the indexes to correspond to their new visible positions
890 fFirstSelected
-= count
;
891 fLastSelected
-= count
;
894 int32 maxIndex
= fList
.CountItems() - 1;
895 if (fFirstSelected
> maxIndex
)
896 fFirstSelected
= maxIndex
;
898 if (fLastSelected
> maxIndex
)
899 fLastSelected
= maxIndex
;
901 if (selectionChanged
)
911 BOutlineListView::LatchRect(BRect itemRect
, int32 level
) const
913 float latchWidth
= be_plain_font
->Size();
914 float latchHeight
= be_plain_font
->Size();
915 float indentOffset
= level
* be_control_look
->DefaultItemSpacing();
916 float heightOffset
= itemRect
.Height() / 2 - latchHeight
/ 2;
918 return BRect(0, 0, latchWidth
, latchHeight
)
919 .OffsetBySelf(itemRect
.left
, itemRect
.top
)
920 .OffsetBySelf(indentOffset
, heightOffset
);
925 BOutlineListView::DrawLatch(BRect itemRect
, int32 level
, bool collapsed
,
926 bool highlighted
, bool misTracked
)
928 BRect
latchRect(LatchRect(itemRect
, level
));
929 rgb_color base
= ui_color(B_PANEL_BACKGROUND_COLOR
);
930 int32 arrowDirection
= collapsed
? BControlLook::B_RIGHT_ARROW
931 : BControlLook::B_DOWN_ARROW
;
933 be_control_look
->DrawArrowShape(this, latchRect
, itemRect
, base
,
934 arrowDirection
, 0, B_DARKEN_4_TINT
);
939 BOutlineListView::DrawItem(BListItem
* item
, BRect itemRect
, bool complete
)
941 if (item
->fHasSubitems
) {
942 DrawLatch(itemRect
, item
->fLevel
, !item
->IsExpanded(),
943 item
->IsSelected() || complete
, false);
946 itemRect
.left
+= LatchRect(itemRect
, item
->fLevel
).right
;
947 BListView::DrawItem(item
, itemRect
, complete
);
952 BOutlineListView::_FullListIndex(int32 index
) const
954 BListItem
* item
= ItemAt(index
);
959 return FullListIndexOf(item
);
964 BOutlineListView::_PopulateTree(BList
* tree
, BList
& target
,
965 int32
& firstIndex
, bool onlyVisible
)
967 BListItem
** items
= (BListItem
**)target
.Items();
968 int32 count
= tree
->CountItems();
970 for (int32 index
= 0; index
< count
; index
++) {
971 BListItem
* item
= (BListItem
*)tree
->ItemAtFast(index
);
973 items
[firstIndex
++] = item
;
975 if (item
->HasSubitems() && (!onlyVisible
|| item
->IsExpanded())) {
976 _PopulateTree(item
->fTemporaryList
, target
, firstIndex
,
984 BOutlineListView::_SortTree(BList
* tree
, bool oneLevelOnly
,
985 int (*compareFunc
)(const BListItem
* a
, const BListItem
* b
))
987 BListItem
** items
= (BListItem
**)tree
->Items();
988 std::sort(items
, items
+ tree
->CountItems(),
989 ListItemComparator(compareFunc
));
994 for (int32 index
= tree
->CountItems(); index
-- > 0;) {
995 BListItem
* item
= (BListItem
*)tree
->ItemAt(index
);
997 if (item
->HasSubitems())
998 _SortTree(item
->fTemporaryList
, false, compareFunc
);
1004 BOutlineListView::_DestructTree(BList
* tree
)
1006 for (int32 index
= tree
->CountItems(); index
-- > 0;) {
1007 BListItem
* item
= (BListItem
*)tree
->ItemAt(index
);
1009 if (item
->HasSubitems())
1010 _DestructTree(item
->fTemporaryList
);
1018 BOutlineListView::_BuildTree(BListItem
* superItem
, int32
& fullListIndex
)
1020 int32 fullCount
= FullListCountItems();
1021 uint32 level
= superItem
!= NULL
? superItem
->OutlineLevel() + 1 : 0;
1022 BList
* list
= new BList
;
1023 if (superItem
!= NULL
)
1024 superItem
->fTemporaryList
= list
;
1026 while (fullListIndex
< fullCount
) {
1027 BListItem
* item
= FullListItemAt(fullListIndex
);
1029 // If we jump out of the subtree, break out
1030 if (item
->fLevel
< level
)
1033 // If the level matches, put them into the list
1034 // (we handle the case of a missing sublevel gracefully)
1035 list
->AddItem(item
);
1038 if (item
->HasSubitems()) {
1039 // we're going deeper
1040 _BuildTree(item
, fullListIndex
);
1049 BOutlineListView::_CullInvisibleItems(BList
& list
)
1052 while (index
< list
.CountItems()) {
1053 if (reinterpret_cast<BListItem
*>(list
.ItemAt(index
))->IsItemVisible())
1056 list
.RemoveItem(index
);
1062 BOutlineListView::_SwapItems(int32 first
, int32 second
)
1064 // same item, do nothing
1065 if (first
== second
)
1068 // fail, first item out of bounds
1069 if ((first
< 0) || (first
>= CountItems()))
1072 // fail, second item out of bounds
1073 if ((second
< 0) || (second
>= CountItems()))
1076 int32 firstIndex
= min_c(first
, second
);
1077 int32 secondIndex
= max_c(first
, second
);
1078 BListItem
* firstItem
= ItemAt(firstIndex
);
1079 BListItem
* secondItem
= ItemAt(secondIndex
);
1080 BList firstSubItems
, secondSubItems
;
1082 if (Superitem(firstItem
) != Superitem(secondItem
))
1085 if (!firstItem
->IsItemVisible() || !secondItem
->IsItemVisible())
1088 int32 fullFirstIndex
= _FullListIndex(firstIndex
);
1089 int32 fullSecondIndex
= _FullListIndex(secondIndex
);
1090 _GetSubItems(fFullList
, firstSubItems
, firstItem
, fullFirstIndex
+ 1);
1091 _GetSubItems(fFullList
, secondSubItems
, secondItem
, fullSecondIndex
+ 1);
1092 _DoSwap(fFullList
, fullFirstIndex
, fullSecondIndex
, &firstSubItems
,
1095 _CullInvisibleItems(firstSubItems
);
1096 _CullInvisibleItems(secondSubItems
);
1097 _DoSwap(fList
, firstIndex
, secondIndex
, &firstSubItems
,
1100 _RecalcItemTops(firstIndex
);
1101 _RescanSelection(firstIndex
, secondIndex
+ secondSubItems
.CountItems());
1102 Invalidate(Bounds());
1108 /*! \brief Removes a single item from the list and all of its children.
1110 Unlike the BeOS version, this one will actually delete the children, too,
1111 as there should be no reference left to them. This may cause problems for
1112 applications that actually take the misbehaviour of the Be classes into
1116 BOutlineListView::_RemoveItem(BListItem
* item
, int32 fullListIndex
)
1118 if (item
== NULL
|| fullListIndex
< 0
1119 || fullListIndex
>= FullListCountItems()) {
1123 uint32 level
= item
->OutlineLevel();
1125 BListItem
* super
= _SuperitemForIndex(fullListIndex
, level
, &superIndex
);
1127 if (item
->IsItemVisible()) {
1128 // remove children, too
1129 while (fullListIndex
+ 1 < FullListCountItems()) {
1130 BListItem
* subItem
= FullListItemAt(fullListIndex
+ 1);
1132 if (subItem
->OutlineLevel() <= level
)
1135 if (subItem
->IsItemVisible())
1136 BListView::RemoveItem(subItem
);
1138 fFullList
.RemoveItem(fullListIndex
+ 1);
1141 BListView::RemoveItem(item
);
1144 fFullList
.RemoveItem(fullListIndex
);
1146 if (super
!= NULL
) {
1147 // we might need to change the fHasSubitems field of the parent
1148 BListItem
* child
= FullListItemAt(superIndex
+ 1);
1149 if (child
== NULL
|| child
->OutlineLevel() <= super
->OutlineLevel())
1150 super
->fHasSubitems
= false;
1157 /*! Returns the super item before the item specified by \a fullListIndex
1161 BOutlineListView::_SuperitemForIndex(int32 fullListIndex
, int32 level
,
1167 while (fullListIndex
>= 0) {
1168 if ((item
= FullListItemAt(fullListIndex
))->OutlineLevel()
1170 if (_superIndex
!= NULL
)
1171 *_superIndex
= fullListIndex
;
1183 BOutlineListView::_FindPreviousVisibleIndex(int32 fullListIndex
)
1187 while (fullListIndex
>= 0) {
1188 if (FullListItemAt(fullListIndex
)->fVisible
)
1189 return fullListIndex
;