summaryrefslogtreecommitdiff
path: root/BJC-Utils2
diff options
context:
space:
mode:
authorbculkin2442 <bjculkin@mix.wvu.edu>2016-01-26 11:32:41 -0500
committerbculkin2442 <bjculkin@mix.wvu.edu>2016-01-26 11:32:41 -0500
commitd8b3b3c5e4441cecec98c06a36fc81570008c888 (patch)
treef71e260819ef4fdf1297ae0cc43c6a1dc4092eb9 /BJC-Utils2
parent6de1845151db750c8dbbc6b12964c4d6e6144eaf (diff)
Updates to various things, and addition of a graph class.
Diffstat (limited to 'BJC-Utils2')
-rw-r--r--BJC-Utils2/src/main/java/bjc/utils/funcdata/FunctionalList.java199
-rw-r--r--BJC-Utils2/src/main/java/bjc/utils/funcdata/FunctionalStringTokenizer.java40
-rw-r--r--BJC-Utils2/src/main/java/bjc/utils/gen/WeightedGrammar.java222
-rw-r--r--BJC-Utils2/src/main/java/bjc/utils/gen/WeightedRandom.java19
-rw-r--r--BJC-Utils2/src/main/java/bjc/utils/graph/AdjacencyMap.java100
-rw-r--r--BJC-Utils2/src/main/java/bjc/utils/graph/Edge.java30
-rw-r--r--BJC-Utils2/src/main/java/bjc/utils/graph/GenHolder.java75
-rw-r--r--BJC-Utils2/src/main/java/bjc/utils/graph/Graph.java236
-rw-r--r--BJC-Utils2/src/main/java/bjc/utils/gui/SimpleDialogs.java142
-rw-r--r--BJC-Utils2/src/main/java/bjc/utils/gui/SimpleJList.java6
-rw-r--r--BJC-Utils2/src/main/java/bjc/utils/gui/awt/ExtensionFileFilter.java37
-rw-r--r--BJC-Utils2/src/main/java/bjc/utils/gui/awt/SimpleFileDialog.java58
12 files changed, 1025 insertions, 139 deletions
diff --git a/BJC-Utils2/src/main/java/bjc/utils/funcdata/FunctionalList.java b/BJC-Utils2/src/main/java/bjc/utils/funcdata/FunctionalList.java
index 73ace88..88db172 100644
--- a/BJC-Utils2/src/main/java/bjc/utils/funcdata/FunctionalList.java
+++ b/BJC-Utils2/src/main/java/bjc/utils/funcdata/FunctionalList.java
@@ -13,16 +13,19 @@ import java.util.function.Function;
import java.util.function.Predicate;
import bjc.utils.data.GenHolder;
+import bjc.utils.data.Pair;
/**
- * A wrapper over another list that provides eager functional operations over it.
- * Differs from a stream in every way except for the fact that they both provide functional
- * operations.
+ * A wrapper over another list that provides eager functional operations
+ * over it. Differs from a stream in every way except for the fact that
+ * they both provide functional operations.
+ *
* @author ben
*
- * @param <E> The type in this list
+ * @param <E>
+ * The type in this list
*/
-public class FunctionalList<E> {
+public class FunctionalList<E> implements Cloneable {
private List<E> wrap;
/**
@@ -34,7 +37,9 @@ public class FunctionalList<E> {
/**
* Create a new functional list containing the specified items.
- * @param items The items to put into this functional list.
+ *
+ * @param items
+ * The items to put into this functional list.
*/
@SafeVarargs
public FunctionalList(E... items) {
@@ -46,26 +51,32 @@ public class FunctionalList<E> {
}
/**
- * Create a functional list using the same backing list as the provided list.
+ * Create a functional list using the same backing list as the provided
+ * list.
*
- * @param fl The source for a backing list
+ * @param fl
+ * The source for a backing list
*/
- public FunctionalList(FunctionalList<E> fl) {
+ public FunctionalList(FunctionalList<E> fl) {
// TODO Find out if this should make a copy of fl.wrap instead.
wrap = fl.wrap;
}
/**
* Create a new functional list with the specified size.
- * @param sz The size of the backing list .
+ *
+ * @param sz
+ * The size of the backing list .
*/
private FunctionalList(int sz) {
wrap = new ArrayList<>(sz);
}
-
+
/**
* Create a new functional list as a wrapper of a existing list.
- * @param l The list to use as a backing list.
+ *
+ * @param l
+ * The list to use as a backing list.
*/
public FunctionalList(List<E> l) {
wrap = l;
@@ -73,17 +84,31 @@ public class FunctionalList<E> {
/**
* Add an item to this list
- * @param item The item to add to this list.
+ *
+ * @param item
+ * The item to add to this list.
* @return Whether the item was added to the list succesfully.
*/
public boolean add(E item) {
return wrap.add(item);
}
+
+ /**
+ * Prepend an item to the list
+ * @param item The item to prepend to the list
+ */
+ public void prepend(E item) {
+ wrap.add(0, item);
+ }
/**
- * Check if all of the elements of this list match the specified predicate.
- * @param p The predicate to use for checking.
- * @return Whether all of the elements of the list match the specified predicate.
+ * Check if all of the elements of this list match the specified
+ * predicate.
+ *
+ * @param p
+ * The predicate to use for checking.
+ * @return Whether all of the elements of the list match the specified
+ * predicate.
*/
public boolean allMatch(Predicate<E> p) {
for (E item : wrap) {
@@ -96,8 +121,11 @@ public class FunctionalList<E> {
/**
* Check if any of the elements in this list match the specified list.
- * @param p The predicate to use for checking.
- * @return Whether any element in the list matches the provided predicate.
+ *
+ * @param p
+ * The predicate to use for checking.
+ * @return Whether any element in the list matches the provided
+ * predicate.
*/
public boolean anyMatch(Predicate<E> p) {
for (E item : wrap) {
@@ -109,29 +137,36 @@ public class FunctionalList<E> {
}
/**
- * Combine this list with another one into a new list and merge the results.
- * Works sort of like a combined zip/map over resulting pairs.
- * Does not change the underlying list.
+ * Combine this list with another one into a new list and merge the
+ * results. Works sort of like a combined zip/map over resulting pairs.
+ * Does not change the underlying list.
+ *
+ * NOTE: The returned list will have the length of the shorter of this
+ * list and the combined one.
*
- * NOTE: The returned list will have the length of the shorter of this list and the combined one.
- * @param l The list to combine with
- * @param bf The function to use for combining element pairs.
+ * @param l
+ * The list to combine with
+ * @param bf
+ * The function to use for combining element pairs.
* @return A new list containing the merged pairs of lists.
*/
- public <T, F> FunctionalList<F> combineWith(FunctionalList<T> l, BiFunction<E, T, F> bf) {
+ public <T, F> FunctionalList<F> combineWith(FunctionalList<T> l,
+ BiFunction<E, T, F> bf) {
FunctionalList<F> r = new FunctionalList<>();
-
+
Iterator<T> i2 = l.wrap.iterator();
-
- for (Iterator<E> i1 = wrap.iterator(); i1.hasNext() && i2.hasNext();) {
+
+ for (Iterator<E> i1 = wrap.iterator(); i1.hasNext()
+ && i2.hasNext();) {
r.add(bf.apply(i1.next(), i2.next()));
}
-
+
return r;
}
/**
* Get the first element in the list
+ *
* @return The first element in this list.
*/
public E first() {
@@ -139,10 +174,13 @@ public class FunctionalList<E> {
}
/**
- * Apply a function to each member of the list, then flatten the results.
- * Does not change the underlying list.
- * @param f The function to apply to each member of the list.
- * @return A new list containing the flattened results of applying the provided function.
+ * Apply a function to each member of the list, then flatten the
+ * results. Does not change the underlying list.
+ *
+ * @param f
+ * The function to apply to each member of the list.
+ * @return A new list containing the flattened results of applying the
+ * provided function.
*/
public <T> FunctionalList<T> flatMap(Function<E, List<T>> f) {
FunctionalList<T> fl = new FunctionalList<>(this.wrap.size());
@@ -158,7 +196,9 @@ public class FunctionalList<E> {
/**
* Apply a given action for each member of the list
- * @param c The action to apply to each member of the list.
+ *
+ * @param c
+ * The action to apply to each member of the list.
*/
public void forEach(Consumer<E> c) {
wrap.forEach(c);
@@ -166,7 +206,10 @@ public class FunctionalList<E> {
/**
* Apply a given function to each element in the list and its index.
- * @param c The function to apply to each element in the list and its index.
+ *
+ * @param c
+ * The function to apply to each element in the list and its
+ * index.
*/
public void forEachIndexed(BiConsumer<Integer, E> c) {
int i = 0;
@@ -178,7 +221,9 @@ public class FunctionalList<E> {
/**
* Retrieve a value in the list by its index.
- * @param i The index to retrieve a value from.
+ *
+ * @param i
+ * The index to retrieve a value from.
* @return The value at the specified index in the list.
*/
public E getByIndex(int i) {
@@ -187,6 +232,7 @@ public class FunctionalList<E> {
/**
* Get the internal backing list.
+ *
* @return The backing list this list is based off of.
*/
public List<E> getInternal() {
@@ -195,6 +241,7 @@ public class FunctionalList<E> {
/**
* Check if this list is empty.
+ *
* @return Whether or not this list is empty.
*/
public boolean isEmpty() {
@@ -202,9 +249,11 @@ public class FunctionalList<E> {
}
/**
- * Create a new list by applying the given function to each element in the list.
- * Does not change the underlying list.
- * @param f The function to apply to each element in the list
+ * Create a new list by applying the given function to each element in
+ * the list. Does not change the underlying list.
+ *
+ * @param f
+ * The function to apply to each element in the list
* @return A new list containing the mapped elements of this list.
*/
public <T> FunctionalList<T> map(Function<E, T> f) {
@@ -216,8 +265,11 @@ public class FunctionalList<E> {
}
/**
- * Select a random item from this list, using the provided random number generator.
- * @param rnd The random number generator to use.
+ * Select a random item from this list, using the provided random
+ * number generator.
+ *
+ * @param rnd
+ * The random number generator to use.
* @return A random element from this list.
*/
public E randItem(Random rnd) {
@@ -226,27 +278,38 @@ public class FunctionalList<E> {
/**
* Reduce this list to a single value, using a accumulative approach.
- * @param val The initial value of the accumulative state.
- * @param bf The function to use to combine a list element with the accumulative state.
- * @param finl The function to use to convert the accumulative state into a final result.
- * @return A single value condensed from this list and transformed into its final state.
+ *
+ * @param val
+ * The initial value of the accumulative state.
+ * @param bf
+ * The function to use to combine a list element with the
+ * accumulative state.
+ * @param finl
+ * The function to use to convert the accumulative state
+ * into a final result.
+ * @return A single value condensed from this list and transformed into
+ * its final state.
*/
- public <T, F> F reduceAux(T val, BiFunction<E, T, T> bf, Function<T, F> finl) {
+ public <T, F> F reduceAux(T val, BiFunction<E, T, T> bf,
+ Function<T, F> finl) {
GenHolder<T> acum = new GenHolder<>(val);
-
+
wrap.forEach(e -> {
acum.held = bf.apply(e, acum.held);
});
-
+
return finl.apply(acum.held);
}
/**
- * Perform a binary search for the specified key using the provided means of
- * comparing elements.
- * Since this IS a binary search, the list must have been sorted before hand.
- * @param key The key to search for.
- * @param cmp The way to compare elements for searching
+ * Perform a binary search for the specified key using the provided
+ * means of comparing elements. Since this IS a binary search, the list
+ * must have been sorted before hand.
+ *
+ * @param key
+ * The key to search for.
+ * @param cmp
+ * The way to compare elements for searching
* @return The element if it is in this list, or null if it is not.
*/
public E search(E key, Comparator<E> cmp) {
@@ -254,19 +317,22 @@ public class FunctionalList<E> {
return (res >= 0) ? wrap.get(res) : null;
}
-
+
/**
- * Sort the elements of this list using the provided way of comparing elements.
- * Does change the underlying list.
- * @param cmp The way to compare elements for sorting.
+ * Sort the elements of this list using the provided way of comparing
+ * elements. Does change the underlying list.
+ *
+ * @param cmp
+ * The way to compare elements for sorting.
*/
public void sort(Comparator<E> cmp) {
Collections.sort(wrap, cmp);
}
-
+
/*
* Reduce this item to a form useful for looking at in the debugger.
* (non-Javadoc)
+ *
* @see java.lang.Object#toString()
*/
public String toString() {
@@ -274,9 +340,24 @@ public class FunctionalList<E> {
forEach(s -> sb.append(s + ", "));
- sb.deleteCharAt(sb.length());
+ sb.deleteCharAt(sb.length() - 1);
sb.append(")");
return sb.toString();
}
+
+ public <T> FunctionalList<Pair<E, T>> pairWith(FunctionalList<T> fl) {
+ return combineWith(fl, Pair<E, T>::new);
+ }
+
+ @Override
+ public FunctionalList<E> clone() {
+ FunctionalList<E> fl = new FunctionalList<>();
+
+ for (E ele : wrap) {
+ fl.add(ele);
+ }
+
+ return fl;
+ }
}
diff --git a/BJC-Utils2/src/main/java/bjc/utils/funcdata/FunctionalStringTokenizer.java b/BJC-Utils2/src/main/java/bjc/utils/funcdata/FunctionalStringTokenizer.java
index 0fe8421..9ee6b60 100644
--- a/BJC-Utils2/src/main/java/bjc/utils/funcdata/FunctionalStringTokenizer.java
+++ b/BJC-Utils2/src/main/java/bjc/utils/funcdata/FunctionalStringTokenizer.java
@@ -6,6 +6,7 @@ import java.util.function.Function;
/**
* A string tokenizer that exposes a functional interface
+ *
* @author ben
*
*/
@@ -14,35 +15,46 @@ public class FunctionalStringTokenizer {
/**
* Create a functional string tokenizer from a non-functional one
- * @param inp The non-functional string tokenizer to wrap
+ *
+ * @param inp
+ * The non-functional string tokenizer to wrap
*/
public FunctionalStringTokenizer(StringTokenizer inp) {
this.inp = inp;
}
-
+
+ public FunctionalStringTokenizer(String inp) {
+ this.inp = new StringTokenizer(inp);
+ }
+
/**
* Execute a provided action for each of the remaining tokens
- * @param f The action to execute for each token
+ *
+ * @param f
+ * The action to execute for each token
*/
public void forEachToken(Consumer<String> f) {
- while(inp.hasMoreTokens()) {
+ while (inp.hasMoreTokens()) {
f.accept(inp.nextToken());
}
}
-
+
/**
- * Return the next token from the tokenizer
- * Returns null if no more tokens are available
+ * Return the next token from the tokenizer Returns null if no more
+ * tokens are available
+ *
* @return The next token from the tokenizer
*/
public String nextToken() {
return inp.hasMoreTokens() ? inp.nextToken() : null;
}
-
+
/**
- * Convert the contents of this tokenizer into a list.
- * Consumes all of the input from this tokenizer.
- * @param f The function to use to convert tokens.
+ * Convert the contents of this tokenizer into a list. Consumes all of
+ * the input from this tokenizer.
+ *
+ * @param f
+ * The function to use to convert tokens.
* @return A list containing all of the converted tokens.
*/
public <E> FunctionalList<E> toList(Function<String, E> f) {
@@ -52,10 +64,12 @@ public class FunctionalStringTokenizer {
return r;
}
-
+
/**
* Create a new tokenizer from the specified string.
- * @param s The string to create a tokenizer from.
+ *
+ * @param s
+ * The string to create a tokenizer from.
* @return A new tokenizer that splits the provided string on spaces.
*/
public static FunctionalStringTokenizer fromString(String s) {
diff --git a/BJC-Utils2/src/main/java/bjc/utils/gen/WeightedGrammar.java b/BJC-Utils2/src/main/java/bjc/utils/gen/WeightedGrammar.java
index 8733723..228f14d 100644
--- a/BJC-Utils2/src/main/java/bjc/utils/gen/WeightedGrammar.java
+++ b/BJC-Utils2/src/main/java/bjc/utils/gen/WeightedGrammar.java
@@ -1,46 +1,55 @@
package bjc.utils.gen;
-import java.util.HashMap;
+import java.util.Hashtable;
import java.util.Map;
import java.util.Random;
+import java.util.Set;
import java.util.function.Function;
+import bjc.utils.data.Pair;
import bjc.utils.funcdata.FunctionalList;
/**
- * A random grammar, where certain rules will come up morre often than
+ * A random grammar, where certain rules will come up more often than
* others.
*
* @author ben
*
- * @param <E> The values that make up sentances of this grammar.
+ * @param <E>
+ * The values that make up sentances of this grammar.
*/
public class WeightedGrammar<E> {
+ protected String initRule;
protected Map<E, WeightedRandom<FunctionalList<E>>> rules;
+ private Random sr;
protected Map<E, WeightedGrammar<E>> subgrammars;
- private Random sr;
/**
- * Create a new weighted grammar that uses the specified source of randomness.
+ * Create a new weighted grammar.
*/
- public WeightedGrammar(Random src) {
- this();
- sr = src;
+ public WeightedGrammar() {
+ rules = new Hashtable<>();
+ subgrammars = new Hashtable<>();
}
-
+
/**
- * Create a new weighted grammar.
+ * Create a new weighted grammar that uses the specified source of
+ * randomness.
*/
- public WeightedGrammar() {
- rules = new HashMap<>();
+ public WeightedGrammar(Random src) {
+ this();
+ sr = src;
}
/**
* Add a case to an already existing rule.
*
- * @param rule The rule to add a case to.
- * @param prob The probability for this rule to be chosen.
- * @param cse The case being added.
+ * @param rule
+ * The rule to add a case to.
+ * @param prob
+ * The probability for this rule to be chosen.
+ * @param cse
+ * The case being added.
*/
public void addCase(E rule, int prob, FunctionalList<E> cse) {
WeightedRandom<FunctionalList<E>> rn = rules.get(rule);
@@ -48,13 +57,28 @@ public class WeightedGrammar<E> {
rn.addProb(prob, cse);
}
+ public boolean addGrammarAlias(E name, E alias) {
+ if (subgrammars.containsKey(alias)) {
+ return false;
+ } else {
+ if (subgrammars.containsKey(name)) {
+ subgrammars.put(alias, subgrammars.get(name));
+ return true;
+ } else {
+ return false;
+ }
+ }
+ }
+
/**
* Add a new rule with no cases.
- * @param name The name of the rule to add.
+ *
+ * @param name
+ * The name of the rule to add.
* @return Whether or not the rule was succesfully added.
*/
public boolean addRule(E name) {
- if(sr == null) {
+ if (sr == null) {
sr = new Random();
}
return addRule(name, new WeightedRandom<>(sr));
@@ -62,8 +86,11 @@ public class WeightedGrammar<E> {
/**
* Add a new rule with a set of cases.
- * @param name The name of the rule to add.
- * @param rnd The set of cases for the rule.
+ *
+ * @param name
+ * The name of the rule to add.
+ * @param rnd
+ * The set of cases for the rule.
* @return Whether or not the rule was succesfully added.
*/
public boolean addRule(E name, WeightedRandom<FunctionalList<E>> rnd) {
@@ -77,8 +104,11 @@ public class WeightedGrammar<E> {
/**
* Add a subgrammar.
- * @param name The name of the subgrammar.
- * @param subG The subgrammar to add.
+ *
+ * @param name
+ * The name of the subgrammar.
+ * @param subG
+ * The subgrammar to add.
* @return Whether or not the subgrammar was succesfully added.
*/
public boolean addSubGrammar(E name, WeightedGrammar<E> subG) {
@@ -91,9 +121,11 @@ public class WeightedGrammar<E> {
}
/**
- * Generate a set of debug sentences for the specified rule.
- * Only generates sentances one layer deep.
- * @param rl The rule to test.
+ * Generate a set of debug sentences for the specified rule. Only
+ * generates sentances one layer deep.
+ *
+ * @param rl
+ * The rule to test.
* @return A set of sentances generated by the specified rule.
*/
public FunctionalList<FunctionalList<E>> debugVals(E rl) {
@@ -111,10 +143,14 @@ public class WeightedGrammar<E> {
/**
* Generate a generic sentance from a initial rule.
*
- * @param initRule The initial rule to start with.
- * @param f The function to transform grammar output into something.
- * @param spacer The spacer element to add in between output tokens.
- * @return A randomly generated sentance from the specified initial rule.
+ * @param initRule
+ * The initial rule to start with.
+ * @param f
+ * The function to transform grammar output into something.
+ * @param spacer
+ * The spacer element to add in between output tokens.
+ * @return A randomly generated sentance from the specified initial
+ * rule.
*/
public <T> FunctionalList<T> genGeneric(E initRule, Function<E, T> f,
T spacer) {
@@ -141,18 +177,29 @@ public class WeightedGrammar<E> {
}
/**
- * Generate a random list of grammar elements from a given initial rule.
- * @param initRule The initial rule to start with.
- * @param spacer The item to use to space the list.
- * @return A list of random grammar elements generated by the specified rule.
+ * Generate a random list of grammar elements from a given initial
+ * rule.
+ *
+ * @param initRule
+ * The initial rule to start with.
+ * @param spacer
+ * The item to use to space the list.
+ * @return A list of random grammar elements generated by the specified
+ * rule.
*/
public FunctionalList<E> genList(E initRule, E spacer) {
return genGeneric(initRule, s -> s, spacer);
}
+ public String getInitRule() {
+ return initRule;
+ }
+
/**
* Get the subgrammar with the specified name.
- * @param name The name of the subgrammar to get.
+ *
+ * @param name
+ * The name of the subgrammar to get.
* @return The subgrammar with the specified name.
*/
public WeightedGrammar<E> getSubGrammar(E name) {
@@ -160,8 +207,68 @@ public class WeightedGrammar<E> {
}
/**
+ * Create a series of alternatives for a rule by prefixing them with a
+ * given token
+ *
+ * @param addProb
+ * The amount to adjust the probability by
+ * @param rName
+ * The name of the rule to prefix
+ * @param prefixToken
+ * The token to prefix to the rule
+ */
+ public void prefixRule(E rName, E prefixToken, int addProb) {
+ WeightedRandom<FunctionalList<E>> rule = rules.get(rName);
+
+ FunctionalList<Pair<Integer, FunctionalList<E>>> newResults = new FunctionalList<>();
+
+ rule.getValues().forEach((par) -> {
+ FunctionalList<E> nl = par.r.clone();
+ nl.prepend(prefixToken);
+
+ newResults.add(new Pair<>(par.l + addProb, nl));
+ });
+
+ newResults.forEach((par) -> {
+ addCase(rName, par.l, par.r);
+ });
+ }
+
+ public void multiPrefixRule(E rName, E prefixToken, int addProb,
+ int nTimes) {
+ WeightedRandom<FunctionalList<E>> rule = rules.get(rName);
+
+ FunctionalList<Pair<Integer, FunctionalList<E>>> newResults = new FunctionalList<>();
+
+ rule.getValues().forEach((par) -> {
+ FunctionalList<FunctionalList<E>> nls = new FunctionalList<>();
+
+ // TODO bugtest this. if it works, write multiSuffixWith
+ for (int i = 1; i <= nTimes; i++) {
+ FunctionalList<E> nl = par.r.clone();
+
+ for (int j = 1; j <= i; j++) {
+ nl.prepend(prefixToken);
+ }
+
+ nls.add(nl);
+ }
+
+ nls.forEach((ls) -> {
+ newResults.add(new Pair<>(par.l + addProb, ls));
+ });
+ });
+
+ newResults.forEach((par) -> {
+ addCase(rName, par.l, par.r);
+ });
+ }
+
+ /**
* Remove a rule with the specified name.
- * @param name The name of the rule to remove.
+ *
+ * @param name
+ * The name of the rule to remove.
*/
public void removeRule(E name) {
rules.remove(name);
@@ -169,9 +276,54 @@ public class WeightedGrammar<E> {
/**
* Remove a subgrammar with the specified name.
- * @param name The name of the subgrammar to remove.
+ *
+ * @param name
+ * The name of the subgrammar to remove.
*/
public void removeSubgrammar(E name) {
subgrammars.remove(name);
}
+
+ /**
+ * Returns the number of rules in this grammar
+ *
+ * @return The number of rules in this grammar
+ */
+ public int ruleCount() {
+ return rules.size();
+ }
+
+ /**
+ * Returns a set containing all of the rules in this grammar
+ *
+ * @return The set of all rule names in this grammar
+ */
+ public Set<E> ruleNames() {
+ return rules.keySet();
+ }
+
+ public void setInitRule(String initRule) {
+ this.initRule = initRule;
+ }
+
+ public void suffixRule(E rName, E prefixToken, int addProb) {
+ WeightedRandom<FunctionalList<E>> rule = rules.get(rName);
+
+ FunctionalList<Pair<Integer, FunctionalList<E>>> newResults = new FunctionalList<>();
+
+ rule.getValues().forEach((par) -> {
+ FunctionalList<E> nl = par.r.clone();
+ nl.add(prefixToken);
+
+ newResults.add(new Pair<>(par.l + addProb, nl));
+ });
+
+ newResults.forEach((par) -> {
+ addCase(rName, par.l, par.r);
+ });
+ }
+
+ public boolean hasInitRule() {
+ return initRule != null && !initRule.equalsIgnoreCase("");
+ }
}
diff --git a/BJC-Utils2/src/main/java/bjc/utils/gen/WeightedRandom.java b/BJC-Utils2/src/main/java/bjc/utils/gen/WeightedRandom.java
index ecd4e36..4313360 100644
--- a/BJC-Utils2/src/main/java/bjc/utils/gen/WeightedRandom.java
+++ b/BJC-Utils2/src/main/java/bjc/utils/gen/WeightedRandom.java
@@ -1,9 +1,9 @@
package bjc.utils.gen;
import java.util.Random;
-
import bjc.utils.funcdata.FunctionalList;
import bjc.utils.data.GenHolder;
+import bjc.utils.data.Pair;
/**
* Represents a random number generator where certain results are weighted more heavily than
@@ -65,4 +65,21 @@ public class WeightedRandom<E> {
return res.held;
}
+
+ /**
+ * Return a list containing values that can be generated paired
+ * with the probability of those values being generated
+ * @return A list of pairs of values and value probabilities
+ */
+ public FunctionalList<Pair<Integer, E>> getValues() {
+ return probs.pairWith(results);
+ }
+
+ /**
+ * Return a list of values that can be generated by this generator
+ * @return A list of all the values that can be generated
+ */
+ public FunctionalList<E> getResults() {
+ return results;
+ }
}
diff --git a/BJC-Utils2/src/main/java/bjc/utils/graph/AdjacencyMap.java b/BJC-Utils2/src/main/java/bjc/utils/graph/AdjacencyMap.java
new file mode 100644
index 0000000..7a79233
--- /dev/null
+++ b/BJC-Utils2/src/main/java/bjc/utils/graph/AdjacencyMap.java
@@ -0,0 +1,100 @@
+package bjc.utils.graph;
+
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.PrintStream;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Scanner;
+import java.util.Set;
+import java.util.stream.IntStream;
+
+public class AdjacencyMap<T> {
+ private Map<T, Map<T, Integer>> adjMap;
+
+ public AdjacencyMap(Set<T> vertices) {
+ vertices.forEach(src -> {
+ Map<T, Integer> srcRow = new HashMap<>();
+
+ vertices.forEach(tgt -> srcRow.put(tgt, 0));
+
+ adjMap.put(src, srcRow);
+ });
+ }
+
+ public boolean isDirected() {
+ GenHolder<Boolean> res = new GenHolder<>(true);
+
+ adjMap.entrySet()
+ .forEach(src -> src.getValue().entrySet().forEach(tgt -> {
+ int lhs = tgt.getValue();
+ int rhs = adjMap.get(tgt.getKey()).get(src.getKey());
+
+ if (lhs != rhs) {
+ res.held = false;
+ }
+ }));
+
+ return res.held;
+ }
+
+ public void setWeight(T src, T tgt, int weight) {
+ adjMap.get(src).put(tgt, weight);
+ }
+
+ public Graph<T> toGraph() {
+ Graph<T> ret = new Graph<>();
+
+ adjMap.entrySet()
+ .forEach(src -> src.getValue().entrySet()
+ .forEach(tgt -> ret.addEdge(src.getKey(),
+ tgt.getKey(), tgt.getValue())));
+
+ return ret;
+ }
+
+ public static AdjacencyMap<Integer> fromStream(InputStream stream) {
+ Scanner scn = new Scanner(stream);
+ scn.useDelimiter("\n");
+
+ // First, read in number of vertices
+ int numVertices = Integer.parseInt(scn.next());
+
+ Set<Integer> vertices = new HashSet<>();
+ IntStream.range(0, numVertices).forEach(e -> vertices.add(e));
+
+ // Create the adjacency map
+ AdjacencyMap<Integer> aMap = new AdjacencyMap<>(vertices);
+
+ GenHolder<Integer> row = new GenHolder<>(0);
+
+ scn.forEachRemaining((strang) -> {
+ String[] parts = strang.split(" ");
+ int col = 0;
+
+ for (String part : parts) {
+ aMap.setWeight(row.held, col, Integer.parseInt(part));
+
+ col++;
+ }
+
+ row.held++;
+ });
+
+ scn.close();
+
+ return aMap;
+ }
+
+ public void toStream(OutputStream os) {
+ PrintStream ps = new PrintStream(os);
+
+ adjMap.entrySet().forEach(src -> {
+ src.getValue().entrySet()
+ .forEach(tgt -> ps.printf("%d ", tgt.getValue()));
+ ps.println();
+ });
+ ps.close();
+ }
+}
diff --git a/BJC-Utils2/src/main/java/bjc/utils/graph/Edge.java b/BJC-Utils2/src/main/java/bjc/utils/graph/Edge.java
new file mode 100644
index 0000000..9fb20c0
--- /dev/null
+++ b/BJC-Utils2/src/main/java/bjc/utils/graph/Edge.java
@@ -0,0 +1,30 @@
+package bjc.utils.graph;
+
+public class Edge<T> {
+ private final T source, target;
+ private final int distance;
+
+ public Edge(T node1, T node2, int distance) {
+ this.source = node1;
+ this.target = node2;
+ this.distance = distance;
+ }
+
+ public T getSource() {
+ return source;
+ }
+
+ public T getTarget() {
+ return target;
+ }
+
+ public int getDistance() {
+ return distance;
+ }
+
+ @Override
+ public String toString() {
+ return " first vertex " + source + " to vertex " + target
+ + " with distance: " + distance;
+ }
+}
diff --git a/BJC-Utils2/src/main/java/bjc/utils/graph/GenHolder.java b/BJC-Utils2/src/main/java/bjc/utils/graph/GenHolder.java
new file mode 100644
index 0000000..df363fa
--- /dev/null
+++ b/BJC-Utils2/src/main/java/bjc/utils/graph/GenHolder.java
@@ -0,0 +1,75 @@
+package bjc.utils.graph;
+
+import java.util.function.Function;
+
+/**
+ * Holds a single value of a specific type. This is used for indirect
+ * references to data, and more specifically for accessing non-final
+ * variables from a lambda. AKA the identity monad
+ *
+ * @author ben
+ *
+ * @param <T>
+ * The type of the data being held
+ */
+public class GenHolder<T> {
+ /**
+ * The state this holder is responsible for.
+ */
+ public T held;
+
+ /**
+ * Creates a new empty holder, with its state set to null
+ */
+ public GenHolder() {
+ held = null;
+ }
+
+ /**
+ * Creates a new holder, with its state initialized to the provided
+ * value
+ *
+ * @param held
+ * The state to initialize this holder to.
+ */
+ public GenHolder(T hld) {
+ held = hld;
+ }
+
+ /**
+ * Apply the given transformation to the held value. Returns the holder
+ * for allowing chaining of transforms
+ *
+ * @param f
+ * The transform to apply to the value
+ * @return The holder
+ */
+ public GenHolder<T> transform(Function<T, T> f) {
+ held = f.apply(held);
+
+ return this;
+ }
+
+ /**
+ * Return the result of applying the given transformation to the held
+ * value Doesn't change the held value
+ *
+ * @param f
+ * The transformation to apply
+ * @return A holder with the transformed value
+ */
+ public <NewT> GenHolder<NewT> map(Function<T, NewT> f) {
+ return new GenHolder<NewT>(f.apply(held));
+ }
+
+ /**
+ * Returns a raw mapped value, not contained in a GenHolder
+ *
+ * @param f
+ * The function to use for mapping the value
+ * @return The mapped value outside of a GenHolder
+ */
+ public <E> E unwrap(Function<T, E> f) {
+ return f.apply(held);
+ }
+}
diff --git a/BJC-Utils2/src/main/java/bjc/utils/graph/Graph.java b/BJC-Utils2/src/main/java/bjc/utils/graph/Graph.java
new file mode 100644
index 0000000..69e42e4
--- /dev/null
+++ b/BJC-Utils2/src/main/java/bjc/utils/graph/Graph.java
@@ -0,0 +1,236 @@
+package bjc.utils.graph;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.NoSuchElementException;
+import java.util.PriorityQueue;
+import java.util.Queue;
+import java.util.Set;
+import java.util.function.BiConsumer;
+import java.util.function.BiPredicate;
+
+/**
+ * A directed weighted graph, where the vertices have some arbitrary label
+ *
+ * @author ben
+ *
+ * @param <T>
+ * The label for vertices
+ */
+public class Graph<T> {
+
+ private final Map<T, Map<T, Integer>> graph;
+
+ /**
+ * Create a new graph
+ */
+ public Graph() {
+ graph = new HashMap<T, Map<T, Integer>>();
+ }
+
+ /**
+ * Add a edge to the graph
+ *
+ * @param source
+ * The source vertex for this edge
+ * @param target
+ * The target vertex for this edge
+ * @param distance
+ * The distance from the source vertex to the target vertex
+ */
+ public void addEdge(T source, T target, int distance) {
+ // Can't add edges with a null source or target
+ if (source == null) {
+ throw new NullPointerException("The vertex 1 cannot be null");
+ }
+ if (target == null) {
+ throw new NullPointerException("The vertex 2 cannot be null");
+ }
+
+ // Initialize adjacency list for vertices if necessary
+ if (!graph.containsKey(source)) {
+ graph.put(source, new HashMap<T, Integer>());
+ }
+ if (!graph.containsKey(target)) {
+ graph.put(target, new HashMap<T, Integer>());
+ }
+
+ // Add the edge to the graph
+ graph.get(source).put(target, distance);
+
+ // Uncomment this to make the graph undirected
+ // graph.get(target).put(source, distance);
+ }
+
+ /**
+ * Execute an action for all edges of a specific vertex matching
+ * conditions
+ *
+ * @param source
+ * The vertex to test edges for
+ * @param bp
+ * The conditions an edge must match
+ * @param bc
+ * The action to execute for matching edges
+ */
+ public void forAllEdgesMatchingAt(T source, BiPredicate<T, Integer> bp,
+ BiConsumer<T, Integer> bc) {
+ getEdges(source).forEach((tgt, weight) -> {
+ if (bp.test(tgt, weight)) {
+ bc.accept(tgt, weight);
+ }
+ });
+ }
+
+ /**
+ * Get all the edges that begin at a particular source vertex
+ *
+ * @param source
+ * The vertex to use as a source
+ * @return All of the edges with the specified vertex as a source
+ */
+ public Map<T, Integer> getEdges(T source) {
+ // Can't find edges for a null source
+ if (source == null) {
+ throw new NullPointerException("The source cannot be null.");
+ }
+
+ return Collections.unmodifiableMap(graph.get(source));
+ }
+
+ /**
+ * Get the initial vertex of the graph
+ *
+ * @return The initial vertex of the graph
+ */
+ public T getInitial() {
+ return graph.keySet().iterator().next();
+ }
+
+ /**
+ * Uses Prim's algorothm to calculate a MST for the graph. If the graph
+ * is non-connected, this will lead to unpredictable results.
+ *
+ * @param graph
+ * a connected graph.
+ * @return a list of edges that constitute the MST
+ */
+ public List<Edge<T>> getMinSpanTree() {
+ // Set of all of the currently available edges
+ Queue<Edge<T>> availEdges = new PriorityQueue<Edge<T>>(10,
+ (e1, e2) -> e1.getDistance() - e2.getDistance());
+
+ // The MST of the graph
+ List<Edge<T>> minEdges = new ArrayList<Edge<T>>();
+
+ // The set of all of the visited vertices.
+ Set<T> visited = new HashSet<T>();
+
+ // Start at the initial vertex and visit it
+ GenHolder<T> src = new GenHolder<>(getInitial());
+ visited.add(src.held);
+
+ // Make sure we visit all the nodes
+ while (visited.size() != getVertexCount()) {
+ // Grab all edges adjacent to the provided edge
+
+ forAllEdgesMatchingAt(src.held,
+ (tgt, weight) -> !visited.contains(tgt),
+ (tgt, weight) -> availEdges
+ .add(new Edge<T>(src.held, tgt, weight)));
+
+ // Get the edge with the minimum distance
+ Edge<T> minEdge = availEdges.poll();
+
+ // Only consider edges where we haven't visited the target of
+ // the edge
+ while (visited.contains(minEdge.getTarget())) {
+ minEdge = availEdges.poll();
+ }
+
+ // Add it to our MST
+ minEdges.add(minEdge);
+
+ // Advance to the next node
+ src.held = minEdge.getTarget();
+
+ // Visit this node
+ visited.add(src.held);
+ }
+
+ return minEdges;
+ }
+
+ public int getVertexCount() {
+ return graph.size();
+ }
+
+ /**
+ * Get all of the vertices in this graph.
+ *
+ * @return A unmodifiable set of all the vertices in the graph.
+ */
+ public Set<T> getVertices() {
+ return Collections.unmodifiableSet(graph.keySet());
+ }
+
+ /**
+ * Remove the edge starting at the source and ending at the target
+ *
+ * @param source
+ * The source vertex for the edge
+ * @param target
+ * The target vertex for the edge
+ */
+ public void removeEdge(T source, T target) {
+ // Can't remove things w/ null vertices
+ if (source == null) {
+ throw new NullPointerException("The vertex 1 cannot be null");
+ }
+ if (target == null) {
+ throw new NullPointerException("The vertex 2 cannot be null");
+ }
+
+ // Can't remove if one vertice doesn't exists
+ if (!graph.containsKey(source)) {
+ throw new NoSuchElementException(
+ "vertex " + source + " does not exist.");
+ }
+ if (!graph.containsKey(target)) {
+ throw new NoSuchElementException(
+ "vertex " + target + " does not exist.");
+ }
+
+ graph.get(source).remove(target);
+
+ // Uncomment this to turn the graph undirected
+ // graph.get(target).remove(source);
+ }
+
+ /**
+ * Convert a graph into a adjacency map/matrix
+ *
+ * @return A adjacency map representing this graph
+ */
+ public AdjacencyMap<T> toMap() {
+ AdjacencyMap<T> aMap = new AdjacencyMap<>(graph.keySet());
+
+ graph.entrySet().forEach(src -> src.getValue().forEach((tgt,
+ weight) -> aMap.setWeight(src.getKey(), tgt, weight)));
+
+ return aMap;
+ }
+
+ public static <E> Graph<E> fromEdgeList(List<Edge<E>> edges) {
+ Graph<E> g = new Graph<>();
+
+ edges.forEach(edge -> g.addEdge(edge.getSource(), edge.getTarget(),
+ edge.getDistance()));
+
+ return g;
+ }
+}
diff --git a/BJC-Utils2/src/main/java/bjc/utils/gui/SimpleDialogs.java b/BJC-Utils2/src/main/java/bjc/utils/gui/SimpleDialogs.java
index 7731529..85b9fa9 100644
--- a/BJC-Utils2/src/main/java/bjc/utils/gui/SimpleDialogs.java
+++ b/BJC-Utils2/src/main/java/bjc/utils/gui/SimpleDialogs.java
@@ -1,24 +1,39 @@
package bjc.utils.gui;
import java.awt.Component;
+import java.awt.Frame;
import java.util.function.Function;
import java.util.function.Predicate;
+import javax.swing.JButton;
+import javax.swing.JComboBox;
+import javax.swing.JDialog;
+import javax.swing.JLabel;
import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+
+import bjc.utils.gui.layout.VLayout;
/**
* Utility class for getting simple input from the user.
+ *
* @author ben
*
*/
public class SimpleDialogs {
/**
* Get a bounded integer from the user.
- * @param parent The parent component for the dialogs.
- * @param title The title for the dialogs.
- * @param prompt The prompt to tell the user what to enter.
- * @param lower The lower integer bound to accept.
- * @param upper The upper integer bound to accept.
+ *
+ * @param parent
+ * The parent component for the dialogs.
+ * @param title
+ * The title for the dialogs.
+ * @param prompt
+ * The prompt to tell the user what to enter.
+ * @param lower
+ * The lower integer bound to accept.
+ * @param upper
+ * The upper integer bound to accept.
* @return A int within the specified bounds.
*/
public static int getBoundedInt(Component parent, String title,
@@ -35,9 +50,13 @@ public class SimpleDialogs {
/**
* Get a integer from the user
- * @param parent The parent component for dialogs.
- * @param title The title for dialogs.
- * @param prompt The prompt to tell the user what to enter.
+ *
+ * @param parent
+ * The parent component for dialogs.
+ * @param title
+ * The title for dialogs.
+ * @param prompt
+ * The prompt to tell the user what to enter.
* @return A int.
*/
public static int getInt(Component parent, String title,
@@ -54,23 +73,34 @@ public class SimpleDialogs {
/**
* Get a string from the user
- * @param parent The parent component for dialogs.
- * @param title The title for the dialogs.
- * @param prompt The prompt to tell the user what to enter.
+ *
+ * @param parent
+ * The parent component for dialogs.
+ * @param title
+ * The title for the dialogs.
+ * @param prompt
+ * The prompt to tell the user what to enter.
* @return A string.
*/
- public static String getString(Component parent, String title, String prompt) {
+ public static String getString(Component parent, String title,
+ String prompt) {
return JOptionPane.showInputDialog(parent, prompt, title,
JOptionPane.QUESTION_MESSAGE);
}
/**
* Get a value parsable from a string from the user.
- * @param parent The parent component for dialogs.
- * @param title The title for dialogs.
- * @param prompt The prompt to tell the user what to enter.
- * @param p A predicate to determine if a input is valid.
- * @param f The function to transform the string into a value.
+ *
+ * @param parent
+ * The parent component for dialogs.
+ * @param title
+ * The title for dialogs.
+ * @param prompt
+ * The prompt to tell the user what to enter.
+ * @param p
+ * A predicate to determine if a input is valid.
+ * @param f
+ * The function to transform the string into a value.
* @return The value parsed from a string.
*/
public static <E> E getValue(Component parent, String title,
@@ -88,9 +118,13 @@ public class SimpleDialogs {
/**
* Get a whole number from the user.
- * @param parent The parent component for dialogs.
- * @param title The title for dialogs.
- * @param prompt The prompt to tell the user what to enter.
+ *
+ * @param parent
+ * The parent component for dialogs.
+ * @param title
+ * The title for dialogs.
+ * @param prompt
+ * The prompt to tell the user what to enter.
* @return A whole number.
*/
public static int getWhole(Component parent, String title,
@@ -100,9 +134,13 @@ public class SimpleDialogs {
/**
* Ask the user a Yes/No question.
- * @param parent The parent component for dialogs.
- * @param title The title for dialogs.
- * @param question The question to ask the user.
+ *
+ * @param parent
+ * The parent component for dialogs.
+ * @param title
+ * The title for dialogs.
+ * @param question
+ * The question to ask the user.
* @return True if the user said yes, false otherwise.
*/
public static boolean getYesNo(Component parent, String title,
@@ -112,12 +150,62 @@ public class SimpleDialogs {
return (res == JOptionPane.YES_OPTION ? true : false);
}
-
+
+ /**
+ * Asks the user to pick an option from a series of choices.
+ *
+ * @param parent
+ * The parent frame for this dialog
+ * @param title
+ * The title of this dialog
+ * @param question
+ * The question being asked
+ * @param choices
+ * The availible choices for the question
+ * @return The choice the user picked, or null if they didn't pick one
+ */
+ @SuppressWarnings("unchecked")
+ public static <E> E getChoice(Frame parent, String title,
+ String question, E... choices) {
+ JDialog jd = new JDialog(parent, title, true);
+ jd.setLayout(new VLayout(2));
+
+ JPanel questionPane = new JPanel();
+
+ JLabel questionText = new JLabel(question);
+ JComboBox<E> questionChoices = new JComboBox<>(choices);
+
+ questionPane.add(questionText);
+ questionPane.add(questionChoices);
+
+ JPanel buttonPane = new JPanel();
+
+ JButton okButton = new JButton("Ok");
+ okButton.addActionListener(e -> jd.dispose());
+ JButton cancelButton = new JButton("Cancel");
+ cancelButton.addActionListener(e -> jd.dispose());
+
+ buttonPane.add(cancelButton);
+ buttonPane.add(okButton);
+
+ jd.add(questionPane);
+ jd.add(buttonPane);
+
+ jd.pack();
+ jd.setVisible(true);
+
+ return (E) questionChoices.getSelectedItem();
+ }
+
/**
* Show a error message to the user
- * @param parent The parent component for dialogs.
- * @param title The title for dialogs.
- * @param err The error to show the user.
+ *
+ * @param parent
+ * The parent component for dialogs.
+ * @param title
+ * The title for dialogs.
+ * @param err
+ * The error to show the user.
*/
public static void showError(Component parent, String title,
String err) {
diff --git a/BJC-Utils2/src/main/java/bjc/utils/gui/SimpleJList.java b/BJC-Utils2/src/main/java/bjc/utils/gui/SimpleJList.java
index 220ac7d..518805b 100644
--- a/BJC-Utils2/src/main/java/bjc/utils/gui/SimpleJList.java
+++ b/BJC-Utils2/src/main/java/bjc/utils/gui/SimpleJList.java
@@ -1,7 +1,5 @@
package bjc.utils.gui;
-import java.util.List;
-
import javax.swing.DefaultListModel;
import javax.swing.JList;
import javax.swing.ListModel;
@@ -17,7 +15,7 @@ public class SimpleJList {
* @param ls The list to populate the JList with.
* @return A JList populated with the elements from ls.
*/
- public static <E> JList<E> buildFromList(List<E> ls) {
+ public static <E> JList<E> buildFromList(Iterable<E> ls) {
return new JList<E>(buildModel(ls));
}
@@ -26,7 +24,7 @@ public class SimpleJList {
* @param ls The list to fill the list model from.
* @return A list model populated with the elements from ls.
*/
- public static <E> ListModel<E> buildModel(List<E> ls) {
+ public static <E> ListModel<E> buildModel(Iterable<E> ls) {
DefaultListModel<E> dlm = new DefaultListModel<>();
ls.forEach(dlm::addElement);
diff --git a/BJC-Utils2/src/main/java/bjc/utils/gui/awt/ExtensionFileFilter.java b/BJC-Utils2/src/main/java/bjc/utils/gui/awt/ExtensionFileFilter.java
new file mode 100644
index 0000000..fb857eb
--- /dev/null
+++ b/BJC-Utils2/src/main/java/bjc/utils/gui/awt/ExtensionFileFilter.java
@@ -0,0 +1,37 @@
+package bjc.utils.gui.awt;
+
+import java.io.File;
+import java.io.FilenameFilter;
+import java.util.ArrayList;
+import java.util.List;
+
+import bjc.utils.funcdata.FunctionalList;
+
+public class ExtensionFileFilter implements FilenameFilter {
+ private FunctionalList<String> extensions;
+
+ /**
+ * Create a new filter only showing files with the specified extensions.
+ * @param exts The extensions to show in this filter.
+ */
+ public ExtensionFileFilter(String... exts) {
+ extensions = new FunctionalList<>(new ArrayList<>(exts.length));
+
+ for (String ext : exts) {
+ extensions.add(ext);
+ }
+ }
+
+ /**
+ * Create a new filter only showing files with the specified extensions.
+ * @param exts The extensions to show in this filter.
+ */
+ public ExtensionFileFilter(List<String> exts) {
+ extensions = new FunctionalList<>(exts);
+ }
+
+ @Override
+ public boolean accept(File dir, String name) {
+ return extensions.anyMatch(name::endsWith);
+ }
+} \ No newline at end of file
diff --git a/BJC-Utils2/src/main/java/bjc/utils/gui/awt/SimpleFileDialog.java b/BJC-Utils2/src/main/java/bjc/utils/gui/awt/SimpleFileDialog.java
new file mode 100644
index 0000000..1d14903
--- /dev/null
+++ b/BJC-Utils2/src/main/java/bjc/utils/gui/awt/SimpleFileDialog.java
@@ -0,0 +1,58 @@
+package bjc.utils.gui.awt;
+
+import java.awt.FileDialog;
+import java.awt.Frame;
+import java.io.File;
+import java.io.FilenameFilter;
+
+import bjc.utils.gui.SimpleDialogs;
+
+public class SimpleFileDialog {
+ public static File getOpenFile(Frame par, String title,
+ String... extensions) {
+ FileDialog fd = new FileDialog(par, title, FileDialog.LOAD);
+
+ if (extensions != null) {
+ FilenameFilter filter = new ExtensionFileFilter(extensions);
+ fd.setFilenameFilter(filter);
+ }
+
+ fd.setVisible(true);
+
+ while (fd.getFile() == null) {
+ SimpleDialogs.showError(par, "File I/O Error",
+ "Please choose a file to open.");
+ fd.setVisible(true);
+ }
+
+ return fd.getFiles()[0];
+ }
+
+ public static File getOpenFile(Frame par, String title) {
+ return getOpenFile(par, title, (String[]) null);
+ }
+
+ public static File getSaveFile(Frame par, String title,
+ String... extensions) {
+ FileDialog fd = new FileDialog(par, title, FileDialog.SAVE);
+
+ if (extensions != null) {
+ FilenameFilter filter = new ExtensionFileFilter(extensions);
+ fd.setFilenameFilter(filter);
+ }
+
+ fd.setVisible(true);
+
+ while (fd.getFile() == null) {
+ SimpleDialogs.showError(par, "File I/O Error",
+ "Please choose a file to save to.");
+ fd.setVisible(true);
+ }
+
+ return fd.getFiles()[0];
+ }
+
+ public static File getSaveFile(Frame par, String title) {
+ return getSaveFile(par, title, (String[]) null);
+ }
+}