From e119a1c1a924998b9315e46c96b1c750aab1deb9 Mon Sep 17 00:00:00 2001 From: Niki Roo Date: Mon, 28 Mar 2016 15:31:32 +0200 Subject: [PATCH] Resources system rewrite + new "--save-config DIR" option --- src/be/nikiroo/jvcard/launcher/Main.java | 107 ++++-- src/be/nikiroo/jvcard/remote/Server.java | 8 +- src/be/nikiroo/jvcard/remote/Sync.java | 19 +- src/be/nikiroo/jvcard/resources/Bundles.java | 360 ++++++++++++++++-- src/be/nikiroo/jvcard/resources/Trans.java | 321 ---------------- .../jvcard/resources/bundles/ColorBundle.java | 43 +++ .../resources/bundles/DisplayBundle.java | 26 ++ .../resources/bundles/RemoteBundle.java | 26 ++ .../jvcard/resources/bundles/TransBundle.java | 183 +++++++++ .../jvcard/resources/colors.properties | 54 ++- .../jvcard/resources/display.properties | 35 +- .../jvcard/resources/enums/ColorOption.java | 86 +++++ .../jvcard/resources/enums/DisplayOption.java | 70 ++++ .../resources/enums/RemotingOption.java | 34 ++ .../jvcard/resources/enums/StringId.java | 87 +++++ .../jvcard/resources/remote.properties | 24 +- src/be/nikiroo/jvcard/tui/KeyAction.java | 2 +- src/be/nikiroo/jvcard/tui/MainWindow.java | 28 +- src/be/nikiroo/jvcard/tui/UiColors.java | 109 ++---- .../jvcard/tui/panes/ContactDetails.java | 87 ++--- .../jvcard/tui/panes/ContactDetailsRaw.java | 28 +- .../nikiroo/jvcard/tui/panes/ContactList.java | 44 ++- src/be/nikiroo/jvcard/tui/panes/FileList.java | 14 +- .../jvcard/tui/panes/MainContentList.java | 25 +- 24 files changed, 1155 insertions(+), 665 deletions(-) delete mode 100644 src/be/nikiroo/jvcard/resources/Trans.java create mode 100644 src/be/nikiroo/jvcard/resources/bundles/ColorBundle.java create mode 100644 src/be/nikiroo/jvcard/resources/bundles/DisplayBundle.java create mode 100644 src/be/nikiroo/jvcard/resources/bundles/RemoteBundle.java create mode 100644 src/be/nikiroo/jvcard/resources/bundles/TransBundle.java create mode 100644 src/be/nikiroo/jvcard/resources/enums/ColorOption.java create mode 100644 src/be/nikiroo/jvcard/resources/enums/DisplayOption.java create mode 100644 src/be/nikiroo/jvcard/resources/enums/RemotingOption.java create mode 100644 src/be/nikiroo/jvcard/resources/enums/StringId.java diff --git a/src/be/nikiroo/jvcard/launcher/Main.java b/src/be/nikiroo/jvcard/launcher/Main.java index 29cf8a6..7f59539 100644 --- a/src/be/nikiroo/jvcard/launcher/Main.java +++ b/src/be/nikiroo/jvcard/launcher/Main.java @@ -7,8 +7,6 @@ import java.net.Socket; import java.nio.charset.Charset; import java.util.LinkedList; import java.util.List; -import java.util.MissingResourceException; -import java.util.ResourceBundle; import javax.imageio.ImageIO; @@ -22,8 +20,12 @@ import be.nikiroo.jvcard.remote.Command; import be.nikiroo.jvcard.remote.SimpleSocket; import be.nikiroo.jvcard.resources.Bundles; import be.nikiroo.jvcard.resources.StringUtils; -import be.nikiroo.jvcard.resources.Trans; -import be.nikiroo.jvcard.resources.Trans.StringId; +import be.nikiroo.jvcard.resources.bundles.ColorBundle; +import be.nikiroo.jvcard.resources.bundles.DisplayBundle; +import be.nikiroo.jvcard.resources.bundles.RemoteBundle; +import be.nikiroo.jvcard.resources.bundles.TransBundle; +import be.nikiroo.jvcard.resources.enums.DisplayOption; +import be.nikiroo.jvcard.resources.enums.StringId; /** * This class contains the runnable Main method. It will parse the user supplied @@ -40,13 +42,13 @@ public class Main { static private final int ERR_NO_FILE = 1; static private final int ERR_SYNTAX = 2; static private final int ERR_INTERNAL = 3; - static private Trans transService; + static private TransBundle transService; static private String defaultFn; static private boolean forceComputedFn; enum Mode { - CONTACT_MANAGER, I18N, SERVER, LOAD_PHOTO, SAVE_PHOTO, ONLY_PHOTO, + CONTACT_MANAGER, I18N, SERVER, LOAD_PHOTO, SAVE_PHOTO, ONLY_PHOTO, SAVE_CONFIG } /** @@ -60,8 +62,8 @@ public class Main { * * @return the translated text with the given value where required */ - static public String trans(StringId id, String... values) { - return transService.trans(id, (String[]) values); + static public String trans(StringId id, Object... values) { + return transService.getString(id, (Object[]) values); } /** @@ -97,7 +99,7 @@ public class Main { // get the "system default" language to help translate the --help // message if needed String language = null; - transService = new Trans(language); + transService = new TransBundle(language); boolean unicode = transService.isUnicode(); String dir = null; @@ -119,7 +121,8 @@ public class Main { + "\t--tui: force pure text mode even if swing treminal is available\n" + "\t--gui: force swing terminal mode\n" + "\t--noutf: force non-utf8 mode if you need it\n" - + "\t--config DIRECTORY: force the given directory as a CONFIG_DIR\n" + + "\t--config DIRECTORY: use the given directory as a CONFIG_DIR\n" + + "\t--save-config DIRECTORY: save the current config to DIRECTORY (lang: only current)\n" + "\t--server PORT: start a remoting server instead of a client\n" + "\t--i18n DIR: generate the translation file for the given language (can be \"\") to/from the .properties given dir\n" + "\t--save-photo DIR FORMAT: save the contacts' photos to DIR, named after FORMAT\n" @@ -145,7 +148,7 @@ public class Main { } language = args[index]; - transService = new Trans(language); + transService = new TransBundle(language); transService.setUnicode(unicode); } else if (!noMoreParams && arg.equals("--config")) { index++; @@ -157,17 +160,39 @@ public class Main { } Bundles.setDirectory(args[index]); - transService = new Trans(language); + transService = new TransBundle(language); transService.setUnicode(unicode); + } else if (!noMoreParams && arg.equals("--save-config")) { + index++; + if (index >= args.length) { + System.err + .println("Syntax error: no config directory given"); + System.exit(ERR_SYNTAX); + return; + } + dir = args[index]; + + if (mode != Mode.CONTACT_MANAGER) { + System.err + .println("Syntax error: you can only use one of: \n" + + "--server\n" + + "--save-config\n" + + "--i18n\n" + + "--load-photo\n" + + "--save-photo\n" + "--only-photo\n"); + System.exit(ERR_SYNTAX); + return; + } + mode = Mode.SAVE_CONFIG; } else if (!noMoreParams && arg.equals("--server")) { if (mode != Mode.CONTACT_MANAGER) { System.err .println("Syntax error: you can only use one of: \n" + "--server\n" + + "--save-config\n" + "--i18n\n" + "--load-photo\n" - + "--save-photo\n" - + "--only-photo\n"); + + "--save-photo\n" + "--only-photo\n"); System.exit(ERR_SYNTAX); return; } @@ -192,10 +217,10 @@ public class Main { System.err .println("Syntax error: you can only use one of: \n" + "--server\n" + + "--save-config\n" + "--i18n\n" + "--load-photo\n" - + "--save-photo\n" - + "--only-photo\n"); + + "--save-photo\n" + "--only-photo\n"); System.exit(ERR_SYNTAX); return; } @@ -218,10 +243,10 @@ public class Main { System.err .println("Syntax error: you can only use one of: \n" + "--server\n" + + "--save-config\n" + "--i18n\n" + "--load-photo\n" - + "--save-photo\n" - + "--only-photo\n"); + + "--save-photo\n" + "--only-photo\n"); System.exit(ERR_SYNTAX); return; } @@ -298,6 +323,27 @@ public class Main { // switch (mode) { + case SAVE_CONFIG: { + try { + if (!new File(dir).isDirectory()) { + if (!new File(dir).mkdir()) { + System.err + .println("Cannot create configuration directory: " + + dir); + } + } + + transService.updateFile(dir); // current lang TransBundle + new TransBundle().updateFile(dir); + new ColorBundle().updateFile(dir); + new DisplayBundle().updateFile(dir); + new RemoteBundle().updateFile(dir); + } catch (IOException e) { + e.printStackTrace(); + System.exit(ERR_INTERNAL); + } + break; + } case SERVER: { try { Optional.runServer(port); @@ -314,11 +360,12 @@ public class Main { } case I18N: { try { - Trans.generateTranslationFile(dir, language); + transService.updateFile(dir); } catch (IOException e) { System.err .println("I/O Exception: Cannot create/update a language in directory: " + dir); + e.printStackTrace(); } break; } @@ -570,23 +617,11 @@ public class Main { * or always, or never. */ static private void readNFN() { - ResourceBundle map = Bundles.getBundle("display"); - try { - defaultFn = map.getString("CONTACT_DETAILS_DEFAULT_FN"); - if (defaultFn.trim().length() == 0) - defaultFn = null; - } catch (MissingResourceException e) { - e.printStackTrace(); - } + DisplayBundle map = new DisplayBundle(); - try { - String forceComputedFnStr = map - .getString("CONTACT_DETAILS_SHOW_COMPUTED_FN"); - if (forceComputedFnStr.length() > 0 - && forceComputedFnStr.equalsIgnoreCase("true")) - forceComputedFn = true; - } catch (MissingResourceException e) { - e.printStackTrace(); - } + defaultFn = map.getString(DisplayOption.CONTACT_DETAILS_DEFAULT_FN); + + forceComputedFn = map.getBoolean( + DisplayOption.CONTACT_DETAILS_SHOW_COMPUTED_FN, false); } } diff --git a/src/be/nikiroo/jvcard/remote/Server.java b/src/be/nikiroo/jvcard/remote/Server.java index 60f323a..962f2d0 100644 --- a/src/be/nikiroo/jvcard/remote/Server.java +++ b/src/be/nikiroo/jvcard/remote/Server.java @@ -11,15 +11,15 @@ import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; -import java.util.ResourceBundle; import be.nikiroo.jvcard.Card; import be.nikiroo.jvcard.Contact; import be.nikiroo.jvcard.Data; import be.nikiroo.jvcard.parsers.Format; import be.nikiroo.jvcard.parsers.Vcard21Parser; -import be.nikiroo.jvcard.resources.Bundles; import be.nikiroo.jvcard.resources.StringUtils; +import be.nikiroo.jvcard.resources.bundles.RemoteBundle; +import be.nikiroo.jvcard.resources.enums.RemotingOption; /** * This class implements a small server that can listen for requests to @@ -58,9 +58,9 @@ public class Server implements Runnable { */ public Server(int port) throws IOException { this.port = port; - ResourceBundle bundle = Bundles.getBundle("remote"); + RemoteBundle bundle = new RemoteBundle(); try { - String dir = bundle.getString("SERVER_DATA_PATH"); + String dir = bundle.getString(RemotingOption.SERVER_DATA_PATH); dataDir = new File(dir); dataDir.mkdir(); diff --git a/src/be/nikiroo/jvcard/remote/Sync.java b/src/be/nikiroo/jvcard/remote/Sync.java index 9963665..609041e 100644 --- a/src/be/nikiroo/jvcard/remote/Sync.java +++ b/src/be/nikiroo/jvcard/remote/Sync.java @@ -16,8 +16,6 @@ import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; -import java.util.MissingResourceException; -import java.util.ResourceBundle; import be.nikiroo.jvcard.Card; import be.nikiroo.jvcard.Contact; @@ -26,8 +24,9 @@ import be.nikiroo.jvcard.launcher.CardResult; import be.nikiroo.jvcard.launcher.CardResult.MergeCallback; import be.nikiroo.jvcard.parsers.Format; import be.nikiroo.jvcard.parsers.Vcard21Parser; -import be.nikiroo.jvcard.resources.Bundles; import be.nikiroo.jvcard.resources.StringUtils; +import be.nikiroo.jvcard.resources.bundles.RemoteBundle; +import be.nikiroo.jvcard.resources.enums.RemotingOption; /** * This class will synchronise {@link Card}s between a local instance an a @@ -588,10 +587,10 @@ public class Sync { */ static private void config() { String dir = null; - ResourceBundle bundle = Bundles.getBundle("remote"); + RemoteBundle bundle = new RemoteBundle(); try { - dir = bundle.getString("CLIENT_CACHE_DIR").trim(); + dir = bundle.getString(RemotingOption.CLIENT_CACHE_DIR); cacheDir = new File(dir + File.separator + "current"); cacheDir.mkdir(); @@ -605,14 +604,8 @@ public class Sync { + dir); } - String autoStr = bundle.getString("CLIENT_AUTO_SYNC"); - if (autoStr != null && autoStr.trim().equalsIgnoreCase("true")) { - autoSync = true; - } - - } catch (MissingResourceException e) { - throw new InvalidParameterException( - "Cannot access remote.properties configuration file"); + autoSync = bundle + .getBoolean(RemotingOption.CLIENT_AUTO_SYNC, false); } catch (Exception e) { throw new InvalidParameterException( "Cannot open or create cache store at: " + dir); diff --git a/src/be/nikiroo/jvcard/resources/Bundles.java b/src/be/nikiroo/jvcard/resources/Bundles.java index 3b18084..00cd58a 100644 --- a/src/be/nikiroo/jvcard/resources/Bundles.java +++ b/src/be/nikiroo/jvcard/resources/Bundles.java @@ -1,5 +1,12 @@ package be.nikiroo.jvcard.resources; +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStreamWriter; +import java.io.Writer; +import java.lang.reflect.Field; import java.util.Locale; import java.util.ResourceBundle; @@ -12,37 +19,40 @@ import java.util.ResourceBundle; public class Bundles { static private String confDir = getConfDir(); - // TODO: create "Trans" like classes for all .properties file, always get it - // them from here, including Trans (create a new one each time like - // currently) + update Main to call trans again when chaning dir - private int TODO; - /** - * Return the non-localised bundle of the given name. - * - * @param name - * the name of the bundle to load + * The type of configuration information the associated {@link Bundle} will + * convey. * - * @return the bundle + * @author niki + * */ - static public ResourceBundle getBundle(String name) { - return ResourceBundle.getBundle(Bundles.class.getPackage().getName() - + "." + name, new FixedResourceBundleControl(confDir)); + public enum Target { + colors, display, jvcard, remote, resources } /** - * Return the localised bundle of the given name and {@link Locale}. - * - * @param name - * the name of the bundle to load - * @param locale - * the {@link Locale} to use + * Return the configuration directory where to try to find the + * .properties files in priority. * - * @return the localised bundle + * @return the configuration directory */ - static public ResourceBundle getBundle(String name, Locale locale) { - return ResourceBundle.getBundle(Bundles.class.getPackage().getName() - + "." + name, locale, new FixedResourceBundleControl(confDir)); + static private String getConfDir() { + // Do not override user-supplied config directory (see --help) + if (Bundles.confDir != null) + return Bundles.confDir; + + try { + ResourceBundle bundle = ResourceBundle.getBundle(Bundles.class + .getPackage().getName() + "." + "jvcard", + Locale.getDefault(), new FixedResourceBundleControl(null)); + + String configDir = bundle.getString("CONFIG_DIR"); + if (configDir != null && configDir.trim().length() > 0) + return configDir; + } catch (Exception e) { + } + + return null; } /** @@ -60,28 +70,298 @@ public class Bundles { } /** - * Return the configuration directory where to try to find the - * .properties files in priority. + * This class encapsulate a {@link ResourceBundle} in UTF-8. It only allows + * to retrieve values associated to an enumeration, and allows some + * additional methods. * - * @return the configuration directory + * @author niki + * + * @param + * the enum to use to get values out of this class */ - static private String getConfDir() { - // Do not override user-supplied config directory (see --help) - if (Bundles.confDir != null) - return Bundles.confDir; + public class Bundle> { + private Class type; + protected Target name; + protected ResourceBundle map; - try { - ResourceBundle bundle = ResourceBundle.getBundle(Bundles.class - .getPackage().getName() + "." + "jvcard", - Locale.getDefault(), new FixedResourceBundleControl(null)); + /** + * Create a new {@link Bundles} of the given name. + * + * @param type + * a runtime instance of the class of E + * + * @param name + * the name of the {@link Bundles} + */ + protected Bundle(Class type, Target name) { + this.type = type; + this.name = name; + this.map = getBundle(name); + } - String configDir = bundle.getString("CONFIG_DIR"); - if (configDir != null && configDir.trim().length() > 0) - return configDir; - } catch (Exception e) { + /** + * Return the value associated to the given id as a {@link String}. + * + * @param mame + * the id of the value to get + * + * @return the associated value + */ + public String getString(E id) { + if (map.containsKey(id.name())) { + return map.getString(id.name()).trim(); + } + + return ""; } - return null; - } + /** + * Return the value associated to the given id as a {@link Boolean}. + * + * @param mame + * the id of the value to get + * + * @return the associated value + */ + public Boolean getBoolean(E id) { + String str = getString(id); + if (str != null && str.length() > 0) { + if (str.equalsIgnoreCase("true") || str.equalsIgnoreCase("on") + || str.equalsIgnoreCase("yes")) + return true; + if (str.equalsIgnoreCase("false") + || str.equalsIgnoreCase("off") + || str.equalsIgnoreCase("no")) + return false; + + } + + return null; + } + + /** + * Return the value associated to the given id as a {@link boolean}. + * + * @param mame + * the id of the value to get + * @param def + * the default value when it is not present in the config + * file or if it is not a boolean value + * + * @return the associated value + */ + public boolean getBoolean(E id, boolean def) { + Boolean b = getBoolean(id); + if (b != null) + return b; + + return def; + } + + /** + * Return the value associated to the given id as an {@link Integer}. + * + * @param mame + * the id of the value to get + * + * @return the associated value + */ + public Integer getInteger(E id) { + try { + return Integer.parseInt(getString(id)); + } catch (Exception e) { + } + + return null; + } + + /** + * Return the value associated to the given id as a {@link int}. + * + * @param mame + * the id of the value to get + * @param def + * the default value when it is not present in the config + * file or if it is not a int value + * + * @return the associated value + */ + public int getInteger(E id, int def) { + Integer i = getInteger(id); + if (i != null) + return i; + + return def; + } + + /** + * Create/update the .properties file. 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 + * + * @throws IOException + * in case of IO errors + */ + public void updateFile(String path) throws IOException { + File file = getUpdateFile(path); + + BufferedWriter writer = new BufferedWriter(new OutputStreamWriter( + new FileOutputStream(file), "UTF-8")); + + writeHeader(writer); + writer.write("\n"); + writer.write("\n"); + + for (Field field : type.getDeclaredFields()) { + Meta meta = field.getAnnotation(Meta.class); + if (meta != null) { + E id = E.valueOf(type, field.getName()); + String info = getMetaInfo(meta); + + if (info != null) { + writer.write(info); + writer.write("\n"); + } + + writeValue(writer, id); + } + } + + writer.close(); + } + /** + * Return formated, display-able information from the {@link Meta} field + * given. Each line will always starts with a "#" character. + * + * @param meta + * the {@link Meta} field + * + * @return the information to display or NULL if none + */ + protected String getMetaInfo(Meta meta) { + String what = meta.what(); + String where = meta.where(); + String format = meta.format(); + String info = meta.info(); + + int opt = what.length() + where.length() + format.length(); + if (opt + info.length() == 0) + return null; + + StringBuilder builder = new StringBuilder(); + builder.append("# "); + + if (opt > 0) { + builder.append("("); + if (what.length() > 0) { + builder.append("WHAT: " + what); + if (where.length() + format.length() > 0) + builder.append(", "); + } + + if (where.length() > 0) { + builder.append("WHERE: " + where); + if (format.length() > 0) + builder.append(", "); + } + + if (format.length() > 0) { + builder.append("FORMAT: " + format); + } + + builder.append(")"); + if (info.length() > 0) { + builder.append("\n# "); + } + } + + builder.append(info); + + return builder.toString(); + } + + /** + * Write the header found in the configuration .properties file + * of this {@link Bundles}. + * + * @param writer + * the {@link Writer} to write the header in + * + * @throws IOException + * in case of IO error + */ + protected void writeHeader(Writer writer) throws IOException { + writer.write("# " + name + "\n"); + writer.write("#\n"); + } + + /** + * Write the given id to the config file, i.e., + * "MY_ID = my_curent_value" followed by a new line + * + * @param writer + * the {@link Writer} to write into + * @param id + * the id to write + * + * @throws IOException + * in case of IO error + */ + protected void writeValue(Writer writer, E id) throws IOException { + writer.write(id.name()); + writer.write(" = "); + writer.write(getString(id)); + writer.write("\n"); + } + + /** + * Return the non-localised bundle of the given name. + * + * @param name + * the name of the bundle to load + * + * @return the bundle + */ + protected ResourceBundle getBundle(Target name) { + return ResourceBundle.getBundle(Bundles.class.getPackage() + .getName() + "." + name.name(), + new FixedResourceBundleControl(confDir)); + } + + /** + * Return the localised bundle of the given name and {@link Locale}. + * + * @param name + * the name of the bundle to load + * @param locale + * the {@link Locale} to use + * + * @return the localised bundle + */ + protected ResourceBundle getBundle(Target name, Locale locale) { + return ResourceBundle.getBundle(Bundles.class.getPackage() + .getName() + "." + name.name(), locale, + new FixedResourceBundleControl(confDir)); + } + + /** + * Return the source file for this {@link Bundles} from the given path. + * + * @param path + * the path where the .properties files are + * + * @return the source {@link File} + * + * @throws IOException + * in case of IO errors + */ + protected File getUpdateFile(String path) { + return new File(path, name.name() + ".properties"); + } + } } diff --git a/src/be/nikiroo/jvcard/resources/Trans.java b/src/be/nikiroo/jvcard/resources/Trans.java deleted file mode 100644 index 1fa0f11..0000000 --- a/src/be/nikiroo/jvcard/resources/Trans.java +++ /dev/null @@ -1,321 +0,0 @@ -package be.nikiroo.jvcard.resources; - -import java.io.BufferedWriter; -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.OutputStreamWriter; -import java.lang.reflect.Field; -import java.util.Locale; -import java.util.ResourceBundle; - -/** - * This class manages the translation of {@link Trans.StringId}s into - * user-understandable text. - * - * @author niki - * - */ -public class Trans { - private ResourceBundle map; - private boolean utf = true; - private Locale locale; - - /** - * Create a translation service with the default language. - */ - public Trans() { - setLanguage(null); - } - - /** - * Create a translation service for the given language. (Will fall back to - * the default one i not found.) - * - * @param language - * the language to use - */ - public Trans(String language) { - setLanguage(language); - } - - /** - * Translate the given {@link StringId} into user text. - * - * @param stringId - * the ID to translate - * @param values - * the values to insert instead of the place holders in the - * translation - * - * @return the translated text with the given value where required - */ - public String trans(StringId stringId, String... values) { - StringId id = stringId; - String result = null; - - if (!isUnicode()) { - try { - id = StringId.valueOf(stringId.name() + "_NOUTF"); - } catch (IllegalArgumentException iae) { - // no special _NOUTF version found - } - } - - if (id == StringId.NULL) { - result = ""; - } else if (id == StringId.DUMMY) { - result = "[dummy]"; - } else if (map.containsKey(id.name())) { - result = map.getString(id.name()); - } else { - result = id.toString(); - } - - if (values != null && values.length > 0) - return String.format(locale, result, (Object[]) values); - else - return result; - } - - /** - * Check if unicode characters should be used. - * - * @return TRUE to allow unicode - */ - public boolean isUnicode() { - return utf; - } - - /** - * Allow or disallow unicode characters in the program. - * - * @param utf - * TRUE to allow unuciode, FALSE to only allow ASCII characters - */ - public void setUnicode(boolean utf) { - this.utf = utf; - } - - /** - * Initialise the translation mappings for the given language. - * - * @param language - * the language to initialise, in the form "en-GB" or "fr" for - * instance - */ - private void setLanguage(String language) { - locale = getLocaleFor(language); - map = Bundles.getBundle("resources", locale); - } - - /** - * Create/update the translation .properties files. Will use the most likely - * candidate as base if the file does not already exists (for instance, - * "en_US" will use "en" as a base). - * - * @param path - * the path where the .properties files are - * - * @param language - * the language code to create/update (e.g.: fr-BE) - * - * @throws IOException - * in case of IO errors - */ - static public void generateTranslationFile(String path, String language) - throws IOException { - - Locale locale = getLocaleFor(language); - String code = locale.toString(); - Trans trans = new Trans(code); - - File file = null; - if (code.length() > 0) { - file = new File(path + "resources_" + code + ".properties"); - } else { - // Default properties file: - file = new File(path + "resources.properties"); - } - - BufferedWriter writer = new BufferedWriter(new OutputStreamWriter( - new FileOutputStream(file), "UTF-8")); - - String name = locale.getDisplayCountry(locale); - if (name.length() == 0) - name = locale.getDisplayLanguage(locale); - if (name.length() == 0) - name = "default"; - - if (code.length() > 0) { - name = name + " (" + code + ")"; - } - - writer.append("# " + name + " translation file (UTF-8)\n"); - writer.append("# \n"); - writer.append("# Note that any key can be doubled with a _NOUTF suffix\n"); - writer.append("# to use when the flag --noutf is passed\n"); - writer.append("# \n"); - writer.append("# Also, the comments always refer to the key below them.\n"); - writer.append("# \n"); - writer.append("\n"); - - for (Field field : StringId.class.getDeclaredFields()) { - Meta meta = field.getAnnotation(Meta.class); - if (meta != null) { - StringId id = StringId.valueOf(field.getName()); - String info = getMetaInfo(meta); - if (info != null) { - writer.append(info); - writer.append("\n"); - } - - writer.append(id.name()); - writer.append(" = "); - if (!trans.trans(id).equals(id.name())) - writer.append(trans.trans(id)); - writer.append("\n"); - } - } - - writer.close(); - } - - /** - * Return the {@link Locale} representing the given language. - * - * @param language - * the language to initialise, in the form "en-GB" or "fr" for - * instance - * - * @return the corresponding {@link Locale} or the default {@link Locale} if - * it is not known - */ - static private Locale getLocaleFor(String language) { - Locale locale; - - if (language == null) { - locale = Locale.getDefault(); - } else { - language = language.replaceAll("_", "-"); - String lang = language; - String country = null; - if (language.contains("-")) { - lang = language.split("-")[0]; - country = language.split("-")[1]; - } - - if (country != null) - locale = new Locale(lang, country); - else - locale = new Locale(lang); - } - - return locale; - } - - /** - * Return formated, display-able information from the {@link Meta} field - * given. Each line will always starts with a "#" character. - * - * @param meta - * the {@link Meta} field - * - * @return the information to display or NULL if none - */ - static private String getMetaInfo(Meta meta) { - String what = meta.what(); - String where = meta.where(); - String format = meta.format(); - String info = meta.info(); - - int opt = what.length() + where.length() + format.length(); - if (opt + info.length() == 0) - return null; - - StringBuilder builder = new StringBuilder(); - builder.append("# "); - - if (opt > 0) { - builder.append("("); - if (what.length() > 0) { - builder.append("WHAT: " + what); - if (where.length() + format.length() > 0) - builder.append(", "); - } - - if (where.length() > 0) { - builder.append("WHERE: " + where); - if (format.length() > 0) - builder.append(", "); - } - - if (format.length() > 0) { - builder.append("FORMAT: " + format); - } - - builder.append(")"); - if (info.length() > 0) { - builder.append("\n# "); - } - } - - builder.append(info); - - return builder.toString(); - } - - /** - * The enum representing textual information to be translated to the user as - * a key. - * - * Note that each key that should be translated MUST be annotated with a - * {@link Meta} annotation. - * - * @author niki - * - */ - public enum StringId { - DUMMY, // <-- TODO : remove - NULL, // Special usage, no annotations so it is not visible in - // .properties files - @Meta(what = "a key to press", where = "action keys", format = "MUST BE 3 chars long", info = "Tab key") - KEY_TAB, // keys - @Meta(what = "a key to press", where = "action keys", format = "MUST BE 3 chars long", info = "Enter key") - KEY_ENTER, // - @Meta(what = "Action key", where = "All screens except the first (KEY_ACTION_QUIT)", format = "", info = "Go back to previous screen") - KEY_ACTION_BACK, // - @Meta(what = "Action key", where = "MainWindow", format = "", info = "Get help text") - KEY_ACTION_HELP, // - @Meta(what = "Action key", where = "FileList", format = "", info = "View the selected card") - KEY_ACTION_VIEW_CARD, // - @Meta(what = "Action key", where = "ContactList", format = "", info = "View the selected contact") - KEY_ACTION_VIEW_CONTACT, // - @Meta(what = "Action key", where = "ContactDetails", format = "", info = "Edit the contact") - KEY_ACTION_EDIT_CONTACT, // - @Meta(what = "Action key", where = "ContactDetails", format = "", info = "Edit the contact in RAW mode") - KEY_ACTION_EDIT_CONTACT_RAW, // - @Meta(what = "Action key", where = "ContactList", format = "", info = "Save the whole card") - KEY_ACTION_SAVE_CARD, // - @Meta(what = "", where = "ContactList", format = "", info = "Delete the selected contact") - KEY_ACTION_DELETE_CONTACT, // - @Meta(what = "Action key", where = "ContactList", format = "", info = "Filter the displayed contacts") - KEY_ACTION_SEARCH, // - @Meta(what = "", where = "", format = "we could use: ' ', ┃, │...", info = "Field separator") - DEAULT_FIELD_SEPARATOR, // MainContentList - @Meta(what = "Action key", where = "ContactDetails", format = "", info = "Invert the photo's colours") - KEY_ACTION_INVERT, // - @Meta(what = "Action key", where = "ContactDetails", format = "", info = "Show the photo in 'fullscreen'") - KEY_ACTION_FULLSCREEN, // - @Meta(what = "Action key", where = "ContactList, ContactDetails, ContactDetailsRaw", format = "", info = "Switch between the available display formats") - KEY_ACTION_SWITCH_FORMAT, // multi-usage - @Meta(what = "Action key", where = "Contact list, Edit Contact", format = "", info = "Add a new contact/field") - KEY_ACTION_ADD, // - @Meta(what = "User question: TEXT", where = "Contact list", format = "", info = "New contact") - ASK_USER_CONTACT_NAME, // - @Meta(what = "User question: [Y|N]", where = "Contact list", format = "%s = contact name", info = "Delete contact") - CONFIRM_USER_DELETE_CONTACT, // - @Meta(what = "Error", where = "Contact list", format = "%s = contact name", info = "cannot delete a contact") - ERR_CANNOT_DELETE_CONTACT, // - }; -} diff --git a/src/be/nikiroo/jvcard/resources/bundles/ColorBundle.java b/src/be/nikiroo/jvcard/resources/bundles/ColorBundle.java new file mode 100644 index 0000000..899ca75 --- /dev/null +++ b/src/be/nikiroo/jvcard/resources/bundles/ColorBundle.java @@ -0,0 +1,43 @@ +package be.nikiroo.jvcard.resources.bundles; + +import java.io.IOException; +import java.io.Writer; + +import be.nikiroo.jvcard.resources.Bundles; +import be.nikiroo.jvcard.resources.Bundles.Bundle; +import be.nikiroo.jvcard.resources.Bundles.Target; +import be.nikiroo.jvcard.resources.enums.ColorOption; + +/** + * All colour information must come from here. + * + * @author niki + * + */ +public class ColorBundle extends Bundle { + public ColorBundle() { + new Bundles().super(ColorOption.class, Target.colors); + } + + @Override + protected void writeHeader(Writer writer) throws IOException { + ColorOption.writeHeader(writer); + } + + @Override + protected void writeValue(Writer writer, ColorOption id) throws IOException { + writer.write(id.name() + "_FG"); + writer.write(" = "); + if (map.containsKey(id.name() + "_FG")) + writer.write(map.getString(id.name() + "_FG").trim()); + + writer.write("\n"); + + writer.write(id.name() + "_BG"); + writer.write(" = "); + if (map.containsKey(id.name() + "_BG")) + writer.write(map.getString(id.name() + "_BG").trim()); + + writer.write("\n"); + } +} diff --git a/src/be/nikiroo/jvcard/resources/bundles/DisplayBundle.java b/src/be/nikiroo/jvcard/resources/bundles/DisplayBundle.java new file mode 100644 index 0000000..df34639 --- /dev/null +++ b/src/be/nikiroo/jvcard/resources/bundles/DisplayBundle.java @@ -0,0 +1,26 @@ +package be.nikiroo.jvcard.resources.bundles; + +import java.io.IOException; +import java.io.Writer; + +import be.nikiroo.jvcard.resources.Bundles; +import be.nikiroo.jvcard.resources.Bundles.Bundle; +import be.nikiroo.jvcard.resources.Bundles.Target; +import be.nikiroo.jvcard.resources.enums.DisplayOption; + +/** + * This class manages the display configuration of the application. + * + * @author niki + * + */ +public class DisplayBundle extends Bundle { + public DisplayBundle() { + new Bundles().super(DisplayOption.class, Target.display); + } + + @Override + protected void writeHeader(Writer writer) throws IOException { + DisplayOption.writeHeader(writer); + } +} diff --git a/src/be/nikiroo/jvcard/resources/bundles/RemoteBundle.java b/src/be/nikiroo/jvcard/resources/bundles/RemoteBundle.java new file mode 100644 index 0000000..0d27bf3 --- /dev/null +++ b/src/be/nikiroo/jvcard/resources/bundles/RemoteBundle.java @@ -0,0 +1,26 @@ +package be.nikiroo.jvcard.resources.bundles; + +import java.io.IOException; +import java.io.Writer; + +import be.nikiroo.jvcard.resources.Bundles; +import be.nikiroo.jvcard.resources.Bundles.Bundle; +import be.nikiroo.jvcard.resources.Bundles.Target; +import be.nikiroo.jvcard.resources.enums.RemotingOption; + +/** + * This class manages the display configuration of the application. + * + * @author niki + * + */ +public class RemoteBundle extends Bundle { + public RemoteBundle() { + new Bundles().super(RemotingOption.class, Target.remote); + } + + @Override + protected void writeHeader(Writer writer) throws IOException { + RemotingOption.writeHeader(writer); + } +} diff --git a/src/be/nikiroo/jvcard/resources/bundles/TransBundle.java b/src/be/nikiroo/jvcard/resources/bundles/TransBundle.java new file mode 100644 index 0000000..4fe7c4b --- /dev/null +++ b/src/be/nikiroo/jvcard/resources/bundles/TransBundle.java @@ -0,0 +1,183 @@ +package be.nikiroo.jvcard.resources.bundles; + +import java.io.File; +import java.io.IOException; +import java.io.Writer; +import java.util.Locale; + +import be.nikiroo.jvcard.resources.Bundles; +import be.nikiroo.jvcard.resources.Bundles.Bundle; +import be.nikiroo.jvcard.resources.Bundles.Target; +import be.nikiroo.jvcard.resources.enums.StringId; + +/** + * This class manages the translation of {@link TransBundle.StringId}s into + * user-understandable text. + * + * @author niki + * + */ +public class TransBundle extends Bundle { + private boolean utf = true; + private Locale locale; + + /** + * Create a translation service with the default language. + */ + public TransBundle() { + new Bundles().super(StringId.class, Target.resources); + setLanguage(null); + } + + /** + * Create a translation service for the given language. (Will fall back to + * the default one i not found.) + * + * @param language + * the language to use + */ + public TransBundle(String language) { + new Bundles().super(StringId.class, Target.resources); + + setLanguage(language); + } + + @Override + public String getString(StringId id) { + return getString(id, (Object[]) null); + } + + /** + * Translate the given {@link StringId} into user text. + * + * @param stringId + * the ID to translate + * @param values + * the values to insert instead of the place holders in the + * translation + * + * @return the translated text with the given value where required + */ + public String getString(StringId stringId, Object... values) { + StringId id = stringId; + String result = ""; + + if (!isUnicode()) { + try { + id = StringId.valueOf(stringId.name() + "_NOUTF"); + } catch (IllegalArgumentException iae) { + // no special _NOUTF version found + } + } + + if (id == StringId.NULL) { + result = ""; + } else if (id == StringId.DUMMY) { + result = "[dummy]"; + } else if (map.containsKey(id.name())) { + result = map.getString(id.name()); + } else { + result = id.toString(); + } + + if (values != null && values.length > 0) + return String.format(locale, result, (Object[]) values); + else + return result; + } + + /** + * Check if unicode characters should be used. + * + * @return TRUE to allow unicode + */ + public boolean isUnicode() { + return utf; + } + + /** + * Allow or disallow unicode characters in the program. + * + * @param utf + * TRUE to allow unuciode, FALSE to only allow ASCII characters + */ + public void setUnicode(boolean utf) { + this.utf = utf; + } + + @Override + protected File getUpdateFile(String path) { + String code = locale.toString(); + File file = null; + if (code.length() > 0) { + file = new File(path, name.name() + "_" + code + ".properties"); + } else { + // Default properties file: + file = new File(path, name.name() + ".properties"); + } + + return file; + } + + @Override + protected void writeHeader(Writer writer) throws IOException { + String code = locale.toString(); + String name = locale.getDisplayCountry(locale); + + if (name.length() == 0) + name = locale.getDisplayLanguage(locale); + if (name.length() == 0) + name = "default"; + + if (code.length() > 0) { + name = name + " (" + code + ")"; + } + + StringId.writeHeader(writer, name); + } + + /** + * Initialise the translation mappings for the given language. + * + * @param language + * the language to initialise, in the form "en-GB" or "fr" for + * instance + */ + private void setLanguage(String language) { + locale = getLocaleFor(language); + map = getBundle(Target.resources, locale); + } + + /** + * Return the {@link Locale} representing the given language. + * + * @param language + * the language to initialise, in the form "en-GB" or "fr" for + * instance + * + * @return the corresponding {@link Locale} or the default {@link Locale} if + * it is not known + */ + static private Locale getLocaleFor(String language) { + Locale locale; + + if (language == null) { + locale = Locale.getDefault(); + } else { + language = language.replaceAll("_", "-"); + String lang = language; + String country = null; + if (language.contains("-")) { + lang = language.split("-")[0]; + country = language.split("-")[1]; + } + + if (country != null) + locale = new Locale(lang, country); + else + locale = new Locale(lang); + } + + return locale; + } +} diff --git a/src/be/nikiroo/jvcard/resources/colors.properties b/src/be/nikiroo/jvcard/resources/colors.properties index e1b7500..7d0bd2c 100644 --- a/src/be/nikiroo/jvcard/resources/colors.properties +++ b/src/be/nikiroo/jvcard/resources/colors.properties @@ -1,4 +1,4 @@ -# application colours +# Application colours # # Note that you can define a colour in one of those 3 ways: # - WHITE: one of the ANSI colour names, in upper case @@ -7,48 +7,66 @@ # - 255: one of the 256 indexed colours of the terminal (the 16 first colours are theme-based) # # ...and thus either for xxx_FG (foreground colour) or xxx_BG (background colour) +# +# (FORMAT: colour) +DEFAULT_FG = BLACK +DEFAULT_BG = WHITE +# (FORMAT: colour) TITLE_MAIN_FG = WHITE TITLE_MAIN_BG = BLUE +# (FORMAT: colour) TITLE_VARIABLE_FG = GREEN TITLE_VARIABLE_BG = BLUE +# (FORMAT: colour) TITLE_COUNT_FG = RED TITLE_COUNT_BG = BLUE - -DEFAULT_FG = BLACK -DEFAULT_BG = WHITE - +# (FORMAT: colour) ACTION_KEY_FG = WHITE ACTION_KEY_BG = RED +# (FORMAT: colour) ACTION_DESC_FG = WHITE ACTION_DESC_BG = BLUE -CONTACT_LINE_FG = WHITE -CONTACT_LINE_BG = BLACK -CONTACT_LINE_SELECTED_FG = WHITE -CONTACT_LINE_SELECTED_BG = BLUE -CONTACT_LINE_SEPARATOR_FG = RED -CONTACT_LINE_SEPARATOR_BG = BLACK -CONTACT_LINE_SEPARATOR_SELECTED_FG = RED -CONTACT_LINE_SEPARATOR_SELECTED_BG = BLUE +# (FORMAT: colour) LINE_MESSAGE_FG = BLUE LINE_MESSAGE_BG = WHITE +# (FORMAT: colour) LINE_MESSAGE_ERR_FG = RED LINE_MESSAGE_ERR_BG = WHITE +# (FORMAT: colour) LINE_MESSAGE_QUESTION_FG = BLUE LINE_MESSAGE_QUESTION_BG = WHITE +# (FORMAT: colour) LINE_MESSAGE_ANS_FG = BLUE LINE_MESSAGE_ANS_BG = BLACK +# (FORMAT: colour) +CONTACT_LINE_FG = WHITE +CONTACT_LINE_BG = BLACK +# (FORMAT: colour) +CONTACT_LINE_SEPARATOR_FG = RED +CONTACT_LINE_SEPARATOR_BG = BLACK +# (FORMAT: colour) +CONTACT_LINE_SELECTED_FG = WHITE +CONTACT_LINE_SELECTED_BG = BLUE +# (FORMAT: colour) +CONTACT_LINE_SEPARATOR_SELECTED_FG = RED +CONTACT_LINE_SEPARATOR_SELECTED_BG = BLUE +# (FORMAT: colour) +CONTACT_LINE_DIRTY_FG = BLACK +CONTACT_LINE_DIRTY_BG = WHITE +# (FORMAT: colour) +CONTACT_LINE_DIRTY_SELECTED_FG = BLACK +CONTACT_LINE_DIRTY_SELECTED_BG = WHITE +# (FORMAT: colour) VIEW_CONTACT_NAME_FG = BLACK VIEW_CONTACT_NAME_BG = WHITE +# (FORMAT: colour) VIEW_CONTACT_NORMAL_FG = WHITE VIEW_CONTACT_NORMAL_BG = BLACK +# (FORMAT: colour) VIEW_CONTACT_HIGHLIGHT_FG = RED VIEW_CONTACT_HIGHLIGHT_BG = BLACK +# (FORMAT: colour) VIEW_CONTACT_NOTES_TITLE_FG = BLACK VIEW_CONTACT_NOTES_TITLE_BG = WHITE -CONTACT_LINE_DIRTY_SELECTED_FG = BLACK -CONTACT_LINE_DIRTY_SELECTED_BG = WHITE -CONTACT_LINE_DIRTY_FG = BLACK -CONTACT_LINE_DIRTY_BG = WHITE - diff --git a/src/be/nikiroo/jvcard/resources/display.properties b/src/be/nikiroo/jvcard/resources/display.properties index 3b6a056..eb7408d 100644 --- a/src/be/nikiroo/jvcard/resources/display.properties +++ b/src/be/nikiroo/jvcard/resources/display.properties @@ -1,6 +1,6 @@ -# display options configuration - -# The contact list format is basically a list of VCF field names +# Display options configuration +# +# The Contact List Format (CLF) is basically a list of VCF field names # separated by a pipe and optionally parametrised. # The parameters allows you to: # - @x: (the 'x' is the letter 'x') show only a present/not present info @@ -9,18 +9,15 @@ # # In case of lists or multiple-fields values, you can select a specific # list or field with: -# - FIELD@(0): select the first value in a list -# - FIELD@[1]: select the second field in a multiple-fields value +# - FIELD@(0): select the first value in a list +# - FIELD@[1]: select the second field in a multiple-fields value # # You can also add a fixed text if it starts with a simple-quote ('). # # Example: "'Contact: |N@10|FN@20|NICK@+|PHOTO@x" # -# You can cycle through them if you have more than one -# (in this case, separate them with a comma (',') -CONTACT_LIST_FORMAT = NICKNAME@10|FN@+|EMAIL@30|PHOTO@x,N@[0]@20|N@[1]@+|EMAIL@40 - -# The list of details to show in View Contact mode: +# +# The Contact Details Info Format (CDIF): # - Each detail (separated by a pipe "|" character) is visible on its own line # - It is made up of two parts: the label and the linked VCF field (optional), # separated by an equal "=", sharp "#", plus "+" or asterisk "*" sign @@ -32,14 +29,24 @@ CONTACT_LIST_FORMAT = NICKNAME@10|FN@+|EMAIL@30|PHOTO@x,N@[0]@20|N@[1]@+|EMAIL@4 # Example: # CONTACT_DETAILS_INFO = Phone:=TEL|eMail:=EMAIL # -# This will print two lines in View mode: +# This will print two lines: # Phone: +32 888 88 88 88 # eMail: nobody@nowhere.com -CONTACT_DETAILS_INFO = Phone:=TEL|eMail:=EMAIL +# + +# (FORMAT: coma-separated list of CLF) +# The format of each line in the contact list +CONTACT_LIST_FORMAT = NICKNAME@10|FN@+|EMAIL@30|PHOTO@x,N@[0]@20|N@[1]@+|EMAIL@40 +# (FORMAT: CDIF) +# The list of details to show in View Contact mode +CONTACT_DETAILS_INFO = Phone:=TEL|eMail:=EMAIL +# (FORMAT: Integer or nothing for auto) # The size of the details' labels CONTACT_DETAILS_LABEL_WIDTH = 12 - +# (FORMAT: CLF) +# The default value of FN if it is not present CONTACT_DETAILS_DEFAULT_FN = N@[1]|' |N@[0] - +# (FORMAT: TRUE or FALSE) +# TRUE to force all FNs to be recreated from CONTACT_DETAILS_DEFAULT_FN CONTACT_DETAILS_SHOW_COMPUTED_FN = true diff --git a/src/be/nikiroo/jvcard/resources/enums/ColorOption.java b/src/be/nikiroo/jvcard/resources/enums/ColorOption.java new file mode 100644 index 0000000..d8816e0 --- /dev/null +++ b/src/be/nikiroo/jvcard/resources/enums/ColorOption.java @@ -0,0 +1,86 @@ +package be.nikiroo.jvcard.resources.enums; + +import java.io.IOException; +import java.io.Writer; + +import be.nikiroo.jvcard.resources.Meta; +import be.nikiroo.jvcard.resources.Bundles.Bundle; + +/** + * Represent an element that can be coloured (foreground/background colours). + * + * @author niki + * + */ +public enum ColorOption { + @Meta(what = "", where = "", format = "colour", info = "") + DEFAULT, // + + @Meta(what = "", where = "", format = "colour", info = "") + TITLE_MAIN, // + @Meta(what = "", where = "", format = "colour", info = "") + TITLE_VARIABLE, // + @Meta(what = "", where = "", format = "colour", info = "") + TITLE_COUNT, // + + @Meta(what = "", where = "", format = "colour", info = "") + ACTION_KEY, // + @Meta(what = "", where = "", format = "colour", info = "") + ACTION_DESC, // + + @Meta(what = "", where = "", format = "colour", info = "") + LINE_MESSAGE, // + @Meta(what = "", where = "", format = "colour", info = "") + LINE_MESSAGE_ERR, // + @Meta(what = "", where = "", format = "colour", info = "") + LINE_MESSAGE_QUESTION, // + @Meta(what = "", where = "", format = "colour", info = "") + LINE_MESSAGE_ANS, // + + @Meta(what = "", where = "", format = "colour", info = "") + CONTACT_LINE, // + @Meta(what = "", where = "", format = "colour", info = "") + CONTACT_LINE_SEPARATOR, // + @Meta(what = "", where = "", format = "colour", info = "") + CONTACT_LINE_SELECTED, // + @Meta(what = "", where = "", format = "colour", info = "") + CONTACT_LINE_SEPARATOR_SELECTED, // + @Meta(what = "", where = "", format = "colour", info = "") + CONTACT_LINE_DIRTY, // + @Meta(what = "", where = "", format = "colour", info = "") + CONTACT_LINE_DIRTY_SELECTED, // + + @Meta(what = "", where = "", format = "colour", info = "") + VIEW_CONTACT_NAME, // + @Meta(what = "", where = "", format = "colour", info = "") + VIEW_CONTACT_NORMAL, // + @Meta(what = "", where = "", format = "colour", info = "") + VIEW_CONTACT_HIGHLIGHT, // + @Meta(what = "", where = "", format = "colour", info = "") + VIEW_CONTACT_NOTES_TITLE, // + + ; + + /** + * Write the header found in the configuration .properties file of + * this {@link Bundle}. + * + * @param writer + * the {@link Writer} to write the header in + * + * @throws IOException + * in case of IO error + */ + static public void writeHeader(Writer writer) throws IOException { + writer.write("# Application colours\n"); + writer.write("# \n"); + writer.write("# Note that you can define a colour in one of those 3 ways:\n"); + writer.write("# - WHITE: one of the ANSI colour names, in upper case\n"); + writer.write("# - @RRGGBB: a RGB code we will try to match using one of the 256 Terminal colours\n"); + writer.write("# - #RRGGBB: an exact RGB colour (please make sure your terminal supports this)\n"); + writer.write("# - 255: one of the 256 indexed colours of the terminal (the 16 first colours are theme-based) \n"); + writer.write("# \n"); + writer.write("# ...and thus either for xxx_FG (foreground colour) or xxx_BG (background colour)\n"); + writer.write("# \n"); + } +} \ No newline at end of file diff --git a/src/be/nikiroo/jvcard/resources/enums/DisplayOption.java b/src/be/nikiroo/jvcard/resources/enums/DisplayOption.java new file mode 100644 index 0000000..24efa45 --- /dev/null +++ b/src/be/nikiroo/jvcard/resources/enums/DisplayOption.java @@ -0,0 +1,70 @@ +package be.nikiroo.jvcard.resources.enums; + +import java.io.IOException; +import java.io.Writer; + +import be.nikiroo.jvcard.resources.Bundles.Bundle; +import be.nikiroo.jvcard.resources.Meta; + +public enum DisplayOption { + @Meta(what = "", where = "", format = "coma-separated list of CLF", info = "The format of each line in the contact list") + CONTACT_LIST_FORMAT, // + @Meta(what = "", where = "", format = "CDIF", info = "The list of details to show in View Contact mode") + CONTACT_DETAILS_INFO, // + @Meta(what = "", where = "", format = "Integer or nothing for auto", info = "The size of the details' labels") + CONTACT_DETAILS_LABEL_WIDTH, // + @Meta(what = "", where = "", format = "CLF", info = "The default value of FN if it is not present") + CONTACT_DETAILS_DEFAULT_FN, // + @Meta(what = "", where = "", format = "TRUE or FALSE", info = "TRUE to force all FNs to be recreated from CONTACT_DETAILS_DEFAULT_FN") + CONTACT_DETAILS_SHOW_COMPUTED_FN, // + + ; + + /** + * Write the header found in the configuration .properties file of + * this {@link Bundle}. + * + * @param writer + * the {@link Writer} to write the header in + * + * @throws IOException + * in case of IO error + */ + static public void writeHeader(Writer writer) throws IOException { + writer.write("# Display options configuration\n"); + writer.write("#\n"); + writer.write("# The Contact List Format (CLF) is basically a list of VCF field names\n"); + writer.write("# separated by a pipe and optionally parametrised.\n"); + writer.write("# The parameters allows you to:\n"); + writer.write("# - @x: (the 'x' is the letter 'x') show only a present/not present info\n"); + writer.write("# - @n: limit the size to a fixed value 'n'\n"); + writer.write("# - @+: expand the size of this field as much as possible\n"); + writer.write("#\n"); + writer.write("# In case of lists or multiple-fields values, you can select a specific\n"); + writer.write("# list or field with:\n"); + writer.write("# - FIELD@(0): select the first value in a list\n"); + writer.write("# - FIELD@[1]: select the second field in a multiple-fields value\n"); + writer.write("#\n"); + writer.write("# You can also add a fixed text if it starts with a simple-quote (').\n"); + writer.write("#\n"); + writer.write("# Example: \"'Contact: |N@10|FN@20|NICK@+|PHOTO@x\"\n"); + writer.write("# \n"); + writer.write("# \n"); + writer.write("# The Contact Details Info Format (CDIF):\n"); + writer.write("# - Each detail (separated by a pipe \"|\" character) is visible on its own line\n"); + writer.write("# - It is made up of two parts: the label and the linked VCF field (optional),\n"); + writer.write("# separated by an equal \"=\", sharp \"#\", plus \"+\" or asterisk \"*\" sign\n"); + writer.write("# - \"=FIELD\" will take the preferred value for this field\n"); + writer.write("# - \"+FIELD\" will take the preferred value for this field and highlight it\n"); + writer.write("# - \"#FIELD\" will take all the values with this field's name\n"); + writer.write("# - \"*FIELD\" will take all the values with this field's name, highlighting the preferred one\n"); + writer.write("#\n"); + writer.write("# Example:\n"); + writer.write("# CONTACT_DETAILS_INFO = Phone:=TEL|eMail:=EMAIL\n"); + writer.write("#\n"); + writer.write("# This will print two lines:\n"); + writer.write("# Phone: +32 888 88 88 88\n"); + writer.write("# eMail: nobody@nowhere.com\n"); + writer.write("#\n"); + } +} diff --git a/src/be/nikiroo/jvcard/resources/enums/RemotingOption.java b/src/be/nikiroo/jvcard/resources/enums/RemotingOption.java new file mode 100644 index 0000000..f0b274b --- /dev/null +++ b/src/be/nikiroo/jvcard/resources/enums/RemotingOption.java @@ -0,0 +1,34 @@ +package be.nikiroo.jvcard.resources.enums; + +import java.io.IOException; +import java.io.Writer; + +import be.nikiroo.jvcard.resources.Meta; +import be.nikiroo.jvcard.resources.Bundles.Bundle; + +public enum RemotingOption { + @Meta(what = "", where = "Server", format = "directory", info = "when starting as a jVCard remote server, where to look for data") + SERVER_DATA_PATH, // + + @Meta(what = "", where = "Client", format = "directory", info = "when loading \"jvcard://\" links, where to save cache files") + CLIENT_CACHE_DIR, // + @Meta(what = "", where = "Client", format = "TRUE or FALSE", info = "Automatically synchronise remote cards") + CLIENT_AUTO_SYNC, // + + ; + + /** + * Write the header found in the configuration .properties file of + * this {@link Bundle}. + * + * @param writer + * the {@link Writer} to write the header in + * + * @throws IOException + * in case of IO error + */ + static public void writeHeader(Writer writer) throws IOException { + writer.write("# Remote configuration (client and server)\n"); + writer.write("#\n"); + } +} diff --git a/src/be/nikiroo/jvcard/resources/enums/StringId.java b/src/be/nikiroo/jvcard/resources/enums/StringId.java new file mode 100644 index 0000000..c933b00 --- /dev/null +++ b/src/be/nikiroo/jvcard/resources/enums/StringId.java @@ -0,0 +1,87 @@ +package be.nikiroo.jvcard.resources.enums; + +import java.io.IOException; +import java.io.Writer; + +import be.nikiroo.jvcard.resources.Bundles.Bundle; +import be.nikiroo.jvcard.resources.Meta; + +/** + * The enum representing textual information to be translated to the user as a + * key. + * + * Note that each key that should be translated MUST be annotated with a + * {@link Meta} annotation. + * + * @author niki + * + */ +public enum StringId { + DUMMY, // <-- TODO : remove + NULL, // Special usage, no annotations so it is not visible in + // .properties files + @Meta(what = "a key to press", where = "action keys", format = "MUST BE 3 chars long", info = "Tab key") + KEY_TAB, // keys + @Meta(what = "a key to press", where = "action keys", format = "MUST BE 3 chars long", info = "Enter key") + KEY_ENTER, // + @Meta(what = "Action key", where = "All screens except the first (KEY_ACTION_QUIT)", format = "", info = "Go back to previous screen") + KEY_ACTION_BACK, // + @Meta(what = "Action key", where = "MainWindow", format = "", info = "Get help text") + KEY_ACTION_HELP, // + @Meta(what = "Action key", where = "FileList", format = "", info = "View the selected card") + KEY_ACTION_VIEW_CARD, // + @Meta(what = "Action key", where = "ContactList", format = "", info = "View the selected contact") + KEY_ACTION_VIEW_CONTACT, // + @Meta(what = "Action key", where = "ContactDetails", format = "", info = "Edit the contact") + KEY_ACTION_EDIT_CONTACT, // + @Meta(what = "Action key", where = "ContactDetails", format = "", info = "Edit the contact in RAW mode") + KEY_ACTION_EDIT_CONTACT_RAW, // + @Meta(what = "Action key", where = "ContactList", format = "", info = "Save the whole card") + KEY_ACTION_SAVE_CARD, // + @Meta(what = "", where = "ContactList", format = "", info = "Delete the selected contact") + KEY_ACTION_DELETE_CONTACT, // + @Meta(what = "Action key", where = "ContactList", format = "", info = "Filter the displayed contacts") + KEY_ACTION_SEARCH, // + @Meta(what = "", where = "", format = "we could use: ' ', ┃, │...", info = "Field separator") + DEAULT_FIELD_SEPARATOR, // MainContentList + @Meta(what = "Action key", where = "ContactDetails", format = "", info = "Invert the photo's colours") + KEY_ACTION_INVERT, // + @Meta(what = "Action key", where = "ContactDetails", format = "", info = "Show the photo in 'fullscreen'") + KEY_ACTION_FULLSCREEN, // + @Meta(what = "Action key", where = "ContactList, ContactDetails, ContactDetailsRaw", format = "", info = "Switch between the available display formats") + KEY_ACTION_SWITCH_FORMAT, // multi-usage + @Meta(what = "Action key", where = "Contact list, Edit Contact", format = "", info = "Add a new contact/field") + KEY_ACTION_ADD, // + @Meta(what = "User question: TEXT", where = "Contact list", format = "", info = "New contact") + ASK_USER_CONTACT_NAME, // + @Meta(what = "User question: [Y|N]", where = "Contact list", format = "%s = contact name", info = "Delete contact") + CONFIRM_USER_DELETE_CONTACT, // + @Meta(what = "Error", where = "Contact list", format = "%s = contact name", info = "cannot delete a contact") + ERR_CANNOT_DELETE_CONTACT, // + + ; + + /** + * Write the header found in the configuration .properties file of + * this {@link Bundle}. + * + * @param writer + * the {@link Writer} to write the header in + * @param name + * the file name + * + * @throws IOException + * in case of IO error + */ + static public void writeHeader(Writer writer, String name) + throws IOException { + writer.write("# " + name + " translation file (UTF-8)\n"); + writer.write("# \n"); + writer.write("# Note that any key can be doubled with a _NOUTF suffix\n"); + writer.write("# to use when the flag --noutf is passed\n"); + writer.write("# \n"); + writer.write("# Also, the comments always refer to the key below them.\n"); + writer.write("# \n"); + writer.write("\n"); + } +}; diff --git a/src/be/nikiroo/jvcard/resources/remote.properties b/src/be/nikiroo/jvcard/resources/remote.properties index d6c9e72..88e0b8f 100644 --- a/src/be/nikiroo/jvcard/resources/remote.properties +++ b/src/be/nikiroo/jvcard/resources/remote.properties @@ -1,19 +1,13 @@ -# remote configuration (client and server) -# +# Remote configuration (client and server) +# -############### -### Server: ### -############### -# when starting as a jVCard remote server, where to look for data: +# (WHERE: Server, FORMAT: directory) +# when starting as a jVCard remote server, where to look for data SERVER_DATA_PATH = /tmp/server/ - -############### -### Client: ### -############### - +# (WHERE: Client, FORMAT: directory) # when loading "jvcard://" links, where to save cache files -CLIENT_CACHE_DIR = /tmp/client/ - -# "true" to automatically synchronise remote cards -CLIENT_AUTO_SYNC = true +CLIENT_CACHE_DIR = /tmp/client/ +# (WHERE: Client, FORMAT: TRUE or FALSE) +# Automatically synchronise remote cards +CLIENT_AUTO_SYNC = true diff --git a/src/be/nikiroo/jvcard/tui/KeyAction.java b/src/be/nikiroo/jvcard/tui/KeyAction.java index 2c10e62..bd91ba7 100644 --- a/src/be/nikiroo/jvcard/tui/KeyAction.java +++ b/src/be/nikiroo/jvcard/tui/KeyAction.java @@ -6,7 +6,7 @@ import be.nikiroo.jvcard.Card; import be.nikiroo.jvcard.Contact; import be.nikiroo.jvcard.Data; import be.nikiroo.jvcard.launcher.Main; -import be.nikiroo.jvcard.resources.Trans.StringId; +import be.nikiroo.jvcard.resources.enums.StringId; import com.googlecode.lanterna.input.KeyStroke; import com.googlecode.lanterna.input.KeyType; diff --git a/src/be/nikiroo/jvcard/tui/MainWindow.java b/src/be/nikiroo/jvcard/tui/MainWindow.java index d7cb80d..1cbc014 100644 --- a/src/be/nikiroo/jvcard/tui/MainWindow.java +++ b/src/be/nikiroo/jvcard/tui/MainWindow.java @@ -8,9 +8,9 @@ import java.util.List; import be.nikiroo.jvcard.launcher.Main; import be.nikiroo.jvcard.resources.StringUtils; -import be.nikiroo.jvcard.resources.Trans.StringId; +import be.nikiroo.jvcard.resources.enums.ColorOption; +import be.nikiroo.jvcard.resources.enums.StringId; import be.nikiroo.jvcard.tui.KeyAction.Mode; -import be.nikiroo.jvcard.tui.UiColors.Element; import be.nikiroo.jvcard.tui.panes.ContactDetails; import be.nikiroo.jvcard.tui.panes.ContactDetailsRaw; import be.nikiroo.jvcard.tui.panes.ContactList; @@ -251,9 +251,9 @@ public class MainWindow extends BasicWindow { if (mess != null || messagePanel.getChildCount() > 0) { messagePanel.removeAllComponents(); if (mess != null) { - Element element = (error ? UiColors.Element.LINE_MESSAGE_ERR - : UiColors.Element.LINE_MESSAGE); - Label lbl = element.createLabel(" " + mess + " "); + ColorOption element = (error ? ColorOption.LINE_MESSAGE_ERR + : ColorOption.LINE_MESSAGE); + Label lbl = UiColors.createLabel(element, " " + mess + " "); messagePanel.addComponent(lbl, LinearLayout .createLayoutData(LinearLayout.Alignment.Center)); } @@ -318,7 +318,7 @@ public class MainWindow extends BasicWindow { llayout.setSpacing(0); hpanel.setLayoutManager(llayout); - Label lbl = UiColors.Element.LINE_MESSAGE_QUESTION.createLabel(" " + Label lbl = UiColors.createLabel(ColorOption.LINE_MESSAGE_QUESTION, " " + question + " "); text = new TextBox(new TerminalSize(getSize().getColumns() - lbl.getSize().getColumns(), 1)); @@ -451,18 +451,18 @@ public class MainWindow extends BasicWindow { super.setTitle(prefix); Label lblPrefix = new Label(prefix); - UiColors.Element.TITLE_MAIN.themeLabel(lblPrefix); + UiColors.themeLabel(ColorOption.TITLE_MAIN, lblPrefix); Label lblTitle = null; if (title.length() > 0) { lblTitle = new Label(title); - UiColors.Element.TITLE_VARIABLE.themeLabel(lblTitle); + UiColors.themeLabel(ColorOption.TITLE_VARIABLE, lblTitle); } Label lblCount = null; if (countStr != null) { lblCount = new Label(countStr); - UiColors.Element.TITLE_COUNT.themeLabel(lblCount); + UiColors.themeLabel(ColorOption.TITLE_COUNT, lblCount); } titlePanel.removeAllComponents(); @@ -520,9 +520,9 @@ public class MainWindow extends BasicWindow { layout.setSpacing(0); kPane.setLayoutManager(layout); - kPane.addComponent(UiColors.Element.ACTION_KEY - .createLabel(keyTrans)); - kPane.addComponent(UiColors.Element.ACTION_DESC.createLabel(trans)); + kPane.addComponent(UiColors.createLabel(ColorOption.ACTION_KEY, + keyTrans)); + kPane.addComponent(UiColors.createLabel(ColorOption.ACTION_DESC, trans)); actionPanel.addComponent(kPane); } @@ -534,8 +534,8 @@ public class MainWindow extends BasicWindow { } if (width > 0) { - actionPanel.addComponent(UiColors.Element.ACTION_DESC - .createLabel(StringUtils.padString("", width))); + actionPanel.addComponent(UiColors.createLabel(ColorOption.ACTION_DESC, + StringUtils.padString("", width))); } } diff --git a/src/be/nikiroo/jvcard/tui/UiColors.java b/src/be/nikiroo/jvcard/tui/UiColors.java index 0a46968..abac7d5 100644 --- a/src/be/nikiroo/jvcard/tui/UiColors.java +++ b/src/be/nikiroo/jvcard/tui/UiColors.java @@ -3,9 +3,9 @@ package be.nikiroo.jvcard.tui; import java.util.HashMap; import java.util.Map; import java.util.MissingResourceException; -import java.util.ResourceBundle; -import be.nikiroo.jvcard.resources.Bundles; +import be.nikiroo.jvcard.resources.bundles.ColorBundle; +import be.nikiroo.jvcard.resources.enums.ColorOption; import com.googlecode.lanterna.TextColor; import com.googlecode.lanterna.gui2.Label; @@ -16,86 +16,28 @@ import com.googlecode.lanterna.gui2.Label; * @author niki * */ -public class UiColors { +public class UiColors extends ColorBundle { static private Object lock = new Object(); static private UiColors instance = null; - private ResourceBundle bundle = null; private Map colorMap = null; private UiColors() { + super(); colorMap = new HashMap(); - bundle = Bundles.getBundle("colors"); } /** - * Represent an element that can be coloured (foreground/background - * colours). - * - * @author niki - * - */ - public enum Element { - DEFAULT, // - TITLE_MAIN, TITLE_VARIABLE, TITLE_COUNT, // - ACTION_KEY, ACTION_DESC, // - LINE_MESSAGE, LINE_MESSAGE_ERR, LINE_MESSAGE_QUESTION, LINE_MESSAGE_ANS, // - CONTACT_LINE, CONTACT_LINE_SEPARATOR, CONTACT_LINE_SELECTED, CONTACT_LINE_SEPARATOR_SELECTED, CONTACT_LINE_DIRTY, CONTACT_LINE_DIRTY_SELECTED, // - VIEW_CONTACT_NAME, VIEW_CONTACT_NORMAL, VIEW_CONTACT_HIGHLIGHT, VIEW_CONTACT_NOTES_TITLE, // - ; - - /** - * Get the foreground colour of this element. - * - * @return the colour - */ - public TextColor getForegroundColor() { - return UiColors.getInstance().getForegroundColor(this); - } - - /** - * Get the background colour of this element. - * - * @return the colour - */ - public TextColor getBackgroundColor() { - return UiColors.getInstance().getBackgroundColor(this); - } - - /** - * Create a new {@link Label} with the colours of this {@link Element}. - * - * @param text - * the text of the {@link Label} - * - * @return the new {@link Label} - */ - public Label createLabel(String text) { - return UiColors.getInstance().createLabel(this, text); - } - - /** - * Theme a {@link Label} with the colours of this {@link Element}. - * - * @param lbl - * the {@link Label} - */ - public void themeLabel(Label lbl) { - UiColors.getInstance().themeLabel(this, lbl); - } - } - - /** - * Create a new {@link Label} with the colours of the given {@link Element}. + * Create a new {@link Label} with the colours of the given {@link ColorOption}. * * @param el - * the {@link Element} + * the {@link ColorOption} * @param text * the text of the {@link Label} * * @return the new {@link Label} */ - private Label createLabel(Element el, String text) { + static public Label createLabel(ColorOption el, String text) { if (text == null) text = ""; @@ -105,62 +47,62 @@ public class UiColors { } /** - * Theme a {@link Label} with the colours of the given {@link Element}. + * Theme a {@link Label} with the colours of the given {@link ColorOption}. * * @param el - * the {@link Element} + * the {@link ColorOption} * @param lbl * the {@link Label} */ - private void themeLabel(Element el, Label lbl) { - lbl.setForegroundColor(el.getForegroundColor()); - lbl.setBackgroundColor(el.getBackgroundColor()); + static public void themeLabel(ColorOption el, Label lbl) { + lbl.setForegroundColor(getForegroundColor(el)); + lbl.setBackgroundColor(getBackgroundColor(el)); } /** * Return the background colour of the given element. * * @param el - * the {@link Element} + * the {@link ColorOption} * * @return its background colour */ - private TextColor getBackgroundColor(Element el) { - if (!colorMap.containsKey(el.name() + "_BG")) { + static public TextColor getBackgroundColor(ColorOption el) { + if (!getInstance().colorMap.containsKey(el.name() + "_BG")) { String value = null; try { - value = bundle.getString(el.name() + "_BG"); + value = getInstance().map.getString(el.name() + "_BG"); } catch (MissingResourceException mre) { value = null; } - colorMap.put(el.name() + "_BG", + getInstance().colorMap.put(el.name() + "_BG", convertToColor(value, TextColor.ANSI.BLACK)); } - return colorMap.get(el.name() + "_BG"); + return getInstance().colorMap.get(el.name() + "_BG"); } /** * Return the foreground colour of the given element. * * @param el - * the {@link Element} + * the {@link ColorOption} * * @return its foreground colour */ - private TextColor getForegroundColor(Element el) { - if (!colorMap.containsKey(el.name() + "_FG")) { + static public TextColor getForegroundColor(ColorOption el) { + if (!getInstance().colorMap.containsKey(el.name() + "_FG")) { String value = null; try { - value = bundle.getString(el.name() + "_FG"); + value = getInstance().map.getString(el.name() + "_FG"); } catch (MissingResourceException mre) { value = null; } - colorMap.put(el.name() + "_FG", + getInstance().colorMap.put(el.name() + "_FG", convertToColor(value, TextColor.ANSI.WHITE)); } - return colorMap.get(el.name() + "_FG"); + return getInstance().colorMap.get(el.name() + "_FG"); } /** @@ -168,7 +110,7 @@ public class UiColors { * * @return the (unique) instance */ - static public UiColors getInstance() { + static private UiColors getInstance() { synchronized (lock) { if (instance == null) instance = new UiColors(); @@ -212,5 +154,4 @@ public class UiColors { return defaultColor; } - } diff --git a/src/be/nikiroo/jvcard/tui/panes/ContactDetails.java b/src/be/nikiroo/jvcard/tui/panes/ContactDetails.java index aa838cb..be2c201 100644 --- a/src/be/nikiroo/jvcard/tui/panes/ContactDetails.java +++ b/src/be/nikiroo/jvcard/tui/panes/ContactDetails.java @@ -3,15 +3,15 @@ package be.nikiroo.jvcard.tui.panes; import java.awt.Image; import java.util.LinkedList; import java.util.List; -import java.util.MissingResourceException; -import java.util.ResourceBundle; import be.nikiroo.jvcard.Contact; import be.nikiroo.jvcard.Data; import be.nikiroo.jvcard.TypeInfo; -import be.nikiroo.jvcard.resources.Bundles; import be.nikiroo.jvcard.resources.StringUtils; -import be.nikiroo.jvcard.resources.Trans; +import be.nikiroo.jvcard.resources.bundles.DisplayBundle; +import be.nikiroo.jvcard.resources.enums.DisplayOption; +import be.nikiroo.jvcard.resources.enums.ColorOption; +import be.nikiroo.jvcard.resources.enums.StringId; import be.nikiroo.jvcard.tui.ImageTextControl; import be.nikiroo.jvcard.tui.KeyAction; import be.nikiroo.jvcard.tui.KeyAction.DataType; @@ -39,28 +39,15 @@ public class ContactDetails extends MainContent { // from .properties file: private int labelSize = -1; private String infoFormat = ""; + // public ContactDetails(Contact contact) { // Get the .properties info: - ResourceBundle map = Bundles.getBundle("display"); - - try { - labelSize = Integer.parseInt(map - .getString("CONTACT_DETAILS_LABEL_WIDTH")); - - } catch (NumberFormatException e) { - e.printStackTrace(); - labelSize = -1; - } catch (MissingResourceException e) { - labelSize = -1; - } - - try { - infoFormat = map.getString("CONTACT_DETAILS_INFO"); - } catch (MissingResourceException e) { - e.printStackTrace(); - } + DisplayBundle map = new DisplayBundle(); + labelSize = map.getInteger(DisplayOption.CONTACT_DETAILS_LABEL_WIDTH, + -1); + infoFormat = map.getString(DisplayOption.CONTACT_DETAILS_INFO); // BorderLayout blayout = new BorderLayout(); @@ -77,9 +64,9 @@ public class ContactDetails extends MainContent { Panel notePanel = new Panel(); notePanel.setLayoutManager(new LinearLayout(Direction.HORIZONTAL)); - notePanel.addComponent(UiColors.Element.VIEW_CONTACT_NOTES_TITLE - .createLabel("Notes:")); - note = UiColors.Element.VIEW_CONTACT_NORMAL.createLabel(""); + notePanel.addComponent(UiColors.createLabel( + ColorOption.VIEW_CONTACT_NOTES_TITLE, "Notes:")); + note = UiColors.createLabel(ColorOption.VIEW_CONTACT_NORMAL, ""); notePanel.addComponent(note); setContact(contact); @@ -105,10 +92,10 @@ public class ContactDetails extends MainContent { infoPanel.removeAllComponents(); String name = contact.getPreferredDataValue("FN"); - infoPanel.addComponent(UiColors.Element.VIEW_CONTACT_NAME - .createLabel(name)); - infoPanel.addComponent(UiColors.Element.VIEW_CONTACT_NORMAL - .createLabel("")); + infoPanel.addComponent(UiColors.createLabel( + ColorOption.VIEW_CONTACT_NAME, name)); + infoPanel.addComponent(UiColors.createLabel( + ColorOption.VIEW_CONTACT_NORMAL, "")); // List of infos: String[] infos = infoFormat.split("\\|"); @@ -129,8 +116,8 @@ public class ContactDetails extends MainContent { all = true; if (all || hl || info.contains("=")) { - UiColors.Element el = hl ? UiColors.Element.VIEW_CONTACT_HIGHLIGHT - : UiColors.Element.VIEW_CONTACT_NORMAL; + ColorOption el = hl ? ColorOption.VIEW_CONTACT_HIGHLIGHT + : ColorOption.VIEW_CONTACT_NORMAL; int index = info.indexOf('='); if (index < 0) @@ -146,37 +133,34 @@ public class ContactDetails extends MainContent { if (all) { for (Data data : contact.getData(field)) { if (data.isPreferred()) { - infoPanel.addComponent(el - .createLabel(StringUtils.padString( - label, labelSize) + infoPanel.addComponent(UiColors.createLabel(el, + StringUtils.padString(label, labelSize) + data.toString())); } else { - infoPanel - .addComponent(UiColors.Element.VIEW_CONTACT_NORMAL - .createLabel(StringUtils - .padString(label, - labelSize) - + data.toString())); + infoPanel.addComponent(UiColors.createLabel( + ColorOption.VIEW_CONTACT_NORMAL, + StringUtils.padString(label, labelSize) + + data.toString())); } } } else { String val = contact.getPreferredDataValue(field); if (val == null) val = ""; - infoPanel.addComponent(el.createLabel(StringUtils - .padString(label, labelSize) + val)); + infoPanel.addComponent(UiColors.createLabel(el, + StringUtils.padString(label, labelSize) + val)); } } else { String label = info; - infoPanel.addComponent(UiColors.Element.VIEW_CONTACT_NORMAL - .createLabel(StringUtils - .padString(label, labelSize))); + infoPanel.addComponent(UiColors.createLabel( + ColorOption.VIEW_CONTACT_NORMAL, + StringUtils.padString(label, labelSize))); } } // end of list - infoPanel.addComponent(UiColors.Element.VIEW_CONTACT_NORMAL - .createLabel("")); + infoPanel.addComponent(UiColors.createLabel( + ColorOption.VIEW_CONTACT_NORMAL, "")); String notes = contact.getPreferredDataValue("NOTE"); if (notes == null) @@ -221,7 +205,7 @@ public class ContactDetails extends MainContent { List actions = new LinkedList(); actions.add(new KeyAction(Mode.NONE, KeyType.Tab, - Trans.StringId.KEY_ACTION_SWITCH_FORMAT) { + StringId.KEY_ACTION_SWITCH_FORMAT) { @Override public boolean onAction() { if (txtImage != null) { @@ -231,8 +215,7 @@ public class ContactDetails extends MainContent { return false; } }); - actions.add(new KeyAction(Mode.NONE, 'i', - Trans.StringId.KEY_ACTION_INVERT) { + actions.add(new KeyAction(Mode.NONE, 'i', StringId.KEY_ACTION_INVERT) { @Override public boolean onAction() { if (txtImage != null) { @@ -243,7 +226,7 @@ public class ContactDetails extends MainContent { } }); actions.add(new KeyAction(Mode.NONE, 'f', - Trans.StringId.KEY_ACTION_FULLSCREEN) { + StringId.KEY_ACTION_FULLSCREEN) { @Override public boolean onAction() { fullscreenImage = !fullscreenImage; @@ -253,7 +236,7 @@ public class ContactDetails extends MainContent { }); // TODO: add "normal" edit actions.add(new KeyAction(Mode.CONTACT_DETAILS_RAW, 'r', - Trans.StringId.KEY_ACTION_EDIT_CONTACT_RAW) { + StringId.KEY_ACTION_EDIT_CONTACT_RAW) { @Override public Object getObject() { return contact; diff --git a/src/be/nikiroo/jvcard/tui/panes/ContactDetailsRaw.java b/src/be/nikiroo/jvcard/tui/panes/ContactDetailsRaw.java index 08cf9b8..5ceee7d 100644 --- a/src/be/nikiroo/jvcard/tui/panes/ContactDetailsRaw.java +++ b/src/be/nikiroo/jvcard/tui/panes/ContactDetailsRaw.java @@ -8,11 +8,11 @@ import be.nikiroo.jvcard.Data; import be.nikiroo.jvcard.TypeInfo; import be.nikiroo.jvcard.launcher.Main; import be.nikiroo.jvcard.resources.StringUtils; -import be.nikiroo.jvcard.resources.Trans; +import be.nikiroo.jvcard.resources.enums.ColorOption; +import be.nikiroo.jvcard.resources.enums.StringId; import be.nikiroo.jvcard.tui.KeyAction; import be.nikiroo.jvcard.tui.KeyAction.DataType; import be.nikiroo.jvcard.tui.KeyAction.Mode; -import be.nikiroo.jvcard.tui.UiColors.Element; import com.googlecode.lanterna.input.KeyType; @@ -41,7 +41,7 @@ public class ContactDetailsRaw extends MainContentList { // TODO: add, remove actions.add(new KeyAction(Mode.ASK_USER, KeyType.Enter, - Trans.StringId.DUMMY) { + StringId.DUMMY) { @Override public Object getObject() { return getSelectedData(); @@ -79,7 +79,7 @@ public class ContactDetailsRaw extends MainContentList { return "Cannot modify value"; } }); - actions.add(new KeyAction(Mode.ASK_USER_KEY, 'd', Trans.StringId.DUMMY) { + actions.add(new KeyAction(Mode.ASK_USER_KEY, 'd', StringId.DUMMY) { @Override public Object getObject() { return getSelectedData(); @@ -108,7 +108,7 @@ public class ContactDetailsRaw extends MainContentList { } }); // TODO: ui - actions.add(new KeyAction(Mode.ASK_USER, 'a', Trans.StringId.DUMMY) { + actions.add(new KeyAction(Mode.ASK_USER, 'a', StringId.DUMMY) { @Override public Object getObject() { return contact; @@ -143,7 +143,7 @@ public class ContactDetailsRaw extends MainContentList { }); // TODO: use a real UI for this, not a simple text box (a list or // something, maybe a whole new pane?) - actions.add(new KeyAction(Mode.ASK_USER, 't', Trans.StringId.DUMMY) { + actions.add(new KeyAction(Mode.ASK_USER, 't', StringId.DUMMY) { private String previous; @Override @@ -186,7 +186,7 @@ public class ContactDetailsRaw extends MainContentList { return "Cannot modify value"; } }); - actions.add(new KeyAction(Mode.ASK_USER, 'g', Trans.StringId.DUMMY) { + actions.add(new KeyAction(Mode.ASK_USER, 'g', StringId.DUMMY) { private String previous; @Override @@ -230,7 +230,7 @@ public class ContactDetailsRaw extends MainContentList { } }); actions.add(new KeyAction(Mode.NONE, KeyType.Tab, - Trans.StringId.KEY_ACTION_SWITCH_FORMAT) { + StringId.KEY_ACTION_SWITCH_FORMAT) { @Override public boolean onAction() { extMode = !extMode; @@ -278,12 +278,12 @@ public class ContactDetailsRaw extends MainContentList { if (data == null) return parts; - Element el = (focused && selected) ? Element.CONTACT_LINE_SELECTED - : Element.CONTACT_LINE; - Element elSep = (focused && selected) ? Element.CONTACT_LINE_SEPARATOR_SELECTED - : Element.CONTACT_LINE_SEPARATOR; - Element elDirty = (focused && selected) ? Element.CONTACT_LINE_DIRTY_SELECTED - : Element.CONTACT_LINE_DIRTY; + ColorOption el = (focused && selected) ? ColorOption.CONTACT_LINE_SELECTED + : ColorOption.CONTACT_LINE; + ColorOption elSep = (focused && selected) ? ColorOption.CONTACT_LINE_SEPARATOR_SELECTED + : ColorOption.CONTACT_LINE_SEPARATOR; + ColorOption elDirty = (focused && selected) ? ColorOption.CONTACT_LINE_DIRTY_SELECTED + : ColorOption.CONTACT_LINE_DIRTY; if (data.isDirty()) { parts.add(new TextPart(" ", el)); diff --git a/src/be/nikiroo/jvcard/tui/panes/ContactList.java b/src/be/nikiroo/jvcard/tui/panes/ContactList.java index 600f90c..023b834 100644 --- a/src/be/nikiroo/jvcard/tui/panes/ContactList.java +++ b/src/be/nikiroo/jvcard/tui/panes/ContactList.java @@ -8,12 +8,13 @@ import be.nikiroo.jvcard.Card; import be.nikiroo.jvcard.Contact; import be.nikiroo.jvcard.Data; import be.nikiroo.jvcard.launcher.Main; -import be.nikiroo.jvcard.resources.Bundles; -import be.nikiroo.jvcard.resources.Trans; +import be.nikiroo.jvcard.resources.bundles.DisplayBundle; +import be.nikiroo.jvcard.resources.enums.DisplayOption; +import be.nikiroo.jvcard.resources.enums.ColorOption; +import be.nikiroo.jvcard.resources.enums.StringId; import be.nikiroo.jvcard.tui.KeyAction; import be.nikiroo.jvcard.tui.KeyAction.DataType; import be.nikiroo.jvcard.tui.KeyAction.Mode; -import be.nikiroo.jvcard.tui.UiColors.Element; import com.googlecode.lanterna.input.KeyType; @@ -27,9 +28,10 @@ public class ContactList extends MainContentList { private String format; public ContactList(Card card) { + DisplayBundle map = new DisplayBundle(); formats = new LinkedList(); - for (String format : Bundles.getBundle("display") - .getString("CONTACT_LIST_FORMAT").split(",")) { + for (String format : map.getString(DisplayOption.CONTACT_LIST_FORMAT) + .split(",")) { formats.add(format); } @@ -93,7 +95,7 @@ public class ContactList extends MainContentList { // TODO ui actions.add(new KeyAction(Mode.ASK_USER, 'a', - Trans.StringId.KEY_ACTION_ADD) { + StringId.KEY_ACTION_ADD) { @Override public Object getObject() { return card; @@ -101,7 +103,7 @@ public class ContactList extends MainContentList { @Override public String getQuestion() { - return Main.trans(Trans.StringId.ASK_USER_CONTACT_NAME); + return Main.trans(StringId.ASK_USER_CONTACT_NAME); } @Override @@ -117,7 +119,7 @@ public class ContactList extends MainContentList { } }); actions.add(new KeyAction(Mode.ASK_USER_KEY, 'd', - Trans.StringId.KEY_ACTION_DELETE_CONTACT) { + StringId.KEY_ACTION_DELETE_CONTACT) { @Override public Object getObject() { return getSelectedContact(); @@ -130,7 +132,8 @@ public class ContactList extends MainContentList { if (contact != null) contactName = "" + contact.getPreferredDataValue("FN"); - return Main.trans(Trans.StringId.CONFIRM_USER_DELETE_CONTACT, + return Main.trans( + StringId.CONFIRM_USER_DELETE_CONTACT, contactName); } @@ -147,7 +150,8 @@ public class ContactList extends MainContentList { if (contact != null) contactName = "" + contact.getPreferredDataValue("FN"); - return Main.trans(Trans.StringId.ERR_CANNOT_DELETE_CONTACT, + return Main.trans( + StringId.ERR_CANNOT_DELETE_CONTACT, contactName); } @@ -155,7 +159,7 @@ public class ContactList extends MainContentList { } }); actions.add(new KeyAction(Mode.ASK_USER_KEY, 's', - Trans.StringId.KEY_ACTION_SAVE_CARD) { + StringId.KEY_ACTION_SAVE_CARD) { @Override public Object getObject() { return card; @@ -187,14 +191,14 @@ public class ContactList extends MainContentList { }); actions.add(new KeyAction(Mode.CONTACT_DETAILS, KeyType.Enter, - Trans.StringId.KEY_ACTION_VIEW_CONTACT) { + StringId.KEY_ACTION_VIEW_CONTACT) { @Override public Object getObject() { return getSelectedContact(); } }); actions.add(new KeyAction(Mode.NONE, KeyType.Tab, - Trans.StringId.KEY_ACTION_SWITCH_FORMAT) { + StringId.KEY_ACTION_SWITCH_FORMAT) { @Override public boolean onAction() { switchFormat(); @@ -202,7 +206,7 @@ public class ContactList extends MainContentList { } }); actions.add(new KeyAction(Mode.ASK_USER, 'w', - Trans.StringId.KEY_ACTION_SEARCH) { + StringId.KEY_ACTION_SEARCH) { @Override public String getQuestion() { @@ -253,12 +257,12 @@ public class ContactList extends MainContentList { if (contact == null) return parts; - Element el = (focused && selected) ? Element.CONTACT_LINE_SELECTED - : Element.CONTACT_LINE; - Element elSep = (focused && selected) ? Element.CONTACT_LINE_SEPARATOR_SELECTED - : Element.CONTACT_LINE_SEPARATOR; - Element elDirty = (focused && selected) ? Element.CONTACT_LINE_DIRTY_SELECTED - : Element.CONTACT_LINE_DIRTY; + ColorOption el = (focused && selected) ? ColorOption.CONTACT_LINE_SELECTED + : ColorOption.CONTACT_LINE; + ColorOption elSep = (focused && selected) ? ColorOption.CONTACT_LINE_SEPARATOR_SELECTED + : ColorOption.CONTACT_LINE_SEPARATOR; + ColorOption elDirty = (focused && selected) ? ColorOption.CONTACT_LINE_DIRTY_SELECTED + : ColorOption.CONTACT_LINE_DIRTY; width -= 2; // dirty mark space diff --git a/src/be/nikiroo/jvcard/tui/panes/FileList.java b/src/be/nikiroo/jvcard/tui/panes/FileList.java index 376aae9..da589aa 100644 --- a/src/be/nikiroo/jvcard/tui/panes/FileList.java +++ b/src/be/nikiroo/jvcard/tui/panes/FileList.java @@ -12,11 +12,11 @@ import be.nikiroo.jvcard.launcher.CardResult.MergeCallback; import be.nikiroo.jvcard.launcher.Main; import be.nikiroo.jvcard.parsers.Format; import be.nikiroo.jvcard.resources.StringUtils; -import be.nikiroo.jvcard.resources.Trans; +import be.nikiroo.jvcard.resources.enums.ColorOption; +import be.nikiroo.jvcard.resources.enums.StringId; import be.nikiroo.jvcard.tui.KeyAction; import be.nikiroo.jvcard.tui.KeyAction.DataType; import be.nikiroo.jvcard.tui.KeyAction.Mode; -import be.nikiroo.jvcard.tui.UiColors.Element; import com.googlecode.lanterna.input.KeyType; @@ -63,10 +63,10 @@ public class FileList extends MainContentList { // TODO: from ini file? int SIZE_COL_1 = 3; - Element el = (focused && selected) ? Element.CONTACT_LINE_SELECTED - : Element.CONTACT_LINE; - Element elSep = (focused && selected) ? Element.CONTACT_LINE_SEPARATOR_SELECTED - : Element.CONTACT_LINE_SEPARATOR; + ColorOption el = (focused && selected) ? ColorOption.CONTACT_LINE_SELECTED + : ColorOption.CONTACT_LINE; + ColorOption elSep = (focused && selected) ? ColorOption.CONTACT_LINE_SEPARATOR_SELECTED + : ColorOption.CONTACT_LINE_SEPARATOR; List parts = new LinkedList(); @@ -104,7 +104,7 @@ public class FileList extends MainContentList { // TODO del, save... actions.add(new KeyAction(Mode.CONTACT_LIST, KeyType.Enter, - Trans.StringId.KEY_ACTION_VIEW_CARD) { + StringId.KEY_ACTION_VIEW_CARD) { private Object obj = null; @Override diff --git a/src/be/nikiroo/jvcard/tui/panes/MainContentList.java b/src/be/nikiroo/jvcard/tui/panes/MainContentList.java index e4c40ba..9e5f8ec 100644 --- a/src/be/nikiroo/jvcard/tui/panes/MainContentList.java +++ b/src/be/nikiroo/jvcard/tui/panes/MainContentList.java @@ -5,8 +5,9 @@ import java.util.List; import be.nikiroo.jvcard.launcher.Main; import be.nikiroo.jvcard.resources.StringUtils; -import be.nikiroo.jvcard.resources.Trans.StringId; -import be.nikiroo.jvcard.tui.UiColors.Element; +import be.nikiroo.jvcard.resources.enums.ColorOption; +import be.nikiroo.jvcard.resources.enums.StringId; +import be.nikiroo.jvcard.tui.UiColors; import com.googlecode.lanterna.TextColor; import com.googlecode.lanterna.gui2.AbstractListBox.ListItemRenderer; @@ -27,9 +28,9 @@ abstract public class MainContentList extends MainContent implements Runnable { */ public class TextPart { private String text; - private Element element; + private ColorOption element; - public TextPart(String text, Element element) { + public TextPart(String text, ColorOption element) { this.text = text; this.element = element; } @@ -38,20 +39,20 @@ abstract public class MainContentList extends MainContent implements Runnable { return text; } - public Element getElement() { + public ColorOption getElement() { return element; } public TextColor getForegroundColor() { if (element != null) - return element.getForegroundColor(); - return Element.DEFAULT.getForegroundColor(); + return UiColors.getForegroundColor(element); + return UiColors.getForegroundColor(ColorOption.DEFAULT); } public TextColor getBackgroundColor() { if (element != null) - return element.getBackgroundColor(); - return Element.DEFAULT.getBackgroundColor(); + return UiColors.getBackgroundColor(element); + return UiColors.getBackgroundColor(ColorOption.DEFAULT); } } @@ -153,7 +154,7 @@ abstract public class MainContentList extends MainContent implements Runnable { addItem(run.toString()); } setSelectedIndex(index); - + return deleted; } @@ -230,10 +231,10 @@ abstract public class MainContentList extends MainContent implements Runnable { if (selected && focused) { parts.add(new TextPart("" + lines.getItems().get(index), - Element.CONTACT_LINE_SELECTED)); + ColorOption.CONTACT_LINE_SELECTED)); } else { parts.add(new TextPart("" + lines.getItems().get(index), - Element.CONTACT_LINE)); + ColorOption.CONTACT_LINE)); } return parts; -- 2.27.0