package org.limewire.ui.swing.options;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.io.IOException;
import javax.swing.BorderFactory;
import javax.swing.ButtonGroup;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import net.miginfocom.swing.MigLayout;
import org.limewire.bittorrent.TorrentManager;
import org.limewire.bittorrent.TorrentManagerSettings;
import org.limewire.bittorrent.TorrentSettingsAnnotation;
import org.limewire.core.api.network.NetworkManager;
import org.limewire.core.settings.BittorrentSettings;
import org.limewire.core.settings.ConnectionSettings;
import org.limewire.core.settings.NetworkSettings;
import org.limewire.ui.swing.components.EmbeddedComponentLabel;
import org.limewire.ui.swing.components.FocusJOptionPane;
import org.limewire.ui.swing.components.MultiLineLabel;
import org.limewire.ui.swing.components.NumericTextField;
import org.limewire.ui.swing.util.BackgroundExecutorService;
import org.limewire.ui.swing.util.I18n;
import com.google.inject.Inject;
import com.google.inject.Provider;
/**
* Listening Ports Option Panel.
*/
public class ListeningPortsOptionPanel extends OptionPanel {
private final NetworkManager networkManager;
private final Provider<TorrentManager> torrentManager;
private final TorrentListeningPortsOptionPanel torrentListeningPorts;
private final GnutellaListeningPortsOptionPanel gnutellaListeningPorts;
private final @TorrentSettingsAnnotation TorrentManagerSettings torrentSettings;
@Inject
public ListeningPortsOptionPanel(NetworkManager networkManager,
Provider<TorrentManager> torrentManager,
@TorrentSettingsAnnotation TorrentManagerSettings torrentSettings) {
setLayout(new MigLayout("insets 15, fillx"));
setOpaque(false);
this.networkManager = networkManager;
this.torrentManager = torrentManager;
this.torrentSettings = torrentSettings;
gnutellaListeningPorts = new GnutellaListeningPortsOptionPanel();
torrentListeningPorts = new TorrentListeningPortsOptionPanel();
JPanel p = new JPanel();
p.setBorder(BorderFactory.createTitledBorder(""));
p.setLayout(new MigLayout("fillx"));
p.setOpaque(false);
p.add(new MultiLineLabel(I18n.tr("You can set the local network port that listens for incoming connections. This port may be changed in case of conflict with another program or if a specific port number is required for direct incoming connections by your firewall. You must also configure your router when choosing \"manual port forward\" or \"do nothing\""),
AdvancedOptionPanel.MULTI_LINE_LABEL_WIDTH), "pad 0, growx, wrap");
p.add(gnutellaListeningPorts, "gaptop 10, growx, wrap");
p.add(torrentListeningPorts, "gaptop 10, growx, wrap");
add(p, "pushx, growx");
}
@Override
void setOptionTabItem(OptionTabItem tab) {
super.setOptionTabItem(tab);
getTorrentListeningPorts().setOptionTabItem(tab);
getGnutellaListeningPorts().setOptionTabItem(tab);
}
private TorrentListeningPortsOptionPanel getTorrentListeningPorts() {
return torrentListeningPorts;
}
private GnutellaListeningPortsOptionPanel getGnutellaListeningPorts() {
return gnutellaListeningPorts;
}
@Override
ApplyOptionResult applyOptions() {
ApplyOptionResult result = null;
result = gnutellaListeningPorts.applyOptions();
if (result.isSuccessful())
result.applyResult(torrentListeningPorts.applyOptions());
return result;
}
@Override
boolean hasChanged() {
return gnutellaListeningPorts.hasChanged() || torrentListeningPorts.hasChanged();
}
@Override
public void initOptions() {
gnutellaListeningPorts.initOptions();
torrentListeningPorts.initOptions();
}
private class GnutellaListeningPortsOptionPanel extends OptionPanel {
private final JRadioButton gnutellaPlugAndPlayRadioButton;
private final JRadioButton gnutellaPortForwardRadioButton;
private final NumericTextField gnutellaForcePortTextField;
private final JLabel gnutellaManualConfigurationWarning;
private final JRadioButton gnutellaDoNothingRadioButton;
private final NumericTextField gnutellaPortField;
private int gnutellaPort;
public GnutellaListeningPortsOptionPanel() {
setLayout(new MigLayout("insets 0, nogrid"));
setOpaque(false);
add(new JLabel(I18n.tr("Gnutella port:")), "split");
gnutellaPortField = new NumericTextField(5, 1, 0xFFFF);
add(gnutellaPortField, "wrap");
gnutellaPlugAndPlayRadioButton = new JRadioButton(I18n
.tr("Use Universal Plug n' Play (Recommended)"));
gnutellaPortForwardRadioButton = new JRadioButton(I18n.tr("Manual Port Forward:"));
gnutellaDoNothingRadioButton = new JRadioButton(I18n.tr("Do Nothing"));
gnutellaPlugAndPlayRadioButton.setOpaque(false);
gnutellaPortForwardRadioButton.setOpaque(false);
gnutellaDoNothingRadioButton.setOpaque(false);
ButtonGroup gnutellaButtonGroup = new ButtonGroup();
gnutellaButtonGroup.add(gnutellaPlugAndPlayRadioButton);
gnutellaButtonGroup.add(gnutellaPortForwardRadioButton);
gnutellaButtonGroup.add(gnutellaDoNothingRadioButton);
add(gnutellaPlugAndPlayRadioButton, "split, wrap");
add(gnutellaPortForwardRadioButton, "split");
gnutellaForcePortTextField = new NumericTextField(5, 1, 0xFFFF);
gnutellaManualConfigurationWarning = new JLabel(I18n
.tr("* You must also configure your router"));
gnutellaManualConfigurationWarning.setVisible(false);
add(gnutellaForcePortTextField, "wrap");
add(gnutellaManualConfigurationWarning, "gapleft 85, wrap, hidemode 2");
add(gnutellaDoNothingRadioButton, "split, wrap");
gnutellaPortForwardRadioButton.addItemListener(new ItemListener() {
@Override
public void itemStateChanged(ItemEvent e) {
updateTextField();
}
});
}
@Override
ApplyOptionResult applyOptions() {
int newGnutellaPort = gnutellaPortField.getValue(gnutellaPort);
if (newGnutellaPort != gnutellaPort) {
try {
NetworkSettings.PORT.setValue(newGnutellaPort);
networkManager.setListeningPort(newGnutellaPort);
gnutellaPort = newGnutellaPort;
networkManager.portChanged();
} catch (IOException ioe) {
FocusJOptionPane.showMessageDialog(ListeningPortsOptionPanel.this, I18n.tr(
"The port chosen {0}, is already in use.", newGnutellaPort), I18n
.tr("Network Port Error"), JOptionPane.ERROR_MESSAGE);
NetworkSettings.PORT.setValue(gnutellaPort);
gnutellaPortField.setValue(gnutellaPort);
}
}
boolean restart = false;
boolean oldUPNP = ConnectionSettings.DISABLE_UPNP.getValue();
final int oldForcedPort = ConnectionSettings.FORCED_PORT.getValue();
final boolean oldForce = ConnectionSettings.FORCE_IP_ADDRESS.getValue();
if (gnutellaPlugAndPlayRadioButton.isSelected()) {
if (!ConnectionSettings.UPNP_IN_USE.getValue()) {
ConnectionSettings.FORCE_IP_ADDRESS.setValue(false);
}
ConnectionSettings.DISABLE_UPNP.setValue(false);
if (oldUPNP || oldForce) {
restart = true;
}
} else if (gnutellaDoNothingRadioButton.isSelected()) {
ConnectionSettings.FORCE_IP_ADDRESS.setValue(false);
ConnectionSettings.DISABLE_UPNP.setValue(true);
} else { // PORT.isSelected()
int gnutellaForcedPort = gnutellaForcePortTextField.getValue(oldForcedPort);
ConnectionSettings.DISABLE_UPNP.setValue(false);
ConnectionSettings.FORCE_IP_ADDRESS.setValue(true);
ConnectionSettings.UPNP_IN_USE.setValue(false);
ConnectionSettings.FORCED_PORT.setValue(gnutellaForcedPort);
}
// Notify that the address changed if:
// 1) The 'forced address' status changed.
// or 2) We're forcing and the ports are different.
final boolean newForce = ConnectionSettings.FORCE_IP_ADDRESS.getValue();
final int newForcedPort = ConnectionSettings.FORCED_PORT.getValue();
BackgroundExecutorService.execute(new Runnable() {
@Override
public void run() {
if (oldForce != newForce) {
networkManager.addressChanged();
}
if (newForce && (oldForcedPort != newForcedPort)) {
networkManager.portChanged();
}
}
});
return new ApplyOptionResult(restart, true);
}
@Override
boolean hasChanged() {
if (ConnectionSettings.FORCE_IP_ADDRESS.getValue()
&& !ConnectionSettings.UPNP_IN_USE.getValue()) {
if (!gnutellaPortForwardRadioButton.isSelected())
return true;
} else if (ConnectionSettings.DISABLE_UPNP.getValue()) {
if (!gnutellaDoNothingRadioButton.isSelected())
return true;
} else {
if (!gnutellaPlugAndPlayRadioButton.isSelected())
return true;
}
int forcedPortSetting = ConnectionSettings.FORCED_PORT.getValue();
int portSetting = NetworkSettings.PORT.getValue();
return portSetting != gnutellaPortField.getValue(portSetting)
|| (gnutellaPortForwardRadioButton.isSelected() && gnutellaForcePortTextField
.getValue(forcedPortSetting) != forcedPortSetting);
}
@Override
public void initOptions() {
gnutellaPort = NetworkSettings.PORT.getValue();
gnutellaPortField.setValue(gnutellaPort);
if (ConnectionSettings.FORCE_IP_ADDRESS.getValue()
&& !ConnectionSettings.UPNP_IN_USE.getValue()) {
gnutellaPortForwardRadioButton.setSelected(true);
} else if (ConnectionSettings.DISABLE_UPNP.getValue()) {
gnutellaDoNothingRadioButton.setSelected(true);
} else {
gnutellaPlugAndPlayRadioButton.setSelected(true);
}
gnutellaForcePortTextField.setValue(ConnectionSettings.FORCED_PORT.getValue());
updateTextField();
}
private void updateTextField() {
gnutellaForcePortTextField.setEnabled(gnutellaPortForwardRadioButton.isSelected());
gnutellaForcePortTextField.setEditable(gnutellaPortForwardRadioButton.isSelected());
gnutellaManualConfigurationWarning.setVisible(gnutellaPortForwardRadioButton
.isSelected());
}
}
private class TorrentListeningPortsOptionPanel extends OptionPanel {
private final JRadioButton torrentPlugAndPlayRadioButton;
private final JRadioButton torrentDoNothingRadioButton;
private final JComponent torrentPortController;
private final NumericTextField torrentStartPortField;
private final NumericTextField torrentEndPortField;
public TorrentListeningPortsOptionPanel() {
setLayout(new MigLayout("insets 0, nogrid"));
setOpaque(false);
torrentStartPortField = new NumericTextField(5, 1, 0xFFFF);
torrentEndPortField = new NumericTextField(5, 1, 0xFFFF);
torrentPortController = new EmbeddedComponentLabel(I18n
.tr("BitTorrent ports: {c} to {c}"), torrentStartPortField, torrentEndPortField);
add(torrentPortController, "wrap");
torrentPlugAndPlayRadioButton = new JRadioButton(I18n
.tr("Use Universal Plug n' Play (Recommended)"));
torrentDoNothingRadioButton = new JRadioButton(I18n.tr("Do Nothing"));
torrentPlugAndPlayRadioButton.setOpaque(false);
torrentDoNothingRadioButton.setOpaque(false);
ButtonGroup torrentButtonGroup = new ButtonGroup();
torrentButtonGroup.add(torrentPlugAndPlayRadioButton);
torrentButtonGroup.add(torrentDoNothingRadioButton);
add(torrentPlugAndPlayRadioButton, "wrap");
add(torrentDoNothingRadioButton, "wrap");
}
@Override
ApplyOptionResult applyOptions() {
int torrentStartPort = torrentStartPortField
.getValue(BittorrentSettings.LIBTORRENT_LISTEN_START_PORT.getValue());
int torrentEndPort = torrentEndPortField
.getValue(BittorrentSettings.LIBTORRENT_LISTEN_END_PORT.getValue());
if (torrentStartPort > torrentEndPort) {
// swap start and end port if start port is larger.
int temp = torrentStartPort;
torrentStartPort = torrentEndPort;
torrentEndPort = temp;
}
BittorrentSettings.LIBTORRENT_LISTEN_START_PORT.setValue(torrentStartPort);
BittorrentSettings.LIBTORRENT_LISTEN_END_PORT.setValue(torrentEndPort);
BittorrentSettings.TORRENT_USE_UPNP
.setValue(torrentPlugAndPlayRadioButton.isSelected());
if (torrentManager.get().isInitialized() && torrentManager.get().isValid()) {
BackgroundExecutorService.execute(new Runnable() {
@Override
public void run() {
torrentManager.get().setTorrentManagerSettings(torrentSettings);
if(BittorrentSettings.TORRENT_USE_UPNP.getValue()) {
torrentManager.get().startUPnP();
} else {
torrentManager.get().stopUPnP();
}
}
});
}
return new ApplyOptionResult(false, true);
}
@Override
boolean hasChanged() {
return torrentStartPortField.getValue(BittorrentSettings.LIBTORRENT_LISTEN_START_PORT
.getValue()) != BittorrentSettings.LIBTORRENT_LISTEN_START_PORT.getValue()
|| torrentEndPortField.getValue(BittorrentSettings.LIBTORRENT_LISTEN_END_PORT
.getValue()) != BittorrentSettings.LIBTORRENT_LISTEN_END_PORT
.getValue()
|| torrentPlugAndPlayRadioButton.isSelected() != BittorrentSettings.TORRENT_USE_UPNP
.getValue();
}
@Override
public void initOptions() {
torrentStartPortField.setValue(BittorrentSettings.LIBTORRENT_LISTEN_START_PORT
.getValue());
torrentEndPortField.setValue(BittorrentSettings.LIBTORRENT_LISTEN_END_PORT.getValue());
torrentPlugAndPlayRadioButton.setSelected(BittorrentSettings.TORRENT_USE_UPNP
.getValue());
torrentDoNothingRadioButton
.setSelected(!BittorrentSettings.TORRENT_USE_UPNP.getValue());
}
}
}