package org.limewire.ui.swing.options;
import java.awt.Component;
import java.awt.Cursor;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.EventObject;
import java.util.List;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JLabel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.event.CellEditorListener;
import javax.swing.event.ChangeEvent;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.TableCellEditor;
import javax.swing.table.TableCellRenderer;
import net.miginfocom.swing.MigLayout;
import org.jdesktop.swingx.JXTable;
import org.limewire.core.api.spam.SpamManager;
import org.limewire.core.settings.FilterSettings;
import org.limewire.io.IP;
import org.limewire.ui.swing.components.MultiLineLabel;
import org.limewire.ui.swing.components.TextFieldClipboardControl;
import org.limewire.ui.swing.util.BackgroundExecutorService;
import org.limewire.ui.swing.util.FontUtils;
import org.limewire.ui.swing.util.I18n;
import com.google.inject.Inject;
/**
* Filtering Option View.
*/
public class FilteringOptionPanel extends OptionPanel {
private SpamManager spamManager;
private BlockHostsPanel blockHostPanel;
private AllowHostsPanel allowHostsPanel;
@Inject
public FilteringOptionPanel(SpamManager spamManager) {
super();
this.spamManager = spamManager;
setLayout(new MigLayout("insets 15, fillx, wrap"));
setOpaque(false);
add(getBlockHostsPanel(), "pushx, growx");
add(getAllowHostsPanel(), "pushx, growx");
}
private OptionPanel getBlockHostsPanel() {
if(blockHostPanel == null) {
blockHostPanel = new BlockHostsPanel();
}
return blockHostPanel;
}
private OptionPanel getAllowHostsPanel() {
if(allowHostsPanel == null) {
allowHostsPanel = new AllowHostsPanel();
}
return allowHostsPanel;
}
@Override
void setOptionTabItem(OptionTabItem tab) {
super.setOptionTabItem(tab);
getAllowHostsPanel().setOptionTabItem(tab);
getBlockHostsPanel().setOptionTabItem(tab);
}
@Override
ApplyOptionResult applyOptions() {
ApplyOptionResult result = null;
result = getBlockHostsPanel().applyOptions();
if (result.isSuccessful())
result.applyResult(getAllowHostsPanel().applyOptions());
return result;
}
@Override
boolean hasChanged() {
return getBlockHostsPanel().hasChanged() || getAllowHostsPanel().hasChanged();
}
@Override
public void initOptions() {
getBlockHostsPanel().initOptions();
getAllowHostsPanel().initOptions();
}
private class BlockHostsPanel extends OptionPanel {
private JTextField addressTextField;
private JButton addButton;
private FilteringTable filterTable;
private JCheckBox backListCheckBox;
private String description = I18n.tr("Use LimeWire's blacklist to protect you from harmful people");
public BlockHostsPanel() {
super(I18n.tr("Block Hosts"));
setLayout(new MigLayout("gapy 10", "[sg 1][sg 1][]", ""));
addressTextField = new JTextField(26);
TextFieldClipboardControl.install(addressTextField);
addButton = new JButton(I18n.tr("Add Address"));
filterTable = new FilteringTable();
backListCheckBox = new JCheckBox();
backListCheckBox.setOpaque(false);
addButton.addActionListener(new AddAction(addressTextField, filterTable));
add(new JLabel("<html>"+I18n.tr("Block contact with specific people by adding their IP address")+"</html>"), "span, growx, wrap");
add(addressTextField, "gapright 10");
add(addButton, "wrap");
add(new JScrollPane(filterTable), "growx, span 2, wrap");
add(backListCheckBox, "span, split");
add(new MultiLineLabel(description, AdvancedOptionPanel.MULTI_LINE_LABEL_WIDTH), "span, growx");
}
@Override
ApplyOptionResult applyOptions() {
List<String> list = filterTable.getFilterModel().getModel();
FilterSettings.USE_NETWORK_FILTER.setValue(backListCheckBox.isSelected());
FilterSettings.BLACK_LISTED_IP_ADDRESSES.set(list.toArray(new String[list.size()]));
BackgroundExecutorService.execute(new Runnable() {
@Override
public void run() {
spamManager.reloadIPFilter();
}
});
return new ApplyOptionResult(false, true);
}
@Override
boolean hasChanged() {
List model = Arrays.asList(FilterSettings.BLACK_LISTED_IP_ADDRESSES.get());
return backListCheckBox.isSelected() != FilterSettings.USE_NETWORK_FILTER.getValue()
|| !model.equals(filterTable.getFilterModel().getModel());
}
@Override
public void initOptions() {
String[] bannedIps = FilterSettings.BLACK_LISTED_IP_ADDRESSES.get();
FilterModel model = new FilterModel(new ArrayList<String>(Arrays.asList(bannedIps)));
filterTable.setModel(model);
backListCheckBox.setSelected(FilterSettings.USE_NETWORK_FILTER.getValue());
}
}
private class AllowHostsPanel extends OptionPanel {
private JTextField addressTextField;
private JButton addButton;
private FilteringTable filterTable;
private final String description = I18n.tr("Override the block list and allow specific people by adding their IP address");
public AllowHostsPanel() {
super(I18n.tr("Allow Hosts"));
setLayout(new MigLayout("gapy 10", "[sg 1][sg 1][]", ""));
addressTextField = new JTextField(26);
TextFieldClipboardControl.install(addressTextField);
addButton = new JButton(I18n.tr("Add Address"));
filterTable = new FilteringTable();
addButton.addActionListener(new AddAction(addressTextField, filterTable));
add(new MultiLineLabel(description, AdvancedOptionPanel.MULTI_LINE_LABEL_WIDTH), "span, growx, wrap");
add(addressTextField, "gapright 10");
add(addButton, "wrap");
add(new JScrollPane(filterTable), "growx, span 2");
}
@Override
ApplyOptionResult applyOptions() {
List<String> list = filterTable.getFilterModel().getModel();
FilterSettings.WHITE_LISTED_IP_ADDRESSES.set(list.toArray(new String[list.size()]));
BackgroundExecutorService.execute(new Runnable() {
@Override
public void run() {
spamManager.reloadIPFilter();
}
});
return new ApplyOptionResult(false, true);
}
@Override
boolean hasChanged() {
List model = Arrays.asList(FilterSettings.WHITE_LISTED_IP_ADDRESSES.get());
return !model.equals(filterTable.getFilterModel().getModel());
}
@Override
public void initOptions() {
String[] allowedIps = FilterSettings.WHITE_LISTED_IP_ADDRESSES.get();
FilterModel model = new FilterModel(new ArrayList<String>(Arrays.asList(allowedIps)));
filterTable.setModel(model);
}
}
private class FilteringTable extends JXTable {
private FilterModel model;
public FilteringTable() {
setTableHeader(null);
setShowGrid(false);
setSelectionMode(0);
setSelectionBackground(getBackground());
setSelectionForeground(getForeground());
addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {//adding this to editor messes up popups
int col = columnAtPoint(e.getPoint());
int row = rowAtPoint(e.getPoint());
if (row >= 0 && col >= 0) {
TableCellEditor editor = getCellEditor();
if (editor != null) {
// force update editor colors
prepareEditor(editor, row, col);
// editor.repaint() takes about a second to show sometimes
repaint();
}
}
}
});
}
public void setModel(FilterModel model) {
super.setModel(model);
this.model = model;
getColumn(1).setCellRenderer(new RemoveButtonRenderer(this));
getColumn(1).setCellEditor(new RemoveButtonRenderer(this));
}
public FilterModel getFilterModel() {
return model;
}
public void addIp(String ip) {
if(model != null) {
model.addIP(ip);
}
}
@Override
public boolean isCellEditable(int row, int col) {
if (row >= getRowCount() || col >= getColumnCount() || row < 0 || col < 0) {
return false;
}
return getColumnModel().getColumn(col).getCellEditor() != null;
}
}
private class RemoveButtonRenderer extends JButton implements TableCellRenderer, TableCellEditor {
private final List<CellEditorListener> listeners = new ArrayList<CellEditorListener>();
public RemoveButtonRenderer(final FilteringTable table) {
// lower case since hyperlink
super(I18n.tr("remove"));
setBorder(BorderFactory.createEmptyBorder());
setContentAreaFilled(false);
FontUtils.underline(this);
setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
addActionListener(new ActionListener(){
@Override
public void actionPerformed(ActionEvent e) {
table.getFilterModel().removeIP(table.getSelectedRow());
cancelCellEditing();
table.repaint();
}
});
}
@Override
public Component getTableCellRendererComponent(JTable table, Object value,
boolean isSelected, boolean hasFocus, int row, int column) {
return this;
}
@Override
public Component getTableCellEditorComponent(JTable table, Object value,
boolean isSelected, int row, int column) {
return this;
}
@Override
public void cancelCellEditing() {
synchronized (listeners) {
for (int i=0, N=listeners.size(); i<N; i++) {
listeners.get(i).editingCanceled(new ChangeEvent(this));
}
}
}
@Override
public Object getCellEditorValue() {
return null;
}
@Override
public boolean isCellEditable(EventObject anEvent) {
return true;
}
@Override
public void removeCellEditorListener(CellEditorListener lis) {
synchronized (listeners) {
if (listeners.contains(lis)) listeners.remove(lis);
}
}
@Override
public void addCellEditorListener(CellEditorListener lis) {
synchronized (listeners) {
if (!listeners.contains(lis)) listeners.add(lis);
}
}
@Override
public boolean shouldSelectCell(EventObject anEvent) {
return true;
}
@Override
public boolean stopCellEditing() {
cancelCellEditing();
return true;
}
}
private class FilterModel extends AbstractTableModel {
private List<String> filters;
public FilterModel(List<String> filters) {
this.filters = filters;
}
@Override
public int getColumnCount() {
return 2;
}
@Override
public int getRowCount() {
return filters.size();
}
@Override
public Object getValueAt(int rowIndex, int columnIndex) {
return filters.get(rowIndex);
}
public List<String> getModel() {
return filters;
}
public void addIP(String ip) {
if(!filters.contains(ip))
filters.add(ip);
repaint();
}
public void removeIP(int index) {
if(index < 0 || index >= filters.size())
return;
filters.remove(index);
}
}
public static class AddAction implements ActionListener {
private JTextField textField;
private FilteringTable table;
public AddAction(JTextField textField, FilteringTable table) {
this.table = table;
this.textField = textField;
}
@Override
public void actionPerformed(ActionEvent e) {
if(textField.getText() != null && textField.getText().length() > 0) {
try {
new IP(textField.getText());
table.addIp(textField.getText());
table.invalidate();
} catch(IllegalArgumentException iae) {
}
textField.setText("");
}
}
}
}