/*
* SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
*
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
package net.java.sip.communicator.plugin.jabberaccregwizz;
import java.awt.*;
import java.awt.event.*;
import java.util.*;
import java.util.List;
import javax.swing.*;
import javax.swing.table.*;
import net.java.sip.communicator.service.protocol.*;
import net.java.sip.communicator.util.*;
import net.java.sip.communicator.util.swing.*;
/**
* ICE configuration panel.
*
* @author Yana Stamcheva
*/
public class IceConfigPanel
extends TransparentPanel
{
/**
* Serial version UID.
*/
private static final long serialVersionUID = 0L;
/**
* The check box allowing the user to choose to use ICE.
*/
private final JCheckBox iceBox = new SIPCommCheckBox(
Resources.getString("plugin.jabberaccregwizz.USE_ICE"));
/**
* The check box allowing the user to choose to automatically discover
* STUN servers.
*/
private final JCheckBox autoDiscoverBox = new SIPCommCheckBox(
Resources.getString("plugin.jabberaccregwizz.AUTO_DISCOVER_STUN"));
/**
* The check box allowing the user to choose to use the default
* SIP Communicator STUN server.
*/
private final JCheckBox defaultStunBox = new SIPCommCheckBox(
Resources.getResources().getI18NString(
"plugin.jabberaccregwizz.USE_DEFAULT_STUN_SERVER",
new String[]{Resources.getResources().getSettingsString(
"service.gui.APPLICATION_NAME")}));
/**
* The table model for our additional stun servers table.
*/
private final ServerTableModel tableModel = new ServerTableModel();
/**
* The stun server table.
*/
private final JTable table = new JTable(tableModel);
/**
* The check box allowing the user to choose to use JingleNodes.
*/
private final JCheckBox jnBox = new SIPCommCheckBox(
Resources.getString("plugin.jabberaccregwizz.USE_JINGLE_NODES"));
/**
* The check box allowing the user to choose to automatically discover
* JingleNodes relays.
*/
private final JCheckBox jnAutoDiscoverBox = new SIPCommCheckBox(
Resources.getString("plugin.jabberaccregwizz.AUTO_DISCOVER_JN"));
/**
* The table model for our additional stun servers table.
*/
private final ServerTableModel jnTableModel =
new ServerTableModel();
/**
* The JingleNodes server table.
*/
private final JTable jnTable = new JTable(jnTableModel);
/**
* Creates an instance of IceConfigPanel.
*/
public IceConfigPanel()
{
this.setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
iceBox.setAlignmentX(Component.LEFT_ALIGNMENT);
autoDiscoverBox.setAlignmentX(Component.LEFT_ALIGNMENT);
defaultStunBox.setAlignmentX(Component.LEFT_ALIGNMENT);
/* ICE and STUN/TURN discovery are enabled by default for a new account,
* these properties will be overridden for existing account when
* they get loaded
*/
iceBox.setSelected(true);
autoDiscoverBox.setSelected(true);
defaultStunBox.setSelected(true);
jnBox.setSelected(true);
jnAutoDiscoverBox.setSelected(true);
JPanel checkBoxPanel = new TransparentPanel(new GridLayout(0, 1));
checkBoxPanel.add(iceBox);
checkBoxPanel.add(autoDiscoverBox);
checkBoxPanel.add(defaultStunBox);
add(checkBoxPanel);
add(Box.createVerticalStrut(10));
add(createAdditionalServersComponent());
checkBoxPanel = new TransparentPanel(new GridLayout(0, 1));
checkBoxPanel.add(jnBox);
checkBoxPanel.add(jnAutoDiscoverBox);
add(checkBoxPanel);
add(Box.createVerticalStrut(10));
add(createAdditionalJingleNodesComponent());
}
/**
* Creates the list of additional STUN/TURN servers that are added by the
* user.
* @return the created component
*/
private Component createAdditionalServersComponent()
{
table.setPreferredScrollableViewportSize(new Dimension(450, 60));
tableModel.addColumn(
Resources.getString("plugin.jabberaccregwizz.IP_ADDRESS")
+ "/" + Resources.getString("service.gui.PORT"));
tableModel.addColumn(
Resources.getString("plugin.jabberaccregwizz.SUPPORT_TURN"));
table.setDefaultRenderer( StunServerDescriptor.class,
new ServerCellRenderer());
//Create the scroll pane and add the table to it.
JScrollPane scrollPane = new JScrollPane(table);
JButton addButton
= new JButton(Resources.getString("service.gui.ADD"));
addButton.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
StunConfigDialog stunDialog = new StunConfigDialog(false);
stunDialog.setVisible(true);
}
});
JButton editButton
= new JButton(Resources.getString("service.gui.EDIT"));
editButton.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
if(table.getSelectedRow() < 0)
return;
StunServerDescriptor stunServer
= (StunServerDescriptor) tableModel.getValueAt(
table.getSelectedRow(), 0);
if (stunServer != null)
{
StunConfigDialog dialog = new StunConfigDialog(
stunServer.getAddress(),
stunServer.getPort(),
stunServer.isTurnSupported(),
StringUtils.getUTF8String(
stunServer.getUsername()),
StringUtils.getUTF8String(
stunServer.getPassword()));
dialog.setVisible(true);
}
}
});
JButton deleteButton
= new JButton(Resources.getString("service.gui.DELETE"));
deleteButton.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
tableModel.removeRow(table.getSelectedRow());
}
});
TransparentPanel buttonsPanel
= new TransparentPanel(new FlowLayout(FlowLayout.RIGHT));
buttonsPanel.add(addButton);
buttonsPanel.add(editButton);
buttonsPanel.add(deleteButton);
TransparentPanel mainPanel = new TransparentPanel(new BorderLayout());
mainPanel.setBorder(BorderFactory.createTitledBorder(
Resources.getString(
"plugin.jabberaccregwizz.ADDITIONAL_STUN_SERVERS")));
mainPanel.add(scrollPane);
mainPanel.add(buttonsPanel, BorderLayout.SOUTH);
return mainPanel;
}
/**
* The STUN configuration window.
*/
private class StunConfigDialog extends SIPCommDialog
{
/**
* Serial version UID.
*/
private static final long serialVersionUID = 0L;
/**
* The main panel
*/
private final JPanel mainPanel
= new TransparentPanel(new BorderLayout());
/**
* The address of the stun server.
*/
private final JTextField addressField = new JTextField();
/**
* The port number field
*/
private final JTextField portField = new JTextField();
/**
* The input verifier that we will be using to validate port numbers.
*/
private final PortVerifier portVerifier = new PortVerifier();
/**
* The check box where user would indicate whether a STUN server is also
* a TURN server.
*/
private final JCheckBox supportTurnCheckBox = new JCheckBox(
Resources.getString("plugin.jabberaccregwizz.SUPPORT_TURN"));
/**
* The user name field
*/
private final JTextField usernameField = new JTextField();
/**
* The password field.
*/
private final JPasswordField passwordField = new JPasswordField();
/**
* The pane where we show errors.
*/
private JEditorPane errorMessagePane;
/**
* If the dialog is open via "edit" button.
*/
private final boolean isEditMode;
/**
* Default STUN/TURN port.
*/
private static final String DEFAULT_STUN_PORT = "3478";
/**
* Creates a new StunConfigDialog with filled in values.
*
* @param address the IP or FQDN of the server
* @param port the port number
* @param isSupportTurn a boolean indicating whether the server
* is also a TURN relay
* @param username the username we should use with this server
* @param password the password we should use with this server
*/
public StunConfigDialog(String address,
int port,
boolean isSupportTurn,
String username,
String password)
{
this(true);
addressField.setText(address);
portField.setText(Integer.toString( port ));
supportTurnCheckBox.setSelected(isSupportTurn);
usernameField.setText(username);
passwordField.setText(password);
if(isSupportTurn)
{
usernameField.setEnabled(true);
passwordField.setEnabled(true);
}
}
/**
* Creates an empty dialog.
*
* @param editMode true if the dialog is in "edit" state, false means
* "add" state
*/
public StunConfigDialog(boolean editMode)
{
super(false);
this.isEditMode = editMode;
setTitle(Resources.getString(
"plugin.jabberaccregwizz.ADD_STUN_SERVER"));
JLabel addressLabel = new JLabel(
Resources.getString("plugin.jabberaccregwizz.IP_ADDRESS"));
JLabel portLabel = new JLabel(
Resources.getString("service.gui.PORT"));
JLabel usernameLabel = new JLabel(
Resources.getString("plugin.jabberaccregwizz.TURN_USERNAME"));
JLabel passwordLabel = new JLabel(
Resources.getString("service.gui.PASSWORD"));
TransparentPanel labelsPanel
= new TransparentPanel(new GridLayout(0, 1));
labelsPanel.add(new JLabel());
labelsPanel.add(addressLabel);
labelsPanel.add(portLabel);
labelsPanel.add(usernameLabel);
labelsPanel.add(passwordLabel);
TransparentPanel valuesPanel
= new TransparentPanel(new GridLayout(0, 1));
usernameField.setEnabled(false);
passwordField.setEnabled(false);
portField.setText(DEFAULT_STUN_PORT);
valuesPanel.add(supportTurnCheckBox);
valuesPanel.add(addressField);
valuesPanel.add(portField);
valuesPanel.add(usernameField);
valuesPanel.add(passwordField);
//register an input verifier so that we would only accept valid
//port numbers.
portField.setInputVerifier(portVerifier);
JButton addButton
= new JButton(Resources.getString(isEditMode ?
"service.gui.EDIT" : "service.gui.ADD"));
JButton cancelButton
= new JButton(Resources.getString("service.gui.CANCEL"));
addButton.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
String address = addressField.getText();
String portStr = portField.getText();
StunServerDescriptor stunServer = null;
int port = -1;
if(portStr != null && portStr.trim().length() > 0)
port = Integer.parseInt( portField.getText() );
String username = usernameField.getText();
char[] password = passwordField.getPassword();
String errorMessage = null;
if (address == null || address.length() <= 0)
errorMessage = Resources.getString(
"plugin.jabberaccregwizz.NO_STUN_ADDRESS");
if ((username == null || username.length() <= 0) &&
supportTurnCheckBox.isSelected())
errorMessage = Resources.getString(
"plugin.jabberaccregwizz.NO_STUN_USERNAME");
stunServer = getStunServer(address, port);
if(stunServer != null && !isEditMode)
{
errorMessage = Resources.getString(
"plugin.jabberaccregwizz.STUN_ALREADY_EXIST");
}
if (errorMessage != null)
{
loadErrorMessage(errorMessage);
return;
}
if(!isEditMode)
{
stunServer = new StunServerDescriptor(
address, port, supportTurnCheckBox.isSelected(),
username, new String( password ));
addStunServer(stunServer);
}
else
{
/* edit an existing STUN/TURN server */
stunServer.setAddress(address);
stunServer.setPort(port);
stunServer.setTurnSupported(
supportTurnCheckBox.isSelected());
stunServer.setUsername(username);
stunServer.setPassword(new String(password));
modifyStunServer(stunServer);
}
dispose();
}
});
cancelButton.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
dispose();
}
});
supportTurnCheckBox.addItemListener(new ItemListener()
{
public void itemStateChanged(ItemEvent evt)
{
if(evt.getStateChange() == ItemEvent.SELECTED)
{
/* show TURN user/password textfield */
usernameField.setEnabled(true);
passwordField.setEnabled(true);
}
else
{
/* hide TURN user/password textfield */
usernameField.setEnabled(false);
passwordField.setEnabled(false);
}
}
});
TransparentPanel buttonsPanel
= new TransparentPanel(new FlowLayout(FlowLayout.RIGHT));
buttonsPanel.add(addButton);
buttonsPanel.add(cancelButton);
mainPanel.add(labelsPanel, BorderLayout.WEST);
mainPanel.add(valuesPanel, BorderLayout.CENTER);
mainPanel.add(buttonsPanel, BorderLayout.SOUTH);
mainPanel.setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20));
getContentPane().add(mainPanel, BorderLayout.NORTH);
pack();
}
/**
* Loads the given error message in the current dialog, by re-validating
* the content.
*
* @param errorMessage The error message to load.
*/
private void loadErrorMessage(String errorMessage)
{
if (errorMessagePane == null)
{
errorMessagePane = new JEditorPane();
errorMessagePane.setOpaque(false);
errorMessagePane.setForeground(Color.RED);
mainPanel.add(errorMessagePane, BorderLayout.NORTH);
}
errorMessagePane.setText(errorMessage);
mainPanel.revalidate();
mainPanel.repaint();
this.pack();
//WORKAROUND: there's something wrong happening in this pack and
//components get cluttered, partially hiding the password text field.
//I am under the impression that this has something to do with the
//message pane preferred size being ignored (or being 0) which is
//why I am adding it's height to the dialog. It's quite ugly so
//please fix if you have something better in mind.
this.setSize(getWidth(), getHeight() +
errorMessagePane.getHeight());
}
/**
* Dummy implementation that we are not using.
*
* @param escaped unused
*/
@Override
protected void close(boolean escaped) {}
}
/**
* A custom cell renderer used in the cell containing the
* StunServer instance.
*/
private static class ServerCellRenderer
extends DefaultTableCellRenderer
{
/**
* Serial version UID.
*/
private static final long serialVersionUID = 0L;
// We need a place to store the color the JLabel should be returned
// to after its foreground and background colors have been set
// to the selection background color.
// These vars will be made protected when their names are finalized.
/** the fore ground color to use when not selected */
private Color unselectedForeground;
/** the fore ground color to use when selected */
private Color unselectedBackground;
/**
* Overrides JComponent.setForeground
to assign
* the unselected-foreground color to the specified color.
*
* @param c set the foreground color to this value
*/
public void setForeground(Color c)
{
super.setForeground(c);
unselectedForeground = c;
}
/**
* Overrides JComponent.setBackground
to assign
* the unselected-background color to the specified color.
*
* @param c set the background color to this value
*/
public void setBackground(Color c)
{
super.setBackground(c);
unselectedBackground = c;
}
/**
* Returns a cell renderer for the specified cell.
*
* @param table the {@link JTable} that the cell belongs to.
* @param value the cell value
* @param isSelected indicates whether the cell is selected
* @param hasFocus indicates whether the cell is currently on focus.
* @param row the row index
* @param column the column index
*
* @return the cell renderer
*/
public Component getTableCellRendererComponent( JTable table,
Object value,
boolean isSelected,
boolean hasFocus,
int row,
int column)
{
if (value instanceof StunServerDescriptor)
{
StunServerDescriptor stunServer = (StunServerDescriptor) value;
this.setText( stunServer.getAddress()
+ "/" + stunServer.getPort());
if (isSelected)
{
super.setForeground(table.getSelectionForeground());
super.setBackground(table.getSelectionBackground());
}
else
{
super.setForeground((unselectedForeground != null)
? unselectedForeground
: table.getForeground());
super.setBackground((unselectedBackground != null)
? unselectedBackground
: table.getBackground());
}
}
else if(value instanceof JingleNodeDescriptor)
{
JingleNodeDescriptor jn = (JingleNodeDescriptor) value;
this.setText(jn.getJID());
if (isSelected)
{
super.setForeground(table.getSelectionForeground());
super.setBackground(table.getSelectionBackground());
}
else
{
super.setForeground((unselectedForeground != null)
? unselectedForeground
: table.getForeground());
super.setBackground((unselectedBackground != null)
? unselectedBackground
: table.getBackground());
}
}
else
return super.getTableCellRendererComponent(table, value,
isSelected, hasFocus, row, column);
return this;
}
}
/**
* A custom table model, with a non editable cells and a custom class column
* objects.
*/
private class ServerTableModel
extends DefaultTableModel
{
/**
* Serial version UID.
*/
private static final long serialVersionUID = 0L;
/**
* Returns the class of the objects contained in the column given by
* the index. The class is used to distinguish which renderer should be
* used.
*
* @param columnIndex the column being queried
* @return the class of objects contained in the column
*/
public Class> getColumnClass(int columnIndex)
{
return getValueAt(0, columnIndex).getClass();
}
/**
* Returns false to indicate that none of the columns is
* editable.
*
* @param row the row whose value is to be queried
* @param column the column whose value is to be queried
* @return false
*/
public boolean isCellEditable(int row, int column)
{
return false;
}
}
/**
* Indicates if ice should be used for this account.
* @return true if ICE should be used for this account, otherwise
* returns false
*/
protected boolean isUseIce()
{
return iceBox.isSelected();
}
/**
* Sets the useIce property.
* @param isUseIce true to indicate that ICE should be used for
* this account, false - otherwise.
*/
protected void setUseIce(boolean isUseIce)
{
iceBox.setSelected(isUseIce);
}
/**
* Indicates if the stun server should be automatically discovered.
* @return true if the stun server should be automatically
* discovered, otherwise returns false.
*/
protected boolean isAutoDiscoverStun()
{
return autoDiscoverBox.isSelected();
}
/**
* Sets the autoDiscoverStun property.
* @param isAutoDiscover true to indicate that stun server should
* be auto-discovered, false - otherwise.
*/
protected void setAutoDiscoverStun(boolean isAutoDiscover)
{
autoDiscoverBox.setSelected(isAutoDiscover);
}
/**
* Indicates if the default stun server should be used
* @return true if the default stun server should be used,
* otherwise returns false.
*/
protected boolean isUseDefaultStunServer()
{
return defaultStunBox.isSelected();
}
/**
* Sets the defaultStun property.
* @param isDefaultStun true to indicate that the default stun
* server should be used, false otherwise.
*/
protected void setUseDefaultStunServer(boolean isDefaultStun)
{
defaultStunBox.setSelected(isDefaultStun);
}
/**
* Returns the list of additional stun servers entered by the user.
*
* @return the list of additional stun servers entered by the user
*/
@SuppressWarnings("unchecked")//getDataVector() is simply not parameterized
protected List getAdditionalStunServers()
{
LinkedList serversList
= new LinkedList();
Vector> serverRows
= tableModel.getDataVector();
for(Vector row : serverRows)
serversList.add(row.elementAt(0));
return serversList;
}
/**
* Adds the given stunServer to the list of additional stun
* servers.
* @param stunServer the stun server to add
*/
protected void addStunServer(StunServerDescriptor stunServer)
{
tableModel.addRow(new Object[]{stunServer,
stunServer.isTurnSupported()});
}
/**
* Modify the given stunServer from the list of stun servers.
*
* @param stunServer the stun server to modify
*/
protected void modifyStunServer(StunServerDescriptor stunServer)
{
for (int i = 0; i < tableModel.getRowCount(); i++)
{
StunServerDescriptor server
= (StunServerDescriptor) tableModel.getValueAt(i, 0);
if(stunServer == server)
{
tableModel.setValueAt(stunServer, i, 0);
tableModel.setValueAt(stunServer.isTurnSupported(), i, 1);
return;
}
}
}
/**
* Indicates if a stun server with the given address and
* port already exists in the additional stun servers table.
*
* @param address the STUN server address to check
* @param port the STUN server port to check
*
* @return StunServerDescriptor if a STUN server with the given
* address and port already exists in the table, otherwise
* returns null
*/
protected StunServerDescriptor getStunServer(String address, int port)
{
for (int i = 0; i < tableModel.getRowCount(); i++)
{
StunServerDescriptor stunServer
= (StunServerDescriptor) tableModel.getValueAt(i, 0);
if (stunServer.getAddress().equalsIgnoreCase(address)
&& stunServer.getPort() == port)
return stunServer;
}
return null;
}
/**
* The input verifier that we use to verify port numbers.
*/
private static class PortVerifier extends InputVerifier
{
/**
* Checks whether the JComponent's input is a valid port number. This
* has no side effects. It returns a boolean indicating
* the status of the argument's input.
*
* @param input the JComponent to verify
* @return true when valid, false when invalid or when
* input is not a {@link JTextField} instance.
*/
public boolean verify(JComponent input)
{
if ( !( input instanceof JTextField ) )
return false;
JTextField portField = (JTextField)input;
String portStr = portField.getText();
int port = -1;
//we accept empty strings as that would mean the default port.
if( portStr== null || portStr.trim().length() == 0)
return true;
try
{
port = Integer.parseInt(portStr);
}
catch(Throwable t)
{
//something's wrong and whatever it is - we don't care we
//simply return false.
return false;
}
return NetworkUtils.isValidPortNumber(port);
}
}
/**
* Creates the list of additional JingleNodes that are added by the user.
*
* @return the created component
*/
private Component createAdditionalJingleNodesComponent()
{
jnTable.setPreferredScrollableViewportSize(new Dimension(450, 60));
jnTableModel.addColumn(
Resources.getString("plugin.jabberaccregwizz.JID_ADDRESS"));
jnTableModel.addColumn(
Resources.getString("plugin.jabberaccregwizz.RELAY_SUPPORT"));
jnTable.setDefaultRenderer(JingleNodeDescriptor.class,
new ServerCellRenderer());
//Create the scroll pane and add the table to it.
JScrollPane scrollPane = new JScrollPane(jnTable);
JButton addButton
= new JButton(Resources.getString("service.gui.ADD"));
addButton.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
JNConfigDialog jnDialog = new JNConfigDialog(false);
jnDialog.setVisible(true);
}
});
JButton editButton
= new JButton(Resources.getString("service.gui.EDIT"));
editButton.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
if(jnTable.getSelectedRow() < 0)
return;
JingleNodeDescriptor jn
= (JingleNodeDescriptor) jnTableModel.getValueAt(
jnTable.getSelectedRow(), 0);
if (jn != null)
{
JNConfigDialog dialog = new JNConfigDialog(
jn.getJID(), jn.isRelaySupported());
dialog.setVisible(true);
}
}
});
JButton deleteButton
= new JButton(Resources.getString("service.gui.DELETE"));
deleteButton.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
jnTableModel.removeRow(jnTable.getSelectedRow());
}
});
TransparentPanel buttonsPanel
= new TransparentPanel(new FlowLayout(FlowLayout.RIGHT));
buttonsPanel.add(addButton);
buttonsPanel.add(editButton);
buttonsPanel.add(deleteButton);
TransparentPanel mainPanel = new TransparentPanel(new BorderLayout());
mainPanel.setBorder(BorderFactory.createTitledBorder(
Resources.getString(
"plugin.jabberaccregwizz.ADDITIONAL_JINGLE_NODES")));
mainPanel.add(scrollPane);
mainPanel.add(buttonsPanel, BorderLayout.SOUTH);
return mainPanel;
}
/**
* The JingleNodes configuration window.
*/
private class JNConfigDialog extends SIPCommDialog
{
/**
* Serial version UID.
*/
private static final long serialVersionUID = 0L;
/**
* The main panel
*/
private final JPanel mainPanel
= new TransparentPanel(new BorderLayout());
/**
* The address of the stun server.
*/
private final JTextField addressField = new JTextField();
/**
* The check box where user would indicate whether a STUN server is also
* a TURN server.
*/
private final JCheckBox supportRelayCheckBox = new JCheckBox(
Resources.getString("plugin.jabberaccregwizz.RELAY_SUPPORT"));
/**
* The pane where we show errors.
*/
private JEditorPane errorMessagePane;
/**
* If the dialog is open via "edit" button.
*/
private final boolean isEditMode;
/**
* Creates a new JNConfigDialog with filled in values.
*
* @param address the IP or FQDN of the server
* @param isRelaySupport a boolean indicating whether the node
* supports relay
*/
public JNConfigDialog(String address, boolean isRelaySupport)
{
this(true);
addressField.setText(address);
supportRelayCheckBox.setSelected(isRelaySupport);
}
/**
* Creates an empty dialog.
*
* @param editMode true if the dialog is in "edit" state, false means
* "add" state
*/
public JNConfigDialog(boolean editMode)
{
super(false);
this.isEditMode = editMode;
setTitle(Resources.getString(
"plugin.jabberaccregwizz.ADD_JINGLE_NODE"));
JLabel addressLabel = new JLabel(
Resources.getString("plugin.jabberaccregwizz.JID_ADDRESS"));
TransparentPanel labelsPanel
= new TransparentPanel(new GridLayout(0, 1));
labelsPanel.add(addressLabel);
labelsPanel.add(new JLabel());
TransparentPanel valuesPanel
= new TransparentPanel(new GridLayout(0, 1));
valuesPanel.add(addressField);
valuesPanel.add(supportRelayCheckBox);
JButton addButton
= new JButton(Resources.getString(isEditMode ?
"service.gui.EDIT" : "service.gui.ADD"));
JButton cancelButton
= new JButton(Resources.getString("service.gui.CANCEL"));
addButton.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
String address = addressField.getText();
JingleNodeDescriptor jnServer = null;
String errorMessage = null;
if (address == null || address.length() <= 0)
errorMessage = Resources.getString(
"plugin.jabberaccregwizz.NO_STUN_ADDRESS");
jnServer = getJingleNodes(address);
if(jnServer != null && !isEditMode)
{
errorMessage = Resources.getString(
"plugin.jabberaccregwizz.STUN_ALREADY_EXIST");
}
if (errorMessage != null)
{
loadErrorMessage(errorMessage);
return;
}
if(!isEditMode)
{
jnServer = new JingleNodeDescriptor(
address, supportRelayCheckBox.isSelected());
addJingleNodes(jnServer);
}
else
{
/* edit an existing Jingle Node */
jnServer.setAddress(address);
jnServer.setRelay(supportRelayCheckBox.isSelected());
modifyJingleNodes(jnServer);
}
dispose();
}
});
cancelButton.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
dispose();
}
});
TransparentPanel buttonsPanel
= new TransparentPanel(new FlowLayout(FlowLayout.RIGHT));
buttonsPanel.add(addButton);
buttonsPanel.add(cancelButton);
mainPanel.add(labelsPanel, BorderLayout.WEST);
mainPanel.add(valuesPanel, BorderLayout.CENTER);
mainPanel.add(buttonsPanel, BorderLayout.SOUTH);
mainPanel.setBorder(BorderFactory.createEmptyBorder(20, 20, 20,
20));
getContentPane().add(mainPanel, BorderLayout.NORTH);
pack();
}
/**
* Loads the given error message in the current dialog, by re-validating
* the content.
*
* @param errorMessage The error message to load.
*/
private void loadErrorMessage(String errorMessage)
{
if (errorMessagePane == null)
{
errorMessagePane = new JEditorPane();
errorMessagePane.setOpaque(false);
errorMessagePane.setForeground(Color.RED);
mainPanel.add(errorMessagePane, BorderLayout.NORTH);
}
errorMessagePane.setText(errorMessage);
mainPanel.revalidate();
mainPanel.repaint();
this.pack();
//WORKAROUND: there's something wrong happening in this pack and
//components get cluttered, partially hiding the password text field.
//I am under the impression that this has something to do with the
//message pane preferred size being ignored (or being 0) which is
//why I am adding it's height to the dialog. It's quite ugly so
//please fix if you have something better in mind.
this.setSize(getWidth(), getHeight() +
errorMessagePane.getHeight());
}
/**
* Dummy implementation that we are not using.
*
* @param escaped unused
*/
@Override
protected void close(boolean escaped) {}
}
/**
* Indicates if Jingle Nodes should be used for this account.
*
* @return true if Jingle Nodes should be used for this account,
* otherwise returns false
*/
protected boolean isUseJingleNodes()
{
return jnBox.isSelected();
}
/**
* Sets the useJingleNodes property.
*
* @param isUseJN true to indicate that Jingle Nodes should be
* used for this account, false - otherwise.
*/
protected void setUseJingleNodes(boolean isUseJN)
{
jnBox.setSelected(isUseJN);
}
/**
* Indicates if the Jingle Nodes relays should be automatically discovered.
*
* @return true if the Jingle Nodes relays should be automatically
* discovered, otherwise returns false.
*/
protected boolean isAutoDiscoverJingleNodes()
{
return jnAutoDiscoverBox.isSelected();
}
/**
* Sets the autoDiscoverJingleNodes property.
*
* @param isAutoDiscover true to indicate that Jingle Nodes relays
* should be auto-discovered, false - otherwise.
*/
protected void setAutoDiscoverJingleNodes(boolean isAutoDiscover)
{
jnAutoDiscoverBox.setSelected(isAutoDiscover);
}
/**
* Returns the list of additional Jingle Nodes entered by the user.
*
* @return the list of additional Jingle Nodes entered by the user
*/
@SuppressWarnings("unchecked")//getDataVector() is simply not parameterized
protected List getAdditionalJingleNodes()
{
LinkedList serversList
= new LinkedList();
Vector> serverRows
= jnTableModel.getDataVector();
for(Vector row : serverRows)
serversList.add(row.elementAt(0));
return serversList;
}
/**
* Indicates if a JingleNodes with the given address already exists
* in the additional stun servers table.
*
* @param address the JingleNodes address to check
*
* @return JingleNodesDescriptor if a Jingle Node with the given
* address already exists in the table, otherwise returns
* null
*/
protected JingleNodeDescriptor getJingleNodes(String address)
{
for (int i = 0; i < jnTableModel.getRowCount(); i++)
{
JingleNodeDescriptor jn
= (JingleNodeDescriptor) jnTableModel.getValueAt(i, 0);
if (jn.getJID().equalsIgnoreCase(address))
return jn;
}
return null;
}
/**
* Adds the given jingleNode to the list of additional JingleNodes
*
* @param jingleNode the Jingle Node server to add
*/
protected void addJingleNodes(JingleNodeDescriptor jingleNode)
{
jnTableModel.addRow(new Object[]{jingleNode,
jingleNode.isRelaySupported()});
}
/**
* Modify the given jingleNode from the list of Jingle Nodes.
*
* @param jingleNode the Jingle Node to modify
*/
protected void modifyJingleNodes(JingleNodeDescriptor jingleNode)
{
for (int i = 0; i < jnTableModel.getRowCount(); i++)
{
JingleNodeDescriptor node
= (JingleNodeDescriptor) jnTableModel.getValueAt(i, 0);
if(jingleNode == node)
{
jnTableModel.setValueAt(jingleNode, i, 0);
jnTableModel.setValueAt(jingleNode.isRelaySupported(), i, 1);
return;
}
}
}
}