libroot/posix/stdio: Remove unused portions.
[haiku.git] / src / preferences / filetypes / IconView.cpp
blob12bf32e9897b8b75641db3f0ed1b09a6a9005083
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 */
7 #include "IconView.h"
9 #include <new>
10 #include <stdlib.h>
11 #include <strings.h>
13 #include <Application.h>
14 #include <AppFileInfo.h>
15 #include <Attributes.h>
16 #include <Bitmap.h>
17 #include <Catalog.h>
18 #include <IconEditorProtocol.h>
19 #include <IconUtils.h>
20 #include <Locale.h>
21 #include <MenuItem.h>
22 #include <Mime.h>
23 #include <NodeMonitor.h>
24 #include <PopUpMenu.h>
25 #include <Resources.h>
26 #include <Roster.h>
27 #include <Size.h>
29 #include "FileTypes.h"
30 #include "MimeTypeListView.h"
33 #undef B_TRANSLATION_CONTEXT
34 #define B_TRANSLATION_CONTEXT "Icon View"
37 using namespace std;
40 status_t
41 icon_for_type(const BMimeType& type, uint8** _data, size_t* _size,
42 icon_source* _source)
44 if (_data == NULL || _size == NULL)
45 return B_BAD_VALUE;
47 icon_source source = kNoIcon;
48 uint8* data;
49 size_t size;
51 if (type.GetIcon(&data, &size) == B_OK)
52 source = kOwnIcon;
54 if (source == kNoIcon) {
55 // check for icon from preferred app
57 char preferred[B_MIME_TYPE_LENGTH];
58 if (type.GetPreferredApp(preferred) == B_OK) {
59 BMimeType preferredApp(preferred);
61 if (preferredApp.GetIconForType(type.Type(), &data, &size) == B_OK)
62 source = kApplicationIcon;
66 if (source == kNoIcon) {
67 // check super type for an icon
69 BMimeType superType;
70 if (type.GetSupertype(&superType) == B_OK) {
71 if (superType.GetIcon(&data, &size) == B_OK)
72 source = kSupertypeIcon;
73 else {
74 // check the super type's preferred app
75 char preferred[B_MIME_TYPE_LENGTH];
76 if (superType.GetPreferredApp(preferred) == B_OK) {
77 BMimeType preferredApp(preferred);
79 if (preferredApp.GetIconForType(superType.Type(),
80 &data, &size) == B_OK)
81 source = kSupertypeIcon;
87 if (source != kNoIcon) {
88 *_data = data;
89 *_size = size;
90 } // NOTE: else there is no data, so nothing is leaked.
91 if (_source)
92 *_source = source;
94 return source != kNoIcon ? B_OK : B_ERROR;
98 status_t
99 icon_for_type(const BMimeType& type, BBitmap& bitmap, icon_size size,
100 icon_source* _source)
102 icon_source source = kNoIcon;
104 if (type.GetIcon(&bitmap, size) == B_OK)
105 source = kOwnIcon;
107 if (source == kNoIcon) {
108 // check for icon from preferred app
110 char preferred[B_MIME_TYPE_LENGTH];
111 if (type.GetPreferredApp(preferred) == B_OK) {
112 BMimeType preferredApp(preferred);
114 if (preferredApp.GetIconForType(type.Type(), &bitmap, size) == B_OK)
115 source = kApplicationIcon;
119 if (source == kNoIcon) {
120 // check super type for an icon
122 BMimeType superType;
123 if (type.GetSupertype(&superType) == B_OK) {
124 if (superType.GetIcon(&bitmap, size) == B_OK)
125 source = kSupertypeIcon;
126 else {
127 // check the super type's preferred app
128 char preferred[B_MIME_TYPE_LENGTH];
129 if (superType.GetPreferredApp(preferred) == B_OK) {
130 BMimeType preferredApp(preferred);
132 if (preferredApp.GetIconForType(superType.Type(),
133 &bitmap, size) == B_OK)
134 source = kSupertypeIcon;
140 if (_source)
141 *_source = source;
143 return source != kNoIcon ? B_OK : B_ERROR;
147 // #pragma mark -
150 Icon::Icon()
152 fLarge(NULL),
153 fMini(NULL),
154 fData(NULL),
155 fSize(0)
160 Icon::Icon(const Icon& source)
162 fLarge(NULL),
163 fMini(NULL),
164 fData(NULL),
165 fSize(0)
167 *this = source;
171 Icon::~Icon()
173 delete fLarge;
174 delete fMini;
175 free(fData);
179 void
180 Icon::SetTo(const BAppFileInfo& info, const char* type)
182 Unset();
184 uint8* data;
185 size_t size;
187 if (info.GetIconForType(type, &data, &size) == B_OK) {
188 // we have the vector icon, no need to get the rest
189 AdoptData(data, size);
190 return;
193 BBitmap* icon = AllocateBitmap(B_LARGE_ICON, B_CMAP8);
194 if (icon && info.GetIconForType(type, icon, B_LARGE_ICON) == B_OK)
195 AdoptLarge(icon);
196 else
197 delete icon;
199 icon = AllocateBitmap(B_MINI_ICON, B_CMAP8);
200 if (icon && info.GetIconForType(type, icon, B_MINI_ICON) == B_OK)
201 AdoptMini(icon);
202 else
203 delete icon;
207 void
208 Icon::SetTo(const entry_ref& ref, const char* type)
210 Unset();
212 BFile file(&ref, B_READ_ONLY);
213 BAppFileInfo info(&file);
214 if (file.InitCheck() == B_OK
215 && info.InitCheck() == B_OK)
216 SetTo(info, type);
220 void
221 Icon::SetTo(const BMimeType& type, icon_source* _source)
223 Unset();
225 uint8* data;
226 size_t size;
227 if (icon_for_type(type, &data, &size, _source) == B_OK) {
228 // we have the vector icon, no need to get the rest
229 AdoptData(data, size);
230 return;
233 BBitmap* icon = AllocateBitmap(B_LARGE_ICON, B_CMAP8);
234 if (icon && icon_for_type(type, *icon, B_LARGE_ICON, _source) == B_OK)
235 AdoptLarge(icon);
236 else
237 delete icon;
239 icon = AllocateBitmap(B_MINI_ICON, B_CMAP8);
240 if (icon && icon_for_type(type, *icon, B_MINI_ICON) == B_OK)
241 AdoptMini(icon);
242 else
243 delete icon;
247 status_t
248 Icon::CopyTo(BAppFileInfo& info, const char* type, bool force) const
250 status_t status = B_OK;
252 if (fLarge != NULL || force)
253 status = info.SetIconForType(type, fLarge, B_LARGE_ICON);
254 if (fMini != NULL || force)
255 status = info.SetIconForType(type, fMini, B_MINI_ICON);
256 if (fData != NULL || force)
257 status = info.SetIconForType(type, fData, fSize);
259 return status;
263 status_t
264 Icon::CopyTo(const entry_ref& ref, const char* type, bool force) const
266 BFile file;
267 status_t status = file.SetTo(&ref, B_READ_ONLY);
268 if (status < B_OK)
269 return status;
271 BAppFileInfo info(&file);
272 status = info.InitCheck();
273 if (status < B_OK)
274 return status;
276 return CopyTo(info, type, force);
280 status_t
281 Icon::CopyTo(BMimeType& type, bool force) const
283 status_t status = B_OK;
285 if (fLarge != NULL || force)
286 status = type.SetIcon(fLarge, B_LARGE_ICON);
287 if (fMini != NULL || force)
288 status = type.SetIcon(fMini, B_MINI_ICON);
289 if (fData != NULL || force)
290 status = type.SetIcon(fData, fSize);
292 return status;
296 status_t
297 Icon::CopyTo(BMessage& message) const
299 status_t status = B_OK;
301 if (status == B_OK && fLarge != NULL) {
302 BMessage archive;
303 status = fLarge->Archive(&archive);
304 if (status == B_OK)
305 status = message.AddMessage("icon/large", &archive);
307 if (status == B_OK && fMini != NULL) {
308 BMessage archive;
309 status = fMini->Archive(&archive);
310 if (status == B_OK)
311 status = message.AddMessage("icon/mini", &archive);
313 if (status == B_OK && fData != NULL)
314 status = message.AddData("icon", B_VECTOR_ICON_TYPE, fData, fSize);
316 return B_OK;
320 void
321 Icon::SetLarge(const BBitmap* large)
323 if (large != NULL) {
324 if (fLarge == NULL)
325 fLarge = new BBitmap(BRect(0, 0, 31, 31), B_CMAP8);
327 memcpy(fLarge->Bits(), large->Bits(), min_c(large->BitsLength(),
328 fLarge->BitsLength()));
329 } else {
330 delete fLarge;
331 fLarge = NULL;
336 void
337 Icon::SetMini(const BBitmap* mini)
339 if (mini != NULL) {
340 if (fMini == NULL)
341 fMini = new BBitmap(BRect(0, 0, 15, 15), B_CMAP8);
343 memcpy(fMini->Bits(), mini->Bits(), min_c(mini->BitsLength(),
344 fMini->BitsLength()));
345 } else {
346 delete fMini;
347 fMini = NULL;
352 void
353 Icon::SetData(const uint8* data, size_t size)
355 free(fData);
356 fData = NULL;
358 if (data != NULL) {
359 fData = (uint8*)malloc(size);
360 if (fData != NULL) {
361 fSize = size;
362 //fType = B_VECTOR_ICON_TYPE;
363 memcpy(fData, data, size);
369 void
370 Icon::Unset()
372 delete fLarge;
373 delete fMini;
374 free(fData);
376 fLarge = fMini = NULL;
377 fData = NULL;
381 bool
382 Icon::HasData() const
384 return fData != NULL || fLarge != NULL || fMini != NULL;
388 status_t
389 Icon::GetData(icon_size which, BBitmap** _bitmap) const
391 BBitmap* source;
392 switch (which) {
393 case B_LARGE_ICON:
394 source = fLarge;
395 break;
396 case B_MINI_ICON:
397 source = fMini;
398 break;
399 default:
400 return B_BAD_VALUE;
403 if (source == NULL)
404 return B_ENTRY_NOT_FOUND;
406 BBitmap* bitmap = new (nothrow) BBitmap(source);
407 if (bitmap == NULL || bitmap->InitCheck() != B_OK) {
408 delete bitmap;
409 return B_NO_MEMORY;
412 *_bitmap = bitmap;
413 return B_OK;
417 status_t
418 Icon::GetData(uint8** _data, size_t* _size) const
420 if (fData == NULL)
421 return B_ENTRY_NOT_FOUND;
423 uint8* data = (uint8*)malloc(fSize);
424 if (data == NULL)
425 return B_NO_MEMORY;
427 memcpy(data, fData, fSize);
428 *_data = data;
429 *_size = fSize;
430 return B_OK;
434 status_t
435 Icon::GetIcon(BBitmap* bitmap) const
437 if (bitmap == NULL)
438 return B_BAD_VALUE;
440 if (fData != NULL
441 && BIconUtils::GetVectorIcon(fData, fSize, bitmap) == B_OK)
442 return B_OK;
444 int32 width = bitmap->Bounds().IntegerWidth() + 1;
446 if (width == B_LARGE_ICON && fLarge != NULL) {
447 bitmap->SetBits(fLarge->Bits(), fLarge->BitsLength(), 0,
448 fLarge->ColorSpace());
449 return B_OK;
451 if (width == B_MINI_ICON && fMini != NULL) {
452 bitmap->SetBits(fMini->Bits(), fMini->BitsLength(), 0,
453 fMini->ColorSpace());
454 return B_OK;
457 return B_ENTRY_NOT_FOUND;
461 Icon&
462 Icon::operator=(const Icon& source)
464 Unset();
466 SetData(source.fData, source.fSize);
467 SetLarge(source.fLarge);
468 SetMini(source.fMini);
470 return *this;
474 void
475 Icon::AdoptLarge(BBitmap *large)
477 delete fLarge;
478 fLarge = large;
482 void
483 Icon::AdoptMini(BBitmap *mini)
485 delete fMini;
486 fMini = mini;
490 void
491 Icon::AdoptData(uint8* data, size_t size)
493 free(fData);
494 fData = data;
495 fSize = size;
499 /*static*/ BBitmap*
500 Icon::AllocateBitmap(int32 size, int32 space)
502 int32 kSpace = B_RGBA32;
503 if (space == -1)
504 space = kSpace;
506 BBitmap* bitmap = new (nothrow) BBitmap(BRect(0, 0, size - 1, size - 1),
507 (color_space)space);
508 if (bitmap == NULL || bitmap->InitCheck() != B_OK) {
509 delete bitmap;
510 return NULL;
513 return bitmap;
517 // #pragma mark -
520 IconView::IconView(const char* name, uint32 flags)
521 : BControl(name, NULL, NULL, B_WILL_DRAW | flags),
522 fModificationMessage(NULL),
523 fIconSize(B_LARGE_ICON),
524 fIcon(NULL),
525 fHeapIcon(NULL),
526 fHasRef(false),
527 fHasType(false),
528 fIconData(NULL),
529 fTracking(false),
530 fDragging(false),
531 fDropTarget(false),
532 fShowEmptyFrame(true)
537 IconView::~IconView()
539 delete fIcon;
540 delete fModificationMessage;
544 void
545 IconView::AttachedToWindow()
547 AdoptParentColors();
549 fTarget = this;
551 // SetTo() was already called before we were a valid messenger
552 if (fHasRef || fHasType)
553 _StartWatching();
557 void
558 IconView::DetachedFromWindow()
560 _StopWatching();
564 void
565 IconView::MessageReceived(BMessage* message)
567 if (message->WasDropped() && message->ReturnAddress() != BMessenger(this)
568 && AcceptsDrag(message)) {
569 // set icon from message
570 BBitmap* mini = NULL;
571 BBitmap* large = NULL;
572 const uint8* data = NULL;
573 ssize_t size = 0;
575 message->FindData("icon", B_VECTOR_ICON_TYPE, (const void**)&data,
576 &size);
578 BMessage archive;
579 if (message->FindMessage("icon/large", &archive) == B_OK)
580 large = (BBitmap*)BBitmap::Instantiate(&archive);
581 if (message->FindMessage("icon/mini", &archive) == B_OK)
582 mini = (BBitmap*)BBitmap::Instantiate(&archive);
584 if (large != NULL || mini != NULL || (data != NULL && size > 0))
585 _SetIcon(large, mini, data, size);
586 else {
587 entry_ref ref;
588 if (message->FindRef("refs", &ref) == B_OK)
589 _SetIcon(&ref);
592 delete large;
593 delete mini;
595 return;
598 switch (message->what) {
599 case kMsgIconInvoked:
600 case kMsgEditIcon:
601 case kMsgAddIcon:
602 _AddOrEditIcon();
603 break;
604 case kMsgRemoveIcon:
605 _RemoveIcon();
606 break;
608 case B_NODE_MONITOR:
610 if (!fHasRef)
611 break;
613 int32 opcode;
614 if (message->FindInt32("opcode", &opcode) != B_OK
615 || opcode != B_ATTR_CHANGED)
616 break;
618 const char* name;
619 if (message->FindString("attr", &name) != B_OK)
620 break;
622 if (!strcmp(name, kAttrMiniIcon)
623 || !strcmp(name, kAttrLargeIcon)
624 || !strcmp(name, kAttrIcon))
625 Update();
626 break;
629 case B_META_MIME_CHANGED:
631 if (!fHasType)
632 break;
634 const char* type;
635 int32 which;
636 if (message->FindString("be:type", &type) != B_OK
637 || message->FindInt32("be:which", &which) != B_OK)
638 break;
640 if (!strcasecmp(type, fType.Type())) {
641 switch (which) {
642 case B_MIME_TYPE_DELETED:
643 Unset();
644 break;
646 case B_ICON_CHANGED:
647 Update();
648 break;
650 default:
651 break;
653 } else if (fSource != kOwnIcon
654 && message->FindString("be:extra_type", &type) == B_OK
655 && !strcasecmp(type, fType.Type())) {
656 // this change could still affect our current icon
658 if (which == B_MIME_TYPE_DELETED
659 || which == B_PREFERRED_APP_CHANGED
660 || which == B_SUPPORTED_TYPES_CHANGED
661 || which == B_ICON_FOR_TYPE_CHANGED)
662 Update();
664 break;
667 case B_ICON_DATA_EDITED:
669 const uint8* data;
670 ssize_t size;
671 if (message->FindData("icon data", B_VECTOR_ICON_TYPE,
672 (const void**)&data, &size) < B_OK)
673 break;
675 _SetIcon(NULL, NULL, data, size);
676 break;
679 default:
680 BControl::MessageReceived(message);
681 break;
686 bool
687 IconView::AcceptsDrag(const BMessage* message)
689 if (!IsEnabled())
690 return false;
692 type_code type;
693 int32 count;
694 if (message->GetInfo("refs", &type, &count) == B_OK && count == 1
695 && type == B_REF_TYPE) {
696 // if we're bound to an entry, check that no one drops this to us
697 entry_ref ref;
698 if (fHasRef && message->FindRef("refs", &ref) == B_OK && fRef == ref)
699 return false;
701 return true;
704 if ((message->GetInfo("icon/large", &type) == B_OK
705 && type == B_MESSAGE_TYPE)
706 || (message->GetInfo("icon", &type) == B_OK
707 && type == B_VECTOR_ICON_TYPE)
708 || (message->GetInfo("icon/mini", &type) == B_OK
709 && type == B_MESSAGE_TYPE))
710 return true;
712 return false;
716 BRect
717 IconView::BitmapRect() const
719 return BRect(0, 0, fIconSize - 1, fIconSize - 1);
723 void
724 IconView::Draw(BRect updateRect)
726 SetDrawingMode(B_OP_ALPHA);
728 if (fHeapIcon != NULL)
729 DrawBitmap(fHeapIcon, BitmapRect().LeftTop());
730 else if (fIcon != NULL)
731 DrawBitmap(fIcon, BitmapRect().LeftTop());
732 else if (!fDropTarget && fShowEmptyFrame) {
733 // draw frame so that the user knows here is something he
734 // might be able to click on
735 SetHighColor(tint_color(ViewColor(), B_DARKEN_1_TINT));
736 StrokeRect(BitmapRect());
739 if (IsFocus()) {
740 // mark this view as a having focus
741 SetHighColor(ui_color(B_KEYBOARD_NAVIGATION_COLOR));
742 StrokeRect(BitmapRect());
744 if (fDropTarget) {
745 // mark this view as a drop target
746 SetHighColor(0, 0, 0);
747 SetPenSize(2);
748 BRect rect = BitmapRect();
749 // TODO: this is an incompatibility between R5 and Haiku and should be fixed!
750 // (Necessary adjustment differs.)
751 rect.left++;
752 rect.top++;
754 StrokeRect(rect);
755 SetPenSize(1);
760 void
761 IconView::GetPreferredSize(float* _width, float* _height)
763 if (_width)
764 *_width = fIconSize;
766 if (_height)
767 *_height = fIconSize;
771 BSize
772 IconView::MinSize()
774 float width, height;
775 GetPreferredSize(&width, &height);
776 return BSize(width, height);
780 BSize
781 IconView::PreferredSize()
783 return MinSize();
787 BSize
788 IconView::MaxSize()
790 return MinSize();
794 void
795 IconView::MouseDown(BPoint where)
797 if (!IsEnabled())
798 return;
800 int32 buttons = B_PRIMARY_MOUSE_BUTTON;
801 int32 clicks = 1;
802 if (Looper() != NULL && Looper()->CurrentMessage() != NULL) {
803 if (Looper()->CurrentMessage()->FindInt32("buttons", &buttons) != B_OK)
804 buttons = B_PRIMARY_MOUSE_BUTTON;
805 if (Looper()->CurrentMessage()->FindInt32("clicks", &clicks) != B_OK)
806 clicks = 1;
809 if ((buttons & B_PRIMARY_MOUSE_BUTTON) != 0
810 && BitmapRect().Contains(where)) {
811 if (clicks == 2) {
812 // double click - open Icon-O-Matic
813 Invoke();
814 } else if (fIcon != NULL) {
815 // start tracking - this icon might be dragged around
816 fDragPoint = where;
817 fTracking = true;
818 SetMouseEventMask(B_POINTER_EVENTS, B_NO_POINTER_HISTORY);
822 if ((buttons & B_SECONDARY_MOUSE_BUTTON) != 0) {
823 // show context menu
825 ConvertToScreen(&where);
827 BPopUpMenu* menu = new BPopUpMenu("context");
828 menu->SetFont(be_plain_font);
830 bool hasIcon = fHasType ? fSource == kOwnIcon : fIcon != NULL;
831 if (hasIcon) {
832 menu->AddItem(new BMenuItem(
833 B_TRANSLATE("Edit icon" B_UTF8_ELLIPSIS),
834 new BMessage(kMsgEditIcon)));
835 } else {
836 menu->AddItem(new BMenuItem(
837 B_TRANSLATE("Add icon" B_UTF8_ELLIPSIS),
838 new BMessage(kMsgAddIcon)));
841 BMenuItem* item = new BMenuItem(
842 B_TRANSLATE("Remove icon"), new BMessage(kMsgRemoveIcon));
843 if (!hasIcon)
844 item->SetEnabled(false);
846 menu->AddItem(item);
847 menu->SetTargetForItems(fTarget);
849 menu->Go(where, true, false, true);
854 void
855 IconView::MouseUp(BPoint where)
857 fTracking = false;
858 fDragging = false;
860 if (fDropTarget) {
861 fDropTarget = false;
862 Invalidate();
867 void
868 IconView::MouseMoved(BPoint where, uint32 transit, const BMessage* dragMessage)
870 if (fTracking && !fDragging && fIcon != NULL
871 && (abs((int32)(where.x - fDragPoint.x)) > 3
872 || abs((int32)(where.y - fDragPoint.y)) > 3)) {
873 // Start drag
874 BMessage message(B_SIMPLE_DATA);
876 ::Icon* icon = fIconData;
877 if (fHasRef || fHasType) {
878 icon = new ::Icon;
879 if (fHasRef)
880 icon->SetTo(fRef, fType.Type());
881 else if (fHasType)
882 icon->SetTo(fType);
885 icon->CopyTo(message);
887 if (icon != fIconData)
888 delete icon;
890 BBitmap *dragBitmap = new BBitmap(fIcon->Bounds(), B_RGBA32, true);
891 dragBitmap->Lock();
892 BView *view
893 = new BView(dragBitmap->Bounds(), B_EMPTY_STRING, B_FOLLOW_NONE, 0);
894 dragBitmap->AddChild(view);
896 view->SetHighColor(B_TRANSPARENT_COLOR);
897 view->FillRect(dragBitmap->Bounds());
898 view->SetBlendingMode(B_CONSTANT_ALPHA, B_ALPHA_COMPOSITE);
899 view->SetDrawingMode(B_OP_ALPHA);
900 view->SetHighColor(0, 0, 0, 160);
901 view->DrawBitmap(fIcon);
903 view->Sync();
904 dragBitmap->Unlock();
906 DragMessage(&message, dragBitmap, B_OP_ALPHA,
907 fDragPoint - BitmapRect().LeftTop(), this);
908 fDragging = true;
911 if (dragMessage != NULL && !fDragging && AcceptsDrag(dragMessage)) {
912 bool dropTarget = transit == B_ENTERED_VIEW || transit == B_INSIDE_VIEW;
913 if (dropTarget != fDropTarget) {
914 fDropTarget = dropTarget;
915 Invalidate();
917 } else if (fDropTarget) {
918 fDropTarget = false;
919 Invalidate();
924 void
925 IconView::KeyDown(const char* bytes, int32 numBytes)
927 if (numBytes == 1) {
928 switch (bytes[0]) {
929 case B_DELETE:
930 case B_BACKSPACE:
931 _RemoveIcon();
932 return;
933 case B_ENTER:
934 case B_SPACE:
935 Invoke();
936 return;
940 BControl::KeyDown(bytes, numBytes);
944 void
945 IconView::MakeFocus(bool focus)
947 if (focus != IsFocus())
948 Invalidate();
950 BControl::MakeFocus(focus);
954 void
955 IconView::SetTo(const entry_ref& ref, const char* fileType)
957 Unset();
959 fHasRef = true;
960 fRef = ref;
961 if (fileType != NULL)
962 fType.SetTo(fileType);
963 else
964 fType.Unset();
966 _StartWatching();
967 Update();
971 void
972 IconView::SetTo(const BMimeType& type)
974 Unset();
976 if (type.Type() == NULL)
977 return;
979 fHasType = true;
980 fType.SetTo(type.Type());
982 _StartWatching();
983 Update();
987 void
988 IconView::SetTo(::Icon* icon)
990 if (fIconData == icon)
991 return;
993 Unset();
995 fIconData = icon;
997 Update();
1001 void
1002 IconView::Unset()
1004 if (fHasRef || fHasType)
1005 _StopWatching();
1007 fHasRef = false;
1008 fHasType = false;
1010 fType.Unset();
1011 fIconData = NULL;
1015 void
1016 IconView::Update()
1018 delete fIcon;
1019 fIcon = NULL;
1021 Invalidate();
1022 // this will actually trigger a redraw *after* we updated the icon below
1024 BBitmap* icon = NULL;
1026 if (fHasRef) {
1027 BFile file(&fRef, B_READ_ONLY);
1028 if (file.InitCheck() != B_OK)
1029 return;
1031 BNodeInfo info;
1032 if (info.SetTo(&file) != B_OK)
1033 return;
1035 icon = Icon::AllocateBitmap(fIconSize);
1036 if (icon != NULL && info.GetTrackerIcon(icon,
1037 (icon_size)fIconSize) != B_OK) {
1038 delete icon;
1039 return;
1041 } else if (fHasType) {
1042 icon = Icon::AllocateBitmap(fIconSize);
1043 if (icon != NULL && icon_for_type(fType, *icon, (icon_size)fIconSize,
1044 &fSource) != B_OK) {
1045 delete icon;
1046 return;
1048 } else if (fIconData) {
1049 icon = Icon::AllocateBitmap(fIconSize);
1050 if (fIconData->GetIcon(icon) != B_OK) {
1051 delete icon;
1052 icon = NULL;
1056 fIcon = icon;
1060 void
1061 IconView::SetIconSize(int32 size)
1063 if (size < B_MINI_ICON)
1064 size = B_MINI_ICON;
1065 if (size > 256)
1066 size = 256;
1067 if (size == fIconSize)
1068 return;
1070 fIconSize = size;
1071 Update();
1075 void
1076 IconView::ShowIconHeap(bool show)
1078 if (show == (fHeapIcon != NULL))
1079 return;
1081 if (show) {
1082 BResources* resources = be_app->AppResources();
1083 if (resources != NULL) {
1084 const void* data = NULL;
1085 size_t size;
1086 data = resources->LoadResource('VICN', "icon heap", &size);
1087 if (data != NULL) {
1088 // got vector icon data
1089 fHeapIcon = Icon::AllocateBitmap(B_LARGE_ICON, B_RGBA32);
1090 if (BIconUtils::GetVectorIcon((const uint8*)data,
1091 size, fHeapIcon) != B_OK) {
1092 // bad data
1093 delete fHeapIcon;
1094 fHeapIcon = NULL;
1095 data = NULL;
1098 if (data == NULL) {
1099 // no vector icon or failed to get bitmap
1100 // try bitmap icon
1101 data = resources->LoadResource(B_LARGE_ICON_TYPE, "icon heap",
1102 NULL);
1103 if (data != NULL) {
1104 fHeapIcon = Icon::AllocateBitmap(B_LARGE_ICON, B_CMAP8);
1105 if (fHeapIcon != NULL) {
1106 memcpy(fHeapIcon->Bits(), data,
1107 fHeapIcon->BitsLength());
1112 } else {
1113 delete fHeapIcon;
1114 fHeapIcon = NULL;
1119 void
1120 IconView::ShowEmptyFrame(bool show)
1122 if (show == fShowEmptyFrame)
1123 return;
1125 fShowEmptyFrame = show;
1126 if (fIcon == NULL)
1127 Invalidate();
1131 status_t
1132 IconView::SetTarget(const BMessenger& target)
1134 fTarget = target;
1135 return B_OK;
1139 void
1140 IconView::SetModificationMessage(BMessage* message)
1142 delete fModificationMessage;
1143 fModificationMessage = message;
1147 status_t
1148 IconView::Invoke(BMessage* message)
1150 if (message == NULL)
1151 fTarget.SendMessage(kMsgIconInvoked);
1152 else
1153 fTarget.SendMessage(message);
1154 return B_OK;
1158 Icon*
1159 IconView::Icon()
1161 return fIconData;
1165 status_t
1166 IconView::GetRef(entry_ref& ref) const
1168 if (!fHasRef)
1169 return B_BAD_TYPE;
1171 ref = fRef;
1172 return B_OK;
1176 status_t
1177 IconView::GetMimeType(BMimeType& type) const
1179 if (!fHasType)
1180 return B_BAD_TYPE;
1182 type.SetTo(fType.Type());
1183 return B_OK;
1187 void
1188 IconView::_AddOrEditIcon()
1190 BMessage message;
1191 if (fHasRef && fType.Type() == NULL) {
1192 // in ref mode, Icon-O-Matic can change the icon directly, and
1193 // we'll pick it up via node monitoring
1194 message.what = B_REFS_RECEIVED;
1195 message.AddRef("refs", &fRef);
1196 } else {
1197 // in static or MIME type mode, Icon-O-Matic needs to return the
1198 // buffer it changed once its done
1199 message.what = B_EDIT_ICON_DATA;
1200 message.AddMessenger("reply to", BMessenger(this));
1202 ::Icon* icon = fIconData;
1203 if (icon == NULL) {
1204 icon = new ::Icon();
1205 if (fHasRef)
1206 icon->SetTo(fRef, fType.Type());
1207 else
1208 icon->SetTo(fType);
1211 if (icon->HasData()) {
1212 uint8* data;
1213 size_t size;
1214 if (icon->GetData(&data, &size) == B_OK) {
1215 message.AddData("icon data", B_VECTOR_ICON_TYPE, data, size);
1216 free(data);
1219 // TODO: somehow figure out how names of objects in the icon
1220 // can be preserved. Maybe in a second (optional) attribute
1221 // where ever a vector icon attribute is present?
1224 if (icon != fIconData)
1225 delete icon;
1228 be_roster->Launch("application/x-vnd.haiku-icon_o_matic", &message);
1232 void
1233 IconView::_SetIcon(BBitmap* large, BBitmap* mini, const uint8* data,
1234 size_t size, bool force)
1236 if (fHasRef) {
1237 BFile file(&fRef, B_READ_WRITE);
1239 if (is_application(file)) {
1240 BAppFileInfo info(&file);
1241 if (info.InitCheck() == B_OK) {
1242 if (large != NULL || force)
1243 info.SetIconForType(fType.Type(), large, B_LARGE_ICON);
1244 if (mini != NULL || force)
1245 info.SetIconForType(fType.Type(), mini, B_MINI_ICON);
1246 if (data != NULL || force)
1247 info.SetIconForType(fType.Type(), data, size);
1249 } else {
1250 BNodeInfo info(&file);
1251 if (info.InitCheck() == B_OK) {
1252 if (large != NULL || force)
1253 info.SetIcon(large, B_LARGE_ICON);
1254 if (mini != NULL || force)
1255 info.SetIcon(mini, B_MINI_ICON);
1256 if (data != NULL || force)
1257 info.SetIcon(data, size);
1260 // the icon shown will be updated using node monitoring
1261 } else if (fHasType) {
1262 if (large != NULL || force)
1263 fType.SetIcon(large, B_LARGE_ICON);
1264 if (mini != NULL || force)
1265 fType.SetIcon(mini, B_MINI_ICON);
1266 if (data != NULL || force)
1267 fType.SetIcon(data, size);
1269 // the icon shown will be updated automatically - we're watching
1270 // any changes to the MIME database
1271 } else if (fIconData != NULL) {
1272 if (large != NULL || force)
1273 fIconData->SetLarge(large);
1274 if (mini != NULL || force)
1275 fIconData->SetMini(mini);
1276 if (data != NULL || force)
1277 fIconData->SetData(data, size);
1279 // replace visible icon
1280 if (fIcon == NULL && fIconData->HasData())
1281 fIcon = Icon::AllocateBitmap(fIconSize);
1283 if (fIconData->GetIcon(fIcon) != B_OK) {
1284 delete fIcon;
1285 fIcon = NULL;
1287 Invalidate();
1290 if (fModificationMessage)
1291 Invoke(fModificationMessage);
1295 void
1296 IconView::_SetIcon(entry_ref* ref)
1298 // retrieve icons from file
1299 BFile file(ref, B_READ_ONLY);
1300 BAppFileInfo info(&file);
1301 if (file.InitCheck() != B_OK || info.InitCheck() != B_OK)
1302 return;
1304 // try vector/PNG icon first
1305 uint8* data = NULL;
1306 size_t size = 0;
1307 if (info.GetIcon(&data, &size) == B_OK) {
1308 _SetIcon(NULL, NULL, data, size);
1309 free(data);
1310 return;
1313 // try large/mini icons
1314 bool hasMini = false;
1315 bool hasLarge = false;
1317 BBitmap* large = new BBitmap(BRect(0, 0, 31, 31), B_CMAP8);
1318 if (large->InitCheck() != B_OK) {
1319 delete large;
1320 large = NULL;
1322 BBitmap* mini = new BBitmap(BRect(0, 0, 15, 15), B_CMAP8);
1323 if (mini->InitCheck() != B_OK) {
1324 delete mini;
1325 mini = NULL;
1328 if (large != NULL && info.GetIcon(large, B_LARGE_ICON) == B_OK)
1329 hasLarge = true;
1330 if (mini != NULL && info.GetIcon(mini, B_MINI_ICON) == B_OK)
1331 hasMini = true;
1333 if (!hasMini && !hasLarge) {
1334 // TODO: don't forget device icons!
1336 // try MIME type icon
1337 char type[B_MIME_TYPE_LENGTH];
1338 if (info.GetType(type) != B_OK)
1339 return;
1341 BMimeType mimeType(type);
1342 if (icon_for_type(mimeType, &data, &size) != B_OK) {
1343 // only try large/mini icons when there is no vector icon
1344 if (large != NULL
1345 && icon_for_type(mimeType, *large, B_LARGE_ICON) == B_OK)
1346 hasLarge = true;
1347 if (mini != NULL
1348 && icon_for_type(mimeType, *mini, B_MINI_ICON) == B_OK)
1349 hasMini = true;
1353 if (data != NULL) {
1354 _SetIcon(NULL, NULL, data, size);
1355 free(data);
1356 } else if (hasLarge || hasMini)
1357 _SetIcon(large, mini, NULL, 0);
1359 delete large;
1360 delete mini;
1364 void
1365 IconView::_RemoveIcon()
1367 _SetIcon(NULL, NULL, NULL, 0, true);
1371 void
1372 IconView::_StartWatching()
1374 if (Looper() == NULL) {
1375 // we are not a valid messenger yet
1376 return;
1379 if (fHasRef) {
1380 BNode node(&fRef);
1381 node_ref nodeRef;
1382 if (node.InitCheck() == B_OK
1383 && node.GetNodeRef(&nodeRef) == B_OK)
1384 watch_node(&nodeRef, B_WATCH_ATTR, this);
1385 } else if (fHasType)
1386 BMimeType::StartWatching(this);
1390 void
1391 IconView::_StopWatching()
1393 if (fHasRef)
1394 stop_watching(this);
1395 else if (fHasType)
1396 BMimeType::StopWatching(this);
1400 #if __GNUC__ == 2
1402 status_t
1403 IconView::SetTarget(BMessenger target)
1405 return BControl::SetTarget(target);
1409 status_t
1410 IconView::SetTarget(const BHandler* handler, const BLooper* looper = NULL)
1412 return BControl::SetTarget(handler,
1413 looper);
1416 #endif