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