xref: /haiku/src/preferences/network/InterfaceListItem.cpp (revision 9642f7705b27e5c270c15fa526d14e1848c2c27d)
1 /*
2  * Copyright 2004-2015 Haiku, Inc. All rights reserved.
3  * Distributed under the terms of the MIT License.
4  *
5  * Authors:
6  *		Alexander von Gluck IV, kallisti5@unixzen.com
7  *		Philippe Houdoin
8  * 		Fredrik Modéen
9  *		John Scipione, jscipione@gmail.com
10  */
11 
12 
13 #include "InterfaceListItem.h"
14 
15 #include <algorithm>
16 
17 #include <Application.h>
18 #include <Bitmap.h>
19 #include <Catalog.h>
20 #include <ControlLook.h>
21 #include <IconUtils.h>
22 #include <OutlineListView.h>
23 #include <Resources.h>
24 #include <String.h>
25 
26 
27 #define ICON_SIZE 32
28 
29 
30 #undef B_TRANSLATION_CONTEXT
31 #define B_TRANSLATION_CONTEXT "InterfaceListItem"
32 
33 
34 InterfaceListItem::InterfaceListItem(const char* name,
35 	BNetworkInterfaceType type)
36 	:
37 	BListItem(0, false),
38 	fType(type),
39 	fIcon(NULL),
40 	fFirstLineOffset(0),
41 	fLineOffset(0),
42 	fDisabled(false),
43 	fHasLink(false),
44 	fConnecting(false)
45 {
46 	fInterface.SetTo(name);
47 	_Init();
48 }
49 
50 
51 InterfaceListItem::~InterfaceListItem()
52 {
53 	delete fIcon;
54 }
55 
56 
57 // #pragma mark - InterfaceListItem public methods
58 
59 
60 void
61 InterfaceListItem::DrawItem(BView* owner, BRect bounds, bool complete)
62 {
63 	owner->PushState();
64 
65 	rgb_color lowColor = owner->LowColor();
66 
67 	if (IsSelected() || complete) {
68 		if (IsSelected()) {
69 			owner->SetHighColor(ui_color(B_LIST_SELECTED_BACKGROUND_COLOR));
70 			owner->SetLowColor(owner->HighColor());
71 		} else
72 			owner->SetHighColor(lowColor);
73 
74 		owner->FillRect(bounds);
75 	}
76 
77 	BBitmap* stateIcon = _StateIcon();
78 	const char* stateText = _StateText();
79 
80 	// Set the initial bounds of item contents
81 	BPoint iconPoint = bounds.LeftTop()
82 		+ BPoint(be_control_look->DefaultLabelSpacing(), 2);
83 	BPoint statePoint = bounds.RightTop() + BPoint(0, fFirstLineOffset)
84 		- BPoint(be_plain_font->StringWidth(stateText)
85 			+ be_control_look->DefaultLabelSpacing(), 0);
86 	BPoint namePoint = bounds.LeftTop()
87 		+ BPoint(ICON_SIZE + (be_control_look->DefaultLabelSpacing() * 2),
88 		fFirstLineOffset);
89 
90 	if (fDisabled) {
91 		owner->SetDrawingMode(B_OP_ALPHA);
92 		owner->SetBlendingMode(B_CONSTANT_ALPHA, B_ALPHA_OVERLAY);
93 		owner->SetHighColor(0, 0, 0, 32);
94 	} else
95 		owner->SetDrawingMode(B_OP_OVER);
96 
97 	owner->DrawBitmapAsync(fIcon, iconPoint);
98 	owner->DrawBitmapAsync(stateIcon, iconPoint);
99 
100 	if (fDisabled) {
101 		rgb_color textColor;
102 		if (IsSelected())
103 			textColor = ui_color(B_LIST_SELECTED_ITEM_TEXT_COLOR);
104 		else
105 			textColor = ui_color(B_LIST_ITEM_TEXT_COLOR);
106 
107 		if (textColor.red + textColor.green + textColor.blue > 128 * 3)
108 			owner->SetHighColor(tint_color(textColor, B_DARKEN_1_TINT));
109 		else
110 			owner->SetHighColor(tint_color(textColor, B_LIGHTEN_1_TINT));
111 	} else {
112 		if (IsSelected())
113 			owner->SetHighColor(ui_color(B_LIST_SELECTED_ITEM_TEXT_COLOR));
114 		else
115 			owner->SetHighColor(ui_color(B_LIST_ITEM_TEXT_COLOR));
116 	}
117 
118 	owner->SetFont(be_bold_font);
119 
120 	owner->DrawString(fDeviceName, namePoint);
121 	owner->SetFont(be_plain_font);
122 	owner->DrawString(stateText, statePoint);
123 
124 	BPoint linePoint = bounds.LeftTop()
125 		+ BPoint(ICON_SIZE + (be_control_look->DefaultLabelSpacing() * 2),
126 		fFirstLineOffset + fLineOffset);
127 	owner->DrawString(fSubtitle, linePoint);
128 
129 	owner->PopState();
130 }
131 
132 
133 void
134 InterfaceListItem::Update(BView* owner, const BFont* font)
135 {
136 	BListItem::Update(owner, font);
137 	font_height height;
138 	font->GetHeight(&height);
139 
140 	float lineHeight = ceilf(height.ascent) + ceilf(height.descent)
141 		+ ceilf(height.leading);
142 
143 	fFirstLineOffset = 2 + ceilf(height.ascent + height.leading / 2);
144 	fLineOffset = lineHeight;
145 
146 	_UpdateState();
147 
148 	SetWidth(fIcon->Bounds().Width() + 36
149 		+ be_control_look->DefaultLabelSpacing()
150 		+ be_bold_font->StringWidth(fDeviceName.String())
151 		+ owner->StringWidth(_StateText()));
152 	SetHeight(std::max(2 * lineHeight + 4, fIcon->Bounds().Height() + 4));
153 		// either to the text height or icon height, whichever is taller
154 }
155 
156 
157 void
158 InterfaceListItem::ConfigurationUpdated(const BMessage& message)
159 {
160 	_UpdateState();
161 }
162 
163 
164 // #pragma mark - InterfaceListItem private methods
165 
166 
167 void
168 InterfaceListItem::_Init()
169 {
170 	switch(fType) {
171 		default:
172 		case B_NETWORK_INTERFACE_TYPE_WIFI:
173 			_PopulateBitmaps("wifi");
174 			break;
175 		case B_NETWORK_INTERFACE_TYPE_ETHERNET:
176 			_PopulateBitmaps("ether");
177 			break;
178 	}
179 }
180 
181 
182 void
183 InterfaceListItem::_PopulateBitmaps(const char* mediaType)
184 {
185 	const uint8* interfaceHVIF;
186 	const uint8* offlineHVIF;
187 	const uint8* pendingHVIF;
188 	const uint8* onlineHVIF;
189 
190 	BBitmap* interfaceBitmap = NULL;
191 
192 	BResources* resources = BApplication::AppResources();
193 
194 	size_t iconSize;
195 
196 	// Try specific interface icon?
197 	interfaceHVIF = (const uint8*)resources->LoadResource(
198 		B_VECTOR_ICON_TYPE, Name(), &iconSize);
199 
200 	if (interfaceHVIF == NULL && mediaType != NULL)
201 		// Not found, try interface media type?
202 		interfaceHVIF = (const uint8*)resources->LoadResource(
203 			B_VECTOR_ICON_TYPE, mediaType, &iconSize);
204 	if (interfaceHVIF == NULL)
205 		// Not found, try default interface icon?
206 		interfaceHVIF = (const uint8*)resources->LoadResource(
207 			B_VECTOR_ICON_TYPE, "ether", &iconSize);
208 
209 	if (interfaceHVIF) {
210 		// Now build the bitmap
211 		interfaceBitmap = new BBitmap(BRect(0, 0, ICON_SIZE, ICON_SIZE),
212 			0, B_RGBA32);
213 		if (BIconUtils::GetVectorIcon(interfaceHVIF,
214 			iconSize, interfaceBitmap) == B_OK)
215 			fIcon = interfaceBitmap;
216 		else
217 			delete interfaceBitmap;
218 	}
219 
220 	// Load possible state icons
221 	offlineHVIF = (const uint8*)resources->LoadResource(
222 		B_VECTOR_ICON_TYPE, "offline", &iconSize);
223 
224 	if (offlineHVIF) {
225 		fIconOffline = new BBitmap(BRect(0, 0, ICON_SIZE, ICON_SIZE),
226 			0, B_RGBA32);
227 		BIconUtils::GetVectorIcon(offlineHVIF, iconSize, fIconOffline);
228 	}
229 
230 	pendingHVIF = (const uint8*)resources->LoadResource(
231 		B_VECTOR_ICON_TYPE, "pending", &iconSize);
232 
233 	if (pendingHVIF) {
234 		fIconPending = new BBitmap(BRect(0, 0, ICON_SIZE, ICON_SIZE),
235 			0, B_RGBA32);
236 		BIconUtils::GetVectorIcon(pendingHVIF, iconSize, fIconPending);
237 	}
238 
239 	onlineHVIF = (const uint8*)resources->LoadResource(
240 		B_VECTOR_ICON_TYPE, "online", &iconSize);
241 
242 	if (onlineHVIF) {
243 		fIconOnline = new BBitmap(BRect(0, 0, ICON_SIZE, ICON_SIZE),
244 			0, B_RGBA32);
245 		BIconUtils::GetVectorIcon(onlineHVIF, iconSize, fIconOnline);
246 	}
247 }
248 
249 
250 void
251 InterfaceListItem::_UpdateState()
252 {
253 	fDeviceName = Name();
254 	fDeviceName.RemoveFirst("/dev/net/");
255 
256 	fDisabled = (fInterface.Flags() & IFF_UP) == 0;
257 	fHasLink = fInterface.HasLink();
258 	fConnecting = (fInterface.Flags() & IFF_CONFIGURING) != 0;
259 
260 	switch (fType) {
261 		case B_NETWORK_INTERFACE_TYPE_WIFI:
262 			fSubtitle = B_TRANSLATE("Wireless device");
263 			break;
264 		case B_NETWORK_INTERFACE_TYPE_ETHERNET:
265 			fSubtitle = B_TRANSLATE("Ethernet device");
266 			break;
267 		case B_NETWORK_INTERFACE_TYPE_DIAL_UP:
268 			fSubtitle = B_TRANSLATE("Dial-up connection");
269 			break;
270 		case B_NETWORK_INTERFACE_TYPE_VPN:
271 			fSubtitle = B_TRANSLATE("VPN connection");
272 			break;
273 		default:
274 			fSubtitle = "";
275 	}
276 }
277 
278 
279 BBitmap*
280 InterfaceListItem::_StateIcon() const
281 {
282 	if (fDisabled)
283 		return fIconOffline;
284 	if (!fHasLink)
285 		return fIconOffline;
286 	// TODO!
287 //	} else if ((fSettings->IPAddr(AF_INET).IsEmpty()
288 //		&& fSettings->IPAddr(AF_INET6).IsEmpty())
289 //		&& (fSettings->AutoConfigure(AF_INET)
290 //		|| fSettings->AutoConfigure(AF_INET6))) {
291 //		interfaceState = "connecting" B_UTF8_ELLIPSIS;
292 //		stateIcon = fIconPending;
293 
294 	return fIconOnline;
295 }
296 
297 
298 const char*
299 InterfaceListItem::_StateText() const
300 {
301 	if (fDisabled)
302 		return B_TRANSLATE("disabled");
303 	if (!fInterface.HasLink())
304 		return B_TRANSLATE("no link");
305 
306 	// TODO!
307 //	} else if ((fSettings->IPAddr(AF_INET).IsEmpty()
308 //		&& fSettings->IPAddr(AF_INET6).IsEmpty())
309 //		&& (fSettings->AutoConfigure(AF_INET)
310 //		|| fSettings->AutoConfigure(AF_INET6))) {
311 //		interfaceState = "connecting" B_UTF8_ELLIPSIS;
312 //		stateIcon = fIconPending;
313 
314 	return B_TRANSLATE("connected");
315 }
316