summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAdrien Hopkins <ahopk127@my.yorku.ca>2022-04-19 16:10:44 -0500
committerAdrien Hopkins <ahopk127@my.yorku.ca>2022-04-19 16:10:44 -0500
commit0aacba9fc8a9140fdf331172ad66afe280d09b5e (patch)
tree3699f6cf4ce40db818233287853474a4cf99ba5c /src
parent40f7b6e806140fc2fc741c63c71f5ce97b4bd1d2 (diff)
Implemented prefix settings, saving & loading of settings
Also fixed some bugs: - Presenter now has default values for its settings in case they don't load properly - UnitDatabase ensures its units, prefixes and dimensions have all of the names you give it
Diffstat (limited to 'src')
-rw-r--r--src/main/java/sevenUnits/unit/UnitDatabase.java29
-rw-r--r--src/main/java/sevenUnits/utils/NameSymbol.java17
-rw-r--r--src/main/java/sevenUnitsGUI/DefaultPrefixRepetitionRule.java95
-rw-r--r--src/main/java/sevenUnitsGUI/Presenter.java175
-rw-r--r--src/main/java/sevenUnitsGUI/TabbedView.java77
-rw-r--r--src/main/java/sevenUnitsGUI/UnitConversionRecord.java19
-rw-r--r--src/main/java/sevenUnitsGUI/View.java6
-rw-r--r--src/main/java/sevenUnitsGUI/ViewBot.java23
-rw-r--r--src/test/java/sevenUnitsGUI/PresenterTest.java25
-rw-r--r--src/test/resources/test-settings.txt4
10 files changed, 384 insertions, 86 deletions
diff --git a/src/main/java/sevenUnits/unit/UnitDatabase.java b/src/main/java/sevenUnits/unit/UnitDatabase.java
index 71676a1..12b78a7 100644
--- a/src/main/java/sevenUnits/unit/UnitDatabase.java
+++ b/src/main/java/sevenUnits/unit/UnitDatabase.java
@@ -1315,13 +1315,9 @@ public final class UnitDatabase {
final ObjectProduct<BaseDimension> dimension) {
Objects.requireNonNull(name, "name may not be null");
Objects.requireNonNull(dimension, "dimension may not be null");
- if (!dimension.getNameSymbol().equals(NameSymbol.EMPTY)) {
- this.dimensions.put(name, dimension);
- } else {
- final ObjectProduct<BaseDimension> namedDimension = dimension
- .withName(NameSymbol.ofName(name));
- this.dimensions.put(name, namedDimension);
- }
+ final ObjectProduct<BaseDimension> namedDimension = dimension
+ .withName(dimension.getNameSymbol().withExtraName(name));
+ this.dimensions.put(name, namedDimension);
}
/**
@@ -1373,7 +1369,7 @@ public final class UnitDatabase {
throw e;
}
- this.addDimension(name, dimension.withName(NameSymbol.ofName(name)));
+ this.addDimension(name, dimension);
}
}
@@ -1387,8 +1383,11 @@ public final class UnitDatabase {
* @since v0.1.0
*/
public void addPrefix(final String name, final UnitPrefix prefix) {
+ Objects.requireNonNull(prefix, "prefix may not be null");
+ final var namedPrefix = prefix
+ .withName(prefix.getNameSymbol().withExtraName(name));
this.prefixes.put(Objects.requireNonNull(name, "name must not be null."),
- Objects.requireNonNull(prefix, "prefix must not be null."));
+ namedPrefix);
}
/**
@@ -1401,9 +1400,11 @@ public final class UnitDatabase {
* @since v0.1.0
*/
public void addUnit(final String name, final Unit unit) {
+ Objects.requireNonNull(unit, "unit may not be null");
+ final var namedUnit = unit
+ .withName(unit.getNameSymbol().withExtraName(name));
this.prefixlessUnits.put(
- Objects.requireNonNull(name, "name must not be null."),
- Objects.requireNonNull(unit, "unit must not be null."));
+ Objects.requireNonNull(name, "name must not be null."), namedUnit);
}
/**
@@ -1458,8 +1459,7 @@ public final class UnitDatabase {
throw e;
}
final String prefixName = name.substring(0, name.length() - 1);
- this.addPrefix(prefixName,
- prefix.withName(NameSymbol.ofName(prefixName)));
+ this.addPrefix(prefixName, prefix);
} else {
// it's a unit, get the unit
final Unit unit;
@@ -1470,8 +1470,7 @@ public final class UnitDatabase {
System.err.printf("Parsing error on line %d:%n", lineCounter);
throw e;
}
-
- this.addUnit(name, unit.withName(NameSymbol.ofName(name)));
+ this.addUnit(name, unit);
}
}
}
diff --git a/src/main/java/sevenUnits/utils/NameSymbol.java b/src/main/java/sevenUnits/utils/NameSymbol.java
index 955f980..7ef2967 100644
--- a/src/main/java/sevenUnits/utils/NameSymbol.java
+++ b/src/main/java/sevenUnits/utils/NameSymbol.java
@@ -288,4 +288,21 @@ public final class NameSymbol {
else
return this.primaryName.orElseGet(this.symbol::orElseThrow);
}
+
+ /**
+ * Creates and returns a copy of this {@code NameSymbol} with the provided
+ * extra name. If this {@code NameSymbol} has a primary name, the provided
+ * name will become an other name, otherwise it will become the primary name.
+ *
+ * @since 2022-04-19
+ */
+ public final NameSymbol withExtraName(String name) {
+ if (this.primaryName.isPresent()) {
+ final var otherNames = new HashSet<>(this.otherNames);
+ otherNames.add(name);
+ return NameSymbol.ofNullable(this.primaryName.orElse(null),
+ this.symbol.orElse(null), otherNames);
+ } else
+ return NameSymbol.ofNullable(name, this.symbol.orElse(null));
+ }
} \ No newline at end of file
diff --git a/src/main/java/sevenUnitsGUI/DefaultPrefixRepetitionRule.java b/src/main/java/sevenUnitsGUI/DefaultPrefixRepetitionRule.java
new file mode 100644
index 0000000..b56356d
--- /dev/null
+++ b/src/main/java/sevenUnitsGUI/DefaultPrefixRepetitionRule.java
@@ -0,0 +1,95 @@
+/**
+ * @since 2020-08-26
+ */
+package sevenUnitsGUI;
+
+import java.util.List;
+import java.util.function.Predicate;
+
+import sevenUnits.unit.Metric;
+import sevenUnits.unit.UnitPrefix;
+
+/**
+ * A rule that specifies whether prefix repetition is allowed
+ *
+ * @since 2020-08-26
+ */
+public enum DefaultPrefixRepetitionRule implements Predicate<List<UnitPrefix>> {
+ NO_REPETITION {
+ @Override
+ public boolean test(List<UnitPrefix> prefixes) {
+ return prefixes.size() <= 1;
+ }
+ },
+ NO_RESTRICTION {
+ @Override
+ public boolean test(List<UnitPrefix> prefixes) {
+ return true;
+ }
+ },
+ /**
+ * You are allowed to have any number of Yotta/Yocto followed by possibly one
+ * Kilo-Zetta/Milli-Zepto followed by possibly one Deca/Hecto. Same for
+ * reducing prefixes, don't mix magnifying and reducing. Non-metric
+ * (including binary) prefixes can't be repeated.
+ */
+ COMPLEX_REPETITION {
+ @Override
+ public boolean test(List<UnitPrefix> prefixes) {
+ // determine whether we are magnifying or reducing
+ final boolean magnifying;
+ if (prefixes.isEmpty())
+ return true;
+ else if (prefixes.get(0).getMultiplier() > 1) {
+ magnifying = true;
+ } else {
+ magnifying = false;
+ }
+
+ // if the first prefix is non-metric (including binary prefixes),
+ // assume we are using non-metric prefixes
+ // non-metric prefixes are allowed, but can't be repeated.
+ if (!Metric.DECIMAL_PREFIXES.contains(prefixes.get(0)))
+ return NO_REPETITION.test(prefixes);
+
+ int part = 0; // 0=yotta/yoctos, 1=kilo-zetta/milli-zepto,
+ // 2=deka,hecto,deci,centi
+
+ for (final UnitPrefix prefix : prefixes) {
+ // check that the current prefix is metric and appropriately
+ // magnifying/reducing
+ if (!Metric.DECIMAL_PREFIXES.contains(prefix))
+ return false;
+ if (magnifying != prefix.getMultiplier() > 1)
+ return false;
+
+ // check if the current prefix is correct
+ // since part is set *after* this check, part designates the state
+ // of the *previous* prefix
+ switch (part) {
+ case 0:
+ // do nothing, any prefix is valid after a yotta
+ break;
+ case 1:
+ // after a kilo-zetta, only deka/hecto are valid
+ if (Metric.THOUSAND_PREFIXES.contains(prefix))
+ return false;
+ break;
+ case 2:
+ // deka/hecto must be the last prefix, so this is always invalid
+ return false;
+ }
+
+ // set part
+ if (Metric.YOTTA.equals(prefix) || Metric.YOCTO.equals(prefix)) {
+ part = 0;
+ } else if (Metric.THOUSAND_PREFIXES.contains(prefix)) {
+ part = 1;
+ } else {
+ part = 2;
+ }
+ }
+ return true;
+ }
+ };
+}
diff --git a/src/main/java/sevenUnitsGUI/Presenter.java b/src/main/java/sevenUnitsGUI/Presenter.java
index f4f3e3a..fd050b7 100644
--- a/src/main/java/sevenUnitsGUI/Presenter.java
+++ b/src/main/java/sevenUnitsGUI/Presenter.java
@@ -16,8 +16,10 @@
*/
package sevenUnitsGUI;
+import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStream;
+import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.HashSet;
@@ -30,7 +32,6 @@ import java.util.Set;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;
-import java.util.stream.Stream;
import sevenUnits.ProgramInfo;
import sevenUnits.unit.BaseDimension;
@@ -140,12 +141,24 @@ public final class Presenter {
}
/**
+ * @return true iff a and b have any elements in common
+ * @since 2022-04-19
+ */
+ private static final boolean sharesAnyElements(Set<?> a, Set<?> b) {
+ for (final Object e : a) {
+ if (b.contains(e))
+ return true;
+ }
+ return false;
+ }
+
+ /**
* @return {@code line} with any comments removed.
* @since 2021-03-13
*/
private static final String withoutComments(String line) {
final int index = line.indexOf('#');
- return index == -1 ? line : line.substring(index);
+ return index == -1 ? line : line.substring(0, index);
}
// ====== SETTINGS ======
@@ -171,14 +184,15 @@ public final class Presenter {
* of unit conversions will be put into this function, and the resulting
* string will be used in the output.
*/
- private Function<UncertainDouble, String> numberDisplayRule;
+ private Function<UncertainDouble, String> numberDisplayRule = StandardDisplayRules
+ .uncertaintyBased();
/**
* A predicate that determines whether or not a certain combination of
* prefixes is allowed. If it returns false, a combination of prefixes will
* not be allowed. Prefixes are put in the list from right to left.
*/
- private Predicate<List<UnitPrefix>> prefixRepetitionRule;
+ private Predicate<List<UnitPrefix>> prefixRepetitionRule = DefaultPrefixRepetitionRule.NO_RESTRICTION;
/**
* The set of units that is considered neither metric nor nonmetric for the
@@ -192,13 +206,13 @@ public final class Presenter {
* removed from the From unit list and imperial/USC units removed from the To
* unit list.
*/
- private boolean oneWayConversionEnabled;
+ private boolean oneWayConversionEnabled = false;
/**
* If this is false, duplicate units and prefixes will be removed from the
* unit view in views that show units as a list to choose from.
*/
- private boolean showDuplicates;
+ private boolean showDuplicates = false;
/**
* Creates a Presenter
@@ -245,7 +259,19 @@ public final class Presenter {
}
// set default settings temporarily
- this.numberDisplayRule = StandardDisplayRules.uncertaintyBased();
+ this.loadSettings(DEFAULT_SETTINGS_FILEPATH);
+
+ // a Predicate that returns true iff the argument is a full base unit
+ final Predicate<Unit> isFullBase = unit -> unit instanceof LinearUnit
+ && ((LinearUnit) unit).isBase();
+
+ // print out unit counts
+ System.out.printf(
+ "Successfully loaded %d units with %d unit names (%d base units).%n",
+ this.database.unitMapPrefixless(false).size(),
+ this.database.unitMapPrefixless(true).size(),
+ this.database.unitMapPrefixless(false).values().stream()
+ .filter(isFullBase).count());
}
/**
@@ -456,18 +482,35 @@ public final class Presenter {
}
/**
+ * @return the rule that determines whether a set of prefixes is valid
+ * @since 2022-04-19
+ */
+ public Predicate<List<UnitPrefix>> getPrefixRepetitionRule() {
+ return this.prefixRepetitionRule;
+ }
+
+ /**
+ * @return the view associated with this presenter
+ * @since 2022-04-19
+ */
+ public View getView() {
+ return this.view;
+ }
+
+ /**
* @return whether or not the provided unit is semi-metric (i.e. an
* exception)
* @since 2022-04-16
*/
- private final boolean isSemiMetric(Unit u) {
+ final boolean isSemiMetric(Unit u) {
// determine if u is an exception
final var primaryName = u.getPrimaryName();
final var symbol = u.getSymbol();
return primaryName.isPresent()
&& this.metricExceptions.contains(primaryName.orElseThrow())
|| symbol.isPresent()
- && this.metricExceptions.contains(symbol.orElseThrow());
+ && this.metricExceptions.contains(symbol.orElseThrow())
+ || sharesAnyElements(this.metricExceptions, u.getOtherNames());
}
/**
@@ -477,7 +520,48 @@ public final class Presenter {
* @param settingsFile file settings should be loaded from
* @since 2021-12-15
*/
- void loadSettings(Path settingsFile) {}
+ void loadSettings(Path settingsFile) {
+ try {
+ // read file line by line
+ final int lineNum = 0;
+ for (final String line : Files.readAllLines(settingsFile)) {
+ final int equalsIndex = line.indexOf('=');
+ if (equalsIndex == -1)
+ throw new IllegalStateException(
+ "Settings file is malformed at line " + lineNum);
+
+ final String param = line.substring(0, equalsIndex);
+ final String value = line.substring(equalsIndex + 1);
+
+ switch (param) {
+ // set manually to avoid the unnecessary saving of the non-manual
+ // methods
+ case "number_display_rule":
+ this.numberDisplayRule = StandardDisplayRules
+ .getStandardRule(value);
+ break;
+ case "prefix_rule":
+ this.prefixRepetitionRule = DefaultPrefixRepetitionRule
+ .valueOf(value);
+ this.database.setPrefixRepetitionRule(this.prefixRepetitionRule);
+ break;
+ case "one_way":
+ this.oneWayConversionEnabled = Boolean.valueOf(value);
+ break;
+ case "include_duplicates":
+ this.showDuplicates = Boolean.valueOf(value);
+ break;
+ default:
+ System.err.printf("Warning: unrecognized setting \"%s\".%n",
+ param);
+ break;
+ }
+ }
+ if (this.view.getPresenter() != null) {
+ this.updateView();
+ }
+ } catch (final IOException e) {}
+ }
/**
* @return true iff the One-Way Conversion feature is available (views that
@@ -520,12 +604,37 @@ public final class Presenter {
}
/**
+ * Saves the presenter's current settings to its default filepath.
+ *
+ * @since 2022-04-19
+ */
+ public void saveSettings() {
+ this.saveSettings(DEFAULT_SETTINGS_FILEPATH);
+ }
+
+ /**
* Saves the presenter's settings to the user settings file.
*
* @param settingsFile file settings should be saved to
* @since 2021-12-15
*/
- void saveSettings(Path settingsFile) {}
+ void saveSettings(Path settingsFile) {
+ try (BufferedWriter writer = Files.newBufferedWriter(settingsFile)) {
+ writer.write(String.format("number_display_rule=%s\n",
+ this.numberDisplayRule));
+ writer.write(
+ String.format("prefix_rule=%s\n", this.prefixRepetitionRule));
+ writer.write(
+ String.format("one_way=%s\n", this.oneWayConversionEnabled));
+ writer.write(
+ String.format("include_duplicates=%s\n", this.showDuplicates));
+ } catch (final IOException e) {
+ e.printStackTrace();
+ this.view.showErrorMessage("I/O Error",
+ "Error occurred while saving settings: "
+ + e.getLocalizedMessage());
+ }
+ }
/**
* @param numberDisplayRule the new rule that will be used by this presenter
@@ -560,6 +669,17 @@ public final class Presenter {
}
/**
+ * @param prefixRepetitionRule the rule that determines whether a set of
+ * prefixes is valid
+ * @since 2022-04-19
+ */
+ public void setPrefixRepetitionRule(
+ Predicate<List<UnitPrefix>> prefixRepetitionRule) {
+ this.prefixRepetitionRule = prefixRepetitionRule;
+ this.database.setPrefixRepetitionRule(prefixRepetitionRule);
+ }
+
+ /**
* @param showDuplicateUnits whether or not duplicate units should be shown
* @since 2022-03-30
*/
@@ -608,9 +728,7 @@ public final class Presenter {
public void updateView() {
if (this.view instanceof UnitConversionView) {
final UnitConversionView ucview = (UnitConversionView) this.view;
- final ObjectProduct<BaseDimension> viewDimension = this.database
- .getDimension(((UnitConversionView) this.view)
- .getSelectedDimensionName().orElseThrow());
+ final var selectedDimensionName = ucview.getSelectedDimensionName();
// load units & prefixes into viewers
this.view.setViewableUnitNames(
@@ -619,29 +737,34 @@ public final class Presenter {
this.database.prefixMap(this.showDuplicates).keySet());
// get From and To units
- Stream<Unit> fromUnits = this.database
- .unitMapPrefixless(this.showDuplicates).entrySet().stream()
- .map(Map.Entry::getValue)
- .filter(u -> viewDimension.equals(u.getDimension()));
+ var fromUnits = this.database.unitMapPrefixless(this.showDuplicates)
+ .entrySet().stream();
+ var toUnits = this.database.unitMapPrefixless(this.showDuplicates)
+ .entrySet().stream();
- Stream<Unit> toUnits = this.database
- .unitMapPrefixless(this.showDuplicates).entrySet().stream()
- .map(Map.Entry::getValue)
- .filter(u -> viewDimension.equals(u.getDimension()));
+ // filter by dimension, if one is selected
+ if (selectedDimensionName.isPresent()) {
+ final var viewDimension = this.database
+ .getDimension(selectedDimensionName.orElseThrow());
+ fromUnits = fromUnits.filter(
+ u -> viewDimension.equals(u.getValue().getDimension()));
+ toUnits = toUnits.filter(
+ u -> viewDimension.equals(u.getValue().getDimension()));
+ }
// filter by unit type, if desired
if (this.oneWayConversionEnabled) {
- fromUnits = fromUnits.filter(u -> UnitType.getType(u,
+ fromUnits = fromUnits.filter(u -> UnitType.getType(u.getValue(),
this::isSemiMetric) != UnitType.METRIC);
- toUnits = toUnits.filter(u -> UnitType.getType(u,
+ toUnits = toUnits.filter(u -> UnitType.getType(u.getValue(),
this::isSemiMetric) != UnitType.NON_METRIC);
}
// set unit names
ucview.setFromUnitNames(
- fromUnits.map(Unit::getName).collect(Collectors.toSet()));
+ fromUnits.map(Map.Entry::getKey).collect(Collectors.toSet()));
ucview.setToUnitNames(
- toUnits.map(Unit::getName).collect(Collectors.toSet()));
+ toUnits.map(Map.Entry::getKey).collect(Collectors.toSet()));
}
}
diff --git a/src/main/java/sevenUnitsGUI/TabbedView.java b/src/main/java/sevenUnitsGUI/TabbedView.java
index 098c374..c8e69ee 100644
--- a/src/main/java/sevenUnitsGUI/TabbedView.java
+++ b/src/main/java/sevenUnitsGUI/TabbedView.java
@@ -543,39 +543,49 @@ final class TabbedView implements ExpressionConversionView, UnitConversionView {
.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 (this.presenter.prefixRule == DefaultPrefixRepetitionRule.NO_REPETITION) {
-// noRepetition.setSelected(true);
-// }
-// noRepetition
-// .addActionListener(e -> this.presenter.setPrefixRepetitionRule(
-// DefaultPrefixRepetitionRule.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 (this.presenter.prefixRule == DefaultPrefixRepetitionRule.NO_RESTRICTION) {
-// noRestriction.setSelected(true);
-// }
-// noRestriction
-// .addActionListener(e -> this.presenter.setPrefixRepetitionRule(
-// DefaultPrefixRepetitionRule.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 (this.presenter.prefixRule == DefaultPrefixRepetitionRule.COMPLEX_REPETITION) {
-// customRepetition.setSelected(true);
-// }
-// customRepetition
-// .addActionListener(e -> this.presenter.setPrefixRepetitionRule(
-// DefaultPrefixRepetitionRule.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());
@@ -628,16 +638,22 @@ final class TabbedView implements ExpressionConversionView, UnitConversionView {
final JCheckBox oneWay = new JCheckBox("Convert One Way Only");
oneWay.setSelected(this.presenter.oneWayConversionEnabled());
- oneWay.addItemListener(e -> this.presenter.setOneWayConversionEnabled(
- e.getStateChange() == ItemEvent.SELECTED));
+ 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));
+ 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());
@@ -678,6 +694,11 @@ final class TabbedView implements ExpressionConversionView, UnitConversionView {
return this.valueInput.getText();
}
+ @Override
+ public Presenter getPresenter() {
+ return this.presenter;
+ }
+
/**
* @return the precision of the presenter's rounding rule, if that is
* meaningful
@@ -698,6 +719,17 @@ final class TabbedView implements ExpressionConversionView, UnitConversionView {
}
/**
+ * @return presenter's prefix repetition rule
+ * @since 2022-04-19
+ */
+ private Optional<DefaultPrefixRepetitionRule> 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 2022-04-18
@@ -830,5 +862,6 @@ final class TabbedView implements ExpressionConversionView, UnitConversionView {
throw new AssertionError();
}
this.presenter.setNumberDisplayRule(roundingRule);
+ this.presenter.saveSettings();
}
}
diff --git a/src/main/java/sevenUnitsGUI/UnitConversionRecord.java b/src/main/java/sevenUnitsGUI/UnitConversionRecord.java
index 60675e2..f951f44 100644
--- a/src/main/java/sevenUnitsGUI/UnitConversionRecord.java
+++ b/src/main/java/sevenUnitsGUI/UnitConversionRecord.java
@@ -16,6 +16,9 @@
*/
package sevenUnitsGUI;
+import java.math.RoundingMode;
+
+import sevenUnits.unit.LinearUnitValue;
import sevenUnits.unit.UnitValue;
/**
@@ -25,6 +28,22 @@ import sevenUnits.unit.UnitValue;
*/
public final class UnitConversionRecord {
/**
+ * Gets a {@code UnitConversionRecord} from two linear unit values
+ *
+ * @param input input unit & value
+ * @param output output unit & value
+ * @return unit conversion record
+ * @since 2022-04-09
+ */
+ public static UnitConversionRecord fromLinearValues(LinearUnitValue input,
+ LinearUnitValue output) {
+ return UnitConversionRecord.valueOf(input.getUnit().getName(),
+ output.getUnit().getName(),
+ input.getValue().toString(false, RoundingMode.HALF_EVEN),
+ output.getValue().toString(false, RoundingMode.HALF_EVEN));
+ }
+
+ /**
* Gets a {@code UnitConversionRecord} from two unit values
*
* @param input input unit & value
diff --git a/src/main/java/sevenUnitsGUI/View.java b/src/main/java/sevenUnitsGUI/View.java
index da3749e..011e87f 100644
--- a/src/main/java/sevenUnitsGUI/View.java
+++ b/src/main/java/sevenUnitsGUI/View.java
@@ -30,6 +30,12 @@ import sevenUnits.utils.NameSymbol;
*/
public interface View {
/**
+ * @return the presenter associated with this view
+ * @since 2022-04-19
+ */
+ Presenter getPresenter();
+
+ /**
* @return name of prefix currently being viewed
* @since 2022-04-10
*/
diff --git a/src/main/java/sevenUnitsGUI/ViewBot.java b/src/main/java/sevenUnitsGUI/ViewBot.java
index dd9869d..9253ae5 100644
--- a/src/main/java/sevenUnitsGUI/ViewBot.java
+++ b/src/main/java/sevenUnitsGUI/ViewBot.java
@@ -196,30 +196,30 @@ final class ViewBot implements UnitConversionView, ExpressionConversionView {
private final Presenter presenter;
/** The dimensions available to select from */
- private Set<String> dimensionNames;
+ private Set<String> dimensionNames = Set.of();
/** The expression in the From field */
- private String fromExpression;
+ private String fromExpression = "";
/** The expression in the To field */
- private String toExpression;
+ private String toExpression = "";
/**
* The user-provided string representing the value in {@code fromSelection}
*/
- private String inputValue;
+ private String inputValue = "";
/** The unit selected in the From selection */
- private Optional<String> fromSelection;
+ private Optional<String> fromSelection = Optional.empty();
/** The unit selected in the To selection */
- private Optional<String> toSelection;
+ private Optional<String> toSelection = Optional.empty();
/** The currently selected dimension */
- private Optional<String> selectedDimensionName;
+ private Optional<String> selectedDimensionName = Optional.empty();
/** The units available in the From selection */
- private Set<String> fromUnits;
+ private Set<String> fromUnits = Set.of();
/** The units available in the To selection */
- private Set<String> toUnits;
+ private Set<String> toUnits = Set.of();
/** The selected unit in the unit viewer */
- private Optional<String> unitViewerSelection;
+ private Optional<String> unitViewerSelection = Optional.empty();
/** The selected unit in the prefix viewer */
- private Optional<String> prefixViewerSelection;
+ private Optional<String> prefixViewerSelection = Optional.empty();
/** Saved outputs of all unit conversions */
private final List<UnitConversionRecord> unitConversions;
@@ -289,6 +289,7 @@ final class ViewBot implements UnitConversionView, ExpressionConversionView {
* @return the presenter associated with tihs view
* @since 2022-01-29
*/
+ @Override
public Presenter getPresenter() {
return this.presenter;
}
diff --git a/src/test/java/sevenUnitsGUI/PresenterTest.java b/src/test/java/sevenUnitsGUI/PresenterTest.java
index 362a5c9..f639329 100644
--- a/src/test/java/sevenUnitsGUI/PresenterTest.java
+++ b/src/test/java/sevenUnitsGUI/PresenterTest.java
@@ -19,6 +19,7 @@ package sevenUnitsGUI;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
+import java.math.RoundingMode;
import java.nio.file.Path;
import java.util.List;
import java.util.Set;
@@ -32,10 +33,10 @@ import org.junit.jupiter.params.provider.MethodSource;
import sevenUnits.unit.BaseDimension;
import sevenUnits.unit.BritishImperial;
+import sevenUnits.unit.LinearUnitValue;
import sevenUnits.unit.Metric;
import sevenUnits.unit.Unit;
import sevenUnits.unit.UnitType;
-import sevenUnits.unit.UnitValue;
import sevenUnits.utils.NameSymbol;
import sevenUnits.utils.Nameable;
import sevenUnits.utils.ObjectProduct;
@@ -91,7 +92,7 @@ public final class PresenterTest {
// test result
final List<UnitConversionRecord> outputs = viewBot
.expressionConversionList();
- assertEquals("10000.0 m = 10.0 km",
+ assertEquals("10000.0 m = 10.00000 km",
outputs.get(outputs.size() - 1).toString());
}
@@ -120,12 +121,14 @@ public final class PresenterTest {
* here (that's for the backend tests), I'm just testing that it correctly
* calls the unit conversion system
*/
- final UnitValue expectedInput = UnitValue.of(Metric.METRE, 10000.0);
- final UnitValue expectedOutput = expectedInput
+ final LinearUnitValue expectedInput = LinearUnitValue.of(Metric.METRE,
+ UncertainDouble.fromRoundedString("10000.0"));
+ final LinearUnitValue expectedOutput = expectedInput
.convertTo(Metric.KILOMETRE);
- final UnitConversionRecord expectedUC = UnitConversionRecord
- .fromValues(expectedInput, expectedOutput);
-
+ final UnitConversionRecord expectedUC = UnitConversionRecord.valueOf(
+ expectedInput.getUnit().getName(),
+ expectedOutput.getUnit().getName(), "10000.0",
+ expectedOutput.getValue().toString(false, RoundingMode.HALF_EVEN));
assertEquals(List.of(expectedUC), viewBot.unitConversionList());
}
@@ -182,13 +185,11 @@ public final class PresenterTest {
// test that units are removed from each side when one-way conversion is
// enabled
presenter.setOneWayConversionEnabled(true);
- presenter.updateView();
- assertEquals(metricNames, viewBot.getFromUnitNames());
- assertEquals(nonMetricNames, viewBot.getToUnitNames());
+ assertEquals(nonMetricNames, viewBot.getFromUnitNames());
+ assertEquals(metricNames, viewBot.getToUnitNames());
// test that units are kept when one-way conversion is disabled
presenter.setOneWayConversionEnabled(false);
- presenter.updateView();
assertEquals(allNames, viewBot.getFromUnitNames());
assertEquals(allNames, viewBot.getToUnitNames());
}
@@ -243,7 +244,7 @@ public final class PresenterTest {
// test the result of the rounding
final String expectedOutputString = roundingRule
- .apply(UncertainDouble.of(12.3456789, 0));
+ .apply(UncertainDouble.fromRoundedString("12.3456789"));
final String actualOutputString = viewBot.unitConversionList().get(0)
.outputValueString();
assertEquals(expectedOutputString, actualOutputString);
diff --git a/src/test/resources/test-settings.txt b/src/test/resources/test-settings.txt
new file mode 100644
index 0000000..932221e
--- /dev/null
+++ b/src/test/resources/test-settings.txt
@@ -0,0 +1,4 @@
+number_display_rule=Round to 11 significant figures
+prefix_rule=NO_RESTRICTION
+one_way=true
+include_duplicates=true