From 40f7b6e806140fc2fc741c63c71f5ce97b4bd1d2 Mon Sep 17 00:00:00 2001 From: Adrien Hopkins Date: Mon, 18 Apr 2022 17:41:43 -0500 Subject: Implemented one-way conversion, duplicate prefixes can now be hidden --- CHANGELOG.org | 1 + .../sevenUnits/converterGUI/SevenUnitsGUI.java | 5 +- src/main/java/sevenUnits/unit/BritishImperial.java | 2 +- src/main/java/sevenUnits/unit/UnitDatabase.java | 26 +++++--- src/main/java/sevenUnits/unit/UnitType.java | 24 ++++++++ src/main/java/sevenUnitsGUI/Presenter.java | 71 +++++++++++++--------- src/main/java/sevenUnitsGUI/TabbedView.java | 9 ++- .../java/sevenUnits/unit/UnitDatabaseTest.java | 2 +- src/test/java/sevenUnitsGUI/PresenterTest.java | 10 +-- 9 files changed, 97 insertions(+), 53 deletions(-) diff --git a/CHANGELOG.org b/CHANGELOG.org index c164d1f..509553b 100644 --- a/CHANGELOG.org +++ b/CHANGELOG.org @@ -12,6 +12,7 @@ - The toString method of the common unit classes is now simpler. Alternate toString functions that describe the full unit are provided. - UncertainDouble and LinearUnitValue accept a RoundingMode in their complicated toString functions. - Rounding rules are now in their own classes + - The "Show Duplicates" setting now affects the prefix viewer in addition to units - Tweaked the look of the unit and expression conversion sections of the view ** v0.3.2 - [2021-12-02 Thu] *** Added diff --git a/src/main/java/sevenUnits/converterGUI/SevenUnitsGUI.java b/src/main/java/sevenUnits/converterGUI/SevenUnitsGUI.java index e10bab4..309bdb9 100644 --- a/src/main/java/sevenUnits/converterGUI/SevenUnitsGUI.java +++ b/src/main/java/sevenUnits/converterGUI/SevenUnitsGUI.java @@ -298,7 +298,8 @@ final class SevenUnitsGUI { this.database.unitMapPrefixless(true).keySet()); this.unitNames.sort(null); // sorts it using Comparable - this.prefixNames = new ArrayList<>(this.database.prefixMap().keySet()); + this.prefixNames = new ArrayList<>( + this.database.prefixMap(true).keySet()); this.prefixNames.sort(this.prefixNameComparator); // sorts it using my // comparator @@ -611,7 +612,7 @@ final class SevenUnitsGUI { * @since v0.2.0 */ public final Set prefixNameSet() { - return this.database.prefixMap().keySet(); + return this.database.prefixMap(true).keySet(); } /** diff --git a/src/main/java/sevenUnits/unit/BritishImperial.java b/src/main/java/sevenUnits/unit/BritishImperial.java index c6e65fb..0ecba6d 100644 --- a/src/main/java/sevenUnits/unit/BritishImperial.java +++ b/src/main/java/sevenUnits/unit/BritishImperial.java @@ -121,5 +121,5 @@ public final class BritishImperial { public static final Unit FAHRENHEIT = Unit .fromConversionFunctions(Metric.KELVIN.getBase(), tempK -> tempK * 1.8 - 459.67, tempF -> (tempF + 459.67) / 1.8) - .withName(NameSymbol.of("degrees Fahrenheit", "\u00B0F")); + .withName(NameSymbol.of("degree Fahrenheit", "\u00B0F")); } diff --git a/src/main/java/sevenUnits/unit/UnitDatabase.java b/src/main/java/sevenUnits/unit/UnitDatabase.java index a4f0c44..71676a1 100644 --- a/src/main/java/sevenUnits/unit/UnitDatabase.java +++ b/src/main/java/sevenUnits/unit/UnitDatabase.java @@ -1160,16 +1160,16 @@ public final class UnitDatabase { } /** - * @return true if entry represents a removable duplicate entry of unitMap. + * @return true if entry represents a removable duplicate entry of map. * @since 2021-05-22 */ - static boolean isRemovableDuplicate(Map unitMap, - Entry entry) { - for (final Entry e : unitMap.entrySet()) { + static boolean isRemovableDuplicate(Map map, + Entry entry) { + for (final Entry e : map.entrySet()) { final String name = e.getKey(); - final Unit value = e.getValue(); + final T value = e.getValue(); if (lengthFirstComparator.compare(entry.getKey(), name) < 0 - && Objects.equals(unitMap.get(entry.getKey()), value)) + && Objects.equals(map.get(entry.getKey()), value)) return true; } return false; @@ -2010,12 +2010,18 @@ public final class UnitDatabase { } /** + * @param includeDuplicates if false, duplicates are removed from the map * @return a map mapping prefix names to prefixes - * @since 2019-04-13 - * @since v0.2.0 + * @since 2022-04-18 + * @since v0.4.0 */ - public Map prefixMap() { - return Collections.unmodifiableMap(this.prefixes); + public Map prefixMap(boolean includeDuplicates) { + if (includeDuplicates) + return Collections.unmodifiableMap(this.prefixes); + else + return Collections.unmodifiableMap(ConditionalExistenceCollections + .conditionalExistenceMap(this.prefixes, + entry -> !isRemovableDuplicate(this.prefixes, entry))); } /** diff --git a/src/main/java/sevenUnits/unit/UnitType.java b/src/main/java/sevenUnits/unit/UnitType.java index a13051a..7cebf2d 100644 --- a/src/main/java/sevenUnits/unit/UnitType.java +++ b/src/main/java/sevenUnits/unit/UnitType.java @@ -16,6 +16,8 @@ */ package sevenUnits.unit; +import java.util.function.Predicate; + /** * A type of unit, as chosen by the type of system it is in. *
    @@ -31,4 +33,26 @@ package sevenUnits.unit; */ public enum UnitType { METRIC, SEMI_METRIC, NON_METRIC; + + /** + * Determines which type a unit is. The type will be: + *
      + *
    • {@code SEMI_METRIC} if the unit passes the provided predicate + *
    • {@code METRIC} if it fails the predicate but is metric + *
    • {@code NON_METRIC} if it fails the predicate and is not metric + *
    + * + * @param u unit to test + * @param isSemiMetric predicate to determine if a unit is semi-metric + * @return type of unit + * @since 2022-04-18 + */ + public static final UnitType getType(Unit u, Predicate isSemiMetric) { + if (isSemiMetric.test(u)) + return SEMI_METRIC; + else if (u.isMetric()) + return METRIC; + else + return NON_METRIC; + } } diff --git a/src/main/java/sevenUnitsGUI/Presenter.java b/src/main/java/sevenUnitsGUI/Presenter.java index 85a0ddc..f4f3e3a 100644 --- a/src/main/java/sevenUnitsGUI/Presenter.java +++ b/src/main/java/sevenUnitsGUI/Presenter.java @@ -30,6 +30,7 @@ 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; @@ -194,10 +195,10 @@ public final class Presenter { private boolean oneWayConversionEnabled; /** - * If this is false, duplicate units will be removed from the unit view in - * views that show units as a list to choose from. + * 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 showDuplicateUnits; + private boolean showDuplicates; /** * Creates a Presenter @@ -416,8 +417,8 @@ public final class Presenter { * @return true iff duplicate units are shown in unit lists * @since 2022-03-30 */ - public boolean duplicateUnitsShown() { - return this.showDuplicateUnits; + public boolean duplicatesShown() { + return this.showDuplicates; } /** @@ -455,25 +456,18 @@ public final class Presenter { } /** - * @return type of unit {@code u} + * @return whether or not the provided unit is semi-metric (i.e. an + * exception) * @since 2022-04-16 */ - private final UnitType getUnitType(Unit u) { + private final boolean isSemiMetric(Unit u) { // determine if u is an exception final var primaryName = u.getPrimaryName(); final var symbol = u.getSymbol(); - final boolean isException = primaryName.isPresent() + return primaryName.isPresent() && this.metricExceptions.contains(primaryName.orElseThrow()) || symbol.isPresent() && this.metricExceptions.contains(symbol.orElseThrow()); - - // determine unit type - if (isException) - return UnitType.SEMI_METRIC; - else if (u.isMetric()) - return UnitType.METRIC; - else - return UnitType.NON_METRIC; } /** @@ -510,10 +504,7 @@ public final class Presenter { ucview.setDimensionNames(this.database.dimensionMap().keySet()); } - // load units & prefixes into viewers - this.view.setViewableUnitNames( - this.database.unitMapPrefixless(this.showDuplicateUnits).keySet()); - this.view.setViewablePrefixNames(this.database.prefixMap().keySet()); + this.updateView(); } void prefixSelected() { @@ -572,8 +563,8 @@ public final class Presenter { * @param showDuplicateUnits whether or not duplicate units should be shown * @since 2022-03-30 */ - public void setShowDuplicateUnits(boolean showDuplicateUnits) { - this.showDuplicateUnits = showDuplicateUnits; + public void setShowDuplicates(boolean showDuplicateUnits) { + this.showDuplicates = showDuplicateUnits; this.updateView(); } @@ -589,7 +580,7 @@ public final class Presenter { || u instanceof LinearUnit && ((LinearUnit) u).isBase(); final var definition = isBase ? "(Base unit)" : u.toDefinitionString(); final var dimensionString = this.getDimensionName(u.getDimension()); - final var unitType = this.getUnitType(u); + final var unitType = UnitType.getType(u, this::isSemiMetric); this.view.showUnit(nameSymbol, definition, dimensionString, unitType); } @@ -621,14 +612,36 @@ public final class Presenter { .getDimension(((UnitConversionView) this.view) .getSelectedDimensionName().orElseThrow()); - final Set units = this.database - .unitMapPrefixless(this.showDuplicateUnits).entrySet().stream() + // load units & prefixes into viewers + this.view.setViewableUnitNames( + this.database.unitMapPrefixless(this.showDuplicates).keySet()); + this.view.setViewablePrefixNames( + this.database.prefixMap(this.showDuplicates).keySet()); + + // get From and To units + Stream fromUnits = this.database + .unitMapPrefixless(this.showDuplicates).entrySet().stream() .map(Map.Entry::getValue) - .filter(u -> viewDimension.equals(u.getDimension())) - .map(Unit::getName).collect(Collectors.toSet()); + .filter(u -> viewDimension.equals(u.getDimension())); + + Stream toUnits = this.database + .unitMapPrefixless(this.showDuplicates).entrySet().stream() + .map(Map.Entry::getValue) + .filter(u -> viewDimension.equals(u.getDimension())); + + // filter by unit type, if desired + if (this.oneWayConversionEnabled) { + fromUnits = fromUnits.filter(u -> UnitType.getType(u, + this::isSemiMetric) != UnitType.METRIC); + toUnits = toUnits.filter(u -> UnitType.getType(u, + this::isSemiMetric) != UnitType.NON_METRIC); + } - ucview.setFromUnitNames(units); - ucview.setToUnitNames(units); + // set unit names + ucview.setFromUnitNames( + fromUnits.map(Unit::getName).collect(Collectors.toSet())); + ucview.setToUnitNames( + toUnits.map(Unit::getName).collect(Collectors.toSet())); } } diff --git a/src/main/java/sevenUnitsGUI/TabbedView.java b/src/main/java/sevenUnitsGUI/TabbedView.java index 3a951ef..098c374 100644 --- a/src/main/java/sevenUnitsGUI/TabbedView.java +++ b/src/main/java/sevenUnitsGUI/TabbedView.java @@ -634,11 +634,10 @@ final class TabbedView implements ExpressionConversionView, UnitConversionView { .setAnchor(GridBagConstraints.LINE_START).build()); final JCheckBox showAllVariations = new JCheckBox( - "Show Duplicates in \"Convert Units\""); - showAllVariations.setSelected(this.presenter.duplicateUnitsShown()); - showAllVariations - .addItemListener(e -> this.presenter.setShowDuplicateUnits( - e.getStateChange() == ItemEvent.SELECTED)); + "Show Duplicate Units & Prefixes"); + showAllVariations.setSelected(this.presenter.duplicatesShown()); + showAllVariations.addItemListener(e -> this.presenter + .setShowDuplicates(e.getStateChange() == ItemEvent.SELECTED)); miscPanel.add(showAllVariations, new GridBagBuilder(0, 1) .setAnchor(GridBagConstraints.LINE_START).build()); diff --git a/src/test/java/sevenUnits/unit/UnitDatabaseTest.java b/src/test/java/sevenUnits/unit/UnitDatabaseTest.java index b8669cb..4be33dd 100644 --- a/src/test/java/sevenUnits/unit/UnitDatabaseTest.java +++ b/src/test/java/sevenUnits/unit/UnitDatabaseTest.java @@ -596,7 +596,7 @@ class UnitDatabaseTest { database.addPrefix("C", C); final int NUM_UNITS = database.unitMapPrefixless(true).size(); - final int NUM_PREFIXES = database.prefixMap().size(); + final int NUM_PREFIXES = database.prefixMap(true).size(); final Iterator nameIterator = database.unitMap().keySet() .iterator(); diff --git a/src/test/java/sevenUnitsGUI/PresenterTest.java b/src/test/java/sevenUnitsGUI/PresenterTest.java index f52d846..362a5c9 100644 --- a/src/test/java/sevenUnitsGUI/PresenterTest.java +++ b/src/test/java/sevenUnitsGUI/PresenterTest.java @@ -147,13 +147,13 @@ public final class PresenterTest { presenter.database.addUnit("meter", meter); // test that only one of them is included if duplicate units disabled - presenter.setShowDuplicateUnits(false); + presenter.setShowDuplicates(false); presenter.updateView(); assertEquals(1, viewBot.getFromUnitNames().size()); assertEquals(1, viewBot.getToUnitNames().size()); // test that both of them is included if duplicate units enabled - presenter.setShowDuplicateUnits(true); + presenter.setShowDuplicates(true); presenter.updateView(); assertEquals(2, viewBot.getFromUnitNames().size()); assertEquals(2, viewBot.getToUnitNames().size()); @@ -262,19 +262,19 @@ public final class PresenterTest { // set and save custom settings presenter.setOneWayConversionEnabled(true); - presenter.setShowDuplicateUnits(true); + presenter.setShowDuplicates(true); presenter.setNumberDisplayRule(StandardDisplayRules.fixedPrecision(11)); presenter.saveSettings(TEST_SETTINGS); // overwrite custom settings presenter.setOneWayConversionEnabled(false); - presenter.setShowDuplicateUnits(false); + presenter.setShowDuplicates(false); presenter.setNumberDisplayRule(StandardDisplayRules.uncertaintyBased()); // load settings & test that they're the same presenter.loadSettings(TEST_SETTINGS); assertTrue(presenter.oneWayConversionEnabled()); - assertTrue(presenter.duplicateUnitsShown()); + assertTrue(presenter.duplicatesShown()); assertEquals(StandardDisplayRules.fixedPrecision(11), presenter.getNumberDisplayRule()); } -- cgit v1.2.3