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