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 if ((fPulseCount % 15) == 0 267 && device.GetNextNetwork(cookie, network) != B_OK) { 268 // We don't seem to know of any networks, and it's been long 269 // enough since the last scan, so trigger one to try and 270 // find some networks. 271 device.Scan(false, false); 272 273 // We don't want to block for the full length of the scan, but 274 // 50ms is often more than enough to find at least one network, 275 // and the increase in perceived QoS to the user of not seeing 276 // "no wireless networks" if we can avoid it is great enough 277 // to merit such a wait. It's only just over ~4 vertical 278 // retraces, anyway. 279 snooze(50 * 1000); 280 } 281 282 cookie = 0; 283 while (device.GetNextNetwork(cookie, network) == B_OK) { 284 BMessage* message = new BMessage(kMsgJoinNetwork); 285 286 message->AddString("device", fInterface.Name()); 287 message->AddString("name", network.name); 288 message->AddFlat("address", &network.address); 289 290 BMenuItem* item = new WirelessNetworkMenuItem(network.name, 291 network.signal_strength, 292 network.authentication_mode, message); 293 if (associated.find(network.address) != associated.end()) 294 item->SetMarked(true); 295 menu->AddItem(item); 296 297 count++; 298 } 299 if (count == 0) { 300 BMenuItem* item = new BMenuItem( 301 B_TRANSLATE("<no wireless networks found>"), NULL); 302 item->SetEnabled(false); 303 menu->AddItem(item); 304 } else { 305 BMenuItem* item = new BMenuItem( 306 B_TRANSLATE("Choose automatically"), NULL); 307 if (menu->FindMarked() == NULL) 308 item->SetMarked(true); 309 menu->AddItem(item, 0); 310 menu->AddItem(new BSeparatorItem(), 1); 311 } 312 menu->SetTargetForItems(this); 313 } 314 315 //fRenegotiateButton->SetEnabled(!disabled); 316 fToggleButton->SetLabel(disabled 317 ? B_TRANSLATE("Enable") : B_TRANSLATE("Disable")); 318 319 return B_OK; 320 } 321