package networkinggui;
import java.util.List;
import java.util.LinkedList;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import javax.swing.JLabel;
import javax.swing.JComboBox;
import javax.swing.JCheckBox;
import javax.swing.JButton;
import javax.swing.JTextField;
import javax.swing.JPasswordField;
import javax.swing.ListCellRenderer;
import javax.swing.JList;
import javax.swing.UIManager;
import javax.swing.UIDefaults;
import javax.swing.SwingUtilities;
import javax.swing.text.PlainDocument;
import javax.swing.text.BadLocationException;
import java.awt.Component;
import java.awt.Color;
import java.awt.GridLayout;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import java.awt.event.FocusListener;
import java.awt.event.FocusEvent;
import java.awt.event.ItemListener;
import java.awt.event.ItemEvent;
import java.awt.event.TextListener;
import java.awt.event.TextEvent;
import org.osgi.framework.BundleContext;
import com.buglabs.bug.networking.pub.IAccessPoint;
import com.buglabs.bug.networking.pub.IAccessPointSecurity;
import com.buglabs.bug.networking.pub.INetworking;
import com.buglabs.bug.networking.pub.IStateEvent;
import com.buglabs.bug.networking.pub.IStateListener;
public class WifiAccessPointPicker implements FocusListener, ItemListener, ActionListener, TextListener {
private final String SECURITY_CHOICE_NONE = "None";
private final String SECURITY_CHOICE_WPA = "WPA";
private final String SECURITY_CHOICE_WEP = "WEP";
private final String availableSecurityChoices[] = {SECURITY_CHOICE_NONE, SECURITY_CHOICE_WPA, SECURITY_CHOICE_WEP};
private INetworking ks;
private JPanel panel;
private JComboBox accessPointChoices;
private JButton scanButton;
private JComboBox securityChoices;
private JTextField ssidField;
private JPanel passphrasePanel;
private JTextField passphraseField;
private JTextField visiblePassphraseField;
private JButton connectButton;
private JLabel statusLabel;
private JProgressBar statusProgressBar;
private PlainDocument passphraseDocument;
private BundleContext context;
private Thread scanThread;
private class AccessPointUIRenderer extends JLabel implements ListCellRenderer {
public AccessPointUIRenderer() {
setOpaque(true);
}
public Component getListCellRendererComponent(JList list,
Object value,
int index,
boolean isSelected,
boolean cellHasFocus) {
if (value != null) {
Color background;
Color foreground;
AccessPointUI ap = (AccessPointUI) value;
StringBuffer displayName = new StringBuffer();
if (ap.isConnected()) {
displayName.append("* ");
}
displayName.append(ap.getName());
setText(displayName.toString());
UIDefaults defaults = UIManager.getDefaults();
if (isSelected) {
background = defaults.getColor("List.selectionBackground");
foreground = defaults.getColor("List.selectionForeground");
} else {
background = defaults.getColor("List.background");
foreground = defaults.getColor("List.foreground");
}
setBackground(background);
setForeground(foreground);
}
return this;
}
}
private class AccessPointUI {
private String name;
private String ssid;
private IAccessPointSecurity security;
private String passphrase;
private IAccessPoint accessPoint;
private boolean isConnected;
private boolean autoConnect;
public AccessPointUI() {
name = new String();
security = ks.accessPointSecurityFactory();
passphrase = new String();
ssid = new String();
isConnected = false;
autoConnect = false;
}
public AccessPointUI(IAccessPoint accessPoint) {
this.accessPoint = accessPoint;
name = accessPoint.getName();
security = accessPoint.getSecurity();
passphrase = accessPoint.getPassphrase();
ssid = accessPoint.getName();
isConnected = accessPoint.isConnected();
autoConnect = accessPoint.getAutoConnect();
}
@Override
public String toString() {
StringBuffer sb = new StringBuffer();
sb.append("{");
sb.append("ssid: '");
sb.append(ssid);
sb.append("', ");
sb.append("security: '");
sb.append(security);
sb.append("', ");
sb.append("passphrase: '");
sb.append(passphrase);
sb.append("'");
sb.append("}");
return sb.toString();
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSsid() {
return ssid;
}
public void setSsid(String ssid) {
this.ssid = ssid;
}
public IAccessPointSecurity getSecurity() {
return security;
}
public String getPassphrase() {
return passphrase;
}
public void setPassphrase(String passphrase) {
this.passphrase = passphrase;
}
public boolean isConnected() {
return isConnected;
}
public void setAutoConnect(boolean autoConnect) {
if (accessPoint != null) {
accessPoint.setAutoConnect(autoConnect);
}
}
public boolean requiresPassphrase() {
return (security.isWEP() || security.isWPA());
}
public void connect() {
if (accessPoint != null) {
if (accessPoint.requiresPassphrase()) {
accessPoint.connect(passphrase);
} else {
accessPoint.connect();
}
}
}
}
private class NoneAccessPoint extends AccessPointUI {
@Override
public String getName() {
return "[None]";
}
@Override
public void connect() {
Activator.logDebug("Connecting to [None]");
// TODO: We should disable the connect button when [None] is selected.
}
}
private class OtherAccessPoint extends AccessPointUI {
@Override
public String getName() {
return "Other...";
}
@Override
public void connect() {
Activator.logDebug("Connecting to Other...");
ks.connectToAccessPoint(getSsid(), getSecurity(), getPassphrase());
}
}
private List<AccessPointUI> accessPoints;
private AccessPointUI selectedAccessPoint;
private final NoneAccessPoint noneAccessPoint;
private final OtherAccessPoint otherAccessPoint;
public WifiAccessPointPicker(INetworking ks, BundleContext context) {
super();
this.ks = ks;
this.context = context;
passphraseDocument = new PlainDocument();
accessPoints = new LinkedList<AccessPointUI>();
noneAccessPoint = new NoneAccessPoint();
otherAccessPoint = new OtherAccessPoint();
accessPointChoices = new JComboBox();
accessPointChoices.addItemListener(this);
accessPointChoices.setRenderer(new AccessPointUIRenderer());
securityChoices = new JComboBox();
for (int i = 0; i < availableSecurityChoices.length; i++) {
securityChoices.addItem(availableSecurityChoices[i]);
}
securityChoices.addItemListener(this);
ssidField = new JTextField();
ssidField.addFocusListener(this);
// ssidField.addTextListener(this);
passphraseField = new JPasswordField();
passphraseField.setDocument(passphraseDocument);
passphraseField.addFocusListener(this);
visiblePassphraseField = new JTextField();
visiblePassphraseField.setDocument(passphraseDocument);
visiblePassphraseField.addFocusListener(this);
connectButton = new JButton("Connect");
connectButton.addActionListener(this);
// connectButton.setBackground(new Color(0xC7, 0xF6, 0x6F));
// connectButton.setBorder(BorderFactory.createLineBorder(new Color(0x65, 0x9A, 0x00), 1));
scanButton = new JButton("Look for Networks");
scanButton.addActionListener(this);
// scanButton.setBackground(new Color(0xC7, 0xF6, 0x6F));
// scanButton.setBorder(BorderFactory.createLineBorder(new Color(0x65, 0x9A, 0x00), 1));
statusLabel = new JLabel();
statusLabel.setHorizontalAlignment(JLabel.CENTER);
statusProgressBar = new JProgressBar();
statusProgressBar.setIndeterminate(true);
IStateListener stateListener = new IStateListener() {
public void stateChanged(final IStateEvent se) {
final Boolean isWifi = new Boolean(se.getDeviceType().isWifi());
final Boolean isAssociation = new Boolean(se.getState().isAssociation());
final Boolean isReady = new Boolean(se.getState().isReady());
final Boolean isFailure = new Boolean(se.getState().isFailure());
final Boolean isDisconnect = new Boolean(se.getState().isDisconnect());
SwingUtilities.invokeLater(new Runnable() {
public void run() {
// Activator.logDebug("STATE CHANGE " + se.getState().toString() + " on " + (se.getDeviceType().isEthernet() ? "ethernet" : "wifi"));
if (isWifi) {
if (isAssociation) {
statusConnecting();
} else if (isReady) {
statusConnected();
selectedAccessPoint.setAutoConnect(true);
} else if (isFailure) {
statusFailedToConnect();
} else if (isDisconnect) {
statusDisconnected();
}
}
}
});
}
};
context.registerService(IStateListener.class.getName(), stateListener, null);
}
private JComboBox getAccessPointChoices() {
return accessPointChoices;
}
private JComboBox getSecurityChoices() {
return securityChoices;
}
private JTextField getPassphraseField() {
return passphraseField;
}
private JTextField getVisiblePassphraseField() {
return visiblePassphraseField;
}
private JTextField getSSIDField() {
return ssidField;
}
private void createPanel() {
panel = new JPanel();
panel.setLayout(new GridLayout(5, 2));
panel.add(scanButton);
panel.add(getAccessPointChoices());
JLabel ssidLabel = new JLabel("SSID");
ssidLabel.setHorizontalAlignment(JLabel.RIGHT);
panel.add(ssidLabel);
panel.add(getSSIDField());
JLabel securityLabel = new JLabel("Security");
securityLabel.setHorizontalAlignment(JLabel.RIGHT);
panel.add(securityLabel);
panel.add(getSecurityChoices());
JPanel passphraseControlPanel = new JPanel();
passphraseControlPanel.setLayout(new GridLayout(1, 2));
passphraseControlPanel.add(new JLabel("Passphrase"));
JCheckBox showPassphrase = new JCheckBox("Show");
passphraseControlPanel.add(showPassphrase);
showPassphrase.addItemListener(new ItemListener() {
public void itemStateChanged(ItemEvent e) {
if (e.getStateChange() == ItemEvent.SELECTED) {
passphrasePanel.remove(getPassphraseField());
passphrasePanel.add(getVisiblePassphraseField());
} else {
passphrasePanel.remove(getVisiblePassphraseField());
passphrasePanel.add(getPassphraseField());
}
passphrasePanel.revalidate();
passphrasePanel.repaint();
}
});
panel.add(passphraseControlPanel);
passphrasePanel = new JPanel(new GridLayout(1, 1));
passphrasePanel.add(getPassphraseField());
panel.add(passphrasePanel);
panel.add(connectButton);
JPanel statusPanel = new JPanel(new GridLayout(2, 1));
statusPanel.add(statusProgressBar);
statusPanel.add(statusLabel);
panel.add(statusPanel);
}
private void statusDisconnected() {
statusProgressBar.setIndeterminate(false);
statusProgressBar.setForeground(Color.BLACK);
statusProgressBar.setValue(0);
statusLabel.setText("Disconnected");
}
private void statusConnecting() {
try {
// statusProgressBar.setIndeterminate(true);
statusProgressBar.setForeground(Color.YELLOW);
statusProgressBar.setValue(50);
statusLabel.setText("Connecting");
} catch (Exception e) {
Activator.logDebug("exception in statusConnecting");
}
}
private void statusConnected() {
try {
statusProgressBar.setIndeterminate(false);
statusProgressBar.setForeground(Color.GREEN);
statusProgressBar.setValue(100);
statusLabel.setText("Connected");
} catch (Exception e) {
Activator.logDebug("exception in statusConnected");
}
}
private void statusFailedToConnect() {
statusProgressBar.setIndeterminate(false);
statusProgressBar.setForeground(Color.RED);
statusProgressBar.setValue(100);
statusLabel.setText("Failed");
}
private void connect() {
Activator.logDebug("handling connect action");
connectButton.setEnabled(false);
Thread connectionThread = new Thread() {
public void run() {
Activator.logDebug("trying to connect");
try {
selectedAccessPoint.connect();
} catch (Exception e) {
Activator.logError("Exception while attempting to connect");
Activator.logError(e.getMessage());
for (StackTraceElement ste : e.getStackTrace()) {
Activator.logError(ste.toString());
}
SwingUtilities.invokeLater(new Runnable() {
public void run() {
statusFailedToConnect();
}
});
}
Activator.logDebug("finished trying to connected");
SwingUtilities.invokeLater(new Runnable() {
public void run() {
connectButton.setEnabled(true);
}
});
}
};
connectionThread.start();
}
private Thread scan() {
scanButton.setEnabled(false);
scanThread = new Thread() {
public void run() {
Activator.logDebug("scanning for access points");
try {
ks.scanAccessPoints();
ks.scanAccessPoints();
} catch (Exception e) {
Activator.logError("Exception while scanning for access points.");
Activator.logError(e.getMessage());
for (StackTraceElement ste : e.getStackTrace()) {
Activator.logError(ste.toString());
}
}
Activator.logDebug("scanned for access points");
updateAccessPoints();
SwingUtilities.invokeLater(new Runnable() {
public void run() {
scanButton.setEnabled(true);
}
});
}
};
scanThread.start();
return scanThread;
}
public JPanel getPanel() {
if (panel == null) {
createPanel();
}
new Thread() {
public void run() {
try {
scan().join();
} catch (InterruptedException e) {
Activator.logDebug("scan was interrupted");
}
final AccessPointUI connectedAccessPoint = getConnectedAccessPoint();
if (connectedAccessPoint == noneAccessPoint) {
Activator.logDebug("no connected access point, using [None]");
} else {
Activator.logDebug("connected access point right here is " + connectedAccessPoint.getName());
}
selectedAccessPoint = connectedAccessPoint;
SwingUtilities.invokeLater(new Runnable() {
public void run() {
updateInterface();
if (connectedAccessPoint != noneAccessPoint) {
statusConnected();
} else {
statusDisconnected();
}
}
});
}
}.start();
return panel;
}
public void focusGained(FocusEvent arg0) {
Utilities.keyboardUp();
}
public void focusLost(FocusEvent arg0) {
Utilities.keyboardDown();
if (arg0.getSource() == passphraseField || arg0.getSource() == visiblePassphraseField) {
try {
selectedAccessPoint.setPassphrase(passphraseDocument.getText(0, passphraseDocument.getLength()));
} catch (BadLocationException e) {
Activator.logDebug("Error while setting the password. This should not happen.");
}
} else if (arg0.getSource() == ssidField) {
selectedAccessPoint.setSsid(ssidField.getText());
}
}
public void setSecurityFromString(String securityString, AccessPointUI ap) {
if (securityString.compareTo(SECURITY_CHOICE_NONE) == 0) {
ap.getSecurity().setNone();
} else if (securityString.compareTo(SECURITY_CHOICE_WEP) == 0) {
ap.getSecurity().setWEP();
} else if (securityString.compareTo(SECURITY_CHOICE_WPA) == 0) {
ap.getSecurity().setWPA();
} else {
Activator.logError("Unknown security type: '" + securityString + "'");
}
}
public String securityToString(IAccessPointSecurity security) {
if (security.isWEP()) {
return SECURITY_CHOICE_WEP;
} else if (security.isWPA()) {
return SECURITY_CHOICE_WPA;
}
return SECURITY_CHOICE_NONE;
}
public void itemStateChanged(ItemEvent e) {
if (e.getStateChange() == ItemEvent.SELECTED) {
if (e.getSource() == accessPointChoices) {
AccessPointUI newlySelectedAccessPoint = (AccessPointUI) accessPointChoices.getSelectedItem();
if (newlySelectedAccessPoint != null) {
selectedAccessPoint = newlySelectedAccessPoint;
} else {
Activator.logDebug("newlySelectedAccessPoint was null, setting selectedAccessPoint to none");
}
Activator.logDebug("Selected AP is " + (selectedAccessPoint == null ? "NOTHING" : selectedAccessPoint.getName()));
updateSSIDField();
updateSecurityChoices();
updatePassphraseField();
} else if (e.getSource() == securityChoices) {
setSecurityFromString((String) securityChoices.getSelectedItem(), selectedAccessPoint);
updatePassphraseField();
}
}
}
public void actionPerformed(ActionEvent e) {
Activator.logDebug("button pressed");
if (e.getSource() == connectButton) {
Activator.logDebug("connectButton pressed");
connect();
} else if (e.getSource() == scanButton) {
try {
scan().join();
} catch (InterruptedException ex) {
Activator.logDebug("interrupted while scanning");
}
SwingUtilities.invokeLater(new Runnable() {
public void run() {
updateInterface();
}
});
}
}
public void textValueChanged(TextEvent e) {
JTextField source = (JTextField) e.getSource();
String value = source.getText();
if (source == ssidField && isSSIDFieldEnabled()) {
Activator.logDebug("setting SSID ...");
selectedAccessPoint.setSsid(value);
} else if (source == passphraseField && isPassphraseFieldEnabled()) {
Activator.logDebug("setting passphrase ...");
selectedAccessPoint.setPassphrase(value);
}
}
private AccessPointUI getConnectedAccessPoint() {
Activator.logDebug("getting connected access point");
for (AccessPointUI ap :getAccessPoints()) {
Activator.logDebug("trying " + ap.getName());
if (ap.isConnected()) {
Activator.logDebug("connected to " + ap.getName());
return ap;
} else {
Activator.logDebug("NOT connected to " + ap.getName());
}
}
Activator.logWarning("could not find connected AP");
return noneAccessPoint;
}
private void updateAccessPoints() {
Activator.logDebug("entering: updateAccessPoints()");
synchronized (accessPoints) {
accessPoints.clear();
List<IAccessPoint> backendAccessPoints = ks.getAccessPoints();
accessPoints.add(noneAccessPoint);
accessPoints.add(otherAccessPoint);
for (IAccessPoint ap : backendAccessPoints) {
Activator.logDebug("Adding access point");
AccessPointUI apUI = new AccessPointUI(ap);
accessPoints.add(apUI);
Activator.logDebug("Added access point " + apUI.getName());
}
}
Activator.logDebug("leaving: updateAccessPoints()");
}
private List<AccessPointUI> getAccessPoints() {
synchronized (accessPoints) {
return accessPoints;
}
}
private AccessPointUI getAccessPointByName(String accessPointName) {
for (AccessPointUI ap : getAccessPoints()) {
if (accessPointName.compareTo(ap.getName()) == 0) {
return ap;
}
}
return noneAccessPoint;
}
private void updateAccessPointChoices() {
synchronized (accessPointChoices) {
Activator.logDebug("removing all access point choices");
accessPointChoices.removeItemListener(this);
// Store the currently selected access point name, because removing all items
// selects a new access point.
String selectedAccessPointName = noneAccessPoint.getName();
if (selectedAccessPoint != null) {
selectedAccessPointName = selectedAccessPoint.getName();
}
accessPointChoices.removeAllItems();
for (AccessPointUI apUI : getAccessPoints()) {
Activator.logDebug("Adding access point " + apUI.getName());
accessPointChoices.addItem(apUI);
}
selectedAccessPoint = getAccessPointByName(selectedAccessPointName);
if (selectedAccessPoint != null) {
Activator.logDebug("selecting " + selectedAccessPoint.getName() + " from accessPointChoices.");
accessPointChoices.setSelectedItem(selectedAccessPoint);
} else {
Activator.logDebug("no selected access point to set");
}
accessPointChoices.addItemListener(this);
}
}
private void updateInterface() {
updateAccessPointChoices();
updateSSIDField();
updateSecurityChoices();
updatePassphraseField();
}
private boolean isSSIDFieldEnabled() {
return selectedAccessPoint == otherAccessPoint;
}
private void updateSSIDField() {
if (isSSIDFieldEnabled()) {
ssidField.setText(otherAccessPoint.getSsid());
} else {
ssidField.setText("");
}
ssidField.setEnabled(isSSIDFieldEnabled());
ssidField.setVisible(isSSIDFieldEnabled());
}
private boolean isSecurityChoicesEnabled() {
return selectedAccessPoint == otherAccessPoint;
}
private boolean isSecurityChoicesVisible() {
return (selectedAccessPoint != noneAccessPoint && (selectedAccessPoint.requiresPassphrase() || selectedAccessPoint == otherAccessPoint));
}
private void updateSecurityChoices() {
String securityString = securityToString(selectedAccessPoint.getSecurity());
securityChoices.setSelectedItem(securityString);
securityChoices.setEnabled(isSecurityChoicesEnabled());
securityChoices.setVisible(isSecurityChoicesVisible());
}
private boolean isPassphraseFieldEnabled() {
return (selectedAccessPoint != noneAccessPoint && selectedAccessPoint.requiresPassphrase());
}
private boolean isPassphraseFieldVisible() {
return (selectedAccessPoint != noneAccessPoint && selectedAccessPoint.requiresPassphrase());
}
private void updatePassphraseField() {
if (isPassphraseFieldEnabled()) {
passphraseField.setText(selectedAccessPoint.getPassphrase());
} else {
passphraseField.setText("");
}
passphraseField.setEnabled(isPassphraseFieldEnabled());
passphraseField.setVisible(isPassphraseFieldVisible());
visiblePassphraseField.setEnabled(isPassphraseFieldEnabled());
visiblePassphraseField.setVisible(isPassphraseFieldVisible());
}
}