* Copyright 2004-2015 Haiku, Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Alexander von Gluck IV, kallisti5@unixzen.com
* Philippe Houdoin
* Fredrik Modéen
* John Scipione, jscipione@gmail.com
*/
#include "InterfaceListItem.h"
#include <algorithm>
#include <Application.h>
#include <Bitmap.h>
#include <Catalog.h>
#include <ControlLook.h>
#include <IconUtils.h>
#include <OutlineListView.h>
#include <Resources.h>
#include <String.h>
#undef B_TRANSLATION_CONTEXT
#define B_TRANSLATION_CONTEXT "InterfaceListItem"
InterfaceListItem::InterfaceListItem(const char* name,
BNetworkInterfaceType type)
:
BListItem(0, false),
fType(type),
fIcon(NULL),
fIconOffline(NULL),
fIconPending(NULL),
fIconOnline(NULL),
fFirstLineOffset(0),
fLineOffset(0),
fDisabled(false),
fHasLink(false),
fConnecting(false)
{
fInterface.SetTo(name);
_Init();
}
InterfaceListItem::~InterfaceListItem()
{
delete fIcon;
delete fIconOffline;
delete fIconPending;
delete fIconOnline;
}
void
InterfaceListItem::DrawItem(BView* owner, BRect bounds, bool complete)
{
owner->PushState();
rgb_color lowColor = owner->LowColor();
if (IsSelected() || complete) {
if (IsSelected()) {
owner->SetHighColor(ui_color(B_LIST_SELECTED_BACKGROUND_COLOR));
owner->SetLowColor(owner->HighColor());
} else
owner->SetHighColor(lowColor);
owner->FillRect(bounds);
}
BBitmap* stateIcon = _StateIcon();
const int32 stateIconWidth = stateIcon->Bounds().IntegerWidth() + 1;
const char* stateText = _StateText();
BPoint iconPoint = bounds.LeftTop()
+ BPoint(be_control_look->DefaultLabelSpacing(), 2);
BPoint statePoint = bounds.RightTop() + BPoint(0, fFirstLineOffset)
- BPoint(be_plain_font->StringWidth(stateText)
+ be_control_look->DefaultLabelSpacing(), 0);
BPoint namePoint = bounds.LeftTop()
+ BPoint(stateIconWidth + (be_control_look->DefaultLabelSpacing() * 2),
fFirstLineOffset);
if (fDisabled) {
owner->SetDrawingMode(B_OP_ALPHA);
owner->SetBlendingMode(B_CONSTANT_ALPHA, B_ALPHA_OVERLAY);
owner->SetHighColor(0, 0, 0, 32);
} else
owner->SetDrawingMode(B_OP_OVER);
owner->DrawBitmapAsync(fIcon, iconPoint);
owner->DrawBitmapAsync(stateIcon, iconPoint);
if (fDisabled) {
rgb_color textColor;
if (IsSelected())
textColor = ui_color(B_LIST_SELECTED_ITEM_TEXT_COLOR);
else
textColor = ui_color(B_LIST_ITEM_TEXT_COLOR);
if (textColor.red + textColor.green + textColor.blue > 128 * 3)
owner->SetHighColor(tint_color(textColor, B_DARKEN_1_TINT));
else
owner->SetHighColor(tint_color(textColor, B_LIGHTEN_1_TINT));
} else {
if (IsSelected())
owner->SetHighColor(ui_color(B_LIST_SELECTED_ITEM_TEXT_COLOR));
else
owner->SetHighColor(ui_color(B_LIST_ITEM_TEXT_COLOR));
}
owner->SetFont(be_bold_font);
owner->DrawString(fDeviceName, namePoint);
owner->SetFont(be_plain_font);
owner->DrawString(stateText, statePoint);
BPoint linePoint = bounds.LeftTop()
+ BPoint(stateIconWidth + (be_control_look->DefaultLabelSpacing() * 2),
fFirstLineOffset + fLineOffset);
owner->DrawString(fSubtitle, linePoint);
owner->PopState();
}
void
InterfaceListItem::Update(BView* owner, const BFont* font)
{
BListItem::Update(owner, font);
font_height height;
font->GetHeight(&height);
float lineHeight = ceilf(height.ascent) + ceilf(height.descent)
+ ceilf(height.leading);
fFirstLineOffset = 2 + ceilf(height.ascent + height.leading / 2);
fLineOffset = lineHeight;
_UpdateState();
SetWidth(fIcon->Bounds().Width() + 36
+ be_control_look->DefaultLabelSpacing()
+ be_bold_font->StringWidth(fDeviceName.String())
+ owner->StringWidth(_StateText()));
SetHeight(std::max(2 * lineHeight + 4, fIcon->Bounds().Height() + 4));
}
void
InterfaceListItem::ConfigurationUpdated(const BMessage& message)
{
_UpdateState();
}
void
InterfaceListItem::_Init()
{
switch (fType) {
case B_NETWORK_INTERFACE_TYPE_WIFI:
_PopulateBitmaps("wifi");
break;
case B_NETWORK_INTERFACE_TYPE_ETHERNET:
_PopulateBitmaps("ether");
break;
case B_NETWORK_INTERFACE_TYPE_VPN:
_PopulateBitmaps("vpn");
break;
case B_NETWORK_INTERFACE_TYPE_DIAL_UP:
_PopulateBitmaps("dialup");
break;
default:
_PopulateBitmaps(NULL);
break;
}
}
void
InterfaceListItem::_PopulateBitmaps(const char* mediaType)
{
const uint8* interfaceHVIF;
const uint8* offlineHVIF;
const uint8* pendingHVIF;
const uint8* onlineHVIF;
BBitmap* interfaceBitmap = NULL;
BBitmap* offlineBitmap = NULL;
BBitmap* pendingBitmap = NULL;
BBitmap* onlineBitmap = NULL;
BResources* resources = BApplication::AppResources();
size_t iconDataSize;
interfaceHVIF = (const uint8*)resources->LoadResource(
B_VECTOR_ICON_TYPE, Name(), &iconDataSize);
if (interfaceHVIF == NULL && mediaType != NULL)
interfaceHVIF = (const uint8*)resources->LoadResource(
B_VECTOR_ICON_TYPE, mediaType, &iconDataSize);
if (interfaceHVIF == NULL)
interfaceHVIF = (const uint8*)resources->LoadResource(
B_VECTOR_ICON_TYPE, "ether", &iconDataSize);
const BSize iconSize = be_control_look->ComposeIconSize(B_LARGE_ICON);
if (interfaceHVIF != NULL) {
interfaceBitmap = new(std::nothrow) BBitmap(
BRect(BPoint(0, 0), iconSize), 0, B_RGBA32);
if (BIconUtils::GetVectorIcon(interfaceHVIF,
iconDataSize, interfaceBitmap) == B_OK)
fIcon = interfaceBitmap;
else
delete interfaceBitmap;
}
offlineHVIF = (const uint8*)resources->LoadResource(
B_VECTOR_ICON_TYPE, "offline", &iconDataSize);
if (offlineHVIF != NULL) {
offlineBitmap = new(std::nothrow) BBitmap(
BRect(BPoint(0, 0), iconSize), 0, B_RGBA32);
if (BIconUtils::GetVectorIcon(offlineHVIF,
iconDataSize, offlineBitmap) == B_OK)
fIconOffline = offlineBitmap;
else
delete offlineBitmap;
}
pendingHVIF = (const uint8*)resources->LoadResource(
B_VECTOR_ICON_TYPE, "pending", &iconDataSize);
if (pendingHVIF != NULL) {
pendingBitmap = new(std::nothrow) BBitmap(
BRect(BPoint(0, 0), iconSize), 0, B_RGBA32);
if (BIconUtils::GetVectorIcon(pendingHVIF,
iconDataSize, pendingBitmap) == B_OK)
fIconPending = pendingBitmap;
else
delete pendingBitmap;
}
onlineHVIF = (const uint8*)resources->LoadResource(
B_VECTOR_ICON_TYPE, "online", &iconDataSize);
if (onlineHVIF != NULL) {
onlineBitmap = new(std::nothrow) BBitmap(
BRect(BPoint(0, 0), iconSize), 0, B_RGBA32);
if (BIconUtils::GetVectorIcon(onlineHVIF,
iconDataSize, onlineBitmap) == B_OK)
fIconOnline = onlineBitmap;
else
delete onlineBitmap;
}
}
void
InterfaceListItem::_UpdateState()
{
fDeviceName = Name();
fDeviceName.RemoveFirst("/dev/net/");
fDisabled = (fInterface.Flags() & IFF_UP) == 0;
fHasLink = fInterface.HasLink();
fConnecting = (fInterface.Flags() & IFF_CONFIGURING) != 0;
switch (fType) {
case B_NETWORK_INTERFACE_TYPE_WIFI:
fSubtitle = B_TRANSLATE("Wireless device");
break;
case B_NETWORK_INTERFACE_TYPE_ETHERNET:
fSubtitle = B_TRANSLATE("Ethernet device");
break;
case B_NETWORK_INTERFACE_TYPE_DIAL_UP:
fSubtitle = B_TRANSLATE("Dial-up connection");
fDisabled = false;
break;
case B_NETWORK_INTERFACE_TYPE_VPN:
fSubtitle = B_TRANSLATE("VPN connection");
fDisabled = false;
break;
default:
fSubtitle = "";
}
}
BBitmap*
InterfaceListItem::_StateIcon() const
{
if (fDisabled)
return fIconOffline;
if (!fHasLink)
return fIconOffline;
return fIconOnline;
}
const char*
InterfaceListItem::_StateText() const
{
if (fDisabled)
return B_TRANSLATE("disabled");
if (!fInterface.HasLink()) {
switch (fType) {
case B_NETWORK_INTERFACE_TYPE_VPN:
case B_NETWORK_INTERFACE_TYPE_DIAL_UP:
return B_TRANSLATE("disconnected");
default:
return B_TRANSLATE("no link");
}
}
return B_TRANSLATE("connected");
}