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