X-Git-Url: http://source.jalview.org/gitweb/?a=blobdiff_plain;f=src%2Fjalview%2Fgui%2FOptsAndParamsPage.java;h=046eb819f35281049b82c7b7597e9e7347c60a44;hb=71c5a29a58e5505aaf7d63a8c9f1bea3ae93d629;hp=0d12347ee66814afaeedeb07077180477b708843;hpb=e8681d11026ff970970e86acd75ecaa2388c1a7a;p=jalview.git diff --git a/src/jalview/gui/OptsAndParamsPage.java b/src/jalview/gui/OptsAndParamsPage.java index 0d12347..046eb81 100644 --- a/src/jalview/gui/OptsAndParamsPage.java +++ b/src/jalview/gui/OptsAndParamsPage.java @@ -20,20 +20,27 @@ */ package jalview.gui; -import static jalview.ws.params.simple.LogarithmicParameter.LOGSLIDERSCALE; - import jalview.bin.Cache; +import jalview.io.DataSourceType; +import jalview.io.FileLoader; +import jalview.io.JalviewFileChooser; +import jalview.io.JalviewFileView; import jalview.util.MessageManager; +import jalview.ws.jws2.dm.JabaOption; import jalview.ws.params.ArgumentI; import jalview.ws.params.OptionI; import jalview.ws.params.ParameterI; import jalview.ws.params.ValueConstrainI; import jalview.ws.params.ValueConstrainI.ValueType; +import jalview.ws.params.simple.FileParameter; import jalview.ws.params.simple.LogarithmicParameter; +import jalview.ws.params.simple.RadioChoiceParameter; import jalview.ws.params.simple.StringParameter; import java.awt.BorderLayout; +import java.awt.Color; import java.awt.Component; +import java.awt.Container; import java.awt.Dimension; import java.awt.FlowLayout; import java.awt.Font; @@ -42,14 +49,17 @@ import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.KeyAdapter; import java.awt.event.KeyEvent; +import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; +import java.io.File; import java.net.URL; import java.util.ArrayList; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; +import javax.swing.ButtonGroup; import javax.swing.JButton; import javax.swing.JCheckBox; import javax.swing.JComboBox; @@ -58,6 +68,7 @@ import javax.swing.JLabel; import javax.swing.JMenuItem; import javax.swing.JPanel; import javax.swing.JPopupMenu; +import javax.swing.JRadioButton; import javax.swing.JScrollPane; import javax.swing.JSlider; import javax.swing.JTextArea; @@ -103,7 +114,7 @@ public class OptsAndParamsPage public class OptionBox extends JPanel implements MouseListener, ActionListener { - JCheckBox enabled = new JCheckBox(); + JCheckBox enabled; final URL finfo; @@ -115,58 +126,91 @@ public class OptsAndParamsPage OptionI option; - JLabel optlabel = new JLabel(); - - JComboBox val = new JComboBox<>(); + JComboBox val; + /** + * Constructs and adds labels and controls to the panel for one Option + * + * @param opt + */ public OptionBox(OptionI opt) { option = opt; setLayout(new FlowLayout(FlowLayout.LEFT)); - enabled.setSelected(opt.isRequired()); // TODO: lock required options - enabled.setFont(new Font("Verdana", Font.PLAIN, 11)); - enabled.setText(""); - enabled.setText(opt.getName()); - enabled.addActionListener(this); - finfo = option.getFurtherDetails(); - String desc = opt.getDescription(); - if (finfo != null) + enabled = new JCheckBox(opt.getLabel()); + enabled.setSelected(opt.isRequired()); + + /* + * If option is required, show a label, if optional a checkbox + * (but not for Jabaws pending JWS-126 resolution) + */ + if (opt.isRequired() && !(opt instanceof JabaOption)) { - hasLink = true; - - enabled.setToolTipText(JvSwingUtils.wrapTooltip(true, - ((desc == null || desc.trim().length() == 0) - ? MessageManager.getString( - "label.opt_and_params_further_details") - : desc) + "
")); - enabled.addMouseListener(this); + finfo = null; + add(new JLabel(opt.getLabel())); } else { - if (desc != null && desc.trim().length() > 0) - { - enabled.setToolTipText( - JvSwingUtils.wrapTooltip(true, opt.getDescription())); - } - } - add(enabled); - for (String str : opt.getPossibleValues()) - { - val.addItem(str); + finfo = option.getFurtherDetails(); + configureCheckbox(opt); + add(enabled); } + + /* + * construct the choice box with possible values, + * or their display names if provided + */ + val = buildComboBox(opt); val.setSelectedItem(opt.getValue()); + + /* + * only show the choicebox if there is more than one option, + * or the option is mandatory + */ if (opt.getPossibleValues().size() > 1 || opt.isRequired()) { val.addActionListener(this); add(val); } - // TODO: add actionListeners for popup (to open further info), - // and to update list of parameters if an option is enabled - // that takes a value. JBPNote: is this TODO still valid ? + setInitialValue(); } + /** + * Configures the checkbox that controls whether or not the option is + * selected + * + * @param opt + */ + protected void configureCheckbox(OptionI opt) + { + enabled.setFont(new Font("Verdana", Font.PLAIN, 11)); + enabled.addActionListener(this); + final String desc = opt.getDescription(); + if (finfo != null) + { + hasLink = true; + String description = desc; + if (desc == null || desc.trim().isEmpty()) + { + description = MessageManager + .getString("label.opt_and_params_further_details"); + } + description = description + "
"; + String text = JvSwingUtils.wrapTooltip(true, description); + enabled.setToolTipText(text); + enabled.addMouseListener(this); // for popup menu to show link + } + else + { + if (desc != null && desc.trim().length() > 0) + { + enabled.setToolTipText(JvSwingUtils.wrapTooltip(true, desc)); + } + } + } + @Override public void actionPerformed(ActionEvent e) { @@ -201,31 +245,21 @@ public class OptsAndParamsPage poparent.argSetModified(this, !notmod); } - public OptionI getOptionIfEnabled() + /** + * Answers null if the option is not selected, else a new Option holding the + * selected value + * + * @return + */ + public ArgumentI getSelectedOption() { if (!enabled.isSelected()) { return null; } + String value = getSelectedValue(option, val.getSelectedIndex()); OptionI opt = option.copy(); - if (opt.getPossibleValues() != null - && opt.getPossibleValues().size() == 1) - { - // Hack to make sure the default value for an enabled option with only - // one value is actually returned - opt.setValue(opt.getPossibleValues().get(0)); - } - if (val.getSelectedItem() != null) - { - opt.setValue((String) val.getSelectedItem()); - } - else - { - if (option.getValue() != null) - { - opt.setValue(option.getValue()); - } - } + opt.setValue(value); return opt; } @@ -304,7 +338,11 @@ public class OptsAndParamsPage public class ParamBox extends JPanel implements ChangeListener, ActionListener, MouseListener { - private static final float SLIDERSCALE = 1000f; + /* + * parameter values (or their logs) are multiplied by this + * scaling factor to ensure an integer range for the slider + */ + private int sliderScaleFactor = 1; boolean isLogarithmicParameter; @@ -312,9 +350,19 @@ public class OptsAndParamsPage boolean isIntegerParameter; + boolean isStringParameter; + boolean adjusting; - JComboBox choicebox; + /* + * drop-down list of choice options (if applicable) + */ + JComboBox choicebox; + + /* + * radio buttons as an alternative to combo box + */ + ButtonGroup buttonGroup; JPanel controlsPanel = new JPanel(); @@ -349,19 +397,40 @@ public class OptsAndParamsPage finfo = parm.getFurtherDetails(); validator = parm.getValidValue(); parameter = parm; + + isLogarithmicParameter = parm instanceof LogarithmicParameter; + if (validator != null) { - isIntegerParameter = validator.getType() == ValueType.Integer; - } - else if (parameter.getPossibleValues() != null) - { - isChoiceParameter = true; - } - if (parm instanceof LogarithmicParameter) - { - isLogarithmicParameter = true; + ValueType type = validator.getType(); + isIntegerParameter = type == ValueType.Integer; + isStringParameter = type == ValueType.String + || type == ValueType.File; + + /* + * ensure slider has an integer range corresponding to + * the min-max range of the parameter + */ + if (validator.getMin() != null && validator.getMax() != null + // && !isIntegerParameter + && !isStringParameter) + { + double min = validator.getMin().doubleValue(); + double max = validator.getMax().doubleValue(); + if (isLogarithmicParameter) + { + min = Math.log(min); + max = Math.log(max); + } + sliderScaleFactor = (int) (1000000 / (max - min)); + // todo scaleMin, scaleMax could also be final fields + } } + List possibleValues = parameter.getPossibleValues(); + isChoiceParameter = possibleValues != null + && !possibleValues.isEmpty(); + if (compact) { addCompactParameter(parm); @@ -513,10 +582,6 @@ public class OptsAndParamsPage { return; } - if (!isChoiceParameter) - { - updateSliderFromValueField(); - } checkIfModified(); } @@ -550,17 +615,30 @@ public class OptsAndParamsPage return Component.BaselineResizeBehavior.CONSTANT_ASCENT; } - public ParameterI getParameter() + /** + * Answers an argument holding the value entered or selected in the dialog + * + * @return + */ + public ArgumentI getParameter() { ParameterI prm = parameter.copy(); - if (isChoiceParameter) + String value = null; + if (parameter instanceof RadioChoiceParameter) { - prm.setValue((String) choicebox.getSelectedItem()); + value = buttonGroup.getSelection().getActionCommand(); + } + else if (isChoiceParameter) + { + value = getSelectedValue(this.parameter, + choicebox.getSelectedIndex()); } else { - prm.setValue(valueField.getText()); + value = valueField.getText(); } + prm.setValue(value); + return prm; } @@ -582,15 +660,11 @@ public class OptsAndParamsPage @Override public void mouseEntered(MouseEvent e) { - // TODO Auto-generated method stub - } @Override public void mouseExited(MouseEvent e) { - // TODO Auto-generated method stub - } @Override @@ -605,32 +679,39 @@ public class OptsAndParamsPage @Override public void mouseReleased(MouseEvent e) { - // TODO Auto-generated method stub - } @Override public void stateChanged(ChangeEvent e) { - if (!adjusting) + if (adjusting) + { + return; + } + try { + adjusting = true; if (!isLogarithmicParameter) { /* * set (int or float formatted) text field value */ - valueField.setText(isIntegerParameter ? String.valueOf(slider.getValue()) - : String.valueOf(slider.getValue() / SLIDERSCALE)); + valueField.setText(isIntegerParameter + ? String.valueOf(slider.getValue()) + : formatDouble( + slider.getValue() / (float) sliderScaleFactor)); } else { - double base = ((LogarithmicParameter) parameter).getBase(); - double value = Math.pow(base, slider.getValue() / LOGSLIDERSCALE); + double value = Math.pow(Math.E, + slider.getValue() / (double) sliderScaleFactor); valueField.setText(formatDouble(value)); } checkIfModified(); + } finally + { + adjusting = false; } - } /** @@ -642,19 +723,36 @@ public class OptsAndParamsPage */ String formatDouble(double value) { - String format = value < 0.001 ? "%3.3e" : "%3.3f"; + String format = value < 0.001 ? "%3.1E" : "%3.3f"; return String.format(format, value); } + /** + * Formats a number as integer or float (3dp) or scientific notation (1dp) + * + * @param n + * @return + */ + String formatNumber(Number n) + { + return n instanceof Integer ? String.valueOf(n.intValue()) + : formatDouble(n.doubleValue()); + } + void updateControls(ParameterI parm) { adjusting = true; - boolean init = (choicebox == null && valueField == null); + boolean init = (choicebox == null && valueField == null + && buttonGroup == null); if (init) { - if (isChoiceParameter) + if (parm instanceof RadioChoiceParameter) { - choicebox = new JComboBox<>(); + buttonGroup = addRadioButtons(parameter, controlsPanel); + } + else if (isChoiceParameter) + { + choicebox = buildComboBox(parm); choicebox.addActionListener(this); controlsPanel.add(choicebox, BorderLayout.CENTER); } @@ -670,7 +768,9 @@ public class OptsAndParamsPage @Override public void keyReleased(KeyEvent e) { - if (e.isActionKey()) + int keyCode = e.getKeyCode(); + if (e.isActionKey() && keyCode != KeyEvent.VK_LEFT + && keyCode != KeyEvent.VK_RIGHT) { if (valueField.getText().trim().length() > 0) { @@ -679,43 +779,57 @@ public class OptsAndParamsPage } } }); - valueField.setPreferredSize(new Dimension(60, 25)); + valueField.setPreferredSize(new Dimension(65, 25)); + if (parm instanceof FileParameter) + { + valueField.setToolTipText(MessageManager + .getString("label.double_click_to_browse")); + valueField.addMouseListener(new MouseAdapter() + { + @Override + public void mouseClicked(MouseEvent e) + { + if (e.getClickCount() == 2) + { + String dir = Cache.getProperty("LAST_DIRECTORY"); + JalviewFileChooser chooser = new JalviewFileChooser(dir); + chooser.setFileView(new JalviewFileView()); + chooser.setDialogTitle( + MessageManager.getString("action.select_ddbb")); + + int val = chooser.showOpenDialog(ParamBox.this); + if (val == JalviewFileChooser.APPROVE_OPTION) + { + File choice = chooser.getSelectedFile(); + String path = choice.getPath(); + valueField.setText(path); + Cache.setProperty("LAST_DIRECTORY", choice.getParent()); + FileLoader.updateRecentlyOpened(path, + DataSourceType.FILE); + } + } + } + }); + } + controlsPanel.add(slider, BorderLayout.WEST); controlsPanel.add(valueField, BorderLayout.EAST); } } - if (parm != null) + String value = parm.getValue(); + if (value != null) { if (isChoiceParameter) { - if (init) - { - for (String val : parm.getPossibleValues()) - { - choicebox.addItem(val); - } - } - - if (parm.getValue() != null) + if (!(parm instanceof RadioChoiceParameter)) { - choicebox.setSelectedItem(parm.getValue()); + choicebox.setSelectedItem(value); } } else { - if (parm instanceof LogarithmicParameter) - { - double base = ((LogarithmicParameter) parm).getBase(); - // double value = Math.pow(base, - // Double.parseDouble(parm.getValue()) / LOGSLIDERSCALE); - double value = Double.parseDouble(parm.getValue()); - valueField.setText(formatDouble(value)); - } - else - { - valueField.setText(parm.getValue()); - } + valueField.setText(value); } } lastVal = updateSliderFromValueField(); @@ -723,10 +837,43 @@ public class OptsAndParamsPage } /** + * Adds a panel to comp, containing a label and radio buttons for the choice + * of values of the given option. Returns a ButtonGroup whose members are + * the added radio buttons. + * + * @param option + * @param comp + * + * @return + */ + protected ButtonGroup addRadioButtons(OptionI option, Container comp) + { + ButtonGroup bg = new ButtonGroup(); + JPanel radioPanel = new JPanel(); + radioPanel.add(new JLabel(option.getDescription())); + + String value = option.getValue(); + + for (String opt : option.getPossibleValues()) + { + JRadioButton btn = new JRadioButton(opt); + btn.setActionCommand(opt); + boolean selected = opt.equals(value); + btn.setSelected(selected); + btn.addActionListener(this); + bg.add(btn); + radioPanel.add(btn); + } + comp.add(radioPanel); + + return bg; + } + + /** * Action depends on the type of the input parameter: *
    *
  • if a text input, returns the trimmed value
  • - *
  • if a choice list, returns the selected value
  • + *
  • if a choice list or radio button, returns the selected value
  • *
  • if a value slider and input field, sets the value of the slider from * the value in the text field, limiting it to any defined min-max * range.
  • @@ -738,45 +885,65 @@ public class OptsAndParamsPage */ Object updateSliderFromValueField() { - if (validator == null) + if (validator == null || isStringParameter) { - if (!isChoiceParameter) + if (isChoiceParameter) { - slider.setVisible(false); - return valueField.getText().trim(); + if (parameter instanceof RadioChoiceParameter) + { + return buttonGroup.getSelection().getActionCommand(); + } + else + { + return getSelectedValue(this.parameter, + choicebox.getSelectedIndex()); + } } - else + slider.setVisible(false); + return valueField.getText().trim(); + } + + if (validator.getMin() == null || validator.getMax() == null) + { + slider.setVisible(false); + } + + valueField.setText(valueField.getText().trim()); + + /* + * ensure not outside min-max range + * TODO: provide some visual indicator if limit reached + */ + try + { + valueField.setBackground(Color.WHITE); + double d = Double.parseDouble(valueField.getText()); + if (validator.getMin() != null + && validator.getMin().doubleValue() > d) + { + valueField.setText(formatNumber(validator.getMin())); + } + if (validator.getMax() != null + && validator.getMax().doubleValue() < d) { - return choicebox.getSelectedItem(); + valueField.setText(formatNumber(validator.getMax())); } + } catch (NumberFormatException e) + { + valueField.setBackground(Color.yellow); + return Float.NaN; } + if (isIntegerParameter) { int iVal = 0; try { - valueField.setText(valueField.getText().trim()); iVal = Integer.valueOf(valueField.getText()); - - /* - * ensure not outside min-max range - * TODO: provide some visual indicator if limit reached - */ - if (validator.getMin() != null - && validator.getMin().intValue() > iVal) - { - iVal = validator.getMin().intValue(); - valueField.setText(String.valueOf(iVal)); - } - if (validator.getMax() != null - && validator.getMax().intValue() < iVal) - { - iVal = validator.getMax().intValue(); - valueField.setText(String.valueOf(iVal)); - } } catch (Exception e) { - Cache.log.error(e.getMessage()); + valueField.setBackground(Color.yellow); + return Integer.valueOf(0); } if (validator.getMin() != null && validator.getMax() != null) @@ -789,93 +956,62 @@ public class OptsAndParamsPage { slider.setVisible(false); } - return new Integer(iVal); + return Integer.valueOf(iVal); } - else if (isLogarithmicParameter) + + if (isLogarithmicParameter) { double dVal = 0d; try { - valueField.setText(valueField.getText().trim()); double eValue = Double.valueOf(valueField.getText()); - - dVal = Math.log(eValue) - / Math.log(((LogarithmicParameter) parameter).getBase()) - * LOGSLIDERSCALE; - - /* - * ensure not outside min-max range - * TODO: provide some visual indicator if limit reached - */ - if (validator.getMin() != null - && validator.getMin().doubleValue() > dVal) - { - dVal = validator.getMin().doubleValue(); - valueField.setText(formatDouble(eValue)); - } - if (validator.getMax() != null - && validator.getMax().doubleValue() < dVal) - { - dVal = validator.getMax().doubleValue(); - valueField.setText(formatDouble(eValue)); - } + dVal = Math.log(eValue); } catch (Exception e) { + // shouldn't be possible here + valueField.setBackground(Color.yellow); + return Double.NaN; } - if (validator.getMin() != null && validator.getMax() != null) { - slider.getModel().setRangeProperties((int) (dVal), 1, - (int) (validator.getMin().doubleValue()), - 1 + (int) (validator.getMax().doubleValue()), true); + double scaleMin = Math.log(validator.getMin().doubleValue()) + * sliderScaleFactor; + double scaleMax = Math.log(validator.getMax().doubleValue()) + * sliderScaleFactor; + slider.getModel().setRangeProperties( + (int) (sliderScaleFactor * dVal), 1, + (int) scaleMin, 1 + (int) scaleMax, true); } else { slider.setVisible(false); } - return new Double(dVal); + return Double.valueOf(dVal); + } + + float fVal = 0f; + try + { + fVal = Float.valueOf(valueField.getText()); + } catch (Exception e) + { + return Float.valueOf(0f); // shouldn't happen + } + if (validator.getMin() != null && validator.getMax() != null) + { + float scaleMin = validator.getMin().floatValue() + * sliderScaleFactor; + float scaleMax = validator.getMax().floatValue() + * sliderScaleFactor; + slider.getModel().setRangeProperties( + (int) (fVal * sliderScaleFactor), 1, (int) scaleMin, + 1 + (int) scaleMax, true); } else { - float fVal = 0f; - try - { - valueField.setText(valueField.getText().trim()); - fVal = Float.valueOf(valueField.getText()); - - /* - * ensure not outside min-max range - * TODO: provide some visual indicator if limit reached - */ - if (validator.getMin() != null - && validator.getMin().floatValue() > fVal) - { - fVal = validator.getMin().floatValue(); - valueField.setText(String.valueOf(fVal)); - } - if (validator.getMax() != null - && validator.getMax().floatValue() < fVal) - { - fVal = validator.getMax().floatValue(); - valueField.setText(String.valueOf(fVal)); - } - } catch (Exception e) - { - } - - if (validator.getMin() != null && validator.getMax() != null) - { - slider.getModel().setRangeProperties((int) (fVal * SLIDERSCALE), - 1, (int) (validator.getMin().floatValue() * SLIDERSCALE), - 1 + (int) (validator.getMax().floatValue() * SLIDERSCALE), - true); - } - else - { - slider.setVisible(false); - } - return new Float(fVal); + slider.setVisible(false); } + return Float.valueOf(fVal); } } @@ -1005,7 +1141,9 @@ public class OptsAndParamsPage } /** - * recover options and parameters from GUI + * Answers a list of arguments representing all the options and arguments + * selected on the dialog, holding their chosen or input values. Optional + * parameters which were not selected are not included. * * @return */ @@ -1014,7 +1152,7 @@ public class OptsAndParamsPage List argSet = new ArrayList<>(); for (OptionBox opts : getOptSet().values()) { - OptionI opt = opts.getOptionIfEnabled(); + ArgumentI opt = opts.getSelectedOption(); if (opt != null) { argSet.add(opt); @@ -1022,7 +1160,7 @@ public class OptsAndParamsPage } for (ParamBox parambox : getParamSet().values()) { - ParameterI parm = parambox.getParameter(); + ArgumentI parm = parambox.getParameter(); if (parm != null) { argSet.add(parm); @@ -1031,4 +1169,58 @@ public class OptsAndParamsPage return argSet; } + + /** + * A helper method that constructs and returns a CombBox for choice of the + * possible option values. If display names are provided, then these are added + * as options, otherwise the actual values are added. + * + * @param opt + * @return + */ + protected static JComboBox buildComboBox(OptionI opt) + { + JComboBox cb = null; + List displayNames = opt.getDisplayNames(); + if (displayNames != null) + { + List displayNamesObjects = new ArrayList<>(); + displayNamesObjects.addAll(displayNames); + cb = JvSwingUtils.buildComboWithTooltips(displayNamesObjects, + opt.getPossibleValues()); + } + else + { + cb = new JComboBox<>(); + for (String v : opt.getPossibleValues()) + { + cb.addItem(v); + } + } + return cb; + } + + /** + * Answers the value corresponding to the selected item in the choice combo + * box. Note that this returns the underlying value even if a different + * display name is used in the combo box. + * + * @return + */ + protected static String getSelectedValue(OptionI opt, int sel) + { + List possibleValues = opt.getPossibleValues(); + String value = null; + if (possibleValues != null && possibleValues.size() == 1) + { + // Hack to make sure the default value for an enabled option with only + // one value is actually returned even if this.val is not displayed + value = possibleValues.get(0); + } + else if (sel >= 0 && sel < possibleValues.size()) + { + value = possibleValues.get(sel); + } + return value; + } }