1 /* 2 * Copyright 2001-2007, 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 <= 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 if (superitem == NULL) 183 return AddItem(item); 184 185 fFullList.AddItem(item, FullListIndexOf(superitem) + 1); 186 187 item->fLevel = superitem->OutlineLevel() + 1; 188 superitem->fHasSubitems = true; 189 190 if (superitem->IsItemVisible() && superitem->IsExpanded()) { 191 item->SetItemVisible(true); 192 193 int32 index = BListView::IndexOf(superitem); 194 195 BListView::AddItem(item, index + 1); 196 Invalidate(LatchRect(ItemFrame(index), superitem->OutlineLevel())); 197 } else 198 item->SetItemVisible(false); 199 200 return true; 201 } 202 203 204 bool 205 BOutlineListView::AddItem(BListItem* item) 206 { 207 return AddItem(item, FullListCountItems()); 208 } 209 210 211 bool 212 BOutlineListView::AddItem(BListItem* item, int32 fullListIndex) 213 { 214 if (fullListIndex < 0) 215 fullListIndex = 0; 216 else if (fullListIndex > FullListCountItems()) 217 fullListIndex = FullListCountItems(); 218 219 if (!fFullList.AddItem(item, fullListIndex)) 220 return false; 221 222 // Check if this item is visible, and if it is, add it to the 223 // other list, too 224 225 if (item->fLevel > 0) { 226 BListItem *super = _SuperitemForIndex(fullListIndex, item->fLevel); 227 if (super == NULL) 228 return true; 229 230 bool hadSubitems = super->fHasSubitems; 231 super->fHasSubitems = true; 232 233 if (!super->IsItemVisible() || !super->IsExpanded()) { 234 item->SetItemVisible(false); 235 return true; 236 } 237 238 if (!hadSubitems) 239 Invalidate(LatchRect(ItemFrame(IndexOf(super)), super->OutlineLevel())); 240 } 241 242 int32 listIndex = _FindPreviousVisibleIndex(fullListIndex); 243 244 if (!BListView::AddItem(item, IndexOf(FullListItemAt(listIndex)) + 1)) { 245 // adding didn't work out, we need to remove it from the main list again 246 fFullList.RemoveItem(fullListIndex); 247 return false; 248 } 249 250 return true; 251 } 252 253 254 bool 255 BOutlineListView::AddList(BList* newItems) 256 { 257 printf("BOutlineListView::AddList Not implemented\n"); 258 return false; 259 } 260 261 262 bool 263 BOutlineListView::AddList(BList* newItems, int32 fullListIndex) 264 { 265 printf("BOutlineListView::AddList Not implemented\n"); 266 return false; 267 } 268 269 270 bool 271 BOutlineListView::RemoveItem(BListItem* item) 272 { 273 return _RemoveItem(item, FullListIndexOf(item)) != NULL; 274 } 275 276 277 BListItem* 278 BOutlineListView::RemoveItem(int32 fullIndex) 279 { 280 return _RemoveItem(FullListItemAt(fullIndex), fullIndex); 281 } 282 283 284 bool 285 BOutlineListView::RemoveItems(int32 fullIndex, int32 count) 286 { 287 if (fullIndex >= FullListCountItems()) 288 fullIndex = -1; 289 if (fullIndex < 0) 290 return false; 291 292 // TODO: very bad for performance!! 293 while (count--) { 294 BOutlineListView::RemoveItem(fullIndex); 295 } 296 297 return true; 298 } 299 300 301 BListItem * 302 BOutlineListView::FullListItemAt(int32 fullListIndex) const 303 { 304 return (BListItem*)fFullList.ItemAt(fullListIndex); 305 } 306 307 308 int32 309 BOutlineListView::FullListIndexOf(BPoint point) const 310 { 311 return BListView::IndexOf(point); 312 } 313 314 315 int32 316 BOutlineListView::FullListIndexOf(BListItem* item) const 317 { 318 return fFullList.IndexOf(item); 319 } 320 321 322 BListItem * 323 BOutlineListView::FullListFirstItem() const 324 { 325 return (BListItem*)fFullList.FirstItem(); 326 } 327 328 329 BListItem * 330 BOutlineListView::FullListLastItem() const 331 { 332 return (BListItem*)fFullList.LastItem(); 333 } 334 335 336 bool 337 BOutlineListView::FullListHasItem(BListItem *item) const 338 { 339 return fFullList.HasItem(item); 340 } 341 342 343 int32 344 BOutlineListView::FullListCountItems() const 345 { 346 return fFullList.CountItems(); 347 } 348 349 350 int32 351 BOutlineListView::FullListCurrentSelection(int32 index) const 352 { 353 int32 i = BListView::CurrentSelection(index); 354 355 BListItem *item = BListView::ItemAt(i); 356 if (item) 357 return fFullList.IndexOf(item); 358 359 return -1; 360 } 361 362 363 void 364 BOutlineListView::MakeEmpty() 365 { 366 fFullList.MakeEmpty(); 367 BListView::MakeEmpty(); 368 } 369 370 371 bool 372 BOutlineListView::FullListIsEmpty() const 373 { 374 return fFullList.IsEmpty(); 375 } 376 377 378 void 379 BOutlineListView::FullListDoForEach(bool(*func)(BListItem* item)) 380 { 381 fFullList.DoForEach(reinterpret_cast<bool (*)(void*)>(func)); 382 } 383 384 385 void 386 BOutlineListView::FullListDoForEach(bool (*func)(BListItem* item, void* arg), 387 void* arg) 388 { 389 fList.DoForEach(reinterpret_cast<bool (*)(void*, void*)>(func), arg); 390 } 391 392 393 BListItem * 394 BOutlineListView::Superitem(const BListItem* item) 395 { 396 int32 index = FullListIndexOf((BListItem*)item); 397 if (index == -1) 398 return NULL; 399 400 return _SuperitemForIndex(index, item->OutlineLevel()); 401 } 402 403 404 void 405 BOutlineListView::Expand(BListItem* item) 406 { 407 if (item->IsExpanded() || !FullListHasItem(item)) 408 return; 409 410 item->fExpanded = true; 411 412 uint32 level = item->fLevel; 413 int32 fullIndex = FullListIndexOf(item); 414 int32 index = IndexOf(item) + 1; 415 int32 count = FullListCountItems() - fullIndex - 1; 416 BListItem** items = (BListItem**)fFullList.Items() + fullIndex + 1; 417 418 BFont font; 419 GetFont(&font); 420 421 while (count-- > 0) { 422 item = items[0]; 423 if (item->fLevel <= level) 424 break; 425 426 if (!item->IsItemVisible()) { 427 // fix selection hints 428 if (index <= fFirstSelected) 429 fFirstSelected++; 430 if (index <= fLastSelected) 431 fLastSelected++; 432 433 fList.AddItem(item, index++); 434 item->Update(this, &font); 435 item->SetItemVisible(true); 436 } 437 438 if (item->HasSubitems() && !item->IsExpanded()) { 439 // Skip hidden children 440 uint32 subLevel = item->fLevel; 441 items++; 442 443 while (--count > 0 && items[0]->fLevel > subLevel) 444 items++; 445 } else 446 items++; 447 } 448 449 _FixupScrollBar(); 450 Invalidate(); 451 } 452 453 454 void 455 BOutlineListView::Collapse(BListItem* item) 456 { 457 if (!item->IsExpanded() || !FullListHasItem(item)) 458 return; 459 460 item->fExpanded = false; 461 462 uint32 level = item->fLevel; 463 int32 fullIndex = FullListIndexOf(item); 464 int32 index = IndexOf(item); 465 int32 max = FullListCountItems() - fullIndex - 1; 466 int32 count = 0; 467 BListItem** items = (BListItem**)fFullList.Items() + fullIndex + 1; 468 469 while (max-- > 0) { 470 item = items[0]; 471 if (item->fLevel <= level) 472 break; 473 474 if (item->IsItemVisible()) { 475 fList.RemoveItem(item); 476 item->SetItemVisible(false); 477 if (item->IsSelected()) 478 item->Deselect(); 479 480 count++; 481 } 482 483 items++; 484 } 485 486 // fix selection hints 487 // TODO: revise for multi selection lists 488 if (index < fFirstSelected) { 489 if (index + count < fFirstSelected) { 490 fFirstSelected -= count; 491 fLastSelected -= count; 492 } else { 493 // select top item 494 //fFirstSelected = fLastSelected = index; 495 //item->Select(); 496 Select(index); 497 } 498 } 499 500 _FixupScrollBar(); 501 Invalidate(); 502 } 503 504 505 bool 506 BOutlineListView::IsExpanded(int32 fullListIndex) 507 { 508 BListItem *item = FullListItemAt(fullListIndex); 509 if (!item) 510 return false; 511 512 return item->IsExpanded(); 513 } 514 515 516 BHandler * 517 BOutlineListView::ResolveSpecifier(BMessage* msg, int32 index, 518 BMessage* specifier, int32 what, const char* property) 519 { 520 return BListView::ResolveSpecifier(msg, index, specifier, what, property); 521 } 522 523 524 status_t 525 BOutlineListView::GetSupportedSuites(BMessage* data) 526 { 527 return BListView::GetSupportedSuites(data); 528 } 529 530 531 status_t 532 BOutlineListView::Perform(perform_code d, void* arg) 533 { 534 return BListView::Perform(d, arg); 535 } 536 537 538 void 539 BOutlineListView::ResizeToPreferred() 540 { 541 BListView::ResizeToPreferred(); 542 } 543 544 545 void 546 BOutlineListView::GetPreferredSize(float* _width, float* _height) 547 { 548 BListView::GetPreferredSize(_width, _height); 549 } 550 551 552 void 553 BOutlineListView::MakeFocus(bool state) 554 { 555 BListView::MakeFocus(state); 556 } 557 558 559 void 560 BOutlineListView::AllAttached() 561 { 562 BListView::AllAttached(); 563 } 564 565 566 void 567 BOutlineListView::AllDetached() 568 { 569 BListView::AllDetached(); 570 } 571 572 573 void 574 BOutlineListView::DetachedFromWindow() 575 { 576 BListView::DetachedFromWindow(); 577 } 578 579 580 void 581 BOutlineListView::FullListSortItems(int (*compareFunc)(const BListItem* a, 582 const BListItem* b)) 583 { 584 SortItemsUnder(NULL, false, compareFunc); 585 } 586 587 588 void 589 BOutlineListView::SortItemsUnder(BListItem* underItem, bool oneLevelOnly, 590 int (*compareFunc)(const BListItem* a, const BListItem* b)) 591 { 592 // This method is quite complicated: basically, it creates a real tree 593 // from the items of the full list, sorts them as needed, and then 594 // populates the entries back into the full and display lists 595 596 int32 firstIndex = FullListIndexOf(underItem) + 1; 597 int32 lastIndex = firstIndex; 598 BList* tree = _BuildTree(underItem, lastIndex); 599 600 _SortTree(tree, oneLevelOnly, compareFunc); 601 602 // Populate to the full list 603 _PopulateTree(tree, fFullList, firstIndex, false); 604 605 if (underItem == NULL || (underItem->IsItemVisible() && underItem->IsExpanded())) { 606 // Populate to BListView's list 607 firstIndex = fList.IndexOf(underItem) + 1; 608 lastIndex = firstIndex; 609 _PopulateTree(tree, fList, lastIndex, true); 610 611 if (fFirstSelected != -1) { 612 // update selection hints 613 fFirstSelected = _CalcFirstSelected(0); 614 fLastSelected = _CalcLastSelected(CountItems()); 615 } 616 617 // only invalidate what may have changed 618 BRect top = ItemFrame(firstIndex); 619 BRect bottom = ItemFrame(lastIndex); 620 BRect update(top.left, top.top, bottom.right, bottom.bottom); 621 Invalidate(update); 622 } 623 624 _DestructTree(tree); 625 } 626 627 628 void 629 BOutlineListView::_PopulateTree(BList* tree, BList& target, 630 int32& firstIndex, bool onlyVisible) 631 { 632 BListItem** items = (BListItem**)target.Items(); 633 int32 count = tree->CountItems(); 634 635 for (int32 index = 0; index < count; index++) { 636 BListItem* item = (BListItem*)tree->ItemAtFast(index); 637 638 items[firstIndex++] = item; 639 640 if (item->HasSubitems() && (!onlyVisible || item->IsExpanded())) 641 _PopulateTree(item->fTemporaryList, target, firstIndex, onlyVisible); 642 } 643 } 644 645 646 void 647 BOutlineListView::_SortTree(BList* tree, bool oneLevelOnly, 648 int (*compareFunc)(const BListItem* a, const BListItem* b)) 649 { 650 // home-brewn quick sort for our compareFunc 651 quick_sort_item_array((BListItem**)tree->Items(), 0, tree->CountItems() - 1, 652 compareFunc); 653 654 if (oneLevelOnly) 655 return; 656 657 for (int32 index = tree->CountItems(); index-- > 0;) { 658 BListItem* item = (BListItem*)tree->ItemAt(index); 659 660 if (item->HasSubitems()) 661 _SortTree(item->fTemporaryList, false, compareFunc); 662 } 663 } 664 665 666 void 667 BOutlineListView::_DestructTree(BList* tree) 668 { 669 for (int32 index = tree->CountItems(); index-- > 0;) { 670 BListItem* item = (BListItem*)tree->ItemAt(index); 671 672 if (item->HasSubitems()) 673 _DestructTree(item->fTemporaryList); 674 } 675 676 delete tree; 677 } 678 679 680 BList* 681 BOutlineListView::_BuildTree(BListItem* underItem, int32& fullIndex) 682 { 683 int32 fullCount = FullListCountItems(); 684 uint32 level = underItem != NULL ? underItem->OutlineLevel() + 1 : 0; 685 BList* list = new BList; 686 if (underItem != NULL) 687 underItem->fTemporaryList = list; 688 689 while (fullIndex < fullCount) { 690 BListItem *item = FullListItemAt(fullIndex); 691 692 // If we jump out of the subtree, break out 693 if (item->fLevel < level) 694 break; 695 696 // If the level matches, put them into the list 697 // (we handle the case of a missing sublevel gracefully) 698 list->AddItem(item); 699 fullIndex++; 700 701 if (item->HasSubitems()) { 702 // we're going deeper 703 _BuildTree(item, fullIndex); 704 } 705 } 706 707 return list; 708 } 709 710 711 int32 712 BOutlineListView::CountItemsUnder(BListItem* underItem, 713 bool oneLevelOnly) const 714 { 715 int32 i = IndexOf(underItem); 716 if (i == -1) 717 return 0; 718 719 int32 count = 0; 720 721 while (i < FullListCountItems()) { 722 BListItem *item = FullListItemAt(i); 723 724 // If we jump out of the subtree, return count 725 if (item->fLevel < underItem->OutlineLevel()) 726 return count; 727 728 // If the level matches, increase count 729 if (!oneLevelOnly || item->fLevel == underItem->OutlineLevel() + 1) 730 count++; 731 732 i++; 733 } 734 735 return count; 736 } 737 738 739 BListItem * 740 BOutlineListView::EachItemUnder(BListItem *underItem, bool oneLevelOnly, 741 BListItem *(*eachFunc)(BListItem* item, void* arg), void* arg) 742 { 743 int32 i = IndexOf(underItem); 744 if (i == -1) 745 return NULL; 746 747 while (i < FullListCountItems()) { 748 BListItem *item = FullListItemAt(i); 749 750 // If we jump out of the subtree, return NULL 751 if (item->fLevel < underItem->OutlineLevel()) 752 return NULL; 753 754 // If the level matches, check the index 755 if (!oneLevelOnly || item->fLevel == underItem->OutlineLevel() + 1) { 756 item = eachFunc(item, arg); 757 if (item != NULL) 758 return item; 759 } 760 761 i++; 762 } 763 764 return NULL; 765 } 766 767 768 BListItem * 769 BOutlineListView::ItemUnderAt(BListItem* underItem, 770 bool oneLevelOnly, int32 index) const 771 { 772 int32 i = IndexOf(underItem); 773 if (i == -1) 774 return NULL; 775 776 while (i < FullListCountItems()) { 777 BListItem *item = FullListItemAt(i); 778 779 // If we jump out of the subtree, return NULL 780 if (item->fLevel < underItem->OutlineLevel()) 781 return NULL; 782 783 // If the level matches, check the index 784 if (!oneLevelOnly || item->fLevel == underItem->OutlineLevel() + 1) { 785 if (index == 0) 786 return item; 787 788 index--; 789 } 790 791 i++; 792 } 793 794 return NULL; 795 } 796 797 798 bool 799 BOutlineListView::DoMiscellaneous(MiscCode code, MiscData* data) 800 { 801 return BListView::DoMiscellaneous(code, data); 802 } 803 804 805 void 806 BOutlineListView::MessageReceived(BMessage* msg) 807 { 808 BListView::MessageReceived(msg); 809 } 810 811 812 void BOutlineListView::_ReservedOutlineListView1() {} 813 void BOutlineListView::_ReservedOutlineListView2() {} 814 void BOutlineListView::_ReservedOutlineListView3() {} 815 void BOutlineListView::_ReservedOutlineListView4() {} 816 817 818 int32 819 BOutlineListView::FullListIndex(int32 index) const 820 { 821 BListItem *item = ItemAt(index); 822 823 if (item == NULL) 824 return -1; 825 826 return FullListIndexOf(item); 827 } 828 829 830 int32 831 BOutlineListView::ListViewIndex(int32 index) const 832 { 833 BListItem *item = ItemAt(index); 834 835 if (item == NULL) 836 return -1; 837 838 return BListView::IndexOf(item); 839 } 840 841 842 void 843 BOutlineListView::ExpandOrCollapse(BListItem *underItem, bool expand) 844 { 845 } 846 847 848 BRect 849 BOutlineListView::LatchRect(BRect itemRect, int32 level) const 850 { 851 return BRect(itemRect.left, itemRect.top, itemRect.left 852 + (level * 10.0f + 15.0f), itemRect.bottom); 853 } 854 855 856 void 857 BOutlineListView::DrawLatch(BRect itemRect, int32 level, bool collapsed, 858 bool highlighted, bool misTracked) 859 { 860 float left = level * 10.0f; 861 862 if (collapsed) { 863 SetHighColor(192, 192, 192); 864 865 FillTriangle(itemRect.LeftTop() + BPoint(left + 4.0f, 2.0f), 866 itemRect.LeftTop() + BPoint(left + 4.0f, 10.0f), 867 itemRect.LeftTop() + BPoint(left + 8.0f, 6.0f)); 868 869 SetHighColor(0, 0, 0); 870 871 StrokeTriangle(itemRect.LeftTop() + BPoint(left + 4.0f, 2.0f), 872 itemRect.LeftTop() + BPoint(left + 4.0f, 10.0f), 873 itemRect.LeftTop() + BPoint(left + 8.0f, 6.0f)); 874 } else { 875 SetHighColor(192, 192, 192); 876 877 FillTriangle(itemRect.LeftTop() + BPoint(left + 2.0f, 4.0f), 878 itemRect.LeftTop() + BPoint(left + 10.0f, 4.0f), 879 itemRect.LeftTop() + BPoint(left + 6.0f, 8.0f)); 880 881 SetHighColor(0, 0, 0); 882 883 StrokeTriangle(itemRect.LeftTop() + BPoint(left + 2.0f, 4.0f), 884 itemRect.LeftTop() + BPoint(left + 10.0f, 4.0f), 885 itemRect.LeftTop() + BPoint(left + 6.0f, 8.0f)); 886 } 887 } 888 889 890 void 891 BOutlineListView::DrawItem(BListItem* item, BRect itemRect, bool complete) 892 { 893 if (item->fHasSubitems) 894 DrawLatch(itemRect, item->fLevel, !item->IsExpanded(), false, false); 895 896 itemRect.left += (item->fLevel) * 10.0f + 15.0f; 897 item->DrawItem(this, itemRect, complete); 898 } 899 900 901 /*! 902 \brief Removes a single item from the list and all of its children. 903 904 Unlike the BeOS version, this one will actually delete the children, too, 905 as there should be no reference left to them. This may cause problems for 906 applications that actually take the misbehaviour of the Be classes into 907 account. 908 */ 909 BListItem * 910 BOutlineListView::_RemoveItem(BListItem* item, int32 fullIndex) 911 { 912 if (item == NULL || fullIndex < 0 || fullIndex >= FullListCountItems()) 913 return NULL; 914 915 uint32 level = item->OutlineLevel(); 916 int32 superIndex; 917 BListItem* super = _SuperitemForIndex(fullIndex, level, &superIndex); 918 919 if (item->IsItemVisible()) { 920 // remove children, too 921 int32 max = FullListCountItems() - fullIndex - 1; 922 BListItem** items = (BListItem**)fFullList.Items() + fullIndex + 1; 923 924 while (max-- > 0) { 925 BListItem* subItem = items[0]; 926 if (subItem->fLevel <= level) 927 break; 928 929 if (subItem->IsItemVisible()) 930 BListView::RemoveItem(subItem); 931 932 fFullList.RemoveItem(fullIndex + 1); 933 934 // TODO: this might be problematic, see comment above 935 delete subItem; 936 } 937 938 BListView::RemoveItem(item); 939 } 940 941 fFullList.RemoveItem(fullIndex); 942 943 if (super != NULL) { 944 // we might need to change the fHasSubitems field of the parent 945 BListItem* child = FullListItemAt(superIndex + 1); 946 if (child == NULL || child->OutlineLevel() <= super->OutlineLevel()) 947 super->fHasSubitems = false; 948 } 949 950 return item; 951 } 952 953 954 BListItem * 955 BOutlineListView::RemoveOne(int32 fullListIndex) 956 { 957 return NULL; 958 } 959 960 961 void 962 BOutlineListView::TrackInLatchItem(void *) 963 { 964 } 965 966 967 void 968 BOutlineListView::TrackOutLatchItem(void *) 969 { 970 } 971 972 973 bool 974 BOutlineListView::OutlineSwapItems(int32 a, int32 b) 975 { 976 return false; 977 } 978 979 980 bool 981 BOutlineListView::OutlineMoveItem(int32 from, int32 to) 982 { 983 return false; 984 } 985 986 987 bool 988 BOutlineListView::OutlineReplaceItem(int32 index, BListItem *item) 989 { 990 return false; 991 } 992 993 994 void 995 BOutlineListView::CommonMoveItems(int32 from, int32 count, int32 to) 996 { 997 } 998 999 1000 /*! 1001 Returns the super item before the item specified by \a fullListIndex 1002 and \a level. 1003 */ 1004 BListItem * 1005 BOutlineListView::_SuperitemForIndex(int32 fullListIndex, int32 level, 1006 int32* _superIndex) 1007 { 1008 BListItem *item; 1009 fullListIndex--; 1010 1011 while (fullListIndex >= 0) { 1012 if ((item = FullListItemAt(fullListIndex))->OutlineLevel() 1013 < (uint32)level) { 1014 if (_superIndex != NULL) 1015 *_superIndex = fullListIndex; 1016 return item; 1017 } 1018 1019 fullListIndex--; 1020 } 1021 1022 return NULL; 1023 } 1024 1025 1026 int32 1027 BOutlineListView::_FindPreviousVisibleIndex(int32 fullListIndex) 1028 { 1029 fullListIndex--; 1030 1031 while (fullListIndex >= 0) { 1032 if (FullListItemAt(fullListIndex)->fVisible) 1033 return fullListIndex; 1034 1035 fullListIndex--; 1036 } 1037 1038 return -1; 1039 } 1040 1041