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 BListView::GetPreferredSize(_width
, _height
);
597 BOutlineListView::MakeFocus(bool state
)
599 BListView::MakeFocus(state
);
604 BOutlineListView::AllAttached()
606 BListView::AllAttached();
611 BOutlineListView::AllDetached()
613 BListView::AllDetached();
618 BOutlineListView::DetachedFromWindow()
620 BListView::DetachedFromWindow();
625 BOutlineListView::FullListSortItems(int (*compareFunc
)(const BListItem
* a
,
628 SortItemsUnder(NULL
, false, compareFunc
);
633 BOutlineListView::SortItemsUnder(BListItem
* superItem
, bool oneLevelOnly
,
634 int (*compareFunc
)(const BListItem
* a
, const BListItem
* b
))
636 // This method is quite complicated: basically, it creates a real tree
637 // from the items of the full list, sorts them as needed, and then
638 // populates the entries back into the full and display lists
640 int32 firstIndex
= FullListIndexOf(superItem
) + 1;
641 int32 lastIndex
= firstIndex
;
642 BList
* tree
= _BuildTree(superItem
, lastIndex
);
644 _SortTree(tree
, oneLevelOnly
, compareFunc
);
646 // Populate to the full list
647 _PopulateTree(tree
, fFullList
, firstIndex
, false);
649 if (superItem
== NULL
650 || (superItem
->IsItemVisible() && superItem
->IsExpanded())) {
651 // Populate to BListView's list
652 firstIndex
= fList
.IndexOf(superItem
) + 1;
653 lastIndex
= firstIndex
;
654 _PopulateTree(tree
, fList
, lastIndex
, true);
656 if (fFirstSelected
!= -1) {
657 // update selection hints
658 fFirstSelected
= _CalcFirstSelected(0);
659 fLastSelected
= _CalcLastSelected(CountItems());
662 // only invalidate what may have changed
663 _RecalcItemTops(firstIndex
);
664 BRect top
= ItemFrame(firstIndex
);
665 BRect bottom
= ItemFrame(lastIndex
- 1);
666 BRect
update(top
.left
, top
.top
, bottom
.right
, bottom
.bottom
);
675 BOutlineListView::CountItemsUnder(BListItem
* superItem
, bool oneLevelOnly
) const
677 int32 i
= FullListIndexOf(superItem
);
683 uint32 baseLevel
= superItem
->OutlineLevel();
685 for (; i
< FullListCountItems(); i
++) {
686 BListItem
* item
= FullListItemAt(i
);
688 // If we jump out of the subtree, return count
689 if (item
->fLevel
<= baseLevel
)
692 // If the level matches, increase count
693 if (!oneLevelOnly
|| item
->fLevel
== baseLevel
+ 1)
702 BOutlineListView::EachItemUnder(BListItem
* superItem
, bool oneLevelOnly
,
703 BListItem
* (*eachFunc
)(BListItem
* item
, void* arg
), void* arg
)
705 int32 i
= IndexOf(superItem
);
709 while (i
< FullListCountItems()) {
710 BListItem
* item
= FullListItemAt(i
);
712 // If we jump out of the subtree, return NULL
713 if (item
->fLevel
< superItem
->OutlineLevel())
716 // If the level matches, check the index
717 if (!oneLevelOnly
|| item
->fLevel
== superItem
->OutlineLevel() + 1) {
718 item
= eachFunc(item
, arg
);
731 BOutlineListView::ItemUnderAt(BListItem
* superItem
, bool oneLevelOnly
,
734 int32 i
= FullListIndexOf(superItem
);
738 while (i
< FullListCountItems()) {
739 BListItem
* item
= FullListItemAt(i
);
741 // If we jump out of the subtree, return NULL
742 if (item
->fLevel
< superItem
->OutlineLevel())
745 // If the level matches, check the index
746 if (!oneLevelOnly
|| item
->fLevel
== superItem
->OutlineLevel() + 1) {
761 BOutlineListView::DoMiscellaneous(MiscCode code
, MiscData
* data
)
763 if (code
== B_SWAP_OP
)
764 return _SwapItems(data
->swap
.a
, data
->swap
.b
);
766 return BListView::DoMiscellaneous(code
, data
);
771 BOutlineListView::MessageReceived(BMessage
* msg
)
773 BListView::MessageReceived(msg
);
777 void BOutlineListView::_ReservedOutlineListView1() {}
778 void BOutlineListView::_ReservedOutlineListView2() {}
779 void BOutlineListView::_ReservedOutlineListView3() {}
780 void BOutlineListView::_ReservedOutlineListView4() {}
784 BOutlineListView::ExpandOrCollapse(BListItem
* item
, bool expand
)
786 if (item
->IsExpanded() == expand
|| !FullListHasItem(item
))
789 item
->fExpanded
= expand
;
791 // TODO: merge these cases together, they are pretty similar
794 uint32 level
= item
->fLevel
;
795 int32 fullListIndex
= FullListIndexOf(item
);
796 int32 index
= IndexOf(item
) + 1;
797 int32 startIndex
= index
;
798 int32 count
= FullListCountItems() - fullListIndex
- 1;
799 BListItem
** items
= (BListItem
**)fFullList
.Items() + fullListIndex
+ 1;
803 while (count
-- > 0) {
805 if (item
->fLevel
<= level
)
808 if (!item
->IsItemVisible()) {
809 // fix selection hints
810 if (index
<= fFirstSelected
)
812 if (index
<= fLastSelected
)
815 fList
.AddItem(item
, index
++);
816 item
->Update(this, &font
);
817 item
->SetItemVisible(true);
820 if (item
->HasSubitems() && !item
->IsExpanded()) {
821 // Skip hidden children
822 uint32 subLevel
= item
->fLevel
;
825 while (--count
> 0 && items
[0]->fLevel
> subLevel
)
830 _RecalcItemTops(startIndex
);
833 uint32 level
= item
->fLevel
;
834 int32 fullListIndex
= FullListIndexOf(item
);
835 int32 index
= IndexOf(item
);
836 int32 startIndex
= index
;
837 int32 max
= FullListCountItems() - fullListIndex
- 1;
839 bool selectionChanged
= false;
841 BListItem
** items
= (BListItem
**)fFullList
.Items() + fullListIndex
+ 1;
845 if (item
->fLevel
<= level
)
848 if (item
->IsItemVisible()) {
849 fList
.RemoveItem(item
);
850 item
->SetItemVisible(false);
851 if (item
->IsSelected()) {
852 selectionChanged
= true;
861 _RecalcItemTops(startIndex
);
862 // fix selection hints
863 // if the selected item was just removed by collapsing, select its
865 if (ListType() == B_SINGLE_SELECTION_LIST
&& selectionChanged
)
866 fFirstSelected
= fLastSelected
= index
;
868 if (index
< fFirstSelected
&& index
+ count
< fFirstSelected
) {
869 // all items removed were higher than the selection range,
870 // adjust the indexes to correspond to their new visible positions
871 fFirstSelected
-= count
;
872 fLastSelected
-= count
;
875 int32 maxIndex
= fList
.CountItems() - 1;
876 if (fFirstSelected
> maxIndex
)
877 fFirstSelected
= maxIndex
;
879 if (fLastSelected
> maxIndex
)
880 fLastSelected
= maxIndex
;
882 if (selectionChanged
)
892 BOutlineListView::LatchRect(BRect itemRect
, int32 level
) const
894 float latchWidth
= be_plain_font
->Size();
895 float latchHeight
= be_plain_font
->Size();
896 float indentOffset
= level
* be_control_look
->DefaultItemSpacing();
897 float heightOffset
= itemRect
.Height() / 2 - latchHeight
/ 2;
899 return BRect(0, 0, latchWidth
, latchHeight
)
900 .OffsetBySelf(itemRect
.left
, itemRect
.top
)
901 .OffsetBySelf(indentOffset
, heightOffset
);
906 BOutlineListView::DrawLatch(BRect itemRect
, int32 level
, bool collapsed
,
907 bool highlighted
, bool misTracked
)
909 BRect
latchRect(LatchRect(itemRect
, level
));
910 rgb_color base
= ui_color(B_PANEL_BACKGROUND_COLOR
);
911 int32 arrowDirection
= collapsed
? BControlLook::B_RIGHT_ARROW
912 : BControlLook::B_DOWN_ARROW
;
914 be_control_look
->DrawArrowShape(this, latchRect
, itemRect
, base
,
915 arrowDirection
, 0, B_DARKEN_4_TINT
);
920 BOutlineListView::DrawItem(BListItem
* item
, BRect itemRect
, bool complete
)
922 if (item
->fHasSubitems
) {
923 DrawLatch(itemRect
, item
->fLevel
, !item
->IsExpanded(),
924 item
->IsSelected() || complete
, false);
927 itemRect
.left
+= LatchRect(itemRect
, item
->fLevel
).right
;
928 BListView::DrawItem(item
, itemRect
, complete
);
933 BOutlineListView::_FullListIndex(int32 index
) const
935 BListItem
* item
= ItemAt(index
);
940 return FullListIndexOf(item
);
945 BOutlineListView::_PopulateTree(BList
* tree
, BList
& target
,
946 int32
& firstIndex
, bool onlyVisible
)
948 BListItem
** items
= (BListItem
**)target
.Items();
949 int32 count
= tree
->CountItems();
951 for (int32 index
= 0; index
< count
; index
++) {
952 BListItem
* item
= (BListItem
*)tree
->ItemAtFast(index
);
954 items
[firstIndex
++] = item
;
956 if (item
->HasSubitems() && (!onlyVisible
|| item
->IsExpanded())) {
957 _PopulateTree(item
->fTemporaryList
, target
, firstIndex
,
965 BOutlineListView::_SortTree(BList
* tree
, bool oneLevelOnly
,
966 int (*compareFunc
)(const BListItem
* a
, const BListItem
* b
))
968 BListItem
** items
= (BListItem
**)tree
->Items();
969 std::sort(items
, items
+ tree
->CountItems(),
970 ListItemComparator(compareFunc
));
975 for (int32 index
= tree
->CountItems(); index
-- > 0;) {
976 BListItem
* item
= (BListItem
*)tree
->ItemAt(index
);
978 if (item
->HasSubitems())
979 _SortTree(item
->fTemporaryList
, false, compareFunc
);
985 BOutlineListView::_DestructTree(BList
* tree
)
987 for (int32 index
= tree
->CountItems(); index
-- > 0;) {
988 BListItem
* item
= (BListItem
*)tree
->ItemAt(index
);
990 if (item
->HasSubitems())
991 _DestructTree(item
->fTemporaryList
);
999 BOutlineListView::_BuildTree(BListItem
* superItem
, int32
& fullListIndex
)
1001 int32 fullCount
= FullListCountItems();
1002 uint32 level
= superItem
!= NULL
? superItem
->OutlineLevel() + 1 : 0;
1003 BList
* list
= new BList
;
1004 if (superItem
!= NULL
)
1005 superItem
->fTemporaryList
= list
;
1007 while (fullListIndex
< fullCount
) {
1008 BListItem
* item
= FullListItemAt(fullListIndex
);
1010 // If we jump out of the subtree, break out
1011 if (item
->fLevel
< level
)
1014 // If the level matches, put them into the list
1015 // (we handle the case of a missing sublevel gracefully)
1016 list
->AddItem(item
);
1019 if (item
->HasSubitems()) {
1020 // we're going deeper
1021 _BuildTree(item
, fullListIndex
);
1030 BOutlineListView::_CullInvisibleItems(BList
& list
)
1033 while (index
< list
.CountItems()) {
1034 if (reinterpret_cast<BListItem
*>(list
.ItemAt(index
))->IsItemVisible())
1037 list
.RemoveItem(index
);
1043 BOutlineListView::_SwapItems(int32 first
, int32 second
)
1045 // same item, do nothing
1046 if (first
== second
)
1049 // fail, first item out of bounds
1050 if ((first
< 0) || (first
>= CountItems()))
1053 // fail, second item out of bounds
1054 if ((second
< 0) || (second
>= CountItems()))
1057 int32 firstIndex
= min_c(first
, second
);
1058 int32 secondIndex
= max_c(first
, second
);
1059 BListItem
* firstItem
= ItemAt(firstIndex
);
1060 BListItem
* secondItem
= ItemAt(secondIndex
);
1061 BList firstSubItems
, secondSubItems
;
1063 if (Superitem(firstItem
) != Superitem(secondItem
))
1066 if (!firstItem
->IsItemVisible() || !secondItem
->IsItemVisible())
1069 int32 fullFirstIndex
= _FullListIndex(firstIndex
);
1070 int32 fullSecondIndex
= _FullListIndex(secondIndex
);
1071 _GetSubItems(fFullList
, firstSubItems
, firstItem
, fullFirstIndex
+ 1);
1072 _GetSubItems(fFullList
, secondSubItems
, secondItem
, fullSecondIndex
+ 1);
1073 _DoSwap(fFullList
, fullFirstIndex
, fullSecondIndex
, &firstSubItems
,
1076 _CullInvisibleItems(firstSubItems
);
1077 _CullInvisibleItems(secondSubItems
);
1078 _DoSwap(fList
, firstIndex
, secondIndex
, &firstSubItems
,
1081 _RecalcItemTops(firstIndex
);
1082 _RescanSelection(firstIndex
, secondIndex
+ secondSubItems
.CountItems());
1083 Invalidate(Bounds());
1089 /*! \brief Removes a single item from the list and all of its children.
1091 Unlike the BeOS version, this one will actually delete the children, too,
1092 as there should be no reference left to them. This may cause problems for
1093 applications that actually take the misbehaviour of the Be classes into
1097 BOutlineListView::_RemoveItem(BListItem
* item
, int32 fullListIndex
)
1099 if (item
== NULL
|| fullListIndex
< 0
1100 || fullListIndex
>= FullListCountItems()) {
1104 uint32 level
= item
->OutlineLevel();
1106 BListItem
* super
= _SuperitemForIndex(fullListIndex
, level
, &superIndex
);
1108 if (item
->IsItemVisible()) {
1109 // remove children, too
1110 while (fullListIndex
+ 1 < FullListCountItems()) {
1111 BListItem
* subItem
= FullListItemAt(fullListIndex
+ 1);
1113 if (subItem
->OutlineLevel() <= level
)
1116 if (subItem
->IsItemVisible())
1117 BListView::RemoveItem(subItem
);
1119 fFullList
.RemoveItem(fullListIndex
+ 1);
1122 BListView::RemoveItem(item
);
1125 fFullList
.RemoveItem(fullListIndex
);
1127 if (super
!= NULL
) {
1128 // we might need to change the fHasSubitems field of the parent
1129 BListItem
* child
= FullListItemAt(superIndex
+ 1);
1130 if (child
== NULL
|| child
->OutlineLevel() <= super
->OutlineLevel())
1131 super
->fHasSubitems
= false;
1138 /*! Returns the super item before the item specified by \a fullListIndex
1142 BOutlineListView::_SuperitemForIndex(int32 fullListIndex
, int32 level
,
1148 while (fullListIndex
>= 0) {
1149 if ((item
= FullListItemAt(fullListIndex
))->OutlineLevel()
1151 if (_superIndex
!= NULL
)
1152 *_superIndex
= fullListIndex
;
1164 BOutlineListView::_FindPreviousVisibleIndex(int32 fullListIndex
)
1168 while (fullListIndex
>= 0) {
1169 if (FullListItemAt(fullListIndex
)->fVisible
)
1170 return fullListIndex
;