/**
* Copyright (C) 2022 Adrien Hopkins
*
* 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 .
*/
package sevenUnitsGUI;
import java.awt.BorderLayout;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import java.awt.event.ItemEvent;
import java.awt.event.KeyEvent;
import java.util.AbstractSet;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.NoSuchElementException;
import java.util.Objects;
import java.util.Optional;
import java.util.OptionalInt;
import java.util.Set;
import java.util.function.Function;
import javax.swing.BorderFactory;
import javax.swing.BoxLayout;
import javax.swing.ButtonGroup;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import javax.swing.JScrollPane;
import javax.swing.JSlider;
import javax.swing.JTabbedPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.SwingConstants;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.WindowConstants;
import javax.swing.border.EmptyBorder;
import javax.swing.border.TitledBorder;
import sevenUnits.ProgramInfo;
import sevenUnits.unit.UnitType;
import sevenUnits.utils.NameSymbol;
import sevenUnits.utils.UncertainDouble;
/**
* A View that separates its functions into multiple tabs
*
* @since v0.4.0
* @since 2022-02-19
*/
final class TabbedView implements ExpressionConversionView, UnitConversionView {
/**
* A Set-like view of a JComboBox's items
*
* @param type of item in list
*
* @since v0.4.0
* @since 2022-02-19
*/
private static final class JComboBoxItemSet extends AbstractSet {
private final JComboBox comboBox;
/**
* @param comboBox combo box to get items from
* @since 2022-02-19
*/
public JComboBoxItemSet(JComboBox comboBox) {
this.comboBox = comboBox;
}
@Override
public Iterator iterator() {
return new Iterator<>() {
private int index = 0;
@Override
public boolean hasNext() {
return this.index < JComboBoxItemSet.this.size();
}
@Override
public E next() {
if (this.hasNext())
return JComboBoxItemSet.this.comboBox.getItemAt(this.index++);
else
throw new NoSuchElementException(
"Iterator has finished iteration");
}
};
}
@Override
public int size() {
return this.comboBox.getItemCount();
}
}
/**
* The standard types of rounding, corresponding to the options on the
* TabbedView's settings panel.
*
* @since v0.4.0
* @since 2022-04-18
*/
private static enum StandardRoundingType {
/**
* Rounds to a fixed number of significant digits. Precision is used,
* representing the number of significant digits to round to.
*/
SIGNIFICANT_DIGITS,
/**
* Rounds to a fixed number of decimal places. Precision is used,
* representing the number of decimal places to round to.
*/
DECIMAL_PLACES,
/**
* Rounds according to UncertainDouble's toString method. The specified
* precision is ignored.
*/
UNCERTAINTY;
}
/**
* Creates a TabbedView.
*
* @param args command line arguments
* @since v0.4.0
* @since 2022-02-19
*/
public static void main(String[] args) {
// This view doesn't need to do anything, the side effects of creating it
// are enough to start the program
@SuppressWarnings("unused")
final View view = new TabbedView();
}
/** The Presenter that handles this View */
final Presenter presenter;
/** The frame that this view lives on */
final JFrame frame;
/** The tabbed pane that contains all of the components */
final JTabbedPane masterPane;
// DIMENSION-BASED CONVERTER
/** The combo box that selects dimensions */
final JComboBox dimensionSelector;
/** The panel for inputting values in the dimension-based converter */
final JTextField valueInput;
/** The panel for "From" in the dimension-based converter */
final SearchBoxList fromSearch;
/** The panel for "To" in the dimension-based converter */
final SearchBoxList toSearch;
/** The button used for conversion */
final JButton convertUnitButton;
/** The output area in the dimension-based converter */
final JTextArea unitOutput;
// EXPRESSION-BASED CONVERTER
/** The "From" entry in the conversion panel */
final JTextField fromEntry;
/** The "To" entry in the conversion panel */
final JTextField toEntry;
/** The button used for conversion */
final JButton convertExpressionButton;
/** The output area in the conversion panel */
final JTextArea expressionOutput;
// UNIT AND PREFIX VIEWERS
/** The searchable list of unit names in the unit viewer */
private final SearchBoxList unitNameList;
/** The searchable list of prefix names in the prefix viewer */
private final SearchBoxList prefixNameList;
/** The text box for unit data in the unit viewer */
private final JTextArea unitTextBox;
/** The text box for prefix data in the prefix viewer */
private final JTextArea prefixTextBox;
// SETTINGS STUFF
private StandardRoundingType roundingType;
private int precision;
/**
* Creates the view and makes it visible to the user
*
* @since v0.4.0
* @since 2022-02-19
*/
public TabbedView() {
// enable system look and feel
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException
| IllegalAccessException | UnsupportedLookAndFeelException e) {
// oh well, just use default theme
System.err.println("Failed to enable system look-and-feel.");
e.printStackTrace();
}
// initialize important components
this.presenter = new Presenter(this);
this.frame = new JFrame("7Units " + ProgramInfo.VERSION);
this.frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
// master components (those that contain everything else within them)
this.masterPane = new JTabbedPane();
this.frame.add(this.masterPane);
// ============ UNIT CONVERSION TAB ============
final JPanel convertUnitPanel = new JPanel();
this.masterPane.addTab("Convert Units", convertUnitPanel);
this.masterPane.setMnemonicAt(0, KeyEvent.VK_U);
convertUnitPanel.setLayout(new BorderLayout());
{ // panel for input part
final JPanel inputPanel = new JPanel();
convertUnitPanel.add(inputPanel, BorderLayout.CENTER);
inputPanel.setLayout(new GridLayout(1, 3));
inputPanel.setBorder(new EmptyBorder(6, 6, 3, 6));
this.fromSearch = new SearchBoxList<>();
inputPanel.add(this.fromSearch);
final JPanel inBetweenPanel = new JPanel();
inputPanel.add(inBetweenPanel);
inBetweenPanel.setLayout(new BorderLayout());
this.dimensionSelector = new JComboBox<>();
inBetweenPanel.add(this.dimensionSelector, BorderLayout.PAGE_START);
this.dimensionSelector
.addItemListener(e -> this.presenter.updateView());
final JLabel arrowLabel = new JLabel("-->");
inBetweenPanel.add(arrowLabel, BorderLayout.CENTER);
arrowLabel.setHorizontalAlignment(SwingConstants.CENTER);
this.toSearch = new SearchBoxList<>();
inputPanel.add(this.toSearch);
}
{ // panel for submit and output, and also value entry
final JPanel outputPanel = new JPanel();
convertUnitPanel.add(outputPanel, BorderLayout.PAGE_END);
outputPanel.setLayout(new BorderLayout());
outputPanel.setBorder(new EmptyBorder(3, 6, 6, 6));
final JLabel valuePrompt = new JLabel("Value to convert: ");
outputPanel.add(valuePrompt, BorderLayout.LINE_START);
this.valueInput = new JTextField();
outputPanel.add(this.valueInput, BorderLayout.CENTER);
// conversion button
this.convertUnitButton = new JButton("Convert");
outputPanel.add(this.convertUnitButton, BorderLayout.LINE_END);
this.convertUnitButton
.addActionListener(e -> this.presenter.convertUnits());
this.convertUnitButton.setMnemonic(KeyEvent.VK_ENTER);
// conversion output
this.unitOutput = new JTextArea(2, 32);
outputPanel.add(this.unitOutput, BorderLayout.PAGE_END);
this.unitOutput.setEditable(false);
}
// ============ EXPRESSION CONVERSION TAB ============
final JPanel convertExpressionPanel = new JPanel();
this.masterPane.addTab("Convert Unit Expressions",
convertExpressionPanel);
this.masterPane.setMnemonicAt(1, KeyEvent.VK_E);
convertExpressionPanel.setLayout(new GridLayout(4, 1));
// from and to expressions
this.fromEntry = new JTextField();
convertExpressionPanel.add(this.fromEntry);
this.fromEntry.setBorder(BorderFactory.createTitledBorder("From"));
this.toEntry = new JTextField();
convertExpressionPanel.add(this.toEntry);
this.toEntry.setBorder(BorderFactory.createTitledBorder("To"));
// button to convert
this.convertExpressionButton = new JButton("Convert");
convertExpressionPanel.add(this.convertExpressionButton);
this.convertExpressionButton
.addActionListener(e -> this.presenter.convertExpressions());
this.convertExpressionButton.setMnemonic(KeyEvent.VK_ENTER);
// output of conversion
this.expressionOutput = new JTextArea(2, 32);
convertExpressionPanel.add(this.expressionOutput);
this.expressionOutput
.setBorder(BorderFactory.createTitledBorder("Output"));
this.expressionOutput.setEditable(false);
// =========== UNIT VIEWER ===========
final JPanel unitLookupPanel = new JPanel();
this.masterPane.addTab("Unit Viewer", unitLookupPanel);
this.masterPane.setMnemonicAt(2, KeyEvent.VK_V);
unitLookupPanel.setLayout(new GridLayout());
this.unitNameList = new SearchBoxList<>();
unitLookupPanel.add(this.unitNameList);
this.unitNameList.getSearchList()
.addListSelectionListener(e -> this.presenter.unitNameSelected());
// the text box for unit's toString
this.unitTextBox = new JTextArea();
unitLookupPanel.add(this.unitTextBox);
this.unitTextBox.setEditable(false);
this.unitTextBox.setLineWrap(true);
// ============ PREFIX VIEWER =============
final JPanel prefixLookupPanel = new JPanel();
this.masterPane.addTab("Prefix Viewer", prefixLookupPanel);
this.masterPane.setMnemonicAt(3, KeyEvent.VK_P);
prefixLookupPanel.setLayout(new GridLayout(1, 2));
this.prefixNameList = new SearchBoxList<>();
prefixLookupPanel.add(this.prefixNameList);
this.prefixNameList.getSearchList()
.addListSelectionListener(e -> this.presenter.prefixSelected());
// the text box for prefix's toString
this.prefixTextBox = new JTextArea();
prefixLookupPanel.add(this.prefixTextBox);
this.prefixTextBox.setEditable(false);
this.prefixTextBox.setLineWrap(true);
// ============ INFO PANEL ============
final JPanel infoPanel = new JPanel();
this.masterPane.addTab("\uD83D\uDEC8", // info (i) character
new JScrollPane(infoPanel));
final JTextArea infoTextArea = new JTextArea();
infoTextArea.setEditable(false);
infoTextArea.setOpaque(false);
infoPanel.add(infoTextArea);
infoTextArea.setText(this.presenter.getAboutText());
// ============ SETTINGS PANEL ============
this.masterPane.addTab("\u2699",
new JScrollPane(this.createSettingsPanel()));
this.masterPane.setMnemonicAt(5, KeyEvent.VK_S);
// ============ FINALIZE CREATION OF VIEW ============
this.presenter.postViewInitialize();
this.frame.pack();
this.frame.setVisible(true);
}
/**
* Creates and returns the settings panel (in its own function to make this
* code more organized, as this function is massive!)
*
* @since 2022-02-19
*/
private JPanel createSettingsPanel() {
final JPanel settingsPanel = new JPanel();
settingsPanel
.setLayout(new BoxLayout(settingsPanel, BoxLayout.PAGE_AXIS));
// ============ ROUNDING SETTINGS ============
{
final JPanel roundingPanel = new JPanel();
settingsPanel.add(roundingPanel);
roundingPanel.setBorder(new TitledBorder("Rounding Settings"));
roundingPanel.setLayout(new GridBagLayout());
// rounding rule selection
final ButtonGroup roundingRuleButtons = new ButtonGroup();
this.roundingType = this.getPresenterRoundingType()
.orElseThrow(() -> new AssertionError(
"Presenter loaded non-standard rounding rule"));
this.precision = this.getPresenterPrecision().orElse(6);
final JLabel roundingRuleLabel = new JLabel("Rounding Rule:");
roundingPanel.add(roundingRuleLabel, new GridBagBuilder(0, 0)
.setAnchor(GridBagConstraints.LINE_START).build());
// sigDigSlider needs to be first so that the rounding-type buttons can
// show and hide it
final JLabel sliderLabel = new JLabel("Precision:");
sliderLabel.setVisible(
this.roundingType != StandardRoundingType.UNCERTAINTY);
roundingPanel.add(sliderLabel, new GridBagBuilder(0, 4)
.setAnchor(GridBagConstraints.LINE_START).build());
final JSlider sigDigSlider = new JSlider(0, 12);
roundingPanel.add(sigDigSlider, new GridBagBuilder(0, 5)
.setAnchor(GridBagConstraints.LINE_START).build());
sigDigSlider.setMajorTickSpacing(4);
sigDigSlider.setMinorTickSpacing(1);
sigDigSlider.setSnapToTicks(true);
sigDigSlider.setPaintTicks(true);
sigDigSlider.setPaintLabels(true);
sigDigSlider.setVisible(
this.roundingType != StandardRoundingType.UNCERTAINTY);
sigDigSlider.setValue(this.precision);
sigDigSlider.addChangeListener(e -> {
this.precision = sigDigSlider.getValue();
this.updatePresenterRoundingRule();
});
// significant digit rounding
final JRadioButton fixedPrecision = new JRadioButton(
"Fixed Precision");
if (this.roundingType == StandardRoundingType.SIGNIFICANT_DIGITS) {
fixedPrecision.setSelected(true);
}
fixedPrecision.addActionListener(e -> {
this.roundingType = StandardRoundingType.SIGNIFICANT_DIGITS;
sliderLabel.setVisible(true);
sigDigSlider.setVisible(true);
this.updatePresenterRoundingRule();
});
roundingRuleButtons.add(fixedPrecision);
roundingPanel.add(fixedPrecision, new GridBagBuilder(0, 1)
.setAnchor(GridBagConstraints.LINE_START).build());
// decimal place rounding
final JRadioButton fixedDecimals = new JRadioButton(
"Fixed Decimal Places");
if (this.roundingType == StandardRoundingType.DECIMAL_PLACES) {
fixedDecimals.setSelected(true);
}
fixedDecimals.addActionListener(e -> {
this.roundingType = StandardRoundingType.DECIMAL_PLACES;
sliderLabel.setVisible(true);
sigDigSlider.setVisible(true);
this.updatePresenterRoundingRule();
});
roundingRuleButtons.add(fixedDecimals);
roundingPanel.add(fixedDecimals, new GridBagBuilder(0, 2)
.setAnchor(GridBagConstraints.LINE_START).build());
// scientific rounding
final JRadioButton relativePrecision = new JRadioButton(
"Uncertainty-Based Rounding");
if (this.roundingType == StandardRoundingType.UNCERTAINTY) {
relativePrecision.setSelected(true);
}
relativePrecision.addActionListener(e -> {
this.roundingType = StandardRoundingType.UNCERTAINTY;
sliderLabel.setVisible(false);
sigDigSlider.setVisible(false);
this.updatePresenterRoundingRule();
});
roundingRuleButtons.add(relativePrecision);
roundingPanel.add(relativePrecision, new GridBagBuilder(0, 3)
.setAnchor(GridBagConstraints.LINE_START).build());
}
// ============ PREFIX REPETITION SETTINGS ============
{
final JPanel prefixRepetitionPanel = new JPanel();
settingsPanel.add(prefixRepetitionPanel);
prefixRepetitionPanel
.setBorder(new TitledBorder("Prefix Repetition Settings"));
prefixRepetitionPanel.setLayout(new GridBagLayout());
final var prefixRule = this.getPresenterPrefixRule()
.orElseThrow(() -> new AssertionError(
"Presenter loaded non-standard prefix rule"));
// prefix rules
final ButtonGroup prefixRuleButtons = new ButtonGroup();
final JRadioButton noRepetition = new JRadioButton("No Repetition");
if (prefixRule == DefaultPrefixRepetitionRule.NO_REPETITION) {
noRepetition.setSelected(true);
}
noRepetition.addActionListener(e -> {
this.presenter.setPrefixRepetitionRule(
DefaultPrefixRepetitionRule.NO_REPETITION);
this.presenter.saveSettings();
});
prefixRuleButtons.add(noRepetition);
prefixRepetitionPanel.add(noRepetition, new GridBagBuilder(0, 0)
.setAnchor(GridBagConstraints.LINE_START).build());
final JRadioButton noRestriction = new JRadioButton("No Restriction");
if (prefixRule == DefaultPrefixRepetitionRule.NO_RESTRICTION) {
noRestriction.setSelected(true);
}
noRestriction.addActionListener(e -> {
this.presenter.setPrefixRepetitionRule(
DefaultPrefixRepetitionRule.NO_RESTRICTION);
this.presenter.saveSettings();
});
prefixRuleButtons.add(noRestriction);
prefixRepetitionPanel.add(noRestriction, new GridBagBuilder(0, 1)
.setAnchor(GridBagConstraints.LINE_START).build());
final JRadioButton customRepetition = new JRadioButton(
"Complex Repetition");
if (prefixRule == DefaultPrefixRepetitionRule.COMPLEX_REPETITION) {
customRepetition.setSelected(true);
}
customRepetition.addActionListener(e -> {
this.presenter.setPrefixRepetitionRule(
DefaultPrefixRepetitionRule.COMPLEX_REPETITION);
this.presenter.saveSettings();
});
prefixRuleButtons.add(customRepetition);
prefixRepetitionPanel.add(customRepetition, new GridBagBuilder(0, 2)
.setAnchor(GridBagConstraints.LINE_START).build());
}
// ============ SEARCH SETTINGS ============
{
final JPanel searchingPanel = new JPanel();
settingsPanel.add(searchingPanel);
searchingPanel.setBorder(new TitledBorder("Search Settings"));
searchingPanel.setLayout(new GridBagLayout());
// searching rules
final ButtonGroup searchRuleButtons = new ButtonGroup();
final var searchRule = this.presenter.getSearchRule();
final JRadioButton noPrefixes = new JRadioButton(
"Never Include Prefixed Units");
noPrefixes.addActionListener(e -> {
this.presenter.setSearchRule(PrefixSearchRule.NO_PREFIXES);
this.presenter.updateView();
this.presenter.saveSettings();
});
searchRuleButtons.add(noPrefixes);
searchingPanel.add(noPrefixes, new GridBagBuilder(0, 0)
.setAnchor(GridBagConstraints.LINE_START).build());
final JRadioButton commonPrefixes = new JRadioButton(
"Include Common Prefixes");
commonPrefixes.addActionListener(e -> {
this.presenter.setSearchRule(PrefixSearchRule.COMMON_PREFIXES);
this.presenter.updateView();
this.presenter.saveSettings();
});
searchRuleButtons.add(commonPrefixes);
searchingPanel.add(commonPrefixes, new GridBagBuilder(0, 1)
.setAnchor(GridBagConstraints.LINE_START).build());
final JRadioButton alwaysInclude = new JRadioButton(
"Include All Single Prefixes");
alwaysInclude.addActionListener(e -> {
this.presenter
.setSearchRule(this.presenter.getUniversalSearchRule());
this.presenter.updateView();
this.presenter.saveSettings();
});
searchRuleButtons.add(alwaysInclude);
searchingPanel.add(alwaysInclude, new GridBagBuilder(0, 3)
.setAnchor(GridBagConstraints.LINE_START).build());
if (PrefixSearchRule.NO_PREFIXES.equals(searchRule)) {
noPrefixes.setSelected(true);
} else if (PrefixSearchRule.COMMON_PREFIXES.equals(searchRule)) {
commonPrefixes.setSelected(true);
} else {
alwaysInclude.setSelected(true);
this.presenter
.setSearchRule(this.presenter.getUniversalSearchRule());
this.presenter.saveSettings();
}
}
// ============ OTHER SETTINGS ============
{
final JPanel miscPanel = new JPanel();
settingsPanel.add(miscPanel);
miscPanel.setLayout(new GridBagLayout());
final JCheckBox oneWay = new JCheckBox("Convert One Way Only");
oneWay.setSelected(this.presenter.oneWayConversionEnabled());
oneWay.addItemListener(e -> {
this.presenter.setOneWayConversionEnabled(
e.getStateChange() == ItemEvent.SELECTED);
this.presenter.saveSettings();
});
miscPanel.add(oneWay, new GridBagBuilder(0, 0)
.setAnchor(GridBagConstraints.LINE_START).build());
final JCheckBox showAllVariations = new JCheckBox(
"Show Duplicate Units & Prefixes");
showAllVariations.setSelected(this.presenter.duplicatesShown());
showAllVariations.addItemListener(e -> {
this.presenter
.setShowDuplicates(e.getStateChange() == ItemEvent.SELECTED);
this.presenter.saveSettings();
});
miscPanel.add(showAllVariations, new GridBagBuilder(0, 1)
.setAnchor(GridBagConstraints.LINE_START).build());
final JButton unitFileButton = new JButton("Manage Unit Data Files");
unitFileButton.setEnabled(false);
miscPanel.add(unitFileButton, new GridBagBuilder(0, 2)
.setAnchor(GridBagConstraints.LINE_START).build());
}
return settingsPanel;
}
@Override
public Set getDimensionNames() {
return Collections
.unmodifiableSet(new JComboBoxItemSet<>(this.dimensionSelector));
}
@Override
public String getFromExpression() {
return this.fromEntry.getText();
}
@Override
public Optional getFromSelection() {
return this.fromSearch.getSelectedValue();
}
@Override
public Set getFromUnitNames() {
// this should work because the only way I can mutate the item list is
// with setFromUnits which only accepts a Set
return new HashSet<>(this.fromSearch.getItems());
}
@Override
public String getInputValue() {
return this.valueInput.getText();
}
@Override
public Presenter getPresenter() {
return this.presenter;
}
/**
* @return the precision of the presenter's rounding rule, if that is
* meaningful
* @since v0.4.0
* @since 2022-04-18
*/
private OptionalInt getPresenterPrecision() {
final var presenterRule = this.presenter.getNumberDisplayRule();
if (presenterRule instanceof StandardDisplayRules.FixedDecimals)
return OptionalInt
.of(((StandardDisplayRules.FixedDecimals) presenterRule)
.decimalPlaces());
else if (presenterRule instanceof StandardDisplayRules.FixedPrecision)
return OptionalInt
.of(((StandardDisplayRules.FixedPrecision) presenterRule)
.significantFigures());
else
return OptionalInt.empty();
}
/**
* @return presenter's prefix repetition rule
* @since v0.4.0
* @since 2022-04-19
*/
private Optional getPresenterPrefixRule() {
final var prefixRule = this.presenter.getPrefixRepetitionRule();
return prefixRule instanceof DefaultPrefixRepetitionRule
? Optional.of((DefaultPrefixRepetitionRule) prefixRule)
: Optional.empty();
}
/**
* Determines which rounding type the presenter is currently using, if any.
*
* @since v0.4.0
* @since 2022-04-18
*/
private Optional getPresenterRoundingType() {
final var presenterRule = this.presenter.getNumberDisplayRule();
if (Objects.equals(presenterRule,
StandardDisplayRules.uncertaintyBased()))
return Optional.of(StandardRoundingType.UNCERTAINTY);
else if (presenterRule instanceof StandardDisplayRules.FixedDecimals)
return Optional.of(StandardRoundingType.DECIMAL_PLACES);
else if (presenterRule instanceof StandardDisplayRules.FixedPrecision)
return Optional.of(StandardRoundingType.SIGNIFICANT_DIGITS);
else
return Optional.empty();
}
@Override
public Optional getSelectedDimensionName() {
final String selectedItem = (String) this.dimensionSelector
.getSelectedItem();
return Optional.ofNullable(selectedItem);
}
@Override
public String getToExpression() {
return this.toEntry.getText();
}
@Override
public Optional getToSelection() {
return this.toSearch.getSelectedValue();
}
@Override
public Set getToUnitNames() {
// this should work because the only way I can mutate the item list is
// with setToUnits which only accepts a Set
return new HashSet<>(this.toSearch.getItems());
}
@Override
public Optional getViewedPrefixName() {
return this.prefixNameList.getSelectedValue();
}
@Override
public Optional getViewedUnitName() {
return this.unitNameList.getSelectedValue();
}
@Override
public void setDimensionNames(Set dimensionNames) {
this.dimensionSelector.removeAllItems();
for (final String d : dimensionNames) {
this.dimensionSelector.addItem(d);
}
}
@Override
public void setFromUnitNames(Set units) {
this.fromSearch.setItems(units);
}
@Override
public void setToUnitNames(Set units) {
this.toSearch.setItems(units);
}
@Override
public void setViewablePrefixNames(Set prefixNames) {
this.prefixNameList.setItems(prefixNames);
}
@Override
public void setViewableUnitNames(Set unitNames) {
this.unitNameList.setItems(unitNames);
}
@Override
public void showErrorMessage(String title, String message) {
JOptionPane.showMessageDialog(this.frame, message, title,
JOptionPane.ERROR_MESSAGE);
}
@Override
public void showExpressionConversionOutput(UnitConversionRecord uc) {
this.expressionOutput.setText(uc.toString());
}
@Override
public void showPrefix(NameSymbol name, String multiplierString) {
this.prefixTextBox.setText(
String.format("%s%nMultiplier: %s", name, multiplierString));
}
@Override
public void showUnit(NameSymbol name, String definition,
String dimensionName, UnitType type) {
this.unitTextBox.setText(
String.format("%s%nDefinition: %s%nDimension: %s%nType: %s", name,
definition, dimensionName, type));
}
@Override
public void showUnitConversionOutput(UnitConversionRecord uc) {
this.unitOutput.setText(uc.toString());
}
/**
* Sets the presenter's rounding rule to the one specified by the current
* settings
*
* @since v0.4.0
* @since 2022-04-18
*/
private void updatePresenterRoundingRule() {
final Function roundingRule;
switch (this.roundingType) {
case DECIMAL_PLACES:
roundingRule = StandardDisplayRules.fixedDecimals(this.precision);
break;
case SIGNIFICANT_DIGITS:
roundingRule = StandardDisplayRules.fixedPrecision(this.precision);
break;
case UNCERTAINTY:
roundingRule = StandardDisplayRules.uncertaintyBased();
break;
default:
throw new AssertionError();
}
this.presenter.setNumberDisplayRule(roundingRule);
this.presenter.saveSettings();
}
@Override
public void updateText() {
// TODO Auto-generated method stub
}
}