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 36using namespace std; 37 38 39status_t 40icon_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 97status_t 98icon_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 149Icon::Icon() 150 : 151 fLarge(NULL), 152 fMini(NULL), 153 fData(NULL), 154 fSize(0) 155{ 156} 157 158 159Icon::Icon(const Icon& source) 160 : 161 fLarge(NULL), 162 fMini(NULL), 163 fData(NULL), 164 fSize(0) 165{ 166 *this = source; 167} 168 169 170Icon::~Icon() 171{ 172 delete fLarge; 173 delete fMini; 174 free(fData); 175} 176 177 178void 179Icon::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 205void 206Icon::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 218void 219Icon::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 245status_t 246Icon::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 260status_t 261Icon::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 277status_t 278Icon::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 292status_t 293Icon::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 316void 317Icon::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 332void 333Icon::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 348void 349Icon::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 365void 366Icon::Unset() 367{ 368 delete fLarge; 369 delete fMini; 370 free(fData); 371 372 fLarge = fMini = NULL; 373 fData = NULL; 374} 375 376 377bool 378Icon::HasData() const 379{ 380 return fData != NULL || fLarge != NULL || fMini != NULL; 381} 382 383 384status_t 385Icon::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 413status_t 414Icon::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 430status_t 431Icon::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 457Icon& 458Icon::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 470void 471Icon::AdoptLarge(BBitmap *large) 472{ 473 delete fLarge; 474 fLarge = large; 475} 476 477 478void 479Icon::AdoptMini(BBitmap *mini) 480{ 481 delete fMini; 482 fMini = mini; 483} 484 485 486void 487Icon::AdoptData(uint8* data, size_t size) 488{ 489 free(fData); 490 fData = data; 491 fSize = size; 492} 493 494 495/*static*/ BBitmap* 496Icon::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 516IconView::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 533IconView::~IconView() 534{ 535 delete fIcon; 536 delete fModificationMessage; 537} 538 539 540void 541IconView::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 556void 557IconView::DetachedFromWindow() 558{ 559 _StopWatching(); 560} 561 562 563void 564IconView::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 685bool 686IconView::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 715BRect 716IconView::BitmapRect() const 717{ 718 return BRect(0, 0, fIconSize - 1, fIconSize - 1); 719} 720 721 722void 723IconView::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 759void 760IconView::GetPreferredSize(float* _width, float* _height) 761{ 762 if (_width) 763 *_width = fIconSize; 764 765 if (_height) 766 *_height = fIconSize; 767} 768 769 770BSize 771IconView::MinSize() 772{ 773 float width, height; 774 GetPreferredSize(&width, &height); 775 return BSize(width, height); 776} 777 778 779BSize 780IconView::PreferredSize() 781{ 782 return MinSize(); 783} 784 785 786BSize 787IconView::MaxSize() 788{ 789 return MinSize(); 790} 791 792 793void 794IconView::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 853void 854IconView::MouseUp(BPoint where) 855{ 856 fTracking = false; 857 fDragging = false; 858 859 if (fDropTarget) { 860 fDropTarget = false; 861 Invalidate(); 862 } 863} 864 865 866void 867IconView::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 923void 924IconView::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 943void 944IconView::MakeFocus(bool focus) 945{ 946 if (focus != IsFocus()) 947 Invalidate(); 948 949 BControl::MakeFocus(focus); 950} 951 952 953void 954IconView::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 970void 971IconView::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 986void 987IconView::SetTo(::Icon* icon) 988{ 989 if (fIconData == icon) 990 return; 991 992 Unset(); 993 994 fIconData = icon; 995 996 Update(); 997} 998 999 1000void 1001IconView::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 1014void 1015IconView::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 1059void 1060IconView::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 1074void 1075IconView::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 1118void 1119IconView::ShowEmptyFrame(bool show) 1120{ 1121 if (show == fShowEmptyFrame) 1122 return; 1123 1124 fShowEmptyFrame = show; 1125 if (fIcon == NULL) 1126 Invalidate(); 1127} 1128 1129 1130status_t 1131IconView::SetTarget(const BMessenger& target) 1132{ 1133 fTarget = target; 1134 return B_OK; 1135} 1136 1137 1138void 1139IconView::SetModificationMessage(BMessage* message) 1140{ 1141 delete fModificationMessage; 1142 fModificationMessage = message; 1143} 1144 1145 1146status_t 1147IconView::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 1157Icon* 1158IconView::Icon() 1159{ 1160 return fIconData; 1161} 1162 1163 1164status_t 1165IconView::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 1175status_t 1176IconView::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 1186void 1187IconView::_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 1231void 1232IconView::_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 1293void 1294IconView::_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 1362void 1363IconView::_RemoveIcon() 1364{ 1365 _SetIcon(NULL, NULL, NULL, 0, true); 1366} 1367 1368 1369void 1370IconView::_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 1388void 1389IconView::_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 1400status_t 1401IconView::SetTarget(BMessenger target) 1402{ 1403 return BControl::SetTarget(target); 1404} 1405 1406 1407status_t 1408IconView::SetTarget(const BHandler* handler, const BLooper* looper = NULL) 1409{ 1410 return BControl::SetTarget(handler, 1411 looper); 1412} 1413 1414#endif 1415 1416