summaryrefslogtreecommitdiff
path: root/src/de/lmu/ifi/dbs/elki/gui/util/ParameterTable.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/de/lmu/ifi/dbs/elki/gui/util/ParameterTable.java')
-rw-r--r--src/de/lmu/ifi/dbs/elki/gui/util/ParameterTable.java299
1 files changed, 199 insertions, 100 deletions
diff --git a/src/de/lmu/ifi/dbs/elki/gui/util/ParameterTable.java b/src/de/lmu/ifi/dbs/elki/gui/util/ParameterTable.java
index a28d3f43..105242c0 100644
--- a/src/de/lmu/ifi/dbs/elki/gui/util/ParameterTable.java
+++ b/src/de/lmu/ifi/dbs/elki/gui/util/ParameterTable.java
@@ -4,7 +4,7 @@ package de.lmu.ifi.dbs.elki.gui.util;
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
- Copyright (C) 2012
+ Copyright (C) 2013
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
@@ -27,21 +27,29 @@ import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
+import java.awt.FileDialog;
+import java.awt.Frame;
import java.awt.Insets;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
+import java.awt.event.KeyEvent;
import java.io.File;
import java.util.BitSet;
import javax.swing.AbstractCellEditor;
+import javax.swing.Action;
+import javax.swing.ActionMap;
import javax.swing.DefaultCellEditor;
+import javax.swing.InputMap;
import javax.swing.JButton;
import javax.swing.JComboBox;
-import javax.swing.JFileChooser;
+import javax.swing.JComponent;
import javax.swing.JPanel;
import javax.swing.JTable;
import javax.swing.JTextField;
+import javax.swing.KeyStroke;
+import javax.swing.SwingUtilities;
import javax.swing.plaf.basic.BasicComboPopup;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.TableCellEditor;
@@ -94,6 +102,11 @@ public class ParameterTable extends JTable {
static final Color COLOR_DEFAULT_VALUE = new Color(0xDFDFDF);
/**
+ * Containing frame.
+ */
+ protected Frame frame;
+
+ /**
* The parameters we edit.
*/
protected DynamicParameters parameters;
@@ -101,11 +114,13 @@ public class ParameterTable extends JTable {
/**
* Constructor
*
+ * @param frame Containing frame
* @param pm Parameter Model
* @param parameters Parameter storage
*/
- public ParameterTable(ParametersModel pm, DynamicParameters parameters) {
+ public ParameterTable(Frame frame, ParametersModel pm, DynamicParameters parameters) {
super(pm);
+ this.frame = frame;
this.parameters = parameters;
this.setPreferredScrollableViewportSize(new Dimension(800, 400));
this.setFillsViewportHeight(true);
@@ -141,16 +156,16 @@ public class ParameterTable extends JTable {
@Override
public void setValue(Object value) {
- if(value instanceof String) {
+ if (value instanceof String) {
setText((String) value);
setToolTipText(null);
return;
}
- if(value instanceof DynamicParameters.Node) {
+ if (value instanceof DynamicParameters.Node) {
Parameter<?> o = ((DynamicParameters.Node) value).param;
// Simulate a tree using indentation - there is no JTreeTable AFAICT
StringBuilder buf = new StringBuilder();
- for(int i = 1; i < ((DynamicParameters.Node) value).depth; i++) {
+ for (int i = 1; i < ((DynamicParameters.Node) value).depth; i++) {
buf.append(' ');
}
buf.append(o.getOptionID().getName());
@@ -165,27 +180,24 @@ public class ParameterTable extends JTable {
@Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
Component c = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
- if(row < parameters.size()) {
- BitSet flags = parameters.getNode(row).flags;
- // TODO: don't hardcode black - maybe mix the other colors, too?
- c.setForeground(Color.BLACK);
- if((flags.get(DynamicParameters.BIT_INVALID))) {
- c.setBackground(COLOR_SYNTAX_ERROR);
- }
- else if((flags.get(DynamicParameters.BIT_SYNTAX_ERROR))) {
- c.setBackground(COLOR_SYNTAX_ERROR);
- }
- else if((flags.get(DynamicParameters.BIT_INCOMPLETE))) {
- c.setBackground(COLOR_INCOMPLETE);
- }
- else if((flags.get(DynamicParameters.BIT_DEFAULT_VALUE))) {
- c.setBackground(COLOR_DEFAULT_VALUE);
- }
- else if((flags.get(DynamicParameters.BIT_OPTIONAL))) {
- c.setBackground(COLOR_OPTIONAL);
- }
- else {
- c.setBackground(null);
+ if (!hasFocus) {
+ if (row < parameters.size()) {
+ BitSet flags = parameters.getNode(row).flags;
+ // TODO: don't hardcode black - maybe mix the other colors, too?
+ c.setForeground(Color.BLACK);
+ if ((flags.get(DynamicParameters.BIT_INVALID))) {
+ c.setBackground(COLOR_SYNTAX_ERROR);
+ } else if ((flags.get(DynamicParameters.BIT_SYNTAX_ERROR))) {
+ c.setBackground(COLOR_SYNTAX_ERROR);
+ } else if ((flags.get(DynamicParameters.BIT_INCOMPLETE))) {
+ c.setBackground(COLOR_INCOMPLETE);
+ } else if ((flags.get(DynamicParameters.BIT_DEFAULT_VALUE))) {
+ c.setBackground(COLOR_DEFAULT_VALUE);
+ } else if ((flags.get(DynamicParameters.BIT_OPTIONAL))) {
+ c.setBackground(COLOR_OPTIONAL);
+ } else {
+ c.setBackground(null);
+ }
}
}
return c;
@@ -204,75 +216,89 @@ public class ParameterTable extends JTable {
private static final long serialVersionUID = 1L;
/**
+ * We need a panel to ensure focusing.
+ */
+ final JPanel panel;
+
+ /**
* Combo box to use
*/
- private final JComboBox comboBox;
+ private final JComboBox<String> comboBox;
/**
* Constructor.
*
* @param comboBox Combo box we're going to use
*/
- public DropdownEditor(JComboBox comboBox) {
+ public DropdownEditor(JComboBox<String> comboBox) {
super(comboBox);
this.comboBox = comboBox;
+ panel = new DispatchingPanel((JComponent) comboBox.getEditor().getEditorComponent());
+ panel.setLayout(new BorderLayout());
+ panel.add(comboBox, BorderLayout.CENTER);
}
@Override
public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {
- Component c = super.getTableCellEditorComponent(table, value, isSelected, row, column);
// remove old contents
comboBox.removeAllItems();
// Put the current value in first.
Object val = table.getValueAt(row, column);
- if(val != null) {
- comboBox.addItem(val);
- comboBox.setSelectedIndex(0);
+ if (val != null && val instanceof String) {
+ String sval = (String) val;
+ if (sval.equals(DynamicParameters.STRING_OPTIONAL)) {
+ sval = "";
+ }
+ if (sval.startsWith(DynamicParameters.STRING_USE_DEFAULT)) {
+ sval = "";
+ }
+ if (sval != "") {
+ comboBox.addItem(sval);
+ comboBox.setSelectedIndex(0);
+ }
}
- if(row < parameters.size()) {
+ if (row < parameters.size()) {
Parameter<?> option = parameters.getNode(row).param;
// We can do dropdown choices for class parameters
- if(option instanceof ClassParameter<?>) {
+ if (option instanceof ClassParameter<?>) {
ClassParameter<?> cp = (ClassParameter<?>) option;
// For parameters with a default value, offer using the default
// For optional parameters, offer not specifying them.
- if(cp.hasDefaultValue()) {
+ if (cp.hasDefaultValue()) {
comboBox.addItem(DynamicParameters.STRING_USE_DEFAULT + cp.getDefaultValueAsString());
- }
- else if(cp.isOptional()) {
+ } else if (cp.isOptional()) {
comboBox.addItem(DynamicParameters.STRING_OPTIONAL);
}
// Offer the shorthand version of class names.
- for(Class<?> impl : cp.getKnownImplementations()) {
+ for (Class<?> impl : cp.getKnownImplementations()) {
comboBox.addItem(ClassParameter.canonicalClassName(impl, cp.getRestrictionClass()));
}
}
// and for Flag parameters.
- else if(option instanceof Flag) {
- if(!Flag.SET.equals(val)) {
+ else if (option instanceof Flag) {
+ if (!Flag.SET.equals(val)) {
comboBox.addItem(Flag.SET);
}
- if(!Flag.NOT_SET.equals(val)) {
+ if (!Flag.NOT_SET.equals(val)) {
comboBox.addItem(Flag.NOT_SET);
}
}
// and for Enum parameters.
- else if(option instanceof EnumParameter<?>) {
+ else if (option instanceof EnumParameter<?>) {
EnumParameter<?> ep = (EnumParameter<?>) option;
- for(String s : ep.getPossibleValues()) {
- if(ep.hasDefaultValue() && ep.getDefaultValueAsString().equals(s)) {
- if(!(DynamicParameters.STRING_USE_DEFAULT + ep.getDefaultValueAsString()).equals(val)) {
+ for (String s : ep.getPossibleValues()) {
+ if (ep.hasDefaultValue() && ep.getDefaultValueAsString().equals(s)) {
+ if (!(DynamicParameters.STRING_USE_DEFAULT + ep.getDefaultValueAsString()).equals(val)) {
comboBox.addItem(DynamicParameters.STRING_USE_DEFAULT + s);
}
- }
- else if(!s.equals(val)) {
+ } else if (!s.equals(val)) {
comboBox.addItem(s);
}
}
}
// No completion for others
}
- return c;
+ return panel;
}
}
@@ -290,7 +316,7 @@ public class ParameterTable extends JTable {
/**
* We need a panel to put our components on.
*/
- final JPanel panel = new JPanel();
+ final JPanel panel;
/**
* Text field to store the name
@@ -303,10 +329,16 @@ public class ParameterTable extends JTable {
final JButton button = new JButton("...");
/**
+ * File selector mode.
+ */
+ int mode = FileDialog.LOAD;
+
+ /**
* Constructor.
*/
public FileNameEditor() {
button.addActionListener(this);
+ panel = new DispatchingPanel(textfield);
panel.setLayout(new BorderLayout());
panel.add(textfield, BorderLayout.CENTER);
panel.add(button, BorderLayout.EAST);
@@ -317,19 +349,35 @@ public class ParameterTable extends JTable {
*/
@Override
public void actionPerformed(ActionEvent e) {
- final JFileChooser fc = new JFileChooser(new File("."));
+ final FileDialog fc = new FileDialog(frame);
+ fc.setDirectory((new File(".")).getAbsolutePath());
+ fc.setMode(mode);
final String curr = textfield.getText();
if (curr != null && curr.length() > 0) {
- fc.setSelectedFile(new File(curr));
+ fc.setFile(curr);
}
- int returnVal = fc.showOpenDialog(button);
-
- if(returnVal == JFileChooser.APPROVE_OPTION) {
- textfield.setText(fc.getSelectedFile().getPath());
- }
- else {
- // Do nothing on cancel.
+ fc.setVisible(true);
+ String filename = fc.getFile();
+ if (filename != null) {
+ textfield.setText(new File(fc.getDirectory(), filename).getPath());
}
+ fc.dispose();
+ textfield.requestFocus();
+
+ // Swing file chooser. Currently much worse on Linux/GTK.
+ // final JFileChooser fc = new JFileChooser(new File("."));
+ // final String curr = textfield.getText();
+ // if (curr != null && curr.length() > 0) {
+ // fc.setSelectedFile(new File(curr));
+ // }
+ // int returnVal = fc.showOpenDialog(button);
+ //
+ // if(returnVal == JFileChooser.APPROVE_OPTION) {
+ // textfield.setText(fc.getSelectedFile().getPath());
+ // }
+ // else {
+ // // Do nothing on cancel.
+ // }
fireEditingStopped();
}
@@ -346,23 +394,24 @@ public class ParameterTable extends JTable {
*/
@Override
public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {
- if(row < parameters.size()) {
+ if (row < parameters.size()) {
Parameter<?> option = parameters.getNode(row).param;
- if(option instanceof FileParameter) {
+ if (option instanceof FileParameter) {
FileParameter fp = (FileParameter) option;
File f = null;
- if(fp.isDefined()) {
+ mode = FileParameter.FileType.INPUT_FILE.equals(fp.getFileType()) ? FileDialog.LOAD : FileDialog.SAVE;
+ if (fp.isDefined()) {
f = fp.getValue();
}
- if(f != null) {
+ if (f != null) {
String fn = f.getPath();
textfield.setText(fn);
- }
- else {
+ } else {
textfield.setText("");
}
}
}
+ textfield.requestFocus();
return panel;
}
}
@@ -381,7 +430,7 @@ public class ParameterTable extends JTable {
/**
* We need a panel to put our components on.
*/
- final JPanel panel = new JPanel();
+ final JPanel panel;
/**
* Text field to store the name
@@ -396,7 +445,7 @@ public class ParameterTable extends JTable {
/**
* The combobox we are abusing to produce the popup
*/
- final JComboBox combo = new JComboBox();
+ final JComboBox<String> combo = new JComboBox<>();
/**
* The popup menu.
@@ -413,6 +462,8 @@ public class ParameterTable extends JTable {
combo.addActionListener(this);
popup = new SuperPopup(combo);
+ panel = new DispatchingPanel(textfield);
+
panel.setLayout(new BorderLayout());
panel.add(textfield, BorderLayout.CENTER);
panel.add(button, BorderLayout.EAST);
@@ -423,31 +474,28 @@ public class ParameterTable extends JTable {
*/
@Override
public void actionPerformed(ActionEvent e) {
- if(e.getSource() == button) {
+ if (e.getSource() == button) {
popup.show(panel);
- }
- else if(e.getSource() == combo) {
+ } else if (e.getSource() == combo) {
String newClass = (String) combo.getSelectedItem();
- if(newClass != null && newClass.length() > 0) {
+ if (newClass != null && newClass.length() > 0) {
String val = textfield.getText();
- if(val.equals(DynamicParameters.STRING_OPTIONAL)) {
+ if (val.equals(DynamicParameters.STRING_OPTIONAL)) {
val = "";
}
- if(val.startsWith(DynamicParameters.STRING_USE_DEFAULT)) {
+ if (val.startsWith(DynamicParameters.STRING_USE_DEFAULT)) {
val = "";
}
- if(val.length() > 0) {
+ if (val.length() > 0) {
val = val + ClassListParameter.LIST_SEP + newClass;
- }
- else {
+ } else {
val = newClass;
}
textfield.setText(val);
popup.hide();
}
fireEditingStopped();
- }
- else {
+ } else {
LoggingUtil.warning("Unrecognized action event in ClassListEditor: " + e);
}
}
@@ -470,7 +518,7 @@ public class ParameterTable extends JTable {
*
* @param combo Combo box used for data storage.
*/
- public SuperPopup(JComboBox combo) {
+ public SuperPopup(JComboBox<String> combo) {
super(combo);
}
@@ -516,30 +564,28 @@ public class ParameterTable extends JTable {
@Override
public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {
combo.removeAllItems();
- if(row < parameters.size()) {
+ if (row < parameters.size()) {
Parameter<?> option = parameters.getNode(row).param;
// We can do dropdown choices for class parameters
- if(option instanceof ClassListParameter<?>) {
+ if (option instanceof ClassListParameter<?>) {
ClassListParameter<?> cp = (ClassListParameter<?>) option;
// Offer the shorthand version of class names.
String prefix = cp.getRestrictionClass().getPackage().getName() + ".";
- for(Class<?> impl : cp.getKnownImplementations()) {
+ for (Class<?> impl : cp.getKnownImplementations()) {
String name = impl.getName();
- if(name.startsWith(prefix)) {
+ if (name.startsWith(prefix)) {
name = name.substring(prefix.length());
}
combo.addItem(name);
}
}
- if(option.isDefined()) {
- if(option.tookDefaultValue()) {
+ if (option.isDefined()) {
+ if (option.tookDefaultValue()) {
textfield.setText(DynamicParameters.STRING_USE_DEFAULT + option.getDefaultValueAsString());
- }
- else {
+ } else {
textfield.setText(option.getValueAsString());
}
- }
- else {
+ } else {
textfield.setText("");
}
}
@@ -593,7 +639,7 @@ public class ParameterTable extends JTable {
* Constructor.
*/
public AdjustingEditor() {
- final JComboBox combobox = new JComboBox();
+ final JComboBox<String> combobox = new JComboBox<>();
combobox.setEditable(true);
this.dropdownEditor = new DropdownEditor(combobox);
this.plaintextEditor = new DefaultCellEditor(new JTextField());
@@ -603,7 +649,7 @@ public class ParameterTable extends JTable {
@Override
public Object getCellEditorValue() {
- if(activeEditor == null) {
+ if (activeEditor == null) {
return null;
}
return activeEditor.getCellEditorValue();
@@ -611,31 +657,31 @@ public class ParameterTable extends JTable {
@Override
public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {
- if(value instanceof String) {
+ if (value instanceof String) {
String s = (String) value;
- if(s.startsWith(DynamicParameters.STRING_USE_DEFAULT)) {
+ if (s.startsWith(DynamicParameters.STRING_USE_DEFAULT)) {
value = s.substring(DynamicParameters.STRING_USE_DEFAULT.length());
}
}
- if(row < parameters.size()) {
+ if (row < parameters.size()) {
Parameter<?> option = parameters.getNode(row).param;
- if(option instanceof Flag) {
+ if (option instanceof Flag) {
activeEditor = dropdownEditor;
return dropdownEditor.getTableCellEditorComponent(table, value, isSelected, row, column);
}
- if(option instanceof ClassListParameter<?>) {
+ if (option instanceof ClassListParameter<?>) {
activeEditor = classListEditor;
return classListEditor.getTableCellEditorComponent(table, value, isSelected, row, column);
}
- if(option instanceof ClassParameter<?>) {
+ if (option instanceof ClassParameter<?>) {
activeEditor = dropdownEditor;
return dropdownEditor.getTableCellEditorComponent(table, value, isSelected, row, column);
}
- if(option instanceof FileParameter) {
+ if (option instanceof FileParameter) {
activeEditor = fileNameEditor;
return fileNameEditor.getTableCellEditorComponent(table, value, isSelected, row, column);
}
- if(option instanceof EnumParameter<?>) {
+ if (option instanceof EnumParameter<?>) {
activeEditor = dropdownEditor;
return dropdownEditor.getTableCellEditorComponent(table, value, isSelected, row, column);
}
@@ -644,4 +690,57 @@ public class ParameterTable extends JTable {
return plaintextEditor.getTableCellEditorComponent(table, value, isSelected, row, column);
}
}
-} \ No newline at end of file
+
+ /**
+ * This is a panel that will dispatch keystrokes to a particular component.
+ *
+ * This makes the tabular GUI much more user friendly.
+ *
+ * @author Erich Schubert
+ *
+ * @apiviz.exclude
+ */
+ private class DispatchingPanel extends JPanel {
+ /**
+ * Serial version.
+ */
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * Component to dispatch to.
+ */
+ protected JComponent component;
+
+ /**
+ * Constructor.
+ *
+ * @param component Component to dispatch to.
+ */
+ public DispatchingPanel(JComponent component) {
+ super();
+ this.component = component;
+ setRequestFocusEnabled(true);
+ }
+
+ @Override
+ public void addNotify() {
+ super.addNotify();
+ component.requestFocus();
+ }
+
+ @Override
+ protected boolean processKeyBinding(KeyStroke ks, KeyEvent e, int condition, boolean pressed) {
+ InputMap map = component.getInputMap(condition);
+ ActionMap am = component.getActionMap();
+
+ if (map != null && am != null && isEnabled()) {
+ Object binding = map.get(ks);
+ Action action = (binding == null) ? null : am.get(binding);
+ if (action != null) {
+ return SwingUtilities.notifyAction(action, ks, e, component, e.getModifiers());
+ }
+ }
+ return false;
+ }
+ };
+}