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 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 . */ import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.KeyEvent; import javax.swing.BoxLayout; import javax.swing.JButton; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import de.lmu.ifi.dbs.elki.gui.configurator.ConfiguratorPanel; import de.lmu.ifi.dbs.elki.logging.Logging; 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.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. * * @author Erich Schubert */ public abstract class ParameterTabPanel extends JPanel implements ChangeListener { /** * Serial version */ private static final long serialVersionUID = 1L; /** * Status code enumeration * * @author Erich Schubert * * @apiviz.exclude */ public enum Status { /** Status to signal the step has been configured properly. */ STATUS_UNCONFIGURED { @Override public String toString() { return "unconfigured"; } }, /** Status to signal the step has been configured properly. */ STATUS_CONFIGURED { @Override public String toString() { return "configured"; } }, /** Status to signal the step is ready to run */ STATUS_READY { @Override public String toString() { return "ready to run"; } }, /** Status to signal the step has been run completely. */ STATUS_COMPLETE { @Override public String toString() { return "complete"; } }, /** Status to signal the step has failed somehow */ STATUS_FAILED { @Override public String toString() { return "failed"; } } } /** * ELKI logger for the GUI */ private static final Logging LOG = Logging.getLogger(ParameterTabPanel.class); /** * The parameter table */ private final ConfiguratorPanel parameterTable; /** * The "run" button. */ private final JButton runButton; /** * The status text field */ private final JLabel statusText; /** * Input pane */ public ParameterTabPanel() { super(); this.setLayout(new GridBagLayout()); { // Button panel JPanel buttonPanel = new JPanel(); buttonPanel.setLayout(new BoxLayout(buttonPanel, BoxLayout.X_AXIS)); // button to launch the task runButton = new JButton("Run Task"); runButton.setMnemonic(KeyEvent.VK_R); runButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { Thread r = new Thread() { @Override public void run() { execute(); } }; r.start(); } }); buttonPanel.add(runButton); // Status text field statusText = new JLabel(); buttonPanel.add(statusText); GridBagConstraints constraints = new GridBagConstraints(); constraints.fill = GridBagConstraints.HORIZONTAL; constraints.gridx = 0; constraints.gridy = 1; constraints.weightx = 1.0; constraints.weighty = 0.01; add(buttonPanel, constraints); } { // Create parameter table parameterTable = new ConfiguratorPanel(); // new // ParameterTable(parameterModel, // parameters); parameterTable.addChangeListener(this); // Create the scroll pane and add the table to it. JScrollPane scrollPane = new JScrollPane(parameterTable); // Add the scroll pane to this panel. GridBagConstraints constraints = new GridBagConstraints(); constraints.fill = GridBagConstraints.BOTH; constraints.gridx = 0; constraints.gridy = 0; constraints.weightx = 1; constraints.weighty = 1; constraints.anchor = GridBagConstraints.NORTH; add(scrollPane, constraints); } } /** * Serialize the parameter table and run setParameters() */ protected void updateParameterTable() { parameterTable.setEnabled(false); ListParameterization config = new ListParameterization(); parameterTable.appendParameters(config); setParameters(config); if (config.getErrors().size() > 0) { reportErrors(config); } config.clearErrors(); parameterTable.setEnabled(true); } /** * Do the actual setParameters invocation. * * @param config Parameterization */ public void setParameters(Parameterization config) { TrackParameters track = new TrackParameters(config); configureStep(track); // update parameter table { parameterTable.setEnabled(false); parameterTable.clear(); for (Pair> pair : track.getAllParameters()) { parameterTable.addParameter(pair.first, pair.getSecond(), track); } // parameters.updateFromTrackParameters(track); parameterTable.revalidate(); parameterTable.setEnabled(true); } // Update status and notify observers updateStatus(); firePanelUpdated(); } /** * Collect parameters * * @param params Parameter list to add to */ public void appendParameters(ListParameterization params) { parameterTable.appendParameters(params); } /** * Report errors in a single error log record. * * @param config Parameterization */ protected void reportErrors(Parameterization config) { StringBuilder buf = new StringBuilder(); for (ParameterException e : config.getErrors()) { if (e instanceof UnspecifiedParameterException) { continue; } buf.append(e.getMessage()).append(FormatUtil.NEWLINE); } if (buf.length() > 0) { LOG.warning("Configuration errors:" + FormatUtil.NEWLINE + FormatUtil.NEWLINE + buf.toString()); } // config.clearErrors(); } /** * Execute the task. */ protected synchronized void execute() { ListParameterization config = new ListParameterization(); parameterTable.appendParameters(config); runButton.setEnabled(false); try { configureStep(config); if (config.hasUnusedParameters()) { // List> remainingParameters = // config.getRemainingParameters(); LOG.warning("Unused parameters: " + "FIXME"); } if (config.getErrors().size() > 0) { reportErrors(config); } else { executeStep(); } } catch (Exception e) { LOG.exception(e); } updateStatus(); firePanelUpdated(); } /** * Configure this step with the given parameters. * * @param config Configuration to use. */ protected abstract void configureStep(Parameterization config); /** * Get the current status of this step. * * @return current status */ protected abstract Status getStatus(); /** * Execute the configured step. */ protected abstract void executeStep(); /** * Test if this tab is ready-to-run * * @return can-run status */ public boolean canRun() { Status status = getStatus(); if (Status.STATUS_READY.equals(status) || Status.STATUS_COMPLETE.equals(status)) { return true; } return false; } /** * Test if this tab is complete * * @return completeness status */ public boolean isComplete() { Status status = getStatus(); if (Status.STATUS_COMPLETE.equals(status)) { return true; } return false; } /** * Invoked to update the UI when the status could have changed. */ protected void updateStatus() { statusText.setText(getStatus().toString()); runButton.setEnabled(canRun()); } protected void firePanelUpdated() { for (ParameterTabPanel p : listenerList.getListeners(ParameterTabPanel.class)) { p.panelUpdated(this); } } public void addPanelListener(ParameterTabPanel o) { listenerList.add(ParameterTabPanel.class, o); } public void removePanelListener(ParameterTabPanel o) { listenerList.remove(ParameterTabPanel.class, o); } @Override public void stateChanged(ChangeEvent e) { if (e.getSource() == this.parameterTable) { // logger.warning("stateChanged!"); updateParameterTable(); } } /** * Called when an observed panel changes. * * @param o Observed panel */ void panelUpdated(ParameterTabPanel o) { // Do nothing by default. }; }