/*
* $Id$
*
* Copyright (c) 2009-2013 by Brent Easton
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License (LGPL) as published by the Free Software Foundation.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, copies are available
* at http://www.opensource.org.
*/
package VASSAL.chat;
import java.awt.Component;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.io.IOException;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.UnknownHostException;
import java.util.Enumeration;
import java.util.List;
import java.util.Properties;
import javax.swing.AbstractAction;
import javax.swing.DefaultListCellRenderer;
import javax.swing.DefaultListModel;
import javax.swing.Icon;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.ListSelectionModel;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import net.miginfocom.swing.MigLayout;
import VASSAL.build.GameModule;
import VASSAL.chat.jabber.JabberClient;
import VASSAL.chat.jabber.JabberClientFactory;
import VASSAL.chat.node.NodeClientFactory;
import VASSAL.chat.peer2peer.P2PClientFactory;
import VASSAL.configure.StringConfigurer;
import VASSAL.i18n.Resources;
import VASSAL.preferences.Prefs;
import VASSAL.tools.PropertiesEncoder;
import VASSAL.tools.SequenceEncoder;
import VASSAL.tools.icon.IconFactory;
import VASSAL.tools.icon.IconFamily;
import VASSAL.tools.swing.Dialogs;
public class ServerAddressBook {
public static final String CURRENT_SERVER = "currentServer"; //$NON-NLS-1$
protected static final String ADDRESS_PREF = "ServerAddressBook"; //$NON-NLS-1$
protected static final String LEGACY_TYPE = NodeClientFactory.NODE_TYPE;
protected static final String DYNAMIC_TYPE = DynamicClientFactory.DYNAMIC_TYPE;
protected static final String JABBER_TYPE = JabberClientFactory.JABBER_SERVER_TYPE;
protected static final String P2P_TYPE = P2PClientFactory.P2P_TYPE;
protected static final String P2P_MODE_KEY = P2PClientFactory.P2P_MODE_KEY;
protected static final String P2P_SERVER_MODE = P2PClientFactory.P2P_SERVER_MODE;
protected static final String P2P_CLIENT_MODE = P2PClientFactory.P2P_CLIENT_MODE;
// protected static final String PRIVATE_TYPE = PrivateClientFactory.PRIVATE_TYPE;
protected static final String TYPE_KEY = ChatServerFactory.TYPE_KEY;
protected static final String DESCRIPTION_KEY = "description"; //$NON-NLS-1$
protected final int LEAF_ICON_SIZE = IconFamily.SMALL;
protected final int CONTROLS_ICON_SIZE = IconFamily.XSMALL;
private boolean frozen;
private JComponent controls;
private StringConfigurer addressConfig;
private JList myList;
private DefaultListModel addressBook;
private AddressBookEntry currentEntry;
private boolean enabled = true;
private PropertyChangeSupport changeSupport = new PropertyChangeSupport(this);
private static ServerAddressBook instance;
private static String localIPAddress;
private static String externalIPAddress;
private JButton addButton;
private JButton removeButton;
private JButton editButton;
private JButton setButton;
public static ServerAddressBook getInstance() {
return instance;
}
public static void editCurrentServer(boolean connected) {
instance.editCurrent(connected);
}
public static void changeServerPopup(JComponent source) {
instance.showPopup(source);
}
public static String getLocalAddress() {
if (localIPAddress == null) {
try {
localIPAddress = getLocalHostLANAddress().getHostAddress();
}
catch (UnknownHostException e) {
localIPAddress = "?"; //$NON-NLS-1$
}
}
return localIPAddress;
}
public static String getExternalAddress() {
return getExternalAddress("?"); //$NON-NLS-1$
}
public static String getExternalAddress(String dflt) {
if (externalIPAddress == null) {
externalIPAddress = dflt;
try {
externalIPAddress = discoverMyIpAddressFromRemote();
}
catch (IOException e) {
externalIPAddress = "?"; //$NON-NLS-1$
}
}
return externalIPAddress;
}
private static String discoverMyIpAddressFromRemote() throws IOException {
String theIp = null;
HttpRequestWrapper r = new HttpRequestWrapper("http://www.vassalengine.org/util/getMyAddress"); //$NON-NLS-1$
List<String> l = r.doGet(null);
if (!l.isEmpty()) {
theIp = l.get(0);
}
else {
throw new IOException(Resources.getString("Server.empty_response")); //$NON-NLS-1$
}
return theIp;
}
/**
* Returns an <code>InetAddress</code> object encapsulating what is most likely the machine's LAN IP address.
* <p/>
* This method is intended for use as a replacement of JDK method <code>InetAddress.getLocalHost</code>, because
* that method is ambiguous on Linux systems. Linux systems enumerate the loopback network interface the same
* way as regular LAN network interfaces, but the JDK <code>InetAddress.getLocalHost</code> method does not
* specify the algorithm used to select the address returned under such circumstances, and will often return the
* loopback address, which is not valid for network communication. Details
* <a href="http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4665037">here</a>.
* <p/>
* This method will scan all IP addresses on all network interfaces on the host machine to determine the IP address
* most likely to be the machine's LAN address. If the machine has multiple IP addresses, this method will prefer
* a site-local IP address (e.g. 192.168.x.x or 10.10.x.x, usually IPv4) if the machine has one (and will return the
* first site-local address if the machine has more than one), but if the machine does not hold a site-local
* address, this method will return simply the first non-loopback address found (IPv4 or IPv6).
* <p/>
* If this method cannot find a non-loopback address using this selection algorithm, it will fall back to
* calling and returning the result of JDK method <code>InetAddress.getLocalHost</code>.
* <p/>
*
* @throws UnknownHostException If the LAN address of the machine cannot be found.
*
* Thanks to https://issues.apache.org/jira/browse/JCS-40 for this code
*/
private static InetAddress getLocalHostLANAddress() throws UnknownHostException {
try {
InetAddress candidateAddress = null;
// Iterate all NICs (network interface cards)...
for (Enumeration<NetworkInterface> ifaces = NetworkInterface.getNetworkInterfaces(); ifaces.hasMoreElements();) {
NetworkInterface iface = (NetworkInterface) ifaces.nextElement();
// Iterate all IP addresses assigned to each card...
for (Enumeration<InetAddress> inetAddrs = iface.getInetAddresses(); inetAddrs.hasMoreElements();) {
InetAddress inetAddr = (InetAddress) inetAddrs.nextElement();
if (!inetAddr.isLoopbackAddress()) {
if (inetAddr.isSiteLocalAddress()) {
// Found non-loopback site-local address. Return it immediately...
return inetAddr;
}
else if (candidateAddress == null) {
// Found non-loopback address, but not necessarily site-local.
// Store it as a candidate to be returned if site-local address is not subsequently found...
candidateAddress = inetAddr;
// Note that we don't repeatedly assign non-loopback non-site-local addresses as candidates,
// only the first. For subsequent iterations, candidate will be non-null.
}
}
}
}
if (candidateAddress != null) {
// We did not find a site-local address, but we found some other non-loopback address.
// Server might have a non-site-local address assigned to its NIC (or it might be running
// IPv6 which deprecates the "site-local" concept).
// Return this non-loopback candidate address...
return candidateAddress;
}
// At this point, we did not find a non-loopback address.
// Fall back to returning whatever InetAddress.getLocalHost() returns...
InetAddress jdkSuppliedAddress = InetAddress.getLocalHost();
if (jdkSuppliedAddress == null) {
throw new UnknownHostException("The JDK InetAddress.getLocalHost() method unexpectedly returned null.");
}
return jdkSuppliedAddress;
}
catch (Exception e) {
UnknownHostException unknownHostException = new UnknownHostException("Failed to determine LAN address: " + e);
unknownHostException.initCause(e);
throw unknownHostException;
}
}
public ServerAddressBook() {
instance = this;
}
public JComponent getControls() {
if (controls == null) {
controls = new JPanel(new MigLayout());
addressConfig = new StringConfigurer(ADDRESS_PREF, null, ""); //$NON-NLS-1$
Prefs.getGlobalPrefs().addOption(null, addressConfig);
addressBook = new DefaultListModel();
loadAddressBook();
myList = new JList(addressBook);
myList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
myList.setCellRenderer(new MyRenderer());
myList.addListSelectionListener(new ListSelectionListener() {
public void valueChanged(ListSelectionEvent evt) {
updateButtonVisibility();
}
});
myList.addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent e) {
if (editButton.isEnabled() && e.getClickCount() == 2) {
int index = myList.locationToIndex(e.getPoint());
editServer(index);
}
}
});
final JScrollPane scroll = new JScrollPane(myList);
myList.repaint();
controls.add(scroll, "grow, push, w 500, h 400, wrap, span 4"); //$NON-NLS-1$
setButton = new JButton(Resources.getString("ServerAddressBook.set_current")); //$NON-NLS-1$
setButton.setToolTipText(Resources.getString("ServerAddressBook.set_selected_server")); //$NON-NLS-1$
setButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
setCurrentServer(myList.getSelectedIndex());
}
});
addButton = new JButton(Resources.getString(Resources.ADD));
addButton.setToolTipText(Resources.getString("ServerAddressBook.add_jabber_server")); //$NON-NLS-1$
addButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
addServer();
}
});
removeButton = new JButton(Resources.getString(Resources.REMOVE));
removeButton.setToolTipText(Resources.getString("ServerAddressBook.remove_selected_server")); //$NON-NLS-1$
removeButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
removeServer(myList.getSelectedIndex());
}
});
editButton = new JButton(Resources.getString(Resources.EDIT));
editButton.setToolTipText(Resources.getString("ServerAddressBook.edit_server")); //$NON-NLS-1$
editButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
editServer(myList.getSelectedIndex());
}
});
controls.add(addButton, "grow, push"); //$NON-NLS-1$
controls.add(editButton, "grow, push"); //$NON-NLS-1$
controls.add(removeButton, "grow, push"); //$NON-NLS-1$
controls.add(setButton, "grow, push"); //$NON-NLS-1$
updateButtonVisibility();
}
return controls;
}
public void setEnabled(boolean b) {
enabled = b;
updateButtonVisibility();
}
public boolean isEnabled() {
return enabled;
}
public void setFrozen(boolean b) {
frozen = b;
}
private void updateButtonVisibility() {
final int index = myList.getSelectedIndex();
if (index >= 0) {
final AddressBookEntry e = (AddressBookEntry) addressBook.get(index);
editButton.setEnabled(e.isEditable() && (isEnabled() || !e.isCurrent()));
removeButton.setEnabled(e.isRemovable() && !e.isCurrent());
setButton.setEnabled(isEnabled() && !e.isCurrent());
}
else {
editButton.setEnabled(false);
removeButton.setEnabled(false);
setButton.setEnabled(false);
}
}
public void setCurrentServer(Properties p) {
// Check for Basic Types, regardless of other properties
int index = 0;
final String type = p.getProperty(TYPE_KEY);
final String dtype = p.getProperty(DYNAMIC_TYPE);
final String ctype = p.getProperty(P2P_MODE_KEY);
for (Enumeration<?> e = addressBook.elements(); e.hasMoreElements();) {
final AddressBookEntry entry = (AddressBookEntry) e.nextElement();
final Properties ep = entry.getProperties();
if (ep.equals(p)) {
setCurrentServer(index);
return;
}
else if (DYNAMIC_TYPE.equals(type) && DYNAMIC_TYPE.equals(ep.getProperty(TYPE_KEY))
&& ep.getProperty(DYNAMIC_TYPE).equals(dtype)) {
setCurrentServer(index);
return;
}
else if (P2P_TYPE.equals(type) && P2P_TYPE.equals(ep.getProperty(TYPE_KEY))
&& ep.getProperty(P2P_MODE_KEY).equals(ctype)) {
setCurrentServer(index);
}
index++;
}
// Some Server we don't know about, add a server entry
final AddressBookEntry newEntry = buildEntry(p);
if (newEntry != null) {
addressBook.addElement(newEntry);
setCurrentServer(addressBook.indexOf(newEntry));
}
saveAddressBook();
}
private void setCurrentServer(AddressBookEntry e) {
setCurrentServer(addressBook.indexOf(e));
}
private void setCurrentServer(int index) {
final AddressBookEntry e = (AddressBookEntry) addressBook.get(index);
if (currentEntry != null) {
currentEntry.setCurrent(false);
}
final Properties oldProps = currentEntry == null ? null : currentEntry.getProperties();
currentEntry = e;
currentEntry.setCurrent(true);
if (!frozen) {
changeSupport.firePropertyChange(CURRENT_SERVER, oldProps, e.getProperties());
}
updateButtonVisibility();
myList.repaint();
}
protected Properties getCurrentServerProperties() {
return currentEntry.getProperties();
}
public void showPopup(JComponent source) {
final JPopupMenu popup = new JPopupMenu();
for (Enumeration<?> e = addressBook.elements(); e.hasMoreElements();) {
final AddressBookEntry entry = (AddressBookEntry) e.nextElement();
final JMenuItem item = new JMenuItem(entry.toString());
final AbstractAction action = new MenuAction(entry);
item.setAction(action);
item.setIcon(entry.getIcon(IconFamily.SMALL));
popup.add(item);
}
popup.show(source, 0, 0);
}
private class MenuAction extends AbstractAction {
private static final long serialVersionUID = 1L;
private AddressBookEntry entry;
public MenuAction (AddressBookEntry e) {
super(e.toString());
entry = e;
}
public void actionPerformed(ActionEvent e) {
ServerAddressBook.getInstance().setCurrentServer(entry);
}
}
public void addPropertyChangeListener(PropertyChangeListener l) {
changeSupport.addPropertyChangeListener(l);
}
public void removePropertyChangeListener(PropertyChangeListener l) {
changeSupport.removePropertyChangeListener(l);
}
public Icon getCurrentIcon() {
return currentEntry.getIcon(CONTROLS_ICON_SIZE);
}
public String getCurrentDescription() {
return currentEntry.toString();
}
private void editCurrent(boolean connected) {
if (currentEntry != null) {
editServer(addressBook.indexOf(currentEntry), connected);
}
}
private void editServer(int index) {
editServer(index, true);
}
private void editServer(int index, boolean enabled) {
final AddressBookEntry e = (AddressBookEntry) addressBook.get(index);
final boolean current = e.equals(currentEntry);
final Properties oldProps = e.getProperties();
if (e.edit(enabled) && current) {
changeSupport.firePropertyChange(CURRENT_SERVER, oldProps, e.getProperties());
}
}
private void removeServer(int index) {
final AddressBookEntry e = (AddressBookEntry) addressBook.get(index);
int i = JOptionPane.showConfirmDialog(GameModule.getGameModule().getFrame(), Resources
.getString("ServerAddressBook.remove_server", e.getDescription())); //$NON-NLS-1$
if (i == 0) {
addressBook.remove(index);
myList.setSelectedIndex(-1);
myList.repaint();
updateButtonVisibility();
saveAddressBook();
}
}
private void addServer() {
final JPopupMenu popup = new JPopupMenu();
final JMenuItem p2pItem = new JMenuItem(Resources.getString("ServerAddressBook.peer_server"));
p2pItem.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
addEntry(new PeerServerEntry());
}});
final JMenuItem jabItem = new JMenuItem(Resources.getString("ServerAddressBook.jabber_server"));
jabItem.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
addEntry(new JabberEntry());
}});
// final JMenuItem privateItem = new JMenuItem(Resources.getString("ServerAddressBook.private_server"));
// privateItem.addActionListener(new ActionListener() {
// public void actionPerformed(ActionEvent arg0) {
// addEntry(new PrivateEntry());
// }});
popup.add(p2pItem);
// popup.add(privateItem);
popup.add(jabItem);
popup.show(addButton, 0, 0);
}
private void addEntry(AddressBookEntry e) {
if (e.edit()) {
addressBook.addElement(e);
saveAddressBook();
}
}
/**
* Set up the default server
* @return
*/
public Properties getDefaultServerProperties() {
// return (new VassalJabberEntry()).getProperties();
return (new LegacyEntry()).getProperties();
}
private void loadAddressBook() {
decodeAddressBook(addressConfig.getValueString());
// Remove any PeerClientEntry's, these are obsolete
final DefaultListModel newAddressBook = new DefaultListModel();
for (Enumeration<?> e = addressBook.elements(); e.hasMoreElements();) {
final AddressBookEntry entry = (AddressBookEntry) e.nextElement();
if (entry instanceof LegacyEntry) {
newAddressBook.add(0, entry);
}
else if (! (entry instanceof PeerClientEntry)) {
newAddressBook.addElement(entry);
}
}
addressBook = newAddressBook;
// Ensure that the Address Book has the basic
// servers in it.
boolean legacy = false;
boolean jabber = false;
boolean peerServer = false;
// boolean peerClient = false;
boolean updated = false;
for (Enumeration<?> e = addressBook.elements(); e.hasMoreElements();) {
final AddressBookEntry entry = (AddressBookEntry) e.nextElement();
if (entry instanceof LegacyEntry) {
legacy = true;
}
else if (entry instanceof VassalJabberEntry) {
jabber = true;
}
else if (entry instanceof PeerServerEntry) {
peerServer = true;
}
// else if (entry instanceof PeerClientEntry) {
// peerClient = true;
// }
}
if (!jabber) {
final AddressBookEntry entry = new VassalJabberEntry();
entry.setCurrent(true);
currentEntry = entry;
addressBook.addElement(entry);
updated = true;
}
if (!legacy) {
addressBook.addElement(new LegacyEntry());
updated = true;
}
if (!peerServer) {
addressBook.addElement(new PeerServerEntry());
updated = true;
}
// if (!peerClient) {
// addressBook.addElement(new PeerClientEntry());
// updated = true;
// }
if (updated) {
saveAddressBook();
}
}
private void saveAddressBook() {
addressConfig.setValue(encodeAddressBook());
if (myList != null) {
myList.repaint();
}
}
private String encodeAddressBook() {
SequenceEncoder se = new SequenceEncoder(',');
for (Enumeration<?> e = addressBook.elements(); e.hasMoreElements();) {
final AddressBookEntry entry = (AddressBookEntry) e.nextElement();
if (entry != null) {
se.append(entry.encode());
}
}
return se.getValue();
}
private void decodeAddressBook(String s) {
addressBook.clear();
for (SequenceEncoder.Decoder sd = new SequenceEncoder.Decoder(s, ','); sd.hasMoreTokens();) {
final String token = sd.nextToken(""); //$NON-NLS-1$
if (token.length() > 0) {
final AddressBookEntry entry = buildEntry(token);
if (entry != null) {
addressBook.addElement(buildEntry(token));
}
}
}
}
/**
* Return an appropriately typed Entry, depending on the Server Properties
* passed
*
* @param s
* Encoded Server Properties
* @return Entry
*/
private AddressBookEntry buildEntry(String s) {
Properties newProperties = new Properties();
try {
newProperties = new PropertiesEncoder(s).getProperties();
}
catch (IOException e) {
// FIXME: Error Message?
}
return buildEntry(newProperties);
}
private AddressBookEntry buildEntry(Properties newProperties) {
final String type = newProperties.getProperty(TYPE_KEY);
if (JABBER_TYPE.equals(type)) {
return new JabberEntry(newProperties);
}
else if (DYNAMIC_TYPE.equals(type)) {
final String dtype = newProperties.getProperty(DYNAMIC_TYPE);
if (JABBER_TYPE.equals(dtype)) {
return new VassalJabberEntry(newProperties);
}
else if (LEGACY_TYPE.equals(dtype)) {
return new LegacyEntry(newProperties);
}
}
else if (P2P_TYPE.equals(type)) {
final String ctype = newProperties.getProperty(P2P_MODE_KEY);
if (P2P_SERVER_MODE.equals(ctype)) {
return new PeerServerEntry(newProperties);
}
else if (P2P_CLIENT_MODE.equals(ctype)) {
return new PeerClientEntry(newProperties);
}
}
return null;
}
/**
* Base class for an Address Book Entry
*
*/
private abstract class AddressBookEntry implements Comparable<AddressBookEntry> {
protected Properties properties = new Properties();
protected boolean current;
protected AddressBookEntry() {
this(new Properties());
}
protected AddressBookEntry(Properties props) {
properties = props;
}
protected String getDescription() {
return getProperty(DESCRIPTION_KEY);
}
protected void setDescription(String desc) {
properties.setProperty(DESCRIPTION_KEY, desc);
}
public String getProperty(String key) {
return properties.getProperty(key);
}
public void setProperty(String key, String value) {
properties.setProperty(key, value);
}
protected boolean isRemovable() {
return true;
}
protected boolean isEditable() {
return true;
}
protected abstract String getIconName();
protected Icon getIcon(int size) {
return IconFactory.getIcon(getIconName(), size);
}
public String getType() {
return properties.getProperty(TYPE_KEY);
}
public void setType(String t) {
properties.setProperty(TYPE_KEY, t);
}
public Properties getProperties() {
return properties;
}
public void setProperties(Properties p) {
properties = p;
}
public String encode() {
return new PropertiesEncoder(properties).getStringValue();
}
public int compareTo(AddressBookEntry target) {
if (getType().equals(target.getType())) {
return getDescription().compareTo(target.getDescription());
}
return getType().compareTo(target.getType());
}
public boolean isCurrent() {
return current;
}
public void setCurrent(boolean b) {
current = b;
}
protected boolean isDescriptionEditable() {
return true;
}
public boolean edit() {
return edit(true);
}
public boolean edit(boolean enabled) {
if (isEditable()) {
final ServerConfig config = getEditor(getProperties(), enabled);
final Integer result = (Integer) Dialogs.showDialog(null,
Resources.getString("ServerAddressBook.edit_server_configuration"), //$NON-NLS-1$
config.getControls(), JOptionPane.PLAIN_MESSAGE, null, JOptionPane.OK_CANCEL_OPTION,
null, null, null, null);
if (result != null && result.intValue() == 0) {
if (enabled) {
setProperties(config.getProperties());
saveAddressBook();
}
return true;
}
}
return false;
}
protected abstract void setAdditionalProperties(Properties props);
protected abstract void getAdditionalProperties(Properties props);
protected abstract void addAdditionalControls(JComponent c, boolean enabled);
public ServerConfig getEditor(Properties p, boolean enabled) {
return new ServerConfig(p, this, enabled);
}
class ServerConfig {
protected JComponent configControls;
protected JTextField description = new JTextField();
protected AddressBookEntry entry;
boolean enabled;
public ServerConfig() {
}
public ServerConfig(Properties props, AddressBookEntry entry, boolean enabled) {
this();
this.entry = entry;
this.enabled = enabled;
description.setText(props.getProperty(DESCRIPTION_KEY));
setAdditionalProperties(props);
}
protected boolean isEnabled() {
return enabled;
}
public JComponent getControls() {
if (configControls == null) {
configControls = new JPanel();
configControls.setLayout(new MigLayout("", "[align right]rel[]", "")); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
configControls.add(
new JLabel(IconFactory.getIcon(entry.getIconName(), IconFamily.LARGE)),
"span 2, align center, wrap"); //$NON-NLS-1$
configControls.add(new JLabel(Resources.getString("Editor.description_label"))); //$NON-NLS-1$
configControls.add(description, "wrap, grow, push"); //$NON-NLS-1$
entry.addAdditionalControls(configControls, enabled);
description.setEditable(isDescriptionEditable() && isEnabled());
}
return configControls;
}
public Properties getProperties() {
final Properties props = new Properties();
props.setProperty(DESCRIPTION_KEY, description.getText());
getAdditionalProperties(props);
return props;
}
}
}
/**
* Address Book entry for a user defined Jabber Server
*
*/
private class JabberEntry extends AddressBookEntry {
private JTextField jabberHost = new JTextField();
private JTextField jabberPort = new JTextField();
private JTextField jabberUser = new JTextField();
private JTextField jabberPw = new JTextField();
private JButton testButton;
public JabberEntry() {
this(new Properties());
setType(JABBER_TYPE);
setDescription(""); //$NON-NLS-1$
setProperty(JabberClientFactory.JABBER_PORT, "5222"); //$NON-NLS-1$
}
public JabberEntry(Properties props) {
super(props);
}
public String toString() {
return Resources.getString("ServerAddressBook.jabber_server") + " " + getDescription() + " [" //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ getProperty(JabberClientFactory.JABBER_HOST) + ":" //$NON-NLS-1$
+ getProperty(JabberClientFactory.JABBER_PORT) + " " //$NON-NLS-1$
+ getProperty(JabberClientFactory.JABBER_LOGIN) + "/" //$NON-NLS-1$
+ getProperty(JabberClientFactory.JABBER_PWD) + "]"; //$NON-NLS-1$
}
protected String getIconName() {
return "jabber"; //$NON-NLS-1$
}
protected boolean isDescriptionEditable() {
return true;
}
protected void setAdditionalProperties(Properties props) {
jabberHost.setText(props.getProperty(JabberClientFactory.JABBER_HOST));
jabberPort.setText(props.getProperty(JabberClientFactory.JABBER_PORT));
jabberUser.setText(props.getProperty(JabberClientFactory.JABBER_LOGIN));
jabberPw.setText(props.getProperty(JabberClientFactory.JABBER_PWD));
}
protected void getAdditionalProperties(Properties props) {
props.setProperty(JabberClientFactory.JABBER_HOST, jabberHost.getText());
props.setProperty(JabberClientFactory.JABBER_PORT, jabberPort.getText());
props.setProperty(JabberClientFactory.JABBER_LOGIN, jabberUser.getText());
props.setProperty(JabberClientFactory.JABBER_PWD, jabberPw.getText());
props.setProperty(TYPE_KEY, JabberClientFactory.JABBER_SERVER_TYPE);
}
protected void addAdditionalControls(JComponent c, boolean enabled) {
jabberHost.setEditable(enabled);
jabberPort.setEditable(enabled);
jabberUser.setEditable(enabled);
jabberPw.setEditable(enabled);
c.add(new JLabel(Resources.getString("ServerAddressBook.jabber_host"))); //$NON-NLS-1$
c.add(jabberHost, "wrap, grow, push"); //$NON-NLS-1$
c.add(new JLabel(Resources.getString("ServerAddressBook.port"))); //$NON-NLS-1$
c.add(jabberPort, "wrap, grow, push"); //$NON-NLS-1$
c.add(new JLabel(Resources.getString("ServerAddressBook.user_name"))); //$NON-NLS-1$
c.add(jabberUser, "wrap, grow, push"); //$NON-NLS-1$
c.add(new JLabel(Resources.getString("ServerAddressBook.password"))); //$NON-NLS-1$
c.add(jabberPw, "wrap, grow, push"); //$NON-NLS-1$
testButton = new JButton(Resources.getString("ServerAddressBook.test_connection")); //$NON-NLS-1$
testButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
test();
}
});
c.add(testButton, "span 2, align center, wrap"); //$NON-NLS-1$
}
protected void test() {
final JTextArea result = new JTextArea(10, 30);
result.setText(JabberClient.testConnection(jabberHost.getText(), jabberPort.getText(),
jabberUser.getText(), jabberPw.getText()));
try {
Dialogs.showDialog(null,
Resources.getString("ServerAddressBook.connection_test"), //$NON-NLS-1$
result, JOptionPane.INFORMATION_MESSAGE, null, JOptionPane.OK_CANCEL_OPTION, null, null,
null, null);
}
catch (IllegalStateException ex) {
ex.printStackTrace();
}
}
}
/**
* Address Book entry for the VASSAL Jabber server
*
*/
private class VassalJabberEntry extends AddressBookEntry {
protected JTextField jabberUser = new JTextField();
protected JTextField jabberPw = new JTextField();
public VassalJabberEntry() {
this(new Properties());
setDescription("VASSAL" + Resources.getString("ServerAddressBook.jabber_server")); //$NON-NLS-1$ //$NON-NLS-2$
setType(DYNAMIC_TYPE);
setProperty(DYNAMIC_TYPE, JabberClientFactory.JABBER_SERVER_TYPE);
setProperty(JabberClientFactory.JABBER_LOGIN, ""); //$NON-NLS-1$
setProperty(JabberClientFactory.JABBER_PWD, ""); //$NON-NLS-1$
setProperty(DynamicClientFactory.URL, DynamicClient.JABBER_URL);
}
public VassalJabberEntry(Properties props) {
super(props);
}
public String toString() {
String details;
final String login = getProperty(JabberClientFactory.JABBER_LOGIN);
final String pw = getProperty(JabberClientFactory.JABBER_PWD);
if (login == null || login.length() == 0 || pw == null || pw.length() == 0) {
details = Resources.getString("ServerAddressBook.login_details_required"); //$NON-NLS-1$
}
else {
details = getProperty(JabberClientFactory.JABBER_LOGIN) + "/" //$NON-NLS-1$
+ getProperty(JabberClientFactory.JABBER_PWD);
}
return getDescription() + " [" + details + "]"; //$NON-NLS-1$ //$NON-NLS-2$
}
protected boolean isRemovable() {
return false;
}
protected boolean isDescriptionEditable() {
return false;
}
protected String getIconName() {
return "VASSAL-jabber"; //$NON-NLS-1$
}
protected void setAdditionalProperties(Properties props) {
jabberUser.setText(props.getProperty(JabberClientFactory.JABBER_LOGIN));
jabberPw.setText(props.getProperty(JabberClientFactory.JABBER_PWD));
setType(DYNAMIC_TYPE);
setProperty(DYNAMIC_TYPE, JABBER_TYPE);
}
protected void getAdditionalProperties(Properties props) {
props.setProperty(JabberClientFactory.JABBER_LOGIN, jabberUser.getText());
props.setProperty(JabberClientFactory.JABBER_PWD, jabberPw.getText());
props.setProperty(TYPE_KEY, DYNAMIC_TYPE);
props.setProperty(DYNAMIC_TYPE, JABBER_TYPE);
}
protected void addAdditionalControls(JComponent c, boolean enabled) {
jabberUser.setEditable(enabled);
jabberPw.setEditable(enabled);
c.add(new JLabel(Resources.getString("ServerAddressBook.user_name"))); //$NON-NLS-1$
c.add(jabberUser, "wrap, grow, push"); //$NON-NLS-1$
c.add(new JLabel(Resources.getString("ServerAddressBook.password"))); //$NON-NLS-1$
c.add(jabberPw, "wrap, grow, push"); //$NON-NLS-1$
}
}
/**
* Address Book entry for the VASSAL legacy server
*
*/
private class LegacyEntry extends AddressBookEntry {
public LegacyEntry() {
this(new Properties());
setDescription(Resources.getString("ServerAddressBook.legacy_server")); //$NON-NLS-1$
setType(DYNAMIC_TYPE);
setProperty(DynamicClientFactory.DYNAMIC_TYPE, NodeClientFactory.NODE_TYPE);
setProperty(DynamicClientFactory.URL, DynamicClient.LEGACY_URL);
}
public LegacyEntry(Properties props) {
super(props);
}
public String toString() {
return getDescription();
}
protected String getIconName() {
return "VASSAL"; //$NON-NLS-1$
}
protected boolean isRemovable() {
return false;
}
protected boolean isEditable() {
return false;
}
protected boolean isDescriptionEditable() {
return false;
}
protected void addAdditionalControls(JComponent c, boolean enabled) {
}
protected void getAdditionalProperties(Properties props) {
}
protected void setAdditionalProperties(Properties props) {
}
}
/**
* Address Book entry for a Private VASSAL server
*
*/
// private class PrivateEntry extends AddressBookEntry {
//
// private JTextField serverPort = new JTextField();
// private JTextField serverIp = new JTextField();
//
// public PrivateEntry() {
// this(new Properties());
// setDescription(Resources.getString("ServerAddressBook.private_server")); //$NON-NLS-1$
// setType(PRIVATE_TYPE);
// setProperty(PrivateClientFactory.PORT, "5050"); //$NON-NLS-1$
// }
//
// public PrivateEntry(Properties props) {
// super(props);
// }
//
// public String toString() {
// return Resources.getString("ServerAddressBook.private_server") + " [" + getDescription() + "]";
// }
//
// public String getDescription() {
// return super.getDescription() + " " + getProperty(PrivateClientFactory.URL) + ":" + getProperty(PrivateClientFactory.PORT);
// }
//
// protected String getIconName() {
// return "VASSAL-private"; //$NON-NLS-1$
// }
//
// protected boolean isRemovable() {
// return true;
// }
//
// protected boolean isEditable() {
// return true;
// }
//
// protected boolean isDescriptionEditable() {
// return true;
// }
//
// protected void addAdditionalControls(JComponent c, boolean enabled) {
// serverIp.setEditable(enabled);
// c.add(new JLabel(Resources.getString("ServerAddressBook.server_ip"))); //$NON-NLS-1$
// c.add(serverIp, "wrap, growx, push"); //$NON-NLS-1$
//
// serverPort.setEditable(enabled);
// c.add(new JLabel(Resources.getString("ServerAddressBook.server_port"))); //$NON-NLS-1$
// c.add(serverPort, "wrap, growx, push"); //$NON-NLS-1$
// }
//
// protected void getAdditionalProperties(Properties props) {
// props.setProperty(PrivateClientFactory.URL, serverIp.getText());
// props.setProperty(PrivateClientFactory.PORT, serverPort.getText());
// props.setProperty(TYPE_KEY, PRIVATE_TYPE);
// }
//
// protected void setAdditionalProperties(Properties props) {
// serverIp.setText(props.getProperty(PrivateClientFactory.URL));
// serverPort.setText(props.getProperty(PrivateClientFactory.PORT));
// }
//
// }
/**
* Address Book Entry for a Peer to Peer connection
*
*/
private class PeerServerEntry extends AddressBookEntry {
private JTextField listenPort = new JTextField();
private JTextField serverPw = new JTextField();
public PeerServerEntry() {
super();
setDescription(Resources.getString("ServerAddressBook.peer_server")); //$NON-NLS-1$
setType(P2P_TYPE);
setProperty(P2P_MODE_KEY, P2P_SERVER_MODE);
setProperty(P2PClientFactory.P2P_LISTEN_PORT, "5050"); //$NON-NLS-1$
setProperty(P2PClientFactory.P2P_SERVER_PW, "xyzzy"); //$NON-NLS-1$
}
public PeerServerEntry(Properties props) {
super(props);
}
public String toString() {
return Resources.getString("ServerAddressBook.peer_server") + " ["+getProperty(DESCRIPTION_KEY)+"]";
}
public boolean isRemovable() {
return true;
}
protected boolean isDescriptionEditable() {
return true;
}
protected String getIconName() {
return "network-server"; //$NON-NLS-1$
}
protected void setAdditionalProperties(Properties p) {
setType(P2P_TYPE);
setProperty(P2P_MODE_KEY, P2P_SERVER_MODE);
listenPort.setText(p.getProperty(P2PClientFactory.P2P_LISTEN_PORT));
serverPw.setText(p.getProperty(P2PClientFactory.P2P_SERVER_PW));
}
protected void getAdditionalProperties(Properties props) {
props.setProperty(TYPE_KEY, P2P_TYPE);
props.setProperty(P2P_MODE_KEY, P2P_SERVER_MODE);
props.setProperty(P2PClientFactory.P2P_LISTEN_PORT, listenPort.getText());
props.setProperty(P2PClientFactory.P2P_SERVER_PW, serverPw.getText());
}
protected void addAdditionalControls(JComponent c, boolean enabled) {
listenPort.setEditable(enabled);
c.add(new JLabel(Resources.getString("ServerAddressBook.listen_port"))); //$NON-NLS-1$
c.add(listenPort, "wrap, growx, push"); //$NON-NLS-1$
serverPw.setEditable(enabled);
c.add(new JLabel(Resources.getString("ServerAddressBook.server_password"))); //$NON-NLS-1$
c.add(serverPw, "wrap, growx, push"); //$NON-NLS-1$
c.add(new JLabel(Resources.getString("Peer2Peer.internet_address"))); //$NON-NLS-1$
final JTextField externalIP = new JTextField(getExternalAddress());
externalIP.setEditable(false);
c.add(externalIP, "wrap, growx, push"); //$NON-NLS-1$
if (!getLocalAddress().equals(getExternalAddress())) {
c.add(new JLabel(Resources.getString("Peer2Peer.local_address"))); //$NON-NLS-1$
final JTextField localIP = new JTextField(getLocalAddress());
localIP.setEditable(false);
c.add(localIP, "wrap, growx, push"); //$NON-NLS-1$
}
}
}
/**
* Address Book Entry for a Peer to Peer connection in Client Mode
*
*/
@Deprecated private class PeerClientEntry extends AddressBookEntry {
private JTextField listenPort = new JTextField();
private JTextField serverName = new JTextField();
private JTextField serverPort = new JTextField();
private JTextField serverIp = new JTextField();
@SuppressWarnings("unused")
public PeerClientEntry() {
super();
setDescription(Resources.getString("ServerAddressBook.peer_client")); //$NON-NLS-1$
setType(P2P_TYPE);
setProperty(P2P_MODE_KEY, P2P_CLIENT_MODE);
setProperty(P2PClientFactory.P2P_LISTEN_PORT, "5050"); //$NON-NLS-1$
setProperty(P2PClientFactory.P2P_SERVER_NAME, ""); //$NON-NLS-1$
setProperty(P2PClientFactory.P2P_SERVER_PORT, "5050"); //$NON-NLS-1$
setProperty(P2PClientFactory.P2P_SERVER_IP, ""); //$NON-NLS-1$
}
public PeerClientEntry(Properties props) {
super(props);
}
public String toString() {
final String listenPort = getProperty(P2PClientFactory.P2P_LISTEN_PORT);
final String serverName = getProperty(P2PClientFactory.P2P_SERVER_NAME);
final String serverIp = getProperty(P2PClientFactory.P2P_SERVER_IP);
final String serverPort = getProperty(P2PClientFactory.P2P_SERVER_PORT);
final StringBuffer desc = new StringBuffer(Resources.getString("ServerAddressBook.peer_client"));
if (serverIp == null || serverIp.length() == 0) {
desc.append(" [");
desc.append(Resources.getString("ServerAddressBook.listening", listenPort));
desc.append("]");
}
else {
if (serverName != null && serverName.length() > 0) {
desc.append(" - ");
desc.append(serverName);
}
if (serverIp != null && serverIp.length() > 0) {
desc.append(" [");
desc.append(serverIp);
desc.append(":");
desc.append(serverPort);
desc.append("]");
}
}
return desc.toString();
}
public boolean isRemovable() {
return true;
}
protected boolean isDescriptionEditable() {
return false;
}
protected String getIconName() {
return "network-idle"; //$NON-NLS-1$
}
protected void setAdditionalProperties(Properties p) {
setType(P2P_TYPE);
setProperty(P2P_MODE_KEY, P2P_CLIENT_MODE);
listenPort.setText(p.getProperty(P2PClientFactory.P2P_LISTEN_PORT));
serverIp.setText(p.getProperty(P2PClientFactory.P2P_SERVER_IP));
serverPort.setText(p.getProperty(P2PClientFactory.P2P_SERVER_PORT));
serverName.setText(p.getProperty(P2PClientFactory.P2P_SERVER_NAME));
setDescription(toString());
}
protected void getAdditionalProperties(Properties props) {
props.setProperty(TYPE_KEY, P2P_TYPE);
props.setProperty(P2P_MODE_KEY, P2P_CLIENT_MODE);
props.setProperty(P2PClientFactory.P2P_LISTEN_PORT, listenPort.getText());
props.setProperty(P2PClientFactory.P2P_SERVER_IP, serverIp.getText());
props.setProperty(P2PClientFactory.P2P_SERVER_PORT, serverPort.getText());
props.setProperty(P2PClientFactory.P2P_SERVER_NAME, serverName.getText());
}
protected void addAdditionalControls(JComponent c, boolean enabled) {
serverName.setEditable(enabled);
c.add(new JLabel(Resources.getString("ServerAddressBook.server_name"))); //$NON-NLS-1$
c.add(serverName, "wrap, growx, push"); //$NON-NLS-1$
serverIp.setEditable(enabled);
c.add(new JLabel(Resources.getString("ServerAddressBook.server_ip"))); //$NON-NLS-1$
c.add(serverIp, "wrap, growx, push"); //$NON-NLS-1$
serverPort.setEditable(enabled);
c.add(new JLabel(Resources.getString("ServerAddressBook.server_port"))); //$NON-NLS-1$
c.add(serverPort, "wrap, growx, push"); //$NON-NLS-1$
listenPort.setEditable(enabled);
c.add(new JLabel(Resources.getString("ServerAddressBook.invite_port"))); //$NON-NLS-1$
c.add(listenPort, "wrap, growx, push"); //$NON-NLS-1$
c.add(new JLabel(Resources.getString("Peer2Peer.internet_address"))); //$NON-NLS-1$
final JTextField externalIP = new JTextField(getExternalAddress());
externalIP.setEditable(false);
c.add(externalIP, "wrap, growx, push"); //$NON-NLS-1$
if (!getLocalAddress().equals(getExternalAddress())) {
c.add(new JLabel(Resources.getString("Peer2Peer.local_address"))); //$NON-NLS-1$
final JTextField localIP = new JTextField(getLocalAddress());
localIP.setEditable(false);
c.add(localIP, "wrap, growx, push"); //$NON-NLS-1$
}
}
}
/**
* Customised List Cell Renderer for the JList display: - Display the Icon
* appropriate to the Server Entry - Highlight the currently selected server
*
*/
private class MyRenderer extends DefaultListCellRenderer {
private static final long serialVersionUID = 1L;
private Font standardFont;
private Font highlightFont;
public Component getListCellRendererComponent(JList list, Object value, int index,
boolean isSelected, boolean cellHasFocus) {
super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
if (standardFont == null) {
standardFont = getFont();
highlightFont = new Font(standardFont.getFamily(), Font.BOLD + Font.ITALIC, standardFont
.getSize());
}
if (value instanceof AddressBookEntry) {
final AddressBookEntry e = (AddressBookEntry) value;
setIcon(e.getIcon(LEAF_ICON_SIZE));
if (e.isCurrent()) {
setFont(highlightFont);
setText(e.toString() + Resources.getString("ServerAddressBook.current")); //$NON-NLS-1$
}
else {
setFont(standardFont);
}
}
return this;
}
}
}