xref: /haiku/src/preferences/network/InterfaceView.cpp (revision a5a3b2d9a3d95cbae71eaf371708c73a1780ac0d)
1 /*
2  * Copyright 2004-2015 Haiku, Inc. All rights reserved.
3  * Distributed under the terms of the MIT License.
4  *
5  * Authors:
6  *		Axel Dörfler, <axeld@pinc-software.de>
7  *		Alexander von Gluck, kallisti5@unixzen.com
8  *		John Scipione, jscipione@gmail.com
9  */
10 
11 
12 #include "InterfaceView.h"
13 
14 #include <set>
15 
16 #include <net/if_media.h>
17 
18 #include <Button.h>
19 #include <Catalog.h>
20 #include <ControlLook.h>
21 #include <LayoutBuilder.h>
22 #include <NetworkAddress.h>
23 #include <NetworkDevice.h>
24 #include <StringForSize.h>
25 #include <StringView.h>
26 #include <TextControl.h>
27 
28 #include "MediaTypes.h"
29 #include "WirelessNetworkMenuItem.h"
30 
31 
32 static const uint32 kMsgInterfaceToggle = 'onof';
33 static const uint32 kMsgInterfaceRenegotiate = 'redo';
34 static const uint32 kMsgJoinNetwork = 'join';
35 
36 
37 #undef B_TRANSLATION_CONTEXT
38 #define B_TRANSLATION_CONTEXT "IntefaceView"
39 
40 
41 // #pragma mark - InterfaceView
42 
43 
44 InterfaceView::InterfaceView()
45 	:
46 	BGroupView(B_VERTICAL),
47 	fPulseCount(0)
48 {
49 	SetFlags(Flags() | B_PULSE_NEEDED);
50 
51 	// TODO: Small graph of throughput?
52 
53 	float minimumWidth = be_control_look->DefaultItemSpacing() * 16;
54 
55 	BStringView* statusLabel = new BStringView("status label",
56 		B_TRANSLATE("Status:"));
57 	statusLabel->SetAlignment(B_ALIGN_RIGHT);
58 	fStatusField = new BStringView("status field", "");
59 	fStatusField->SetExplicitMinSize(BSize(minimumWidth, B_SIZE_UNSET));
60 	BStringView* macAddressLabel = new BStringView("mac address label",
61 		B_TRANSLATE("MAC address:"));
62 	macAddressLabel->SetAlignment(B_ALIGN_RIGHT);
63 	fMacAddressField = new BStringView("mac address field", "");
64 	fMacAddressField->SetExplicitMinSize(BSize(minimumWidth, B_SIZE_UNSET));
65 	BStringView* linkSpeedLabel = new BStringView("link speed label",
66 		B_TRANSLATE("Link speed:"));
67 	linkSpeedLabel->SetAlignment(B_ALIGN_RIGHT);
68 	fLinkSpeedField = new BStringView("link speed field", "");
69 	fLinkSpeedField->SetExplicitMinSize(BSize(minimumWidth, B_SIZE_UNSET));
70 
71 	// TODO: These metrics may be better in a BScrollView?
72 	BStringView* linkTxLabel = new BStringView("tx label",
73 		B_TRANSLATE("Sent:"));
74 	linkTxLabel->SetAlignment(B_ALIGN_RIGHT);
75 	fLinkTxField = new BStringView("tx field", "");
76 	fLinkTxField ->SetExplicitMinSize(BSize(minimumWidth, B_SIZE_UNSET));
77 	BStringView* linkRxLabel = new BStringView("rx label",
78 		B_TRANSLATE("Received:"));
79 	linkRxLabel->SetAlignment(B_ALIGN_RIGHT);
80 	fLinkRxField = new BStringView("rx field", "");
81 	fLinkRxField ->SetExplicitMinSize(BSize(minimumWidth, B_SIZE_UNSET));
82 
83 	fNetworkMenuField = new BMenuField(B_TRANSLATE("Network:"), new BMenu(
84 		B_TRANSLATE("Choose automatically")));
85 	fNetworkMenuField->SetAlignment(B_ALIGN_RIGHT);
86 	fNetworkMenuField->Menu()->SetLabelFromMarked(true);
87 
88 	// Construct the BButtons
89 	fToggleButton = new BButton("onoff", B_TRANSLATE("Disable"),
90 		new BMessage(kMsgInterfaceToggle));
91 
92 	fRenegotiateButton = new BButton("heal", B_TRANSLATE("Renegotiate"),
93 		new BMessage(kMsgInterfaceRenegotiate));
94 	fRenegotiateButton->SetEnabled(false);
95 
96 	BLayoutBuilder::Group<>(this)
97 		.AddGrid()
98 			.Add(statusLabel, 0, 0)
99 			.Add(fStatusField, 1, 0)
100 			.Add(fNetworkMenuField->CreateLabelLayoutItem(), 0, 1)
101 			.Add(fNetworkMenuField->CreateMenuBarLayoutItem(), 1, 1)
102 			.Add(macAddressLabel, 0, 2)
103 			.Add(fMacAddressField, 1, 2)
104 			.Add(linkSpeedLabel, 0, 3)
105 			.Add(fLinkSpeedField, 1, 3)
106 			.Add(linkTxLabel, 0, 4)
107 			.Add(fLinkTxField, 1, 4)
108 			.Add(linkRxLabel, 0, 5)
109 			.Add(fLinkRxField, 1, 5)
110 		.End()
111 		.AddGlue()
112 		.AddGroup(B_HORIZONTAL)
113 			.AddGlue()
114 			.Add(fToggleButton)
115 			.Add(fRenegotiateButton)
116 		.End();
117 }
118 
119 
120 InterfaceView::~InterfaceView()
121 {
122 }
123 
124 
125 void
126 InterfaceView::SetTo(const char* name)
127 {
128 	fInterface.SetTo(name);
129 }
130 
131 
132 void
133 InterfaceView::AttachedToWindow()
134 {
135 	_Update();
136 		// Populate the fields
137 
138 	fToggleButton->SetTarget(this);
139 	fRenegotiateButton->SetTarget(this);
140 }
141 
142 
143 void
144 InterfaceView::MessageReceived(BMessage* message)
145 {
146 	switch (message->what) {
147 		case kMsgJoinNetwork:
148 		{
149 			const char* name;
150 			BNetworkAddress address;
151 			if (message->FindString("name", &name) == B_OK
152 				&& message->FindFlat("address", &address) == B_OK) {
153 				BNetworkDevice device(fInterface.Name());
154 				status_t status = device.JoinNetwork(address);
155 				if (status != B_OK) {
156 					// This does not really matter, as it's stored this way,
157 					// anyway.
158 				}
159 				// TODO: store value
160 			}
161 			break;
162 		}
163 		case kMsgInterfaceToggle:
164 		{
165 			// Disable/enable interface
166 			uint32 flags = fInterface.Flags();
167 			if ((flags & IFF_UP) != 0)
168 				flags &= ~IFF_UP;
169 			else
170 				flags |= IFF_UP;
171 
172 			if (fInterface.SetFlags(flags) == B_OK)
173 				_Update();
174 			break;
175 		}
176 
177 		case kMsgInterfaceRenegotiate:
178 		{
179 			// TODO: renegotiate addresses
180 			break;
181 		}
182 
183 		default:
184 			BView::MessageReceived(message);
185 	}
186 }
187 
188 
189 void
190 InterfaceView::Pulse()
191 {
192 	// Update the wireless network menu every 5 seconds
193 	_Update((fPulseCount++ % 5) == 0);
194 }
195 
196 
197 /*!	Populate fields with current settings.
198 */
199 status_t
200 InterfaceView::_Update(bool updateWirelessNetworks)
201 {
202 	BNetworkDevice device(fInterface.Name());
203 	bool isWireless = device.IsWireless();
204 	bool disabled = (fInterface.Flags() & IFF_UP) == 0;
205 
206 	if (fInterface.HasLink()) {
207 		if (isWireless) {
208 			// TODO!
209 			BString network = "---";
210 			network.Prepend(" (");
211 			network.Prepend(B_TRANSLATE("connected"));
212 			network.Append(")");
213 			fStatusField->SetText(network.String());
214 		} else {
215 			fStatusField->SetText(B_TRANSLATE("connected"));
216 		}
217 	} else
218 		fStatusField->SetText(B_TRANSLATE("disconnected"));
219 
220 	BNetworkAddress hardwareAddress;
221 	if (device.GetHardwareAddress(hardwareAddress) == B_OK)
222 		fMacAddressField->SetText(hardwareAddress.ToString());
223 	else
224 		fMacAddressField->SetText("-");
225 
226 	int media = fInterface.Media();
227 	if ((media & IFM_ACTIVE) != 0)
228 		fLinkSpeedField->SetText(media_type_to_string(media));
229 	else
230 		fLinkSpeedField->SetText("-");
231 
232 	// Update Link stats
233 	ifreq_stats stats;
234 	if (fInterface.GetStats(stats) == B_OK) {
235 		char buffer[100];
236 
237 		string_for_size(stats.send.bytes, buffer, sizeof(buffer));
238 		fLinkTxField->SetText(buffer);
239 
240 		string_for_size(stats.receive.bytes, buffer, sizeof(buffer));
241 		fLinkRxField->SetText(buffer);
242 	}
243 
244 	// TODO: move the wireless info to a separate tab. We should have a
245 	// BListView of available networks, rather than a menu, to make them more
246 	// readable and easier to browse and select.
247 	if (fNetworkMenuField->IsHidden(fNetworkMenuField) && isWireless)
248 		fNetworkMenuField->Show();
249 	else if (!fNetworkMenuField->IsHidden(fNetworkMenuField) && !isWireless)
250 		fNetworkMenuField->Hide();
251 
252 	if (isWireless && updateWirelessNetworks) {
253 		// Rebuild network menu
254 		BMenu* menu = fNetworkMenuField->Menu();
255 		menu->RemoveItems(0, menu->CountItems(), true);
256 
257 		std::set<BNetworkAddress> associated;
258 		BNetworkAddress address;
259 		uint32 cookie = 0;
260 		while (device.GetNextAssociatedNetwork(cookie, address) == B_OK)
261 			associated.insert(address);
262 
263 		wireless_network network;
264 		int32 count = 0;
265 		cookie = 0;
266 		while (device.GetNextNetwork(cookie, network) == B_OK) {
267 			BMessage* message = new BMessage(kMsgJoinNetwork);
268 
269 			message->AddString("device", fInterface.Name());
270 			message->AddString("name", network.name);
271 			message->AddFlat("address", &network.address);
272 
273 			BMenuItem* item = new WirelessNetworkMenuItem(network.name,
274 				network.signal_strength,
275 				network.authentication_mode, message);
276 			if (associated.find(network.address) != associated.end())
277 				item->SetMarked(true);
278 			menu->AddItem(item);
279 
280 			count++;
281 		}
282 		if (count == 0) {
283 			BMenuItem* item = new BMenuItem(
284 				B_TRANSLATE("<no wireless networks found>"), NULL);
285 			item->SetEnabled(false);
286 			menu->AddItem(item);
287 		} else {
288 			BMenuItem* item = new BMenuItem(
289 				B_TRANSLATE("Choose automatically"), NULL);
290 			if (menu->FindMarked() == NULL)
291 				item->SetMarked(true);
292 			menu->AddItem(item, 0);
293 			menu->AddItem(new BSeparatorItem(), 1);
294 		}
295 		menu->SetTargetForItems(this);
296 	}
297 
298 	//fRenegotiateButton->SetEnabled(!disabled);
299 	fToggleButton->SetLabel(disabled ? "Enable" : "Disable");
300 
301 	return B_OK;
302 }
303