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