/*
* Copyright 2006-2007, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
* Distributed under the terms of the MIT License.
*/
#include "IconView.h"
#include <new>
#include <stdlib.h>
#include <strings.h>
#include <Application.h>
#include <AppFileInfo.h>
#include <Attributes.h>
#include <Bitmap.h>
#include <Catalog.h>
#include <IconEditorProtocol.h>
#include <IconUtils.h>
#include <Locale.h>
#include <MenuItem.h>
#include <Mime.h>
#include <NodeMonitor.h>
#include <PopUpMenu.h>
#include <Resources.h>
#include <Roster.h>
#include <Size.h>
#include "FileTypes.h"
#include "MimeTypeListView.h"
#undef B_TRANSLATION_CONTEXT
#define B_TRANSLATION_CONTEXT "Icon View"
using namespace std;
status_t
icon_for_type(const BMimeType& type, uint8** _data, size_t* _size,
icon_source* _source)
{
if (_data == NULL || _size == NULL)
return B_BAD_VALUE;
icon_source source = kNoIcon;
uint8* data;
size_t size;
if (type.GetIcon(&data, &size) == B_OK)
source = kOwnIcon;
if (source == kNoIcon) {
// check for icon from preferred app
char preferred[B_MIME_TYPE_LENGTH];
if (type.GetPreferredApp(preferred) == B_OK) {
BMimeType preferredApp(preferred);
if (preferredApp.GetIconForType(type.Type(), &data, &size) == B_OK)
source = kApplicationIcon;
}
}
if (source == kNoIcon) {
// check super type for an icon
BMimeType superType;
if (type.GetSupertype(&superType) == B_OK) {
if (superType.GetIcon(&data, &size) == B_OK)
source = kSupertypeIcon;
else {
// check the super type's preferred app
char preferred[B_MIME_TYPE_LENGTH];
if (superType.GetPreferredApp(preferred) == B_OK) {
BMimeType preferredApp(preferred);
if (preferredApp.GetIconForType(superType.Type(),
&data, &size) == B_OK)
source = kSupertypeIcon;
}
}
}
}
if (source != kNoIcon) {
*_data = data;
*_size = size;
} // NOTE: else there is no data, so nothing is leaked.
if (_source)
*_source = source;
return source != kNoIcon ? B_OK : B_ERROR;
}
status_t
icon_for_type(const BMimeType& type, BBitmap& bitmap, icon_size size,
icon_source* _source)
{
icon_source source = kNoIcon;
if (type.GetIcon(&bitmap, size) == B_OK)
source = kOwnIcon;
if (source == kNoIcon) {
// check for icon from preferred app
char preferred[B_MIME_TYPE_LENGTH];
if (type.GetPreferredApp(preferred) == B_OK) {
BMimeType preferredApp(preferred);
if (preferredApp.GetIconForType(type.Type(), &bitmap, size) == B_OK)
source = kApplicationIcon;
}
}
if (source == kNoIcon) {
// check super type for an icon
BMimeType superType;
if (type.GetSupertype(&superType) == B_OK) {
if (superType.GetIcon(&bitmap, size) == B_OK)
source = kSupertypeIcon;
else {
// check the super type's preferred app
char preferred[B_MIME_TYPE_LENGTH];
if (superType.GetPreferredApp(preferred) == B_OK) {
BMimeType preferredApp(preferred);
if (preferredApp.GetIconForType(superType.Type(),
&bitmap, size) == B_OK)
source = kSupertypeIcon;
}
}
}
}
if (_source)
*_source = source;
return source != kNoIcon ? B_OK : B_ERROR;
}
// #pragma mark -
Icon::Icon()
:
fLarge(NULL),
fMini(NULL),
fData(NULL),
fSize(0)
{
}
Icon::Icon(const Icon& source)
:
fLarge(NULL),
fMini(NULL),
fData(NULL),
fSize(0)
{
*this = source;
}
Icon::~Icon()
{
delete fLarge;
delete fMini;
free(fData);
}
void
Icon::SetTo(const BAppFileInfo& info, const char* type)
{
Unset();
uint8* data;
size_t size;
if (info.GetIconForType(type, &data, &size) == B_OK) {
// we have the vector icon, no need to get the rest
AdoptData(data, size);
return;
}
BBitmap* icon = AllocateBitmap(B_LARGE_ICON, B_CMAP8);
if (icon && info.GetIconForType(type, icon, B_LARGE_ICON) == B_OK)
AdoptLarge(icon);
else
delete icon;
icon = AllocateBitmap(B_MINI_ICON, B_CMAP8);
if (icon && info.GetIconForType(type, icon, B_MINI_ICON) == B_OK)
AdoptMini(icon);
else
delete icon;
}
void
Icon::SetTo(const entry_ref& ref, const char* type)
{
Unset();
BFile file(&ref, B_READ_ONLY);
BAppFileInfo info(&file);
if (file.InitCheck() == B_OK
&& info.InitCheck() == B_OK)
SetTo(info, type);
}
void
Icon::SetTo(const BMimeType& type, icon_source* _source)
{
Unset();
uint8* data;
size_t size;
if (icon_for_type(type, &data, &size, _source) == B_OK) {
// we have the vector icon, no need to get the rest
AdoptData(data, size);
return;
}
BBitmap* icon = AllocateBitmap(B_LARGE_ICON, B_CMAP8);
if (icon && icon_for_type(type, *icon, B_LARGE_ICON, _source) == B_OK)
AdoptLarge(icon);
else
delete icon;
icon = AllocateBitmap(B_MINI_ICON, B_CMAP8);
if (icon && icon_for_type(type, *icon, B_MINI_ICON) == B_OK)
AdoptMini(icon);
else
delete icon;
}
status_t
Icon::CopyTo(BAppFileInfo& info, const char* type, bool force) const
{
status_t status = B_OK;
if (fLarge != NULL || force)
status = info.SetIconForType(type, fLarge, B_LARGE_ICON);
if (fMini != NULL || force)
status = info.SetIconForType(type, fMini, B_MINI_ICON);
if (fData != NULL || force)
status = info.SetIconForType(type, fData, fSize);
return status;
}
status_t
Icon::CopyTo(const entry_ref& ref, const char* type, bool force) const
{
BFile file;
status_t status = file.SetTo(&ref, B_READ_ONLY);
if (status < B_OK)
return status;
BAppFileInfo info(&file);
status = info.InitCheck();
if (status < B_OK)
return status;
return CopyTo(info, type, force);
}
status_t
Icon::CopyTo(BMimeType& type, bool force) const
{
status_t status = B_OK;
if (fLarge != NULL || force)
status = type.SetIcon(fLarge, B_LARGE_ICON);
if (fMini != NULL || force)
status = type.SetIcon(fMini, B_MINI_ICON);
if (fData != NULL || force)
status = type.SetIcon(fData, fSize);
return status;
}
status_t
Icon::CopyTo(BMessage& message) const
{
status_t status = B_OK;
if (status == B_OK && fLarge != NULL) {
BMessage archive;
status = fLarge->Archive(&archive);
if (status == B_OK)
status = message.AddMessage("icon/large", &archive);
}
if (status == B_OK && fMini != NULL) {
BMessage archive;
status = fMini->Archive(&archive);
if (status == B_OK)
status = message.AddMessage("icon/mini", &archive);
}
if (status == B_OK && fData != NULL)
status = message.AddData("icon", B_VECTOR_ICON_TYPE, fData, fSize);
return B_OK;
}
void
Icon::SetLarge(const BBitmap* large)
{
if (large != NULL) {
if (fLarge == NULL)
fLarge = new BBitmap(BRect(0, 0, 31, 31), B_CMAP8);
memcpy(fLarge->Bits(), large->Bits(), min_c(large->BitsLength(),
fLarge->BitsLength()));
} else {
delete fLarge;
fLarge = NULL;
}
}
void
Icon::SetMini(const BBitmap* mini)
{
if (mini != NULL) {
if (fMini == NULL)
fMini = new BBitmap(BRect(0, 0, 15, 15), B_CMAP8);
memcpy(fMini->Bits(), mini->Bits(), min_c(mini->BitsLength(),
fMini->BitsLength()));
} else {
delete fMini;
fMini = NULL;
}
}
void
Icon::SetData(const uint8* data, size_t size)
{
free(fData);
fData = NULL;
if (data != NULL) {
fData = (uint8*)malloc(size);
if (fData != NULL) {
fSize = size;
//fType = B_VECTOR_ICON_TYPE;
memcpy(fData, data, size);
}
}
}
void
Icon::Unset()
{
delete fLarge;
delete fMini;
free(fData);
fLarge = fMini = NULL;
fData = NULL;
}
bool
Icon::HasData() const
{
return fData != NULL || fLarge != NULL || fMini != NULL;
}
status_t
Icon::GetData(icon_size which, BBitmap** _bitmap) const
{
BBitmap* source;
switch (which) {
case B_LARGE_ICON:
source = fLarge;
break;
case B_MINI_ICON:
source = fMini;
break;
default:
return B_BAD_VALUE;
}
if (source == NULL)
return B_ENTRY_NOT_FOUND;
BBitmap* bitmap = new (nothrow) BBitmap(source);
if (bitmap == NULL || bitmap->InitCheck() != B_OK) {
delete bitmap;
return B_NO_MEMORY;
}
*_bitmap = bitmap;
return B_OK;
}
status_t
Icon::GetData(uint8** _data, size_t* _size) const
{
if (fData == NULL)
return B_ENTRY_NOT_FOUND;
uint8* data = (uint8*)malloc(fSize);
if (data == NULL)
return B_NO_MEMORY;
memcpy(data, fData, fSize);
*_data = data;
*_size = fSize;
return B_OK;
}
status_t
Icon::GetIcon(BBitmap* bitmap) const
{
if (bitmap == NULL)
return B_BAD_VALUE;
if (fData != NULL
&& BIconUtils::GetVectorIcon(fData, fSize, bitmap) == B_OK)
return B_OK;
int32 width = bitmap->Bounds().IntegerWidth() + 1;
if (width == B_LARGE_ICON && fLarge != NULL) {
bitmap->SetBits(fLarge->Bits(), fLarge->BitsLength(), 0,
fLarge->ColorSpace());
return B_OK;
}
if (width == B_MINI_ICON && fMini != NULL) {
bitmap->SetBits(fMini->Bits(), fMini->BitsLength(), 0,
fMini->ColorSpace());
return B_OK;
}
return B_ENTRY_NOT_FOUND;
}
Icon&
Icon::operator=(const Icon& source)
{
Unset();
SetData(source.fData, source.fSize);
SetLarge(source.fLarge);
SetMini(source.fMini);
return *this;
}
void
Icon::AdoptLarge(BBitmap *large)
{
delete fLarge;
fLarge = large;
}
void
Icon::AdoptMini(BBitmap *mini)
{
delete fMini;
fMini = mini;
}
void
Icon::AdoptData(uint8* data, size_t size)
{
free(fData);
fData = data;
fSize = size;
}
/*static*/ BBitmap*
Icon::AllocateBitmap(int32 size, int32 space)
{
int32 kSpace = B_RGBA32;
if (space == -1)
space = kSpace;
BBitmap* bitmap = new (nothrow) BBitmap(BRect(0, 0, size - 1, size - 1),
(color_space)space);
if (bitmap == NULL || bitmap->InitCheck() != B_OK) {
delete bitmap;
return NULL;
}
return bitmap;
}
// #pragma mark -
IconView::IconView(const char* name, uint32 flags)
: BControl(name, NULL, NULL, B_WILL_DRAW | flags),
fModificationMessage(NULL),
fIconSize(B_LARGE_ICON),
fIcon(NULL),
fHeapIcon(NULL),
fHasRef(false),
fHasType(false),
fIconData(NULL),
fTracking(false),
fDragging(false),
fDropTarget(false),
fShowEmptyFrame(true)
{
}
IconView::~IconView()
{
delete fIcon;
delete fModificationMessage;
}
void
IconView::AttachedToWindow()
{
AdoptParentColors();
fTarget = this;
// SetTo() was already called before we were a valid messenger
if (fHasRef || fHasType)
_StartWatching();
}
void
IconView::DetachedFromWindow()
{
_StopWatching();
}
void
IconView::MessageReceived(BMessage* message)
{
if (message->WasDropped() && message->ReturnAddress() != BMessenger(this)
&& AcceptsDrag(message)) {
// set icon from message
BBitmap* mini = NULL;
BBitmap* large = NULL;
const uint8* data = NULL;
ssize_t size = 0;
message->FindData("icon", B_VECTOR_ICON_TYPE, (const void**)&data,
&size);
BMessage archive;
if (message->FindMessage("icon/large", &archive) == B_OK)
large = (BBitmap*)BBitmap::Instantiate(&archive);
if (message->FindMessage("icon/mini", &archive) == B_OK)
mini = (BBitmap*)BBitmap::Instantiate(&archive);
if (large != NULL || mini != NULL || (data != NULL && size > 0))
_SetIcon(large, mini, data, size);
else {
entry_ref ref;
if (message->FindRef("refs", &ref) == B_OK)
_SetIcon(&ref);
}
delete large;
delete mini;
return;
}
switch (message->what) {
case kMsgIconInvoked:
case kMsgEditIcon:
case kMsgAddIcon:
_AddOrEditIcon();
break;
case kMsgRemoveIcon:
_RemoveIcon();
break;
case B_NODE_MONITOR:
{
if (!fHasRef)
break;
int32 opcode;
if (message->FindInt32("opcode", &opcode) != B_OK
|| opcode != B_ATTR_CHANGED)
break;
const char* name;
if (message->FindString("attr", &name) != B_OK)
break;
if (!strcmp(name, kAttrMiniIcon)
|| !strcmp(name, kAttrLargeIcon)
|| !strcmp(name, kAttrIcon))
Update();
break;
}
case B_META_MIME_CHANGED:
{
if (!fHasType)
break;
const char* type;
int32 which;
if (message->FindString("be:type", &type) != B_OK
|| message->FindInt32("be:which", &which) != B_OK)
break;
if (!strcasecmp(type, fType.Type())) {
switch (which) {
case B_MIME_TYPE_DELETED:
Unset();
break;
case B_ICON_CHANGED:
Update();
break;
default:
break;
}
} else if (fSource != kOwnIcon
&& message->FindString("be:extra_type", &type) == B_OK
&& !strcasecmp(type, fType.Type())) {
// this change could still affect our current icon
if (which == B_MIME_TYPE_DELETED
|| which == B_PREFERRED_APP_CHANGED
|| which == B_SUPPORTED_TYPES_CHANGED
|| which == B_ICON_FOR_TYPE_CHANGED)
Update();
}
break;
}
case B_ICON_DATA_EDITED:
{
const uint8* data;
ssize_t size;
if (message->FindData("icon data", B_VECTOR_ICON_TYPE,
(const void**)&data, &size) < B_OK)
break;
_SetIcon(NULL, NULL, data, size);
break;
}
default:
BControl::MessageReceived(message);
break;
}
}
bool
IconView::AcceptsDrag(const BMessage* message)
{
if (!IsEnabled())
return false;
type_code type;
int32 count;
if (message->GetInfo("refs", &type, &count) == B_OK && count == 1
&& type == B_REF_TYPE) {
// if we're bound to an entry, check that no one drops this to us
entry_ref ref;
if (fHasRef && message->FindRef("refs", &ref) == B_OK && fRef == ref)
return false;
return true;
}
if ((message->GetInfo("icon/large", &type) == B_OK
&& type == B_MESSAGE_TYPE)
|| (message->GetInfo("icon", &type) == B_OK
&& type == B_VECTOR_ICON_TYPE)
|| (message->GetInfo("icon/mini", &type) == B_OK
&& type == B_MESSAGE_TYPE))
return true;
return false;
}
BRect
IconView::BitmapRect() const
{
return BRect(0, 0, fIconSize - 1, fIconSize - 1);
}
void
IconView::Draw(BRect updateRect)
{
SetDrawingMode(B_OP_ALPHA);
if (fHeapIcon != NULL)
DrawBitmap(fHeapIcon, BitmapRect().LeftTop());
else if (fIcon != NULL)
DrawBitmap(fIcon, BitmapRect().LeftTop());
else if (!fDropTarget && fShowEmptyFrame) {
// draw frame so that the user knows here is something he
// might be able to click on
SetHighColor(tint_color(ViewColor(), B_DARKEN_1_TINT));
StrokeRect(BitmapRect());
}
if (IsFocus()) {
// mark this view as a having focus
SetHighColor(ui_color(B_KEYBOARD_NAVIGATION_COLOR));
StrokeRect(BitmapRect());
}
if (fDropTarget) {
// mark this view as a drop target
SetHighColor(0, 0, 0);
SetPenSize(2);
BRect rect = BitmapRect();
// TODO: this is an incompatibility between R5 and Haiku and should be fixed!
// (Necessary adjustment differs.)
rect.left++;
rect.top++;
StrokeRect(rect);
SetPenSize(1);
}
}
void
IconView::GetPreferredSize(float* _width, float* _height)
{
if (_width)
*_width = fIconSize;
if (_height)
*_height = fIconSize;
}
BSize
IconView::MinSize()
{
float width, height;
GetPreferredSize(&width, &height);
return BSize(width, height);
}
BSize
IconView::PreferredSize()
{
return MinSize();
}
BSize
IconView::MaxSize()
{
return MinSize();
}
void
IconView::MouseDown(BPoint where)
{
if (!IsEnabled())
return;
int32 buttons = B_PRIMARY_MOUSE_BUTTON;
int32 clicks = 1;
if (Looper() != NULL && Looper()->CurrentMessage() != NULL) {
if (Looper()->CurrentMessage()->FindInt32("buttons", &buttons) != B_OK)
buttons = B_PRIMARY_MOUSE_BUTTON;
if (Looper()->CurrentMessage()->FindInt32("clicks", &clicks) != B_OK)
clicks = 1;
}
if ((buttons & B_PRIMARY_MOUSE_BUTTON) != 0
&& BitmapRect().Contains(where)) {
if (clicks == 2) {
// double click - open Icon-O-Matic
Invoke();
} else if (fIcon != NULL) {
// start tracking - this icon might be dragged around
fDragPoint = where;
fTracking = true;
SetMouseEventMask(B_POINTER_EVENTS, B_NO_POINTER_HISTORY);
}
}
if ((buttons & B_SECONDARY_MOUSE_BUTTON) != 0) {
// show context menu
ConvertToScreen(&where);
BPopUpMenu* menu = new BPopUpMenu("context");
menu->SetFont(be_plain_font);
bool hasIcon = fHasType ? fSource == kOwnIcon : fIcon != NULL;
if (hasIcon) {
menu->AddItem(new BMenuItem(
B_TRANSLATE("Edit icon" B_UTF8_ELLIPSIS),
new BMessage(kMsgEditIcon)));
} else {
menu->AddItem(new BMenuItem(
B_TRANSLATE("Add icon" B_UTF8_ELLIPSIS),
new BMessage(kMsgAddIcon)));
}
BMenuItem* item = new BMenuItem(
B_TRANSLATE("Remove icon"), new BMessage(kMsgRemoveIcon));
if (!hasIcon)
item->SetEnabled(false);
menu->AddItem(item);
menu->SetTargetForItems(fTarget);
menu->Go(where, true, false, true);
}
}
void
IconView::MouseUp(BPoint where)
{
fTracking = false;
fDragging = false;
if (fDropTarget) {
fDropTarget = false;
Invalidate();
}
}
void
IconView::MouseMoved(BPoint where, uint32 transit, const BMessage* dragMessage)
{
if (fTracking && !fDragging && fIcon != NULL
&& (abs((int32)(where.x - fDragPoint.x)) > 3
|| abs((int32)(where.y - fDragPoint.y)) > 3)) {
// Start drag
BMessage message(B_SIMPLE_DATA);
::Icon* icon = fIconData;
if (fHasRef || fHasType) {
icon = new ::Icon;
if (fHasRef)
icon->SetTo(fRef, fType.Type());
else if (fHasType)
icon->SetTo(fType);
}
icon->CopyTo(message);
if (icon != fIconData)
delete icon;
BBitmap *dragBitmap = new BBitmap(fIcon->Bounds(), B_RGBA32, true);
dragBitmap->Lock();
BView *view
= new BView(dragBitmap->Bounds(), B_EMPTY_STRING, B_FOLLOW_NONE, 0);
dragBitmap->AddChild(view);
view->SetHighColor(B_TRANSPARENT_COLOR);
view->FillRect(dragBitmap->Bounds());
view->SetBlendingMode(B_CONSTANT_ALPHA, B_ALPHA_COMPOSITE);
view->SetDrawingMode(B_OP_ALPHA);
view->SetHighColor(0, 0, 0, 160);
view->DrawBitmap(fIcon);
view->Sync();
dragBitmap->Unlock();
DragMessage(&message, dragBitmap, B_OP_ALPHA,
fDragPoint - BitmapRect().LeftTop(), this);
fDragging = true;
}
if (dragMessage != NULL && !fDragging && AcceptsDrag(dragMessage)) {
bool dropTarget = transit == B_ENTERED_VIEW || transit == B_INSIDE_VIEW;
if (dropTarget != fDropTarget) {
fDropTarget = dropTarget;
Invalidate();
}
} else if (fDropTarget) {
fDropTarget = false;
Invalidate();
}
}
void
IconView::KeyDown(const char* bytes, int32 numBytes)
{
if (numBytes == 1) {
switch (bytes[0]) {
case B_DELETE:
case B_BACKSPACE:
_RemoveIcon();
return;
case B_ENTER:
case B_SPACE:
Invoke();
return;
}
}
BControl::KeyDown(bytes, numBytes);
}
void
IconView::MakeFocus(bool focus)
{
if (focus != IsFocus())
Invalidate();
BControl::MakeFocus(focus);
}
void
IconView::SetTo(const entry_ref& ref, const char* fileType)
{
Unset();
fHasRef = true;
fRef = ref;
if (fileType != NULL)
fType.SetTo(fileType);
else
fType.Unset();
_StartWatching();
Update();
}
void
IconView::SetTo(const BMimeType& type)
{
Unset();
if (type.Type() == NULL)
return;
fHasType = true;
fType.SetTo(type.Type());
_StartWatching();
Update();
}
void
IconView::SetTo(::Icon* icon)
{
if (fIconData == icon)
return;
Unset();
fIconData = icon;
Update();
}
void
IconView::Unset()
{
if (fHasRef || fHasType)
_StopWatching();
fHasRef = false;
fHasType = false;
fType.Unset();
fIconData = NULL;
}
void
IconView::Update()
{
delete fIcon;
fIcon = NULL;
Invalidate();
// this will actually trigger a redraw *after* we updated the icon below
BBitmap* icon = NULL;
if (fHasRef) {
BFile file(&fRef, B_READ_ONLY);
if (file.InitCheck() != B_OK)
return;
BNodeInfo info;
if (info.SetTo(&file) != B_OK)
return;
icon = Icon::AllocateBitmap(fIconSize);
if (icon != NULL && info.GetTrackerIcon(icon,
(icon_size)fIconSize) != B_OK) {
delete icon;
return;
}
} else if (fHasType) {
icon = Icon::AllocateBitmap(fIconSize);
if (icon != NULL && icon_for_type(fType, *icon, (icon_size)fIconSize,
&fSource) != B_OK) {
delete icon;
return;
}
} else if (fIconData) {
icon = Icon::AllocateBitmap(fIconSize);
if (fIconData->GetIcon(icon) != B_OK) {
delete icon;
icon = NULL;
}
}
fIcon = icon;
}
void
IconView::SetIconSize(int32 size)
{
if (size < B_MINI_ICON)
size = B_MINI_ICON;
if (size > 256)
size = 256;
if (size == fIconSize)
return;
fIconSize = size;
Update();
}
void
IconView::ShowIconHeap(bool show)
{
if (show == (fHeapIcon != NULL))
return;
if (show) {
BResources* resources = be_app->AppResources();
if (resources != NULL) {
const void* data = NULL;
size_t size;
data = resources->LoadResource('VICN', "icon heap", &size);
if (data != NULL) {
// got vector icon data
fHeapIcon = Icon::AllocateBitmap(B_LARGE_ICON, B_RGBA32);
if (BIconUtils::GetVectorIcon((const uint8*)data,
size, fHeapIcon) != B_OK) {
// bad data
delete fHeapIcon;
fHeapIcon = NULL;
data = NULL;
}
}
if (data == NULL) {
// no vector icon or failed to get bitmap
// try bitmap icon
data = resources->LoadResource(B_LARGE_ICON_TYPE, "icon heap",
NULL);
if (data != NULL) {
fHeapIcon = Icon::AllocateBitmap(B_LARGE_ICON, B_CMAP8);
if (fHeapIcon != NULL) {
memcpy(fHeapIcon->Bits(), data,
fHeapIcon->BitsLength());
}
}
}
}
} else {
delete fHeapIcon;
fHeapIcon = NULL;
}
}
void
IconView::ShowEmptyFrame(bool show)
{
if (show == fShowEmptyFrame)
return;
fShowEmptyFrame = show;
if (fIcon == NULL)
Invalidate();
}
status_t
IconView::SetTarget(const BMessenger& target)
{
fTarget = target;
return B_OK;
}
void
IconView::SetModificationMessage(BMessage* message)
{
delete fModificationMessage;
fModificationMessage = message;
}
status_t
IconView::Invoke(BMessage* message)
{
if (message == NULL)
fTarget.SendMessage(kMsgIconInvoked);
else
fTarget.SendMessage(message);
return B_OK;
}
Icon*
IconView::Icon()
{
return fIconData;
}
status_t
IconView::GetRef(entry_ref& ref) const
{
if (!fHasRef)
return B_BAD_TYPE;
ref = fRef;
return B_OK;
}
status_t
IconView::GetMimeType(BMimeType& type) const
{
if (!fHasType)
return B_BAD_TYPE;
type.SetTo(fType.Type());
return B_OK;
}
void
IconView::_AddOrEditIcon()
{
BMessage message;
if (fHasRef && fType.Type() == NULL) {
// in ref mode, Icon-O-Matic can change the icon directly, and
// we'll pick it up via node monitoring
message.what = B_REFS_RECEIVED;
message.AddRef("refs", &fRef);
} else {
// in static or MIME type mode, Icon-O-Matic needs to return the
// buffer it changed once its done
message.what = B_EDIT_ICON_DATA;
message.AddMessenger("reply to", BMessenger(this));
::Icon* icon = fIconData;
if (icon == NULL) {
icon = new ::Icon();
if (fHasRef)
icon->SetTo(fRef, fType.Type());
else
icon->SetTo(fType);
}
if (icon->HasData()) {
uint8* data;
size_t size;
if (icon->GetData(&data, &size) == B_OK) {
message.AddData("icon data", B_VECTOR_ICON_TYPE, data, size);
free(data);
}
// TODO: somehow figure out how names of objects in the icon
// can be preserved. Maybe in a second (optional) attribute
// where ever a vector icon attribute is present?
}
if (icon != fIconData)
delete icon;
}
be_roster->Launch("application/x-vnd.haiku-icon_o_matic", &message);
}
void
IconView::_SetIcon(BBitmap* large, BBitmap* mini, const uint8* data,
size_t size, bool force)
{
if (fHasRef) {
BFile file(&fRef, B_READ_WRITE);
if (is_application(file)) {
BAppFileInfo info(&file);
if (info.InitCheck() == B_OK) {
if (large != NULL || force)
info.SetIconForType(fType.Type(), large, B_LARGE_ICON);
if (mini != NULL || force)
info.SetIconForType(fType.Type(), mini, B_MINI_ICON);
if (data != NULL || force)
info.SetIconForType(fType.Type(), data, size);
}
} else {
BNodeInfo info(&file);
if (info.InitCheck() == B_OK) {
if (large != NULL || force)
info.SetIcon(large, B_LARGE_ICON);
if (mini != NULL || force)
info.SetIcon(mini, B_MINI_ICON);
if (data != NULL || force)
info.SetIcon(data, size);
}
}
// the icon shown will be updated using node monitoring
} else if (fHasType) {
if (large != NULL || force)
fType.SetIcon(large, B_LARGE_ICON);
if (mini != NULL || force)
fType.SetIcon(mini, B_MINI_ICON);
if (data != NULL || force)
fType.SetIcon(data, size);
// the icon shown will be updated automatically - we're watching
// any changes to the MIME database
} else if (fIconData != NULL) {
if (large != NULL || force)
fIconData->SetLarge(large);
if (mini != NULL || force)
fIconData->SetMini(mini);
if (data != NULL || force)
fIconData->SetData(data, size);
// replace visible icon
if (fIcon == NULL && fIconData->HasData())
fIcon = Icon::AllocateBitmap(fIconSize);
if (fIconData->GetIcon(fIcon) != B_OK) {
delete fIcon;
fIcon = NULL;
}
Invalidate();
}
if (fModificationMessage)
Invoke(fModificationMessage);
}
void
IconView::_SetIcon(entry_ref* ref)
{
// retrieve icons from file
BFile file(ref, B_READ_ONLY);
BAppFileInfo info(&file);
if (file.InitCheck() != B_OK || info.InitCheck() != B_OK)
return;
// try vector/PNG icon first
uint8* data = NULL;
size_t size = 0;
if (info.GetIcon(&data, &size) == B_OK) {
_SetIcon(NULL, NULL, data, size);
free(data);
return;
}
// try large/mini icons
bool hasMini = false;
bool hasLarge = false;
BBitmap* large = new BBitmap(BRect(0, 0, 31, 31), B_CMAP8);
if (large->InitCheck() != B_OK) {
delete large;
large = NULL;
}
BBitmap* mini = new BBitmap(BRect(0, 0, 15, 15), B_CMAP8);
if (mini->InitCheck() != B_OK) {
delete mini;
mini = NULL;
}
if (large != NULL && info.GetIcon(large, B_LARGE_ICON) == B_OK)
hasLarge = true;
if (mini != NULL && info.GetIcon(mini, B_MINI_ICON) == B_OK)
hasMini = true;
if (!hasMini && !hasLarge) {
// TODO: don't forget device icons!
// try MIME type icon
char type[B_MIME_TYPE_LENGTH];
if (info.GetType(type) != B_OK)
return;
BMimeType mimeType(type);
if (icon_for_type(mimeType, &data, &size) != B_OK) {
// only try large/mini icons when there is no vector icon
if (large != NULL
&& icon_for_type(mimeType, *large, B_LARGE_ICON) == B_OK)
hasLarge = true;
if (mini != NULL
&& icon_for_type(mimeType, *mini, B_MINI_ICON) == B_OK)
hasMini = true;
}
}
if (data != NULL) {
_SetIcon(NULL, NULL, data, size);
free(data);
} else if (hasLarge || hasMini)
_SetIcon(large, mini, NULL, 0);
delete large;
delete mini;
}
void
IconView::_RemoveIcon()
{
_SetIcon(NULL, NULL, NULL, 0, true);
}
void
IconView::_StartWatching()
{
if (Looper() == NULL) {
// we are not a valid messenger yet
return;
}
if (fHasRef) {
BNode node(&fRef);
node_ref nodeRef;
if (node.InitCheck() == B_OK
&& node.GetNodeRef(&nodeRef) == B_OK)
watch_node(&nodeRef, B_WATCH_ATTR, this);
} else if (fHasType)
BMimeType::StartWatching(this);
}
void
IconView::_StopWatching()
{
if (fHasRef)
stop_watching(this);
else if (fHasType)
BMimeType::StopWatching(this);
}
#if __GNUC__ == 2
status_t
IconView::SetTarget(BMessenger target)
{
return BControl::SetTarget(target);
}
status_t
IconView::SetTarget(const BHandler* handler, const BLooper* looper = NULL)
{
return BControl::SetTarget(handler,
looper);
}
#endif
↑ V730 Not all members of a class are initialized inside the constructor. Consider inspecting: fSource.
↑ V773 Visibility scope of the 'icon' pointer was exited without releasing the memory. A memory leak is possible.
↑ V773 Visibility scope of the 'icon' pointer was exited without releasing the memory. A memory leak is possible.
↑ V773 Visibility scope of the 'menu' pointer was exited without releasing the memory. A memory leak is possible.