Package de.lmu.ifi.dbs.elki.gui.minigui

Source Code of de.lmu.ifi.dbs.elki.gui.minigui.MiniGUI$SettingsComboboxModel

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) 2011
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.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.BitSet;
import java.util.List;
import java.util.logging.Level;

import javax.swing.AbstractListModel;
import javax.swing.BoxLayout;
import javax.swing.ComboBoxModel;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.SwingWorker;
import javax.swing.UIManager;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;

import de.lmu.ifi.dbs.elki.KDDTask;
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.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.parameterization.SerializedParameterization;
import de.lmu.ifi.dbs.elki.utilities.optionhandling.parameterization.TrackParameters;
import de.lmu.ifi.dbs.elki.workflow.LoggingStep;
import de.lmu.ifi.dbs.elki.workflow.OutputStep;

/**
* Minimal GUI built around a table-based parameter editor.
*
* @author Erich Schubert
*
* @apiviz.composedOf SettingsComboboxModel
* @apiviz.composedOf LoggingStep
* @apiviz.owns de.lmu.ifi.dbs.elki.gui.util.ParameterTable
* @apiviz.owns de.lmu.ifi.dbs.elki.gui.util.DynamicParameters
*/
public class MiniGUI extends JPanel {
  /**
   * Serial version
   */
  private static final long serialVersionUID = 1L;

  /**
   * Filename for saved settings
   */
  public static final String SAVED_SETTINGS_FILENAME = "MiniGUI-saved-settings.txt";

  /**
   * Newline used in output.
   */
  public static final String NEWLINE = System.getProperty("line.separator");

  /**
   * ELKI logger for the GUI
   */
  protected static final Logging logger = Logging.getLogger(MiniGUI.class);

  /**
   * Logging output area.
   */
  protected LogPanel outputArea;

  /**
   * The parameter table
   */
  protected ParameterTable parameterTable;

  /**
   * Parameter storage
   */
  protected DynamicParameters parameters;

  /**
   * Settings storage
   */
  protected SavedSettingsFile store = new SavedSettingsFile(SAVED_SETTINGS_FILENAME);

  /**
   * Combo box for saved settings
   */
  protected JComboBox savedCombo;

  /**
   * Model to link the combobox with
   */
  protected SettingsComboboxModel savedSettingsModel;

  /**
   * The "run" button.
   */
  protected JButton runButton;

