Network: Sort network menu items w/o deleting
* Delete dropped out networks. * Add in newly discovered networks. * Add static (aka class) compare method to WirelessNetworkMenuItem that is used to sort items by signal strength descending. Add == operator to wireless_network struct to determine if existing items have a known network attached. Remove the non-network items from the menu, save them, sort network menu items, then add non-network items back into the menu. Update NetworkStatus preflet to use same compare method as Network preflet. signal_strength_compare function had a bool return value instead of int which worked to sort items the first time, but does not work on successive compares. By not deleting and recreating the menu items each Pulse(), the Network preflet no longer crashes on update. The menu flashes on update still but doesn't crash. Fixes #12024 Change-Id: Ie5b22cea4e66350b9c5df8e3b8de266ede50ad6d Reviewed-on: https://review.haiku-os.org/c/haiku/+/4243 Reviewed-by: John Scipione <jscipione@gmail.com> Reviewed-by: waddlesplash <waddlesplash@gmail.com> Reviewed-by: Axel Dörfler <axeld@pinc-software.de>
This commit is contained in:
parent
0a53cbb3b9
commit
02ad92185d
@ -7,6 +7,7 @@
|
||||
|
||||
|
||||
#include <net/if.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <NetworkAddress.h>
|
||||
|
||||
@ -24,6 +25,18 @@ struct wireless_network {
|
||||
uint32 cipher;
|
||||
uint32 group_cipher;
|
||||
uint32 key_mode;
|
||||
|
||||
bool operator==(const wireless_network& other) {
|
||||
return strncmp(name, other.name, 32) == 0
|
||||
// ignore address difference
|
||||
&& noise_level == other.noise_level
|
||||
&& signal_strength == other.signal_strength
|
||||
&& flags == other.flags
|
||||
&& authentication_mode == other.authentication_mode
|
||||
&& cipher == other.cipher
|
||||
&& group_cipher == other.group_cipher
|
||||
&& key_mode == other.key_mode;
|
||||
}
|
||||
};
|
||||
|
||||
// flags
|
||||
|
@ -37,7 +37,6 @@
|
||||
#include <Locale.h>
|
||||
#include <MenuItem.h>
|
||||
#include <MessageRunner.h>
|
||||
#include <NetworkDevice.h>
|
||||
#include <NetworkInterface.h>
|
||||
#include <NetworkRoster.h>
|
||||
#include <PopUpMenu.h>
|
||||
@ -75,20 +74,7 @@ const uint32 kMinIconWidth = 16;
|
||||
const uint32 kMinIconHeight = 16;
|
||||
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
|
||||
static bool
|
||||
signal_strength_compare(const wireless_network &a,
|
||||
const wireless_network &b)
|
||||
{
|
||||
if (a.signal_strength == b.signal_strength)
|
||||
return strcmp(a.name, b.name) > 0;
|
||||
return a.signal_strength > b.signal_strength;
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark -
|
||||
// #pragma mark - NetworkStatusView
|
||||
|
||||
|
||||
NetworkStatusView::NetworkStatusView(BRect frame, int32 resizingMode,
|
||||
@ -393,80 +379,61 @@ NetworkStatusView::MouseDown(BPoint point)
|
||||
menu->SetAsyncAutoDestruct(true);
|
||||
menu->SetFont(be_plain_font);
|
||||
BString wifiInterface;
|
||||
BNetworkDevice wifiDevice;
|
||||
BNetworkDevice device;
|
||||
|
||||
// Add interfaces
|
||||
if (!fInterfaceStatuses.empty()) {
|
||||
for (std::map<BString, int32>::const_iterator it
|
||||
= fInterfaceStatuses.begin(); it != fInterfaceStatuses.end();
|
||||
++it) {
|
||||
const BString& name = it->first;
|
||||
|
||||
for (std::map<BString, int32>::const_iterator it
|
||||
= fInterfaceStatuses.begin(); it != fInterfaceStatuses.end(); ++it) {
|
||||
const BString& name = it->first;
|
||||
|
||||
BString label = name;
|
||||
label += ": ";
|
||||
label += kStatusDescriptions[
|
||||
_DetermineInterfaceStatus(name.String())];
|
||||
|
||||
BMessage* info = new BMessage(kMsgShowConfiguration);
|
||||
info->AddString("interface", name.String());
|
||||
menu->AddItem(new BMenuItem(label.String(), info));
|
||||
|
||||
// We only show the networks of the first wireless device we find.
|
||||
if (wifiInterface.IsEmpty()) {
|
||||
wifiDevice.SetTo(name);
|
||||
if (wifiDevice.IsWireless())
|
||||
wifiInterface = name;
|
||||
// we only show network of the first wireless device we find
|
||||
if (wifiInterface.IsEmpty()) {
|
||||
device.SetTo(name);
|
||||
if (device.IsWireless())
|
||||
wifiInterface = name;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!fInterfaceStatuses.empty())
|
||||
menu->AddSeparatorItem();
|
||||
|
||||
// Add wireless networks, if any
|
||||
// Add wireless networks, if any, first so that we can sort the menu
|
||||
|
||||
if (!wifiInterface.IsEmpty()) {
|
||||
std::set<BNetworkAddress> associated;
|
||||
BNetworkAddress address;
|
||||
wireless_network network;
|
||||
uint32 cookie = 0;
|
||||
while (wifiDevice.GetNextAssociatedNetwork(cookie, address) == B_OK)
|
||||
while (device.GetNextAssociatedNetwork(cookie, address) == B_OK)
|
||||
associated.insert(address);
|
||||
|
||||
int32 wifiCount = 0;
|
||||
cookie = 0;
|
||||
wireless_network network;
|
||||
typedef std::vector<wireless_network> WirelessNetworkVector;
|
||||
WirelessNetworkVector wirelessNetworks;
|
||||
while (wifiDevice.GetNextNetwork(cookie, network) == B_OK)
|
||||
wirelessNetworks.push_back(network);
|
||||
|
||||
std::sort(wirelessNetworks.begin(), wirelessNetworks.end(),
|
||||
signal_strength_compare);
|
||||
|
||||
int32 count = 0;
|
||||
for (WirelessNetworkVector::iterator it = wirelessNetworks.begin();
|
||||
it != wirelessNetworks.end(); it++) {
|
||||
wireless_network &network = *it;
|
||||
|
||||
while (device.GetNextNetwork(cookie, network) == B_OK) {
|
||||
BMessage* message = new BMessage(kMsgJoinNetwork);
|
||||
message->AddString("device", wifiInterface);
|
||||
message->AddString("name", network.name);
|
||||
message->AddFlat("address", &network.address);
|
||||
|
||||
BMenuItem* item = new WirelessNetworkMenuItem(network.name,
|
||||
network.signal_strength, network.authentication_mode, message);
|
||||
BMenuItem* item = new WirelessNetworkMenuItem(network, message);
|
||||
menu->AddItem(item);
|
||||
wifiCount++;
|
||||
if (associated.find(network.address) != associated.end())
|
||||
item->SetMarked(true);
|
||||
|
||||
count++;
|
||||
}
|
||||
if (count == 0) {
|
||||
|
||||
if (wifiCount == 0) {
|
||||
BMenuItem* item = new BMenuItem(
|
||||
B_TRANSLATE("<no wireless networks found>"), NULL);
|
||||
item->SetEnabled(false);
|
||||
menu->AddItem(item);
|
||||
}
|
||||
} else
|
||||
menu->SortItems(WirelessNetworkMenuItem::CompareSignalStrength);
|
||||
|
||||
menu->AddSeparatorItem();
|
||||
}
|
||||
|
||||
// add action menu items
|
||||
|
||||
menu->AddItem(new BMenuItem(B_TRANSLATE(
|
||||
"Open network preferences" B_UTF8_ELLIPSIS),
|
||||
new BMessage(kMsgOpenNetworkPreferences)));
|
||||
@ -475,6 +442,32 @@ NetworkStatusView::MouseDown(BPoint point)
|
||||
menu->AddItem(new BMenuItem(B_TRANSLATE("Quit"),
|
||||
new BMessage(B_QUIT_REQUESTED)));
|
||||
}
|
||||
|
||||
// Add wired interfaces to top of menu
|
||||
if (!fInterfaceStatuses.empty()) {
|
||||
int32 wiredCount = 0;
|
||||
for (std::map<BString, int32>::const_iterator it
|
||||
= fInterfaceStatuses.begin(); it != fInterfaceStatuses.end();
|
||||
++it) {
|
||||
const BString& name = it->first;
|
||||
|
||||
BString label = name;
|
||||
label += ": ";
|
||||
label += kStatusDescriptions[
|
||||
_DetermineInterfaceStatus(name.String())];
|
||||
|
||||
BMessage* info = new BMessage(kMsgShowConfiguration);
|
||||
info->AddString("interface", name.String());
|
||||
menu->AddItem(new BMenuItem(label.String(), info), wiredCount);
|
||||
wiredCount++;
|
||||
}
|
||||
|
||||
// add separator item between wired and wireless networks
|
||||
// (or between wired networks and actions if no wireless found)
|
||||
if (wiredCount > 0)
|
||||
menu->AddItem(new BSeparatorItem(), wiredCount);
|
||||
}
|
||||
|
||||
menu->SetTargetForItems(this);
|
||||
|
||||
ConvertToScreen(&point);
|
||||
|
@ -6,27 +6,29 @@
|
||||
|
||||
#include "WirelessNetworkMenuItem.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include <Catalog.h>
|
||||
#include <NetworkDevice.h>
|
||||
#include <String.h>
|
||||
|
||||
#include "RadioView.h"
|
||||
|
||||
|
||||
#undef B_TRANSLATION_CONTEXT
|
||||
#define B_TRANSLATION_CONTEXT "WirelessNetworkMenuItem"
|
||||
|
||||
|
||||
WirelessNetworkMenuItem::WirelessNetworkMenuItem(const char* name,
|
||||
int32 signalQuality, int32 authenticationMode, BMessage* message)
|
||||
WirelessNetworkMenuItem::WirelessNetworkMenuItem(wireless_network network,
|
||||
BMessage* message)
|
||||
:
|
||||
BMenuItem(name, message),
|
||||
fQuality(signalQuality)
|
||||
BMenuItem(network.name, message),
|
||||
fNetwork(network)
|
||||
{
|
||||
// Append authentication mode to label
|
||||
BString label = B_TRANSLATE("%name% (%authenticationMode%)");
|
||||
label.Replace("%name%", name, 1);
|
||||
label.Replace("%name%", network.name, 1);
|
||||
label.Replace("%authenticationMode%",
|
||||
AuthenticationName(authenticationMode), 1);
|
||||
AuthenticationName(network.authentication_mode), 1);
|
||||
|
||||
SetLabel(label.String());
|
||||
}
|
||||
@ -37,13 +39,6 @@ WirelessNetworkMenuItem::~WirelessNetworkMenuItem()
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
WirelessNetworkMenuItem::SetSignalQuality(int32 quality)
|
||||
{
|
||||
fQuality = quality;
|
||||
}
|
||||
|
||||
|
||||
BString
|
||||
WirelessNetworkMenuItem::AuthenticationName(int32 mode)
|
||||
{
|
||||
@ -99,5 +94,23 @@ WirelessNetworkMenuItem::DrawRadioIcon()
|
||||
bounds.right -= 4;
|
||||
bounds.bottom -= 2;
|
||||
|
||||
RadioView::Draw(Menu(), bounds, fQuality, RadioView::DefaultMax());
|
||||
RadioView::Draw(Menu(), bounds, fNetwork.signal_strength,
|
||||
RadioView::DefaultMax());
|
||||
}
|
||||
|
||||
|
||||
/*static*/ int
|
||||
WirelessNetworkMenuItem::CompareSignalStrength(const BMenuItem* a,
|
||||
const BMenuItem* b)
|
||||
{
|
||||
WirelessNetworkMenuItem* aItem = *(WirelessNetworkMenuItem**)a;
|
||||
WirelessNetworkMenuItem* bItem = *(WirelessNetworkMenuItem**)b;
|
||||
|
||||
wireless_network aNetwork = aItem->Network();
|
||||
wireless_network bNetwork = bItem->Network();
|
||||
|
||||
if (aNetwork.signal_strength == bNetwork.signal_strength)
|
||||
return strncasecmp(aNetwork.name, bNetwork.name, 32);
|
||||
|
||||
return bNetwork.signal_strength - aNetwork.signal_strength;
|
||||
}
|
||||
|
@ -7,20 +7,23 @@
|
||||
|
||||
|
||||
#include <MenuItem.h>
|
||||
#include <NetworkDevice.h>
|
||||
|
||||
|
||||
class WirelessNetworkMenuItem : public BMenuItem {
|
||||
public:
|
||||
WirelessNetworkMenuItem(const char* name,
|
||||
int32 signalQuality, int32 authenticationMode,
|
||||
WirelessNetworkMenuItem(
|
||||
wireless_network network,
|
||||
BMessage* message);
|
||||
virtual ~WirelessNetworkMenuItem();
|
||||
|
||||
void SetSignalQuality(int32 quality);
|
||||
int32 SignalQuality() const
|
||||
{ return fQuality; }
|
||||
wireless_network Network() const { return fNetwork; }
|
||||
|
||||
BString AuthenticationName(int32 mode);
|
||||
|
||||
static int CompareSignalStrength(const BMenuItem* a,
|
||||
const BMenuItem* b);
|
||||
|
||||
protected:
|
||||
virtual void DrawContent();
|
||||
virtual void Highlight(bool isHighlighted);
|
||||
@ -28,7 +31,7 @@ protected:
|
||||
void DrawRadioIcon();
|
||||
|
||||
private:
|
||||
int32 fQuality;
|
||||
wireless_network fNetwork;
|
||||
};
|
||||
|
||||
|
||||
|
@ -20,7 +20,6 @@
|
||||
#include <ControlLook.h>
|
||||
#include <LayoutBuilder.h>
|
||||
#include <NetworkAddress.h>
|
||||
#include <NetworkDevice.h>
|
||||
#include <StringForSize.h>
|
||||
#include <StringView.h>
|
||||
#include <TextControl.h>
|
||||
@ -243,7 +242,27 @@ InterfaceView::_Update(bool updateWirelessNetworks)
|
||||
if (isWireless && updateWirelessNetworks) {
|
||||
// Rebuild network menu
|
||||
BMenu* menu = fNetworkMenuField->Menu();
|
||||
menu->RemoveItems(0, menu->CountItems(), true);
|
||||
int32 count = menu->CountItems();
|
||||
|
||||
// remove non-network items from menu and save them for later
|
||||
BMenuItem* chooseItem = NULL;
|
||||
BSeparatorItem* separatorItem = NULL;
|
||||
if (count > 0 && strcmp(menu->ItemAt(0)->Label(),
|
||||
B_TRANSLATE("Choose automatically")) == 0) {
|
||||
// remove Choose automatically item
|
||||
chooseItem = menu->RemoveItem((int32)0);
|
||||
// remove separator item too
|
||||
separatorItem = (BSeparatorItem*)menu->RemoveItem((int32)0);
|
||||
count -= 2;
|
||||
}
|
||||
|
||||
BMenuItem* noNetworksFoundItem = NULL;
|
||||
if (menu->CountItems() > 0 && strcmp(menu->ItemAt(0)->Label(),
|
||||
B_TRANSLATE("<no wireless networks found>")) == 0) {
|
||||
// remove <no wireless networks found> item
|
||||
noNetworksFoundItem = menu->RemoveItem((int32)0);
|
||||
count--;
|
||||
}
|
||||
|
||||
std::set<BNetworkAddress> associated;
|
||||
BNetworkAddress address;
|
||||
@ -252,7 +271,6 @@ InterfaceView::_Update(bool updateWirelessNetworks)
|
||||
associated.insert(address);
|
||||
|
||||
wireless_network network;
|
||||
int32 count = 0;
|
||||
cookie = 0;
|
||||
if ((fPulseCount % 15) == 0
|
||||
&& device.GetNextNetwork(cookie, network) != B_OK) {
|
||||
@ -270,36 +288,92 @@ InterfaceView::_Update(bool updateWirelessNetworks)
|
||||
snooze(50 * 1000);
|
||||
}
|
||||
|
||||
// go through menu items and remove networks that have dropped out
|
||||
for (int32 index = 0; index < count; index++) {
|
||||
WirelessNetworkMenuItem* networkItem =
|
||||
dynamic_cast<WirelessNetworkMenuItem*>(
|
||||
menu->ItemAt(index));
|
||||
if (networkItem == NULL)
|
||||
break;
|
||||
|
||||
bool networkFound = false;
|
||||
cookie = 0;
|
||||
while (device.GetNextNetwork(cookie, network) == B_OK) {
|
||||
if (networkItem->Network() == network) {
|
||||
networkFound = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!networkFound) {
|
||||
menu->RemoveItem(networkItem);
|
||||
count--;
|
||||
}
|
||||
}
|
||||
|
||||
// go through networks and add new ones to menu
|
||||
cookie = 0;
|
||||
while (device.GetNextNetwork(cookie, network) == B_OK) {
|
||||
BMessage* message = new BMessage(kMsgJoinNetwork);
|
||||
bool networkFound = false;
|
||||
for (int32 index = 0; index < count; index++) {
|
||||
WirelessNetworkMenuItem* networkItem =
|
||||
dynamic_cast<WirelessNetworkMenuItem*>(
|
||||
menu->ItemAt(index));
|
||||
if (networkItem == NULL)
|
||||
break;
|
||||
|
||||
message->AddString("device", fInterface.Name());
|
||||
message->AddString("name", network.name);
|
||||
message->AddFlat("address", &network.address);
|
||||
if (networkItem->Network() == network) {
|
||||
// found it
|
||||
networkFound = true;
|
||||
if (associated.find(network.address) != associated.end())
|
||||
networkItem->SetMarked(true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
if (!networkFound) {
|
||||
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,
|
||||
message);
|
||||
menu->AddItem(item);
|
||||
if (associated.find(network.address) != associated.end())
|
||||
item->SetMarked(true);
|
||||
}
|
||||
|
||||
count++;
|
||||
}
|
||||
|
||||
if (count == 0) {
|
||||
BMenuItem* item = new BMenuItem(
|
||||
B_TRANSLATE("<no wireless networks found>"), NULL);
|
||||
item->SetEnabled(false);
|
||||
menu->AddItem(item);
|
||||
// no networks found
|
||||
if (noNetworksFoundItem != NULL)
|
||||
menu->AddItem(noNetworksFoundItem);
|
||||
else {
|
||||
BMenuItem* item = new BMenuItem(
|
||||
B_TRANSLATE("<no wireless networks found>"), 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);
|
||||
// sort items by signal strength
|
||||
menu->SortItems(WirelessNetworkMenuItem::CompareSignalStrength);
|
||||
|
||||
// add Choose automatically item to start
|
||||
if (chooseItem != NULL) {
|
||||
menu->AddItem(chooseItem, 0);
|
||||
menu->AddItem(separatorItem, 1);
|
||||
} 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);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user