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