  /**
   * Constructor
   */
  public MiniGUI() {
    super();
    this.setLayout(new GridBagLayout());

    {
      // Button panel
      JPanel buttonPanel = new JPanel();
      buttonPanel.setLayout(new BoxLayout(buttonPanel, BoxLayout.X_AXIS));

      // Combo box for saved settings
      savedSettingsModel = new SettingsComboboxModel(store);
      savedCombo = new JComboBox(savedSettingsModel);
      savedCombo.setEditable(true);
      savedCombo.setSelectedItem("[Saved Settings]");
      buttonPanel.add(savedCombo);

      // button to load settings
      JButton loadButton = new JButton("Load");
      loadButton.setMnemonic(KeyEvent.VK_L);
      loadButton.addActionListener(new ActionListener() {
        @Override
        public void actionPerformed(ActionEvent e) {
          String key = savedSettingsModel.getSelectedItem();
          ArrayList<String> settings = store.get(key);
          if(settings != null) {
            outputArea.clear();
            outputArea.publish("Parameters: " + FormatUtil.format(settings, " ") + NEWLINE, Level.INFO);
            doSetParameters(settings);
          }
        }
      });
      buttonPanel.add(loadButton);
      // button to save settings
      JButton saveButton = new JButton("Save");
      saveButton.setMnemonic(KeyEvent.VK_S);
      saveButton.addActionListener(new ActionListener() {
        @Override
        public void actionPerformed(ActionEvent e) {
          String key = savedSettingsModel.getSelectedItem();
          // Stop editing the table.
          parameterTable.editCellAt(-1, -1);
          store.put(key, parameters.serializeParameters());
          try {
            store.save();
          }
          catch(IOException e1) {
            logger.exception(e1);
          }
          savedSettingsModel.update();
        }
      });
      buttonPanel.add(saveButton);
      // button to remove saved settings
      JButton removeButton = new JButton("Remove");
      removeButton.setMnemonic(KeyEvent.VK_E);
      removeButton.addActionListener(new ActionListener() {
        @Override
        public void actionPerformed(ActionEvent e) {
          String key = savedSettingsModel.getSelectedItem();
          store.remove(key);
          try {
            store.save();
          }
          catch(IOException e1) {
            logger.exception(e1);
          }
          savedCombo.setSelectedItem("[Saved Settings]");
          savedSettingsModel.update();
        }
      });
      buttonPanel.add(removeButton);

      // 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) {
          startTask();
        }
      });
      buttonPanel.add(runButton);

      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);
    }

    {
      // Setup parameter storage and table model
      this.parameters = new DynamicParameters();
      ParametersModel parameterModel = new ParametersModel(parameters);
      parameterModel.addTableModelListener(new TableModelListener() {
        @Override
        public void tableChanged(TableModelEvent e) {
          // logger.debug("Change event.");
          updateParameterTable();
        }
      });

      // Create parameter table
      parameterTable = new ParameterTable(parameterModel, parameters);
      // 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;
      add(scrollPane, constraints);
    }

    {
      // setup text output area
      outputArea = new LogPanel();

      // Create the scroll pane and add the table to it.
      JScrollPane outputPane = new JScrollPane(outputArea);
      outputPane.setPreferredSize(new Dimension(800, 400));

      // Add the output pane to the bottom
      GridBagConstraints constraints = new GridBagConstraints();
      constraints.fill = GridBagConstraints.BOTH;
      constraints.gridx = 0;
      constraints.gridy = 2;
      constraints.weightx = 1;
      constraints.weighty = 1;
      add(outputPane, constraints);

      // reconfigure logging
      outputArea.becomeDefaultLogger();
    }

    // refresh Parameters
    ArrayList<String> ps = new ArrayList<String>();
    doSetParameters(ps);

    // load saved settings (we wanted to have the logger first!)
    try {
      store.load();
      savedSettingsModel.update();
    }
    catch(FileNotFoundException e) {
      // Ignore - probably didn't save any settings yet.
    }
    catch(IOException e) {
      logger.exception(e);
    }

  }

  /**
   * Serialize the parameter table and run setParameters()
   */
  protected void updateParameterTable() {
    parameterTable.setEnabled(false);
    ArrayList<String> params = parameters.serializeParameters();
    outputArea.clear();
    outputArea.publish("Parameters: " + FormatUtil.format(params, " ") + NEWLINE, Level.INFO);
    doSetParameters(params);
    parameterTable.setEnabled(true);
  }

  /**
   * Do the actual setParameters invocation.
   *
   * @param params Parameters
   */
  protected void doSetParameters(List<String> params) {
    SerializedParameterization config = new SerializedParameterization(params);
    TrackParameters track = new TrackParameters(config);
    track.tryInstantiate(LoggingStep.class);
    track.tryInstantiate(KDDTask.class);
    config.logUnusedParameters();
    // config.logAndClearReportedErrors();
    if(config.getErrors().size() > 0) {
      reportErrors(config);
      runButton.setEnabled(false);
    }
    else {
      runButton.setEnabled(true);
    }

    List<String> remainingParameters = config.getRemainingParameters();

    // update table:
    parameterTable.setEnabled(false);
    parameters.updateFromTrackParameters(track);
    // Add remaining parameters
    if(remainingParameters != null && !remainingParameters.isEmpty()) {
      DynamicParameters.RemainingOptions remo = new DynamicParameters.RemainingOptions();
      try {
        remo.setValue(FormatUtil.format(remainingParameters, " "));
      }
      catch(ParameterException e) {
        logger.exception(e);
      }
      BitSet bits = new BitSet();
      bits.set(DynamicParameters.BIT_INVALID);
      bits.set(DynamicParameters.BIT_SYNTAX_ERROR);
      parameters.addParameter(remo, remo.getValue(), bits, 0);
    }

    parameterTable.revalidate();
    parameterTable.setEnabled(true);
  }

  /**
   * Do a full run of the KDDTask with the specified parameters.
   */
  protected void startTask() {
    parameterTable.editCellAt(-1, -1);
    parameterTable.setEnabled(false);
    final ArrayList<String> params = parameters.serializeParameters();
    parameterTable.setEnabled(true);

    runButton.setEnabled(false);

    outputArea.clear();
    outputArea.publish("Running: " + FormatUtil.format(params, " ") + NEWLINE, Level.INFO);

    SwingWorker<Void, Void> r = new SwingWorker<Void, Void>() {
      @Override
      public Void doInBackground() {
        SerializedParameterization config = new SerializedParameterization(params);
        config.tryInstantiate(LoggingStep.class);
        KDDTask task = config.tryInstantiate(KDDTask.class);
        try {
          config.logUnusedParameters();
          if(config.getErrors().size() == 0) {
            task.run();
          }
          else {
            reportErrors(config);
          }
        }
        catch(Exception e) {
          logger.exception(e);
        }
        return null;
      }

      @Override
      protected void done() {
        super.done();
        runButton.setEnabled(true);
      }
    };
    r.execute();
  }

  /**
   * Report errors in a single error log record.
   *
   * @param config Parameterization
   */
  protected void reportErrors(SerializedParameterization config) {
    StringBuffer buf = new StringBuffer();
    buf.append("Could not run task because of configuration errors:" + NEWLINE + NEWLINE);
    for(ParameterException e : config.getErrors()) {
      buf.append(e.getMessage() + NEWLINE);
    }
    logger.warning(buf.toString());
    config.clearErrors();
  }

  /**
   * Create the GUI and show it. For thread safety, this method should be
   * invoked from the event-dispatching thread.
   *
   * args Command line arguments
   */
  protected static void createAndShowGUI(String[] args) {
    // Create and set up the window.
    JFrame frame = new JFrame("ELKI MiniGUI");
    frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
    try {
      UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
      // Class<?> cls =
      // ClassLoader.getSystemClassLoader().loadClass("org.jdesktop.swinghelper.debug.CheckThreadViolationRepaintManager");
      // RepaintManager.setCurrentManager((RepaintManager) cls.newInstance());
    }
    catch(Exception e) {
      // ignore
    }
    try {
      frame.setIconImage(new ImageIcon(KDDTask.class.getResource("elki-icon.png")).getImage());
    }
    catch(Exception e) {
      // Ignore - icon not found is not fatal.
    }

    // Create and set up the content pane.
    MiniGUI newContentPane = new MiniGUI();
    if (args != null && args.length > 0) {
      newContentPane.doSetParameters(Arrays.asList(args));
    }
    newContentPane.setOpaque(true); // content panes must be opaque
    frame.setContentPane(newContentPane);

    // Display the window.
    frame.pack();
    frame.setVisible(true);
  }

  /**
   * Main method that just spawns the UI.
   *
   * @param args command line parameters
   */
  public static void main(final String[] args) {
    OutputStep.setDefaultHandlerVisualizer();
    javax.swing.SwingUtilities.invokeLater(new Runnable() {
      @Override
      public void run() {
        createAndShowGUI(args);
      }
    });
  }

  /**
   * Class to interface between the saved settings list and a JComboBox
   *
   * @author Erich Schubert
   *
   * @apiviz.composedOf de.lmu.ifi.dbs.elki.gui.util.SavedSettingsFile
   */
  class SettingsComboboxModel extends AbstractListModel implements ComboBoxModel {
    /**
     * Serial version
     */
    private static final long serialVersionUID = 1L;

    /**
     * Settings storage
     */
    protected SavedSettingsFile store;

    /**
     * Selected entry
     */
    protected String selected = null;

    /**
     * Constructor
     *
     * @param store Store to access
     */
    public SettingsComboboxModel(SavedSettingsFile store) {
      super();
      this.store = store;
    }

    @Override
    public String getSelectedItem() {
      return selected;
    }

    @Override
    public void setSelectedItem(Object anItem) {
      if(anItem instanceof String) {
        selected = (String) anItem;
      }
    }

    @Override
    public Object getElementAt(int index) {
      return store.getElementAt(index).first;
    }

    @Override
    public int getSize() {
      return store.size();
    }

    /**
     * Force an update
     */
    public void update() {
      fireContentsChanged(this, 0, getSize() + 1);
    }
  }
}
TOP

Related Classes of de.lmu.ifi.dbs.elki.gui.minigui.MiniGUI$SettingsComboboxModel

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.