summaryrefslogtreecommitdiff
path: root/src/de/lmu/ifi/dbs/elki/gui
diff options
context:
space:
mode:
Diffstat (limited to 'src/de/lmu/ifi/dbs/elki/gui')
-rw-r--r--src/de/lmu/ifi/dbs/elki/gui/GUIUtil.java3
-rw-r--r--src/de/lmu/ifi/dbs/elki/gui/configurator/AbstractParameterConfigurator.java2
-rw-r--r--src/de/lmu/ifi/dbs/elki/gui/configurator/AbstractSingleParameterConfigurator.java2
-rw-r--r--src/de/lmu/ifi/dbs/elki/gui/configurator/ClassListParameterConfigurator.java148
-rw-r--r--src/de/lmu/ifi/dbs/elki/gui/configurator/ClassParameterConfigurator.java150
-rw-r--r--src/de/lmu/ifi/dbs/elki/gui/configurator/ConfiguratorPanel.java2
-rw-r--r--src/de/lmu/ifi/dbs/elki/gui/configurator/EnumParameterConfigurator.java2
-rw-r--r--src/de/lmu/ifi/dbs/elki/gui/configurator/FileParameterConfigurator.java2
-rw-r--r--src/de/lmu/ifi/dbs/elki/gui/configurator/FlagParameterConfigurator.java2
-rw-r--r--src/de/lmu/ifi/dbs/elki/gui/configurator/ParameterConfigurator.java2
-rw-r--r--src/de/lmu/ifi/dbs/elki/gui/configurator/TextParameterConfigurator.java2
-rw-r--r--src/de/lmu/ifi/dbs/elki/gui/configurator/package-info.java2
-rw-r--r--src/de/lmu/ifi/dbs/elki/gui/icons/StockIcon.java8
-rw-r--r--src/de/lmu/ifi/dbs/elki/gui/icons/copyright-tango-project.txt2
-rw-r--r--src/de/lmu/ifi/dbs/elki/gui/icons/edit-find.pngbin0 -> 617 bytes
-rw-r--r--src/de/lmu/ifi/dbs/elki/gui/icons/package-info.java2
-rw-r--r--src/de/lmu/ifi/dbs/elki/gui/icons/package.pngbin0 -> 540 bytes
-rw-r--r--src/de/lmu/ifi/dbs/elki/gui/icons/system-search.pngbin0 -> 935 bytes
-rw-r--r--src/de/lmu/ifi/dbs/elki/gui/minigui/MiniGUI.java96
-rw-r--r--src/de/lmu/ifi/dbs/elki/gui/minigui/package-info.java2
-rw-r--r--src/de/lmu/ifi/dbs/elki/gui/multistep/MultiStepGUI.java23
-rw-r--r--src/de/lmu/ifi/dbs/elki/gui/multistep/package-info.java2
-rw-r--r--src/de/lmu/ifi/dbs/elki/gui/multistep/panels/AlgorithmTabPanel.java2
-rw-r--r--src/de/lmu/ifi/dbs/elki/gui/multistep/panels/EvaluationTabPanel.java2
-rw-r--r--src/de/lmu/ifi/dbs/elki/gui/multistep/panels/InputTabPanel.java2
-rw-r--r--src/de/lmu/ifi/dbs/elki/gui/multistep/panels/LoggingTabPanel.java2
-rw-r--r--src/de/lmu/ifi/dbs/elki/gui/multistep/panels/OutputTabPanel.java2
-rw-r--r--src/de/lmu/ifi/dbs/elki/gui/multistep/panels/ParameterTabPanel.java9
-rw-r--r--src/de/lmu/ifi/dbs/elki/gui/multistep/panels/SavedSettingsTabPanel.java2
-rw-r--r--src/de/lmu/ifi/dbs/elki/gui/multistep/panels/package-info.java2
-rw-r--r--src/de/lmu/ifi/dbs/elki/gui/package-info.java2
-rw-r--r--src/de/lmu/ifi/dbs/elki/gui/util/ClassTree.java211
-rw-r--r--src/de/lmu/ifi/dbs/elki/gui/util/DynamicParameters.java8
-rw-r--r--src/de/lmu/ifi/dbs/elki/gui/util/LogPane.java2
-rw-r--r--src/de/lmu/ifi/dbs/elki/gui/util/LogPanel.java2
-rw-r--r--src/de/lmu/ifi/dbs/elki/gui/util/ParameterTable.java461
-rw-r--r--src/de/lmu/ifi/dbs/elki/gui/util/ParametersModel.java2
-rw-r--r--src/de/lmu/ifi/dbs/elki/gui/util/SavedSettingsFile.java2
-rw-r--r--src/de/lmu/ifi/dbs/elki/gui/util/TreePopup.java412
-rw-r--r--src/de/lmu/ifi/dbs/elki/gui/util/package-info.java2
40 files changed, 1215 insertions, 366 deletions
diff --git a/src/de/lmu/ifi/dbs/elki/gui/GUIUtil.java b/src/de/lmu/ifi/dbs/elki/gui/GUIUtil.java
index 27cccded..e48edcea 100644
--- a/src/de/lmu/ifi/dbs/elki/gui/GUIUtil.java
+++ b/src/de/lmu/ifi/dbs/elki/gui/GUIUtil.java
@@ -4,7 +4,7 @@ package de.lmu.ifi.dbs.elki.gui;
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
- Copyright (C) 2013
+ Copyright (C) 2014
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
@@ -110,5 +110,4 @@ public final class GUIUtil {
logger.warning("Could not set the Default Uncaught Exception Handler", e);
}
}
-
}
diff --git a/src/de/lmu/ifi/dbs/elki/gui/configurator/AbstractParameterConfigurator.java b/src/de/lmu/ifi/dbs/elki/gui/configurator/AbstractParameterConfigurator.java
index c6883653..6857feba 100644
--- a/src/de/lmu/ifi/dbs/elki/gui/configurator/AbstractParameterConfigurator.java
+++ b/src/de/lmu/ifi/dbs/elki/gui/configurator/AbstractParameterConfigurator.java
@@ -4,7 +4,7 @@ package de.lmu.ifi.dbs.elki.gui.configurator;
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
- Copyright (C) 2013
+ Copyright (C) 2014
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
diff --git a/src/de/lmu/ifi/dbs/elki/gui/configurator/AbstractSingleParameterConfigurator.java b/src/de/lmu/ifi/dbs/elki/gui/configurator/AbstractSingleParameterConfigurator.java
index 240515cd..b37d23cc 100644
--- a/src/de/lmu/ifi/dbs/elki/gui/configurator/AbstractSingleParameterConfigurator.java
+++ b/src/de/lmu/ifi/dbs/elki/gui/configurator/AbstractSingleParameterConfigurator.java
@@ -4,7 +4,7 @@ package de.lmu.ifi.dbs.elki.gui.configurator;
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
- Copyright (C) 2013
+ Copyright (C) 2014
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
diff --git a/src/de/lmu/ifi/dbs/elki/gui/configurator/ClassListParameterConfigurator.java b/src/de/lmu/ifi/dbs/elki/gui/configurator/ClassListParameterConfigurator.java
index 182c7a0a..a49ec23f 100644
--- a/src/de/lmu/ifi/dbs/elki/gui/configurator/ClassListParameterConfigurator.java
+++ b/src/de/lmu/ifi/dbs/elki/gui/configurator/ClassListParameterConfigurator.java
@@ -4,7 +4,7 @@ package de.lmu.ifi.dbs.elki.gui.configurator;
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
- Copyright (C) 2013
+ Copyright (C) 2014
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
@@ -27,20 +27,24 @@ import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.Insets;
-import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
+import javax.swing.Icon;
import javax.swing.JButton;
-import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
-import javax.swing.plaf.basic.BasicComboPopup;
+import javax.swing.tree.DefaultTreeModel;
+import javax.swing.tree.TreeNode;
+import javax.swing.tree.TreePath;
import de.lmu.ifi.dbs.elki.gui.icons.StockIcon;
+import de.lmu.ifi.dbs.elki.gui.util.ClassTree;
+import de.lmu.ifi.dbs.elki.gui.util.ClassTree.ClassNode;
+import de.lmu.ifi.dbs.elki.gui.util.TreePopup;
import de.lmu.ifi.dbs.elki.logging.LoggingUtil;
import de.lmu.ifi.dbs.elki.utilities.optionhandling.parameterization.ListParameterization;
import de.lmu.ifi.dbs.elki.utilities.optionhandling.parameterization.TrackParameters;
@@ -54,8 +58,12 @@ import de.lmu.ifi.dbs.elki.utilities.optionhandling.parameters.Parameter;
* @author Erich Schubert
*
* @apiviz.uses ClassListParameter
+ * @apiviz.uses ClassTree
*/
public class ClassListParameterConfigurator extends AbstractSingleParameterConfigurator<ClassListParameter<?>> implements ActionListener, ChangeListener {
+ /**
+ * Configurator for children
+ */
final ConfiguratorPanel child;
/**
@@ -74,15 +82,16 @@ public class ClassListParameterConfigurator extends AbstractSingleParameterConfi
final JButton button;
/**
- * The combobox we are abusing to produce the popup
+ * The popup we use.
*/
- final JComboBox<String> combo;
+ final TreePopup popup;
/**
- * The popup menu.
+ * Constructor.
+ *
+ * @param cp Class list parameter
+ * @param parent Parent component
*/
- final SuperPopup popup;
-
public ClassListParameterConfigurator(ClassListParameter<?> cp, JComponent parent) {
super(cp, parent);
textfield = new JTextField();
@@ -95,26 +104,20 @@ public class ClassListParameterConfigurator extends AbstractSingleParameterConfi
button = new JButton(StockIcon.getStockIcon(StockIcon.LIST_ADD));
button.setToolTipText(param.getShortDescription());
button.addActionListener(this);
- // So the first item doesn't get automatically selected
- combo = new JComboBox<>();
- combo.setEditable(true);
- combo.setPrototypeDisplayValue(cp.getRestrictionClass().getSimpleName());
- popup = new SuperPopup(combo);
- // fill dropdown menu
- {
- // Offer the shorthand version of class names.
- String prefix = cp.getRestrictionClass().getPackage().getName() + ".";
- for(Class<?> impl : cp.getKnownImplementations()) {
- String name = impl.getName();
- if(name.startsWith(prefix)) {
- name = name.substring(prefix.length());
- }
- combo.addItem(name);
- }
- }
- combo.addActionListener(this);
+ TreeNode root = ClassTree.build(cp.getKnownImplementations(), cp.getRestrictionClass().getPackage().getName());
+
+ popup = new TreePopup(new DefaultTreeModel(root));
+ popup.getTree().setRootVisible(false);
+ // popup.setPrototypeDisplayValue(cp.getRestrictionClass().getSimpleName());
+ popup.addActionListener(this);
+ Icon classIcon = StockIcon.getStockIcon(StockIcon.GO_NEXT);
+ Icon packageIcon = StockIcon.getStockIcon(StockIcon.PACKAGE);
+ TreePopup.Renderer renderer = (TreePopup.Renderer) popup.getTree().getCellRenderer();
+ renderer.setLeafIcon(classIcon);
+ renderer.setFolderIcon(packageIcon);
+
// setup panel
{
panel = new JPanel();
@@ -156,82 +159,43 @@ public class ClassListParameterConfigurator extends AbstractSingleParameterConfi
public void actionPerformed(ActionEvent e) {
if(e.getSource() == button) {
popup.show(panel);
+ return;
}
- else if(e.getSource() == combo) {
- String newClass = (String) combo.getSelectedItem();
- if(newClass != null && newClass.length() > 0) {
- String val = textfield.getText();
- if(val.length() > 0) {
- val = val + ClassListParameter.LIST_SEP + newClass;
- }
- else {
- val = newClass;
- }
- textfield.setText(val);
- popup.hide();
- fireValueChanged();
- }
- }
- else if(e.getSource() == textfield) {
+ if(e.getSource() == textfield) {
fireValueChanged();
+ return;
}
- else {
- LoggingUtil.warning("actionPerformed triggered by unknown source: " + e.getSource());
- }
- }
-
- // FIXME: Refactor - duplicate code.
- /** @apiviz.exclude */
- class SuperPopup extends BasicComboPopup {
- /**
- * Serial version
- */
- private static final long serialVersionUID = 1L;
-
- /**
- * Constructor.
- *
- * @param combo Combo box used for data storage.
- */
- public SuperPopup(JComboBox<String> combo) {
- super(combo);
- }
-
- /**
- * Show the menu on a particular panel.
- *
- * This code is mostly copied from {@link BasicComboPopup#getPopupLocation}
- *
- * @param parent Parent element to show at.
- */
- public void show(JPanel parent) {
- Dimension popupSize = parent.getSize();
- Insets insets = getInsets();
-
- // reduce the width of the scrollpane by the insets so that the popup
- // is the same width as the combo box.
- popupSize.setSize(popupSize.width - (insets.right + insets.left), getPopupHeightForRowCount(comboBox.getMaximumRowCount()));
- Rectangle popupBounds = computePopupBounds(0, comboBox.getBounds().height, popupSize.width, popupSize.height);
- Dimension scrollSize = popupBounds.getSize();
-
- scroller.setMaximumSize(scrollSize);
- scroller.setPreferredSize(scrollSize);
- scroller.setMinimumSize(scrollSize);
-
- list.revalidate();
-
- super.show(parent, 0, parent.getBounds().height);
+ if(e.getSource() == popup) {
+ if(e.getActionCommand() == TreePopup.ACTION_CANCELED) {
+ popup.setVisible(false);
+ textfield.requestFocus();
+ return;
+ }
+ TreePath path = popup.getTree().getSelectionPath();
+ final Object comp = path != null ? path.getLastPathComponent() : null;
+ if(comp instanceof ClassNode) {
+ ClassNode sel = (path != null) ? (ClassNode) comp : null;
+ String newClass = (sel != null) ? sel.getClassName() : null;
+ if(newClass != null && newClass.length() > 0) {
+ String val = textfield.getText();
+ val = (val.length() > 0) ? val + ClassListParameter.LIST_SEP + newClass : newClass;
+ textfield.setText(val);
+ popup.setVisible(false);
+ fireValueChanged();
+ }
+ }
+ return;
}
+ LoggingUtil.warning("actionPerformed triggered by unknown source: " + e.getSource());
}
@Override
public void stateChanged(ChangeEvent e) {
if(e.getSource() == child) {
fireValueChanged();
+ return;
}
- else {
- LoggingUtil.warning("stateChanged triggered by unknown source: " + e.getSource());
- }
+ LoggingUtil.warning("stateChanged triggered by unknown source: " + e.getSource());
}
@Override
diff --git a/src/de/lmu/ifi/dbs/elki/gui/configurator/ClassParameterConfigurator.java b/src/de/lmu/ifi/dbs/elki/gui/configurator/ClassParameterConfigurator.java
index cbe03a4f..8deb72ed 100644
--- a/src/de/lmu/ifi/dbs/elki/gui/configurator/ClassParameterConfigurator.java
+++ b/src/de/lmu/ifi/dbs/elki/gui/configurator/ClassParameterConfigurator.java
@@ -4,7 +4,7 @@ package de.lmu.ifi.dbs.elki.gui.configurator;
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
- Copyright (C) 2013
+ Copyright (C) 2014
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
@@ -23,17 +23,31 @@ package de.lmu.ifi.dbs.elki.gui.configurator;
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+import java.awt.BorderLayout;
+import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
-import javax.swing.JComboBox;
+import javax.swing.Icon;
+import javax.swing.JButton;
import javax.swing.JComponent;
+import javax.swing.JPanel;
+import javax.swing.JTextField;
+import javax.swing.UIManager;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
-
+import javax.swing.plaf.basic.BasicArrowButton;
+import javax.swing.tree.DefaultTreeModel;
+import javax.swing.tree.TreeNode;
+import javax.swing.tree.TreePath;
+
+import de.lmu.ifi.dbs.elki.gui.icons.StockIcon;
+import de.lmu.ifi.dbs.elki.gui.util.ClassTree;
+import de.lmu.ifi.dbs.elki.gui.util.ClassTree.ClassNode;
import de.lmu.ifi.dbs.elki.gui.util.DynamicParameters;
+import de.lmu.ifi.dbs.elki.gui.util.TreePopup;
import de.lmu.ifi.dbs.elki.logging.LoggingUtil;
import de.lmu.ifi.dbs.elki.utilities.optionhandling.parameterization.ListParameterization;
import de.lmu.ifi.dbs.elki.utilities.optionhandling.parameterization.TrackParameters;
@@ -49,41 +63,91 @@ import de.lmu.ifi.dbs.elki.utilities.optionhandling.parameters.Parameter;
* @apiviz.uses ClassParameter
*/
public class ClassParameterConfigurator extends AbstractSingleParameterConfigurator<ClassParameter<?>> implements ActionListener, ChangeListener {
- final JComboBox<String> value;
-
+ /**
+ * We need a panel to put our components on.
+ */
+ final JPanel panel;
+
+ /**
+ * Text field to store the name
+ */
+ final JTextField textfield;
+
+ /**
+ * The button to open the file selector
+ */
+ final JButton button;
+
+ /**
+ * The popup we use.
+ */
+ final TreePopup popup;
+
+ /**
+ * Configuration panel for child.
+ */
final ConfiguratorPanel child;
+ /**
+ * Constructor.
+ *
+ * @param cp Class parameter
+ * @param parent Parent component.
+ */
public ClassParameterConfigurator(ClassParameter<?> cp, JComponent parent) {
super(cp, parent);
- // Input field
+ textfield = new JTextField();
+ textfield.setToolTipText(param.getShortDescription());
+ if(cp.isDefined() && !cp.tookDefaultValue()) {
+ textfield.setText(cp.getValueAsString());
+ }
+ textfield.setPreferredSize(new Dimension(400, textfield.getPreferredSize().height));
+ if(!param.tookDefaultValue() && param.isDefined() && param.getGivenValue() != null) {
+ textfield.setText(param.getValueAsString());
+ // FIXME: pre-select the current / default value in tree!
+ }
+
+ // This is a hack, but the BasicArrowButton looks very odd on GTK.
+ if(UIManager.getLookAndFeel().getName().indexOf("GTK") >= 0) {
+ // This is not optimal either, but looks more consistent at least.
+ button = new JButton(StockIcon.getStockIcon(StockIcon.EDIT_FIND));
+ }
+ else {
+ button = new BasicArrowButton(BasicArrowButton.SOUTH);
+ }
+ button.setToolTipText(param.getShortDescription());
+ button.addActionListener(this);
+
+ TreeNode root = ClassTree.build(cp.getKnownImplementations(), cp.getRestrictionClass().getPackage().getName());
+
+ popup = new TreePopup(new DefaultTreeModel(root));
+ popup.getTree().setRootVisible(false);
+ // popup.setPrototypeDisplayValue(cp.getRestrictionClass().getSimpleName());
+ popup.addActionListener(this);
+
+ Icon classIcon = StockIcon.getStockIcon(StockIcon.GO_NEXT);
+ Icon packageIcon = StockIcon.getStockIcon(StockIcon.PACKAGE);
+ TreePopup.Renderer renderer = (TreePopup.Renderer) popup.getTree().getCellRenderer();
+ renderer.setLeafIcon(classIcon);
+ renderer.setFolderIcon(packageIcon);
+
+ // setup panel
{
+ panel = new JPanel();
+ panel.setLayout(new BorderLayout());
+ panel.add(textfield, BorderLayout.CENTER);
+ panel.add(button, BorderLayout.EAST);
+
GridBagConstraints constraints = new GridBagConstraints();
constraints.fill = GridBagConstraints.HORIZONTAL;
constraints.weightx = 1.0;
- value = new JComboBox<>();
- value.setToolTipText(param.getShortDescription());
- value.setPrototypeDisplayValue(cp.getRestrictionClass().getSimpleName());
- parent.add(value, constraints);
+ parent.add(panel, constraints);
finishGridRow();
}
- if(!param.tookDefaultValue() && param.isDefined() && param.getGivenValue() != null) {
- value.addItem(param.getValueAsString());
- value.setSelectedIndex(0);
- }
+ // FIXME: re-add "none" option for optional parameters!
+ // FIXME: re-highlight default value!
- // For parameters with a default value, offer using the default
- // For optional parameters, offer not specifying them.
- if(cp.hasDefaultValue()) {
- value.addItem(DynamicParameters.STRING_USE_DEFAULT + cp.getDefaultValueAsString());
- }
- else if(cp.isOptional()) {
- value.addItem(DynamicParameters.STRING_OPTIONAL);
- }
- // Offer the shorthand version of class names.
- for(Class<?> impl : cp.getKnownImplementations()) {
- value.addItem(ClassParameter.canonicalClassName(impl, cp.getRestrictionClass()));
- }
// Child options
{
GridBagConstraints constraints = new GridBagConstraints();
@@ -95,7 +159,6 @@ public class ClassParameterConfigurator extends AbstractSingleParameterConfigura
child.addChangeListener(this);
parent.add(child, constraints);
}
- value.addActionListener(this);
}
@Override
@@ -105,27 +168,44 @@ public class ClassParameterConfigurator extends AbstractSingleParameterConfigura
@Override
public void actionPerformed(ActionEvent e) {
- if(e.getSource() == value) {
- fireValueChanged();
+ if(e.getSource() == button) {
+ popup.show(panel);
+ return;
}
- else {
- LoggingUtil.warning("actionPerformed triggered by unknown source: " + e.getSource());
+ if(e.getSource() == popup) {
+ if (e.getActionCommand() == TreePopup.ACTION_CANCELED) {
+ popup.setVisible(false);
+ textfield.requestFocus();
+ return;
+ }
+ TreePath path = popup.getTree().getSelectionPath();
+ final Object comp = path != null ? path.getLastPathComponent() : null;
+ if(comp instanceof ClassNode) {
+ ClassNode sel = (path != null) ? (ClassNode) comp : null;
+ String newClass = (sel != null) ? sel.getClassName() : null;
+ if(newClass != null && newClass.length() > 0) {
+ textfield.setText(newClass);
+ popup.setVisible(false);
+ fireValueChanged();
+ }
+ }
+ return;
}
+ LoggingUtil.warning("actionPerformed triggered by unknown source: " + e.getSource());
}
@Override
public void stateChanged(ChangeEvent e) {
if(e.getSource() == child) {
fireValueChanged();
+ return;
}
- else {
- LoggingUtil.warning("stateChanged triggered by unknown source: " + e.getSource());
- }
+ LoggingUtil.warning("stateChanged triggered by unknown source: " + e.getSource());
}
@Override
public String getUserInput() {
- String val = (String) value.getSelectedItem();
+ String val = textfield.getText();
if(val.startsWith(DynamicParameters.STRING_USE_DEFAULT)) {
return null;
}
diff --git a/src/de/lmu/ifi/dbs/elki/gui/configurator/ConfiguratorPanel.java b/src/de/lmu/ifi/dbs/elki/gui/configurator/ConfiguratorPanel.java
index 440d5d0a..fc24d7f8 100644
--- a/src/de/lmu/ifi/dbs/elki/gui/configurator/ConfiguratorPanel.java
+++ b/src/de/lmu/ifi/dbs/elki/gui/configurator/ConfiguratorPanel.java
@@ -4,7 +4,7 @@ package de.lmu.ifi.dbs.elki.gui.configurator;
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
- Copyright (C) 2013
+ Copyright (C) 2014
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
diff --git a/src/de/lmu/ifi/dbs/elki/gui/configurator/EnumParameterConfigurator.java b/src/de/lmu/ifi/dbs/elki/gui/configurator/EnumParameterConfigurator.java
index f361efa2..4aeed477 100644
--- a/src/de/lmu/ifi/dbs/elki/gui/configurator/EnumParameterConfigurator.java
+++ b/src/de/lmu/ifi/dbs/elki/gui/configurator/EnumParameterConfigurator.java
@@ -4,7 +4,7 @@ package de.lmu.ifi.dbs.elki.gui.configurator;
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
- Copyright (C) 2013
+ Copyright (C) 2014
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
diff --git a/src/de/lmu/ifi/dbs/elki/gui/configurator/FileParameterConfigurator.java b/src/de/lmu/ifi/dbs/elki/gui/configurator/FileParameterConfigurator.java
index 1fce49f0..58880251 100644
--- a/src/de/lmu/ifi/dbs/elki/gui/configurator/FileParameterConfigurator.java
+++ b/src/de/lmu/ifi/dbs/elki/gui/configurator/FileParameterConfigurator.java
@@ -4,7 +4,7 @@ package de.lmu.ifi.dbs.elki.gui.configurator;
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
- Copyright (C) 2013
+ Copyright (C) 2014
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
diff --git a/src/de/lmu/ifi/dbs/elki/gui/configurator/FlagParameterConfigurator.java b/src/de/lmu/ifi/dbs/elki/gui/configurator/FlagParameterConfigurator.java
index 5f73663c..163c11e2 100644
--- a/src/de/lmu/ifi/dbs/elki/gui/configurator/FlagParameterConfigurator.java
+++ b/src/de/lmu/ifi/dbs/elki/gui/configurator/FlagParameterConfigurator.java
@@ -4,7 +4,7 @@ package de.lmu.ifi.dbs.elki.gui.configurator;
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
- Copyright (C) 2013
+ Copyright (C) 2014
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
diff --git a/src/de/lmu/ifi/dbs/elki/gui/configurator/ParameterConfigurator.java b/src/de/lmu/ifi/dbs/elki/gui/configurator/ParameterConfigurator.java
index 6118355c..3e0ce509 100644
--- a/src/de/lmu/ifi/dbs/elki/gui/configurator/ParameterConfigurator.java
+++ b/src/de/lmu/ifi/dbs/elki/gui/configurator/ParameterConfigurator.java
@@ -4,7 +4,7 @@ package de.lmu.ifi.dbs.elki.gui.configurator;
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
- Copyright (C) 2013
+ Copyright (C) 2014
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
diff --git a/src/de/lmu/ifi/dbs/elki/gui/configurator/TextParameterConfigurator.java b/src/de/lmu/ifi/dbs/elki/gui/configurator/TextParameterConfigurator.java
index 411d056d..650a76f2 100644
--- a/src/de/lmu/ifi/dbs/elki/gui/configurator/TextParameterConfigurator.java
+++ b/src/de/lmu/ifi/dbs/elki/gui/configurator/TextParameterConfigurator.java
@@ -4,7 +4,7 @@ package de.lmu.ifi.dbs.elki.gui.configurator;
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
- Copyright (C) 2013
+ Copyright (C) 2014
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
diff --git a/src/de/lmu/ifi/dbs/elki/gui/configurator/package-info.java b/src/de/lmu/ifi/dbs/elki/gui/configurator/package-info.java
index cb7ef043..8209d8a3 100644
--- a/src/de/lmu/ifi/dbs/elki/gui/configurator/package-info.java
+++ b/src/de/lmu/ifi/dbs/elki/gui/configurator/package-info.java
@@ -8,7 +8,7 @@
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
-Copyright (C) 2013
+Copyright (C) 2014
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
diff --git a/src/de/lmu/ifi/dbs/elki/gui/icons/StockIcon.java b/src/de/lmu/ifi/dbs/elki/gui/icons/StockIcon.java
index c0550da3..1b213643 100644
--- a/src/de/lmu/ifi/dbs/elki/gui/icons/StockIcon.java
+++ b/src/de/lmu/ifi/dbs/elki/gui/icons/StockIcon.java
@@ -4,7 +4,7 @@ package de.lmu.ifi.dbs.elki.gui.icons;
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
- Copyright (C) 2013
+ Copyright (C) 2014
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
@@ -58,6 +58,8 @@ public class StockIcon {
public static final String EDIT_UNDO = "edit-undo";
+ public static final String EDIT_FIND = "edit-find";
+
public static final String EMBLEM_IMPORTANT = "emblem-important";
public static final String GO_BOTTOM = "go-bottom";
@@ -86,8 +88,12 @@ public class StockIcon {
public static final String LIST_REMOVE = "list-remove";
+ public static final String PACKAGE = "package";
+
public static final String PROCESS_STOP = "process-stop";
+ public static final String SYSTEM_SEARCH = "system-search";
+
private static final Map<String, SoftReference<Icon>> iconcache = new HashMap<>();
/**
diff --git a/src/de/lmu/ifi/dbs/elki/gui/icons/copyright-tango-project.txt b/src/de/lmu/ifi/dbs/elki/gui/icons/copyright-tango-project.txt
index d6e91e12..93bf1b6f 100644
--- a/src/de/lmu/ifi/dbs/elki/gui/icons/copyright-tango-project.txt
+++ b/src/de/lmu/ifi/dbs/elki/gui/icons/copyright-tango-project.txt
@@ -20,6 +20,7 @@ document-open.png
document-properties.png
document-save.png
edit-clear.png
+edit-find.png
edit-redo.png
edit-undo.png
emblem-important.png
@@ -36,6 +37,7 @@ go-up.png
help-browser.png
list-add.png
list-remove.png
+package.png
process-stop.png
---
diff --git a/src/de/lmu/ifi/dbs/elki/gui/icons/edit-find.png b/src/de/lmu/ifi/dbs/elki/gui/icons/edit-find.png
new file mode 100644
index 00000000..d072d3cb
--- /dev/null
+++ b/src/de/lmu/ifi/dbs/elki/gui/icons/edit-find.png
Binary files differ
diff --git a/src/de/lmu/ifi/dbs/elki/gui/icons/package-info.java b/src/de/lmu/ifi/dbs/elki/gui/icons/package-info.java
index c7ffb7d0..a07456f2 100644
--- a/src/de/lmu/ifi/dbs/elki/gui/icons/package-info.java
+++ b/src/de/lmu/ifi/dbs/elki/gui/icons/package-info.java
@@ -5,7 +5,7 @@
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
-Copyright (C) 2013
+Copyright (C) 2014
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
diff --git a/src/de/lmu/ifi/dbs/elki/gui/icons/package.png b/src/de/lmu/ifi/dbs/elki/gui/icons/package.png
new file mode 100644
index 00000000..90154261
--- /dev/null
+++ b/src/de/lmu/ifi/dbs/elki/gui/icons/package.png
Binary files differ
diff --git a/src/de/lmu/ifi/dbs/elki/gui/icons/system-search.png b/src/de/lmu/ifi/dbs/elki/gui/icons/system-search.png
new file mode 100644
index 00000000..fd7f0b07
--- /dev/null
+++ b/src/de/lmu/ifi/dbs/elki/gui/icons/system-search.png
Binary files differ
diff --git a/src/de/lmu/ifi/dbs/elki/gui/minigui/MiniGUI.java b/src/de/lmu/ifi/dbs/elki/gui/minigui/MiniGUI.java
index f60ac69e..9624a0d6 100644
--- a/src/de/lmu/ifi/dbs/elki/gui/minigui/MiniGUI.java
+++ b/src/de/lmu/ifi/dbs/elki/gui/minigui/MiniGUI.java
@@ -4,7 +4,7 @@ package de.lmu.ifi.dbs.elki.gui.minigui;
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
- Copyright (C) 2013
+ Copyright (C) 2014
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
@@ -24,6 +24,7 @@ package de.lmu.ifi.dbs.elki.gui.minigui;
*/
import java.awt.Dimension;
+import java.awt.Event;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
@@ -34,9 +35,11 @@ import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.BitSet;
+import java.util.Collections;
import java.util.List;
import java.util.logging.Level;
+import javax.swing.AbstractAction;
import javax.swing.AbstractListModel;
import javax.swing.BoxLayout;
import javax.swing.ComboBoxModel;
@@ -46,19 +49,24 @@ import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
+import javax.swing.KeyStroke;
import javax.swing.SwingWorker;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;
import de.lmu.ifi.dbs.elki.KDDTask;
import de.lmu.ifi.dbs.elki.application.AbstractApplication;
+import de.lmu.ifi.dbs.elki.application.ELKILauncher;
+import de.lmu.ifi.dbs.elki.application.KDDCLIApplication;
import de.lmu.ifi.dbs.elki.gui.GUIUtil;
import de.lmu.ifi.dbs.elki.gui.util.DynamicParameters;
import de.lmu.ifi.dbs.elki.gui.util.LogPanel;
import de.lmu.ifi.dbs.elki.gui.util.ParameterTable;
import de.lmu.ifi.dbs.elki.gui.util.ParametersModel;
import de.lmu.ifi.dbs.elki.gui.util.SavedSettingsFile;
+import de.lmu.ifi.dbs.elki.logging.CLISmartHandler;
import de.lmu.ifi.dbs.elki.logging.Logging;
+import de.lmu.ifi.dbs.elki.logging.LoggingConfiguration;
import de.lmu.ifi.dbs.elki.utilities.Alias;
import de.lmu.ifi.dbs.elki.utilities.FormatUtil;
import de.lmu.ifi.dbs.elki.utilities.exceptions.UnableToComplyException;
@@ -66,6 +74,7 @@ import de.lmu.ifi.dbs.elki.utilities.optionhandling.ParameterException;
import de.lmu.ifi.dbs.elki.utilities.optionhandling.UnspecifiedParameterException;
import de.lmu.ifi.dbs.elki.utilities.optionhandling.parameterization.SerializedParameterization;
import de.lmu.ifi.dbs.elki.utilities.optionhandling.parameterization.TrackParameters;
+import de.lmu.ifi.dbs.elki.utilities.pairs.Pair;
import de.lmu.ifi.dbs.elki.workflow.LoggingStep;
import de.lmu.ifi.dbs.elki.workflow.OutputStep;
@@ -79,7 +88,7 @@ import de.lmu.ifi.dbs.elki.workflow.OutputStep;
* @apiviz.owns ParameterTable
* @apiviz.owns DynamicParameters
*/
-@Alias({"mini", "minigui"})
+@Alias({ "mini", "minigui" })
public class MiniGUI extends AbstractApplication {
/**
* Filename for saved settings.
@@ -97,6 +106,11 @@ public class MiniGUI extends AbstractApplication {
private static final Logging LOG = Logging.getLogger(MiniGUI.class);
/**
+ * Quit action, for mnemonics.
+ */
+ protected static final String ACTION_QUIT = "quit";
+
+ /**
* The frame
*/
JFrame frame;
@@ -142,6 +156,11 @@ public class MiniGUI extends AbstractApplication {
protected JButton runButton;
/**
+ * Application to configure / run.
+ */
+ private Class<? extends AbstractApplication> maincls = KDDCLIApplication.class;
+
+ /**
* Constructor.
*/
public MiniGUI() {
@@ -305,6 +324,26 @@ public class MiniGUI extends AbstractApplication {
LOG.exception(e);
}
+ {
+ KeyStroke key = KeyStroke.getKeyStroke(KeyEvent.VK_Q, Event.CTRL_MASK);
+ panel.getInputMap().put(key, ACTION_QUIT);
+ }
+ {
+ KeyStroke key = KeyStroke.getKeyStroke(KeyEvent.VK_W, Event.CTRL_MASK);
+ panel.getInputMap().put(key, ACTION_QUIT);
+ }
+ panel.getActionMap().put(ACTION_QUIT, new AbstractAction() {
+ /**
+ * Serial version
+ */
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ frame.dispose();
+ }
+ });
+
// Finalize the frame.
frame.setContentPane(panel);
frame.pack();
@@ -331,7 +370,7 @@ public class MiniGUI extends AbstractApplication {
SerializedParameterization config = new SerializedParameterization(params);
TrackParameters track = new TrackParameters(config);
track.tryInstantiate(LoggingStep.class);
- track.tryInstantiate(KDDTask.class);
+ track.tryInstantiate(maincls);
config.logUnusedParameters();
// config.logAndClearReportedErrors();
final boolean hasErrors = (config.getErrors().size() > 0);
@@ -367,6 +406,18 @@ public class MiniGUI extends AbstractApplication {
}
/**
+ * Auto-load the last task from the history file.
+ */
+ protected void loadLatest() {
+ int size = store.size();
+ if(size > 0) {
+ final Pair<String, ArrayList<String>> pair = store.getElementAt(size - 1);
+ savedSettingsModel.setSelectedItem(pair.first);
+ doSetParameters(pair.second);
+ }
+ }
+
+ /**
* Do a full run of the KDDTask with the specified parameters.
*/
protected void startTask() {
@@ -385,7 +436,7 @@ public class MiniGUI extends AbstractApplication {
public Void doInBackground() {
SerializedParameterization config = new SerializedParameterization(params);
config.tryInstantiate(LoggingStep.class);
- KDDTask task = config.tryInstantiate(KDDTask.class);
+ AbstractApplication task = config.tryInstantiate(maincls);
try {
config.logUnusedParameters();
if(config.getErrors().size() == 0) {
@@ -455,14 +506,41 @@ public class MiniGUI extends AbstractApplication {
try {
final MiniGUI gui = new MiniGUI();
gui.run();
+ List<String> params = Collections.emptyList();
if(args != null && args.length > 0) {
- gui.doSetParameters(Arrays.asList(args));
- }
- else {
- gui.doSetParameters(new ArrayList<String>());
+ params = new ArrayList<>(Arrays.asList(args));
+ // TODO: it would be nicer to use the Parameterization API for this!
+ if(params.size() > 0) {
+ try {
+ gui.maincls = ELKILauncher.findMainClass(params.get(0));
+ params.remove(0); // on success
+ }
+ catch(ClassNotFoundException e) {
+ // Ignore.
+ }
+ }
+ if(params.remove("-minigui.last")) {
+ javax.swing.SwingUtilities.invokeLater(new Runnable() {
+ @Override
+ public void run() {
+ gui.loadLatest();
+ }
+ });
+ }
+ if(params.remove("-minigui.autorun")) {
+ javax.swing.SwingUtilities.invokeLater(new Runnable() {
+ @Override
+ public void run() {
+ gui.startTask();
+ }
+ });
+ }
}
+ gui.doSetParameters(params);
}
- catch(UnableToComplyException e) {
+ catch(Exception | Error e) {
+ // Restore error handler, as the GUI is likely broken.
+ LoggingConfiguration.replaceDefaultHandler(new CLISmartHandler());
LOG.exception(e);
}
}
diff --git a/src/de/lmu/ifi/dbs/elki/gui/minigui/package-info.java b/src/de/lmu/ifi/dbs/elki/gui/minigui/package-info.java
index 7acb0045..3dd5ea02 100644
--- a/src/de/lmu/ifi/dbs/elki/gui/minigui/package-info.java
+++ b/src/de/lmu/ifi/dbs/elki/gui/minigui/package-info.java
@@ -5,7 +5,7 @@
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
-Copyright (C) 2013
+Copyright (C) 2014
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
diff --git a/src/de/lmu/ifi/dbs/elki/gui/multistep/MultiStepGUI.java b/src/de/lmu/ifi/dbs/elki/gui/multistep/MultiStepGUI.java
index 11a45d25..31e24ef6 100644
--- a/src/de/lmu/ifi/dbs/elki/gui/multistep/MultiStepGUI.java
+++ b/src/de/lmu/ifi/dbs/elki/gui/multistep/MultiStepGUI.java
@@ -4,7 +4,7 @@ package de.lmu.ifi.dbs.elki.gui.multistep;
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
- Copyright (C) 2013
+ Copyright (C) 2014
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
@@ -47,7 +47,9 @@ import de.lmu.ifi.dbs.elki.gui.multistep.panels.OutputTabPanel;
import de.lmu.ifi.dbs.elki.gui.multistep.panels.SavedSettingsTabPanel;
import de.lmu.ifi.dbs.elki.gui.util.LogPanel;
import de.lmu.ifi.dbs.elki.gui.util.SavedSettingsFile;
+import de.lmu.ifi.dbs.elki.logging.CLISmartHandler;
import de.lmu.ifi.dbs.elki.logging.Logging;
+import de.lmu.ifi.dbs.elki.logging.LoggingConfiguration;
import de.lmu.ifi.dbs.elki.utilities.Alias;
import de.lmu.ifi.dbs.elki.utilities.exceptions.UnableToComplyException;
import de.lmu.ifi.dbs.elki.utilities.optionhandling.parameterization.ListParameterization;
@@ -124,7 +126,8 @@ public class MultiStepGUI extends AbstractApplication {
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
try {
frame.setIconImage(new ImageIcon(KDDTask.class.getResource("elki-icon.png")).getImage());
- } catch (Exception e) {
+ }
+ catch(Exception e) {
// Ignore - icon not found is not fatal.
}
@@ -171,9 +174,11 @@ public class MultiStepGUI extends AbstractApplication {
SavedSettingsFile settings = new SavedSettingsFile(MiniGUI.SAVED_SETTINGS_FILENAME);
try {
settings.load();
- } catch (FileNotFoundException e) {
+ }
+ catch(FileNotFoundException e) {
LOG.warning("Error loading saved settings.", e);
- } catch (IOException e) {
+ }
+ catch(IOException e) {
LOG.exception(e);
}
@@ -250,12 +255,16 @@ public class MultiStepGUI extends AbstractApplication {
try {
final MultiStepGUI gui = new MultiStepGUI();
gui.run();
- if (args != null && args.length > 0) {
+ if(args != null && args.length > 0) {
gui.setParameters(new SerializedParameterization(args));
- } else {
+ }
+ else {
gui.setParameters(new SerializedParameterization());
}
- } catch (UnableToComplyException e) {
+ }
+ catch(Exception | Error e) {
+ // Restore error handler, as the GUI is likely broken.
+ LoggingConfiguration.replaceDefaultHandler(new CLISmartHandler());
LOG.exception(e);
}
}
diff --git a/src/de/lmu/ifi/dbs/elki/gui/multistep/package-info.java b/src/de/lmu/ifi/dbs/elki/gui/multistep/package-info.java
index 3e8f11b2..cc3df902 100644
--- a/src/de/lmu/ifi/dbs/elki/gui/multistep/package-info.java
+++ b/src/de/lmu/ifi/dbs/elki/gui/multistep/package-info.java
@@ -5,7 +5,7 @@
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
-Copyright (C) 2013
+Copyright (C) 2014
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
diff --git a/src/de/lmu/ifi/dbs/elki/gui/multistep/panels/AlgorithmTabPanel.java b/src/de/lmu/ifi/dbs/elki/gui/multistep/panels/AlgorithmTabPanel.java
index d6622e8f..7968a5dd 100644
--- a/src/de/lmu/ifi/dbs/elki/gui/multistep/panels/AlgorithmTabPanel.java
+++ b/src/de/lmu/ifi/dbs/elki/gui/multistep/panels/AlgorithmTabPanel.java
@@ -4,7 +4,7 @@ package de.lmu.ifi.dbs.elki.gui.multistep.panels;
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
- Copyright (C) 2013
+ Copyright (C) 2014
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
diff --git a/src/de/lmu/ifi/dbs/elki/gui/multistep/panels/EvaluationTabPanel.java b/src/de/lmu/ifi/dbs/elki/gui/multistep/panels/EvaluationTabPanel.java
index d8d4153c..e89bb187 100644
--- a/src/de/lmu/ifi/dbs/elki/gui/multistep/panels/EvaluationTabPanel.java
+++ b/src/de/lmu/ifi/dbs/elki/gui/multistep/panels/EvaluationTabPanel.java
@@ -4,7 +4,7 @@ package de.lmu.ifi.dbs.elki.gui.multistep.panels;
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
- Copyright (C) 2013
+ Copyright (C) 2014
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
diff --git a/src/de/lmu/ifi/dbs/elki/gui/multistep/panels/InputTabPanel.java b/src/de/lmu/ifi/dbs/elki/gui/multistep/panels/InputTabPanel.java
index 2f4d027b..e2866183 100644
--- a/src/de/lmu/ifi/dbs/elki/gui/multistep/panels/InputTabPanel.java
+++ b/src/de/lmu/ifi/dbs/elki/gui/multistep/panels/InputTabPanel.java
@@ -4,7 +4,7 @@ package de.lmu.ifi.dbs.elki.gui.multistep.panels;
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
- Copyright (C) 2013
+ Copyright (C) 2014
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
diff --git a/src/de/lmu/ifi/dbs/elki/gui/multistep/panels/LoggingTabPanel.java b/src/de/lmu/ifi/dbs/elki/gui/multistep/panels/LoggingTabPanel.java
index c4933673..2495eb03 100644
--- a/src/de/lmu/ifi/dbs/elki/gui/multistep/panels/LoggingTabPanel.java
+++ b/src/de/lmu/ifi/dbs/elki/gui/multistep/panels/LoggingTabPanel.java
@@ -4,7 +4,7 @@ package de.lmu.ifi.dbs.elki.gui.multistep.panels;
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
- Copyright (C) 2013
+ Copyright (C) 2014
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
diff --git a/src/de/lmu/ifi/dbs/elki/gui/multistep/panels/OutputTabPanel.java b/src/de/lmu/ifi/dbs/elki/gui/multistep/panels/OutputTabPanel.java
index 12af18d3..124bbe61 100644
--- a/src/de/lmu/ifi/dbs/elki/gui/multistep/panels/OutputTabPanel.java
+++ b/src/de/lmu/ifi/dbs/elki/gui/multistep/panels/OutputTabPanel.java
@@ -4,7 +4,7 @@ package de.lmu.ifi.dbs.elki.gui.multistep.panels;
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
- Copyright (C) 2013
+ Copyright (C) 2014
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
diff --git a/src/de/lmu/ifi/dbs/elki/gui/multistep/panels/ParameterTabPanel.java b/src/de/lmu/ifi/dbs/elki/gui/multistep/panels/ParameterTabPanel.java
index 667960a1..287f4e48 100644
--- a/src/de/lmu/ifi/dbs/elki/gui/multistep/panels/ParameterTabPanel.java
+++ b/src/de/lmu/ifi/dbs/elki/gui/multistep/panels/ParameterTabPanel.java
@@ -4,7 +4,7 @@ package de.lmu.ifi.dbs.elki.gui.multistep.panels;
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
- Copyright (C) 2013
+ Copyright (C) 2014
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
@@ -43,10 +43,9 @@ import de.lmu.ifi.dbs.elki.utilities.FormatUtil;
import de.lmu.ifi.dbs.elki.utilities.optionhandling.ParameterException;
import de.lmu.ifi.dbs.elki.utilities.optionhandling.UnspecifiedParameterException;
import de.lmu.ifi.dbs.elki.utilities.optionhandling.parameterization.ListParameterization;
+import de.lmu.ifi.dbs.elki.utilities.optionhandling.parameterization.TrackedParameter;
import de.lmu.ifi.dbs.elki.utilities.optionhandling.parameterization.Parameterization;
import de.lmu.ifi.dbs.elki.utilities.optionhandling.parameterization.TrackParameters;
-import de.lmu.ifi.dbs.elki.utilities.optionhandling.parameters.Parameter;
-import de.lmu.ifi.dbs.elki.utilities.pairs.Pair;
/**
* Abstract panel, showing particular options.
@@ -219,8 +218,8 @@ public abstract class ParameterTabPanel extends JPanel implements ChangeListener
parameterTable.setEnabled(false);
parameterTable.clear();
- for (Pair<Object, Parameter<?>> pair : track.getAllParameters()) {
- parameterTable.addParameter(pair.first, pair.getSecond(), track);
+ for (TrackedParameter pair : track.getAllParameters()) {
+ parameterTable.addParameter(pair.getOwner(), pair.getParameter(), track);
}
// parameters.updateFromTrackParameters(track);
diff --git a/src/de/lmu/ifi/dbs/elki/gui/multistep/panels/SavedSettingsTabPanel.java b/src/de/lmu/ifi/dbs/elki/gui/multistep/panels/SavedSettingsTabPanel.java
index acebdc16..201a99c6 100644
--- a/src/de/lmu/ifi/dbs/elki/gui/multistep/panels/SavedSettingsTabPanel.java
+++ b/src/de/lmu/ifi/dbs/elki/gui/multistep/panels/SavedSettingsTabPanel.java
@@ -4,7 +4,7 @@ package de.lmu.ifi.dbs.elki.gui.multistep.panels;
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
- Copyright (C) 2013
+ Copyright (C) 2014
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
diff --git a/src/de/lmu/ifi/dbs/elki/gui/multistep/panels/package-info.java b/src/de/lmu/ifi/dbs/elki/gui/multistep/panels/package-info.java
index 77d1779d..1ace9d34 100644
--- a/src/de/lmu/ifi/dbs/elki/gui/multistep/panels/package-info.java
+++ b/src/de/lmu/ifi/dbs/elki/gui/multistep/panels/package-info.java
@@ -5,7 +5,7 @@
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
-Copyright (C) 2013
+Copyright (C) 2014
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
diff --git a/src/de/lmu/ifi/dbs/elki/gui/package-info.java b/src/de/lmu/ifi/dbs/elki/gui/package-info.java
index 8fa23e0d..47c29c71 100644
--- a/src/de/lmu/ifi/dbs/elki/gui/package-info.java
+++ b/src/de/lmu/ifi/dbs/elki/gui/package-info.java
@@ -5,7 +5,7 @@
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
-Copyright (C) 2013
+Copyright (C) 2014
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
diff --git a/src/de/lmu/ifi/dbs/elki/gui/util/ClassTree.java b/src/de/lmu/ifi/dbs/elki/gui/util/ClassTree.java
new file mode 100644
index 00000000..3071aa7e
--- /dev/null
+++ b/src/de/lmu/ifi/dbs/elki/gui/util/ClassTree.java
@@ -0,0 +1,211 @@
+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) 2014
+ Ludwig-Maximilians-Universität München
+ Lehr- und Forschungseinheit für Datenbanksysteme
+ ELKI Development Team
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+import java.util.HashMap;
+import java.util.List;
+
+import javax.swing.tree.DefaultMutableTreeNode;
+import javax.swing.tree.MutableTreeNode;
+import javax.swing.tree.TreeNode;
+
+/**
+ * Build a tree of available classes for use in Swing UIs.
+ *
+ * @author Erich Schubert
+ *
+ * @apiviz.has TreeNode
+ */
+public class ClassTree {
+ /**
+ * Build the class tree for a given set of choices.
+ *
+ * @param choices Class choices
+ * @param rootpkg Root package name (to strip / hide)
+ * @return Root node.
+ */
+ public static TreeNode build(List<Class<?>> choices, String rootpkg) {
+ MutableTreeNode root = new PackageNode(rootpkg, rootpkg);
+ HashMap<String, MutableTreeNode> lookup = new HashMap<>();
+ if(rootpkg != null) {
+ lookup.put(rootpkg, root);
+ }
+ lookup.put("de.lmu.ifi.dbs.elki", root);
+ lookup.put("", root);
+
+ // Use the shorthand version of class names.
+ String prefix = rootpkg != null ? rootpkg + "." : null;
+
+ for(Class<?> impl : choices) {
+ String name = impl.getName();
+ name = (prefix != null && name.startsWith(prefix)) ? name.substring(prefix.length()) : name;
+ MutableTreeNode c = new ClassNode(impl.getName().substring(impl.getPackage().getName().length() + 1), name);
+
+ MutableTreeNode p = null;
+ int l = name.lastIndexOf('.');
+ while(p == null) {
+ if(l < 0) {
+ p = root;
+ break;
+ }
+ String pname = name.substring(0, l);
+ p = lookup.get(pname);
+ if(p != null) {
+ break;
+ }
+ l = pname.lastIndexOf('.');
+ MutableTreeNode tmp = new PackageNode(l >= 0 ? pname.substring(l + 1) : pname, pname);
+ tmp.insert(c, 0);
+ c = tmp;
+ lookup.put(pname, tmp);
+ name = pname;
+ }
+ p.insert(c, p.getChildCount());
+ }
+ // Simplify tree, except for root node
+ for(int i = 0; i < root.getChildCount(); i++) {
+ MutableTreeNode c = (MutableTreeNode) root.getChildAt(i);
+ MutableTreeNode c2 = simplifyTree(c, null);
+ if(c != c2) {
+ root.remove(i);
+ root.insert(c2, i);
+ }
+ }
+ return root;
+ }
+
+ /**
+ * Simplify the tree.
+ *
+ * @param cur Current node
+ * @param prefix Prefix to add
+ * @return Replacement node
+ */
+ private static MutableTreeNode simplifyTree(MutableTreeNode cur, String prefix) {
+ if(cur instanceof PackageNode) {
+ PackageNode node = (PackageNode) cur;
+ if(node.getChildCount() == 1) {
+ String newprefix = (prefix != null) ? prefix + "." + (String) node.getUserObject() : (String) node.getUserObject();
+ cur = simplifyTree((MutableTreeNode) node.getChildAt(0), newprefix);
+ }
+ else {
+ if(prefix != null) {
+ node.setUserObject(prefix + "." + (String) node.getUserObject());
+ }
+ for(int i = 0; i < node.getChildCount(); i++) {
+ MutableTreeNode c = (MutableTreeNode) node.getChildAt(i);
+ MutableTreeNode c2 = simplifyTree(c, null);
+ if(c != c2) {
+ node.remove(i);
+ node.insert(c2, i);
+ }
+ }
+ }
+ }
+ else if(cur instanceof ClassNode) {
+ ClassNode node = (ClassNode) cur;
+ if(prefix != null) {
+ node.setUserObject(prefix + "." + (String) node.getUserObject());
+ }
+ }
+ return cur;
+ }
+
+ /**
+ * Tree node representing a single class.
+ *
+ * @author Erich Schubert
+ *
+ * @apiviz.exclude
+ */
+ public static class PackageNode extends DefaultMutableTreeNode {
+ /**
+ * Serial version
+ */
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * Class name.
+ */
+ private String pkgname;
+
+ /**
+ * Current class name.
+ *
+ * @param display Displayed name
+ * @param pkgname Actual class name
+ */
+ public PackageNode(String display, String pkgname) {
+ super(display);
+ this.pkgname = pkgname;
+ }
+
+ /**
+ * Return the package name.
+ *
+ * @return Package name
+ */
+ public String getPackageName() {
+ return pkgname;
+ }
+ }
+
+ /**
+ * Tree node representing a single class.
+ *
+ * @author Erich Schubert
+ *
+ * @apiviz.exclude
+ */
+ public static class ClassNode extends DefaultMutableTreeNode {
+ /**
+ * Serial version
+ */
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * Class name.
+ */
+ private String clsname;
+
+ /**
+ * Current class name.
+ *
+ * @param display Displayed name
+ * @param clsname Actual class name
+ */
+ public ClassNode(String display, String clsname) {
+ super(display);
+ this.clsname = clsname;
+ }
+
+ /**
+ * Return the class name.
+ *
+ * @return Class name
+ */
+ public String getClassName() {
+ return clsname;
+ }
+ }
+}
diff --git a/src/de/lmu/ifi/dbs/elki/gui/util/DynamicParameters.java b/src/de/lmu/ifi/dbs/elki/gui/util/DynamicParameters.java
index d974a6d6..2836b33c 100644
--- a/src/de/lmu/ifi/dbs/elki/gui/util/DynamicParameters.java
+++ b/src/de/lmu/ifi/dbs/elki/gui/util/DynamicParameters.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) 2013
+ Copyright (C) 2014
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
@@ -28,12 +28,12 @@ import java.util.BitSet;
import de.lmu.ifi.dbs.elki.utilities.optionhandling.OptionID;
import de.lmu.ifi.dbs.elki.utilities.optionhandling.ParameterException;
+import de.lmu.ifi.dbs.elki.utilities.optionhandling.parameterization.TrackedParameter;
import de.lmu.ifi.dbs.elki.utilities.optionhandling.parameterization.SerializedParameterization;
import de.lmu.ifi.dbs.elki.utilities.optionhandling.parameterization.TrackParameters;
import de.lmu.ifi.dbs.elki.utilities.optionhandling.parameters.Flag;
import de.lmu.ifi.dbs.elki.utilities.optionhandling.parameters.Parameter;
import de.lmu.ifi.dbs.elki.utilities.optionhandling.parameters.StringParameter;
-import de.lmu.ifi.dbs.elki.utilities.pairs.Pair;
/**
* Wrapper around a set of parameters for ELKI, that may not yet be complete or
@@ -141,8 +141,8 @@ public class DynamicParameters {
*/
public synchronized void updateFromTrackParameters(TrackParameters track) {
parameters.clear();
- for (Pair<Object, Parameter<?>> p : track.getAllParameters()) {
- Parameter<?> option = p.getSecond();
+ for (TrackedParameter p : track.getAllParameters()) {
+ Parameter<?> option = p.getParameter();
String value = null;
if (option.isDefined()) {
if (option.tookDefaultValue()) {
diff --git a/src/de/lmu/ifi/dbs/elki/gui/util/LogPane.java b/src/de/lmu/ifi/dbs/elki/gui/util/LogPane.java
index 4664b852..e19fd752 100644
--- a/src/de/lmu/ifi/dbs/elki/gui/util/LogPane.java
+++ b/src/de/lmu/ifi/dbs/elki/gui/util/LogPane.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) 2013
+ Copyright (C) 2014
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
diff --git a/src/de/lmu/ifi/dbs/elki/gui/util/LogPanel.java b/src/de/lmu/ifi/dbs/elki/gui/util/LogPanel.java
index 11080cc9..99cf50b2 100644
--- a/src/de/lmu/ifi/dbs/elki/gui/util/LogPanel.java
+++ b/src/de/lmu/ifi/dbs/elki/gui/util/LogPanel.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) 2013
+ Copyright (C) 2014
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
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 105242c0..aa94f3ef 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) 2013
+ Copyright (C) 2014
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
@@ -29,18 +29,19 @@ 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.awt.event.KeyListener;
import java.io.File;
import java.util.BitSet;
import javax.swing.AbstractCellEditor;
import javax.swing.Action;
import javax.swing.ActionMap;
+import javax.swing.BorderFactory;
import javax.swing.DefaultCellEditor;
+import javax.swing.Icon;
import javax.swing.InputMap;
import javax.swing.JButton;
import javax.swing.JComboBox;
@@ -50,11 +51,17 @@ 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;
import javax.swing.table.TableColumn;
-
+import javax.swing.tree.DefaultMutableTreeNode;
+import javax.swing.tree.DefaultTreeModel;
+import javax.swing.tree.TreeModel;
+import javax.swing.tree.TreeNode;
+import javax.swing.tree.TreePath;
+
+import de.lmu.ifi.dbs.elki.gui.icons.StockIcon;
+import de.lmu.ifi.dbs.elki.gui.util.ClassTree.ClassNode;
import de.lmu.ifi.dbs.elki.logging.LoggingUtil;
import de.lmu.ifi.dbs.elki.utilities.optionhandling.parameters.ClassListParameter;
import de.lmu.ifi.dbs.elki.utilities.optionhandling.parameters.ClassParameter;
@@ -134,6 +141,54 @@ public class ParameterTable extends JTable {
col1.setPreferredWidth(150);
TableColumn col2 = this.getColumnModel().getColumn(1);
col2.setPreferredWidth(650);
+ this.addKeyListener(new Handler());
+
+ // Increase row height, to make editors usable.
+ setRowHeight(getRowHeight() + 4);
+ }
+
+ /**
+ * Internal key listener.
+ *
+ * @author Erich Schubert
+ *
+ * @apiviz.exclude
+ */
+ protected class Handler implements KeyListener {
+ @Override
+ public void keyTyped(KeyEvent e) {
+ // ignore
+ }
+
+ @Override
+ public void keyPressed(KeyEvent e) {
+ if((e.getModifiersEx() & KeyEvent.CTRL_DOWN_MASK) != 0) {
+ if(e.getKeyCode() == KeyEvent.VK_SPACE //
+ || e.getKeyCode() == KeyEvent.VK_ENTER //
+ || e.getKeyCode() == KeyEvent.VK_DOWN //
+ || e.getKeyCode() == KeyEvent.VK_KP_DOWN) {
+ final ParameterTable parent = ParameterTable.this;
+ if(!parent.isEditing()) {
+ int leadRow = parent.getSelectionModel().getLeadSelectionIndex();
+ int leadColumn = parent.getColumnModel().getSelectionModel().getLeadSelectionIndex();
+ parent.editCellAt(leadRow, leadColumn);
+ Component editorComponent = getEditorComponent();
+ // This is a hack, to make the content assist open immediately.
+ if(editorComponent instanceof DispatchingPanel) {
+ KeyListener[] l = ((DispatchingPanel) editorComponent).component.getKeyListeners();
+ for(KeyListener li : l) {
+ li.keyPressed(e);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ @Override
+ public void keyReleased(KeyEvent e) {
+ // ignore
+ }
}
/**
@@ -156,16 +211,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());
@@ -180,22 +235,27 @@ 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 (!hasFocus) {
- if (row < parameters.size()) {
+ 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))) {
+ if((flags.get(DynamicParameters.BIT_INVALID))) {
c.setBackground(COLOR_SYNTAX_ERROR);
- } else if ((flags.get(DynamicParameters.BIT_SYNTAX_ERROR))) {
+ }
+ else if((flags.get(DynamicParameters.BIT_SYNTAX_ERROR))) {
c.setBackground(COLOR_SYNTAX_ERROR);
- } else if ((flags.get(DynamicParameters.BIT_INCOMPLETE))) {
+ }
+ else if((flags.get(DynamicParameters.BIT_INCOMPLETE))) {
c.setBackground(COLOR_INCOMPLETE);
- } else if ((flags.get(DynamicParameters.BIT_DEFAULT_VALUE))) {
+ }
+ else if((flags.get(DynamicParameters.BIT_DEFAULT_VALUE))) {
c.setBackground(COLOR_DEFAULT_VALUE);
- } else if ((flags.get(DynamicParameters.BIT_OPTIONAL))) {
+ }
+ else if((flags.get(DynamicParameters.BIT_OPTIONAL))) {
c.setBackground(COLOR_OPTIONAL);
- } else {
+ }
+ else {
c.setBackground(null);
}
}
@@ -209,7 +269,7 @@ public class ParameterTable extends JTable {
*
* @author Erich Schubert
*/
- private class DropdownEditor extends DefaultCellEditor {
+ private class DropdownEditor extends DefaultCellEditor implements KeyListener {
/**
* Serial Version
*/
@@ -236,6 +296,32 @@ public class ParameterTable extends JTable {
panel = new DispatchingPanel((JComponent) comboBox.getEditor().getEditorComponent());
panel.setLayout(new BorderLayout());
panel.add(comboBox, BorderLayout.CENTER);
+ comboBox.setBorder(BorderFactory.createEmptyBorder(0, 3, 0, 3));
+ }
+
+ @Override
+ public void keyTyped(KeyEvent e) {
+ // Ignore
+ }
+
+ @Override
+ public void keyPressed(KeyEvent e) {
+ if((e.getModifiersEx() & KeyEvent.CTRL_DOWN_MASK) != 0) {
+ if(e.getKeyCode() == KeyEvent.VK_SPACE //
+ || e.getKeyCode() == KeyEvent.VK_ENTER //
+ || e.getKeyCode() == KeyEvent.VK_DOWN //
+ || e.getKeyCode() == KeyEvent.VK_KP_DOWN) {
+ if(!comboBox.isPopupVisible()) {
+ comboBox.showPopup();
+ e.consume();
+ }
+ }
+ }
+ }
+
+ @Override
+ public void keyReleased(KeyEvent e) {
+ // Ignore
}
@Override
@@ -244,54 +330,40 @@ public class ParameterTable extends JTable {
comboBox.removeAllItems();
// Put the current value in first.
Object val = table.getValueAt(row, column);
- if (val != null && val instanceof String) {
+ if(val != null && val instanceof String) {
String sval = (String) val;
- if (sval.equals(DynamicParameters.STRING_OPTIONAL)) {
+ if(sval.equals(DynamicParameters.STRING_OPTIONAL)) {
sval = "";
}
- if (sval.startsWith(DynamicParameters.STRING_USE_DEFAULT)) {
+ if(sval.startsWith(DynamicParameters.STRING_USE_DEFAULT)) {
sval = "";
}
- if (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<?>) {
- ClassParameter<?> cp = (ClassParameter<?>) option;
- // For parameters with a default value, offer using the default
- // For optional parameters, offer not specifying them.
- if (cp.hasDefaultValue()) {
- comboBox.addItem(DynamicParameters.STRING_USE_DEFAULT + cp.getDefaultValueAsString());
- } else if (cp.isOptional()) {
- comboBox.addItem(DynamicParameters.STRING_OPTIONAL);
- }
- // Offer the shorthand version of class names.
- 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)) {
+ // for Flag parameters.
+ 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);
}
}
@@ -307,7 +379,7 @@ public class ParameterTable extends JTable {
*
* @author Erich Schubert
*/
- private class FileNameEditor extends AbstractCellEditor implements TableCellEditor, ActionListener {
+ private class FileNameEditor extends AbstractCellEditor implements TableCellEditor, ActionListener, KeyListener {
/**
* Serial version number
*/
@@ -334,6 +406,11 @@ public class ParameterTable extends JTable {
int mode = FileDialog.LOAD;
/**
+ * Default path.
+ */
+ String defaultpath = (new File(".")).getAbsolutePath();
+
+ /**
* Constructor.
*/
public FileNameEditor() {
@@ -342,6 +419,8 @@ public class ParameterTable extends JTable {
panel.setLayout(new BorderLayout());
panel.add(textfield, BorderLayout.CENTER);
panel.add(button, BorderLayout.EAST);
+ textfield.setBorder(BorderFactory.createEmptyBorder(0, 3, 0, 3));
+ textfield.addKeyListener(this);
}
/**
@@ -349,38 +428,47 @@ public class ParameterTable extends JTable {
*/
@Override
public void actionPerformed(ActionEvent e) {
- final FileDialog fc = new FileDialog(frame);
- fc.setDirectory((new File(".")).getAbsolutePath());
+ FileDialog fc = new FileDialog(frame);
+ fc.setDirectory(defaultpath);
fc.setMode(mode);
final String curr = textfield.getText();
- if (curr != null && curr.length() > 0) {
+ if(curr != null && curr.length() > 0) {
fc.setFile(curr);
}
fc.setVisible(true);
String filename = fc.getFile();
- if (filename != null) {
+ if(filename != null) {
textfield.setText(new File(fc.getDirectory(), filename).getPath());
}
+ fc.setVisible(false);
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();
}
+ @Override
+ public void keyTyped(KeyEvent e) {
+ // Ignore
+ }
+
+ @Override
+ public void keyPressed(KeyEvent e) {
+ if((e.getModifiersEx() & KeyEvent.CTRL_DOWN_MASK) != 0) {
+ if(e.getKeyCode() == KeyEvent.VK_SPACE //
+ || e.getKeyCode() == KeyEvent.VK_ENTER //
+ || e.getKeyCode() == KeyEvent.VK_DOWN //
+ || e.getKeyCode() == KeyEvent.VK_KP_DOWN) {
+ e.consume();
+ actionPerformed(new ActionEvent(e.getSource(), ActionEvent.ACTION_PERFORMED, "assist"));
+ }
+ }
+ }
+
+ @Override
+ public void keyReleased(KeyEvent e) {
+ // Ignore
+ }
+
/**
* Delegate getCellEditorValue to the text field.
*/
@@ -394,21 +482,16 @@ 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;
mode = FileParameter.FileType.INPUT_FILE.equals(fp.getFileType()) ? FileDialog.LOAD : FileDialog.SAVE;
- if (fp.isDefined()) {
+ if(fp.isDefined()) {
f = fp.getValue();
}
- if (f != null) {
- String fn = f.getPath();
- textfield.setText(fn);
- } else {
- textfield.setText("");
- }
+ textfield.setText(f != null ? f.getPath() : "");
}
}
textfield.requestFocus();
@@ -417,11 +500,11 @@ public class ParameterTable extends JTable {
}
/**
- * Editor for selecting input and output file and folders names
+ * Editor for choosing classes.
*
* @author Erich Schubert
*/
- private class ClassListEditor extends AbstractCellEditor implements TableCellEditor, ActionListener {
+ private class ClassListEditor extends AbstractCellEditor implements TableCellEditor, ActionListener, KeyListener {
/**
* Serial version number
*/
@@ -443,30 +526,43 @@ public class ParameterTable extends JTable {
final JButton button = new JButton("+");
/**
- * The combobox we are abusing to produce the popup
+ * The popup menu.
*/
- final JComboBox<String> combo = new JComboBox<>();
+ final TreePopup popup;
/**
- * The popup menu.
+ * Tree model
*/
- final SuperPopup popup;
+ private TreeModel model;
+
+ /**
+ * Parameter we are currently editing.
+ */
+ private Parameter<?> option;
/**
* Constructor.
*/
public ClassListEditor() {
+ textfield.addKeyListener(this);
button.addActionListener(this);
- // So the first item doesn't get automatically selected
- combo.setEditable(true);
- combo.addActionListener(this);
- popup = new SuperPopup(combo);
+ model = new DefaultTreeModel(new DefaultMutableTreeNode());
+ popup = new TreePopup(model);
+ popup.getTree().setRootVisible(false);
+ popup.addActionListener(this);
+
+ Icon classIcon = StockIcon.getStockIcon(StockIcon.GO_NEXT);
+ Icon packageIcon = StockIcon.getStockIcon(StockIcon.PACKAGE);
+ TreePopup.Renderer renderer = (TreePopup.Renderer) popup.getTree().getCellRenderer();
+ renderer.setLeafIcon(classIcon);
+ renderer.setFolderIcon(packageIcon);
panel = new DispatchingPanel(textfield);
panel.setLayout(new BorderLayout());
panel.add(textfield, BorderLayout.CENTER);
panel.add(button, BorderLayout.EAST);
+ textfield.setBorder(BorderFactory.createEmptyBorder(0, 3, 0, 3));
}
/**
@@ -474,80 +570,42 @@ 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) {
- String newClass = (String) combo.getSelectedItem();
- if (newClass != null && newClass.length() > 0) {
- String val = textfield.getText();
- if (val.equals(DynamicParameters.STRING_OPTIONAL)) {
- val = "";
- }
- if (val.startsWith(DynamicParameters.STRING_USE_DEFAULT)) {
- val = "";
- }
- if (val.length() > 0) {
- val = val + ClassListParameter.LIST_SEP + newClass;
- } else {
- val = newClass;
+ return;
+ }
+ if(e.getSource() == popup) {
+ if(e.getActionCommand() == TreePopup.ACTION_CANCELED) {
+ popup.setVisible(false);
+ textfield.requestFocus();
+ return;
+ }
+ TreePath path = popup.getTree().getSelectionPath();
+ final Object comp = (path != null) ? path.getLastPathComponent() : null;
+ if(comp instanceof ClassNode) {
+ ClassNode sel = (path != null) ? (ClassNode) comp : null;
+ String newClass = (sel != null) ? sel.getClassName() : null;
+ if(newClass != null && newClass.length() > 0) {
+ if(option instanceof ClassListParameter) {
+ String val = textfield.getText();
+ if(val.equals(DynamicParameters.STRING_OPTIONAL) //
+ || val.startsWith(DynamicParameters.STRING_USE_DEFAULT)) {
+ val = "";
+ }
+ val = (val.length() > 0) ? val + ClassListParameter.LIST_SEP + newClass : newClass;
+ textfield.setText(val);
+ }
+ else {
+ textfield.setText(newClass);
+ }
+ popup.setVisible(false);
+ fireEditingStopped();
+ textfield.requestFocus();
}
- textfield.setText(val);
- popup.hide();
}
- fireEditingStopped();
- } else {
- LoggingUtil.warning("Unrecognized action event in ClassListEditor: " + e);
- }
- }
-
- /**
- * Modified popup
- *
- * @author Erich Schubert
- *
- * @apiviz.exclude
- */
- class SuperPopup extends BasicComboPopup {
- /**
- * Serial version
- */
- private static final long serialVersionUID = 1L;
-
- /**
- * Constructor.
- *
- * @param combo Combo box used for data storage.
- */
- public SuperPopup(JComboBox<String> combo) {
- super(combo);
- }
-
- /**
- * Show the menu on a particular panel.
- *
- * This code is mostly copied from
- * {@link BasicComboPopup#getPopupLocation}
- *
- * @param parent Parent element to show at.
- */
- public void show(JPanel parent) {
- Dimension popupSize = parent.getSize();
- Insets insets = getInsets();
-
- // reduce the width of the scrollpane by the insets so that the popup
- // is the same width as the combo box.
- popupSize.setSize(popupSize.width - (insets.right + insets.left), getPopupHeightForRowCount(comboBox.getMaximumRowCount()));
- Rectangle popupBounds = computePopupBounds(0, comboBox.getBounds().height, popupSize.width, popupSize.height);
- Dimension scrollSize = popupBounds.getSize();
-
- scroller.setMaximumSize(scrollSize);
- scroller.setPreferredSize(scrollSize);
- scroller.setMinimumSize(scrollSize);
-
- list.revalidate();
-
- super.show(parent, 0, parent.getBounds().height);
+ return;
}
+ LoggingUtil.warning("Unrecognized action event in ClassListEditor: " + e);
}
/**
@@ -558,36 +616,65 @@ public class ParameterTable extends JTable {
return textfield.getText();
}
+ @Override
+ public void keyTyped(KeyEvent e) {
+ // Ignore
+ }
+
+ @Override
+ public void keyPressed(KeyEvent e) {
+ if((e.getModifiersEx() & KeyEvent.CTRL_DOWN_MASK) != 0) {
+ if(e.getKeyCode() == KeyEvent.VK_SPACE //
+ || e.getKeyCode() == KeyEvent.VK_ENTER //
+ || e.getKeyCode() == KeyEvent.VK_DOWN //
+ || e.getKeyCode() == KeyEvent.VK_KP_DOWN) {
+ if(!popup.isVisible()) {
+ popup.show(ClassListEditor.this.panel);
+ e.consume();
+ }
+ }
+ }
+ }
+
+ @Override
+ public void keyReleased(KeyEvent e) {
+ // Ignore
+ }
+
/**
* Apply the Editor for a selected option.
*/
@Override
public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {
- combo.removeAllItems();
- if (row < parameters.size()) {
- Parameter<?> option = parameters.getNode(row).param;
+ if(row < parameters.size()) {
+ this.option = parameters.getNode(row).param;
+ TreeNode root;
// 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()) {
- String name = impl.getName();
- if (name.startsWith(prefix)) {
- name = name.substring(prefix.length());
- }
- combo.addItem(name);
- }
+ root = ClassTree.build(cp.getKnownImplementations(), cp.getRestrictionClass().getPackage().getName());
+ button.setText("+");
+ }
+ else if(option instanceof ClassParameter<?>) {
+ ClassParameter<?> cp = (ClassParameter<?>) option;
+ root = ClassTree.build(cp.getKnownImplementations(), cp.getRestrictionClass().getPackage().getName());
+ button.setText("v");
+ }
+ else {
+ root = new DefaultMutableTreeNode();
}
- 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("");
}
+ popup.getTree().setModel(new DefaultTreeModel(root));
}
return panel;
}
@@ -642,14 +729,16 @@ public class ParameterTable extends JTable {
final JComboBox<String> combobox = new JComboBox<>();
combobox.setEditable(true);
this.dropdownEditor = new DropdownEditor(combobox);
- this.plaintextEditor = new DefaultCellEditor(new JTextField());
+ JTextField tf = new JTextField();
+ tf.setBorder(BorderFactory.createEmptyBorder(0, 3, 0, 3));
+ this.plaintextEditor = new DefaultCellEditor(tf);
this.classListEditor = new ClassListEditor();
this.fileNameEditor = new FileNameEditor();
}
@Override
public Object getCellEditorValue() {
- if (activeEditor == null) {
+ if(activeEditor == null) {
return null;
}
return activeEditor.getCellEditorValue();
@@ -657,31 +746,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<?>) {
- activeEditor = dropdownEditor;
- return dropdownEditor.getTableCellEditorComponent(table, value, isSelected, row, column);
+ if(option instanceof ClassParameter<?>) {
+ activeEditor = classListEditor;
+ return classListEditor.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);
}
@@ -733,10 +822,10 @@ public class ParameterTable extends JTable {
InputMap map = component.getInputMap(condition);
ActionMap am = component.getActionMap();
- if (map != null && am != null && isEnabled()) {
+ if(map != null && am != null && isEnabled()) {
Object binding = map.get(ks);
Action action = (binding == null) ? null : am.get(binding);
- if (action != null) {
+ if(action != null) {
return SwingUtilities.notifyAction(action, ks, e, component, e.getModifiers());
}
}
diff --git a/src/de/lmu/ifi/dbs/elki/gui/util/ParametersModel.java b/src/de/lmu/ifi/dbs/elki/gui/util/ParametersModel.java
index 42f0a1af..82a0ee74 100644
--- a/src/de/lmu/ifi/dbs/elki/gui/util/ParametersModel.java
+++ b/src/de/lmu/ifi/dbs/elki/gui/util/ParametersModel.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) 2013
+ Copyright (C) 2014
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
diff --git a/src/de/lmu/ifi/dbs/elki/gui/util/SavedSettingsFile.java b/src/de/lmu/ifi/dbs/elki/gui/util/SavedSettingsFile.java
index a99b7414..8e614b85 100644
--- a/src/de/lmu/ifi/dbs/elki/gui/util/SavedSettingsFile.java
+++ b/src/de/lmu/ifi/dbs/elki/gui/util/SavedSettingsFile.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) 2013
+ Copyright (C) 2014
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
diff --git a/src/de/lmu/ifi/dbs/elki/gui/util/TreePopup.java b/src/de/lmu/ifi/dbs/elki/gui/util/TreePopup.java
new file mode 100644
index 00000000..60ad0604
--- /dev/null
+++ b/src/de/lmu/ifi/dbs/elki/gui/util/TreePopup.java
@@ -0,0 +1,412 @@
+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) 2014
+ Ludwig-Maximilians-Universität München
+ Lehr- und Forschungseinheit für Datenbanksysteme
+ ELKI Development Team
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+import java.awt.BorderLayout;
+import java.awt.Color;
+import java.awt.Component;
+import java.awt.Dimension;
+import java.awt.GraphicsConfiguration;
+import java.awt.Insets;
+import java.awt.Point;
+import java.awt.Rectangle;
+import java.awt.Toolkit;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.FocusEvent;
+import java.awt.event.FocusListener;
+import java.awt.event.KeyEvent;
+import java.awt.event.KeyListener;
+import java.awt.event.MouseEvent;
+import java.awt.event.MouseListener;
+
+import javax.swing.BoxLayout;
+import javax.swing.Icon;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JPopupMenu;
+import javax.swing.JScrollPane;
+import javax.swing.JTree;
+import javax.swing.ScrollPaneConstants;
+import javax.swing.SwingUtilities;
+import javax.swing.UIManager;
+import javax.swing.border.Border;
+import javax.swing.border.LineBorder;
+import javax.swing.tree.DefaultMutableTreeNode;
+import javax.swing.tree.DefaultTreeModel;
+import javax.swing.tree.TreeCellRenderer;
+import javax.swing.tree.TreeModel;
+
+/**
+ * Popup menu that contains a JTree.
+ *
+ * @author Erich Schubert
+ */
+public class TreePopup extends JPopupMenu {
+ /**
+ * Serialization version.
+ */
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * Action string for confirmed operations (enter or click).
+ */
+ public static final String ACTION_SELECTED = "selected";
+
+ /**
+ * Action string for canceled operations (escape button pressed).
+ */
+ public static final String ACTION_CANCELED = "canceled";
+
+ /**
+ * Tree.
+ */
+ protected JTree tree;
+
+ /**
+ * Scroll pane, containing the tree.
+ */
+ protected JScrollPane scroller;
+
+ /**
+ * Tree model.
+ */
+ private TreeModel model;
+
+ /**
+ * Event handler
+ */
+ private Handler handler = new Handler();
+
+ /**
+ * Border of the popup.
+ */
+ private static Border TREE_BORDER = new LineBorder(Color.BLACK, 1);
+
+ /**
+ * Constructor with an empty tree model.
+ *
+ * This needs to also add a root node, and therefore sets
+ * {@code getTree().setRootVisible(false)}.
+ */
+ public TreePopup() {
+ this(new DefaultTreeModel(new DefaultMutableTreeNode()));
+ tree.setRootVisible(false);
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param model Tree model
+ */
+ public TreePopup(TreeModel model) {
+ super();
+ this.setName("TreePopup.popup");
+ this.model = model;
+
+ // UI construction of the popup.
+ tree = createTree();
+ scroller = createScroller();
+ configurePopup();
+ }
+
+ /**
+ * Creates the JList used in the popup to display the items in the combo box
+ * model. This method is called when the UI class is created.
+ *
+ * @return a <code>JList</code> used to display the combo box items
+ */
+ protected JTree createTree() {
+ JTree tree = new JTree(model);
+ tree.setName("TreePopup.tree");
+ tree.setFont(getFont());
+ tree.setForeground(getForeground());
+ tree.setBackground(getBackground());
+ tree.setBorder(null);
+ tree.setFocusable(true);
+ tree.addMouseListener(handler);
+ tree.addKeyListener(handler);
+ tree.setCellRenderer(new Renderer());
+ return tree;
+ }
+
+ /**
+ * Configure the popup display.
+ */
+ protected void configurePopup() {
+ setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
+ setBorderPainted(true);
+ setBorder(TREE_BORDER);
+ setOpaque(false);
+ add(scroller);
+ setDoubleBuffered(true);
+ setFocusable(false);
+ }
+
+ /**
+ * Creates the scroll pane which houses the scrollable tree.
+ */
+ protected JScrollPane createScroller() {
+ JScrollPane sp = new JScrollPane(tree, ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
+ sp.setHorizontalScrollBar(null);
+ sp.setName("TreePopup.scrollPane");
+ sp.setFocusable(false);
+ sp.getVerticalScrollBar().setFocusable(false);
+ sp.setBorder(null);
+ return sp;
+ }
+
+ /**
+ * Access the tree contained.
+ *
+ * @return Tree
+ */
+ public JTree getTree() {
+ return tree;
+ }
+
+ /**
+ * Display the popup, attached to the given component.
+ *
+ * @param parent Parent component
+ */
+ public void show(Component parent) {
+ Dimension parentSize = parent.getSize();
+ Insets insets = getInsets();
+
+ // reduce the width of the scrollpane by the insets so that the popup
+ // is the same width as the combo box.
+ parentSize.setSize(parentSize.width - (insets.right + insets.left), 10 * parentSize.height);
+ Dimension scrollSize = computePopupBounds(parent, 0, getBounds().height, parentSize.width, parentSize.height).getSize();
+
+ scroller.setMaximumSize(scrollSize);
+ scroller.setPreferredSize(scrollSize);
+ scroller.setMinimumSize(scrollSize);
+
+ super.show(parent, 0, parent.getHeight());
+ tree.requestFocusInWindow();
+ }
+
+ protected Rectangle computePopupBounds(Component parent, int px, int py, int pw, int ph) {
+ Toolkit toolkit = Toolkit.getDefaultToolkit();
+ Rectangle screenBounds;
+
+ // Calculate the desktop dimensions relative to the combo box.
+ GraphicsConfiguration gc = parent.getGraphicsConfiguration();
+ Point p = new Point();
+ SwingUtilities.convertPointFromScreen(p, parent);
+ if(gc != null) {
+ Insets screenInsets = toolkit.getScreenInsets(gc);
+ screenBounds = gc.getBounds();
+ screenBounds.width -= (screenInsets.left + screenInsets.right);
+ screenBounds.height -= (screenInsets.top + screenInsets.bottom);
+ screenBounds.x += (p.x + screenInsets.left);
+ screenBounds.y += (p.y + screenInsets.top);
+ }
+ else {
+ screenBounds = new Rectangle(p, toolkit.getScreenSize());
+ }
+
+ Rectangle rect = new Rectangle(px, py, pw, ph);
+ if(py + ph > screenBounds.y + screenBounds.height && ph < screenBounds.height) {
+ rect.y = -rect.height;
+ }
+ return rect;
+ }
+
+ /**
+ * Register an action listener.
+ *
+ * @param listener Action listener
+ */
+ public void addActionListener(ActionListener listener) {
+ listenerList.add(ActionListener.class, listener);
+ }
+
+ /**
+ * Unregister an action listener.
+ *
+ * @param listener Action listener
+ */
+ public void removeActionListener(ActionListener listener) {
+ listenerList.remove(ActionListener.class, listener);
+ }
+
+ /**
+ * Notify action listeners.
+ *
+ * @param event the <code>ActionEvent</code> object
+ */
+ protected void fireActionPerformed(ActionEvent event) {
+ Object[] listeners = listenerList.getListenerList();
+ for(int i = listeners.length - 2; i >= 0; i -= 2) {
+ if(listeners[i] == ActionListener.class) {
+ ((ActionListener) listeners[i + 1]).actionPerformed(event);
+ }
+ }
+ }
+
+ /**
+ * Tree cell render.
+ *
+ * @author Erich Schubert
+ *
+ * @apiviz.exclude
+ */
+ public class Renderer extends JPanel implements TreeCellRenderer {
+ /**
+ * Serial version
+ */
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * Label to render
+ */
+ JLabel label;
+
+ /**
+ * Colors
+ */
+ private Color selbg, defbg, selfg, deffg;
+
+ /**
+ * Icons
+ */
+ private Icon leafIcon, folderIcon;
+
+ /**
+ * Constructor.
+ */
+ protected Renderer() {
+ selbg = UIManager.getColor("Tree.selectionBackground");
+ defbg = UIManager.getColor("Tree.textBackground");
+ selfg = UIManager.getColor("Tree.selectionForeground");
+ deffg = UIManager.getColor("Tree.textForeground");
+
+ setLayout(new BorderLayout());
+ add(label = new JLabel("This should never be rendered."));
+ }
+
+ @Override
+ public Component getTreeCellRendererComponent(JTree tree, Object value, boolean selected, boolean expanded, boolean leaf, int row, boolean hasFocus) {
+ label.setText((String) ((DefaultMutableTreeNode) value).getUserObject());
+ setForeground(selected ? selfg : deffg);
+ setBackground(selected ? selbg : defbg);
+ label.setIcon(leaf ? leafIcon : folderIcon);
+ setPreferredSize(new Dimension(1000, label.getPreferredSize().height));
+ return this;
+ }
+
+ /**
+ * Set the leaf icon
+ *
+ * @param leafIcon Leaf icon
+ */
+ public void setLeafIcon(Icon leafIcon) {
+ this.leafIcon = leafIcon;
+ }
+
+ /**
+ * Set the folder icon.
+ *
+ * @param folderIcon Folder icon
+ */
+ public void setFolderIcon(Icon folderIcon) {
+ this.folderIcon = folderIcon;
+ }
+ }
+
+ /**
+ * Event handler class.
+ *
+ * @author Erich Schubert
+ *
+ * @apiviz.exclude
+ */
+ protected class Handler implements MouseListener, KeyListener, FocusListener {
+ @Override
+ public void keyTyped(KeyEvent e) {
+ if(e.getKeyChar() == '\n') {
+ e.consume();
+ }
+ }
+
+ @Override
+ public void keyPressed(KeyEvent e) {
+ if(e.getKeyCode() == KeyEvent.VK_ENTER) {
+ fireActionPerformed(new ActionEvent(TreePopup.this, ActionEvent.ACTION_PERFORMED, ACTION_SELECTED, e.getWhen(), e.getModifiers()));
+ e.consume();
+ return;
+ }
+ if(e.getKeyCode() == KeyEvent.VK_ESCAPE) {
+ fireActionPerformed(new ActionEvent(TreePopup.this, ActionEvent.ACTION_PERFORMED, ACTION_CANCELED, e.getWhen(), e.getModifiers()));
+ }
+ }
+
+ @Override
+ public void keyReleased(KeyEvent e) {
+ if(e.getKeyCode() == KeyEvent.VK_ENTER) {
+ e.consume();
+ }
+ }
+
+ @Override
+ public void mouseClicked(MouseEvent e) {
+ if(e.getButton() == MouseEvent.BUTTON1) {
+ fireActionPerformed(new ActionEvent(TreePopup.this, ActionEvent.ACTION_PERFORMED, ACTION_SELECTED, e.getWhen(), e.getModifiers()));
+ }
+ // ignore
+ }
+
+ @Override
+ public void mousePressed(MouseEvent e) {
+ // ignore
+ }
+
+ @Override
+ public void mouseReleased(MouseEvent e) {
+ // ignore
+ }
+
+ @Override
+ public void mouseEntered(MouseEvent e) {
+ // ignore
+ }
+
+ @Override
+ public void mouseExited(MouseEvent e) {
+ // ignore
+ }
+
+ @Override
+ public void focusGained(FocusEvent e) {
+ // ignore
+ }
+
+ @Override
+ public void focusLost(FocusEvent e) {
+ fireActionPerformed(new ActionEvent(TreePopup.this, ActionEvent.ACTION_PERFORMED, ACTION_CANCELED));
+ }
+ }
+}
diff --git a/src/de/lmu/ifi/dbs/elki/gui/util/package-info.java b/src/de/lmu/ifi/dbs/elki/gui/util/package-info.java
index 706f587a..55f3d259 100644
--- a/src/de/lmu/ifi/dbs/elki/gui/util/package-info.java
+++ b/src/de/lmu/ifi/dbs/elki/gui/util/package-info.java
@@ -5,7 +5,7 @@
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
-Copyright (C) 2013
+Copyright (C) 2014
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team