/* * Copyright 2004-2015 Haiku, Inc. All rights reserved. * Distributed under the terms of the MIT License. * * Authors: * Axel Dörfler, * Alexander von Gluck, kallisti5@unixzen.com * John Scipione, jscipione@gmail.com */ #include "InterfaceView.h" #include #include #include #include #include #include #include #include #include #include #include #include "MediaTypes.h" #include "WirelessNetworkMenuItem.h" static const uint32 kMsgInterfaceToggle = 'onof'; static const uint32 kMsgInterfaceRenegotiate = 'redo'; static const uint32 kMsgJoinNetwork = 'join'; #undef B_TRANSLATION_CONTEXT #define B_TRANSLATION_CONTEXT "IntefaceView" // #pragma mark - InterfaceView InterfaceView::InterfaceView() : BGroupView(B_VERTICAL), fPulseCount(0) { SetFlags(Flags() | B_PULSE_NEEDED); // TODO: Small graph of throughput? float minimumWidth = be_control_look->DefaultItemSpacing() * 16; BStringView* statusLabel = new BStringView("status label", B_TRANSLATE("Status:")); statusLabel->SetAlignment(B_ALIGN_RIGHT); fStatusField = new BStringView("status field", ""); fStatusField->SetExplicitMinSize(BSize(minimumWidth, B_SIZE_UNSET)); BStringView* macAddressLabel = new BStringView("mac address label", B_TRANSLATE("MAC address:")); macAddressLabel->SetAlignment(B_ALIGN_RIGHT); fMacAddressField = new BStringView("mac address field", ""); fMacAddressField->SetExplicitMinSize(BSize(minimumWidth, B_SIZE_UNSET)); BStringView* linkSpeedLabel = new BStringView("link speed label", B_TRANSLATE("Link speed:")); linkSpeedLabel->SetAlignment(B_ALIGN_RIGHT); fLinkSpeedField = new BStringView("link speed field", ""); fLinkSpeedField->SetExplicitMinSize(BSize(minimumWidth, B_SIZE_UNSET)); // TODO: These metrics may be better in a BScrollView? BStringView* linkTxLabel = new BStringView("tx label", B_TRANSLATE("Sent:")); linkTxLabel->SetAlignment(B_ALIGN_RIGHT); fLinkTxField = new BStringView("tx field", ""); fLinkTxField ->SetExplicitMinSize(BSize(minimumWidth, B_SIZE_UNSET)); BStringView* linkRxLabel = new BStringView("rx label", B_TRANSLATE("Received:")); linkRxLabel->SetAlignment(B_ALIGN_RIGHT); fLinkRxField = new BStringView("rx field", ""); fLinkRxField ->SetExplicitMinSize(BSize(minimumWidth, B_SIZE_UNSET)); fNetworkMenuField = new BMenuField(B_TRANSLATE("Network:"), new BMenu( B_TRANSLATE("Choose automatically"))); fNetworkMenuField->SetAlignment(B_ALIGN_RIGHT); fNetworkMenuField->Menu()->SetLabelFromMarked(true); // Construct the BButtons fToggleButton = new BButton("onoff", B_TRANSLATE("Disable"), new BMessage(kMsgInterfaceToggle)); fRenegotiateButton = new BButton("heal", B_TRANSLATE("Renegotiate"), new BMessage(kMsgInterfaceRenegotiate)); fRenegotiateButton->SetEnabled(false); BLayoutBuilder::Group<>(this) .AddGrid() .Add(statusLabel, 0, 0) .Add(fStatusField, 1, 0) .Add(fNetworkMenuField->CreateLabelLayoutItem(), 0, 1) .Add(fNetworkMenuField->CreateMenuBarLayoutItem(), 1, 1) .Add(macAddressLabel, 0, 2) .Add(fMacAddressField, 1, 2) .Add(linkSpeedLabel, 0, 3) .Add(fLinkSpeedField, 1, 3) .Add(linkTxLabel, 0, 4) .Add(fLinkTxField, 1, 4) .Add(linkRxLabel, 0, 5) .Add(fLinkRxField, 1, 5) .End() .AddGlue() .AddGroup(B_HORIZONTAL) .AddGlue() .Add(fToggleButton) .Add(fRenegotiateButton) .End(); } InterfaceView::~InterfaceView() { } void InterfaceView::SetTo(const char* name) { fInterface.SetTo(name); } void InterfaceView::AttachedToWindow() { _Update(); // Populate the fields fToggleButton->SetTarget(this); fRenegotiateButton->SetTarget(this); } void InterfaceView::MessageReceived(BMessage* message) { switch (message->what) { case kMsgJoinNetwork: { const char* name; BNetworkAddress address; if (message->FindString("name", &name) == B_OK && message->FindFlat("address", &address) == B_OK) { BNetworkDevice device(fInterface.Name()); status_t status = device.JoinNetwork(address); if (status != B_OK) { // This does not really matter, as it's stored this way, // anyway. } // TODO: store value } break; } case kMsgInterfaceToggle: { // Disable/enable interface uint32 flags = fInterface.Flags(); if ((flags & IFF_UP) != 0) flags &= ~IFF_UP; else flags |= IFF_UP; if (fInterface.SetFlags(flags) == B_OK) _Update(); break; } case kMsgInterfaceRenegotiate: { // TODO: renegotiate addresses break; } default: BView::MessageReceived(message); } } void InterfaceView::Pulse() { // Update the wireless network menu every 5 seconds _Update((fPulseCount++ % 5) == 0); } /*! Populate fields with current settings. */ status_t InterfaceView::_Update(bool updateWirelessNetworks) { BNetworkDevice device(fInterface.Name()); bool isWireless = device.IsWireless(); bool disabled = (fInterface.Flags() & IFF_UP) == 0; if (fInterface.HasLink()) fStatusField->SetText(B_TRANSLATE("connected")); else fStatusField->SetText(B_TRANSLATE("disconnected")); BNetworkAddress hardwareAddress; if (device.GetHardwareAddress(hardwareAddress) == B_OK) fMacAddressField->SetText(hardwareAddress.ToString()); else fMacAddressField->SetText("-"); int media = fInterface.Media(); if ((media & IFM_ACTIVE) != 0) fLinkSpeedField->SetText(media_type_to_string(media)); else fLinkSpeedField->SetText("-"); // Update Link stats ifreq_stats stats; if (fInterface.GetStats(stats) == B_OK) { char buffer[100]; string_for_size(stats.send.bytes, buffer, sizeof(buffer)); fLinkTxField->SetText(buffer); string_for_size(stats.receive.bytes, buffer, sizeof(buffer)); fLinkRxField->SetText(buffer); } // TODO: move the wireless info to a separate tab. We should have a // BListView of available networks, rather than a menu, to make them more // readable and easier to browse and select. if (fNetworkMenuField->IsHidden(fNetworkMenuField) && isWireless) fNetworkMenuField->Show(); else if (!fNetworkMenuField->IsHidden(fNetworkMenuField) && !isWireless) fNetworkMenuField->Hide(); if (isWireless && updateWirelessNetworks) { // Rebuild network menu BMenu* menu = fNetworkMenuField->Menu(); menu->RemoveItems(0, menu->CountItems(), true); std::set associated; BNetworkAddress address; uint32 cookie = 0; while (device.GetNextAssociatedNetwork(cookie, address) == B_OK) associated.insert(address); wireless_network network; int32 count = 0; cookie = 0; if ((fPulseCount % 15) == 0 && device.GetNextNetwork(cookie, network) != B_OK) { // We don't seem to know of any networks, and it's been long // enough since the last scan, so trigger one to try and // find some networks. device.Scan(false, false); // We don't want to block for the full length of the scan, but // 50ms is often more than enough to find at least one network, // and the increase in perceived QoS to the user of not seeing // "no wireless networks" if we can avoid it is great enough // to merit such a wait. It's only just over ~4 vertical // retraces, anyway. snooze(50 * 1000); } cookie = 0; while (device.GetNextNetwork(cookie, network) == B_OK) { BMessage* message = new BMessage(kMsgJoinNetwork); message->AddString("device", fInterface.Name()); message->AddString("name", network.name); message->AddFlat("address", &network.address); BMenuItem* item = new WirelessNetworkMenuItem(network.name, network.signal_strength, network.authentication_mode, message); if (associated.find(network.address) != associated.end()) item->SetMarked(true); menu->AddItem(item); count++; } if (count == 0) { BMenuItem* item = new BMenuItem( B_TRANSLATE(""), NULL); item->SetEnabled(false); menu->AddItem(item); } else { BMenuItem* item = new BMenuItem( B_TRANSLATE("Choose automatically"), NULL); if (menu->FindMarked() == NULL) item->SetMarked(true); menu->AddItem(item, 0); menu->AddItem(new BSeparatorItem(), 1); } menu->SetTargetForItems(this); } //fRenegotiateButton->SetEnabled(!disabled); fToggleButton->SetLabel(disabled ? B_TRANSLATE("Enable") : B_TRANSLATE("Disable")); return B_OK; }