summaryrefslogtreecommitdiff
path: root/src/main/java
diff options
context:
space:
mode:
authorAdrien Hopkins <ahopk127@my.yorku.ca>2022-07-08 10:31:06 -0500
committerAdrien Hopkins <ahopk127@my.yorku.ca>2022-07-08 10:31:06 -0500
commitb80d16bfd2dca34733e5cb37283df93d10805512 (patch)
treedc90cf748a4d754e56ca16845e4b4358dd9bd931 /src/main/java
parent768468b303627c215046cd10cf9e8ba62151ac65 (diff)
parenteba6fb3778b07b10ee321310991d375202f4c9d2 (diff)
Merge branch 'feature-search-settings' into develop
Diffstat (limited to 'src/main/java')
-rw-r--r--src/main/java/sevenUnitsGUI/PrefixSearchRule.java172
-rw-r--r--src/main/java/sevenUnitsGUI/Presenter.java77
-rw-r--r--src/main/java/sevenUnitsGUI/TabbedView.java47
3 files changed, 278 insertions, 18 deletions
diff --git a/src/main/java/sevenUnitsGUI/PrefixSearchRule.java b/src/main/java/sevenUnitsGUI/PrefixSearchRule.java
new file mode 100644
index 0000000..2928082
--- /dev/null
+++ b/src/main/java/sevenUnitsGUI/PrefixSearchRule.java
@@ -0,0 +1,172 @@
+/**
+ * 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 <https://www.gnu.org/licenses/>.
+ */
+package sevenUnitsGUI;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.function.Function;
+import java.util.function.Predicate;
+
+import sevenUnits.unit.LinearUnit;
+import sevenUnits.unit.Metric;
+import sevenUnits.unit.UnitPrefix;
+
+/**
+ * A search rule that applies a certain set of prefixes to a unit. It always
+ * includes the original unit in the output map.
+ *
+ * @since 2022-07-06
+ */
+public final class PrefixSearchRule implements
+ Function<Map.Entry<String, LinearUnit>, Map<String, LinearUnit>> {
+ /**
+ * A rule that does not add any prefixed versions of units.
+ */
+ public static final PrefixSearchRule NO_PREFIXES = getUniversalRule(
+ Set.of());
+
+ /**
+ * A rule that gives every unit a common set of prefixes.
+ */
+ public static final PrefixSearchRule COMMON_PREFIXES = getCoherentOnlyRule(
+ Set.of(Metric.MILLI, Metric.KILO));
+
+ /**
+ * A rule that gives every unit all metric prefixes.
+ */
+ public static final PrefixSearchRule ALL_METRIC_PREFIXES = getCoherentOnlyRule(
+ Metric.ALL_PREFIXES);
+
+ /**
+ * Gets a rule that applies the provided prefixes to coherent units only (as
+ * defined by {@link LinearUnit#isCoherent}), except the kilogram
+ * (specifically, units named "kilogram").
+ *
+ * @param prefixes prefixes to apply
+ * @return prefix rule
+ * @since 2022-07-06
+ */
+ public static final PrefixSearchRule getCoherentOnlyRule(
+ Set<UnitPrefix> prefixes) {
+ return new PrefixSearchRule(prefixes,
+ u -> u.isCoherent() && !u.getName().equals("kilogram"));
+ }
+
+ /**
+ * Gets a rule that applies the provided prefixes to all units.
+ *
+ * @param prefixes prefixes to apply
+ * @return prefix rule
+ * @since 2022-07-06
+ */
+ public static final PrefixSearchRule getUniversalRule(
+ Set<UnitPrefix> prefixes) {
+ return new PrefixSearchRule(prefixes, u -> true);
+ }
+
+ /**
+ * The set of prefixes that will be applied to the unit.
+ */
+ private final Set<UnitPrefix> prefixes;
+
+ /**
+ * Determines which units are given prefixes.
+ */
+ private final Predicate<LinearUnit> allowUnit;
+
+ /**
+ * @param prefixes
+ * @param metricOnly
+ * @since 2022-07-06
+ */
+ public PrefixSearchRule(Set<UnitPrefix> prefixes,
+ Predicate<LinearUnit> allowUnit) {
+ this.prefixes = Collections.unmodifiableSet(new HashSet<>(prefixes));
+ this.allowUnit = allowUnit;
+ }
+
+ @Override
+ public Map<String, LinearUnit> apply(Entry<String, LinearUnit> t) {
+ final Map<String, LinearUnit> outputUnits = new HashMap<>();
+ final String originalName = t.getKey();
+ final LinearUnit originalUnit = t.getValue();
+ outputUnits.put(originalName, originalUnit);
+ if (this.allowUnit.test(originalUnit)) {
+ for (final UnitPrefix prefix : this.prefixes) {
+ outputUnits.put(prefix.getName() + originalName,
+ originalUnit.withPrefix(prefix));
+ }
+ }
+ return outputUnits;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (!(obj instanceof PrefixSearchRule))
+ return false;
+ final PrefixSearchRule other = (PrefixSearchRule) obj;
+ if (this.allowUnit == null) {
+ if (other.allowUnit != null)
+ return false;
+ } else if (!this.allowUnit.equals(other.allowUnit))
+ return false;
+ if (this.prefixes == null) {
+ if (other.prefixes != null)
+ return false;
+ } else if (!this.prefixes.equals(other.prefixes))
+ return false;
+ return true;
+ }
+
+ /**
+ * @return the allowUnit
+ * @since 2022-07-06
+ */
+ public Predicate<LinearUnit> getAllowUnit() {
+ return this.allowUnit;
+ }
+
+ /**
+ * @return the prefixes that are applied by this rule
+ * @since 2022-07-06
+ */
+ public Set<UnitPrefix> getPrefixes() {
+ return this.prefixes;
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result
+ + (this.allowUnit == null ? 0 : this.allowUnit.hashCode());
+ result = prime * result
+ + (this.prefixes == null ? 0 : this.prefixes.hashCode());
+ return result;
+ }
+
+ @Override
+ public String toString() {
+ return "Apply the following prefixes: " + this.prefixes;
+ }
+}
diff --git a/src/main/java/sevenUnitsGUI/Presenter.java b/src/main/java/sevenUnitsGUI/Presenter.java
index 4feea44..a5c4d48 100644
--- a/src/main/java/sevenUnitsGUI/Presenter.java
+++ b/src/main/java/sevenUnitsGUI/Presenter.java
@@ -32,6 +32,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;
@@ -195,6 +196,13 @@ public final class Presenter {
private Predicate<List<UnitPrefix>> prefixRepetitionRule = DefaultPrefixRepetitionRule.NO_RESTRICTION;
/**
+ * A rule that accepts a prefixless name-unit pair and returns a map mapping
+ * names to prefixed versions of that unit (including the unit itself) that
+ * should be searchable.
+ */
+ private Function<Map.Entry<String, LinearUnit>, Map<String, LinearUnit>> searchRule = PrefixSearchRule.NO_PREFIXES;
+
+ /**
* The set of units that is considered neither metric nor nonmetric for the
* purposes of the metric-imperial one-way conversion. These units are
* included in both From and To, even if One Way Conversion is enabled.
@@ -275,6 +283,26 @@ public final class Presenter {
}
/**
+ * Applies a search rule to an entry in a name-unit map.
+ *
+ * @param e entry
+ * @return stream of entries, ready for flat-mapping
+ * @since 2022-07-06
+ */
+ private final Stream<Map.Entry<String, Unit>> applySearchRule(
+ Map.Entry<String, Unit> e) {
+ final Unit u = e.getValue();
+ if (u instanceof LinearUnit) {
+ final String name = e.getKey();
+ final Map.Entry<String, LinearUnit> linearEntry = Map.entry(name,
+ (LinearUnit) u);
+ return this.searchRule.apply(linearEntry).entrySet().stream().map(
+ entry -> Map.entry(entry.getKey(), (Unit) entry.getValue()));
+ } else
+ return Stream.of(e);
+ }
+
+ /**
* Converts from the view's input expression to its output expression.
* Displays an error message if any of the required fields are invalid.
*
@@ -490,6 +518,23 @@ public final class Presenter {
}
/**
+ * @return the rule that determines which units are prefixed
+ * @since 2022-07-08
+ */
+ public Function<Map.Entry<String, LinearUnit>, Map<String, LinearUnit>> getSearchRule() {
+ return this.searchRule;
+ }
+
+ /**
+ * @return a search rule that shows all single prefixes
+ * @since 2022-07-08
+ */
+ public Function<Map.Entry<String, LinearUnit>, Map<String, LinearUnit>> getUniversalSearchRule() {
+ return PrefixSearchRule.getCoherentOnlyRule(
+ new HashSet<>(this.database.prefixMap(true).values()));
+ }
+
+ /**
* @return the view associated with this presenter
* @since 2022-04-19
*/
@@ -551,6 +596,16 @@ public final class Presenter {
case "include_duplicates":
this.showDuplicates = Boolean.valueOf(value);
break;
+ case "search_prefix_rule":
+ if (PrefixSearchRule.NO_PREFIXES.toString().equals(value)) {
+ this.searchRule = PrefixSearchRule.NO_PREFIXES;
+ } else if (PrefixSearchRule.COMMON_PREFIXES.toString()
+ .equals(value)) {
+ this.searchRule = PrefixSearchRule.COMMON_PREFIXES;
+ } else {
+ this.searchRule = this.getUniversalSearchRule();
+ }
+ break;
default:
System.err.printf("Warning: unrecognized setting \"%s\".%n",
param);
@@ -628,6 +683,8 @@ public final class Presenter {
String.format("one_way=%s\n", this.oneWayConversionEnabled));
writer.write(
String.format("include_duplicates=%s\n", this.showDuplicates));
+ writer.write(
+ String.format("search_prefix_rule=%s\n", this.searchRule));
} catch (final IOException e) {
e.printStackTrace();
this.view.showErrorMessage("I/O Error",
@@ -680,6 +737,18 @@ public final class Presenter {
}
/**
+ * @param searchRule A rule that accepts a prefixless name-unit pair and
+ * returns a map mapping names to prefixed versions of that
+ * unit (including the unit itself) that should be
+ * searchable.
+ * @since 2022-07-08
+ */
+ public void setSearchRule(
+ Function<Map.Entry<String, LinearUnit>, Map<String, LinearUnit>> searchRule) {
+ this.searchRule = searchRule;
+ }
+
+ /**
* @param showDuplicateUnits whether or not duplicate units should be shown
* @since 2022-03-30
*/
@@ -761,10 +830,10 @@ public final class Presenter {
}
// set unit names
- ucview.setFromUnitNames(
- fromUnits.map(Map.Entry::getKey).collect(Collectors.toSet()));
- ucview.setToUnitNames(
- toUnits.map(Map.Entry::getKey).collect(Collectors.toSet()));
+ ucview.setFromUnitNames(fromUnits.flatMap(this::applySearchRule)
+ .map(Map.Entry::getKey).collect(Collectors.toSet()));
+ ucview.setToUnitNames(toUnits.flatMap(this::applySearchRule)
+ .map(Map.Entry::getKey).collect(Collectors.toSet()));
}
}
diff --git a/src/main/java/sevenUnitsGUI/TabbedView.java b/src/main/java/sevenUnitsGUI/TabbedView.java
index be80ccb..e3b5610 100644
--- a/src/main/java/sevenUnitsGUI/TabbedView.java
+++ b/src/main/java/sevenUnitsGUI/TabbedView.java
@@ -531,33 +531,52 @@ final class TabbedView implements ExpressionConversionView, UnitConversionView {
// searching rules
final ButtonGroup searchRuleButtons = new ButtonGroup();
+ final var searchRule = this.presenter.getSearchRule();
+
final JRadioButton noPrefixes = new JRadioButton(
"Never Include Prefixed Units");
- noPrefixes.setEnabled(false);
+ 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 fixedPrefixes = new JRadioButton(
- "Include Some Prefixes");
- fixedPrefixes.setEnabled(false);
- searchRuleButtons.add(fixedPrefixes);
- searchingPanel.add(fixedPrefixes, new GridBagBuilder(0, 1)
- .setAnchor(GridBagConstraints.LINE_START).build());
-
- final JRadioButton explicitPrefixes = new JRadioButton(
- "Include Explicit Prefixes");
- explicitPrefixes.setEnabled(false);
- searchRuleButtons.add(explicitPrefixes);
- searchingPanel.add(explicitPrefixes, new GridBagBuilder(0, 2)
+ 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.setEnabled(false);
+ 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 ============