1 //------------------------------------------------------------------------------ 2 // Copyright (c) 2001-2002, OpenBeOS 3 // 4 // Permission is hereby granted, free of charge, to any person obtaining a 5 // copy of this software and associated documentation files (the "Software"), 6 // to deal in the Software without restriction, including without limitation 7 // the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 // and/or sell copies of the Software, and to permit persons to whom the 9 // Software is furnished to do so, subject to the following conditions: 10 // 11 // The above copyright notice and this permission notice shall be included in 12 // all copies or substantial portions of the Software. 13 // 14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 20 // DEALINGS IN THE SOFTWARE. 21 // 22 // File Name: ListView.cpp 23 // Author: Ulrich Wimboeck 24 // Marc Flerackers (mflerackers@androme.be) 25 // Description: BListView represents a one-dimensional list view. 26 //------------------------------------------------------------------------------ 27 28 // Standard Includes ----------------------------------------------------------- 29 30 // System Includes ------------------------------------------------------------- 31 #include <ListView.h> 32 #include <ScrollBar.h> 33 #include <ScrollView.h> 34 #include <support/Errors.h> 35 #include <PropertyInfo.h> 36 #include <Window.h> 37 38 // Project Includes ------------------------------------------------------------ 39 40 // Local Includes -------------------------------------------------------------- 41 42 // Local Defines --------------------------------------------------------------- 43 44 // Globals --------------------------------------------------------------------- 45 static property_info prop_list[] = 46 { 47 { "Item", { B_COUNT_PROPERTIES, 0 }, { B_DIRECT_SPECIFIER, 0 }, 48 "Returns the number of BListItems currently in the list." }, 49 { "Item", { B_EXECUTE_PROPERTY, 0 }, { B_INDEX_SPECIFIER, B_REVERSE_INDEX_SPECIFIER, 50 B_RANGE_SPECIFIER, B_REVERSE_RANGE_SPECIFIER, 0 }, 51 "Select and invoke the specified items, first removing any existing selection." }, 52 { "Selection", { B_COUNT_PROPERTIES, 0 }, { B_DIRECT_SPECIFIER, 0 }, 53 "Returns int32 count of items in the selection." }, 54 { "Selection", { B_EXECUTE_PROPERTY, 0 }, { B_DIRECT_SPECIFIER, 0 }, 55 "Invoke items in selection." }, 56 { "Selection", { B_GET_PROPERTY, 0 }, { B_DIRECT_SPECIFIER, 0 }, 57 "Returns int32 indices of all items in the selection." }, 58 { "Selection", { B_SET_PROPERTY, 0 }, { B_INDEX_SPECIFIER, B_REVERSE_INDEX_SPECIFIER, 59 B_RANGE_SPECIFIER, B_REVERSE_RANGE_SPECIFIER, 0 }, 60 "Extends current selection or deselects specified items. Boolean field \"data\" " 61 "chooses selection or deselection." }, 62 { "Selection", { B_SET_PROPERTY, 0 }, { B_DIRECT_SPECIFIER, 0 }, 63 "Select or deselect all items in the selection. Boolean field \"data\" chooses " 64 "selection or deselection." }, 65 }; 66 67 //------------------------------------------------------------------------------ 68 BListView::BListView(BRect frame, const char *name, list_view_type type, 69 uint32 resizingMode, uint32 flags) 70 : BView(frame, name, resizingMode, flags) 71 { 72 InitObject(type); 73 } 74 //------------------------------------------------------------------------------ 75 BListView::BListView(BMessage *archive) 76 : BView(archive) 77 { 78 int32 listType; 79 80 archive->FindInt32("_lv_type", &listType); 81 fListType = (list_view_type)listType; 82 83 fFirstSelected = -1; 84 fLastSelected = -1; 85 fAnchorIndex = -1; 86 87 fSelectMessage = NULL; 88 fScrollView = NULL; 89 fTrack = NULL; 90 91 fWidth = Bounds().Width(); 92 93 int32 i = 0; 94 BMessage subData; 95 96 while (archive->FindMessage("_l_items", i++, &subData)) 97 { 98 BArchivable *object = instantiate_object(&subData); 99 100 if (!object) 101 continue; 102 103 BListItem *item = dynamic_cast<BListItem*>(object); 104 105 if (!item) 106 continue; 107 108 AddItem(item); 109 } 110 111 if (archive->HasMessage("_msg")) 112 { 113 BMessage *invokationMessage = new BMessage; 114 115 archive->FindMessage("_msg", invokationMessage); 116 SetInvocationMessage(invokationMessage); 117 } 118 119 if (archive->HasMessage("_2nd_msg")) 120 { 121 BMessage *selectionMessage = new BMessage; 122 123 archive->FindMessage("_2nd_msg", selectionMessage); 124 SetSelectionMessage(selectionMessage); 125 } 126 } 127 //------------------------------------------------------------------------------ 128 BListView::~BListView() 129 { 130 SetSelectionMessage(NULL); 131 132 if (fSelectMessage) 133 delete fSelectMessage; 134 } 135 //------------------------------------------------------------------------------ 136 BArchivable *BListView::Instantiate(BMessage *archive) 137 { 138 if (validate_instantiation(archive, "BListView")) 139 return new BListView(archive); 140 else 141 return NULL; 142 } 143 //------------------------------------------------------------------------------ 144 status_t BListView::Archive(BMessage *archive, bool deep) const 145 { 146 BView::Archive ( archive, deep ); 147 148 archive->AddInt32("_lv_type", fListType); 149 150 if (deep) 151 { 152 int32 i = 0; 153 BListItem *item; 154 155 while ((item = ItemAt(i++))) 156 { 157 BMessage subData; 158 159 if (item->Archive(&subData, true) != B_OK) 160 continue; 161 162 archive->AddMessage("_l_items", &subData); 163 } 164 } 165 166 if (InvocationMessage()) 167 archive->AddMessage("_msg", InvocationMessage()); 168 169 if (fSelectMessage) 170 archive->AddMessage("_2nd_msg", fSelectMessage); 171 172 return B_OK; 173 } 174 //------------------------------------------------------------------------------ 175 void BListView::Draw(BRect updateRect) 176 { 177 for (int i = 0; i < CountItems(); i++) 178 { 179 BRect item_frame = ItemFrame(i); 180 181 if (item_frame.Intersects(updateRect)) 182 DrawItem(((BListItem*)ItemAt(i)), item_frame); 183 } 184 } 185 //------------------------------------------------------------------------------ 186 void BListView::MessageReceived ( BMessage *msg ) 187 { 188 switch ( msg->what ) 189 { 190 case B_COUNT_PROPERTIES: 191 case B_EXECUTE_PROPERTY: 192 case B_GET_PROPERTY: 193 case B_SET_PROPERTY: 194 { 195 BPropertyInfo propInfo ( prop_list ); 196 BMessage specifier; 197 const char *property; 198 199 if ( msg->GetCurrentSpecifier ( NULL, &specifier ) != B_OK || 200 specifier.FindString ( "property", &property ) != B_OK ) 201 return; 202 203 switch ( propInfo.FindMatch ( msg, 0, &specifier, msg->what, property ) ) 204 { 205 case B_ERROR: 206 BView::MessageReceived ( msg ); 207 break; 208 209 case 0: 210 { 211 BMessage reply ( B_REPLY ); 212 213 reply.AddInt32 ( "result", CountItems () ); 214 reply.AddInt32 ( "error", B_OK ); 215 216 msg->SendReply ( &reply ); 217 break; 218 } 219 case 1: 220 break; 221 case 2: 222 { 223 BMessage reply ( B_REPLY ); 224 225 int32 count = 0; 226 227 for ( int32 i = 0; i < CountItems (); i++ ) 228 if ( ItemAt ( i )->IsSelected () ) 229 count++; 230 231 reply.AddInt32 ( "result", count ); 232 reply.AddInt32 ( "error", B_OK ); 233 234 msg->SendReply ( &reply ); 235 break; 236 } 237 case 3: 238 break; 239 case 4: 240 { 241 BMessage reply ( B_REPLY ); 242 243 for ( int32 i = 0; i < CountItems (); i++ ) 244 if ( ItemAt ( i )->IsSelected () ) 245 reply.AddInt32 ( "result", i ); 246 247 reply.AddInt32 ( "error", B_OK ); 248 249 msg->SendReply ( &reply ); 250 break; 251 } 252 case 5: 253 break; 254 case 6: 255 { 256 BMessage reply ( B_REPLY ); 257 258 bool select; 259 260 msg->FindBool ( "data", &select ); 261 262 if ( select ) 263 Select ( 0, CountItems () - 1, false ); 264 else 265 DeselectAll (); 266 267 reply.AddInt32 ( "error", B_OK ); 268 269 msg->SendReply ( &reply ); 270 break; 271 } 272 } 273 274 break; 275 } 276 case B_SELECT_ALL: 277 { 278 Select(0, CountItems() - 1, false); 279 break; 280 } 281 default: 282 BView::MessageReceived(msg); 283 } 284 285 286 } 287 //------------------------------------------------------------------------------ 288 void BListView::MouseDown(BPoint point) 289 { 290 if (!IsFocus()) 291 { 292 MakeFocus(); 293 Sync(); 294 Window()->UpdateIfNeeded(); 295 } 296 297 int index = IndexOf(point); 298 299 if (index > -1) 300 { 301 BMessage *message = Looper()->CurrentMessage(); 302 int32 clicks; 303 int32 modifiers; 304 305 message->FindInt32("clicks", &clicks); 306 message->FindInt32("modifiers", &modifiers); 307 308 bool extend = false; 309 310 if (fListType == B_MULTIPLE_SELECTION_LIST && (modifiers & B_CONTROL_KEY)) 311 extend = true; 312 313 if (clicks == 2) 314 { 315 if (!ItemAt(index)->IsSelected()) 316 Select(index, extend); 317 Invoke(); 318 } 319 if (!InitiateDrag(point, index, IsItemSelected(index))) 320 { 321 if (CurrentSelection() == -1 || (!ItemAt(index)->IsSelected() && 322 !(modifiers & B_SHIFT_KEY))) 323 fAnchorIndex = index; 324 325 if (modifiers & B_SHIFT_KEY) 326 Select(fAnchorIndex, index, extend); 327 else 328 { 329 if (!ItemAt(index)->IsSelected()) 330 Select(index, extend); 331 else 332 { 333 ItemAt(index)->Deselect(); 334 InvalidateItem(index); 335 } 336 } 337 } 338 } 339 340 // TODO: InitiateDrag 341 } 342 //------------------------------------------------------------------------------ 343 void BListView::KeyDown(const char *bytes, int32 numBytes) 344 { 345 switch ( bytes[0] ) 346 { 347 case B_UP_ARROW: 348 { 349 if (fFirstSelected == -1) 350 break; 351 352 bool extend = false; 353 354 if (fListType == B_MULTIPLE_SELECTION_LIST && (modifiers() & B_SHIFT_KEY)) 355 extend = true; 356 357 Select (fFirstSelected - 1, extend); 358 359 ScrollToSelection (); 360 361 break; 362 } 363 case B_DOWN_ARROW: 364 { 365 if (fFirstSelected == -1) 366 break; 367 368 bool extend = false; 369 370 if (fListType == B_MULTIPLE_SELECTION_LIST && (modifiers() & B_SHIFT_KEY)) 371 extend = true; 372 373 Select (fLastSelected + 1, extend); 374 375 ScrollToSelection (); 376 377 break; 378 } 379 case B_HOME: 380 { 381 Select ( 0, fListType == B_MULTIPLE_SELECTION_LIST ); 382 383 ScrollToSelection (); 384 385 break; 386 } 387 case B_END: 388 { 389 Select ( CountItems () - 1, fListType == B_MULTIPLE_SELECTION_LIST ); 390 391 ScrollToSelection (); 392 393 break; 394 } 395 case B_RETURN: 396 case B_SPACE: 397 { 398 Invoke (); 399 400 break; 401 } 402 default: 403 BView::KeyDown ( bytes, numBytes ); 404 } 405 } 406 //------------------------------------------------------------------------------ 407 void BListView::MakeFocus(bool focused) 408 { 409 if (IsFocus() == focused) 410 return; 411 412 BView::MakeFocus(focused); 413 414 if (fScrollView) 415 fScrollView->SetBorderHighlighted(focused); 416 } 417 //------------------------------------------------------------------------------ 418 void BListView::FrameResized(float width, float height) 419 { 420 // TODO 421 FixupScrollBar(); 422 } 423 //------------------------------------------------------------------------------ 424 void BListView::TargetedByScrollView(BScrollView *view) 425 { 426 fScrollView = view; 427 } 428 //------------------------------------------------------------------------------ 429 void BListView::ScrollTo(BPoint point) 430 { 431 BView::ScrollTo(point); 432 fWidth = Bounds().right; 433 } 434 //------------------------------------------------------------------------------ 435 bool BListView::AddItem(BListItem *item, int32 index) 436 { 437 if (!fList.AddItem(item, index)) 438 return false; 439 440 if (fFirstSelected != -1 && index < fFirstSelected) 441 fFirstSelected++; 442 443 if (fLastSelected != -1 && index < fLastSelected) 444 fLastSelected++; 445 446 if (Window()) 447 { 448 BFont font; 449 GetFont(&font); 450 451 item->Update(this, &font); 452 453 FixupScrollBar(); 454 InvalidateFrom(index); 455 } 456 457 return true; 458 } 459 //------------------------------------------------------------------------------ 460 bool BListView::AddItem(BListItem *item) 461 { 462 if (!fList.AddItem(item)) 463 return false; 464 465 if (Window()) 466 { 467 BFont font; 468 GetFont(&font); 469 470 item->Update(this, &font); 471 472 FixupScrollBar(); 473 InvalidateItem(CountItems() - 1); 474 } 475 476 return true; 477 } 478 //------------------------------------------------------------------------------ 479 bool BListView::AddList(BList *list, int32 index) 480 { 481 if (!fList.AddList(list, index)) 482 return false; 483 484 int32 count = fList.CountItems(); 485 486 if (fFirstSelected != -1 && index < fFirstSelected) 487 fFirstSelected += count; 488 489 if (fLastSelected != -1 && index < fLastSelected) 490 fLastSelected += count; 491 492 if (Window()) 493 { 494 BFont font; 495 GetFont(&font); 496 497 int32 i = 0; 498 while(BListItem *item = (BListItem*)list->ItemAt(i)) 499 { 500 item->Update(this, &font); 501 i++; 502 } 503 504 FixupScrollBar(); 505 Invalidate(); // TODO 506 } 507 508 return true; 509 } 510 //------------------------------------------------------------------------------ 511 bool BListView::AddList(BList *list) 512 { 513 return AddList(list, CountItems()); 514 } 515 //------------------------------------------------------------------------------ 516 BListItem *BListView::RemoveItem(int32 index) 517 { 518 BListItem *item = ItemAt(index); 519 520 if (!item) 521 return NULL; 522 523 if (item->IsSelected()) 524 Deselect(index); 525 526 if(!fList.RemoveItem(item)) 527 return item; 528 529 if (fFirstSelected != -1 && index < fFirstSelected) 530 fFirstSelected--; 531 532 if (fLastSelected != -1 && index < fLastSelected) 533 fLastSelected--; 534 535 InvalidateFrom(index); 536 FixupScrollBar(); 537 538 return item; 539 } 540 //------------------------------------------------------------------------------ 541 bool BListView::RemoveItem(BListItem *item) 542 { 543 return RemoveItem(IndexOf(item)) != NULL; 544 } 545 //------------------------------------------------------------------------------ 546 bool BListView::RemoveItems(int32 index, int32 count) 547 { 548 if (index >= CountItems()) 549 index = -1; 550 551 if (index < 0) 552 return false; 553 554 while (count--) 555 RemoveItem(index); 556 557 return true; 558 } 559 //------------------------------------------------------------------------------ 560 void BListView::SetSelectionMessage(BMessage *message) 561 { 562 if (fSelectMessage) 563 delete fSelectMessage; 564 565 fSelectMessage = message; 566 } 567 //------------------------------------------------------------------------------ 568 void BListView::SetInvocationMessage(BMessage *message) 569 { 570 BInvoker::SetMessage(message); 571 } 572 //------------------------------------------------------------------------------ 573 BMessage *BListView::InvocationMessage() const 574 { 575 return BInvoker::Message(); 576 } 577 //------------------------------------------------------------------------------ 578 uint32 BListView::InvocationCommand() const 579 { 580 return BInvoker::Command(); 581 } 582 //------------------------------------------------------------------------------ 583 BMessage *BListView::SelectionMessage() const 584 { 585 return fSelectMessage; 586 } 587 //------------------------------------------------------------------------------ 588 uint32 BListView::SelectionCommand() const 589 { 590 if (fSelectMessage) 591 return fSelectMessage->what; 592 else 593 return 0; 594 } 595 //------------------------------------------------------------------------------ 596 void BListView::SetListType(list_view_type type) 597 { 598 if (fListType == B_MULTIPLE_SELECTION_LIST && 599 type == B_SINGLE_SELECTION_LIST) 600 DeselectAll(); 601 602 fListType = type; 603 } 604 //------------------------------------------------------------------------------ 605 list_view_type BListView::ListType() const 606 { 607 return fListType; 608 } 609 //------------------------------------------------------------------------------ 610 BListItem *BListView::ItemAt(int32 index) const 611 { 612 return (BListItem*)fList.ItemAt(index); 613 } 614 //------------------------------------------------------------------------------ 615 int32 BListView::IndexOf(BListItem *item) const 616 { 617 return fList.IndexOf(item); 618 } 619 //------------------------------------------------------------------------------ 620 int32 BListView::IndexOf(BPoint point) const 621 { 622 float y = 0.0f; 623 624 for (int i = 0; i < fList.CountItems(); i++) 625 { 626 y += ItemAt(i)->Height(); 627 628 if ( point.y < y ) 629 return i; 630 } 631 632 return -1; 633 } 634 //------------------------------------------------------------------------------ 635 BListItem *BListView::FirstItem() const 636 { 637 return (BListItem*)fList.FirstItem(); 638 } 639 //------------------------------------------------------------------------------ 640 BListItem *BListView::LastItem() const 641 { 642 return (BListItem*)fList.LastItem(); 643 } 644 //------------------------------------------------------------------------------ 645 bool BListView::HasItem(BListItem *item) const 646 { 647 return fList.HasItem(item); 648 } 649 //------------------------------------------------------------------------------ 650 int32 BListView::CountItems() const 651 { 652 return fList.CountItems(); 653 } 654 //------------------------------------------------------------------------------ 655 void BListView::MakeEmpty() 656 { 657 _DeselectAll(-1, -1); 658 fList.MakeEmpty(); 659 //virtual(&int32[2]) 660 Invalidate(); 661 } 662 //------------------------------------------------------------------------------ 663 bool BListView::IsEmpty() const 664 { 665 return fList.IsEmpty(); 666 } 667 //------------------------------------------------------------------------------ 668 void BListView::DoForEach(bool (*func)(BListItem *)) 669 { 670 fList.DoForEach(reinterpret_cast<bool (*)(void*)>(func)); 671 } 672 //------------------------------------------------------------------------------ 673 void BListView::DoForEach(bool (*func)(BListItem *, void *), void *arg ) 674 { 675 fList.DoForEach(reinterpret_cast<bool (*)(void*, void*)>(func), arg); 676 } 677 //------------------------------------------------------------------------------ 678 const BListItem **BListView::Items() const 679 { 680 return (const BListItem**)fList.Items(); 681 } 682 //------------------------------------------------------------------------------ 683 void BListView::InvalidateItem(int32 index) 684 { 685 Invalidate(Bounds() & ItemFrame(index)); 686 } 687 //------------------------------------------------------------------------------ 688 void BListView::ScrollToSelection () 689 { 690 BRect item_frame = ItemFrame ( CurrentSelection ( 0 ) ); 691 692 if ( Bounds ().Intersects ( item_frame.InsetByCopy ( 0.0f, 2.0f ) ) ) 693 return; 694 695 if ( item_frame.top < Bounds ().top ) 696 ScrollTo ( 0, item_frame.top ); 697 else 698 ScrollTo ( 0, item_frame.bottom - Bounds ().Height () ); 699 } 700 //------------------------------------------------------------------------------ 701 void BListView::Select(int32 index, bool extend) 702 { 703 _Select(index, extend); 704 705 SelectionChanged(); 706 InvokeNotify(fSelectMessage, B_CONTROL_MODIFIED); 707 } 708 //------------------------------------------------------------------------------ 709 void BListView::Select(int32 start, int32 finish, bool extend) 710 { 711 _Select(start, finish, extend); 712 713 SelectionChanged(); 714 InvokeNotify(fSelectMessage, B_CONTROL_MODIFIED); 715 } 716 //------------------------------------------------------------------------------ 717 bool BListView::IsItemSelected(int32 index) const 718 { 719 BListItem *item = ItemAt(index); 720 721 if (item) 722 return item->IsSelected(); 723 else 724 return false; 725 } 726 //------------------------------------------------------------------------------ 727 int32 BListView::CurrentSelection(int32 index) const 728 { 729 if (fFirstSelected == -1) 730 return -1; 731 732 if (index == 0) 733 return fFirstSelected; 734 735 for (int32 i = fFirstSelected; i <= fLastSelected; i++) 736 { 737 if (ItemAt(i)->IsSelected()) 738 { 739 if (index == 0) 740 return i; 741 742 index--; 743 } 744 } 745 746 return -1; 747 } 748 //------------------------------------------------------------------------------ 749 status_t BListView::Invoke(BMessage *message) 750 { 751 bool notify = false; 752 uint32 kind = InvokeKind(¬ify); 753 754 BMessage clone(kind); 755 status_t err = B_BAD_VALUE; 756 757 if (!message && !notify) 758 message = Message(); 759 760 if (!message) 761 { 762 if (!IsWatched()) 763 return err; 764 } 765 else 766 clone = *message; 767 768 clone.AddInt64("when", (int64)system_time()); 769 clone.AddPointer("source", this); 770 clone.AddMessenger("be:sender", BMessenger(this)); 771 772 if (fListType == B_SINGLE_SELECTION_LIST) 773 clone.AddInt32("index", fFirstSelected); 774 else 775 { 776 for (int32 i = fFirstSelected; i <= fLastSelected; i++) 777 { 778 if (ItemAt(i)->IsSelected()) 779 clone.AddInt32("index", i); 780 } 781 } 782 783 if (message) 784 err = BInvoker::Invoke(&clone); 785 786 // TODO: assynchronous messaging 787 // SendNotices(kind, &clone); 788 789 return err; 790 } 791 //------------------------------------------------------------------------------ 792 void BListView::DeselectAll() 793 { 794 if (fFirstSelected == -1) 795 return; 796 797 for (int32 index = fFirstSelected; index <= fLastSelected; ++index) 798 { 799 if (!ItemAt(index)->IsSelected()) 800 { 801 ItemAt(index)->Deselect(); 802 InvalidateItem(index); 803 } 804 } 805 } 806 //------------------------------------------------------------------------------ 807 void BListView::DeselectExcept(int32 start, int32 finish) 808 { 809 if (fFirstSelected == -1 || finish < start) 810 return; 811 812 int32 index; 813 814 for (index = fFirstSelected; index < start; ++index) 815 { 816 if (!ItemAt(index)->IsSelected()) 817 { 818 ItemAt(index)->Deselect(); 819 InvalidateItem(index); 820 } 821 } 822 for (index = finish + 1; index <= fLastSelected; ++index) 823 { 824 if (!ItemAt(index)->IsSelected()) 825 { 826 ItemAt(index)->Deselect(); 827 InvalidateItem(index); 828 } 829 } 830 831 SelectionChanged(); 832 } 833 //------------------------------------------------------------------------------ 834 void BListView::Deselect(int32 index) 835 { 836 if (_Deselect(index)) 837 { 838 SelectionChanged(); 839 InvokeNotify(fSelectMessage, B_CONTROL_MODIFIED); 840 } 841 } 842 //------------------------------------------------------------------------------ 843 void BListView::SelectionChanged() 844 { 845 } 846 //------------------------------------------------------------------------------ 847 void BListView::SortItems(int (*cmp)(const void *, const void *)) 848 { 849 if (_DeselectAll(-1, -1)) 850 { 851 SelectionChanged(); 852 InvokeNotify(fSelectMessage, B_CONTROL_MODIFIED); 853 } 854 855 fList.SortItems(cmp); 856 Invalidate(); 857 } 858 //------------------------------------------------------------------------------ 859 bool BListView::SwapItems(int32 a, int32 b) 860 { 861 MiscData data; 862 863 data.swap.a = a; 864 data.swap.b = b; 865 866 return DoMiscellaneous(B_SWAP_OP, &data); 867 } 868 //------------------------------------------------------------------------------ 869 bool BListView::MoveItem(int32 from, int32 to) 870 { 871 MiscData data; 872 873 data.move.from = from; 874 data.move.to = to; 875 876 return DoMiscellaneous(B_MOVE_OP, &data); 877 } 878 //------------------------------------------------------------------------------ 879 bool BListView::ReplaceItem(int32 index, BListItem *item) 880 { 881 MiscData data; 882 883 data.replace.index = index; 884 data.replace.item = item; 885 886 return DoMiscellaneous(B_REPLACE_OP, &data); 887 } 888 //------------------------------------------------------------------------------ 889 void BListView::AttachedToWindow() 890 { 891 BView::AttachedToWindow(); 892 FontChanged(); 893 894 if (!Messenger().IsValid()) 895 SetTarget(Window(), NULL); 896 897 FixupScrollBar(); 898 } 899 //------------------------------------------------------------------------------ 900 void BListView::FrameMoved(BPoint new_position) 901 { 902 BView::FrameMoved(new_position); 903 } 904 //------------------------------------------------------------------------------ 905 BRect BListView::ItemFrame(int32 index) 906 { 907 BRect frame(0, 0, Bounds().Width(), -1); 908 909 if (index < 0 || index >= CountItems()) 910 return frame; 911 912 for (int32 i = 0; i <= index; i++) 913 { 914 frame.top = frame.bottom + 1; 915 frame.bottom += (float)ceil(ItemAt(i)->Height()); 916 } 917 918 return frame; 919 } 920 //------------------------------------------------------------------------------ 921 BHandler *BListView::ResolveSpecifier(BMessage *msg, int32 index, 922 BMessage *specifier, int32 form, 923 const char *property) 924 { 925 BPropertyInfo propInfo(prop_list); 926 927 if (propInfo.FindMatch(msg, 0, specifier, form, property) < 0) 928 return BView::ResolveSpecifier(msg, index, specifier, form, property); 929 930 // TODO: msg->AddInt32("_match_code_", ); 931 932 return this; 933 } 934 //------------------------------------------------------------------------------ 935 status_t BListView::GetSupportedSuites( BMessage *data ) 936 { 937 data->AddString("suites", "suite/vnd.Be-list-view"); 938 data->AddFlat("messages", &BPropertyInfo(prop_list)); 939 940 return BView::GetSupportedSuites(data); 941 } 942 //------------------------------------------------------------------------------ 943 status_t BListView::Perform(perform_code d, void *arg) 944 { 945 return BView::Perform(d, arg); 946 } 947 //------------------------------------------------------------------------------ 948 void BListView::WindowActivated(bool state) 949 { 950 BView::WindowActivated(state); 951 952 if (IsFocus()) 953 Draw(Bounds()); 954 } 955 //------------------------------------------------------------------------------ 956 void BListView::MouseUp(BPoint pt) 957 { 958 if (fWidth == 0) 959 return; 960 961 DoMouseMoved(pt); 962 DoMouseUp(pt); 963 } 964 //------------------------------------------------------------------------------ 965 void BListView::MouseMoved(BPoint pt, uint32 code, const BMessage *msg) 966 { 967 if (fTrack == NULL) 968 return; 969 970 if (TryInitiateDrag(pt)) 971 return; 972 973 DoMouseMoved(pt); 974 } 975 //------------------------------------------------------------------------------ 976 void BListView::DetachedFromWindow() 977 { 978 BView::DetachedFromWindow(); 979 } 980 //------------------------------------------------------------------------------ 981 bool BListView::InitiateDrag(BPoint point, int32 index, bool wasSelected) 982 { 983 return false; 984 } 985 //------------------------------------------------------------------------------ 986 void BListView::ResizeToPreferred() 987 { 988 BView::ResizeToPreferred(); 989 } 990 //------------------------------------------------------------------------------ 991 void BListView::GetPreferredSize(float *width, float *height) 992 { 993 BView::GetPreferredSize(width, height); 994 } 995 //------------------------------------------------------------------------------ 996 void BListView::AllAttached() 997 { 998 BView::AllAttached(); 999 } 1000 //------------------------------------------------------------------------------ 1001 void BListView::AllDetached() 1002 { 1003 BView::AllDetached(); 1004 } 1005 //------------------------------------------------------------------------------ 1006 bool BListView::DoMiscellaneous(MiscCode code, MiscData *data) 1007 { 1008 if (code > B_SWAP_OP) 1009 return false; 1010 1011 switch (code) 1012 { 1013 case B_NO_OP: 1014 { 1015 break; 1016 } 1017 case B_REPLACE_OP: 1018 { 1019 return ReplaceItem(data->replace.index, data->replace.item); 1020 } 1021 case B_MOVE_OP: 1022 { 1023 return MoveItem(data->move.from, data->move.to); 1024 } 1025 case B_SWAP_OP: 1026 { 1027 return SwapItems(data->swap.a, data->swap.b); 1028 } 1029 } 1030 1031 return false; 1032 } 1033 //------------------------------------------------------------------------------ 1034 void BListView::_ReservedListView2() {} 1035 void BListView::_ReservedListView3() {} 1036 void BListView::_ReservedListView4() {} 1037 //------------------------------------------------------------------------------ 1038 BListView &BListView::operator=(const BListView &) 1039 { 1040 return *this; 1041 } 1042 //------------------------------------------------------------------------------ 1043 void BListView::InitObject(list_view_type type) 1044 { 1045 fListType = type; 1046 fFirstSelected = -1; 1047 fLastSelected = -1; 1048 fAnchorIndex = -1; 1049 fWidth = Bounds().Width(); 1050 fSelectMessage = NULL; 1051 fScrollView = NULL; 1052 fTrack = NULL; 1053 } 1054 //------------------------------------------------------------------------------ 1055 void BListView::FixupScrollBar() 1056 { 1057 BRect bounds, frame; 1058 BScrollBar *vertScroller = ScrollBar(B_VERTICAL); 1059 1060 if (!vertScroller) 1061 return; 1062 1063 bounds = Bounds(); 1064 int32 count = CountItems(); 1065 1066 float y = 0; 1067 1068 for (int32 i = 0; i < count; i++) 1069 { 1070 frame = ItemFrame(i); 1071 y += frame.Height(); 1072 } 1073 1074 if (bounds.Height() > y) 1075 { 1076 vertScroller->SetRange(0.0f, 0.0f); 1077 vertScroller->SetValue(0.0f); 1078 } 1079 else 1080 { 1081 vertScroller->SetRange(0.0f, y - bounds.Height()); 1082 vertScroller->SetProportion(bounds.Height () / y); 1083 } 1084 1085 if (count != 0) 1086 vertScroller->SetSteps((float)ceil(FirstItem()->Height()), 1087 bounds.Height()); 1088 } 1089 //------------------------------------------------------------------------------ 1090 void BListView::InvalidateFrom(int32 index) 1091 { 1092 if (index <= fList.CountItems()) 1093 Invalidate(Bounds() & ItemFrame(index)); 1094 } 1095 //------------------------------------------------------------------------------ 1096 void BListView::FontChanged() 1097 { 1098 BFont font; 1099 GetFont(&font); 1100 1101 for (int i = 0; i < CountItems (); i ++) 1102 ItemAt(i)->Update(this, &font); 1103 } 1104 //------------------------------------------------------------------------------ 1105 bool BListView::_Select(int32 index, bool extend) 1106 { 1107 if (index < 0 || index >= CountItems()) 1108 return false; 1109 1110 if ((fFirstSelected != -1) && (!extend)) 1111 { 1112 for (int32 item = fFirstSelected; item <= fLastSelected; ++item) 1113 { 1114 if ((ItemAt(item)->IsSelected()) && (item != index)) 1115 { 1116 ItemAt(item)->Deselect(); 1117 InvalidateItem(item); 1118 } 1119 } 1120 1121 fFirstSelected = -1; 1122 } 1123 1124 if (fFirstSelected == -1) 1125 { 1126 fFirstSelected = index; 1127 fLastSelected = index; 1128 } 1129 else if (index < fFirstSelected) 1130 fFirstSelected = index; 1131 else if (index > fLastSelected) 1132 fLastSelected = index; 1133 1134 if (!ItemAt(index)->IsSelected()) 1135 { 1136 ItemAt(index)->Select(); 1137 InvalidateItem(index); 1138 } 1139 1140 return true; 1141 } 1142 //------------------------------------------------------------------------------ 1143 bool BListView::_Select(int32 from, int32 to, bool extend) 1144 { 1145 if (to < from) 1146 return false; 1147 1148 if ((fFirstSelected != -1) && (!extend)) 1149 { 1150 for (int32 item = fFirstSelected; item <= fLastSelected; ++item) 1151 { 1152 if ((ItemAt(item)->IsSelected()) && (item < from || item > to)) 1153 { 1154 ItemAt(item)->Deselect(); 1155 InvalidateItem(item); 1156 } 1157 } 1158 1159 fFirstSelected = -1; 1160 } 1161 1162 if (fFirstSelected == -1) 1163 { 1164 fFirstSelected = from; 1165 fLastSelected = to; 1166 } 1167 else if (from < fFirstSelected) 1168 fFirstSelected = from; 1169 else if (to > fLastSelected) 1170 fLastSelected = to; 1171 1172 for (int32 item = from; item <= to; ++item) 1173 { 1174 if (!ItemAt(item)->IsSelected()) 1175 { 1176 ItemAt(item)->Select(); 1177 InvalidateItem(item); 1178 } 1179 } 1180 1181 return true; 1182 } 1183 //------------------------------------------------------------------------------ 1184 bool BListView::_Deselect(int32 index) 1185 { 1186 if (index < 0 || index >= CountItems()) 1187 return false; 1188 1189 if (!Window()->Lock()) 1190 return false; 1191 1192 BListItem *item = ItemAt(index); 1193 1194 if (item->IsSelected()) 1195 { 1196 BRect frame(ItemFrame(index)); 1197 BRect bounds(Bounds()); 1198 1199 item->Deselect(); 1200 1201 if (fFirstSelected == index && fLastSelected == index) 1202 { 1203 fFirstSelected = -1; 1204 fLastSelected = -1; 1205 } 1206 else 1207 { 1208 if (fFirstSelected == index) 1209 fFirstSelected = CalcFirstSelected(index); 1210 1211 if (fLastSelected == index) 1212 fLastSelected = CalcLastSelected(index); 1213 } 1214 1215 if (bounds.Intersects(frame)) 1216 DrawItem(ItemAt(index), frame, true); 1217 } 1218 1219 Window()->Unlock(); 1220 1221 return true; 1222 } 1223 //------------------------------------------------------------------------------ 1224 void BListView::Deselect(int32 from, int32 to) 1225 { 1226 if (from < 0 || from >= CountItems() || to < 0 || to >= CountItems()) 1227 return; 1228 1229 bool changed = false; 1230 1231 for (int32 i = from; i <= to; i++) 1232 { 1233 if (_Deselect(i)) 1234 changed = true; 1235 } 1236 1237 if (changed) 1238 { 1239 SelectionChanged(); 1240 InvokeNotify(fSelectMessage, B_CONTROL_MODIFIED); 1241 } 1242 } 1243 //------------------------------------------------------------------------------ 1244 bool BListView::_DeselectAll(int32 except_from, int32 except_to) 1245 { 1246 if (fFirstSelected == -1) 1247 return true; 1248 1249 return true; 1250 } 1251 //------------------------------------------------------------------------------ 1252 bool BListView::TryInitiateDrag(BPoint where) 1253 { 1254 return false; 1255 } 1256 //------------------------------------------------------------------------------ 1257 int32 BListView::CalcFirstSelected(int32 after) 1258 { 1259 if (after >= CountItems()) 1260 return -1; 1261 1262 for (int32 i = after; i < CountItems(); i++) 1263 { 1264 if (ItemAt(i)->IsSelected()) 1265 return i; 1266 } 1267 1268 return -1; 1269 } 1270 //------------------------------------------------------------------------------ 1271 int32 BListView::CalcLastSelected(int32 before) 1272 { 1273 if (before < 0) 1274 return -1; 1275 1276 for (int32 i = before; i >= 0; i--) 1277 { 1278 if (ItemAt(i)->IsSelected()) 1279 return i; 1280 } 1281 1282 return -1; 1283 } 1284 //------------------------------------------------------------------------------ 1285 void BListView::DrawItem(BListItem *item, BRect itemRect, bool complete) 1286 { 1287 item->DrawItem(this, itemRect, complete); 1288 } 1289 //------------------------------------------------------------------------------ 1290 bool BListView::DoSwapItems(int32 a, int32 b) 1291 { 1292 if (!fList.SwapItems(a, b)) 1293 return false; 1294 1295 Invalidate(ItemFrame(a)); 1296 Invalidate(ItemFrame(b)); 1297 1298 if (fAnchorIndex == a) 1299 fAnchorIndex = b; 1300 else if (fAnchorIndex == b) 1301 fAnchorIndex = a; 1302 1303 RescanSelection(a, b); 1304 1305 return true; 1306 } 1307 //------------------------------------------------------------------------------ 1308 bool BListView::DoMoveItem(int32 from, int32 to) 1309 { 1310 BRect frameFrom = ItemFrame(from); 1311 BRect frameTo = ItemFrame(to); 1312 1313 if (!fList.MoveItem(from, to)) 1314 return false; 1315 1316 RescanSelection(from, to); 1317 1318 BRect frame = frameFrom | frameTo; 1319 1320 if (Bounds().Intersects(frame)) 1321 Invalidate(Bounds() & frame); 1322 1323 return true; 1324 } 1325 //------------------------------------------------------------------------------ 1326 bool BListView::DoReplaceItem(int32 index, BListItem *item) 1327 { 1328 BRect frame = ItemFrame(index); 1329 1330 if (!fList.ReplaceItem(index, item)) 1331 return false; 1332 1333 if (frame != ItemFrame(index)) 1334 InvalidateFrom(index); 1335 else 1336 Invalidate(frame); 1337 1338 return true; 1339 } 1340 //------------------------------------------------------------------------------ 1341 void BListView::RescanSelection(int32 from, int32 to) 1342 { 1343 if (from > to) 1344 { 1345 int32 tmp = from; 1346 from = to; 1347 to = tmp; 1348 } 1349 1350 if (fAnchorIndex != -1) 1351 { 1352 if (fAnchorIndex == from) 1353 fAnchorIndex = to; 1354 else if (fAnchorIndex == to) 1355 fAnchorIndex = from; 1356 } 1357 1358 /* if (from < fFirstSelected && from < fLastSelected) 1359 return; 1360 1361 if (to > fFirstSelected && to > fLastSelected) 1362 return;*/ 1363 1364 int32 i; 1365 1366 for (i = from; i <= to; i++) 1367 { 1368 if (ItemAt(i)->IsSelected()) 1369 { 1370 fFirstSelected = i; 1371 break; 1372 } 1373 } 1374 1375 for (i = from; i <= to; i++) 1376 if (ItemAt(i)->IsSelected()) 1377 fLastSelected = i; 1378 } 1379 //------------------------------------------------------------------------------ 1380 void BListView::DoMouseUp(BPoint where) 1381 { 1382 } 1383 //------------------------------------------------------------------------------ 1384 void BListView::DoMouseMoved(BPoint where) 1385 { 1386 } 1387 //------------------------------------------------------------------------------ 1388 1389 /* 1390 * $Log $ 1391 * 1392 * $Id $ 1393 * 1394 */ 1395