1 /* 2 * Copyright 2001-2006, Haiku Inc. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Marc Flerackers (mflerackers@androme.be) 7 * Axel Dörfler, axeld@pinc-software.de 8 */ 9 10 //! BOutlineListView represents a "nestable" list view. 11 12 #include <OutlineListView.h> 13 14 #include <stdio.h> 15 #include <stdlib.h> 16 17 18 /*! 19 \brief A simple recursive quick sort implementations for BListItem arrays. 20 21 We need to implement it ourselves, since the BOutlineListView sort methods 22 use a different comparison function than the standard functions. 23 */ 24 static void 25 quick_sort_item_array(BListItem** items, int32 first, int32 last, 26 int (*compareFunc)(const BListItem* a, const BListItem* b)) 27 { 28 if (last - 1 <= first) 29 return; 30 31 BListItem* pivot = items[first + (rand() % (last - first))]; 32 // choose an arbitrary pivot element 33 34 int32 left = first; 35 int32 right = last; 36 37 do { 38 while (compareFunc(items[left], pivot) < 0) { 39 left++; 40 } 41 while (compareFunc(items[right], pivot) > 0) { 42 right--; 43 } 44 45 if (left <= right) { 46 // swap entries 47 BListItem* temp = items[left]; 48 items[left] = items[right]; 49 items[right] = temp; 50 51 left++; 52 right--; 53 } 54 } while (left <= right); 55 56 // At this point, the elements in the left half are all smaller 57 // than the elements in the right half 58 59 if (first < right) { 60 // sort left half 61 quick_sort_item_array(items, first, right, compareFunc); 62 } 63 if (left < last) { 64 // sort right half 65 quick_sort_item_array(items, left, last, compareFunc); 66 } 67 } 68 69 70 // #pragma mark - 71 72 73 BOutlineListView::BOutlineListView(BRect frame, const char* name, 74 list_view_type type, uint32 resizeMode, uint32 flags) 75 : BListView(frame, name, type, resizeMode, flags) 76 { 77 } 78 79 80 BOutlineListView::BOutlineListView(BMessage* archive) 81 : BListView(archive) 82 { 83 } 84 85 86 BOutlineListView::~BOutlineListView() 87 { 88 fFullList.MakeEmpty(); 89 } 90 91 92 BArchivable * 93 BOutlineListView::Instantiate(BMessage* archive) 94 { 95 if (validate_instantiation(archive, "BOutlineListView")) 96 return new BOutlineListView(archive); 97 98 return NULL; 99 } 100 101 102 status_t 103 BOutlineListView::Archive(BMessage* archive, bool deep) const 104 { 105 return BListView::Archive(archive, deep); 106 } 107 108 109 void 110 BOutlineListView::MouseDown(BPoint point) 111 { 112 MakeFocus(); 113 114 int32 index = IndexOf(point); 115 116 if (index != -1) { 117 BListItem *item = ItemAt(index); 118 119 if (item->fHasSubitems 120 && LatchRect(ItemFrame(index), item->fLevel).Contains(point)) { 121 if (item->IsExpanded()) 122 Collapse(item); 123 else 124 Expand(item); 125 } else 126 BListView::MouseDown(point); 127 } 128 } 129 130 131 void 132 BOutlineListView::KeyDown(const char* bytes, int32 numBytes) 133 { 134 if (numBytes == 1) { 135 switch (bytes[0]) { 136 case B_RIGHT_ARROW: 137 { 138 BListItem *item = ItemAt(CurrentSelection()); 139 if (item && item->fHasSubitems) 140 Expand(item); 141 return; 142 } 143 144 case B_LEFT_ARROW: 145 { 146 BListItem *item = ItemAt(CurrentSelection()); 147 if (item && item->fHasSubitems) 148 Collapse(item); 149 return; 150 } 151 } 152 } 153 154 BListView::KeyDown(bytes, numBytes); 155 } 156 157 158 void 159 BOutlineListView::FrameMoved(BPoint newPosition) 160 { 161 BListView::FrameMoved(newPosition); 162 } 163 164 165 void 166 BOutlineListView::FrameResized(float newWidth, float newHeight) 167 { 168 BListView::FrameResized(newWidth, newHeight); 169 } 170 171 172 void 173 BOutlineListView::MouseUp(BPoint where) 174 { 175 BListView::MouseUp(where); 176 } 177 178 179 bool 180 BOutlineListView::AddUnder(BListItem* item, BListItem* superitem) 181 { 182 fFullList.AddItem(item, FullListIndexOf(superitem) + 1); 183 184 item->fLevel = superitem->OutlineLevel() + 1; 185 superitem->fHasSubitems = true; 186 187 if (superitem->IsItemVisible() && superitem->IsExpanded()) { 188 item->SetItemVisible(true); 189 190 int32 index = BListView::IndexOf(superitem); 191 192 BListView::AddItem(item, index + 1); 193 Invalidate(LatchRect(ItemFrame(index), superitem->OutlineLevel())); 194 } else 195 item->SetItemVisible(false); 196 197 return true; 198 } 199 200 201 bool 202 BOutlineListView::AddItem(BListItem* item) 203 { 204 if (!fFullList.AddItem(item)) 205 return false; 206 207 return BListView::AddItem(item); 208 } 209 210 211 bool 212 BOutlineListView::AddItem(BListItem* item, int32 fullListIndex) 213 { 214 if (fullListIndex < 0) 215 fullListIndex = 0; 216 else if (fullListIndex > CountItems()) 217 fullListIndex = CountItems(); 218 219 fFullList.AddItem(item, fullListIndex); 220 221 if (item->fLevel > 0) { 222 BListItem *super = SuperitemForIndex(fullListIndex, item->fLevel); 223 224 if (!super->IsItemVisible() || !super->IsExpanded()) 225 return true; 226 } 227 228 int32 listIndex = FindPreviousVisibleIndex(fullListIndex); 229 230 return BListView::AddItem(item, IndexOf(FullListItemAt(listIndex)) + 1); 231 } 232 233 234 bool 235 BOutlineListView::AddList(BList* newItems) 236 { 237 printf("BOutlineListView::AddList Not implemented\n"); 238 return false; 239 } 240 241 242 bool 243 BOutlineListView::AddList(BList* newItems, int32 fullListIndex) 244 { 245 printf("BOutlineListView::AddList Not implemented\n"); 246 return false; 247 } 248 249 250 bool 251 BOutlineListView::RemoveItem(BListItem* item) 252 { 253 return _RemoveItem(item, FullListIndexOf(item)) != NULL; 254 } 255 256 257 BListItem* 258 BOutlineListView::RemoveItem(int32 fullIndex) 259 { 260 return _RemoveItem(FullListItemAt(fullIndex), fullIndex); 261 } 262 263 264 bool 265 BOutlineListView::RemoveItems(int32 fullListIndex, int32 count) 266 { 267 printf("BOutlineListView::RemoveItems Not implemented\n"); 268 269 return false; 270 } 271 272 273 BListItem * 274 BOutlineListView::FullListItemAt(int32 fullListIndex) const 275 { 276 return (BListItem*)fFullList.ItemAt(fullListIndex); 277 } 278 279 280 int32 281 BOutlineListView::FullListIndexOf(BPoint point) const 282 { 283 return BListView::IndexOf(point); 284 } 285 286 287 int32 288 BOutlineListView::FullListIndexOf(BListItem* item) const 289 { 290 return fFullList.IndexOf(item); 291 } 292 293 294 BListItem * 295 BOutlineListView::FullListFirstItem() const 296 { 297 return (BListItem*)fFullList.FirstItem(); 298 } 299 300 301 BListItem * 302 BOutlineListView::FullListLastItem() const 303 { 304 return (BListItem*)fFullList.LastItem(); 305 } 306 307 308 bool 309 BOutlineListView::FullListHasItem(BListItem *item) const 310 { 311 return fFullList.HasItem(item); 312 } 313 314 315 int32 316 BOutlineListView::FullListCountItems() const 317 { 318 return fFullList.CountItems(); 319 } 320 321 322 int32 323 BOutlineListView::FullListCurrentSelection(int32 index) const 324 { 325 int32 i = BListView::CurrentSelection(index); 326 327 BListItem *item = BListView::ItemAt(i); 328 if (item) 329 return fFullList.IndexOf(item); 330 331 return -1; 332 } 333 334 335 void 336 BOutlineListView::MakeEmpty() 337 { 338 fFullList.MakeEmpty(); 339 BListView::MakeEmpty(); 340 } 341 342 343 bool 344 BOutlineListView::FullListIsEmpty() const 345 { 346 return fFullList.IsEmpty(); 347 } 348 349 350 void 351 BOutlineListView::FullListDoForEach(bool(*func)(BListItem* item)) 352 { 353 fFullList.DoForEach(reinterpret_cast<bool (*)(void*)>(func)); 354 } 355 356 357 void 358 BOutlineListView::FullListDoForEach(bool (*func)(BListItem* item, void* arg), 359 void* arg) 360 { 361 fList.DoForEach(reinterpret_cast<bool (*)(void*, void*)>(func), arg); 362 } 363 364 365 BListItem * 366 BOutlineListView::Superitem(const BListItem* item) 367 { 368 int32 index = FullListIndexOf((BListItem*)item); 369 if (index == -1) 370 return NULL; 371 372 return SuperitemForIndex(index, item->OutlineLevel()); 373 } 374 375 376 void 377 BOutlineListView::Expand(BListItem* item) 378 { 379 if (item->IsExpanded() || !FullListHasItem(item)) 380 return; 381 382 item->fExpanded = true; 383 384 uint32 level = item->fLevel; 385 int32 fullIndex = FullListIndexOf(item); 386 int32 index = IndexOf(item) + 1; 387 int32 count = FullListCountItems() - fullIndex - 1; 388 BListItem** items = (BListItem**)fFullList.Items() + fullIndex + 1; 389 390 BFont font; 391 GetFont(&font); 392 393 while (count-- > 0) { 394 item = items[0]; 395 if (item->fLevel <= level) 396 break; 397 398 if (!item->IsItemVisible()) { 399 // fix selection hints 400 if (index <= fFirstSelected) 401 fFirstSelected++; 402 if (index <= fLastSelected) 403 fLastSelected++; 404 405 fList.AddItem(item, index++); 406 item->Update(this, &font); 407 item->SetItemVisible(true); 408 } 409 410 if (item->HasSubitems() && !item->IsExpanded()) { 411 // Skip hidden children 412 uint32 subLevel = item->fLevel; 413 items++; 414 415 while (--count > 0 && items[0]->fLevel > subLevel) 416 items++; 417 } else 418 items++; 419 } 420 421 _FixupScrollBar(); 422 Invalidate(); 423 } 424 425 426 void 427 BOutlineListView::Collapse(BListItem* item) 428 { 429 if (!item->IsExpanded() || !FullListHasItem(item)) 430 return; 431 432 item->fExpanded = false; 433 434 uint32 level = item->fLevel; 435 int32 fullIndex = FullListIndexOf(item); 436 int32 index = IndexOf(item); 437 int32 max = FullListCountItems() - fullIndex - 1; 438 int32 count = 0; 439 BListItem** items = (BListItem**)fFullList.Items() + fullIndex + 1; 440 441 while (max-- > 0) { 442 item = items[0]; 443 if (item->fLevel <= level) 444 break; 445 446 if (item->IsItemVisible()) { 447 fList.RemoveItem(item); 448 item->SetItemVisible(false); 449 if (item->IsSelected()) 450 item->Deselect(); 451 452 count++; 453 } 454 455 items++; 456 } 457 458 // fix selection hints 459 // TODO: revise for multi selection lists 460 if (index < fFirstSelected) { 461 if (index + count < fFirstSelected) { 462 fFirstSelected -= count; 463 fLastSelected -= count; 464 } else { 465 // select top item 466 //fFirstSelected = fLastSelected = index; 467 //item->Select(); 468 Select(index); 469 } 470 } 471 472 _FixupScrollBar(); 473 Invalidate(); 474 } 475 476 477 bool 478 BOutlineListView::IsExpanded(int32 fullListIndex) 479 { 480 BListItem *item = FullListItemAt(fullListIndex); 481 if (!item) 482 return false; 483 484 return item->IsExpanded(); 485 } 486 487 488 BHandler * 489 BOutlineListView::ResolveSpecifier(BMessage* msg, int32 index, 490 BMessage* specifier, int32 what, const char* property) 491 { 492 return BListView::ResolveSpecifier(msg, index, specifier, what, property); 493 } 494 495 496 status_t 497 BOutlineListView::GetSupportedSuites(BMessage* data) 498 { 499 return BListView::GetSupportedSuites(data); 500 } 501 502 503 status_t 504 BOutlineListView::Perform(perform_code d, void* arg) 505 { 506 return BListView::Perform(d, arg); 507 } 508 509 510 void 511 BOutlineListView::ResizeToPreferred() 512 { 513 BListView::ResizeToPreferred(); 514 } 515 516 517 void 518 BOutlineListView::GetPreferredSize(float* _width, float* _height) 519 { 520 BListView::GetPreferredSize(_width, _height); 521 } 522 523 524 void 525 BOutlineListView::MakeFocus(bool state) 526 { 527 BListView::MakeFocus(state); 528 } 529 530 531 void 532 BOutlineListView::AllAttached() 533 { 534 BListView::AllAttached(); 535 } 536 537 538 void 539 BOutlineListView::AllDetached() 540 { 541 BListView::AllDetached(); 542 } 543 544 545 void 546 BOutlineListView::DetachedFromWindow() 547 { 548 BListView::DetachedFromWindow(); 549 } 550 551 552 void 553 BOutlineListView::FullListSortItems(int (*compareFunc)(const BListItem* a, 554 const BListItem* b)) 555 { 556 SortItemsUnder(NULL, false, compareFunc); 557 } 558 559 560 void 561 BOutlineListView::SortItemsUnder(BListItem* underItem, bool oneLevelOnly, 562 int (*compareFunc)(const BListItem* a, const BListItem* b)) 563 { 564 // This method is quite complicated: basically, it creates a real tree 565 // from the items of the full list, sorts them as needed, and then 566 // populates the entries back into the full and display lists 567 568 int32 firstIndex = FullListIndexOf(underItem) + 1; 569 int32 lastIndex = firstIndex; 570 BList* tree = _BuildTree(underItem, lastIndex); 571 572 _SortTree(tree, oneLevelOnly, compareFunc); 573 574 // Populate to the full list 575 _PopulateTree(tree, fFullList, firstIndex, false); 576 577 // Populate to BListView's list 578 firstIndex = fList.IndexOf(underItem) + 1; 579 _PopulateTree(tree, fList, firstIndex, true); 580 581 _DestructTree(tree); 582 } 583 584 585 void 586 BOutlineListView::_PopulateTree(BList* tree, BList& target, 587 int32& firstIndex, bool onlyVisible) 588 { 589 BListItem** items = (BListItem**)target.Items(); 590 int32 count = tree->CountItems(); 591 592 for (int32 index = 0; index < count; index++) { 593 BListItem* item = (BListItem*)tree->ItemAtFast(index); 594 595 items[firstIndex++] = item; 596 597 if (item->HasSubitems() && (!onlyVisible || item->IsExpanded())) 598 _PopulateTree(item->fTemporaryList, target, firstIndex, onlyVisible); 599 } 600 } 601 602 603 void 604 BOutlineListView::_SortTree(BList* tree, bool oneLevelOnly, 605 int (*compareFunc)(const BListItem* a, const BListItem* b)) 606 { 607 // home-brewn quick sort for our compareFunc 608 quick_sort_item_array((BListItem**)tree->Items(), 0, tree->CountItems() - 1, 609 compareFunc); 610 611 if (oneLevelOnly) 612 return; 613 614 for (int32 index = tree->CountItems(); index-- > 0;) { 615 BListItem* item = (BListItem*)tree->ItemAt(index); 616 617 if (item->HasSubitems()) 618 _SortTree(item->fTemporaryList, false, compareFunc); 619 } 620 } 621 622 623 void 624 BOutlineListView::_DestructTree(BList* tree) 625 { 626 for (int32 index = tree->CountItems(); index-- > 0;) { 627 BListItem* item = (BListItem*)tree->ItemAt(index); 628 629 if (item->HasSubitems()) 630 _DestructTree(item->fTemporaryList); 631 } 632 633 delete tree; 634 } 635 636 637 BList* 638 BOutlineListView::_BuildTree(BListItem* underItem, int32& fullIndex) 639 { 640 int32 fullCount = FullListCountItems(); 641 uint32 level = underItem != NULL ? underItem->OutlineLevel() + 1 : 0; 642 BList* list = new BList; 643 if (underItem != NULL) 644 underItem->fTemporaryList = list; 645 646 while (fullIndex < fullCount) { 647 BListItem *item = FullListItemAt(fullIndex); 648 649 // If we jump out of the subtree, break out 650 if (item->fLevel < level) 651 break; 652 653 if (item->fLevel == level) { 654 // If the level matches, put them into the list 655 list->AddItem(item); 656 } 657 658 fullIndex++; 659 660 if (item->HasSubitems()) { 661 // we're going deeper 662 _BuildTree(item, fullIndex); 663 } 664 } 665 666 return list; 667 } 668 669 670 int32 671 BOutlineListView::CountItemsUnder(BListItem* underItem, 672 bool oneLevelOnly) const 673 { 674 int32 i = IndexOf(underItem); 675 if (i == -1) 676 return 0; 677 678 int32 count = 0; 679 680 while (i < FullListCountItems()) { 681 BListItem *item = FullListItemAt(i); 682 683 // If we jump out of the subtree, return count 684 if (item->fLevel < underItem->OutlineLevel()) 685 return count; 686 687 // If the level matches, increase count 688 if (!oneLevelOnly || item->fLevel == underItem->OutlineLevel() + 1) 689 count++; 690 691 i++; 692 } 693 694 return count; 695 } 696 697 698 BListItem * 699 BOutlineListView::EachItemUnder(BListItem *underItem, bool oneLevelOnly, 700 BListItem *(*eachFunc)(BListItem* item, void* arg), void* arg) 701 { 702 int32 i = IndexOf(underItem); 703 if (i == -1) 704 return NULL; 705 706 while (i < FullListCountItems()) { 707 BListItem *item = FullListItemAt(i); 708 709 // If we jump out of the subtree, return NULL 710 if (item->fLevel < underItem->OutlineLevel()) 711 return NULL; 712 713 // If the level matches, check the index 714 if (!oneLevelOnly || item->fLevel == underItem->OutlineLevel() + 1) { 715 item = eachFunc(item, arg); 716 if (item != NULL) 717 return item; 718 } 719 720 i++; 721 } 722 723 return NULL; 724 } 725 726 727 BListItem * 728 BOutlineListView::ItemUnderAt(BListItem* underItem, 729 bool oneLevelOnly, int32 index) const 730 { 731 int32 i = IndexOf(underItem); 732 if (i == -1) 733 return NULL; 734 735 while (i < FullListCountItems()) { 736 BListItem *item = FullListItemAt(i); 737 738 // If we jump out of the subtree, return NULL 739 if (item->fLevel < underItem->OutlineLevel()) 740 return NULL; 741 742 // If the level matches, check the index 743 if (!oneLevelOnly || item->fLevel == underItem->OutlineLevel() + 1) { 744 if (index == 0) 745 return item; 746 747 index--; 748 } 749 750 i++; 751 } 752 753 return NULL; 754 } 755 756 757 bool 758 BOutlineListView::DoMiscellaneous(MiscCode code, MiscData* data) 759 { 760 return BListView::DoMiscellaneous(code, data); 761 } 762 763 764 void 765 BOutlineListView::MessageReceived(BMessage* msg) 766 { 767 BListView::MessageReceived(msg); 768 } 769 770 771 void BOutlineListView::_ReservedOutlineListView1() {} 772 void BOutlineListView::_ReservedOutlineListView2() {} 773 void BOutlineListView::_ReservedOutlineListView3() {} 774 void BOutlineListView::_ReservedOutlineListView4() {} 775 776 777 int32 778 BOutlineListView::FullListIndex(int32 index) const 779 { 780 BListItem *item = ItemAt(index); 781 782 if (item == NULL) 783 return -1; 784 785 return FullListIndexOf(item); 786 } 787 788 789 int32 790 BOutlineListView::ListViewIndex(int32 index) const 791 { 792 BListItem *item = ItemAt(index); 793 794 if (item == NULL) 795 return -1; 796 797 return BListView::IndexOf(item); 798 } 799 800 801 void 802 BOutlineListView::ExpandOrCollapse(BListItem *underItem, bool expand) 803 { 804 } 805 806 807 BRect 808 BOutlineListView::LatchRect(BRect itemRect, int32 level) const 809 { 810 return BRect(itemRect.left, itemRect.top, itemRect.left 811 + (level * 10.0f + 15.0f), itemRect.bottom); 812 } 813 814 815 void 816 BOutlineListView::DrawLatch(BRect itemRect, int32 level, bool collapsed, 817 bool highlighted, bool misTracked) 818 { 819 float left = level * 10.0f; 820 821 if (collapsed) { 822 SetHighColor(192, 192, 192); 823 824 FillTriangle(itemRect.LeftTop() + BPoint(left + 4.0f, 2.0f), 825 itemRect.LeftTop() + BPoint(left + 4.0f, 10.0f), 826 itemRect.LeftTop() + BPoint(left + 8.0f, 6.0f)); 827 828 SetHighColor(0, 0, 0); 829 830 StrokeTriangle(itemRect.LeftTop() + BPoint(left + 4.0f, 2.0f), 831 itemRect.LeftTop() + BPoint(left + 4.0f, 10.0f), 832 itemRect.LeftTop() + BPoint(left + 8.0f, 6.0f)); 833 } else { 834 SetHighColor(192, 192, 192); 835 836 FillTriangle(itemRect.LeftTop() + BPoint(left + 2.0f, 4.0f), 837 itemRect.LeftTop() + BPoint(left + 10.0f, 4.0f), 838 itemRect.LeftTop() + BPoint(left + 6.0f, 8.0f)); 839 840 SetHighColor(0, 0, 0); 841 842 StrokeTriangle(itemRect.LeftTop() + BPoint(left + 2.0f, 4.0f), 843 itemRect.LeftTop() + BPoint(left + 10.0f, 4.0f), 844 itemRect.LeftTop() + BPoint(left + 6.0f, 8.0f)); 845 } 846 } 847 848 849 void 850 BOutlineListView::DrawItem(BListItem* item, BRect itemRect, bool complete) 851 { 852 if (item->fHasSubitems) 853 DrawLatch(itemRect, item->fLevel, !item->IsExpanded(), false, false); 854 855 itemRect.left += (item->fLevel) * 10.0f + 15.0f; 856 item->DrawItem(this, itemRect, complete); 857 } 858 859 860 /*! 861 \brief Removes a single item from the list and all of its children. 862 863 Unlike the BeOS version, this one will actually delete the children, too, 864 as there should be no reference left to them. This may cause problems for 865 applications that actually take the misbehaviour of the Be classes into 866 account. 867 */ 868 BListItem * 869 BOutlineListView::_RemoveItem(BListItem* item, int32 fullIndex) 870 { 871 if (item == NULL || fullIndex < 0 || fullIndex >= FullListCountItems()) 872 return NULL; 873 874 if (item->IsItemVisible()) { 875 // remove children, too 876 uint32 level = item->OutlineLevel(); 877 int32 max = FullListCountItems() - fullIndex - 1; 878 BListItem** items = (BListItem**)fFullList.Items() + fullIndex + 1; 879 880 while (max-- > 0) { 881 BListItem* subItem = items[0]; 882 if (subItem->fLevel <= level) 883 break; 884 885 if (subItem->IsItemVisible()) 886 BListView::RemoveItem(subItem); 887 888 fFullList.RemoveItem(fullIndex + 1); 889 890 // TODO: this might be problematic, see comment above 891 delete subItem; 892 } 893 894 BListView::RemoveItem(item); 895 } 896 897 fFullList.RemoveItem(fullIndex); 898 return item; 899 } 900 901 902 BListItem * 903 BOutlineListView::RemoveOne(int32 fullListIndex) 904 { 905 return NULL; 906 } 907 908 909 void 910 BOutlineListView::TrackInLatchItem(void *) 911 { 912 } 913 914 915 void 916 BOutlineListView::TrackOutLatchItem(void *) 917 { 918 } 919 920 921 bool 922 BOutlineListView::OutlineSwapItems(int32 a, int32 b) 923 { 924 return false; 925 } 926 927 928 bool 929 BOutlineListView::OutlineMoveItem(int32 from, int32 to) 930 { 931 return false; 932 } 933 934 935 bool 936 BOutlineListView::OutlineReplaceItem(int32 index, BListItem *item) 937 { 938 return false; 939 } 940 941 942 void 943 BOutlineListView::CommonMoveItems(int32 from, int32 count, int32 to) 944 { 945 } 946 947 948 BListItem * 949 BOutlineListView::SuperitemForIndex(int32 fullListIndex, int32 level) 950 { 951 BListItem *item; 952 fullListIndex--; 953 954 while (fullListIndex >= 0) { 955 if ((item = FullListItemAt(fullListIndex))->OutlineLevel() < 956 (uint32)level) 957 return item; 958 959 fullListIndex--; 960 } 961 962 return NULL; 963 } 964 965 966 int32 967 BOutlineListView::FindPreviousVisibleIndex(int32 fullListIndex) 968 { 969 fullListIndex--; 970 971 while (fullListIndex >= 0) { 972 if (FullListItemAt(fullListIndex)->fVisible) 973 return fullListIndex; 974 975 fullListIndex--; 976 } 977 978 return -1; 979 } 980 981