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