xref: /haiku/src/preferences/network/InterfaceListItem.cpp (revision 7aa55747139506809789e3048dbee94bb9437437)
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 	fIconOffline(NULL),
41 	fIconPending(NULL),
42 	fIconOnline(NULL),
43 	fFirstLineOffset(0),
44 	fLineOffset(0),
45 	fDisabled(false),
46 	fHasLink(false),
47 	fConnecting(false)
48 {
49 	fInterface.SetTo(name);
50 	_Init();
51 }
52 
53 
54 InterfaceListItem::~InterfaceListItem()
55 {
56 	delete fIcon;
57 	delete fIconOffline;
58 	delete fIconPending;
59 	delete fIconOnline;
60 }
61 
62 
63 // #pragma mark - InterfaceListItem public methods
64 
65 
66 void
67 InterfaceListItem::DrawItem(BView* owner, BRect bounds, bool complete)
68 {
69 	owner->PushState();
70 
71 	rgb_color lowColor = owner->LowColor();
72 
73 	if (IsSelected() || complete) {
74 		if (IsSelected()) {
75 			owner->SetHighColor(ui_color(B_LIST_SELECTED_BACKGROUND_COLOR));
76 			owner->SetLowColor(owner->HighColor());
77 		} else
78 			owner->SetHighColor(lowColor);
79 
80 		owner->FillRect(bounds);
81 	}
82 
83 	BBitmap* stateIcon = _StateIcon();
84 	const char* stateText = _StateText();
85 
86 	// Set the initial bounds of item contents
87 	BPoint iconPoint = bounds.LeftTop()
88 		+ BPoint(be_control_look->DefaultLabelSpacing(), 2);
89 	BPoint statePoint = bounds.RightTop() + BPoint(0, fFirstLineOffset)
90 		- BPoint(be_plain_font->StringWidth(stateText)
91 			+ be_control_look->DefaultLabelSpacing(), 0);
92 	BPoint namePoint = bounds.LeftTop()
93 		+ BPoint(ICON_SIZE + (be_control_look->DefaultLabelSpacing() * 2),
94 		fFirstLineOffset);
95 
96 	if (fDisabled) {
97 		owner->SetDrawingMode(B_OP_ALPHA);
98 		owner->SetBlendingMode(B_CONSTANT_ALPHA, B_ALPHA_OVERLAY);
99 		owner->SetHighColor(0, 0, 0, 32);
100 	} else
101 		owner->SetDrawingMode(B_OP_OVER);
102 
103 	owner->DrawBitmapAsync(fIcon, iconPoint);
104 	owner->DrawBitmapAsync(stateIcon, iconPoint);
105 
106 	if (fDisabled) {
107 		rgb_color textColor;
108 		if (IsSelected())
109 			textColor = ui_color(B_LIST_SELECTED_ITEM_TEXT_COLOR);
110 		else
111 			textColor = ui_color(B_LIST_ITEM_TEXT_COLOR);
112 
113 		if (textColor.red + textColor.green + textColor.blue > 128 * 3)
114 			owner->SetHighColor(tint_color(textColor, B_DARKEN_1_TINT));
115 		else
116 			owner->SetHighColor(tint_color(textColor, B_LIGHTEN_1_TINT));
117 	} else {
118 		if (IsSelected())
119 			owner->SetHighColor(ui_color(B_LIST_SELECTED_ITEM_TEXT_COLOR));
120 		else
121 			owner->SetHighColor(ui_color(B_LIST_ITEM_TEXT_COLOR));
122 	}
123 
124 	owner->SetFont(be_bold_font);
125 
126 	owner->DrawString(fDeviceName, namePoint);
127 	owner->SetFont(be_plain_font);
128 	owner->DrawString(stateText, statePoint);
129 
130 	BPoint linePoint = bounds.LeftTop()
131 		+ BPoint(ICON_SIZE + (be_control_look->DefaultLabelSpacing() * 2),
132 		fFirstLineOffset + fLineOffset);
133 	owner->DrawString(fSubtitle, linePoint);
134 
135 	owner->PopState();
136 }
137 
138 
139 void
140 InterfaceListItem::Update(BView* owner, const BFont* font)
141 {
142 	BListItem::Update(owner, font);
143 	font_height height;
144 	font->GetHeight(&height);
145 
146 	float lineHeight = ceilf(height.ascent) + ceilf(height.descent)
147 		+ ceilf(height.leading);
148 
149 	fFirstLineOffset = 2 + ceilf(height.ascent + height.leading / 2);
150 	fLineOffset = lineHeight;
151 
152 	_UpdateState();
153 
154 	SetWidth(fIcon->Bounds().Width() + 36
155 		+ be_control_look->DefaultLabelSpacing()
156 		+ be_bold_font->StringWidth(fDeviceName.String())
157 		+ owner->StringWidth(_StateText()));
158 	SetHeight(std::max(2 * lineHeight + 4, fIcon->Bounds().Height() + 4));
159 		// either to the text height or icon height, whichever is taller
160 }
161 
162 
163 void
164 InterfaceListItem::ConfigurationUpdated(const BMessage& message)
165 {
166 	_UpdateState();
167 }
168 
169 
170 // #pragma mark - InterfaceListItem private methods
171 
172 
173 void
174 InterfaceListItem::_Init()
175 {
176 	switch(fType) {
177 		default:
178 		case B_NETWORK_INTERFACE_TYPE_WIFI:
179 			_PopulateBitmaps("wifi");
180 			break;
181 		case B_NETWORK_INTERFACE_TYPE_ETHERNET:
182 			_PopulateBitmaps("ether");
183 			break;
184 		case B_NETWORK_INTERFACE_TYPE_VPN:
185 			_PopulateBitmaps("vpn");
186 			break;
187 		case B_NETWORK_INTERFACE_TYPE_DIAL_UP:
188 			_PopulateBitmaps("dialup");
189 			break;
190 	}
191 }
192 
193 
194 void
195 InterfaceListItem::_PopulateBitmaps(const char* mediaType)
196 {
197 	const uint8* interfaceHVIF;
198 	const uint8* offlineHVIF;
199 	const uint8* pendingHVIF;
200 	const uint8* onlineHVIF;
201 
202 	BBitmap* interfaceBitmap = NULL;
203 	BBitmap* offlineBitmap = NULL;
204 	BBitmap* pendingBitmap = NULL;
205 	BBitmap* onlineBitmap = NULL;
206 
207 	BResources* resources = BApplication::AppResources();
208 
209 	size_t iconSize;
210 
211 	// Try specific interface icon?
212 	interfaceHVIF = (const uint8*)resources->LoadResource(
213 		B_VECTOR_ICON_TYPE, Name(), &iconSize);
214 
215 	if (interfaceHVIF == NULL && mediaType != NULL)
216 		// Not found, try interface media type?
217 		interfaceHVIF = (const uint8*)resources->LoadResource(
218 			B_VECTOR_ICON_TYPE, mediaType, &iconSize);
219 	if (interfaceHVIF == NULL)
220 		// Not found, try default interface icon?
221 		interfaceHVIF = (const uint8*)resources->LoadResource(
222 			B_VECTOR_ICON_TYPE, "ether", &iconSize);
223 
224 	if (interfaceHVIF != NULL) {
225 		// Now build the bitmap
226 		interfaceBitmap = new(std::nothrow) BBitmap(
227 			BRect(0, 0, ICON_SIZE, ICON_SIZE), 0, B_RGBA32);
228 		if (BIconUtils::GetVectorIcon(interfaceHVIF,
229 				iconSize, interfaceBitmap) == B_OK)
230 			fIcon = interfaceBitmap;
231 		else
232 			delete interfaceBitmap;
233 	}
234 
235 	// Load possible state icons
236 	offlineHVIF = (const uint8*)resources->LoadResource(
237 		B_VECTOR_ICON_TYPE, "offline", &iconSize);
238 
239 	if (offlineHVIF != NULL) {
240 		offlineBitmap = new(std::nothrow) BBitmap(
241 			BRect(0, 0, ICON_SIZE, ICON_SIZE), 0, B_RGBA32);
242 		if (BIconUtils::GetVectorIcon(offlineHVIF,
243 				iconSize, offlineBitmap) == B_OK)
244 			fIconOffline = offlineBitmap;
245 		else
246 			delete offlineBitmap;
247 	}
248 
249 	pendingHVIF = (const uint8*)resources->LoadResource(
250 		B_VECTOR_ICON_TYPE, "pending", &iconSize);
251 
252 	if (pendingHVIF != NULL) {
253 		pendingBitmap = new(std::nothrow) BBitmap(
254 			BRect(0, 0, ICON_SIZE, ICON_SIZE), 0, B_RGBA32);
255 		if (BIconUtils::GetVectorIcon(pendingHVIF,
256 				iconSize, pendingBitmap) == B_OK)
257 			fIconPending = pendingBitmap;
258 		else
259 			delete pendingBitmap;
260 	}
261 
262 	onlineHVIF = (const uint8*)resources->LoadResource(
263 		B_VECTOR_ICON_TYPE, "online", &iconSize);
264 
265 	if (onlineHVIF != NULL) {
266 		onlineBitmap = new(std::nothrow) BBitmap(
267 			BRect(0, 0, ICON_SIZE, ICON_SIZE), 0, B_RGBA32);
268 		if (BIconUtils::GetVectorIcon(onlineHVIF,
269 				iconSize, onlineBitmap) == B_OK)
270 			fIconOnline = onlineBitmap;
271 		else
272 			delete onlineBitmap;
273 	}
274 }
275 
276 
277 void
278 InterfaceListItem::_UpdateState()
279 {
280 	fDeviceName = Name();
281 	fDeviceName.RemoveFirst("/dev/net/");
282 
283 	fDisabled = (fInterface.Flags() & IFF_UP) == 0;
284 	fHasLink = fInterface.HasLink();
285 	fConnecting = (fInterface.Flags() & IFF_CONFIGURING) != 0;
286 
287 	switch (fType) {
288 		case B_NETWORK_INTERFACE_TYPE_WIFI:
289 			fSubtitle = B_TRANSLATE("Wireless device");
290 			break;
291 		case B_NETWORK_INTERFACE_TYPE_ETHERNET:
292 			fSubtitle = B_TRANSLATE("Ethernet device");
293 			break;
294 		case B_NETWORK_INTERFACE_TYPE_DIAL_UP:
295 			fSubtitle = B_TRANSLATE("Dial-up connection");
296 			fDisabled = false;
297 			break;
298 		case B_NETWORK_INTERFACE_TYPE_VPN:
299 			fSubtitle = B_TRANSLATE("VPN connection");
300 			fDisabled = false;
301 			break;
302 		default:
303 			fSubtitle = "";
304 	}
305 }
306 
307 
308 BBitmap*
309 InterfaceListItem::_StateIcon() const
310 {
311 	if (fDisabled)
312 		return fIconOffline;
313 	if (!fHasLink)
314 		return fIconOffline;
315 	// TODO!
316 //	} else if ((fSettings->IPAddr(AF_INET).IsEmpty()
317 //		&& fSettings->IPAddr(AF_INET6).IsEmpty())
318 //		&& (fSettings->AutoConfigure(AF_INET)
319 //		|| fSettings->AutoConfigure(AF_INET6))) {
320 //		interfaceState = "connecting" B_UTF8_ELLIPSIS;
321 //		stateIcon = fIconPending;
322 
323 	return fIconOnline;
324 }
325 
326 
327 const char*
328 InterfaceListItem::_StateText() const
329 {
330 	if (fDisabled)
331 		return B_TRANSLATE("disabled");
332 
333 	if (!fInterface.HasLink()) {
334 		switch (fType) {
335 			case B_NETWORK_INTERFACE_TYPE_VPN:
336 			case B_NETWORK_INTERFACE_TYPE_DIAL_UP:
337 				return B_TRANSLATE("disconnected");
338 			default:
339 				return B_TRANSLATE("no link");
340 		}
341 	}
342 
343 	// TODO!
344 //	} else if ((fSettings->IPAddr(AF_INET).IsEmpty()
345 //		&& fSettings->IPAddr(AF_INET6).IsEmpty())
346 //		&& (fSettings->AutoConfigure(AF_INET)
347 //		|| fSettings->AutoConfigure(AF_INET6))) {
348 //		interfaceState = "connecting" B_UTF8_ELLIPSIS;
349 //		stateIcon = fIconPending;
350 
351 	return B_TRANSLATE("connected");
352 }
353