152 changed files with 2054 additions and 1456 deletions
+3 -3
View File
@@ -114,12 +114,12 @@ public class Convert {
if (o == null) return def; if (o == null) return def;
if (o instanceof String) return ((String) o); if (o instanceof String) return ((String) o);
if (o instanceof Float) return Support.str((float) o); if (o instanceof Float) return Str.val((float) o);
if (o instanceof Double) return Support.str((double) o); if (o instanceof Double) return Str.val((double) o);
if (o instanceof Class<?>) { if (o instanceof Class<?>) {
return Support.str(o); return Str.val(o);
} }
return o.toString(); return o.toString();
+43 -14
View File
@@ -17,6 +17,19 @@ import java.util.Map.Entry;
*/ */
public class MapSort { public class MapSort {
/**
* Sort a map by keys, maintaining key-value pairs, using natural order.
*
* @param map map to be sorted
* @return linked hash map with sorted entries
*/
@SuppressWarnings({ "rawtypes" })
public static <K extends Comparable, V> LinkedHashMap<K, V> byKeys(Map<K, V> map)
{
return byKeys(map, null);
}
/** /**
* Sort a map by keys, maintaining key-value pairs. * Sort a map by keys, maintaining key-value pairs.
* *
@@ -24,20 +37,25 @@ public class MapSort {
* @param comparator a comparator, or null for natural ordering * @param comparator a comparator, or null for natural ordering
* @return linked hash map with sorted entries * @return linked hash map with sorted entries
*/ */
@SuppressWarnings({ "rawtypes", "unchecked" }) @SuppressWarnings({ "unchecked" })
public static <K extends Comparable, V extends Comparable> Map<K, V> sortByKeys(Map<K, V> map, final Comparator<K> comparator) public static <K, V> LinkedHashMap<K, V> byKeys(Map<K, V> map, Comparator<K> comparator)
{ {
final List<K> keys = new LinkedList<>(map.keySet()); final List<K> keys = new LinkedList<>(map.keySet());
if (comparator == null) { if (comparator == null) {
Collections.sort(keys); comparator = new Comparator<K>() {
} else {
Collections.sort(keys, comparator); @Override
public int compare(K arg0, K arg1)
{
return ((Comparable<K>) arg0).compareTo(arg1);
}
};
} }
// LinkedHashMap will keep the keys in the order they are inserted Collections.sort(keys, comparator);
// which is currently sorted on natural ordering
final Map<K, V> sortedMap = new LinkedHashMap<>(); final LinkedHashMap<K, V> sortedMap = new LinkedHashMap<>();
for (final K key : keys) { for (final K key : keys) {
sortedMap.put(key, map.get(key)); sortedMap.put(key, map.get(key));
} }
@@ -46,6 +64,19 @@ public class MapSort {
} }
/**
* Sort a map by values, maintaining key-value pairs, using natural order.
*
* @param map map to be sorted
* @return linked hash map with sorted entries
*/
@SuppressWarnings("rawtypes")
public static <K, V extends Comparable> LinkedHashMap<K, V> byValues(Map<K, V> map)
{
return byValues(map, null);
}
/** /**
* Sort a map by values, maintaining key-value pairs. * Sort a map by values, maintaining key-value pairs.
* *
@@ -53,24 +84,22 @@ public class MapSort {
* @param comparator a comparator, or null for natural ordering * @param comparator a comparator, or null for natural ordering
* @return linked hash map with sorted entries * @return linked hash map with sorted entries
*/ */
@SuppressWarnings("rawtypes") public static <K, V> LinkedHashMap<K, V> byValues(Map<K, V> map, final Comparator<V> comparator)
public static <K extends Comparable, V extends Comparable> Map<K, V> sortByValues(Map<K, V> map, final Comparator<V> comparator)
{ {
final List<Map.Entry<K, V>> entries = new LinkedList<>(map.entrySet()); final List<Map.Entry<K, V>> entries = new LinkedList<>(map.entrySet());
Collections.sort(entries, new Comparator<Map.Entry<K, V>>() { Collections.sort(entries, new Comparator<Map.Entry<K, V>>() {
@SuppressWarnings("unchecked")
@Override @Override
public int compare(Entry<K, V> o1, Entry<K, V> o2) public int compare(Entry<K, V> o1, Entry<K, V> o2)
{ {
if (comparator == null) return o1.getValue().compareTo(o2.getValue()); if (comparator == null) return ((Comparable<V>) o1.getValue()).compareTo(o2.getValue());
return comparator.compare(o1.getValue(), o2.getValue()); return comparator.compare(o1.getValue(), o2.getValue());
} }
}); });
// LinkedHashMap will keep the keys in the order they are inserted final LinkedHashMap<K, V> sortedMap = new LinkedHashMap<>();
// which is currently sorted on natural ordering
final Map<K, V> sortedMap = new LinkedHashMap<>();
for (final Map.Entry<K, V> entry : entries) { for (final Map.Entry<K, V> entry : entries) {
sortedMap.put(entry.getKey(), entry.getValue()); sortedMap.put(entry.getKey(), entry.getValue());
+12 -2
View File
@@ -65,10 +65,20 @@ public class Reflect {
return classes; return classes;
} }
throw new RuntimeException(Support.str(clazz) + " is not generic."); throw new RuntimeException(Str.val(clazz) + " is not generic.");
} }
/**
* Get value of a public static final field. If the modifiers don't match,
* an exception is thrown.
*
* @param objClass the class
* @param fieldName field to retrieve
* @return the field value
* @throws ReflectiveOperationException if the field is not constant, or if
* the value could not be retrieved.
*/
public static Object getConstantFieldValue(Class<?> objClass, String fieldName) throws ReflectiveOperationException public static Object getConstantFieldValue(Class<?> objClass, String fieldName) throws ReflectiveOperationException
{ {
final Field fld = objClass.getDeclaredField(fieldName); final Field fld = objClass.getDeclaredField(fieldName);
@@ -76,7 +86,7 @@ public class Reflect {
final int modif = fld.getModifiers(); final int modif = fld.getModifiers();
if (!Modifier.isFinal(modif) || !Modifier.isStatic(modif)) { if (!Modifier.isFinal(modif) || !Modifier.isStatic(modif)) {
throw new RuntimeException("The " + fieldName + " field of " + Support.str(objClass) + " must be static and final!"); throw new ReflectiveOperationException("The " + fieldName + " field of " + Str.val(objClass) + " must be static and final!");
} }
fld.setAccessible(true); fld.setAccessible(true);
+231
View File
@@ -0,0 +1,231 @@
package mightypork.utils;
import mightypork.utils.annotations.Alias;
import mightypork.utils.math.AlignX;
/**
* General purpose string utilities
*
* @author Ondřej Hruška (MightyPork)
*/
public class Str {
public static String fromLastDot(String s)
{
return fromLast(s, '.');
}
public static String toLastDot(String s)
{
return toLast(s, '.');
}
public static String fromLast(String s, char c)
{
if (s == null) return null;
if (s.lastIndexOf(c) == -1) return "";
return s.substring(s.lastIndexOf(c) + 1, s.length());
}
public static String toLast(String s, char c)
{
if (s == null) return null;
if (s.lastIndexOf(c) == -1) return s;
return s.substring(0, s.lastIndexOf(c));
}
public static String fromFirst(String s, char c)
{
if (s == null) return null;
if (s.indexOf(c) == -1) return "";
return s.substring(s.indexOf(c) + 1, s.length());
}
public static String toFirst(String s, char c)
{
if (s == null) return null;
if (s.indexOf(c) == -1) return s;
return s.substring(0, s.indexOf(c));
}
public static String fromEnd(String s, int chars)
{
return s.substring(s.length() - chars, s.length());
}
public static String fromStart(String s, int chars)
{
return s.substring(0, chars);
}
public static String pad(String s, int length)
{
return pad(s, length, AlignX.LEFT);
}
public static String pad(String s, int length, AlignX align)
{
return pad(s, length, align, ' ');
}
public static String pad(String s, int length, AlignX align, char fill)
{
final String filling = repeat("" + fill, length);
switch (align) {
case LEFT:
s += filling;
return fromStart(s, length);
case RIGHT:
s += filling;
return fromEnd(s, length);
case CENTER:
if (s.length() >= length) return s;
s = filling + s + filling;
final int cut = (int) (s.length() / 2D - length / 2D);
return s.substring(cut, s.length() - cut);
}
throw new IllegalArgumentException("Impossible error.");
}
/**
* Repeat a string
*
* @param repeated string
* @param count
* @return output
*/
public static String repeat(String repeated, int count)
{
String s = "";
for (int i = 0; i < count; i++)
s += repeated;
return s;
}
public static boolean isValidFilenameChar(char ch)
{
return isValidFilenameString(Character.toString(ch));
}
public static boolean isValidFilenameString(String filename)
{
return filename.matches("[a-zA-Z0-9 +\\-.,_%@#!]+");
}
public static String ellipsisStart(String orig, int length)
{
if (orig.length() > length) {
orig = "\u2026" + orig.substring(length, orig.length());
}
return orig;
}
public static String ellipsisEnd(String orig, int length)
{
if (orig.length() > length) {
orig = orig.substring(0, length - 1) + "\u2026";
}
return orig;
}
/**
* Convert a class to string, preserving name and outer class, but excluding
* path.
*
* @param cls the class
* @return class name
*/
public static String val(Class<?> cls)
{
final Alias ln = cls.getAnnotation(Alias.class);
if (ln != null) {
return ln.name();
}
String name = cls.getName();
String sep = "";
if (name.contains("$")) {
name = name.substring(name.lastIndexOf("$") + 1);
sep = "$";
} else {
name = name.substring(name.lastIndexOf(".") + 1);
sep = ".";
}
final Class<?> enclosing = cls.getEnclosingClass();
return (enclosing == null ? "" : Str.val(enclosing) + sep) + name;
}
/**
* Convert double to string, remove the mess at the end.
*
* @param d double
* @return string
*/
public static String val(Double d)
{
String s = d.toString();
s = s.replace(',', '.');
s = s.replaceAll("([0-9]+\\.[0-9]+)00+[0-9]+", "$1");
s = s.replaceAll("0+$", "");
s = s.replaceAll("\\.$", "");
return s;
}
/**
* Convert object to string. If the object overrides toString(), it is
* caled. Otherwise it's class name is converted to string.
*
* @param o object
* @return string representation
*/
public static String val(Object o)
{
if (o == null) return "<null>";
boolean hasToString = false;
try {
hasToString = (o.getClass().getMethod("toString").getDeclaringClass() != Object.class);
} catch (final Throwable t) {
// oh well..
}
if (hasToString) {
return o.toString();
} else {
return val(o.getClass());
}
}
}
-96
View File
@@ -9,8 +9,6 @@ import java.util.Iterator;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.Map; import java.util.Map;
import mightypork.utils.annotations.Alias;
/** /**
* Miscelanous utilities * Miscelanous utilities
@@ -153,7 +151,6 @@ public final class Support {
return new IterableEnumerationWrapper<>(enumeration); return new IterableEnumerationWrapper<>(enumeration);
} }
/** /**
* Helper class for iterationg over an {@link Enumeration} * Helper class for iterationg over an {@link Enumeration}
* *
@@ -202,97 +199,4 @@ public final class Support {
} }
} }
/**
* Convert a class to string, preserving name and outer class, but excluding
* path.
*
* @param cls
* @return
*/
public static String str(Class<?> cls)
{
final Alias ln = cls.getAnnotation(Alias.class);
if (ln != null) {
return ln.name();
}
String name = cls.getName();
String sep = "";
if (name.contains("$")) {
name = name.substring(name.lastIndexOf("$") + 1);
sep = "$";
} else {
name = name.substring(name.lastIndexOf(".") + 1);
sep = ".";
}
final Class<?> enclosing = cls.getEnclosingClass();
return (enclosing == null ? "" : Support.str(enclosing) + sep) + name;
}
/**
* Convert double to string, remove the mess at the end.
*
* @param d double
* @return string
*/
public static String str(Double d)
{
String s = d.toString();
s = s.replace(',', '.');
s = s.replaceAll("([0-9]+\\.[0-9]+)00+[0-9]+", "$1");
s = s.replaceAll("0+$", "");
s = s.replaceAll("\\.$", "");
return s;
}
/**
* Convert float to string, remove the mess at the end.
*
* @param f float
* @return string
*/
public static String str(Float f)
{
String s = f.toString();
s = s.replaceAll("([0-9]+\\.[0-9]+)00+[0-9]+", "$1");
s = s.replaceAll("0+$", "");
s = s.replaceAll("\\.$", "");
return s;
}
/**
* Convert object to string. If the object overrides toString(), it is
* caled. Otherwise it's class name is converted to string.
*
* @param o object
* @return string representation
*/
public static String str(Object o)
{
if (o == null) return "<null>";
boolean hasToString = false;
try {
hasToString = (o.getClass().getMethod("toString").getDeclaringClass() != Object.class);
} catch (final Throwable t) {
// oh well..
}
if (hasToString) {
return o.toString();
} else {
return str(o.getClass());
}
}
} }
@@ -18,6 +18,6 @@ import java.lang.annotation.Target;
@Documented @Documented
@Retention(RetentionPolicy.SOURCE) @Retention(RetentionPolicy.SOURCE)
@Target(value = { ElementType.METHOD }) @Target(value = { ElementType.METHOD })
public @interface DefaultImpl { public @interface Stub {
// //
} }
@@ -1,4 +1,4 @@
package mightypork.utils.files.config; package mightypork.utils.config;
import java.io.File; import java.io.File;
@@ -9,7 +9,7 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Map.Entry; import java.util.Map.Entry;
import mightypork.utils.files.FileUtils; import mightypork.utils.files.FileUtil;
import mightypork.utils.logging.Log; import mightypork.utils.logging.Log;
@@ -33,7 +33,7 @@ public class SimpleConfig {
*/ */
public static List<String> listFromFile(File file) throws IOException public static List<String> listFromFile(File file) throws IOException
{ {
final String fileText = FileUtils.fileToString(file); final String fileText = FileUtil.fileToString(file);
return listFromString(fileText); return listFromString(fileText);
} }
@@ -48,7 +48,7 @@ public class SimpleConfig {
*/ */
public static Map<String, String> mapFromFile(File file) throws IOException public static Map<String, String> mapFromFile(File file) throws IOException
{ {
final String fileText = FileUtils.fileToString(file); final String fileText = FileUtil.fileToString(file);
return mapFromString(fileText); return mapFromString(fileText);
} }
@@ -173,7 +173,7 @@ public class SimpleConfig {
text += s; text += s;
} }
FileUtils.stringToFile(target, text); FileUtil.stringToFile(target, text);
} }
@@ -199,7 +199,7 @@ public class SimpleConfig {
text += s; text += s;
} }
FileUtils.stringToFile(target, text); FileUtil.stringToFile(target, text);
} }
} }
@@ -0,0 +1,123 @@
package mightypork.utils.config.propmgr;
import mightypork.utils.Convert;
import mightypork.utils.annotations.Stub;
/**
* Property entry for the {@link PropertyManager}.<br>
* Extending this class can be used to add custom property types that are not
* supported by default.
*
* @author Ondřej Hruška (MightyPork)
* @param <T> property type
*/
public abstract class Property<T> {
protected final String comment;
protected final String key;
protected T value;
protected final T defaultValue;
/**
* Create a property without comment
*
* @param key key in the config file
* @param defaultValue defualt property value (used as fallback when
* parsing)
*/
public Property(String key, T defaultValue)
{
this(key, defaultValue, null);
}
/**
* Create a property with a comment
*
* @param key key in the config file
* @param defaultValue default property value, used as fallback when
* parsing. Initially the value is assigned to defaultValue.
* @param comment optional property comment included above the property in
* the config file. Can be null.
*/
public Property(String key, T defaultValue, String comment)
{
this.comment = comment;
this.key = key;
this.value = defaultValue;
this.defaultValue = defaultValue;
}
/**
* Parse a string representation of the value into this property. If the
* value cannot be decoded, use the default value instead.
*
* @param string property value as string
*/
public abstract void fromString(String string);
/**
* Get property value as string (compatible with `fromString())
*
* @return property value as string
*/
@Override
@Stub
public String toString()
{
return Convert.toString(value, Convert.toString(defaultValue));
}
/**
* Get the current property value
*
* @return the value
*/
public T getValue()
{
return value;
}
/**
* Set property value.<br>
* Uses Object to allow setValue(Object) method in {@link PropertyManager}
*
* @param value value to set.
* @throws ClassCastException in case of incompatible type.
*/
@SuppressWarnings("unchecked")
public void setValue(Object value)
{
this.value = (T) value;
}
/**
* Get property comment.
*
* @return the comment text (can be null if no comment is defined)
*/
public String getComment()
{
return comment;
}
/**
* Get property key
*
* @return property key
*/
public String getKey()
{
return key;
}
}
@@ -0,0 +1,289 @@
package mightypork.utils.config.propmgr;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Map.Entry;
import java.util.TreeMap;
import mightypork.utils.Convert;
import mightypork.utils.config.propmgr.properties.BooleanProperty;
import mightypork.utils.config.propmgr.properties.DoubleProperty;
import mightypork.utils.config.propmgr.properties.IntegerProperty;
import mightypork.utils.config.propmgr.properties.StringProperty;
import mightypork.utils.config.propmgr.store.PropertyFile;
import mightypork.utils.logging.Log;
/**
* Property manager with advanced formatting and value checking.
*
* @author Ondřej Hruška (MightyPork)
*/
public class PropertyManager {
private final TreeMap<String, Property<?>> entries = new TreeMap<>();
private final TreeMap<String, String> renameTable = new TreeMap<>();
private final PropertyStore props;
/**
* Create property manager from file path and a header comment.<br>
* This is the same as using a {@link PropertyFile} store.
*
* @param file property file
* @param comment header comment.
*/
public PropertyManager(File file, String comment)
{
this(new PropertyFile(file, comment));
}
/**
* Create property manager based on provided {@link PropertyStore}
*
* @param props a property store implementation backing this property
* manager
*/
public PropertyManager(PropertyStore props)
{
this.props = props;
}
/**
* Load from file
*/
public void load()
{
props.load();
// rename keys (useful if keys change but value is to be kept)
for (final Entry<String, String> entry : renameTable.entrySet()) {
final String value = props.getProperty(entry.getKey());
if (value == null) continue;
final String oldKey = entry.getKey();
final String newKey = entry.getValue();
props.removeProperty(oldKey);
props.setProperty(newKey, value, entries.get(newKey).getComment());
}
for (final Property<?> entry : entries.values()) {
entry.fromString(props.getProperty(entry.getKey()));
}
}
public void save()
{
try {
final ArrayList<String> keyList = new ArrayList<>();
// validate entries one by one, replace with default when needed
for (final Property<?> entry : entries.values()) {
keyList.add(entry.getKey());
props.setProperty(entry.getKey(), entry.toString(), entry.getComment());
}
// removed unused props
for (final String key : props.keys()) {
if (!keyList.contains(key)) {
props.removeProperty(key);
}
}
props.save();
} catch (final IOException ioe) {
ioe.printStackTrace();
}
}
/**
* Get a property entry (rarely used)
*
* @param k key
* @return the entry
*/
public Property<?> getProperty(String k)
{
try {
return entries.get(k);
} catch (final Exception e) {
Log.w(e);
return null;
}
}
/**
* Get boolean property
*
* @param k key
* @return the boolean found, or false
*/
public Boolean getBoolean(String k)
{
return Convert.toBoolean(getProperty(k).getValue());
}
/**
* Get numeric property
*
* @param k key
* @return the int found, or null
*/
public Integer getInteger(String k)
{
return Convert.toInteger(getProperty(k).getValue());
}
/**
* Get numeric property as double
*
* @param k key
* @return the double found, or null
*/
public Double getDouble(String k)
{
return Convert.toDouble(getProperty(k).getValue());
}
/**
* Get string property
*
* @param k key
* @return the string found, or null
*/
public String getString(String k)
{
return Convert.toString(getProperty(k).getValue());
}
/**
* Get arbitrary property. Make sure it's of the right type!
*
* @param k key
* @return the prioperty found
*/
@SuppressWarnings("unchecked")
public <T> T getValue(String k)
{
try {
return ((Property<T>) getProperty(k)).getValue();
} catch (final ClassCastException e) {
return null;
}
}
/**
* Add a boolean property
*
* @param k key
* @param d default value
* @param comment the in-file comment
*/
public void addBoolean(String k, boolean d, String comment)
{
addProperty(new BooleanProperty(k, d, comment));
}
/**
* Add a numeric property (double)
*
* @param k key
* @param d default value
* @param comment the in-file comment
*/
public void addDouble(String k, double d, String comment)
{
addProperty(new DoubleProperty(k, d, comment));
}
/**
* Add a numeric property
*
* @param k key
* @param d default value
* @param comment the in-file comment
*/
public void addInteger(String k, int d, String comment)
{
addProperty(new IntegerProperty(k, d, comment));
}
/**
* Add a string property
*
* @param k key
* @param d default value
* @param comment the in-file comment
*/
public void addString(String k, String d, String comment)
{
addProperty(new StringProperty(k, d, comment));
}
/**
* Add a generic property (can be used with custom property types)
*
* @param prop property to add
*/
public <T> void addProperty(Property<T> prop)
{
entries.put(prop.getKey(), prop);
}
/**
* Rename key before loading; value is preserved
*
* @param oldKey old key
* @param newKey new key
*/
public void renameKey(String oldKey, String newKey)
{
renameTable.put(oldKey, newKey);
return;
}
/**
* Set value saved to certain key.
*
* @param key key
* @param value the saved value
*/
public void setValue(String key, Object value)
{
getProperty(key).setValue(value);
}
/**
* Set heading comment of the property store.
*
* @param fileComment comment text (can be multi-line)
*/
public void setFileComment(String fileComment)
{
props.setComment(fileComment);
}
}
@@ -0,0 +1,79 @@
package mightypork.utils.config.propmgr;
import java.io.IOException;
import java.util.Collection;
/**
* Interface for a property store (used by {@link PropertyManager}).<br>
* Due to this abstraction, different kind of property storage can be used, not
* only a file.
*
* @author Ondřej Hruška (MightyPork)
*/
public interface PropertyStore {
/**
* Set a header comment
*
* @param comment the comment text (can be multi-line)
*/
void setComment(String comment);
/**
* Load properties from the file / store. If the file does not exist or is
* inaccessible, nothing is loaded.
*/
void load();
/**
* Save properties to the file / store.
*
* @throws IOException if the file cannot be created or written.
*/
void save() throws IOException;
/**
* Get a property value
*
* @param key property key
* @return value retrieved from the file, or null if none found.
*/
String getProperty(String key);
/**
* Set a property value
*
* @param key property key
* @param value property value to set
* @param comment property comment. Can be null.
*/
void setProperty(String key, String value, String comment);
/**
* Remove a property from the list.
*
* @param key property key to remove
*/
void removeProperty(String key);
/**
* Clear the property list
*/
void clear();
/**
* Get keys collection (can be used for iterating)
*
* @return keys collection
*/
public Collection<String> keys();
}
@@ -0,0 +1,32 @@
package mightypork.utils.config.propmgr.properties;
import mightypork.utils.Convert;
import mightypork.utils.config.propmgr.Property;
/**
* Boolean property
*
* @author Ondřej Hruška (MightyPork)
*/
public class BooleanProperty extends Property<Boolean> {
public BooleanProperty(String key, Boolean defaultValue)
{
super(key, defaultValue);
}
public BooleanProperty(String key, Boolean defaultValue, String comment)
{
super(key, defaultValue, comment);
}
@Override
public void fromString(String string)
{
setValue(Convert.toBoolean(string, defaultValue));
}
}
@@ -0,0 +1,32 @@
package mightypork.utils.config.propmgr.properties;
import mightypork.utils.Convert;
import mightypork.utils.config.propmgr.Property;
/**
* Double property
*
* @author Ondřej Hruška (MightyPork)
*/
public class DoubleProperty extends Property<Double> {
public DoubleProperty(String key, Double defaultValue)
{
super(key, defaultValue);
}
public DoubleProperty(String key, Double defaultValue, String comment)
{
super(key, defaultValue, comment);
}
@Override
public void fromString(String string)
{
setValue(Convert.toDouble(string, defaultValue));
}
}
@@ -0,0 +1,32 @@
package mightypork.utils.config.propmgr.properties;
import mightypork.utils.Convert;
import mightypork.utils.config.propmgr.Property;
/**
* Integer property
*
* @author Ondřej Hruška (MightyPork)
*/
public class IntegerProperty extends Property<Integer> {
public IntegerProperty(String key, Integer defaultValue)
{
super(key, defaultValue);
}
public IntegerProperty(String key, Integer defaultValue, String comment)
{
super(key, defaultValue, comment);
}
@Override
public void fromString(String string)
{
setValue(Convert.toInteger(string, defaultValue));
}
}
@@ -0,0 +1,32 @@
package mightypork.utils.config.propmgr.properties;
import mightypork.utils.Convert;
import mightypork.utils.config.propmgr.Property;
/**
* String property
*
* @author Ondřej Hruška (MightyPork)
*/
public class StringProperty extends Property<String> {
public StringProperty(String key, String defaultValue)
{
super(key, defaultValue);
}
public StringProperty(String key, String defaultValue, String comment)
{
super(key, defaultValue, comment);
}
@Override
public void fromString(String string)
{
setValue(Convert.toString(string, defaultValue));
}
}
@@ -0,0 +1,121 @@
package mightypork.utils.config.propmgr.store;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Collection;
import mightypork.utils.config.propmgr.PropertyStore;
/**
* File based implementation utilizing {@link java.util.Properties}, hacked to
* support UTF-8.
*
* @author Ondřej Hruška (MightyPork)
*/
public class PropertyFile implements PropertyStore {
private String comment;
private final File file;
private final SortedProperties props;
public PropertyFile(File file)
{
this.file = file;
this.comment = null;
this.props = new SortedProperties();
}
public PropertyFile(File file, String comment)
{
this.file = file;
this.comment = comment;
this.props = new SortedProperties();
}
@Override
public void setComment(String comment)
{
this.comment = comment;
}
@Override
public void load()
{
if (!file.exists()) return;
try(FileInputStream in = new FileInputStream(file)) {
props.load(in);
} catch (final IOException e) {
// ignore
}
}
@Override
public void save() throws IOException
{
if (!file.getParentFile().mkdirs()) {
if (!file.getParentFile().exists()) {
throw new IOException("Cound not create config file.");
}
}
try(FileOutputStream out = new FileOutputStream(file)) {
props.store(out, comment);
}
}
@Override
public String getProperty(String key)
{
return props.getProperty(key);
}
@Override
public void setProperty(String key, String value, String comment)
{
props.setProperty(key, value);
props.setKeyComment(key, comment);
}
@Override
public void removeProperty(String key)
{
props.remove(key);
}
@Override
public void clear()
{
props.clear();
}
@SuppressWarnings("unchecked")
@Override
public Collection<String> keys()
{
// Set<String> keys = new HashSet<>();
// for (Object o : props.keySet()) {
// keys.add((String) o);
// }
// return keys;
// we know it is strings.
return (Collection<String>) (Collection<?>) props.keySet();
}
}
@@ -1,4 +1,4 @@
package mightypork.utils.files.config; package mightypork.utils.config.propmgr.store;
import java.io.BufferedWriter; import java.io.BufferedWriter;
@@ -16,20 +16,13 @@ import java.util.Vector;
/** /**
* Properties stored in file, alphabetically sorted.<br> * Properties stored in file, alphabetically sorted.<br>
* Uses UTF-8 encoding and each property can have it's own comment. * Uses UTF-8 encoding and each property can have it's own comment.<br>
* FIXME The quality of this class is dubious. It would probably be a good idea
* to rewrite it without using {@link java.util.Properties} at all.
* *
* @author Ondřej Hruška (MightyPork) * @author Ondřej Hruška (MightyPork)
*/ */
public class SortedProperties extends java.util.Properties { class SortedProperties extends java.util.Properties {
/** Option: put empty line before each comment. */
public boolean cfgBlankRowBeforeComment = true;
/**
* Option: Separate sections by newline<br>
* Section = string before first dot in key.
*/
public boolean cfgBlankRowBetweenSections = true;
/** Comments for individual keys */ /** Comments for individual keys */
private final Hashtable<String, String> keyComments = new Hashtable<>(); private final Hashtable<String, String> keyComments = new Hashtable<>();
@@ -205,7 +198,8 @@ public class SortedProperties extends java.util.Properties {
key = saveConvert(key, true, escUnicode); key = saveConvert(key, true, escUnicode);
val = saveConvert(val, false, escUnicode); val = saveConvert(val, false, escUnicode);
if (cfgBlankRowBetweenSections && !lastSectionBeginning.equals(key.split("[.]")[0])) { // separate sections
if (!lastSectionBeginning.equals(key.split("[.]")[0])) {
if (!firstEntry) { if (!firstEntry) {
bw.newLine(); bw.newLine();
bw.newLine(); bw.newLine();
@@ -223,7 +217,8 @@ public class SortedProperties extends java.util.Properties {
final String[] cmlines = cm.split("\n"); final String[] cmlines = cm.split("\n");
if (!wasNewLine && !firstEntry && cfgBlankRowBeforeComment) { // newline before comments
if (!wasNewLine && !firstEntry) {
bw.newLine(); bw.newLine();
} }
@@ -298,6 +293,7 @@ public class SortedProperties extends java.util.Properties {
sb.append(c); sb.append(c);
} }
// discard comments
final String read = sb.toString().replaceAll("(#|;|//|--)[^\n]*\n", "\n"); final String read = sb.toString().replaceAll("(#|;|//|--)[^\n]*\n", "\n");
final String inputString = escapifyStr(read); final String inputString = escapifyStr(read);
@@ -1,16 +0,0 @@
package mightypork.utils.eventbus;
/**
* Access to an {@link EventBus} instance
*
* @author Ondřej Hruška (MightyPork)
*/
public interface BusAccess {
/**
* @return event bus
*/
EventBus getEventBus();
}
+6 -3
View File
@@ -1,6 +1,7 @@
package mightypork.utils.eventbus; package mightypork.utils.eventbus;
import mightypork.utils.annotations.Stub;
import mightypork.utils.eventbus.events.flags.DelayedEvent; import mightypork.utils.eventbus.events.flags.DelayedEvent;
import mightypork.utils.eventbus.events.flags.DirectEvent; import mightypork.utils.eventbus.events.flags.DirectEvent;
import mightypork.utils.eventbus.events.flags.NonConsumableEvent; import mightypork.utils.eventbus.events.flags.NonConsumableEvent;
@@ -82,8 +83,8 @@ public abstract class BusEvent<HANDLER> {
/** /**
* Check if the event is consumed. Consumed event is not served to other * Check if the event is consumed. When an event is consumed, no other
* clients. * clients will receive it.
* *
* @return true if consumed * @return true if consumed
*/ */
@@ -96,7 +97,7 @@ public abstract class BusEvent<HANDLER> {
/** /**
* @return true if the event was served to at least 1 client * @return true if the event was served to at least 1 client
*/ */
final boolean wasServed() public final boolean wasServed()
{ {
return served; return served;
} }
@@ -117,7 +118,9 @@ public abstract class BusEvent<HANDLER> {
* *
* @param bus event bus instance * @param bus event bus instance
*/ */
@Stub
public void onDispatchComplete(EventBus bus) public void onDispatchComplete(EventBus bus)
{ {
//
} }
} }
+12 -19
View File
@@ -10,7 +10,7 @@ import java.util.concurrent.Delayed;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import mightypork.utils.Reflect; import mightypork.utils.Reflect;
import mightypork.utils.Support; import mightypork.utils.Str;
import mightypork.utils.eventbus.clients.DelegatingClient; import mightypork.utils.eventbus.clients.DelegatingClient;
import mightypork.utils.eventbus.events.flags.DelayedEvent; import mightypork.utils.eventbus.events.flags.DelayedEvent;
import mightypork.utils.eventbus.events.flags.DirectEvent; import mightypork.utils.eventbus.events.flags.DirectEvent;
@@ -25,7 +25,7 @@ import mightypork.utils.logging.Log;
* *
* @author Ondřej Hruška (MightyPork) * @author Ondřej Hruška (MightyPork)
*/ */
final public class EventBus implements Destroyable, BusAccess { final public class EventBus implements Destroyable {
/** /**
* Queued event holder * Queued event holder
@@ -206,7 +206,7 @@ final public class EventBus implements Destroyable, BusAccess {
final DelayQueueEntry dm = new DelayQueueEntry(delay, event); final DelayQueueEntry dm = new DelayQueueEntry(delay, event);
if (shallLog(event)) { if (shallLog(event)) {
Log.f3(logMark + "Qu [" + Support.str(event) + "]" + (delay == 0 ? "" : (", delay: " + delay + "s"))); Log.f3(logMark + "Qu [" + Str.val(event) + "]" + (delay == 0 ? "" : (", delay: " + delay + "s")));
} }
sendQueue.add(dm); sendQueue.add(dm);
@@ -224,7 +224,7 @@ final public class EventBus implements Destroyable, BusAccess {
{ {
assertLive(); assertLive();
if (shallLog(event)) Log.f3(logMark + "Di [" + Support.str(event) + "]"); if (shallLog(event)) Log.f3(logMark + "Di [" + Str.val(event) + "]");
dispatch(event); dispatch(event);
} }
@@ -234,7 +234,7 @@ final public class EventBus implements Destroyable, BusAccess {
{ {
assertLive(); assertLive();
if (shallLog(event)) Log.f3(logMark + "Di->sub [" + Support.str(event) + "]"); if (shallLog(event)) Log.f3(logMark + "Di->sub [" + Str.val(event) + "]");
doDispatch(delegatingClient.getChildClients(), event); doDispatch(delegatingClient.getChildClients(), event);
} }
@@ -254,7 +254,7 @@ final public class EventBus implements Destroyable, BusAccess {
clients.add(client); clients.add(client);
if (detailedLogging) Log.f3(logMark + "Client joined: " + Support.str(client)); if (detailedLogging) Log.f3(logMark + "Client joined: " + Str.val(client));
} }
@@ -269,7 +269,7 @@ final public class EventBus implements Destroyable, BusAccess {
clients.remove(client); clients.remove(client);
if (detailedLogging) Log.f3(logMark + "Client left: " + Support.str(client)); if (detailedLogging) Log.f3(logMark + "Client left: " + Str.val(client));
} }
@@ -278,7 +278,7 @@ final public class EventBus implements Destroyable, BusAccess {
{ {
try { try {
if (detailedLogging) { if (detailedLogging) {
Log.f3(logMark + "Setting up channel for new event type: " + Support.str(event.getClass())); Log.f3(logMark + "Setting up channel for new event type: " + Str.val(event.getClass()));
} }
final Class<?> listener = getEventListenerClass(event); final Class<?> listener = getEventListenerClass(event);
@@ -290,13 +290,13 @@ final public class EventBus implements Destroyable, BusAccess {
//channels.flush(); //channels.flush();
if (detailedLogging) { if (detailedLogging) {
Log.f3(logMark + "Created new channel: " + Support.str(event.getClass()) + " -> " + Support.str(listener)); Log.f3(logMark + "Created new channel: " + Str.val(event.getClass()) + " -> " + Str.val(listener));
} }
return true; return true;
} else { } else {
Log.w(logMark + "Could not create channel for event " + Support.str(event.getClass())); Log.w(logMark + "Could not create channel for event " + Str.val(event.getClass()));
} }
} catch (final Throwable t) { } catch (final Throwable t) {
@@ -362,8 +362,8 @@ final public class EventBus implements Destroyable, BusAccess {
break; break;
} }
if (!accepted) Log.e(logMark + "Not accepted by any channel: " + Support.str(event)); if (!accepted) Log.e(logMark + "Not accepted by any channel: " + Str.val(event));
if (!event.wasServed() && shallLog(event)) Log.w(logMark + "Not delivered: " + Support.str(event)); if (!event.wasServed() && shallLog(event)) Log.w(logMark + "Not delivered: " + Str.val(event));
} }
@@ -375,11 +375,4 @@ final public class EventBus implements Destroyable, BusAccess {
return true; return true;
} }
@Override
public EventBus getEventBus()
{
return this; // just for compatibility use-case
}
} }
@@ -5,7 +5,7 @@ import java.util.Collection;
import java.util.HashSet; import java.util.HashSet;
import mightypork.utils.Reflect; import mightypork.utils.Reflect;
import mightypork.utils.Support; import mightypork.utils.Str;
import mightypork.utils.eventbus.clients.DelegatingClient; import mightypork.utils.eventbus.clients.DelegatingClient;
import mightypork.utils.eventbus.clients.ToggleableClient; import mightypork.utils.eventbus.clients.ToggleableClient;
import mightypork.utils.eventbus.events.flags.NonRejectableEvent; import mightypork.utils.eventbus.events.flags.NonRejectableEvent;
@@ -76,7 +76,7 @@ class EventChannel<EVENT extends BusEvent<CLIENT>, CLIENT> {
// avoid executing more times // avoid executing more times
if (processed.contains(client)) { if (processed.contains(client)) {
Log.w(EventBus.logMark + "Client already served: " + Support.str(client)); Log.w(EventBus.logMark + "Client already served: " + Str.val(client));
continue; continue;
} }
processed.add(client); processed.add(client);
@@ -203,6 +203,6 @@ class EventChannel<EVENT extends BusEvent<CLIENT>, CLIENT> {
@Override @Override
public String toString() public String toString()
{ {
return "{ " + Support.str(eventClass) + " => " + Support.str(clientClass) + " }"; return "{ " + Str.val(eventClass) + " => " + Str.val(clientClass) + " }";
} }
} }
@@ -5,7 +5,6 @@ import java.util.Collection;
import java.util.LinkedHashSet; import java.util.LinkedHashSet;
import java.util.Set; import java.util.Set;
import mightypork.utils.eventbus.BusAccess;
import mightypork.utils.eventbus.EventBus; import mightypork.utils.eventbus.EventBus;
@@ -15,24 +14,13 @@ import mightypork.utils.eventbus.EventBus;
* *
* @author Ondřej Hruška (MightyPork) * @author Ondřej Hruška (MightyPork)
*/ */
public abstract class BusNode implements BusAccess, ClientHub { public abstract class BusNode implements ClientHub {
private final BusAccess busAccess;
private final Set<Object> clients = new LinkedHashSet<>(); private final Set<Object> clients = new LinkedHashSet<>();
private boolean listening = true; private boolean listening = true;
private boolean delegating = true; private boolean delegating = true;
/**
* @param busAccess access to bus
*/
public BusNode(BusAccess busAccess)
{
this.busAccess = busAccess;
}
@Override @Override
public Collection<Object> getChildClients() public Collection<Object> getChildClients()
{ {
@@ -62,10 +50,6 @@ public abstract class BusNode implements BusAccess, ClientHub {
@Override @Override
public void addChildClient(Object client) public void addChildClient(Object client)
{ {
if (client instanceof RootBusNode) {
throw new IllegalArgumentException("Cannot nest RootBusNode.");
}
clients.add(client); clients.add(client);
} }
@@ -104,12 +88,4 @@ public abstract class BusNode implements BusAccess, ClientHub {
{ {
this.delegating = delegating; this.delegating = delegating;
} }
@Override
public EventBus getEventBus()
{
return busAccess.getEventBus();
}
} }
@@ -18,5 +18,4 @@ public class ClientList extends ArrayList<Object> {
super.add(c); super.add(c);
} }
} }
} }
@@ -11,17 +11,30 @@ import mightypork.utils.interfaces.Enableable;
* *
* @author Ondřej Hruška (MightyPork) * @author Ondřej Hruška (MightyPork)
*/ */
public class DelegatingList extends ClientList implements DelegatingClient, Enableable { public class DelegatingList extends ClientList implements DelegatingClient, Enableable, ToggleableClient {
private boolean enabled = true; private boolean enabled = true;
/**
* Delegating list with initial clients
*
* @param clients initial list members (clients)
*/
public DelegatingList(Object... clients) public DelegatingList(Object... clients)
{ {
super(clients); super(clients);
} }
/**
* Empty delegating list.
*/
public DelegatingList()
{
}
@Override @Override
public Collection<?> getChildClients() public Collection<?> getChildClients()
{ {
@@ -36,6 +49,13 @@ public class DelegatingList extends ClientList implements DelegatingClient, Enab
} }
@Override
public boolean isListening()
{
return isEnabled();
}
@Override @Override
public void setEnabled(boolean yes) public void setEnabled(boolean yes)
{ {
@@ -1,45 +0,0 @@
package mightypork.utils.eventbus.clients;
import mightypork.utils.annotations.DefaultImpl;
import mightypork.utils.eventbus.BusAccess;
import mightypork.utils.interfaces.Destroyable;
/**
* Bus node that should be directly attached to the bus.
*
* @author Ondřej Hruška (MightyPork)
*/
public abstract class RootBusNode extends BusNode implements Destroyable {
/**
* @param busAccess access to bus
*/
public RootBusNode(BusAccess busAccess)
{
super(busAccess);
getEventBus().subscribe(this);
}
@Override
public final void destroy()
{
deinit();
getEventBus().unsubscribe(this);
}
/**
* Deinitialize the subsystem<br>
* (called during destruction)
*/
@DefaultImpl
protected void deinit()
{
}
}
@@ -4,6 +4,7 @@ package mightypork.utils.eventbus.events;
import mightypork.utils.eventbus.BusEvent; import mightypork.utils.eventbus.BusEvent;
import mightypork.utils.eventbus.events.flags.DirectEvent; import mightypork.utils.eventbus.events.flags.DirectEvent;
import mightypork.utils.eventbus.events.flags.NonConsumableEvent; import mightypork.utils.eventbus.events.flags.NonConsumableEvent;
import mightypork.utils.eventbus.events.flags.NonRejectableEvent;
import mightypork.utils.interfaces.Destroyable; import mightypork.utils.interfaces.Destroyable;
@@ -14,6 +15,7 @@ import mightypork.utils.interfaces.Destroyable;
*/ */
@DirectEvent @DirectEvent
@NonConsumableEvent @NonConsumableEvent
@NonRejectableEvent
public class DestroyEvent extends BusEvent<Destroyable> { public class DestroyEvent extends BusEvent<Destroyable> {
@Override @Override
@@ -17,12 +17,13 @@ import java.io.UnsupportedEncodingException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import mightypork.utils.Str;
import mightypork.utils.logging.Log; import mightypork.utils.logging.Log;
import mightypork.utils.string.StringUtil;
import mightypork.utils.string.validation.StringFilter; import mightypork.utils.string.validation.StringFilter;
public class FileUtils { public class FileUtil {
/** /**
* Copy directory recursively. * Copy directory recursively.
@@ -188,7 +189,7 @@ public class FileUtils {
*/ */
public static List<File> listDirectory(File dir) public static List<File> listDirectory(File dir)
{ {
return FileUtils.listDirectory(dir, null); return FileUtil.listDirectory(dir, null);
} }
@@ -233,7 +234,7 @@ public class FileUtils {
public static String getExtension(String file) public static String getExtension(String file)
{ {
return StringUtil.fromLastChar(file, '.'); return Str.fromLast(file, '.');
} }
@@ -248,13 +249,13 @@ public class FileUtils {
String ext, name; String ext, name;
try { try {
ext = StringUtil.fromLastDot(filename); ext = Str.fromLastDot(filename);
} catch (final StringIndexOutOfBoundsException e) { } catch (final StringIndexOutOfBoundsException e) {
ext = ""; ext = "";
} }
try { try {
name = StringUtil.toLastDot(filename); name = Str.toLastDot(filename);
} catch (final StringIndexOutOfBoundsException e) { } catch (final StringIndexOutOfBoundsException e) {
name = ""; name = "";
Log.w("Error extracting extension from file " + filename); Log.w("Error extracting extension from file " + filename);
@@ -335,24 +336,31 @@ public class FileUtils {
public static InputStream getResource(String path) public static InputStream getResource(String path)
{ {
final InputStream in = FileUtils.class.getResourceAsStream(path); final InputStream in = FileUtil.class.getResourceAsStream(path);
if (in != null) return in; if (in != null) return in;
try { try {
return new FileInputStream(new File(".", path)); return new FileInputStream(new File(".", path));
} catch (final FileNotFoundException e) { } catch (final FileNotFoundException e) {
// error
Log.w("Could not open resource stream: " + path); try {
return new FileInputStream(WorkDir.getFile(path));
} catch (final FileNotFoundException e2) {
Log.w("Could not open resource stream, file not found: " + path);
return null; return null;
} }
} }
}
public static String getResourceAsString(String path) public static String getResourceAsString(String path)
{ {
return streamToString(FileUtils.class.getResourceAsStream(path)); return streamToString(getResource(path));
} }
@@ -394,13 +402,13 @@ public class FileUtils {
public static String getBasename(String name) public static String getBasename(String name)
{ {
return StringUtil.toLastChar(StringUtil.fromLastChar(name, '/'), '.'); return Str.toLast(Str.fromLast(name, '/'), '.');
} }
public static String getFilename(String name) public static String getFilename(String name)
{ {
return StringUtil.fromLastChar(name, '/'); return Str.fromLast(name, '/');
} }
@@ -413,10 +421,10 @@ public class FileUtils {
*/ */
public static void resourceToFile(String resname, File file) throws IOException public static void resourceToFile(String resname, File file) throws IOException
{ {
try(InputStream in = FileUtils.getResource(resname); try(InputStream in = FileUtil.getResource(resname);
OutputStream out = new FileOutputStream(file)) { OutputStream out = new FileOutputStream(file)) {
FileUtils.copyStream(in, out); FileUtil.copyStream(in, out);
} }
} }
@@ -431,7 +439,7 @@ public class FileUtils {
*/ */
public static String resourceToString(String resname) throws IOException public static String resourceToString(String resname) throws IOException
{ {
try(InputStream in = FileUtils.getResource(resname)) { try(InputStream in = FileUtil.getResource(resname)) {
return streamToString(in); return streamToString(in);
} }
} }
+96
View File
@@ -0,0 +1,96 @@
package mightypork.utils.files;
import java.io.File;
import java.util.HashMap;
import java.util.Map;
import mightypork.utils.logging.Log;
/**
* Working directory helper.
*
* @author Ondřej Hruška (MightyPork)
*/
public class WorkDir {
private static File baseDir = new File(".");
private static Map<String, String> namedPaths = new HashMap<>();
/**
* Initialize the workdir for the given root path
*
* @param workdir workdir root path
*/
public static void setBaseDir(File workdir)
{
WorkDir.baseDir = workdir;
}
/**
* Add a path alias (dir or file), relative to the workdir.
*
* @param alias path alias
* @param path path relative to workdir
*/
public static void addPath(String alias, String path)
{
namedPaths.put(alias, path);
}
/**
* Get workdir folder, create if not exists.
*
* @param path dir path relative to workdir
* @return dir file
*/
public static File getDir(String path)
{
if (namedPaths.containsKey(path)) path = namedPaths.get(path);
final File f = new File(baseDir, path);
if (!f.exists()) {
if (!f.mkdirs()) {
Log.w("Could not create a directory: " + f + " (path: " + path + ")");
}
}
return f;
}
/**
* Get workdir file, create parent if not exists.
*
* @param path dir path relative to workdir
* @return dir file
*/
public static File getFile(String path)
{
if (namedPaths.containsKey(path)) path = namedPaths.get(path);
final File f = new File(baseDir, path);
// create the parent dir
if (!f.getParent().equals(baseDir)) {
f.getParentFile().mkdirs();
}
return f;
}
/**
* @return the workdir File
*/
public static File getBaseDir()
{
return baseDir;
}
}
@@ -1,71 +0,0 @@
package mightypork.utils.files.config;
import mightypork.utils.Convert;
public abstract class Property<T extends Object> {
private final String comment;
private final String key;
private T value;
private final T defaultValue;
public Property(String key, T defaultValue, String comment)
{
super();
this.comment = comment;
this.key = key;
this.value = defaultValue;
this.defaultValue = defaultValue;
}
public final void parse(String string)
{
setValue(decode(string, defaultValue));
}
public abstract T decode(String string, T defval);
public String encode(T value)
{
return Convert.toString(value, Convert.toString(defaultValue));
}
@Override
public final String toString()
{
return encode(value);
}
public T getValue()
{
return value;
}
@SuppressWarnings("unchecked")
public void setValue(Object value)
{
this.value = (T) value;
}
public String getComment()
{
return comment;
}
public String getKey()
{
return key;
}
}
@@ -1,377 +0,0 @@
package mightypork.utils.files.config;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Map.Entry;
import java.util.TreeMap;
import mightypork.utils.Convert;
import mightypork.utils.logging.Log;
/**
* Property manager with advanced formatting and value checking.
*
* @author Ondřej Hruška (MightyPork)
*/
public class PropertyManager {
private class BooleanProperty extends Property<Boolean> {
public BooleanProperty(String key, Boolean defaultValue, String comment)
{
super(key, defaultValue, comment);
}
@Override
public Boolean decode(String string, Boolean defval)
{
return Convert.toBoolean(string, defval);
}
}
private class IntegerProperty extends Property<Integer> {
public IntegerProperty(String key, Integer defaultValue, String comment)
{
super(key, defaultValue, comment);
}
@Override
public Integer decode(String string, Integer defval)
{
return Convert.toInteger(string, defval);
}
}
private class DoubleProperty extends Property<Double> {
public DoubleProperty(String key, Double defaultValue, String comment)
{
super(key, defaultValue, comment);
}
@Override
public Double decode(String string, Double defval)
{
return Convert.toDouble(string, defval);
}
}
private class StringProperty extends Property<String> {
public StringProperty(String key, String defaultValue, String comment)
{
super(key, defaultValue, comment);
}
@Override
public String decode(String string, String defval)
{
return Convert.toString(string, defval);
}
}
/** put newline before entry comments */
private boolean cfgNewlineBeforeComments = true;
/** Put newline between sections. */
private boolean cfgSeparateSections = true;
private final File file;
private String fileComment = "";
private final TreeMap<String, Property<?>> entries;
private final TreeMap<String, String> renameTable;
private SortedProperties props = new SortedProperties();
/**
* Create property manager from file path and an initial comment.
*
* @param file file with the props
* @param comment the initial comment. Use \n in it if you want.
*/
public PropertyManager(File file, String comment)
{
this.file = file;
this.entries = new TreeMap<>();
this.renameTable = new TreeMap<>();
this.fileComment = comment;
}
/**
* Load, fix and write to file.
*/
public void load()
{
if (!file.getParentFile().mkdirs()) {
if (!file.getParentFile().exists()) {
throw new RuntimeException("Cound not create config file.");
}
}
try(FileInputStream fis = new FileInputStream(file)) {
props.load(fis);
} catch (final IOException e) {
props = new SortedProperties();
}
props.cfgBlankRowBetweenSections = cfgSeparateSections;
props.cfgBlankRowBeforeComment = cfgNewlineBeforeComments;
// rename keys
for (final Entry<String, String> entry : renameTable.entrySet()) {
final String pr = props.getProperty(entry.getKey());
if (pr == null) continue;
props.remove(entry.getKey());
props.setProperty(entry.getValue(), pr);
}
for (final Property<?> entry : entries.values()) {
entry.parse(props.getProperty(entry.getKey()));
}
renameTable.clear();
}
public void save()
{
try {
final ArrayList<String> keyList = new ArrayList<>();
// validate entries one by one, replace with default when needed
for (final Property<?> entry : entries.values()) {
keyList.add(entry.getKey());
if (entry.getComment() != null) {
props.setKeyComment(entry.getKey(), entry.getComment());
}
props.setProperty(entry.getKey(), entry.toString());
}
// removed unused props
for (final String propname : props.keySet().toArray(new String[props.size()])) {
if (!keyList.contains(propname)) {
props.remove(propname);
}
}
try(FileOutputStream fos = new FileOutputStream(file)) {
props.store(fos, fileComment);
}
} catch (final IOException ioe) {
ioe.printStackTrace();
}
}
/**
* @param newlineBeforeComments put newline before comments
*/
public void cfgNewlineBeforeComments(boolean newlineBeforeComments)
{
this.cfgNewlineBeforeComments = newlineBeforeComments;
}
/**
* @param separateSections do separate sections by newline
*/
public void cfgSeparateSections(boolean separateSections)
{
this.cfgSeparateSections = separateSections;
}
/**
* Get a property entry (rarely used)
*
* @param k key
* @return the entry
*/
public Property<?> getProperty(String k)
{
try {
return entries.get(k);
} catch (final Exception e) {
Log.w(e);
return null;
}
}
/**
* Get boolean property
*
* @param k key
* @return the boolean found, or false
*/
public Boolean getBoolean(String k)
{
return Convert.toBoolean(getProperty(k).getValue());
}
/**
* Get numeric property
*
* @param k key
* @return the int found, or null
*/
public Integer getInteger(String k)
{
return Convert.toInteger(getProperty(k).getValue());
}
/**
* Get numeric property as double
*
* @param k key
* @return the double found, or null
*/
public Double getDouble(String k)
{
return Convert.toDouble(getProperty(k).getValue());
}
/**
* Get string property
*
* @param k key
* @return the string found, or null
*/
public String getString(String k)
{
return Convert.toString(getProperty(k).getValue());
}
/**
* Get arbitrary property. Make sure it's of the right type!
*
* @param k key
* @return the prioperty found
*/
@SuppressWarnings("unchecked")
public <T> T getValue(String k)
{
try {
return ((Property<T>) getProperty(k)).getValue();
} catch (final ClassCastException e) {
return null;
}
}
/**
* Add a boolean property
*
* @param k key
* @param d default value
* @param comment the in-file comment
*/
public void putBoolean(String k, boolean d, String comment)
{
putProperty(new BooleanProperty(k, d, comment));
}
/**
* Add a numeric property (double)
*
* @param k key
* @param d default value
* @param comment the in-file comment
*/
public void putDouble(String k, double d, String comment)
{
putProperty(new DoubleProperty(k, d, comment));
}
/**
* Add a numeric property
*
* @param k key
* @param d default value
* @param comment the in-file comment
*/
public void putInteger(String k, int d, String comment)
{
putProperty(new IntegerProperty(k, d, comment));
}
/**
* Add a string property
*
* @param k key
* @param d default value
* @param comment the in-file comment
*/
public void putString(String k, String d, String comment)
{
putProperty(new StringProperty(k, d, comment));
}
/**
* Add a range property
*
* @param prop property to put
*/
public <T> void putProperty(Property<T> prop)
{
entries.put(prop.getKey(), prop);
}
/**
* Rename key before loading; value is preserved
*
* @param oldKey old key
* @param newKey new key
*/
public void renameKey(String oldKey, String newKey)
{
renameTable.put(oldKey, newKey);
return;
}
/**
* Set value saved to certain key.
*
* @param key key
* @param value the saved value
*/
public void setValue(String key, Object value)
{
getProperty(key).setValue(value);
}
public void setFileComment(String fileComment)
{
this.fileComment = fileComment;
}
}
@@ -10,7 +10,7 @@ import java.util.HashSet;
import java.util.zip.ZipEntry; import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream; import java.util.zip.ZipOutputStream;
import mightypork.utils.files.FileUtils; import mightypork.utils.files.FileUtil;
import mightypork.utils.logging.Log; import mightypork.utils.logging.Log;
@@ -57,7 +57,7 @@ public class ZipBuilder {
out.putNextEntry(new ZipEntry(path)); out.putNextEntry(new ZipEntry(path));
FileUtils.copyStream(in, out); FileUtil.copyStream(in, out);
} }
@@ -76,8 +76,8 @@ public class ZipBuilder {
out.putNextEntry(new ZipEntry(path)); out.putNextEntry(new ZipEntry(path));
try(InputStream in = FileUtils.stringToStream(text)) { try(InputStream in = FileUtil.stringToStream(text)) {
FileUtils.copyStream(in, out); FileUtil.copyStream(in, out);
} }
} }
@@ -97,8 +97,8 @@ public class ZipBuilder {
out.putNextEntry(new ZipEntry(path)); out.putNextEntry(new ZipEntry(path));
try(InputStream in = FileUtils.getResource(resPath)) { try(InputStream in = FileUtil.getResource(resPath)) {
FileUtils.copyStream(in, out); FileUtil.copyStream(in, out);
} }
} }
+3 -3
View File
@@ -13,7 +13,7 @@ import java.util.List;
import java.util.zip.ZipEntry; import java.util.zip.ZipEntry;
import java.util.zip.ZipFile; import java.util.zip.ZipFile;
import mightypork.utils.files.FileUtils; import mightypork.utils.files.FileUtil;
import mightypork.utils.logging.Log; import mightypork.utils.logging.Log;
import mightypork.utils.string.validation.StringFilter; import mightypork.utils.string.validation.StringFilter;
@@ -144,7 +144,7 @@ public class ZipUtils {
FileOutputStream fos = new FileOutputStream(destFile); FileOutputStream fos = new FileOutputStream(destFile);
BufferedOutputStream dest = new BufferedOutputStream(fos, BUFFER_SIZE)) { BufferedOutputStream dest = new BufferedOutputStream(fos, BUFFER_SIZE)) {
FileUtils.copyStream(is, dest); FileUtil.copyStream(is, dest);
} }
} }
@@ -162,7 +162,7 @@ public class ZipUtils {
BufferedInputStream is = null; BufferedInputStream is = null;
try { try {
is = new BufferedInputStream(zip.getInputStream(entry)); is = new BufferedInputStream(zip.getInputStream(entry));
final String s = FileUtils.streamToString(is); final String s = FileUtil.streamToString(is);
return s; return s;
} finally { } finally {
try { try {
@@ -0,0 +1,15 @@
package mightypork.utils.interfaces;
/**
* Element that can be hidden or visible
*
* @author Ondřej Hruška (MightyPork)
*/
public interface Hideable {
void setVisible(boolean yes);
boolean isVisible();
}
+7 -9
View File
@@ -13,7 +13,7 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import mightypork.utils.Reflect; import mightypork.utils.Reflect;
import mightypork.utils.Support; import mightypork.utils.Str;
/** /**
@@ -85,7 +85,6 @@ public class Ion {
/** Array of arbitrary objects */ /** Array of arbitrary objects */
public static final int OBJECT_ARRAY = 26; public static final int OBJECT_ARRAY = 26;
/** Ionizables<Mark, Class> */ /** Ionizables<Mark, Class> */
private static Map<Integer, Class<?>> markToClass = new HashMap<>(); private static Map<Integer, Class<?>> markToClass = new HashMap<>();
private static Map<Class<?>, Integer> classToMark = new HashMap<>(); private static Map<Class<?>, Integer> classToMark = new HashMap<>();
@@ -117,7 +116,7 @@ public class Ion {
{ {
if (!IonBinary.class.isAssignableFrom(objClass)) { if (!IonBinary.class.isAssignableFrom(objClass)) {
if (!IonBundled.class.isAssignableFrom(objClass)) { if (!IonBundled.class.isAssignableFrom(objClass)) {
throw new IllegalArgumentException("Cannot register directly: " + Support.str(objClass)); throw new IllegalArgumentException("Cannot register directly: " + Str.val(objClass));
} }
} }
@@ -136,7 +135,7 @@ public class Ion {
{ {
if (!IonBinary.class.isAssignableFrom(objClass)) { if (!IonBinary.class.isAssignableFrom(objClass)) {
if (!IonBundled.class.isAssignableFrom(objClass)) { if (!IonBundled.class.isAssignableFrom(objClass)) {
throw new IllegalArgumentException("Cannot register directly: " + Support.str(objClass)); throw new IllegalArgumentException("Cannot register directly: " + Str.val(objClass));
} }
} }
@@ -162,7 +161,7 @@ public class Ion {
registerUsingMark(mark, objClass); registerUsingMark(mark, objClass);
} catch (final Exception e) { } catch (final Exception e) {
throw new RuntimeException("Could not register " + Support.str(objClass) + " using an ION_MARK field.", e); throw new RuntimeException("Could not register " + Str.val(objClass) + " using an ION_MARK field.", e);
} }
} }
@@ -224,7 +223,7 @@ public class Ion {
} }
if (classToMark.containsKey(objClass)) { if (classToMark.containsKey(objClass)) {
throw new IllegalArgumentException(Support.str(objClass) + " is already registered."); throw new IllegalArgumentException(Str.val(objClass) + " is already registered.");
} }
} }
@@ -377,7 +376,7 @@ public class Ion {
inst.load(bundle); inst.load(bundle);
return inst; return inst;
} catch (InstantiationException | IllegalAccessException e) { } catch (InstantiationException | IllegalAccessException e) {
throw new IOException("Could not instantiate " + Support.str(objClass) + "."); throw new IOException("Could not instantiate " + Str.val(objClass) + ".");
} }
} }
@@ -483,7 +482,7 @@ public class Ion {
static void assertRegistered(Object obj) static void assertRegistered(Object obj)
{ {
if (!isRegistered(obj)) { if (!isRegistered(obj)) {
throw new RuntimeException("Type not registered: " + Support.str(obj.getClass())); throw new RuntimeException("Type not registered: " + Str.val(obj.getClass()));
} }
} }
@@ -496,7 +495,6 @@ public class Ion {
{ {
final List<Integer> toRemove = new ArrayList<>(); final List<Integer> toRemove = new ArrayList<>();
// remove direct // remove direct
for (final Integer mark : markToClass.keySet()) { for (final Integer mark : markToClass.keySet()) {
if (!isMarkReserved(mark)) { if (!isMarkReserved(mark)) {
-2
View File
@@ -300,7 +300,6 @@ public class IonInput implements Closeable {
{ {
final int mark = readMark(); final int mark = readMark();
try { try {
if (Ion.isMarkForBinary(mark)) { if (Ion.isMarkForBinary(mark)) {
@@ -308,7 +307,6 @@ public class IonInput implements Closeable {
loaded = (IonBinary) Ion.getClassForMark(mark).newInstance(); loaded = (IonBinary) Ion.getClassForMark(mark).newInstance();
loaded.load(this); loaded.load(this);
return loaded; return loaded;
} }
-1
View File
@@ -299,7 +299,6 @@ public class IonOutput implements Closeable {
return; return;
} }
if (Ion.isObjectIndirectBundled(obj)) { if (Ion.isObjectIndirectBundled(obj)) {
final IonizerBundled<?> ionizer = Ion.getIonizerBundledForClass(obj.getClass()); final IonizerBundled<?> ionizer = Ion.getIonizerBundledForClass(obj.getClass());
+4 -1
View File
@@ -1,5 +1,6 @@
package mightypork.utils.ion; package mightypork.utils.ion;
import java.io.IOException; import java.io.IOException;
@@ -13,10 +14,12 @@ import java.io.IOException;
public abstract class IonizerBinary<T> { public abstract class IonizerBinary<T> {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
final void _save(Object object, IonOutput out) throws IOException{ final void _save(Object object, IonOutput out) throws IOException
{
save((T) object, out); save((T) object, out);
} }
/** /**
* Save an object to ion output * Save an object to ion output
* *
+3 -1
View File
@@ -11,10 +11,12 @@ package mightypork.utils.ion;
public abstract class IonizerBundled<T> { public abstract class IonizerBundled<T> {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
final void _save(Object object, IonDataBundle out) { final void _save(Object object, IonDataBundle out)
{
save((T) object, out); save((T) object, out);
} }
/** /**
* Save an object to data bundle * Save an object to data bundle
* *
+8 -2
View File
@@ -7,13 +7,13 @@ import java.io.StringWriter;
import java.util.HashMap; import java.util.HashMap;
import java.util.logging.Level; import java.util.logging.Level;
import mightypork.utils.Str;
import mightypork.utils.annotations.FactoryMethod; import mightypork.utils.annotations.FactoryMethod;
import mightypork.utils.logging.monitors.LogMonitor; import mightypork.utils.logging.monitors.LogMonitor;
import mightypork.utils.logging.monitors.LogMonitorStdout; import mightypork.utils.logging.monitors.LogMonitorStdout;
import mightypork.utils.logging.writers.ArchivingLog; import mightypork.utils.logging.writers.ArchivingLog;
import mightypork.utils.logging.writers.LogWriter; import mightypork.utils.logging.writers.LogWriter;
import mightypork.utils.logging.writers.SimpleLog; import mightypork.utils.logging.writers.SimpleLog;
import mightypork.utils.string.StringUtil;
/** /**
@@ -82,6 +82,12 @@ public class Log {
} }
public static LogWriter getMainLogger()
{
return main;
}
public static void addMonitor(LogMonitor mon) public static void addMonitor(LogMonitor mon)
{ {
assertInited(); assertInited();
@@ -309,7 +315,7 @@ public class Log {
final long time_ms = (System.currentTimeMillis() - start_ms); final long time_ms = (System.currentTimeMillis() - start_ms);
final double time_s = time_ms / 1000D; final double time_s = time_ms / 1000D;
final String time = String.format("%6.2f ", time_s); final String time = String.format("%6.2f ", time_s);
final String time_blank = StringUtil.repeat(" ", time.length()); final String time_blank = Str.repeat(" ", time.length());
String prefix = "[ ? ]"; String prefix = "[ ? ]";
@@ -9,8 +9,8 @@ import java.util.Comparator;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
import mightypork.utils.files.FileUtils; import mightypork.utils.Str;
import mightypork.utils.string.StringUtil; import mightypork.utils.files.FileUtil;
/** /**
@@ -67,10 +67,10 @@ public class ArchivingLog extends SimpleLog {
final File log_file = getFile(); final File log_file = getFile();
final File log_dir = log_file.getParentFile(); final File log_dir = log_file.getParentFile();
final String fname = FileUtils.getBasename(log_file.toString()); final String fname = FileUtil.getBasename(log_file.toString());
// move old file // move old file
for (final File f : FileUtils.listDirectory(log_dir)) { for (final File f : FileUtil.listDirectory(log_dir)) {
if (!f.isFile()) continue; if (!f.isFile()) continue;
if (f.equals(getFile())) { if (f.equals(getFile())) {
@@ -88,7 +88,7 @@ public class ArchivingLog extends SimpleLog {
if (logs_to_keep == -1) return; // keep all if (logs_to_keep == -1) return; // keep all
final List<File> oldLogs = FileUtils.listDirectory(log_dir, new FileFilter() { final List<File> oldLogs = FileUtil.listDirectory(log_dir, new FileFilter() {
@Override @Override
public boolean accept(File f) public boolean accept(File f)
@@ -125,6 +125,6 @@ public class ArchivingLog extends SimpleLog {
*/ */
private String getSuffix() private String getSuffix()
{ {
return StringUtil.fromLastChar(getFile().toString(), '.'); return Str.fromLast(getFile().toString(), '.');
} }
} }
+12
View File
@@ -0,0 +1,12 @@
package mightypork.utils.math;
/**
* Horizontal align sides
*
* @author Ondřej Hruška (MightyPork)
*/
public enum AlignX
{
LEFT, CENTER, RIGHT;
}
+12
View File
@@ -0,0 +1,12 @@
package mightypork.utils.math;
/**
* Vertical align sides
*
* @author Ondřej Hruška (MightyPork)
*/
public enum AlignY
{
TOP, CENTER, BOTTOM;
}
@@ -100,7 +100,6 @@ public abstract class PathFinder {
a.h_cost = (int) (heuristic.getCost(a.pos, end) * getMinCost()); a.h_cost = (int) (heuristic.getCost(a.pos, end) * getMinCost());
a.parent = current; a.parent = current;
if (!closed.contains(a)) { if (!closed.contains(a)) {
if (open.contains(a)) { if (open.contains(a)) {
@@ -1,7 +1,7 @@
package mightypork.utils.math.animation; package mightypork.utils.math.animation;
import mightypork.utils.annotations.DefaultImpl; import mightypork.utils.annotations.Stub;
import mightypork.utils.interfaces.Pauseable; import mightypork.utils.interfaces.Pauseable;
import mightypork.utils.interfaces.Updateable; import mightypork.utils.interfaces.Updateable;
import mightypork.utils.math.Calc; import mightypork.utils.math.Calc;
@@ -120,7 +120,7 @@ public abstract class Animator implements NumBound, Updateable, Pauseable {
} }
@DefaultImpl @Stub
protected abstract void nextCycle(NumAnimated anim); protected abstract void nextCycle(NumAnimated anim);
@@ -244,4 +244,37 @@ public abstract class Color {
{ {
return new ColorAlphaAdjuster(this, multiplier); return new ColorAlphaAdjuster(this, multiplier);
} }
@Override
public int hashCode()
{
final int prime = 31;
int result = 1;
long temp;
temp = Double.doubleToLongBits(b());
result = prime * result + (int) (temp ^ (temp >>> 32));
temp = Double.doubleToLongBits(g());
result = prime * result + (int) (temp ^ (temp >>> 32));
temp = Double.doubleToLongBits(r());
result = prime * result + (int) (temp ^ (temp >>> 32));
temp = Double.doubleToLongBits(a());
result = prime * result + (int) (temp ^ (temp >>> 32));
return result;
}
@Override
public boolean equals(Object obj)
{
if (this == obj) return true;
if (obj == null) return false;
if (!(obj instanceof Color)) return false;
final Color other = (Color) obj;
if (Double.doubleToLongBits(b()) != Double.doubleToLongBits(other.b())) return false;
if (Double.doubleToLongBits(g()) != Double.doubleToLongBits(other.g())) return false;
if (Double.doubleToLongBits(r()) != Double.doubleToLongBits(other.r())) return false;
if (Double.doubleToLongBits(a()) != Double.doubleToLongBits(other.a())) return false;
return true;
}
} }
+29
View File
@@ -0,0 +1,29 @@
package mightypork.utils.math.color;
/**
* Linear gradient (each corner can have different color)
*
* @author MightyPork
*/
public class Grad {
public final Color leftTop, rightTop, rightBottom, leftBottom;
/**
* Create a gradient
*
* @param leftTop left top color
* @param rightTop right top color
* @param rightBottom right bottom color
* @param leftBottom left bottom color
*/
public Grad(Color leftTop, Color rightTop, Color rightBottom, Color leftBottom)
{
this.leftTop = leftTop;
this.rightTop = rightTop;
this.rightBottom = rightBottom;
this.leftBottom = leftBottom;
}
}
@@ -0,0 +1,15 @@
package mightypork.utils.math.color;
/**
* Linear horizontal gradient
*
* @author MightyPork
*/
public class GradH extends Grad {
public GradH(Color left, Color right)
{
super(left, right, right, left);
}
}
@@ -0,0 +1,15 @@
package mightypork.utils.math.color;
/**
* Linear vertical gradient
*
* @author MightyPork
*/
public class GradV extends Grad {
public GradV(Color top, Color bottom)
{
super(top, top, bottom, bottom);
}
}
@@ -21,7 +21,6 @@ public class RGB {
public static final Color BLACK_80 = Color.rgba(0, 0, 0, 0.8); public static final Color BLACK_80 = Color.rgba(0, 0, 0, 0.8);
public static final Color BLACK_90 = Color.rgba(0, 0, 0, 0.9); public static final Color BLACK_90 = Color.rgba(0, 0, 0, 0.9);
public static final Color WHITE = Color.fromHex(0xFFFFFF); public static final Color WHITE = Color.fromHex(0xFFFFFF);
public static final Color BLACK = Color.fromHex(0x000000); public static final Color BLACK = Color.fromHex(0x000000);
public static final Color GRAY_DARK = Color.fromHex(0x808080); public static final Color GRAY_DARK = Color.fromHex(0x808080);
@@ -1058,5 +1058,4 @@ public abstract class Rect implements RectBound, CachedDigestable<RectDigest> {
return ((rw < rx || rw > tx) && (rh < ry || rh > ty) && (tw < tx || tw > rx) && (th < ty || th > ry)); return ((rw < rx || rw > tx) && (rh < ry || rh > ty) && (tw < tx || tw > rx) && (th < ty || th > ry));
} }
} }
+36 -4
View File
@@ -1,31 +1,63 @@
package mightypork.utils.math.timing; package mightypork.utils.math.timing;
import mightypork.utils.Support;
import mightypork.utils.Str;
/**
* Time metering utils for profiling.<br>
* The profiler work with long (starting ms time), so it has very little
* overhead and you can easily have multiple "profilers" running at the same
* time.
*
* @author Ondřej Hruška (MightyPork)
*/
public class Profiler { public class Profiler {
/**
* Get current time, to be later used in the end*() methods
*
* @return current time (ms)
*/
public static long begin() public static long begin()
{ {
return System.currentTimeMillis(); return System.currentTimeMillis();
} }
/**
* Get seconds since begin.
*
* @param begun profiling start time (ms), obtained using begin()
* @return seconds elapsed
*/
public static double end(long begun) public static double end(long begun)
{ {
return endLong(begun) / 1000D; return endMs(begun) / 1000D;
} }
public static long endLong(long begun) /**
* Get milliseconds since begin.
*
* @param begun profiling start time (ms), obtained using begin()
* @return milliseconds elapsed
*/
public static long endMs(long begun)
{ {
return System.currentTimeMillis() - begun; return System.currentTimeMillis() - begun;
} }
/**
* Elapsed time in human readable format, in seconds.
*
* @param begun profiling start time (ms), obtained using begin()
* @return something like "0.121 s"
*/
public static String endStr(long begun) public static String endStr(long begun)
{ {
return Support.str(end(begun)) + " s"; return Str.val(end(begun)) + " s";
} }
} }
@@ -1,82 +0,0 @@
package mightypork.utils.string;
/**
* General purpose string utilities
*
* @author Ondřej Hruška (MightyPork)
*/
public class StringUtil {
public static String fromLastDot(String s)
{
return fromLastChar(s, '.');
}
public static String toLastDot(String s)
{
return toLastChar(s, '.');
}
public static String fromLastChar(String s, char c)
{
if (s == null) return null;
return s.substring(s.lastIndexOf(c) + 1, s.length());
}
public static String toLastChar(String s, char c)
{
if (s == null) return null;
if (s.lastIndexOf(c) == -1) return s;
return s.substring(0, s.lastIndexOf(c));
}
/**
* Repeat a string
*
* @param repeated string
* @param count
* @return output
*/
public static String repeat(String repeated, int count)
{
String s = "";
for (int i = 0; i < count; i++)
s += repeated;
return s;
}
public static boolean isValidFilenameChar(char ch)
{
return isValidFilenameString(Character.toString(ch));
}
public static boolean isValidFilenameString(String filename)
{
return filename.matches("[a-zA-Z0-9 +\\-.,_%@#!]+");
}
public static String ellipsisStart(String orig, int length)
{
if (orig.length() > length) {
orig = "\u2026" + orig.substring(length, orig.length());
}
return orig;
}
public static String ellipsisEnd(String orig, int length)
{
if (orig.length() > length) {
orig = orig.substring(0, length - 1) + "\u2026";
}
return orig;
}
}
+18 -2
View File
@@ -2,21 +2,37 @@ package mightypork.utils.string;
/** /**
* String provider with constant string * String provider that holds a string.
* *
* @author Ondřej Hruška (MightyPork) * @author Ondřej Hruška (MightyPork)
*/ */
public class StringWrapper implements StringProvider { public class StringWrapper implements StringProvider {
private final String value; private String value;
/**
* Create a string wrapper
*
* @param value original value
*/
public StringWrapper(String value) public StringWrapper(String value)
{ {
this.value = value; this.value = value;
} }
/**
* Set the string
*
* @param value string to set
*/
public void setString(String value)
{
this.value = value;
}
@Override @Override
public String getString() public String getString()
{ {