#
# Version:
# - 1.0.0: add a version comment
+# - 1.1.0: add help, sjar
# Required parameters (the commented out ones are supposed to change per project):
RJAR = java
RJAR_FLAGS += -jar
-# Usual options:
-# make : to build the jar file
-# make libs : to update the libraries into src/
-# make build : to update the binaries (not the jar)
-# make test : to update the test binaries
-# make build jar : to update the binaries and jar file
-# make clean : to clean the directory of intermediate files
-# make mrpropre : to clean the directory of all outputs
-# make run : to run the program from the binaries
-# make run-test : to run the test program from the binaries
-# make jrun : to run the program from the jar file
-# make install : to install the application into $PREFIX
-
-# Note: build is actually slower than rebuild in most cases except when
-# small changes only are detected ; so we use rebuild by default
-
all: build jar
-.PHONY: all clean mrproper mrpropre build run jrun jar resources test-resources install libs love
+help:
+ @echo "Usual options:"
+ @echo "=============="
+ @echo " make : to build the jar file"
+ @echo " make help : to get this help screen"
+ @echo " make libs : to update the libraries into src/"
+ @echo " make build : to update the binaries (not the jar)"
+ @echo " make test : to update the test binaries"
+ @echo " make build jar : to update the binaries and jar file"
+ @echo " make sjar : to create the sources jar file"
+ @echo " make clean : to clean the directory of intermediate files"
+ @echo " make mrpropre : to clean the directory of all outputs"
+ @echo " make run : to run the program from the binaries"
+ @echo " make run-test : to run the test program from the binaries"
+ @echo " make jrun : to run the program from the jar file"
+ @echo " make install : to install the application into $PREFIX"
+
+.PHONY: all clean mrproper mrpropre build run jrun jar sjar resources test-resources install libs love
bin:
@mkdir -p bin
jar: $(NAME).jar
+sjar: $(NAME)-sources.jar
+
build: resources
@echo Compiling program...
@echo " src/$(MAIN)"
done )
@[ ! -d libs ] || touch bin/libs
-$(NAME).jar: resources
- @[ -e bin/$(MAIN).class ] || echo You need to build the sources
- @[ -e bin/$(MAIN).class ]
- @echo Making JAR file...
+$(NAME)-sources.jar: libs
+ @echo Making sources JAR file...
@echo > bin/manifest
@[ "$(SJAR_FLAGS)" = "" ] || echo Creating $(NAME)-sources.jar...
@[ "$(SJAR_FLAGS)" = "" ] || $(JAR) cfm $(NAME)-sources.jar bin/manifest $(SJAR_FLAGS)
@[ "$(SJAR_FLAGS)" = "" ] || [ ! -e VERSION ] || echo Copying to "$(NAME)-`cat VERSION`-sources.jar"...
@[ "$(SJAR_FLAGS)" = "" ] || [ ! -e VERSION ] || cp $(NAME)-sources.jar "$(NAME)-`cat VERSION`-sources.jar"
+
+$(NAME).jar: resources
+ @[ -e bin/$(MAIN).class ] || echo You need to build the sources
+ @[ -e bin/$(MAIN).class ]
@echo "Main-Class: `echo "$(MAIN)" | sed 's:/:.:g'`" > bin/manifest
@echo >> bin/manifest
$(JAR) cfm $(NAME).jar bin/manifest $(JAR_FLAGS)
# nikiroo-utils
+## Version 4.0.1
+
+- Android compatibility (see configure.sh --android=yes)
+
## Version 4.0.0
- Deplace all dependencies on java.awt into its own package (ui)
private long tooOldStable;
private TraceHandler tracer = new TraceHandler();
+ /**
+ * Only for inheritance.
+ */
+ protected Cache() {
+ }
+
/**
* Create a new {@link Cache} object.
*
this.tracer = tracer;
}
+ /**
+ * Check the resource to see if it is in the cache.
+ *
+ * @param uniqueID
+ * the resource to check
+ * @param allowTooOld
+ * allow files even if they are considered too old
+ * @param stable
+ * a stable file (that dones't change too often) -- parameter
+ * used to check if the file is too old to keep or not
+ *
+ * @return TRUE if it is
+ *
+ */
+ public boolean check(String uniqueID, boolean allowTooOld, boolean stable) {
+ return check(getCached(uniqueID), allowTooOld, stable);
+ }
+
/**
* Check the resource to see if it is in the cache.
*
*
*/
public boolean check(URL url, boolean allowTooOld, boolean stable) {
- File file = getCached(url);
- if (file.exists() && file.isFile()) {
- if (allowTooOld || !isOld(file, stable)) {
+ return check(getCached(url), allowTooOld, stable);
+ }
+
+ /**
+ * Check the resource to see if it is in the cache.
+ *
+ * @param cached
+ * the resource to check
+ * @param allowTooOld
+ * allow files even if they are considered too old
+ * @param stable
+ * a stable file (that dones't change too often) -- parameter
+ * used to check if the file is too old to keep or not
+ *
+ * @return TRUE if it is
+ *
+ */
+ private boolean check(File cached, boolean allowTooOld, boolean stable) {
+ if (cached.exists() && cached.isFile()) {
+ if (allowTooOld || !isOld(cached, stable)) {
return true;
}
}
* @param uniqueID
* a unique ID used to locate the cached resource
*
- * @return the resulting {@link File}
- *
* @throws IOException
* in case of I/O error
*/
- public File save(InputStream in, String uniqueID) throws IOException {
+ public void save(InputStream in, String uniqueID) throws IOException {
File cached = getCached(uniqueID);
cached.getParentFile().mkdirs();
- return save(in, cached);
+ save(in, cached);
}
/**
* @param url
* the {@link URL} used to locate the cached resource
*
- * @return the actual cache file
- *
* @throws IOException
* in case of I/O error
*/
- public File save(InputStream in, URL url) throws IOException {
+ public void save(InputStream in, URL url) throws IOException {
File cached = getCached(url);
- return save(in, cached);
+ save(in, cached);
}
/**
* @param cached
* the cached {@link File} to save to
*
- * @return the actual cache file
- *
* @throws IOException
* in case of I/O error
*/
- private File save(InputStream in, File cached) throws IOException {
+ private void save(InputStream in, File cached) throws IOException {
IOUtils.write(in, cached);
- return cached;
}
/**
--- /dev/null
+package be.nikiroo.utils;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * A memory only version of {@link Cache}.
+ *
+ * @author niki
+ */
+public class CacheMemory extends Cache {
+ private Map<String, byte[]> data = new HashMap<String, byte[]>();
+
+ /**
+ * Create a new {@link CacheMemory}.
+ */
+ public CacheMemory() {
+ }
+
+ @Override
+ public boolean check(String uniqueID, boolean allowTooOld, boolean stable) {
+ return data.containsKey(getKey(uniqueID));
+ }
+
+ @Override
+ public boolean check(URL url, boolean allowTooOld, boolean stable) {
+ return data.containsKey(getKey(url));
+ }
+
+ @Override
+ public int clean(boolean onlyOld) {
+ int cleaned = 0;
+ if (!onlyOld) {
+ cleaned = data.size();
+ data.clear();
+ }
+
+ return cleaned;
+ }
+
+ @Override
+ public InputStream load(String uniqueID, boolean allowTooOld, boolean stable) {
+ if (check(uniqueID, allowTooOld, stable)) {
+ return load(uniqueID, allowTooOld, stable);
+ }
+
+ return null;
+ }
+
+ @Override
+ public InputStream load(URL url, boolean allowTooOld, boolean stable) {
+ if (check(url, allowTooOld, stable)) {
+ return load(url, allowTooOld, stable);
+ }
+
+ return null;
+ }
+
+ @Override
+ public boolean remove(String uniqueID) {
+ return data.remove(getKey(uniqueID)) != null;
+ }
+
+ @Override
+ public boolean remove(URL url) {
+ return data.remove(getKey(url)) != null;
+ }
+
+ @Override
+ public void save(InputStream in, String uniqueID) throws IOException {
+ data.put(getKey(uniqueID), IOUtils.toByteArray(in));
+ }
+
+ @Override
+ public void save(InputStream in, URL url) throws IOException {
+ data.put(getKey(url), IOUtils.toByteArray(in));
+ }
+
+ /**
+ * Return a key mapping to the given unique ID.
+ *
+ * @param uniqueID
+ * the unique ID
+ *
+ * @return the key
+ */
+ private String getKey(String uniqueID) {
+ return "_/" + uniqueID;
+ }
+
+ /**
+ * Return a key mapping to the given urm.
+ *
+ * @param url
+ * thr url
+ *
+ * @return the key
+ */
+ private String getKey(URL url) {
+ return url.toString();
+ }
+}
* @return the {@link ImageUtils}
*/
private static ImageUtils newObject() {
- for (String clazz : new String[] { "be.nikiroo.utils.ui.ImageUtilsAwt" }) {
+ for (String clazz : new String[] { "be.nikiroo.utils.ui.ImageUtilsAwt",
+ "be.nikiroo.utils.android.ImageUtilsAndroid" }) {
try {
return (ImageUtils) SerialUtils.createObject(clazz);
} catch (Exception e) {
End
}
- static private Pattern marks = Pattern
- .compile("[\\p{InCombiningDiacriticalMarks}\\p{IsLm}\\p{IsSk}]+");
+ static private Pattern marks = getMarks();
/**
* Fix the size of the given {@link String} either with space-padding or by
if (removeAllAccents) {
input = Normalizer.normalize(input, Form.NFKD);
- input = marks.matcher(input).replaceAll("");
+ if (marks != null) {
+ input = marks.matcher(input).replaceAll("");
+ }
}
input = Normalizer.normalize(input, Form.NFKC);
* the time as a {@link String}
*
* @return the number of milliseconds since the standard base time known as
- * "the epoch", namely January 1, 1970, 00:00:00 GMT
+ * "the epoch", namely January 1, 1970, 00:00:00 GMT, or -1 in case
+ * of error
+ *
+ * @throws ParseException
+ * in case of parse error
*/
- static public long toTime(String displayTime) {
+ static public long toTime(String displayTime) throws ParseException {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
- try {
- return sdf.parse(displayTime).getTime();
- } catch (ParseException e) {
- return -1;
- }
+ return sdf.parse(displayTime).getTime();
}
/**
scan.close();
}
}
+
+ /**
+ * The "remove accents" pattern.
+ *
+ * @return the pattern, or NULL if a problem happens
+ */
+ private static Pattern getMarks() {
+ try {
+ return Pattern
+ .compile("[\\p{InCombiningDiacriticalMarks}\\p{IsLm}\\p{IsSk}]+");
+ } catch (Exception e) {
+ // Can fail on Android...
+ return null;
+ }
+ }
}
--- /dev/null
+package be.nikiroo.utils.android;
+
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import be.nikiroo.utils.Image;
+import be.nikiroo.utils.ImageUtils;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+/**
+ * This class offer some utilities based around images and uses the Android framework.
+ *
+ * @author niki
+ */
+public class ImageUtilsAndroid extends ImageUtils {
+ @Override
+ public void saveAsImage(Image img, File target, String format)
+ throws IOException {
+ FileOutputStream fos = new FileOutputStream(target);
+ try {
+ Bitmap image = fromImage(img);
+
+ boolean ok = false;
+ try {
+ ok = image.compress(
+ Bitmap.CompressFormat.valueOf(format.toUpperCase()),
+ 90, fos);
+ } catch (Exception e) {
+ ok = false;
+ }
+
+ // Some formats are not reliable
+ // Second change: PNG
+ if (!ok && !format.equals("png")) {
+ ok = image.compress(Bitmap.CompressFormat.PNG, 90, fos);
+ }
+
+ if (!ok) {
+ throw new IOException(
+ "Cannot find a writer for this image and format: "
+ + format);
+ }
+ } catch (IOException e) {
+ throw new IOException("Cannot write image to " + target, e);
+ } finally {
+ fos.close();
+ }
+ }
+
+ /**
+ * Convert the given {@link Image} into a {@link Bitmap} object.
+ *
+ * @param img
+ * the {@link Image}
+ * @return the {@link Image} object
+ * @throws IOException
+ * in case of IO error
+ */
+ static public Bitmap fromImage(Image img) throws IOException {
+ Bitmap image = BitmapFactory.decodeByteArray(img.getData(), 0,
+ img.getData().length);
+ if (image == null) {
+ throw new IOException("Failed to convert input to image");
+ }
+
+ return image;
+ }
+}
--- /dev/null
+package be.nikiroo.utils.android.test;
+
+import be.nikiroo.utils.android.ImageUtilsAndroid;
+
+public class TestAndroid {
+ ImageUtilsAndroid a = new ImageUtilsAndroid();
+}
* @return the associated value
*/
public char getCharacter(E id, char def) {
- String s = getString(id).trim();
- if (s.length() > 0) {
- return s.charAt(0);
+ String s = getString(id);
+ if (s != null && s.length() > 0) {
+ return s.trim().charAt(0);
}
return def;
writer.close();
}
+ /**
+ * Delete the .properties file.
+ * <p>
+ * Will use the most likely candidate as base if the file does not already
+ * exists and this resource is translatable (for instance, "en_US" will use
+ * "en" as a base if the resource is a translation file).
+ * <p>
+ * Will delete the files in {@link Bundles#getDirectory()}; it <b>MUST</b>
+ * be set.
+ *
+ * @return TRUE if the file was deleted
+ */
+ public boolean deleteFile() {
+ return deleteFile(Bundles.getDirectory());
+ }
+
+ /**
+ * Delete the .properties file.
+ * <p>
+ * Will use the most likely candidate as base if the file does not already
+ * exists and this resource is translatable (for instance, "en_US" will use
+ * "en" as a base if the resource is a translation file).
+ *
+ * @param path
+ * the path where the .properties files are, <b>MUST NOT</b> be
+ * NULL
+ *
+ * @return TRUE if the file was deleted
+ */
+ public boolean deleteFile(String path) {
+ File file = getUpdateFile(path);
+ return file.delete();
+ }
+
/**
* The description {@link TransBundle}, that is, a {@link TransBundle}
* dedicated to the description of the values of the given {@link Bundle}
Meta.Format format = meta.format();
String[] list = meta.list();
boolean nullable = meta.nullable();
+ String def = meta.def();
String info = meta.info();
boolean array = meta.array();
// Default, empty values -> NULL
- if (desc.length() + list.length + info.length() == 0 && !group
- && nullable && format == Meta.Format.STRING) {
+ if (desc.length() + list.length + info.length() + def.length() == 0
+ && !group && nullable && format == Meta.Format.STRING) {
return null;
}
protected void setBundle(Enum<?> name, Locale locale, boolean resetToDefault) {
changeMap.clear();
String dir = Bundles.getDirectory();
+ String bname = type.getPackage().getName() + "." + name.name();
boolean found = false;
if (!resetToDefault && dir != null) {
+ // Look into Bundles.getDirectory() for .properties files
try {
File file = getPropertyFile(dir, name.name(), locale);
if (file != null) {
}
if (!found) {
- String bname = type.getPackage().getName() + "." + name.name();
+ // Look into the package itself for resources
try {
resetMap(ResourceBundle
.getBundle(bname, locale, type.getClassLoader(),
new FixedResourceBundleControl()));
+ found = true;
+ } catch (MissingResourceException e) {
} catch (Exception e) {
- // We have no bundle for this Bundle
- System.err.println("No bundle found for: " + bname);
- resetMap(null);
+ e.printStackTrace();
}
}
+
+ if (!found) {
+ // We have no bundle for this Bundle
+ System.err.println("No bundle found for: " + bname);
+ resetMap(null);
+ }
}
/**
- * Reset the backing map to the content of the given bundle, or empty if
- * bundle is NULL.
+ * Reset the backing map to the content of the given bundle, or with default
+ * valiues if bundle is NULL.
*
* @param bundle
* the bundle to copy
*/
protected void resetMap(ResourceBundle bundle) {
this.map.clear();
-
- if (bundle != null) {
- for (E field : type.getEnumConstants()) {
- try {
- String value = bundle.getString(field.name());
- this.map.put(field.name(),
- value == null ? null : value.trim());
- } catch (MissingResourceException e) {
+ for (Field field : type.getDeclaredFields()) {
+ try {
+ Meta meta = field.getAnnotation(Meta.class);
+ if (meta != null) {
+ E id = Enum.valueOf(type, field.getName());
+
+ String value;
+ if (bundle != null) {
+ value = bundle.getString(id.name());
+ } else {
+ value = meta.def();
+ }
+
+ this.map.put(id.name(), value == null ? null : value.trim());
}
+ } catch (MissingResourceException e) {
}
}
}
* use the value in the program, and LANGUAGE_CODE_FR, LANGUAGE_CODE_EN
* inside for which the value must be set.
*
- * @return the group
+ * @return TRUE if it is a group
*/
boolean group() default false;
*/
boolean nullable() default true;
+ /**
+ * The default value of this item.
+ *
+ * @return the value
+ */
+ String def() default "";
+
/**
* This item is a comma-separated list of values instead of a single value.
*
import java.util.ArrayList;
import java.util.Collection;
import java.util.Enumeration;
+import java.util.List;
import java.util.regex.Pattern;
import java.util.zip.ZipEntry;
import java.util.zip.ZipException;
private static Collection<String> getResourcesFromDirectory(
final File directory, final Pattern pattern) {
- final ArrayList<String> retval = new ArrayList<String>();
+ List<String> acc = new ArrayList<String>();
+ List<File> dirs = new ArrayList<File>();
+ getResourcesFromDirectory(acc, dirs, directory, pattern);
+
+ List<String> rep = new ArrayList<String>();
+ for (String value : acc) {
+ if (pattern.matcher(value).matches()) {
+ rep.add(value);
+ }
+ }
+
+ return rep;
+ }
+
+ private static void getResourcesFromDirectory(List<String> acc,
+ List<File> dirs, final File directory, final Pattern pattern) {
final File[] fileList = directory.listFiles();
- for (final File file : fileList) {
- if (file.isDirectory()) {
- retval.addAll(getResourcesFromDirectory(file, pattern));
- } else {
- try {
- final String fileName = file.getCanonicalPath();
- final boolean accept = pattern.matcher(fileName).matches();
- if (accept) {
- retval.add(fileName);
+ if (fileList != null) {
+ for (final File file : fileList) {
+ if (!dirs.contains(file)) {
+ try {
+ String key = file.getCanonicalPath();
+ if (!acc.contains(key)) {
+ if (file.isDirectory()) {
+ dirs.add(file);
+ getResourcesFromDirectory(acc, dirs, file,
+ pattern);
+ } else {
+ acc.add(key);
+ }
+ }
+ } catch (IOException e) {
}
- } catch (final IOException e) {
- throw new Error(e);
}
}
}
-
- return retval;
}
}
public void saveAsImage(Image img, File target, String format)
throws IOException {
try {
- BufferedImage image = ImageUtilsAwt.fromImage(img);
+ BufferedImage image = fromImage(img);
boolean ok = false;
try {
}
// Some formats are not reliable
- // Second change: PNG
+ // Second chance: PNG
if (!ok && !format.equals("png")) {
ok = ImageIO.write(image, "png", target);
}