xref: /haiku/src/preferences/network/InterfaceListItem.cpp (revision 52c4471a3024d2eb81fe88e2c3982b9f8daa5e56)
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 		default:
176 		case B_NETWORK_INTERFACE_TYPE_WIFI:
177 			_PopulateBitmaps("wifi");
178 			break;
179 		case B_NETWORK_INTERFACE_TYPE_ETHERNET:
180 			_PopulateBitmaps("ether");
181 			break;
182 		case B_NETWORK_INTERFACE_TYPE_VPN:
183 			_PopulateBitmaps("vpn");
184 			break;
185 		case B_NETWORK_INTERFACE_TYPE_DIAL_UP:
186 			_PopulateBitmaps("dialup");
187 			break;
188 	}
189 }
190 
191 
192 void
193 InterfaceListItem::_PopulateBitmaps(const char* mediaType)
194 {
195 	const uint8* interfaceHVIF;
196 	const uint8* offlineHVIF;
197 	const uint8* pendingHVIF;
198 	const uint8* onlineHVIF;
199 
200 	BBitmap* interfaceBitmap = NULL;
201 	BBitmap* offlineBitmap = NULL;
202 	BBitmap* pendingBitmap = NULL;
203 	BBitmap* onlineBitmap = NULL;
204 
205 	BResources* resources = BApplication::AppResources();
206 
207 	size_t iconDataSize;
208 
209 	// Try specific interface icon?
210 	interfaceHVIF = (const uint8*)resources->LoadResource(
211 		B_VECTOR_ICON_TYPE, Name(), &iconDataSize);
212 
213 	if (interfaceHVIF == NULL && mediaType != NULL)
214 		// Not found, try interface media type?
215 		interfaceHVIF = (const uint8*)resources->LoadResource(
216 			B_VECTOR_ICON_TYPE, mediaType, &iconDataSize);
217 	if (interfaceHVIF == NULL)
218 		// Not found, try default interface icon?
219 		interfaceHVIF = (const uint8*)resources->LoadResource(
220 			B_VECTOR_ICON_TYPE, "ether", &iconDataSize);
221 
222 	const BSize iconSize = be_control_look->ComposeIconSize(B_LARGE_ICON);
223 	if (interfaceHVIF != NULL) {
224 		// Now build the bitmap
225 		interfaceBitmap = new(std::nothrow) BBitmap(
226 			BRect(BPoint(0, 0), iconSize), 0, B_RGBA32);
227 		if (BIconUtils::GetVectorIcon(interfaceHVIF,
228 				iconDataSize, interfaceBitmap) == B_OK)
229 			fIcon = interfaceBitmap;
230 		else
231 			delete interfaceBitmap;
232 	}
233 
234 	// Load possible state icons
235 	offlineHVIF = (const uint8*)resources->LoadResource(
236 		B_VECTOR_ICON_TYPE, "offline", &iconDataSize);
237 
238 	if (offlineHVIF != NULL) {
239 		offlineBitmap = new(std::nothrow) BBitmap(
240 			BRect(BPoint(0, 0), iconSize), 0, B_RGBA32);
241 		if (BIconUtils::GetVectorIcon(offlineHVIF,
242 				iconDataSize, offlineBitmap) == B_OK)
243 			fIconOffline = offlineBitmap;
244 		else
245 			delete offlineBitmap;
246 	}
247 
248 	pendingHVIF = (const uint8*)resources->LoadResource(
249 		B_VECTOR_ICON_TYPE, "pending", &iconDataSize);
250 
251 	if (pendingHVIF != NULL) {
252 		pendingBitmap = new(std::nothrow) BBitmap(
253 			BRect(BPoint(0, 0), iconSize), 0, B_RGBA32);
254 		if (BIconUtils::GetVectorIcon(pendingHVIF,
255 				iconDataSize, pendingBitmap) == B_OK)
256 			fIconPending = pendingBitmap;
257 		else
258 			delete pendingBitmap;
259 	}
260 
261 	onlineHVIF = (const uint8*)resources->LoadResource(
262 		B_VECTOR_ICON_TYPE, "online", &iconDataSize);
263 
264 	if (onlineHVIF != NULL) {
265 		onlineBitmap = new(std::nothrow) BBitmap(
266 			BRect(BPoint(0, 0), iconSize), 0, B_RGBA32);
267 		if (BIconUtils::GetVectorIcon(onlineHVIF,
268 				iconDataSize, onlineBitmap) == B_OK)
269 			fIconOnline = onlineBitmap;
270 		else
271 			delete onlineBitmap;
272 	}
273 }
274 
275 
276 void
277 InterfaceListItem::_UpdateState()
278 {
279 	fDeviceName = Name();
280 	fDeviceName.RemoveFirst("/dev/net/");
281 
282 	fDisabled = (fInterface.Flags() & IFF_UP) == 0;
283 	fHasLink = fInterface.HasLink();
284 	fConnecting = (fInterface.Flags() & IFF_CONFIGURING) != 0;
285 
286 	switch (fType) {
287 		case B_NETWORK_INTERFACE_TYPE_WIFI:
288 			fSubtitle = B_TRANSLATE("Wireless device");
289 			break;
290 		case B_NETWORK_INTERFACE_TYPE_ETHERNET:
291 			fSubtitle = B_TRANSLATE("Ethernet device");
292 			break;
293 		case B_NETWORK_INTERFACE_TYPE_DIAL_UP:
294 			fSubtitle = B_TRANSLATE("Dial-up connection");
295 			fDisabled = false;
296 			break;
297 		case B_NETWORK_INTERFACE_TYPE_VPN:
298 			fSubtitle = B_TRANSLATE("VPN connection");
299 			fDisabled = false;
300 			break;
301 		default:
302 			fSubtitle = "";
303 	}
304 }
305 
306 
307 BBitmap*
308 InterfaceListItem::_StateIcon() const
309 {
310 	if (fDisabled)
311 		return fIconOffline;
312 	if (!fHasLink)
313 		return fIconOffline;
314 	// TODO!
315 //	} else if ((fSettings->IPAddr(AF_INET).IsEmpty()
316 //		&& fSettings->IPAddr(AF_INET6).IsEmpty())
317 //		&& (fSettings->AutoConfigure(AF_INET)
318 //		|| fSettings->AutoConfigure(AF_INET6))) {
319 //		interfaceState = "connecting" B_UTF8_ELLIPSIS;
320 //		stateIcon = fIconPending;
321 
322 	return fIconOnline;
323 }
324 
325 
326 const char*
327 InterfaceListItem::_StateText() const
328 {
329 	if (fDisabled)
330 		return B_TRANSLATE("disabled");
331 
332 	if (!fInterface.HasLink()) {
333 		switch (fType) {
334 			case B_NETWORK_INTERFACE_TYPE_VPN:
335 			case B_NETWORK_INTERFACE_TYPE_DIAL_UP:
336 				return B_TRANSLATE("disconnected");
337 			default:
338 				return B_TRANSLATE("no link");
339 		}
340 	}
341 
342 	// TODO!
343 //	} else if ((fSettings->IPAddr(AF_INET).IsEmpty()
344 //		&& fSettings->IPAddr(AF_INET6).IsEmpty())
345 //		&& (fSettings->AutoConfigure(AF_INET)
346 //		|| fSettings->AutoConfigure(AF_INET6))) {
347 //		interfaceState = "connecting" B_UTF8_ELLIPSIS;
348 //		stateIcon = fIconPending;
349 
350 	return B_TRANSLATE("connected");
351 }
352