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