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 void 645 BOutlineListView::_PopulateTree(BList* tree, BList& target, 646 int32& firstIndex, bool onlyVisible) 647 { 648 BListItem** items = (BListItem**)target.Items(); 649 int32 count = tree->CountItems(); 650 651 for (int32 index = 0; index < count; index++) { 652 BListItem* item = (BListItem*)tree->ItemAtFast(index); 653 654 items[firstIndex++] = item; 655 656 if (item->HasSubitems() && (!onlyVisible || item->IsExpanded())) 657 _PopulateTree(item->fTemporaryList, target, firstIndex, onlyVisible); 658 } 659 } 660 661 662 void 663 BOutlineListView::_SortTree(BList* tree, bool oneLevelOnly, 664 int (*compareFunc)(const BListItem* a, const BListItem* b)) 665 { 666 // home-brewn quick sort for our compareFunc 667 quick_sort_item_array((BListItem**)tree->Items(), 0, tree->CountItems() - 1, 668 compareFunc); 669 670 if (oneLevelOnly) 671 return; 672 673 for (int32 index = tree->CountItems(); index-- > 0;) { 674 BListItem* item = (BListItem*)tree->ItemAt(index); 675 676 if (item->HasSubitems()) 677 _SortTree(item->fTemporaryList, false, compareFunc); 678 } 679 } 680 681 682 void 683 BOutlineListView::_DestructTree(BList* tree) 684 { 685 for (int32 index = tree->CountItems(); index-- > 0;) { 686 BListItem* item = (BListItem*)tree->ItemAt(index); 687 688 if (item->HasSubitems()) 689 _DestructTree(item->fTemporaryList); 690 } 691 692 delete tree; 693 } 694 695 696 BList* 697 BOutlineListView::_BuildTree(BListItem* underItem, int32& fullIndex) 698 { 699 int32 fullCount = FullListCountItems(); 700 uint32 level = underItem != NULL ? underItem->OutlineLevel() + 1 : 0; 701 BList* list = new BList; 702 if (underItem != NULL) 703 underItem->fTemporaryList = list; 704 705 while (fullIndex < fullCount) { 706 BListItem *item = FullListItemAt(fullIndex); 707 708 // If we jump out of the subtree, break out 709 if (item->fLevel < level) 710 break; 711 712 // If the level matches, put them into the list 713 // (we handle the case of a missing sublevel gracefully) 714 list->AddItem(item); 715 fullIndex++; 716 717 if (item->HasSubitems()) { 718 // we're going deeper 719 _BuildTree(item, fullIndex); 720 } 721 } 722 723 return list; 724 } 725 726 727 int32 728 BOutlineListView::CountItemsUnder(BListItem* underItem, 729 bool oneLevelOnly) const 730 { 731 int32 i = IndexOf(underItem); 732 if (i == -1) 733 return 0; 734 735 int32 count = 0; 736 737 while (i < FullListCountItems()) { 738 BListItem *item = FullListItemAt(i); 739 740 // If we jump out of the subtree, return count 741 if (item->fLevel < underItem->OutlineLevel()) 742 return count; 743 744 // If the level matches, increase count 745 if (!oneLevelOnly || item->fLevel == underItem->OutlineLevel() + 1) 746 count++; 747 748 i++; 749 } 750 751 return count; 752 } 753 754 755 BListItem * 756 BOutlineListView::EachItemUnder(BListItem *underItem, bool oneLevelOnly, 757 BListItem *(*eachFunc)(BListItem* item, void* arg), void* arg) 758 { 759 int32 i = IndexOf(underItem); 760 if (i == -1) 761 return NULL; 762 763 while (i < FullListCountItems()) { 764 BListItem *item = FullListItemAt(i); 765 766 // If we jump out of the subtree, return NULL 767 if (item->fLevel < underItem->OutlineLevel()) 768 return NULL; 769 770 // If the level matches, check the index 771 if (!oneLevelOnly || item->fLevel == underItem->OutlineLevel() + 1) { 772 item = eachFunc(item, arg); 773 if (item != NULL) 774 return item; 775 } 776 777 i++; 778 } 779 780 return NULL; 781 } 782 783 784 BListItem * 785 BOutlineListView::ItemUnderAt(BListItem* underItem, 786 bool oneLevelOnly, int32 index) const 787 { 788 int32 i = IndexOf(underItem); 789 if (i == -1) 790 return NULL; 791 792 while (i < FullListCountItems()) { 793 BListItem *item = FullListItemAt(i); 794 795 // If we jump out of the subtree, return NULL 796 if (item->fLevel < underItem->OutlineLevel()) 797 return NULL; 798 799 // If the level matches, check the index 800 if (!oneLevelOnly || item->fLevel == underItem->OutlineLevel() + 1) { 801 if (index == 0) 802 return item; 803 804 index--; 805 } 806 807 i++; 808 } 809 810 return NULL; 811 } 812 813 int32 814 BOutlineListView::_GetSubitemCount(BList &list, int32 itemIndex) 815 { 816 uint32 level = ((BListItem *)list.ItemAt(itemIndex))->OutlineLevel(); 817 int32 count = 1; // the count we return includes the parent 818 for (int32 i = itemIndex + 1; i < fFullList.CountItems(); i++, count++) { 819 if (((BListItem *)list.ItemAt(i))->OutlineLevel() <= level) 820 break; 821 } 822 823 return count; 824 } 825 826 void 827 BOutlineListView::_DoSwap(BList &list, int32 firstIndex, int32 secondIndex, int32 firstCount, 828 int32 secondCount, int32 swapCount) 829 { 830 if (firstCount < secondCount) { 831 for (int32 i = swapCount + 1; i < secondCount; i++) 832 list.MoveItem(secondIndex + swapCount + i, firstIndex + i); 833 } else { 834 for (int32 i = swapCount + 1; i < firstCount; i++) 835 list.MoveItem(firstIndex + swapCount + 1, secondIndex + swapCount + 1); 836 } 837 } 838 839 bool 840 BOutlineListView::_SwapItems(int32 first, int32 second) 841 { 842 // same item, do nothing 843 if (first == second) 844 return true; 845 846 // fail, first item out of bounds 847 if ((first < 0) || (first >= CountItems())) 848 return false; 849 850 // fail, second item out of bounds 851 if ((second < 0) || (second >= CountItems())) 852 return false; 853 854 int32 firstIndex = min_c(first, second); 855 int32 secondIndex = max_c(first, second); 856 BListItem *firstItem = ItemAt(firstIndex); 857 BListItem *secondItem = ItemAt(secondIndex); 858 859 if (Superitem(firstItem) != Superitem(secondItem)) 860 return false; 861 862 if (!firstItem->IsItemVisible() || !secondItem->IsItemVisible()) 863 return false; 864 865 int32 fullFirstIndex = FullListIndex(firstIndex); 866 int32 fullSecondIndex = FullListIndex(secondIndex); 867 int32 firstCount = _GetSubitemCount(fFullList, fullFirstIndex); 868 int32 secondCount = _GetSubitemCount(fFullList, fullSecondIndex); 869 870 int32 index = (firstCount < secondCount) ? firstCount : secondCount; 871 for (int32 i = 0; i < index; i++) 872 fFullList.SwapItems(fullFirstIndex + i, fullSecondIndex + i); 873 _DoSwap(fFullList, fullFirstIndex, fullSecondIndex, firstCount, secondCount, index); 874 875 firstCount = _GetSubitemCount(fList, firstIndex); 876 secondCount = _GetSubitemCount(fList, secondIndex); 877 index = (firstCount < secondCount) ? firstCount : secondCount; 878 for (int32 i = 0; i < index; i++) 879 fList.SwapItems(firstIndex + i, secondIndex + i); 880 _DoSwap(fList, firstIndex, secondIndex, firstCount, secondCount, index); 881 882 _RecalcItemTops(firstIndex); 883 _RescanSelection(firstIndex, secondIndex + secondCount); 884 Invalidate(Bounds()); 885 return true; 886 } 887 888 bool 889 BOutlineListView::DoMiscellaneous(MiscCode code, MiscData* data) 890 { 891 if (code == B_SWAP_OP) 892 return _SwapItems(data->swap.a, data->swap.b); 893 894 return BListView::DoMiscellaneous(code, data); 895 } 896 897 898 void 899 BOutlineListView::MessageReceived(BMessage* msg) 900 { 901 BListView::MessageReceived(msg); 902 } 903 904 905 void BOutlineListView::_ReservedOutlineListView1() {} 906 void BOutlineListView::_ReservedOutlineListView2() {} 907 void BOutlineListView::_ReservedOutlineListView3() {} 908 void BOutlineListView::_ReservedOutlineListView4() {} 909 910 911 int32 912 BOutlineListView::FullListIndex(int32 index) const 913 { 914 BListItem *item = ItemAt(index); 915 916 if (item == NULL) 917 return -1; 918 919 return FullListIndexOf(item); 920 } 921 922 923 int32 924 BOutlineListView::ListViewIndex(int32 index) const 925 { 926 BListItem *item = ItemAt(index); 927 928 if (item == NULL) 929 return -1; 930 931 return BListView::IndexOf(item); 932 } 933 934 935 void 936 BOutlineListView::ExpandOrCollapse(BListItem *underItem, bool expand) 937 { 938 } 939 940 941 BRect 942 BOutlineListView::LatchRect(BRect itemRect, int32 level) const 943 { 944 return BRect(itemRect.left, itemRect.top, itemRect.left 945 + (level * 10.0f + 15.0f), itemRect.bottom); 946 } 947 948 949 void 950 BOutlineListView::DrawLatch(BRect itemRect, int32 level, bool collapsed, 951 bool highlighted, bool misTracked) 952 { 953 float left = level * 10.0f; 954 955 if (collapsed) { 956 SetHighColor(192, 192, 192); 957 958 FillTriangle(itemRect.LeftTop() + BPoint(left + 4.0f, 2.0f), 959 itemRect.LeftTop() + BPoint(left + 4.0f, 10.0f), 960 itemRect.LeftTop() + BPoint(left + 8.0f, 6.0f)); 961 962 SetHighColor(0, 0, 0); 963 964 StrokeTriangle(itemRect.LeftTop() + BPoint(left + 4.0f, 2.0f), 965 itemRect.LeftTop() + BPoint(left + 4.0f, 10.0f), 966 itemRect.LeftTop() + BPoint(left + 8.0f, 6.0f)); 967 } else { 968 SetHighColor(192, 192, 192); 969 970 FillTriangle(itemRect.LeftTop() + BPoint(left + 2.0f, 4.0f), 971 itemRect.LeftTop() + BPoint(left + 10.0f, 4.0f), 972 itemRect.LeftTop() + BPoint(left + 6.0f, 8.0f)); 973 974 SetHighColor(0, 0, 0); 975 976 StrokeTriangle(itemRect.LeftTop() + BPoint(left + 2.0f, 4.0f), 977 itemRect.LeftTop() + BPoint(left + 10.0f, 4.0f), 978 itemRect.LeftTop() + BPoint(left + 6.0f, 8.0f)); 979 } 980 } 981 982 983 void 984 BOutlineListView::DrawItem(BListItem* item, BRect itemRect, bool complete) 985 { 986 if (item->fHasSubitems) 987 DrawLatch(itemRect, item->fLevel, !item->IsExpanded(), false, false); 988 989 itemRect.left += (item->fLevel) * 10.0f + 15.0f; 990 item->DrawItem(this, itemRect, complete); 991 } 992 993 994 /*! 995 \brief Removes a single item from the list and all of its children. 996 997 Unlike the BeOS version, this one will actually delete the children, too, 998 as there should be no reference left to them. This may cause problems for 999 applications that actually take the misbehaviour of the Be classes into 1000 account. 1001 */ 1002 BListItem * 1003 BOutlineListView::_RemoveItem(BListItem* item, int32 fullIndex) 1004 { 1005 if (item == NULL || fullIndex < 0 || fullIndex >= FullListCountItems()) 1006 return NULL; 1007 1008 uint32 level = item->OutlineLevel(); 1009 int32 superIndex; 1010 BListItem* super = _SuperitemForIndex(fullIndex, level, &superIndex); 1011 1012 if (item->IsItemVisible()) { 1013 // remove children, too 1014 while (fullIndex + 1 < CountItems()) { 1015 BListItem *subItem = ItemAt(fullIndex + 1); 1016 1017 if (subItem->OutlineLevel() <= level) 1018 break; 1019 1020 if (subItem->IsItemVisible()) 1021 BListView::RemoveItem(subItem); 1022 1023 fFullList.RemoveItem(fullIndex + 1); 1024 delete subItem; 1025 } 1026 BListView::RemoveItem(item); 1027 } 1028 1029 fFullList.RemoveItem(fullIndex); 1030 1031 if (super != NULL) { 1032 // we might need to change the fHasSubitems field of the parent 1033 BListItem* child = FullListItemAt(superIndex + 1); 1034 if (child == NULL || child->OutlineLevel() <= super->OutlineLevel()) 1035 super->fHasSubitems = false; 1036 } 1037 return item; 1038 } 1039 1040 1041 BListItem * 1042 BOutlineListView::RemoveOne(int32 fullListIndex) 1043 { 1044 return NULL; 1045 } 1046 1047 1048 void 1049 BOutlineListView::TrackInLatchItem(void *) 1050 { 1051 } 1052 1053 1054 void 1055 BOutlineListView::TrackOutLatchItem(void *) 1056 { 1057 } 1058 1059 1060 bool 1061 BOutlineListView::OutlineSwapItems(int32 a, int32 b) 1062 { 1063 return false; 1064 } 1065 1066 1067 bool 1068 BOutlineListView::OutlineMoveItem(int32 from, int32 to) 1069 { 1070 return false; 1071 } 1072 1073 1074 bool 1075 BOutlineListView::OutlineReplaceItem(int32 index, BListItem *item) 1076 { 1077 return false; 1078 } 1079 1080 1081 void 1082 BOutlineListView::CommonMoveItems(int32 from, int32 count, int32 to) 1083 { 1084 } 1085 1086 1087 /*! 1088 Returns the super item before the item specified by \a fullListIndex 1089 and \a level. 1090 */ 1091 BListItem * 1092 BOutlineListView::_SuperitemForIndex(int32 fullListIndex, int32 level, 1093 int32* _superIndex) 1094 { 1095 BListItem *item; 1096 fullListIndex--; 1097 1098 while (fullListIndex >= 0) { 1099 if ((item = FullListItemAt(fullListIndex))->OutlineLevel() 1100 < (uint32)level) { 1101 if (_superIndex != NULL) 1102 *_superIndex = fullListIndex; 1103 return item; 1104 } 1105 1106 fullListIndex--; 1107 } 1108 1109 return NULL; 1110 } 1111 1112 1113 int32 1114 BOutlineListView::_FindPreviousVisibleIndex(int32 fullListIndex) 1115 { 1116 fullListIndex--; 1117 1118 while (fullListIndex >= 0) { 1119 if (FullListItemAt(fullListIndex)->fVisible) 1120 return fullListIndex; 1121 1122 fullListIndex--; 1123 } 1124 1125 return -1; 1126 } 1127 1128