1 /* 2 * Copyright 2006-2007, Axel Dörfler, axeld@pinc-software.de. All rights reserved. 3 * Distributed under the terms of the MIT License. 4 */ 5 6 7 #include "IconView.h" 8 #include "MimeTypeListView.h" 9 10 #include <Application.h> 11 #include <AppFileInfo.h> 12 #include <Bitmap.h> 13 #include <Catalog.h> 14 #include <IconEditorProtocol.h> 15 #include <IconUtils.h> 16 #include <Locale.h> 17 #include <MenuItem.h> 18 #include <Mime.h> 19 #include <NodeMonitor.h> 20 #include <PopUpMenu.h> 21 #include <Resources.h> 22 #include <Roster.h> 23 #include <Size.h> 24 25 #include <new> 26 #include <stdlib.h> 27 #include <string.h> 28 29 30 #undef B_TRANSLATION_CONTEXT 31 #define B_TRANSLATION_CONTEXT "Icon View" 32 33 34 using namespace std; 35 36 37 status_t 38 icon_for_type(const BMimeType& type, uint8** _data, size_t* _size, 39 icon_source* _source) 40 { 41 if (_data == NULL || _size == NULL) 42 return B_BAD_VALUE; 43 44 icon_source source = kNoIcon; 45 uint8* data; 46 size_t size; 47 48 if (type.GetIcon(&data, &size) == B_OK) 49 source = kOwnIcon; 50 51 if (source == kNoIcon) { 52 // check for icon from preferred app 53 54 char preferred[B_MIME_TYPE_LENGTH]; 55 if (type.GetPreferredApp(preferred) == B_OK) { 56 BMimeType preferredApp(preferred); 57 58 if (preferredApp.GetIconForType(type.Type(), &data, &size) == B_OK) 59 source = kApplicationIcon; 60 } 61 } 62 63 if (source == kNoIcon) { 64 // check super type for an icon 65 66 BMimeType superType; 67 if (type.GetSupertype(&superType) == B_OK) { 68 if (superType.GetIcon(&data, &size) == B_OK) 69 source = kSupertypeIcon; 70 else { 71 // check the super type's preferred app 72 char preferred[B_MIME_TYPE_LENGTH]; 73 if (superType.GetPreferredApp(preferred) == B_OK) { 74 BMimeType preferredApp(preferred); 75 76 if (preferredApp.GetIconForType(superType.Type(), 77 &data, &size) == B_OK) 78 source = kSupertypeIcon; 79 } 80 } 81 } 82 } 83 84 if (source != kNoIcon) { 85 *_data = data; 86 *_size = size; 87 } // NOTE: else there is no data, so nothing is leaked. 88 if (_source) 89 *_source = source; 90 91 return source != kNoIcon ? B_OK : B_ERROR; 92 } 93 94 95 status_t 96 icon_for_type(const BMimeType& type, BBitmap& bitmap, icon_size size, 97 icon_source* _source) 98 { 99 icon_source source = kNoIcon; 100 101 if (type.GetIcon(&bitmap, size) == B_OK) 102 source = kOwnIcon; 103 104 if (source == kNoIcon) { 105 // check for icon from preferred app 106 107 char preferred[B_MIME_TYPE_LENGTH]; 108 if (type.GetPreferredApp(preferred) == B_OK) { 109 BMimeType preferredApp(preferred); 110 111 if (preferredApp.GetIconForType(type.Type(), &bitmap, size) == B_OK) 112 source = kApplicationIcon; 113 } 114 } 115 116 if (source == kNoIcon) { 117 // check super type for an icon 118 119 BMimeType superType; 120 if (type.GetSupertype(&superType) == B_OK) { 121 if (superType.GetIcon(&bitmap, size) == B_OK) 122 source = kSupertypeIcon; 123 else { 124 // check the super type's preferred app 125 char preferred[B_MIME_TYPE_LENGTH]; 126 if (superType.GetPreferredApp(preferred) == B_OK) { 127 BMimeType preferredApp(preferred); 128 129 if (preferredApp.GetIconForType(superType.Type(), 130 &bitmap, size) == B_OK) 131 source = kSupertypeIcon; 132 } 133 } 134 } 135 } 136 137 if (_source) 138 *_source = source; 139 140 return source != kNoIcon ? B_OK : B_ERROR; 141 } 142 143 144 // #pragma mark - 145 146 147 Icon::Icon() 148 : 149 fLarge(NULL), 150 fMini(NULL), 151 fData(NULL), 152 fSize(0) 153 { 154 } 155 156 157 Icon::Icon(const Icon& source) 158 : 159 fLarge(NULL), 160 fMini(NULL), 161 fData(NULL), 162 fSize(0) 163 { 164 *this = source; 165 } 166 167 168 Icon::~Icon() 169 { 170 delete fLarge; 171 delete fMini; 172 free(fData); 173 } 174 175 176 void 177 Icon::SetTo(const BAppFileInfo& info, const char* type) 178 { 179 Unset(); 180 181 uint8* data; 182 size_t size; 183 if (info.GetIconForType(type, &data, &size) == B_OK) { 184 // we have the vector icon, no need to get the rest 185 AdoptData(data, size); 186 return; 187 } 188 189 BBitmap* icon = AllocateBitmap(B_LARGE_ICON, B_CMAP8); 190 if (icon && info.GetIconForType(type, icon, B_LARGE_ICON) == B_OK) 191 AdoptLarge(icon); 192 else 193 delete icon; 194 195 icon = AllocateBitmap(B_MINI_ICON, B_CMAP8); 196 if (icon && info.GetIconForType(type, icon, B_MINI_ICON) == B_OK) 197 AdoptMini(icon); 198 else 199 delete icon; 200 } 201 202 203 void 204 Icon::SetTo(const entry_ref& ref, const char* type) 205 { 206 Unset(); 207 208 BFile file(&ref, B_READ_ONLY); 209 BAppFileInfo info(&file); 210 if (file.InitCheck() == B_OK 211 && info.InitCheck() == B_OK) 212 SetTo(info, type); 213 } 214 215 216 void 217 Icon::SetTo(const BMimeType& type, icon_source* _source) 218 { 219 Unset(); 220 221 uint8* data; 222 size_t size; 223 if (icon_for_type(type, &data, &size, _source) == B_OK) { 224 // we have the vector icon, no need to get the rest 225 AdoptData(data, size); 226 return; 227 } 228 229 BBitmap* icon = AllocateBitmap(B_LARGE_ICON, B_CMAP8); 230 if (icon && icon_for_type(type, *icon, B_LARGE_ICON, _source) == B_OK) 231 AdoptLarge(icon); 232 else 233 delete icon; 234 235 icon = AllocateBitmap(B_MINI_ICON, B_CMAP8); 236 if (icon && icon_for_type(type, *icon, B_MINI_ICON) == B_OK) 237 AdoptMini(icon); 238 else 239 delete icon; 240 } 241 242 243 status_t 244 Icon::CopyTo(BAppFileInfo& info, const char* type, bool force) const 245 { 246 status_t status = B_OK; 247 248 if (fLarge != NULL || force) 249 status = info.SetIconForType(type, fLarge, B_LARGE_ICON); 250 if (fMini != NULL || force) 251 status = info.SetIconForType(type, fMini, B_MINI_ICON); 252 if (fData != NULL || force) 253 status = info.SetIconForType(type, fData, fSize); 254 return status; 255 } 256 257 258 status_t 259 Icon::CopyTo(const entry_ref& ref, const char* type, bool force) const 260 { 261 BFile file; 262 status_t status = file.SetTo(&ref, B_READ_ONLY); 263 if (status < B_OK) 264 return status; 265 266 BAppFileInfo info(&file); 267 status = info.InitCheck(); 268 if (status < B_OK) 269 return status; 270 271 return CopyTo(info, type, force); 272 } 273 274 275 status_t 276 Icon::CopyTo(BMimeType& type, bool force) const 277 { 278 status_t status = B_OK; 279 280 if (fLarge != NULL || force) 281 status = type.SetIcon(fLarge, B_LARGE_ICON); 282 if (fMini != NULL || force) 283 status = type.SetIcon(fMini, B_MINI_ICON); 284 if (fData != NULL || force) 285 status = type.SetIcon(fData, fSize); 286 return status; 287 } 288 289 290 status_t 291 Icon::CopyTo(BMessage& message) const 292 { 293 status_t status = B_OK; 294 295 if (status == B_OK && fLarge != NULL) { 296 BMessage archive; 297 status = fLarge->Archive(&archive); 298 if (status == B_OK) 299 status = message.AddMessage("icon/large", &archive); 300 } 301 if (status == B_OK && fMini != NULL) { 302 BMessage archive; 303 status = fMini->Archive(&archive); 304 if (status == B_OK) 305 status = message.AddMessage("icon/mini", &archive); 306 } 307 if (status == B_OK && fData != NULL) 308 status = message.AddData("icon", B_VECTOR_ICON_TYPE, fData, fSize); 309 310 return B_OK; 311 } 312 313 314 void 315 Icon::SetLarge(const BBitmap* large) 316 { 317 if (large != NULL) { 318 if (fLarge == NULL) 319 fLarge = new BBitmap(BRect(0, 0, 31, 31), B_CMAP8); 320 321 memcpy(fLarge->Bits(), large->Bits(), min_c(large->BitsLength(), 322 fLarge->BitsLength())); 323 } else { 324 delete fLarge; 325 fLarge = NULL; 326 } 327 } 328 329 330 void 331 Icon::SetMini(const BBitmap* mini) 332 { 333 if (mini != NULL) { 334 if (fMini == NULL) 335 fMini = new BBitmap(BRect(0, 0, 15, 15), B_CMAP8); 336 337 memcpy(fMini->Bits(), mini->Bits(), min_c(mini->BitsLength(), 338 fMini->BitsLength())); 339 } else { 340 delete fMini; 341 fMini = NULL; 342 } 343 } 344 345 346 void 347 Icon::SetData(const uint8* data, size_t size) 348 { 349 free(fData); 350 fData = NULL; 351 352 if (data != NULL) { 353 fData = (uint8*)malloc(size); 354 if (fData != NULL) { 355 fSize = size; 356 //fType = B_VECTOR_ICON_TYPE; 357 memcpy(fData, data, size); 358 } 359 } 360 } 361 362 363 void 364 Icon::Unset() 365 { 366 delete fLarge; 367 delete fMini; 368 free(fData); 369 370 fLarge = fMini = NULL; 371 fData = NULL; 372 } 373 374 375 bool 376 Icon::HasData() const 377 { 378 return fData != NULL || fLarge != NULL || fMini != NULL; 379 } 380 381 382 status_t 383 Icon::GetData(icon_size which, BBitmap** _bitmap) const 384 { 385 BBitmap* source; 386 switch (which) { 387 case B_LARGE_ICON: 388 source = fLarge; 389 break; 390 case B_MINI_ICON: 391 source = fMini; 392 break; 393 default: 394 return B_BAD_VALUE; 395 } 396 397 if (source == NULL) 398 return B_ENTRY_NOT_FOUND; 399 400 BBitmap* bitmap = new (nothrow) BBitmap(source); 401 if (bitmap == NULL || bitmap->InitCheck() != B_OK) { 402 delete bitmap; 403 return B_NO_MEMORY; 404 } 405 406 *_bitmap = bitmap; 407 return B_OK; 408 } 409 410 411 status_t 412 Icon::GetData(uint8** _data, size_t* _size) const 413 { 414 if (fData == NULL) 415 return B_ENTRY_NOT_FOUND; 416 417 uint8* data = (uint8*)malloc(fSize); 418 if (data == NULL) 419 return B_NO_MEMORY; 420 421 memcpy(data, fData, fSize); 422 *_data = data; 423 *_size = fSize; 424 return B_OK; 425 } 426 427 428 status_t 429 Icon::GetIcon(BBitmap* bitmap) const 430 { 431 if (bitmap == NULL) 432 return B_BAD_VALUE; 433 434 if (fData != NULL 435 && BIconUtils::GetVectorIcon(fData, fSize, bitmap) == B_OK) 436 return B_OK; 437 438 int32 width = bitmap->Bounds().IntegerWidth() + 1; 439 440 if (width == B_LARGE_ICON && fLarge != NULL) { 441 bitmap->SetBits(fLarge->Bits(), fLarge->BitsLength(), 0, 442 fLarge->ColorSpace()); 443 return B_OK; 444 } 445 if (width == B_MINI_ICON && fMini != NULL) { 446 bitmap->SetBits(fMini->Bits(), fMini->BitsLength(), 0, 447 fMini->ColorSpace()); 448 return B_OK; 449 } 450 451 return B_ENTRY_NOT_FOUND; 452 } 453 454 455 Icon& 456 Icon::operator=(const Icon& source) 457 { 458 Unset(); 459 460 SetData(source.fData, source.fSize); 461 SetLarge(source.fLarge); 462 SetMini(source.fMini); 463 464 return *this; 465 } 466 467 468 void 469 Icon::AdoptLarge(BBitmap *large) 470 { 471 delete fLarge; 472 fLarge = large; 473 } 474 475 476 void 477 Icon::AdoptMini(BBitmap *mini) 478 { 479 delete fMini; 480 fMini = mini; 481 } 482 483 484 void 485 Icon::AdoptData(uint8* data, size_t size) 486 { 487 free(fData); 488 fData = data; 489 fSize = size; 490 } 491 492 493 /*static*/ BBitmap* 494 Icon::AllocateBitmap(int32 size, int32 space) 495 { 496 int32 kSpace = B_RGBA32; 497 if (space == -1) 498 space = kSpace; 499 500 BBitmap* bitmap = new (nothrow) BBitmap(BRect(0, 0, size - 1, size - 1), 501 (color_space)space); 502 if (bitmap == NULL || bitmap->InitCheck() != B_OK) { 503 delete bitmap; 504 return NULL; 505 } 506 507 return bitmap; 508 } 509 510 511 // #pragma mark - 512 513 514 IconView::IconView(const char* name, uint32 flags) 515 : BControl(name, NULL, NULL, B_WILL_DRAW | flags), 516 fModificationMessage(NULL), 517 fIconSize(B_LARGE_ICON), 518 fIcon(NULL), 519 fHeapIcon(NULL), 520 fHasRef(false), 521 fHasType(false), 522 fIconData(NULL), 523 fTracking(false), 524 fDragging(false), 525 fDropTarget(false), 526 fShowEmptyFrame(true) 527 { 528 } 529 530 531 IconView::~IconView() 532 { 533 delete fIcon; 534 delete fModificationMessage; 535 } 536 537 538 void 539 IconView::AttachedToWindow() 540 { 541 if (Parent()) 542 SetViewColor(Parent()->ViewColor()); 543 else 544 SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR)); 545 546 fTarget = this; 547 548 // SetTo() was already called before we were a valid messenger 549 if (fHasRef || fHasType) 550 _StartWatching(); 551 } 552 553 554 void 555 IconView::DetachedFromWindow() 556 { 557 _StopWatching(); 558 } 559 560 561 void 562 IconView::MessageReceived(BMessage* message) 563 { 564 if (message->WasDropped() && message->ReturnAddress() != BMessenger(this) 565 && AcceptsDrag(message)) { 566 // set icon from message 567 BBitmap* mini = NULL; 568 BBitmap* large = NULL; 569 const uint8* data = NULL; 570 ssize_t size = 0; 571 572 message->FindData("icon", B_VECTOR_ICON_TYPE, (const void**)&data, 573 &size); 574 575 BMessage archive; 576 if (message->FindMessage("icon/large", &archive) == B_OK) 577 large = (BBitmap*)BBitmap::Instantiate(&archive); 578 if (message->FindMessage("icon/mini", &archive) == B_OK) 579 mini = (BBitmap*)BBitmap::Instantiate(&archive); 580 581 if (large != NULL || mini != NULL || (data != NULL && size > 0)) 582 _SetIcon(large, mini, data, size); 583 else { 584 entry_ref ref; 585 if (message->FindRef("refs", &ref) == B_OK) 586 _SetIcon(&ref); 587 } 588 589 delete large; 590 delete mini; 591 592 return; 593 } 594 595 switch (message->what) { 596 case kMsgIconInvoked: 597 case kMsgEditIcon: 598 case kMsgAddIcon: 599 _AddOrEditIcon(); 600 break; 601 case kMsgRemoveIcon: 602 _RemoveIcon(); 603 break; 604 605 case B_NODE_MONITOR: 606 { 607 if (!fHasRef) 608 break; 609 610 int32 opcode; 611 if (message->FindInt32("opcode", &opcode) != B_OK 612 || opcode != B_ATTR_CHANGED) 613 break; 614 615 const char* name; 616 if (message->FindString("attr", &name) != B_OK) 617 break; 618 619 if (!strcmp(name, "BEOS:L:STD_ICON")) 620 Update(); 621 break; 622 } 623 624 case B_META_MIME_CHANGED: 625 { 626 if (!fHasType) 627 break; 628 629 const char* type; 630 int32 which; 631 if (message->FindString("be:type", &type) != B_OK 632 || message->FindInt32("be:which", &which) != B_OK) 633 break; 634 635 if (!strcasecmp(type, fType.Type())) { 636 switch (which) { 637 case B_MIME_TYPE_DELETED: 638 Unset(); 639 break; 640 641 case B_ICON_CHANGED: 642 Update(); 643 break; 644 645 default: 646 break; 647 } 648 } else if (fSource != kOwnIcon 649 && message->FindString("be:extra_type", &type) == B_OK 650 && !strcasecmp(type, fType.Type())) { 651 // this change could still affect our current icon 652 653 if (which == B_MIME_TYPE_DELETED 654 || which == B_PREFERRED_APP_CHANGED 655 || which == B_SUPPORTED_TYPES_CHANGED 656 || which == B_ICON_FOR_TYPE_CHANGED) 657 Update(); 658 } 659 break; 660 } 661 662 case B_ICON_DATA_EDITED: 663 { 664 const uint8* data; 665 ssize_t size; 666 if (message->FindData("icon data", B_VECTOR_ICON_TYPE, 667 (const void**)&data, &size) < B_OK) 668 break; 669 670 _SetIcon(NULL, NULL, data, size); 671 break; 672 } 673 674 default: 675 BControl::MessageReceived(message); 676 break; 677 } 678 } 679 680 681 bool 682 IconView::AcceptsDrag(const BMessage* message) 683 { 684 if (!IsEnabled()) 685 return false; 686 687 type_code type; 688 int32 count; 689 if (message->GetInfo("refs", &type, &count) == B_OK && count == 1 690 && type == B_REF_TYPE) { 691 // if we're bound to an entry, check that no one drops this to us 692 entry_ref ref; 693 if (fHasRef && message->FindRef("refs", &ref) == B_OK && fRef == ref) 694 return false; 695 696 return true; 697 } 698 699 if ((message->GetInfo("icon/large", &type) == B_OK 700 && type == B_MESSAGE_TYPE) 701 || (message->GetInfo("icon", &type) == B_OK 702 && type == B_VECTOR_ICON_TYPE) 703 || (message->GetInfo("icon/mini", &type) == B_OK 704 && type == B_MESSAGE_TYPE)) 705 return true; 706 707 return false; 708 } 709 710 711 BRect 712 IconView::BitmapRect() const 713 { 714 return BRect(0, 0, fIconSize - 1, fIconSize - 1); 715 } 716 717 718 void 719 IconView::Draw(BRect updateRect) 720 { 721 SetDrawingMode(B_OP_ALPHA); 722 723 if (fHeapIcon != NULL) 724 DrawBitmap(fHeapIcon, BitmapRect().LeftTop()); 725 else if (fIcon != NULL) 726 DrawBitmap(fIcon, BitmapRect().LeftTop()); 727 else if (!fDropTarget && fShowEmptyFrame) { 728 // draw frame so that the user knows here is something he 729 // might be able to click on 730 SetHighColor(tint_color(ViewColor(), B_DARKEN_1_TINT)); 731 StrokeRect(BitmapRect()); 732 } 733 734 if (IsFocus()) { 735 // mark this view as a having focus 736 SetHighColor(ui_color(B_KEYBOARD_NAVIGATION_COLOR)); 737 StrokeRect(BitmapRect()); 738 } 739 if (fDropTarget) { 740 // mark this view as a drop target 741 SetHighColor(0, 0, 0); 742 SetPenSize(2); 743 BRect rect = BitmapRect(); 744 // TODO: this is an incompatibility between R5 and Haiku and should be fixed! 745 // (Necessary adjustment differs.) 746 rect.left++; 747 rect.top++; 748 749 StrokeRect(rect); 750 SetPenSize(1); 751 } 752 } 753 754 755 void 756 IconView::GetPreferredSize(float* _width, float* _height) 757 { 758 if (_width) 759 *_width = fIconSize; 760 761 if (_height) 762 *_height = fIconSize; 763 } 764 765 766 BSize 767 IconView::MinSize() 768 { 769 float width, height; 770 GetPreferredSize(&width, &height); 771 return BSize(width, height); 772 } 773 774 775 BSize 776 IconView::PreferredSize() 777 { 778 return MinSize(); 779 } 780 781 782 BSize 783 IconView::MaxSize() 784 { 785 return MinSize(); 786 } 787 788 789 void 790 IconView::MouseDown(BPoint where) 791 { 792 if (!IsEnabled()) 793 return; 794 795 int32 buttons = B_PRIMARY_MOUSE_BUTTON; 796 int32 clicks = 1; 797 if (Looper() != NULL && Looper()->CurrentMessage() != NULL) { 798 if (Looper()->CurrentMessage()->FindInt32("buttons", &buttons) != B_OK) 799 buttons = B_PRIMARY_MOUSE_BUTTON; 800 if (Looper()->CurrentMessage()->FindInt32("clicks", &clicks) != B_OK) 801 clicks = 1; 802 } 803 804 if ((buttons & B_PRIMARY_MOUSE_BUTTON) != 0 805 && BitmapRect().Contains(where)) { 806 if (clicks == 2) { 807 // double click - open Icon-O-Matic 808 Invoke(); 809 } else if (fIcon != NULL) { 810 // start tracking - this icon might be dragged around 811 fDragPoint = where; 812 fTracking = true; 813 } 814 } 815 816 if ((buttons & B_SECONDARY_MOUSE_BUTTON) != 0) { 817 // show context menu 818 819 ConvertToScreen(&where); 820 821 BPopUpMenu* menu = new BPopUpMenu("context"); 822 menu->SetFont(be_plain_font); 823 824 bool hasIcon = fHasType ? fSource == kOwnIcon : fIcon != NULL; 825 if (hasIcon) { 826 menu->AddItem(new BMenuItem( 827 B_TRANSLATE("Edit icon" B_UTF8_ELLIPSIS), 828 new BMessage(kMsgEditIcon))); 829 } else { 830 menu->AddItem(new BMenuItem( 831 B_TRANSLATE("Add icon" B_UTF8_ELLIPSIS), 832 new BMessage(kMsgAddIcon))); 833 } 834 835 BMenuItem* item = new BMenuItem( 836 B_TRANSLATE("Remove icon"), new BMessage(kMsgRemoveIcon)); 837 if (!hasIcon) 838 item->SetEnabled(false); 839 840 menu->AddItem(item); 841 menu->SetTargetForItems(fTarget); 842 843 menu->Go(where, true, false, true); 844 } 845 } 846 847 848 void 849 IconView::MouseUp(BPoint where) 850 { 851 fTracking = false; 852 fDragging = false; 853 854 if (fDropTarget) { 855 fDropTarget = false; 856 Invalidate(); 857 } 858 } 859 860 861 void 862 IconView::MouseMoved(BPoint where, uint32 transit, const BMessage* dragMessage) 863 { 864 if (fTracking && !fDragging && fIcon != NULL 865 && (abs((int32)(where.x - fDragPoint.x)) > 3 866 || abs((int32)(where.y - fDragPoint.y)) > 3)) { 867 // Start drag 868 BMessage message(B_SIMPLE_DATA); 869 870 ::Icon* icon = fIconData; 871 if (fHasRef || fHasType) { 872 icon = new ::Icon; 873 if (fHasRef) 874 icon->SetTo(fRef, fType.Type()); 875 else if (fHasType) 876 icon->SetTo(fType); 877 } 878 879 icon->CopyTo(message); 880 881 if (icon != fIconData) 882 delete icon; 883 884 BBitmap *dragBitmap = new BBitmap(fIcon->Bounds(), B_RGBA32, true); 885 dragBitmap->Lock(); 886 BView *view 887 = new BView(dragBitmap->Bounds(), B_EMPTY_STRING, B_FOLLOW_NONE, 0); 888 dragBitmap->AddChild(view); 889 890 view->SetHighColor(B_TRANSPARENT_COLOR); 891 view->FillRect(dragBitmap->Bounds()); 892 view->SetBlendingMode(B_CONSTANT_ALPHA, B_ALPHA_COMPOSITE); 893 view->SetDrawingMode(B_OP_ALPHA); 894 view->SetHighColor(0, 0, 0, 160); 895 view->DrawBitmap(fIcon); 896 897 view->Sync(); 898 dragBitmap->Unlock(); 899 900 DragMessage(&message, dragBitmap, B_OP_ALPHA, 901 fDragPoint - BitmapRect().LeftTop(), this); 902 fDragging = true; 903 SetMouseEventMask(B_POINTER_EVENTS, B_NO_POINTER_HISTORY); 904 } 905 906 if (dragMessage != NULL && !fDragging && AcceptsDrag(dragMessage)) { 907 bool dropTarget = transit == B_ENTERED_VIEW || transit == B_INSIDE_VIEW; 908 if (dropTarget != fDropTarget) { 909 fDropTarget = dropTarget; 910 Invalidate(); 911 } 912 } else if (fDropTarget) { 913 fDropTarget = false; 914 Invalidate(); 915 } 916 } 917 918 919 void 920 IconView::KeyDown(const char* bytes, int32 numBytes) 921 { 922 if (numBytes == 1) { 923 switch (bytes[0]) { 924 case B_DELETE: 925 case B_BACKSPACE: 926 _RemoveIcon(); 927 return; 928 case B_ENTER: 929 case B_SPACE: 930 Invoke(); 931 return; 932 } 933 } 934 935 BControl::KeyDown(bytes, numBytes); 936 } 937 938 939 void 940 IconView::MakeFocus(bool focus) 941 { 942 if (focus != IsFocus()) 943 Invalidate(); 944 945 BControl::MakeFocus(focus); 946 } 947 948 949 void 950 IconView::SetTo(const entry_ref& ref, const char* fileType) 951 { 952 Unset(); 953 954 fHasRef = true; 955 fRef = ref; 956 if (fileType != NULL) 957 fType.SetTo(fileType); 958 else 959 fType.Unset(); 960 961 _StartWatching(); 962 Update(); 963 } 964 965 966 void 967 IconView::SetTo(const BMimeType& type) 968 { 969 Unset(); 970 971 if (type.Type() == NULL) 972 return; 973 974 fHasType = true; 975 fType.SetTo(type.Type()); 976 977 _StartWatching(); 978 Update(); 979 } 980 981 982 void 983 IconView::SetTo(::Icon* icon) 984 { 985 if (fIconData == icon) 986 return; 987 988 Unset(); 989 990 fIconData = icon; 991 992 Update(); 993 } 994 995 996 void 997 IconView::Unset() 998 { 999 if (fHasRef || fHasType) 1000 _StopWatching(); 1001 1002 fHasRef = false; 1003 fHasType = false; 1004 1005 fType.Unset(); 1006 fIconData = NULL; 1007 } 1008 1009 1010 void 1011 IconView::Update() 1012 { 1013 delete fIcon; 1014 fIcon = NULL; 1015 1016 Invalidate(); 1017 // this will actually trigger a redraw *after* we updated the icon below 1018 1019 BBitmap* icon = NULL; 1020 1021 if (fHasRef) { 1022 BFile file(&fRef, B_READ_ONLY); 1023 if (file.InitCheck() != B_OK) 1024 return; 1025 1026 BAppFileInfo info; 1027 if (info.SetTo(&file) != B_OK) 1028 return; 1029 1030 icon = Icon::AllocateBitmap(fIconSize); 1031 if (icon != NULL && info.GetIconForType(fType.Type(), icon, 1032 (icon_size)fIconSize) != B_OK) { 1033 delete icon; 1034 return; 1035 } 1036 } else if (fHasType) { 1037 icon = Icon::AllocateBitmap(fIconSize); 1038 if (icon != NULL && icon_for_type(fType, *icon, (icon_size)fIconSize, 1039 &fSource) != B_OK) { 1040 delete icon; 1041 return; 1042 } 1043 } else if (fIconData) { 1044 icon = Icon::AllocateBitmap(fIconSize); 1045 if (fIconData->GetIcon(icon) != B_OK) { 1046 delete icon; 1047 icon = NULL; 1048 } 1049 } 1050 1051 fIcon = icon; 1052 } 1053 1054 1055 void 1056 IconView::SetIconSize(int32 size) 1057 { 1058 if (size < B_MINI_ICON) 1059 size = B_MINI_ICON; 1060 if (size > 256) 1061 size = 256; 1062 if (size == fIconSize) 1063 return; 1064 1065 fIconSize = size; 1066 Update(); 1067 } 1068 1069 1070 void 1071 IconView::ShowIconHeap(bool show) 1072 { 1073 if (show == (fHeapIcon != NULL)) 1074 return; 1075 1076 if (show) { 1077 BResources* resources = be_app->AppResources(); 1078 if (resources != NULL) { 1079 const void* data = NULL; 1080 size_t size; 1081 data = resources->LoadResource('VICN', "icon heap", &size); 1082 if (data != NULL) { 1083 // got vector icon data 1084 fHeapIcon = Icon::AllocateBitmap(B_LARGE_ICON, B_RGBA32); 1085 if (BIconUtils::GetVectorIcon((const uint8*)data, 1086 size, fHeapIcon) != B_OK) { 1087 // bad data 1088 delete fHeapIcon; 1089 fHeapIcon = NULL; 1090 data = NULL; 1091 } 1092 } 1093 if (data == NULL) { 1094 // no vector icon or failed to get bitmap 1095 // try bitmap icon 1096 data = resources->LoadResource(B_LARGE_ICON_TYPE, "icon heap", 1097 NULL); 1098 if (data != NULL) { 1099 fHeapIcon = Icon::AllocateBitmap(B_LARGE_ICON, B_CMAP8); 1100 if (fHeapIcon != NULL) { 1101 memcpy(fHeapIcon->Bits(), data, 1102 fHeapIcon->BitsLength()); 1103 } 1104 } 1105 } 1106 } 1107 } else { 1108 delete fHeapIcon; 1109 fHeapIcon = NULL; 1110 } 1111 } 1112 1113 1114 void 1115 IconView::ShowEmptyFrame(bool show) 1116 { 1117 if (show == fShowEmptyFrame) 1118 return; 1119 1120 fShowEmptyFrame = show; 1121 if (fIcon == NULL) 1122 Invalidate(); 1123 } 1124 1125 1126 status_t 1127 IconView::SetTarget(const BMessenger& target) 1128 { 1129 fTarget = target; 1130 return B_OK; 1131 } 1132 1133 1134 void 1135 IconView::SetModificationMessage(BMessage* message) 1136 { 1137 delete fModificationMessage; 1138 fModificationMessage = message; 1139 } 1140 1141 1142 status_t 1143 IconView::Invoke(BMessage* message) 1144 { 1145 if (message == NULL) 1146 fTarget.SendMessage(kMsgIconInvoked); 1147 else 1148 fTarget.SendMessage(message); 1149 return B_OK; 1150 } 1151 1152 1153 Icon* 1154 IconView::Icon() 1155 { 1156 return fIconData; 1157 } 1158 1159 1160 status_t 1161 IconView::GetRef(entry_ref& ref) const 1162 { 1163 if (!fHasRef) 1164 return B_BAD_TYPE; 1165 1166 ref = fRef; 1167 return B_OK; 1168 } 1169 1170 1171 status_t 1172 IconView::GetMimeType(BMimeType& type) const 1173 { 1174 if (!fHasType) 1175 return B_BAD_TYPE; 1176 1177 type.SetTo(fType.Type()); 1178 return B_OK; 1179 } 1180 1181 1182 void 1183 IconView::_AddOrEditIcon() 1184 { 1185 BMessage message; 1186 if (fHasRef && fType.Type() == NULL) { 1187 // in ref mode, Icon-O-Matic can change the icon directly, and 1188 // we'll pick it up via node monitoring 1189 message.what = B_REFS_RECEIVED; 1190 message.AddRef("refs", &fRef); 1191 } else { 1192 // in static or MIME type mode, Icon-O-Matic needs to return the 1193 // buffer it changed once its done 1194 message.what = B_EDIT_ICON_DATA; 1195 message.AddMessenger("reply to", BMessenger(this)); 1196 1197 ::Icon* icon = fIconData; 1198 if (icon == NULL) { 1199 icon = new ::Icon(); 1200 if (fHasRef) 1201 icon->SetTo(fRef, fType.Type()); 1202 else 1203 icon->SetTo(fType); 1204 } 1205 1206 if (icon->HasData()) { 1207 uint8* data; 1208 size_t size; 1209 if (icon->GetData(&data, &size) == B_OK) { 1210 message.AddData("icon data", B_VECTOR_ICON_TYPE, data, size); 1211 free(data); 1212 } 1213 1214 // TODO: somehow figure out how names of objects in the icon 1215 // can be preserved. Maybe in a second (optional) attribute 1216 // where ever a vector icon attribute is present? 1217 } 1218 1219 if (icon != fIconData) 1220 delete icon; 1221 } 1222 1223 be_roster->Launch("application/x-vnd.haiku-icon_o_matic", &message); 1224 } 1225 1226 1227 void 1228 IconView::_SetIcon(BBitmap* large, BBitmap* mini, const uint8* data, 1229 size_t size, bool force) 1230 { 1231 if (fHasRef) { 1232 BFile file(&fRef, B_READ_WRITE); 1233 1234 BAppFileInfo info(&file); 1235 if (info.InitCheck() == B_OK) { 1236 if (large != NULL || force) 1237 info.SetIconForType(fType.Type(), large, B_LARGE_ICON); 1238 if (mini != NULL || force) 1239 info.SetIconForType(fType.Type(), mini, B_MINI_ICON); 1240 if (data != NULL || force) 1241 info.SetIconForType(fType.Type(), data, size); 1242 } 1243 // the icon shown will be updated using node monitoring 1244 } else if (fHasType) { 1245 if (large != NULL || force) 1246 fType.SetIcon(large, B_LARGE_ICON); 1247 if (mini != NULL || force) 1248 fType.SetIcon(mini, B_MINI_ICON); 1249 if (data != NULL || force) 1250 fType.SetIcon(data, size); 1251 // the icon shown will be updated automatically - we're watching 1252 // any changes to the MIME database 1253 } else if (fIconData != NULL) { 1254 if (large != NULL || force) 1255 fIconData->SetLarge(large); 1256 if (mini != NULL || force) 1257 fIconData->SetMini(mini); 1258 if (data != NULL || force) 1259 fIconData->SetData(data, size); 1260 1261 // replace visible icon 1262 if (fIcon == NULL && fIconData->HasData()) 1263 fIcon = Icon::AllocateBitmap(fIconSize); 1264 1265 if (fIconData->GetIcon(fIcon) != B_OK) { 1266 delete fIcon; 1267 fIcon = NULL; 1268 } 1269 Invalidate(); 1270 } 1271 1272 if (fModificationMessage) 1273 Invoke(fModificationMessage); 1274 } 1275 1276 1277 void 1278 IconView::_SetIcon(entry_ref* ref) 1279 { 1280 // retrieve icons from file 1281 BFile file(ref, B_READ_ONLY); 1282 BAppFileInfo info(&file); 1283 if (file.InitCheck() != B_OK || info.InitCheck() != B_OK) 1284 return; 1285 1286 // try vector/PNG icon first 1287 uint8* data = NULL; 1288 size_t size = 0; 1289 if (info.GetIcon(&data, &size) == B_OK) { 1290 _SetIcon(NULL, NULL, data, size); 1291 free(data); 1292 return; 1293 } 1294 1295 // try large/mini icons 1296 bool hasMini = false; 1297 bool hasLarge = false; 1298 1299 BBitmap* large = new BBitmap(BRect(0, 0, 31, 31), B_CMAP8); 1300 if (large->InitCheck() != B_OK) { 1301 delete large; 1302 large = NULL; 1303 } 1304 BBitmap* mini = new BBitmap(BRect(0, 0, 15, 15), B_CMAP8); 1305 if (mini->InitCheck() != B_OK) { 1306 delete mini; 1307 mini = NULL; 1308 } 1309 1310 if (large != NULL && info.GetIcon(large, B_LARGE_ICON) == B_OK) 1311 hasLarge = true; 1312 if (mini != NULL && info.GetIcon(mini, B_MINI_ICON) == B_OK) 1313 hasMini = true; 1314 1315 if (!hasMini && !hasLarge) { 1316 // TODO: don't forget device icons! 1317 1318 // try MIME type icon 1319 char type[B_MIME_TYPE_LENGTH]; 1320 if (info.GetType(type) != B_OK) 1321 return; 1322 1323 BMimeType mimeType(type); 1324 if (icon_for_type(mimeType, &data, &size) != B_OK) { 1325 // only try large/mini icons when there is no vector icon 1326 if (large != NULL 1327 && icon_for_type(mimeType, *large, B_LARGE_ICON) == B_OK) 1328 hasLarge = true; 1329 if (mini != NULL 1330 && icon_for_type(mimeType, *mini, B_MINI_ICON) == B_OK) 1331 hasMini = true; 1332 } 1333 } 1334 1335 if (data != NULL) { 1336 _SetIcon(NULL, NULL, data, size); 1337 free(data); 1338 } else if (hasLarge || hasMini) 1339 _SetIcon(large, mini, NULL, 0); 1340 1341 delete large; 1342 delete mini; 1343 } 1344 1345 1346 void 1347 IconView::_RemoveIcon() 1348 { 1349 _SetIcon(NULL, NULL, NULL, 0, true); 1350 } 1351 1352 1353 void 1354 IconView::_StartWatching() 1355 { 1356 if (Looper() == NULL) { 1357 // we are not a valid messenger yet 1358 return; 1359 } 1360 1361 if (fHasRef) { 1362 BNode node(&fRef); 1363 node_ref nodeRef; 1364 if (node.InitCheck() == B_OK 1365 && node.GetNodeRef(&nodeRef) == B_OK) 1366 watch_node(&nodeRef, B_WATCH_ATTR, this); 1367 } else if (fHasType) 1368 BMimeType::StartWatching(this); 1369 } 1370 1371 1372 void 1373 IconView::_StopWatching() 1374 { 1375 if (fHasRef) 1376 stop_watching(this); 1377 else if (fHasType) 1378 BMimeType::StopWatching(this); 1379 } 1380 1381 1382 #if __GNUC__ == 2 1383 1384 status_t 1385 IconView::SetTarget(BMessenger target) 1386 { 1387 return BControl::SetTarget(target); 1388 } 1389 1390 1391 status_t 1392 IconView::SetTarget(const BHandler* handler, const BLooper* looper = NULL) 1393 { 1394 return BControl::SetTarget(handler, 1395 looper); 1396 } 1397 1398 #endif 1399 1400