import java.util.List;
import java.util.ListIterator;
-import be.nikiroo.jvcard.tui.StringUtils;
+import be.nikiroo.jvcard.resources.StringUtils;
/**
* This class is basically a List with a parent and a "dirty" state check. It
import be.nikiroo.jvcard.parsers.Format;
import be.nikiroo.jvcard.parsers.Parser;
-import be.nikiroo.jvcard.tui.StringUtils;
+import be.nikiroo.jvcard.resources.StringUtils;
/**
* A contact is the information that represent a contact person or organisation.
--- /dev/null
+package be.nikiroo.jvcard.launcher;
+
+import java.io.File;
+import java.io.IOException;
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.net.Socket;
+import java.nio.charset.Charset;
+import java.util.LinkedList;
+import java.util.List;
+
+import be.nikiroo.jvcard.Card;
+import be.nikiroo.jvcard.parsers.Format;
+import be.nikiroo.jvcard.remote.Command.Verb;
+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;
+
+/**
+ * This class contains the runnable Main method. It will parse the user supplied
+ * parameters and take action based upon those. Most of the time, it will start
+ * a MainWindow.
+ *
+ * @author niki
+ *
+ */
+public class Main {
+ static public final String APPLICATION_TITLE = "jVcard";
+ static public final String APPLICATION_VERSION = "1.0-beta2-dev";
+
+ 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;
+
+ /**
+ * Translate the given {@link StringId}.
+ *
+ * @param id
+ * the ID to translate
+ *
+ * @return the translation
+ */
+ static public String trans(StringId id) {
+ return transService.trans(id);
+ }
+
+ /**
+ * Check if unicode characters should be used.
+ *
+ * @return TRUE to allow unicode
+ */
+ static public boolean isUnicode() {
+ return transService.isUnicode();
+ }
+
+ /**
+ * Start the application.
+ *
+ * <p>
+ * The returned exit codes are:
+ * <ul>
+ * <li>1: no files to open</li>
+ * <li>2: invalid syntax</li>
+ * <li>3: internal error</li>
+ * </ul>
+ * </p>
+ *
+ * @param args
+ * the parameters (see <tt>--help</tt> to know which are
+ * supported)
+ */
+ public static void main(String[] args) {
+ Boolean textMode = null;
+ boolean noMoreParams = false;
+ boolean filesTried = false;
+
+ // get the "system default" language to help translate the --help
+ // message if needed
+ String language = null;
+ transService = new Trans(language);
+
+ boolean unicode = transService.isUnicode();
+ String i18nDir = null;
+ List<String> files = new LinkedList<String>();
+ Integer port = null;
+ for (int index = 0; index < args.length; index++) {
+ String arg = args[index];
+ if (!noMoreParams && arg.equals("--")) {
+ noMoreParams = true;
+ } else if (!noMoreParams && arg.equals("--help")) {
+ System.out
+ .println("TODO: implement some help text.\n"
+ + "Usable switches:\n"
+ + "\t--: stop looking for switches\n"
+ + "\t--help: this here thingy\n"
+ + "\t--lang LANGUAGE: choose the language, for instance en_GB\n"
+ + "\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--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"
+ + "everyhing else is either a file to open or a directory to open\n"
+ + "(we will only open 1st level files in given directories)\n"
+ + "('jvcard://hostname:8888/file' links -- or without 'file' -- are also ok)\n");
+ return;
+ } else if (!noMoreParams && arg.equals("--tui")) {
+ textMode = true;
+ } else if (!noMoreParams && arg.equals("--gui")) {
+ textMode = false;
+ } else if (!noMoreParams && arg.equals("--noutf")) {
+ unicode = false;
+ transService.setUnicode(unicode);
+ } else if (!noMoreParams && arg.equals("--lang")) {
+ index++;
+ if (index >= args.length) {
+ System.err.println("Syntax error: no language given");
+ System.exit(ERR_SYNTAX);
+ return;
+ }
+
+ language = args[index];
+ transService = new Trans(language);
+ transService.setUnicode(unicode);
+ } else if (!noMoreParams && arg.equals("--config")) {
+ index++;
+ if (index >= args.length) {
+ System.err
+ .println("Syntax error: no config directory given");
+ System.exit(ERR_SYNTAX);
+ return;
+ }
+
+ Bundles.setDirectory(args[index]);
+ transService = new Trans(language);
+ transService.setUnicode(unicode);
+ } else if (!noMoreParams && arg.equals("--server")) {
+ index++;
+ if (index >= args.length) {
+ System.err.println("Syntax error: no port given");
+ System.exit(ERR_SYNTAX);
+ return;
+ }
+
+ try {
+ port = Integer.parseInt(args[index]);
+ } catch (NumberFormatException e) {
+ System.err.println("Invalid port number: " + args[index]);
+ System.exit(ERR_SYNTAX);
+ return;
+ }
+ } else if (!noMoreParams && arg.equals("--i18n")) {
+ index++;
+ if (index >= args.length) {
+ System.err
+ .println("Syntax error: no .properties directory given");
+ System.exit(ERR_SYNTAX);
+ return;
+ }
+
+ i18nDir = args[index];
+ } else {
+ filesTried = true;
+ files.addAll(open(arg));
+ }
+ }
+
+ if (unicode) {
+ utf8();
+ }
+
+ // Error management:
+ if (port != null && files.size() > 0) {
+ System.err
+ .println("Invalid syntax: you cannot both use --server and provide card files");
+ System.exit(ERR_SYNTAX);
+ } else if (i18nDir != null && files.size() > 0) {
+ System.err
+ .println("Invalid syntax: you cannot both use --i18n and provide card files");
+ System.exit(ERR_SYNTAX);
+ } else if (port != null && i18nDir != null) {
+ System.err
+ .println("Invalid syntax: you cannot both use --server and --i18n");
+ System.exit(ERR_SYNTAX);
+ } else if (i18nDir != null && language == null) {
+ System.err
+ .println("Invalid syntax: you cannot use --i18n without --lang");
+ System.exit(ERR_SYNTAX);
+ } else if (port == null && i18nDir == null && files.size() == 0) {
+ if (files.size() == 0 && !filesTried) {
+ files.addAll(open("."));
+ }
+
+ if (files.size() == 0) {
+ System.err.println("No files to open");
+ System.exit(ERR_NO_FILE);
+ return;
+ }
+ }
+ //
+
+ if (port != null) {
+ try {
+ runServer(port);
+ } catch (Exception e) {
+ if (e instanceof IOException) {
+ System.err
+ .println("I/O Exception: Cannot start the server");
+ } else {
+ System.err.println("FATAL ERROR");
+ e.printStackTrace();
+ System.exit(ERR_INTERNAL);
+ }
+ }
+ } else if (i18nDir != null) {
+ try {
+ Trans.generateTranslationFile(i18nDir, language);
+ } catch (IOException e) {
+ System.err
+ .println("I/O Exception: Cannot create/update a language in directory: "
+ + i18nDir);
+ }
+ } else {
+ try {
+ startTui(textMode, files);
+ } catch (Exception e) {
+ if (e instanceof IOException) {
+ System.err
+ .println("I/O Exception: Cannot start the program with the given cards");
+ } else {
+ System.err.println("FATAL ERROR");
+ e.printStackTrace();
+ System.exit(ERR_INTERNAL);
+ }
+ }
+ }
+ }
+
+ /**
+ * Return the {@link Card} corresponding to the given resource name -- a
+ * file or a remote jvcard URL
+ *
+ * @param input
+ * a filename or a remote jvcard url with named resource (e.g.:
+ * <tt>jvcard://localhost:4444/coworkers.vcf</tt>)
+ *
+ * @return the {@link Card}
+ *
+ * @throws IOException
+ * in case of IO error or remoting not available
+ */
+ static public Card getCard(String input) throws IOException {
+ boolean remote = false;
+ Format format = Format.Abook;
+ String ext = input;
+ if (ext.contains(".")) {
+ String tab[] = ext.split("\\.");
+ if (tab.length > 1 && tab[tab.length - 1].equalsIgnoreCase("vcf")) {
+ format = Format.VCard21;
+ }
+ }
+
+ if (input.contains("://")) {
+ format = Format.VCard21;
+ remote = true;
+ }
+
+ Card card = null;
+ try {
+ if (remote) {
+ card = syncCard(input);
+ } else {
+ card = new Card(new File(input), format);
+ }
+ } catch (IOException ioe) {
+ throw ioe;
+ } catch (Exception e) {
+ throw new IOException("Remoting not available", e);
+ }
+
+ return card;
+ }
+
+ /**
+ * Create a new jVCard server on the given port, then run it.
+ *
+ * @param port
+ * the port to run on
+ *
+ * @throws SecurityException
+ * in case of internal error
+ * @throws NoSuchMethodException
+ * in case of internal error
+ * @throws ClassNotFoundException
+ * in case of internal error
+ * @throws IllegalAccessException
+ * in case of internal error
+ * @throws InstantiationException
+ * in case of internal error
+ * @throws InvocationTargetException
+ * in case of internal error
+ * @throws IllegalArgumentException
+ * in case of internal error
+ * @throws IOException
+ * in case of IO error
+ */
+ @SuppressWarnings("unchecked")
+ static private void runServer(int port) throws NoSuchMethodException,
+ SecurityException, ClassNotFoundException, InstantiationException,
+ IllegalAccessException, IllegalArgumentException,
+ InvocationTargetException {
+ @SuppressWarnings("rawtypes")
+ Class serverClass = Class.forName("be.nikiroo.jvcard.remote.Server");
+ Method run = serverClass.getDeclaredMethod("run", new Class[] {});
+ run.invoke(serverClass.getConstructor(int.class).newInstance(port));
+ }
+
+ /**
+ * Start the TUI program.
+ *
+ * @param textMode
+ * TRUE to force text mode, FALSE to force the Swing terminal
+ * emulator, null to automatically determine the best choice
+ * @param files
+ * the files to show at startup
+ *
+ * @throws SecurityException
+ * in case of internal error
+ * @throws NoSuchMethodException
+ * in case of internal error
+ * @throws ClassNotFoundException
+ * in case of internal error
+ * @throws IllegalAccessException
+ * in case of internal error
+ * @throws InstantiationException
+ * in case of internal error
+ * @throws InvocationTargetException
+ * in case of internal error
+ * @throws IllegalArgumentException
+ * in case of internal error
+ * @throws IOException
+ * in case of IO error
+ */
+ @SuppressWarnings("unchecked")
+ static private void startTui(Boolean textMode, List<String> files)
+ throws NoSuchMethodException, SecurityException,
+ ClassNotFoundException, InstantiationException,
+ IllegalAccessException, IllegalArgumentException,
+ InvocationTargetException {
+ @SuppressWarnings("rawtypes")
+ Class launcherClass = Class
+ .forName("be.nikiroo.jvcard.tui.TuiLauncher");
+ Method start = launcherClass.getDeclaredMethod("start", new Class[] {
+ Boolean.class, List.class });
+ start.invoke(launcherClass.newInstance(), textMode, files);
+ }
+
+ /**
+ * Return the {@link Card} corresponding to the given URL, synchronised if
+ * necessary.
+ *
+ * @param input
+ * the jvcard:// with resource name URL (e.g.:
+ * <tt>jvcard://localhost:4444/coworkers</tt>)
+ *
+ * @throws SecurityException
+ * in case of internal error
+ * @throws NoSuchMethodException
+ * in case of internal error
+ * @throws ClassNotFoundException
+ * in case of internal error
+ * @throws IllegalAccessException
+ * in case of internal error
+ * @throws InstantiationException
+ * in case of internal error
+ * @throws InvocationTargetException
+ * in case of internal error
+ * @throws IllegalArgumentException
+ * in case of internal error
+ * @throws IOException
+ * in case of IO error
+ */
+ @SuppressWarnings("unchecked")
+ static private Card syncCard(String input) throws ClassNotFoundException,
+ NoSuchMethodException, SecurityException, InstantiationException,
+ IllegalAccessException, IllegalArgumentException,
+ InvocationTargetException, IOException {
+ @SuppressWarnings("rawtypes")
+ Class syncClass = Class.forName("be.nikiroo.jvcard.remote.Sync");
+ Method getCache = syncClass.getDeclaredMethod("getCache",
+ new Class[] {});
+ Method sync = syncClass.getDeclaredMethod("sync", new Class[] {
+ Card.class, boolean.class });
+
+ Object o = syncClass.getConstructor(String.class).newInstance(input);
+
+ File file = (File) getCache.invoke(o);
+ Card card = new Card(file, Format.VCard21);
+ card.setRemote(true);
+ sync.invoke(o, card, false);
+
+ return card;
+ }
+
+ /**
+ * Open the given path and add all its files if it is a directory or just
+ * this one if not to the returned list.
+ *
+ * @param path
+ * the path to open
+ *
+ * @return the list of opened files
+ */
+ static private List<String> open(String path) {
+ List<String> files = new LinkedList<String>();
+
+ if (path != null && path.startsWith("jvcard://")) {
+ if (path.endsWith("/")) {
+ files.addAll(list(path));
+ } else {
+ files.add(path);
+ }
+ } else {
+ File file = new File(path);
+ if (file.exists()) {
+ if (file.isDirectory()) {
+ for (File subfile : file.listFiles()) {
+ if (!subfile.isDirectory())
+ files.add(subfile.getAbsolutePath());
+ }
+ } else {
+ files.add(file.getAbsolutePath());
+ }
+ } else {
+ System.err.println("File or directory not found: \"" + path
+ + "\"");
+ }
+ }
+
+ return files;
+ }
+
+ /**
+ * List all the available {@link Card}s on the given network location (which
+ * is expected to be a jVCard remote server, obviously).
+ *
+ * @param path
+ * the jVCard remote server path (e.g.:
+ * <tt>jvcard://localhost:4444/</tt>)
+ *
+ * @return the list of {@link Card}s
+ */
+ static private List<String> list(String path) {
+ List<String> files = new LinkedList<String>();
+
+ try {
+ String host = path.split("\\:")[1].substring(2);
+ int port = Integer.parseInt(path.split("\\:")[2].replaceAll("/$",
+ ""));
+ SimpleSocket s = new SimpleSocket(new Socket(host, port),
+ "sync client");
+ s.open(true);
+
+ s.sendCommand(Verb.LIST);
+ for (String p : s.receiveBlock()) {
+ files.add(path
+ + p.substring(StringUtils.fromTime(0).length() + 1));
+ }
+ s.close();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ return files;
+ }
+
+ /**
+ * Really, really ask for UTF-8 encoding.
+ */
+ static private void utf8() {
+ try {
+ System.setProperty("file.encoding", "UTF-8");
+ Field charset = Charset.class.getDeclaredField("defaultCharset");
+ charset.setAccessible(true);
+ charset.set(null, null);
+ } catch (SecurityException e) {
+ } catch (NoSuchFieldException e) {
+ } catch (IllegalArgumentException e) {
+ } catch (IllegalAccessException e) {
+ }
+ }
+}
import be.nikiroo.jvcard.parsers.Vcard21Parser;
import be.nikiroo.jvcard.remote.Command.Verb;
import be.nikiroo.jvcard.resources.Bundles;
-import be.nikiroo.jvcard.tui.StringUtils;
+import be.nikiroo.jvcard.resources.StringUtils;
/**
* This class implements a small server that can listen for requests to
private Object updateLock = new Object();
- public static void main(String[] args) throws IOException {
- Server server = new Server(4444);
- server.run();
- }
-
/**
- * Create a new jVCard sercer on the given port.
+ * Create a new jVCard server on the given port.
*
* @param port
* the port to run on
import be.nikiroo.jvcard.parsers.Vcard21Parser;
import be.nikiroo.jvcard.remote.Command.Verb;
import be.nikiroo.jvcard.resources.Bundles;
-import be.nikiroo.jvcard.tui.StringUtils;
+import be.nikiroo.jvcard.resources.StringUtils;
/**
* This class will synchronise {@link Card}s between a local instance an a
}
// return: synced or not
+ //TODO jDoc
public boolean sync(Card card, boolean force) throws UnknownHostException,
IOException {
--- /dev/null
+/**
+ * TODO: describe protocol here.
+ *
+ * @author niki
+ */
+package be.nikiroo.jvcard.remote;
\ No newline at end of file
public class Bundles {
static private String confDir = getConfDir();
- // TODO: rename to bundle, use it as base for i18n.Trans, create one for
- // each resource
+ // 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;
/**
-package be.nikiroo.jvcard.i18n;
+package be.nikiroo.jvcard.resources;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
-package be.nikiroo.jvcard.tui;
+package be.nikiroo.jvcard.resources;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
-package be.nikiroo.jvcard.i18n;
+package be.nikiroo.jvcard.resources;
import java.io.BufferedWriter;
import java.io.File;
import java.util.Locale;
import java.util.ResourceBundle;
-import be.nikiroo.jvcard.resources.Bundles;
-import be.nikiroo.jvcard.tui.UiColors;
-
-import com.googlecode.lanterna.input.KeyStroke;
-
/**
* This class manages the translation of {@link Trans.StringId}s into
* user-understandable text.
*/
public class Trans {
private ResourceBundle map;
+ private boolean utf = true;
/**
* Create a translation service with the default language.
*/
public String trans(StringId stringId) {
StringId id = stringId;
- if (!UiColors.getInstance().isUnicode()) {
+ if (!isUnicode()) {
try {
id = StringId.valueOf(stringId.name() + "_NOUTF");
} catch (IllegalArgumentException iae) {
}
/**
- * Translate the given {@link KeyStroke} into a user text {@link String} of
- * size 3.
+ * Check if unicode characters should be used.
*
- * @param key
- * the key to translate
- *
- * @return the translated text
+ * @return TRUE to allow unicode
*/
- public String trans(KeyStroke key) {
- String keyTrans = "";
-
- switch (key.getKeyType()) {
- case Enter:
- if (UiColors.getInstance().isUnicode())
- keyTrans = " ⤶ ";
- else
- keyTrans = trans(StringId.KEY_ENTER);
- break;
- case Tab:
- if (UiColors.getInstance().isUnicode())
- keyTrans = " ↹ ";
- else
- keyTrans = trans(StringId.KEY_TAB);
-
- break;
- case Character:
- keyTrans = " " + key.getCharacter() + " ";
- break;
- default:
- keyTrans = "" + key.getKeyType();
- int width = 3;
- if (keyTrans.length() > width) {
- keyTrans = keyTrans.substring(0, width);
- } else if (keyTrans.length() < width) {
- keyTrans = keyTrans
- + new String(new char[width - keyTrans.length()])
- .replace('\0', ' ');
- }
- break;
- }
+ public boolean isUnicode() {
+ return utf;
+ }
- return keyTrans;
+ /**
+ * 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;
}
/**
* candidate as base if the file does not already exists (for instance,
* "en_US" will use "en" as a base).
*
- * @param args
- * the path where the .properties files are, then the languages
- * to create/update
+ * @param path
+ * the path where the .properties files are
+ *
+ * @param language
+ * the language code to create/update (e.g.: <tt>fr-BE</tt>)
*
* @throws IOException
* in case of IO errors
*/
- static public void main(String[] args) throws IOException {
- String path = args[0];
- for (int i = 1; i < args.length; i++) {
- Locale locale = getLocaleFor(args[i]);
- 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");
- }
+ static public void generateTranslationFile(String path, String language)
+ throws IOException {
- BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(
- new FileOutputStream(file), "UTF-8"));
+ Locale locale = getLocaleFor(language);
+ String code = locale.toString();
+ Trans trans = new Trans(code);
- String name = locale.getDisplayCountry(locale);
- if (name.length() == 0)
- name = locale.getDisplayLanguage(locale);
- if (name.length() == 0)
- name = "default";
+ File file = null;
+ if (code.length() > 0) {
+ file = new File(path + "resources_" + code + ".properties");
+ } else {
+ // Default properties file:
+ file = new File(path + "resources.properties");
+ }
- if (code.length() > 0) {
- name = name + " (" + code + ")";
- }
+ BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(
+ new FileOutputStream(file), "UTF-8"));
- 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));
+ 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.close();
+ writer.append(id.name());
+ writer.append(" = ");
+ if (!trans.trans(id).equals(id.name()))
+ writer.append(trans.trans(id));
+ writer.append("\n");
+ }
}
+
+ writer.close();
}
/**
import java.awt.Image;
+import be.nikiroo.jvcard.launcher.Main;
import be.nikiroo.jvcard.tui.ImageText.Mode;
import com.googlecode.lanterna.TerminalSize;
*/
public ImageTextControl(Image image, TerminalSize size) {
Mode mode = Mode.DOUBLE_DITHERING;
- if (!UiColors.getInstance().isUnicode()) {
+ if (!Main.isUnicode()) {
mode = Mode.ASCII;
}
* @return TRUE if it was possible to switch modes
*/
public boolean switchMode() {
- if (image == null || !UiColors.getInstance().isUnicode())
+ if (image == null || !Main.isUnicode())
return false;
Mode[] modes = Mode.values();
import be.nikiroo.jvcard.Card;
import be.nikiroo.jvcard.Contact;
import be.nikiroo.jvcard.Data;
-import be.nikiroo.jvcard.i18n.Trans.StringId;
+import be.nikiroo.jvcard.launcher.Main;
+import be.nikiroo.jvcard.resources.Trans.StringId;
import com.googlecode.lanterna.input.KeyStroke;
import com.googlecode.lanterna.input.KeyType;
public String getDefaultAnswer() {
return null;
}
+
+ /**
+ * Translate the given {@link KeyStroke} into a user text {@link String} of
+ * size 3.
+ *
+ * @param key
+ * the key to translate
+ *
+ * @return the translated text
+ */
+ static public String trans(KeyStroke key) {
+ String keyTrans = "";
+
+ switch (key.getKeyType()) {
+ case Enter:
+ if (Main.isUnicode())
+ keyTrans = " ⤶ ";
+ else
+ keyTrans = Main.trans(StringId.KEY_ENTER);
+ break;
+ case Tab:
+ if (Main.isUnicode())
+ keyTrans = " ↹ ";
+ else
+ keyTrans = Main.trans(StringId.KEY_TAB);
+
+ break;
+ case Character:
+ keyTrans = " " + key.getCharacter() + " ";
+ break;
+ default:
+ keyTrans = "" + key.getKeyType();
+ int width = 3;
+ if (keyTrans.length() > width) {
+ keyTrans = keyTrans.substring(0, width);
+ } else if (keyTrans.length() < width) {
+ keyTrans = keyTrans
+ + new String(new char[width - keyTrans.length()])
+ .replace('\0', ' ');
+ }
+ break;
+ }
+
+ return keyTrans;
+ }
}
+++ /dev/null
-package be.nikiroo.jvcard.tui;
-
-import java.io.File;
-import java.io.IOException;
-import java.lang.reflect.Field;
-import java.net.Socket;
-import java.nio.charset.Charset;
-import java.util.LinkedList;
-import java.util.List;
-
-import be.nikiroo.jvcard.Card;
-import be.nikiroo.jvcard.i18n.Trans;
-import be.nikiroo.jvcard.i18n.Trans.StringId;
-import be.nikiroo.jvcard.remote.Command.Verb;
-import be.nikiroo.jvcard.remote.SimpleSocket;
-import be.nikiroo.jvcard.resources.Bundles;
-import be.nikiroo.jvcard.tui.panes.FileList;
-
-import com.googlecode.lanterna.gui2.Window;
-import com.googlecode.lanterna.input.KeyStroke;
-
-/**
- * This class contains the runnable Main method. It will parse the user supplied
- * parameters and take action based upon those. Most of the time, it will start
- * a MainWindow.
- *
- * @author niki
- *
- */
-public class Main {
- // TODO: move Main to be.nikiroo.jvcard, use introspection to load the other
- // main classes, allow the 3 programs to run from this new Main
- // also requires StringUtils/... in a new package
- private int TODO;
-
- public static final String APPLICATION_TITLE = "jVcard";
- public static final String APPLICATION_VERSION = "1.0-beta2-dev";
-
- static private Trans transService;
-
- /**
- * Translate the given {@link StringId}.
- *
- * @param id
- * the ID to translate
- *
- * @return the translation
- */
- static public String trans(StringId id) {
- if (transService == null)
- return "";
-
- return transService.trans(id);
- }
-
- /**
- * Translate the given {@link KeyStroke}.
- *
- * @param key
- * the key to translate
- *
- * @return the translation
- */
- static public String trans(KeyStroke key) {
- if (transService == null)
- return "";
-
- return transService.trans(key);
- }
-
- /**
- * Start the application.
- *
- * @param args
- * the parameters (see <tt>--help</tt> to know which are
- * supported)
- */
- public static void main(String[] args) {
- Boolean textMode = null;
- boolean noMoreParams = false;
- boolean filesTried = false;
-
- // get the "system default" language to help translate the --help
- // message if needed
- String language = null;
- transService = new Trans(language);
-
- List<String> files = new LinkedList<String>();
- for (int index = 0; index < args.length; index++) {
- String arg = args[index];
- if (!noMoreParams && arg.equals("--")) {
- noMoreParams = true;
- } else if (!noMoreParams && arg.equals("--help")) {
- System.out
- .println("TODO: implement some help text.\n"
- + "Usable switches:\n"
- + "\t--: stop looking for switches\n"
- + "\t--help: this here thingy\n"
- + "\t--lang LANGUAGE: choose the language, for instance en_GB\n"
- + "\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"
- + "everyhing else is either a file to open or a directory to open\n"
- + "(we will only open 1st level files in given directories)\n"
- + "('jvcard://hostname:8888/file' links -- or without 'file' -- are also ok)\n");
- return;
- } else if (!noMoreParams && arg.equals("--tui")) {
- textMode = true;
- } else if (!noMoreParams && arg.equals("--gui")) {
- textMode = false;
- } else if (!noMoreParams && arg.equals("--noutf")) {
- UiColors.getInstance().setUnicode(false);
- } else if (!noMoreParams && arg.equals("--lang")) {
- index++;
- if (index < args.length)
- language = args[index];
- transService = new Trans(language);
- } else if (!noMoreParams && arg.equals("--config")) {
- index++;
- if (index < args.length) {
- Bundles.setDirectory(args[index]);
- transService = new Trans(language);
- }
- } else {
- filesTried = true;
- files.addAll(open(arg));
- }
- }
-
- if (UiColors.getInstance().isUnicode()) {
- utf8();
- }
-
- if (files.size() == 0) {
- if (filesTried) {
- System.exit(1);
- return;
- }
-
- files.addAll(open("."));
- }
-
- // TODO error case when no file
-
- Window win = new MainWindow(new FileList(files));
-
- try {
- TuiLauncher.start(textMode, win);
- } catch (IOException ioe) {
- ioe.printStackTrace();
- System.exit(2);
- }
- }
-
- /**
- * Open the given path and add all its files if it is a directory or just
- * this one if not to the returned list.
- *
- * @param path
- * the path to open
- *
- * @return the list of opened files
- */
- static private List<String> open(String path) {
- List<String> files = new LinkedList<String>();
-
- if (path != null && path.startsWith("jvcard://")) {
- if (path.endsWith("/")) {
- files.addAll(list(path));
- } else {
- files.add(path);
- }
- } else {
- File file = new File(path);
- if (file.exists()) {
- if (file.isDirectory()) {
- for (File subfile : file.listFiles()) {
- if (!subfile.isDirectory())
- files.add(subfile.getAbsolutePath());
- }
- } else {
- files.add(file.getAbsolutePath());
- }
- } else {
- System.err.println("File or directory not found: \"" + path
- + "\"");
- }
- }
-
- return files;
- }
-
- /**
- * List all the available {@link Card}s on the given network location (which
- * is expected to be a jVCard remote server, obviously).
- *
- * @param path
- * the jVCard remote server path (e.g.:
- * <tt>jvcard://localhost:4444/</tt>)
- *
- * @return the list of {@link Card}s
- */
- static private List<String> list(String path) {
- List<String> files = new LinkedList<String>();
-
- try {
- String host = path.split("\\:")[1].substring(2);
- int port = Integer.parseInt(path.split("\\:")[2].replaceAll("/$",
- ""));
- SimpleSocket s = new SimpleSocket(new Socket(host, port),
- "sync client");
- s.open(true);
-
- s.sendCommand(Verb.LIST);
- for (String p : s.receiveBlock()) {
- files.add(path
- + p.substring(StringUtils.fromTime(0).length() + 1));
- }
- s.close();
- } catch (Exception e) {
- e.printStackTrace();
- }
-
- return files;
- }
-
- /**
- * Really, really ask for UTF-8 encoding.
- */
- static private void utf8() {
- try {
- System.setProperty("file.encoding", "UTF-8");
- Field charset = Charset.class.getDeclaredField("defaultCharset");
- charset.setAccessible(true);
- charset.set(null, null);
- } catch (SecurityException e) {
- } catch (NoSuchFieldException e) {
- } catch (IllegalArgumentException e) {
- } catch (IllegalAccessException e) {
- }
- }
-}
import java.util.LinkedList;
import java.util.List;
-import be.nikiroo.jvcard.i18n.Trans.StringId;
+import be.nikiroo.jvcard.launcher.Main;
+import be.nikiroo.jvcard.resources.StringUtils;
+import be.nikiroo.jvcard.resources.Trans.StringId;
import be.nikiroo.jvcard.tui.KeyAction.Mode;
import be.nikiroo.jvcard.tui.UiColors.Element;
import be.nikiroo.jvcard.tui.panes.ContactDetails;
if (title.length() > 0) {
prefix = prefix + ": ";
- title = StringUtils.sanitize(title, UiColors.getInstance()
- .isUnicode());
+ title = StringUtils.sanitize(title, Main.isUnicode());
}
String countStr = "";
if (" ".equals(trans))
continue;
- String keyTrans = Main.trans(action.getKey());
+ String keyTrans = KeyAction.trans(action.getKey());
Panel kPane = new Panel();
LinearLayout layout = new LinearLayout(Direction.HORIZONTAL);
package be.nikiroo.jvcard.tui;
import java.io.IOException;
+import java.util.List;
+
+import be.nikiroo.jvcard.tui.panes.FileList;
import com.googlecode.lanterna.TerminalSize;
import com.googlecode.lanterna.TextColor;
*
*/
public class TuiLauncher {
+ /**
+ * Start the TUI program.
+ *
+ * @param textMode
+ * TRUE to force text mode, FALSE to force the Swing terminal
+ * emulator, null to automatically determine the best choice
+ * @param files
+ * the files to show at startup
+ *
+ * @throws IOException
+ * in case of IO error
+ */
+ static public void start(Boolean textMode, List<String> files)
+ throws IOException {
+ Window win = new MainWindow(new FileList(files));
+ TuiLauncher.start(textMode, win);
+ }
+ /**
+ * Start the TUI program.
+ *
+ * @param textMode
+ * TRUE to force text mode, FALSE to force the Swing terminal
+ * emulator, null to automatically determine the best choice
+ * @param win
+ * the window to show at start
+ *
+ * @throws IOException
+ * in case of IO error
+ */
static public void start(Boolean textMode, Window win) throws IOException {
Terminal terminal = null;
private ResourceBundle bundle = null;
private Map<String, TextColor> colorMap = null;
- private boolean utf = true;
private UiColors() {
colorMap = new HashMap<String, TextColor>();
}
}
- /**
- * 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;
- }
-
/**
* Create a new {@link Label} with the colours of the given {@link Element}.
*
import be.nikiroo.jvcard.Contact;
import be.nikiroo.jvcard.Data;
import be.nikiroo.jvcard.TypeInfo;
-import be.nikiroo.jvcard.i18n.Trans;
+import be.nikiroo.jvcard.resources.Trans;
import be.nikiroo.jvcard.tui.ImageTextControl;
import be.nikiroo.jvcard.tui.KeyAction;
import be.nikiroo.jvcard.tui.KeyAction.DataType;
import be.nikiroo.jvcard.Contact;
import be.nikiroo.jvcard.Data;
import be.nikiroo.jvcard.TypeInfo;
-import be.nikiroo.jvcard.i18n.Trans;
+import be.nikiroo.jvcard.launcher.Main;
+import be.nikiroo.jvcard.resources.StringUtils;
+import be.nikiroo.jvcard.resources.Trans;
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.StringUtils;
-import be.nikiroo.jvcard.tui.UiColors;
import be.nikiroo.jvcard.tui.UiColors.Element;
import com.googlecode.lanterna.input.KeyType;
value = valueBuilder.toString();
- name = StringUtils.sanitize(name, UiColors.getInstance().isUnicode());
- value = StringUtils.sanitize(value, UiColors.getInstance().isUnicode());
+ name = StringUtils.sanitize(name, Main.isUnicode());
+ value = StringUtils.sanitize(value, Main.isUnicode());
name = StringUtils.padString(name, SIZE_COL_1);
group = StringUtils.padString(group, SIZE_COL_2_OPT);
import be.nikiroo.jvcard.Card;
import be.nikiroo.jvcard.Contact;
import be.nikiroo.jvcard.Data;
-import be.nikiroo.jvcard.i18n.Trans;
+import be.nikiroo.jvcard.launcher.Main;
import be.nikiroo.jvcard.resources.Bundles;
+import be.nikiroo.jvcard.resources.Trans;
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;
import be.nikiroo.jvcard.tui.UiColors.Element;
import com.googlecode.lanterna.input.KeyType;
width -= 2; // dirty mark space
String[] array = contact.toStringArray(format, getSeparator(), " ",
- width, UiColors.getInstance().isUnicode());
+ width, Main.isUnicode());
if (contact.isDirty()) {
parts.add(new TextPart(" ", el));
package be.nikiroo.jvcard.tui.panes;
-import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import be.nikiroo.jvcard.Card;
-import be.nikiroo.jvcard.i18n.Trans;
-import be.nikiroo.jvcard.parsers.Format;
-import be.nikiroo.jvcard.remote.Sync;
+import be.nikiroo.jvcard.launcher.Main;
+import be.nikiroo.jvcard.resources.StringUtils;
+import be.nikiroo.jvcard.resources.Trans;
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.StringUtils;
-import be.nikiroo.jvcard.tui.UiColors;
import be.nikiroo.jvcard.tui.UiColors.Element;
import com.googlecode.lanterna.input.KeyType;
name = name.substring(indexSl + 1);
}
- name = StringUtils.sanitize(name, UiColors.getInstance().isUnicode());
+ name = StringUtils.sanitize(name, Main.isUnicode());
count = " " + StringUtils.padString(count, SIZE_COL_1) + " ";
name = " "
String file = files.get(index);
try {
- Card card = FileList.getCard(file);
+ Card card = Main.getCard(file);
cards.set(index, card);
invalidate();
return actions;
}
-
- static private Card getCard(String input) throws IOException {
- boolean remote = false;
- Format format = Format.Abook;
- String ext = input;
- if (ext.contains(".")) {
- String tab[] = ext.split("\\.");
- if (tab.length > 1 && tab[tab.length - 1].equalsIgnoreCase("vcf")) {
- format = Format.VCard21;
- }
- }
-
- if (input.contains("://")) {
- format = Format.VCard21;
- remote = true;
- }
-
- Card card = null;
- try {
- if (remote) {
- Sync sync = new Sync(input);
- card = new Card(sync.getCache(), format);
- card.setRemote(true);
- sync.sync(card, false);
- } else {
- card = new Card(new File(input), format);
- }
- } catch (IOException ioe) {
- ioe.printStackTrace();
- throw ioe;
- }
-
- return card;
- }
}
import java.util.LinkedList;
import java.util.List;
-import be.nikiroo.jvcard.i18n.Trans.StringId;
-import be.nikiroo.jvcard.tui.Main;
-import be.nikiroo.jvcard.tui.StringUtils;
-import be.nikiroo.jvcard.tui.UiColors;
+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 com.googlecode.lanterna.TextColor;
graphics.setBackgroundColor(part.getBackgroundColor());
String label = StringUtils.sanitize(part.getText(),
- UiColors.getInstance().isUnicode());
+ Main.isUnicode());
graphics.putString(position, 0, label);
position += label.length();