package org.jabref.gui.externalfiletype;
import java.awt.BorderLayout;
import java.awt.Component;
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.Collection;
import java.util.Collections;
import java.util.List;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.ActionMap;
import javax.swing.BorderFactory;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.InputMap;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.TableCellRenderer;
import org.jabref.Globals;
import org.jabref.gui.IconTheme;
import org.jabref.gui.JabRefDialog;
import org.jabref.gui.JabRefFrame;
import org.jabref.gui.actions.MnemonicAwareAction;
import org.jabref.gui.keyboard.KeyBinding;
import org.jabref.logic.l10n.Localization;
import com.jgoodies.forms.builder.ButtonBarBuilder;
import com.jgoodies.forms.builder.ButtonStackBuilder;
/**
* Editor for external file types.
*/
public class ExternalFileTypeEditor extends JabRefDialog {
private JFrame frame;
private JDialog dialog;
private List<ExternalFileType> fileTypes;
private JTable table;
private ExternalFileTypeEntryEditor entryEditor;
private FileTypeTableModel tableModel;
private final JButton ok = new JButton(Localization.lang("OK"));
private final JButton cancel = new JButton(Localization.lang("Cancel"));
private final JButton add = new JButton(IconTheme.JabRefIcon.ADD_NOBOX.getIcon());
private final JButton remove = new JButton(IconTheme.JabRefIcon.REMOVE_NOBOX.getIcon());
private final JButton edit = new JButton(IconTheme.JabRefIcon.EDIT.getIcon());
private final JButton toDefaults = new JButton(Localization.lang("Default"));
private final EditListener editListener = new EditListener();
private ExternalFileTypeEditor(JFrame frame) {
super(frame, Localization.lang("Manage external file types"), true, ExternalFileTypeEditor.class);
this.frame = frame;
init();
}
private ExternalFileTypeEditor(JDialog dialog) {
super(dialog, Localization.lang("Manage external file types"), true, ExternalFileTypeEditor.class);
this.dialog = dialog;
init();
}
/**
* Update the editor to show the current settings in Preferences.
*/
private void setValues() {
fileTypes.clear();
Collection<ExternalFileType> types = ExternalFileTypes.getInstance().getExternalFileTypeSelection();
for (ExternalFileType type : types) {
fileTypes.add(type.copy());
}
Collections.sort(fileTypes);
}
/**
* Store the list of external entry types to Preferences.
*/
private void storeSettings() {
ExternalFileTypes.getInstance().setExternalFileTypes(fileTypes);
}
private void init() {
ok.addActionListener(e -> {
storeSettings();
dispose();
});
Action cancelAction = new AbstractAction() {
@Override
public void actionPerformed(ActionEvent e) {
dispose();
}
};
cancel.addActionListener(cancelAction);
// The toDefaults resets the entire list to its default values.
toDefaults.addActionListener(e -> {
/*int reply = JOptionPane.showConfirmDialog(ExternalFileTypeEditor.this,
Globals.lang("All custom file types will be lost. Proceed?"),
Globals.lang("Reset file type definitions"), JOptionPane.YES_NO_OPTION,
JOptionPane.QUESTION_MESSAGE);*/
//if (reply == JOptionPane.YES_OPTION) {
List<ExternalFileType> list = ExternalFileTypes.getDefaultExternalFileTypes();
fileTypes.clear();
fileTypes.addAll(list);
Collections.sort(fileTypes);
//Globals.prefs.resetExternalFileTypesToDefault();
//setValues();
tableModel.fireTableDataChanged();
//}
});
add.addActionListener(e -> {
// Generate a new file type:
ExternalFileType type = new ExternalFileType("", "", "", "", "new",
IconTheme.JabRefIcon.FILE.getSmallIcon());
// Show the file type editor:
getEditor(type).setVisible(true);
if (entryEditor.okPressed()) {
// Ok was pressed. Add the new file type and update the table:
fileTypes.add(type);
tableModel.fireTableDataChanged();
}
});
remove.addActionListener(e -> {
int[] rows = table.getSelectedRows();
if (rows.length == 0) {
return;
}
for (int i = rows.length - 1; i >= 0; i--) {
fileTypes.remove(rows[i]);
}
tableModel.fireTableDataChanged();
if (!fileTypes.isEmpty()) {
int row = Math.min(rows[0], fileTypes.size() - 1);
table.setRowSelectionInterval(row, row);
}
});
edit.addActionListener(editListener);
fileTypes = new ArrayList<>();
setValues();
tableModel = new FileTypeTableModel();
table = new JTable(tableModel);
table.setDefaultRenderer(ImageIcon.class, new IconRenderer());
table.addMouseListener(new TableClickListener());
table.getColumnModel().getColumn(0).setMaxWidth(24);
table.getColumnModel().getColumn(0).setMinWidth(24);
table.getColumnModel().getColumn(1).setMinWidth(170);
table.getColumnModel().getColumn(2).setMinWidth(60);
table.getColumnModel().getColumn(3).setMinWidth(100);
table.getColumnModel().getColumn(0).setResizable(false);
JScrollPane sp = new JScrollPane(table);
JPanel upper = new JPanel();
upper.setLayout(new BorderLayout());
upper.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
upper.add(sp, BorderLayout.CENTER);
getContentPane().add(upper, BorderLayout.CENTER);
ButtonStackBuilder bs = new ButtonStackBuilder();
bs.addButton(add);
bs.addButton(remove);
bs.addButton(edit);
bs.addRelatedGap();
bs.addButton(toDefaults);
upper.add(bs.getPanel(), BorderLayout.EAST);
ButtonBarBuilder bb = new ButtonBarBuilder();
bb.addGlue();
bb.addButton(ok);
bb.addButton(cancel);
bb.addGlue();
bb.getPanel().setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
getContentPane().add(bb.getPanel(), BorderLayout.SOUTH);
pack();
// Key bindings:
ActionMap am = upper.getActionMap();
InputMap im = upper.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
im.put(Globals.getKeyPrefs().getKey(KeyBinding.CLOSE_DIALOG), "close");
am.put("close", cancelAction);
am = bb.getPanel().getActionMap();
im = bb.getPanel().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
im.put(Globals.getKeyPrefs().getKey(KeyBinding.CLOSE_DIALOG), "close");
am.put("close", cancelAction);
if (frame == null) {
setLocationRelativeTo(dialog);
} else {
setLocationRelativeTo(frame);
}
}
private ExternalFileTypeEntryEditor getEditor(ExternalFileType type) {
if (entryEditor == null) {
entryEditor = new ExternalFileTypeEntryEditor(ExternalFileTypeEditor.this, type);
} else {
entryEditor.setEntry(type);
}
return entryEditor;
}
/**
* Get an AbstractAction for opening the external file types editor.
* @param frame The JFrame used as parent window for the dialog.
* @return An Action for opening the editor.
*/
public static AbstractAction getAction(JabRefFrame frame) {
return new EditExternalFileTypesAction(frame);
}
/**
* Get an AbstractAction for opening the external file types editor.
* @param dialog The JDialog used as parent window for the dialog.
* @return An Action for opening the editor.
*/
public static AbstractAction getAction(JDialog dialog) {
return new EditExternalFileTypesAction(dialog);
}
class EditListener implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
int[] rows = table.getSelectedRows();
if (rows.length != 1) {
return;
}
getEditor(fileTypes.get(rows[0])).setVisible(true);
if (entryEditor.okPressed()) {
tableModel.fireTableDataChanged();
}
}
}
static class IconRenderer implements TableCellRenderer {
private final JLabel lab = new JLabel();
@Override
public Component getTableCellRendererComponent(JTable tab, Object value, boolean isSelected, boolean hasFocus,
int row, int column) {
lab.setText(null);
lab.setIcon((Icon) value);
return lab;
}
}
private class FileTypeTableModel extends AbstractTableModel {
@Override
public int getColumnCount() {
return 5;
}
@Override
public int getRowCount() {
return fileTypes.size();
}
@Override
public String getColumnName(int column) {
switch (column) {
case 0:
return " ";
case 1:
return Localization.lang("Name");
case 2:
return Localization.lang("Extension");
case 3:
return Localization.lang("MIME type");
default: // Five columns
return Localization.lang("Application");
}
}
@Override
public Class<?> getColumnClass(int columnIndex) {
if (columnIndex == 0) {
return ImageIcon.class;
} else {
return String.class;
}
}
@Override
public Object getValueAt(int rowIndex, int columnIndex) {
ExternalFileType type = fileTypes.get(rowIndex);
switch (columnIndex) {
case 0:
return type.getIcon();
case 1:
return type.getName();
case 2:
return type.getExtension();
case 3:
return type.getMimeType();
default:
return type.getOpenWithApplication();
}
}
}
class TableClickListener extends MouseAdapter {
private void handleClick(MouseEvent e) {
if (e.getClickCount() == 2) {
editListener.actionPerformed(null);
}
}
@Override
public void mouseClicked(MouseEvent e) {
handleClick(e);
}
@Override
public void mousePressed(MouseEvent e) {
handleClick(e);
}
@Override
public void mouseReleased(MouseEvent e) {
handleClick(e);
}
}
public static class EditExternalFileTypesAction extends MnemonicAwareAction {
private JabRefFrame frame;
private JDialog dialog;
private ExternalFileTypeEditor editor;
public EditExternalFileTypesAction(JabRefFrame frame) {
super();
putValue(Action.NAME, Localization.menuTitle("Manage external file types"));
this.frame = frame;
}
public EditExternalFileTypesAction(JDialog dialog) {
super();
putValue(Action.NAME, Localization.menuTitle("Manage external file types"));
this.dialog = dialog;
}
@Override
public void actionPerformed(ActionEvent e) {
if (editor == null) {
if (frame == null) {
editor = new ExternalFileTypeEditor(dialog);
} else {
editor = new ExternalFileTypeEditor(frame);
}
}
editor.setValues();
editor.setVisible(true);
if ((frame != null) && (frame.getCurrentBasePanel() != null)) {
frame.getCurrentBasePanel().getMainTable().repaint();
}
}
}
}