From b9f192ed5290f3263f60dc5a2dc9fd754eead958 Mon Sep 17 00:00:00 2001 From: Niki Roo Date: Fri, 11 Mar 2016 09:32:10 +0100 Subject: [PATCH] Some fixes (crash when adding raw "x=" field, "dirty" handling) --- src/be/nikiroo/jvcard/BaseClass.java | 17 +- src/be/nikiroo/jvcard/Card.java | 151 +++++++++++++++--- src/be/nikiroo/jvcard/parsers/Format.java | 2 +- src/be/nikiroo/jvcard/parsers/Parser.java | 7 +- src/be/nikiroo/jvcard/tui/StringUtils.java | 35 ++++ .../jvcard/tui/panes/ContactDetailsRaw.java | 20 ++- 6 files changed, 197 insertions(+), 35 deletions(-) diff --git a/src/be/nikiroo/jvcard/BaseClass.java b/src/be/nikiroo/jvcard/BaseClass.java index b96edea..cb07948 100644 --- a/src/be/nikiroo/jvcard/BaseClass.java +++ b/src/be/nikiroo/jvcard/BaseClass.java @@ -29,18 +29,22 @@ public abstract class BaseClass> implements List { private List list; /** - * Create a new {@link BaseClass} with the given list as its descendants. + * Create a new {@link BaseClass} with the items in the given list as its + * descendants. + * + * Note: the elements will be copied from the {@link List}, you cannot + * manage the {@link List} from outside * * @param list * the descendants of this object, or NULL if none */ protected BaseClass(List list) { this.list = new ArrayList(); - + if (list != null) { this.list.addAll(list); } - + for (E child : this) { _enter(child, true); } @@ -102,6 +106,9 @@ public abstract class BaseClass> implements List { */ void setDirty() { dirty = true; + if (parent != null) { + parent.setDirty(); + } } /** @@ -156,8 +163,10 @@ public abstract class BaseClass> implements List { */ private void _enter(E child, boolean initialLoad) { child.setParent(this); - if (!initialLoad) + if (!initialLoad) { + setDirty(); child.setDirty(); + } } @Override diff --git a/src/be/nikiroo/jvcard/Card.java b/src/be/nikiroo/jvcard/Card.java index 2622266..e714b56 100644 --- a/src/be/nikiroo/jvcard/Card.java +++ b/src/be/nikiroo/jvcard/Card.java @@ -25,36 +25,73 @@ public class Card extends BaseClass { private File file; private String name; private Format format; + private long lastModified; + private boolean remote; /** * Create a new {@link Card} from the given {@link File} and {@link Format}. * * @param file - * the file containing the {@link Card} data, must not be NULL + * the input {@link File} containing the {@link Card} data or + * NULL for an empty card (usually a {@link File} name or a + * network path) * @param format * the {@link Format} to use to parse it * * @throws IOException * in case of IO error - * @throws NullPointerException - * if file is NULL * @throws InvalidParameterException * if format is NULL */ public Card(File file, Format format) throws IOException { - super(load(file, format)); + this(load(file, format)); + + if (file != null) { + if (file.exists()) { + lastModified = file.lastModified(); + } + } - this.file = file; this.format = format; - this.name = file.getName(); + + if (file != null) { + this.file = file; + switch (format) { + case VCard21: + this.name = file.getName().replaceAll( + ".[vV][cC][fF]$", ""); + break; + case Abook: + default: + this.name = file.getName(); + break; + } + } + } + + /** + * Create a new {@link Card} from the given {@link Contact}s. + * + * @param contacts + * the input contacts + * + * @throws IOException + * in case of IO error + * @throws InvalidParameterException + * if format is NULL + */ + public Card(List contacts) throws IOException { + super(contacts); + + lastModified = -1; } /** * Save the {@link Card} to the given {@link File} with the given * {@link Format}. * - * @param file - * the {@link File} to save to + * @param output + * the output to save to * @param format * the {@link Format} to use * @@ -63,15 +100,15 @@ public class Card extends BaseClass { * @throws IOException * in case of IO errors */ - public boolean saveAs(File file, Format format) throws IOException { - if (file == null) + public boolean saveAs(File output, Format format) throws IOException { + if (output == null) return false; - BufferedWriter writer = new BufferedWriter(new FileWriter(file)); + BufferedWriter writer = new BufferedWriter(new FileWriter(output)); writer.append(toString(format)); writer.close(); - if (file.equals(this.file)) { + if (output.getCanonicalPath().equals(this.file.getCanonicalPath())) { setPristine(); } @@ -90,6 +127,23 @@ public class Card extends BaseClass { return saveAs(file, format); } + /** + * Reload the data from the input. + * + * @return TRUE if it was done + * + * @throws IOException + * in case of IO error + */ + public boolean reload() throws IOException { + if (file == null) + return false; + + this.replaceListContent(load(file, format)); + setPristine(); + return true; + } + /** * Return a {@link String} representation of this {@link Card} in the given * {@link Format}. @@ -113,6 +167,53 @@ public class Card extends BaseClass { return name; } + /** + * Return the original {@link Format} of the {@link Card}. + * + * @return the {@link Format} + */ + public Format getFormat() { + return format; + } + + /** + * Return the input which was used to open this {@link Card}. + * + * @return the input + */ + public File getInput() { + return file; + } + + /** + * Return the date of the last modification for this {@link Card} (or -1 if + * unknown/new). + * + * @return the last modified date + */ + public long getLastModified() { + return lastModified; + } + + /** + * Check if this {@link Card} is remote. + * + * @return TRUE if this {@link Card} is remote + */ + public boolean isRemote() { + return remote; + } + + /** + * Set the remote option on this {@link Card}. + * + * @param remote + * TRUE if this {@link Card} is remote + */ + public void setRemote(boolean remote) { + this.remote = remote; + } + @Override public String toString() { return toString(Format.VCard21); @@ -122,24 +223,32 @@ public class Card extends BaseClass { * Load the data from the given {@link File} under the given {@link Format}. * * @param file - * the {@link File} to load from + * the input to load from * @param format * the {@link Format} to load as * * @return the list of elements + * * @throws IOException * in case of IO error */ - static private List load(File file, Format format) + private static List load(File file, Format format) throws IOException { - BufferedReader buffer = new BufferedReader(new InputStreamReader( - new FileInputStream(file), "UTF-8")); - List lines = new LinkedList(); - for (String line = buffer.readLine(); line != null; line = buffer - .readLine()) { - lines.add(line); + List lines = null; + + if (file != null && file.exists()) { + BufferedReader buffer = new BufferedReader(new InputStreamReader( + new FileInputStream(file), "UTF-8")); + lines = new LinkedList(); + for (String line = buffer.readLine(); line != null; line = buffer + .readLine()) { + lines.add(line); + } + buffer.close(); } - buffer.close(); + + if (lines == null) + return new LinkedList(); return Parser.parse(lines, format); } diff --git a/src/be/nikiroo/jvcard/parsers/Format.java b/src/be/nikiroo/jvcard/parsers/Format.java index 501d2ca..5f15dec 100644 --- a/src/be/nikiroo/jvcard/parsers/Format.java +++ b/src/be/nikiroo/jvcard/parsers/Format.java @@ -14,5 +14,5 @@ public enum Format { /** * (Al)Pine Contact Book format, also called abook (usually .addressbook). */ - Abook + Abook, } diff --git a/src/be/nikiroo/jvcard/parsers/Parser.java b/src/be/nikiroo/jvcard/parsers/Parser.java index cec4c1a..5ecad4a 100644 --- a/src/be/nikiroo/jvcard/parsers/Parser.java +++ b/src/be/nikiroo/jvcard/parsers/Parser.java @@ -37,7 +37,8 @@ public class Parser { } // -1 = no bkeys - public static String toString(Contact contact, Format format, int startingBKey) { + public static String toString(Contact contact, Format format, + int startingBKey) { switch (format) { case VCard21: return Vcard21Parser.toString(contact, startingBKey); @@ -54,8 +55,8 @@ public class Parser { public static int getBKey(Data data) { if (data.isBinary() && data.getValue().startsWith("", "")); + int bkey = Integer.parseInt(data.getValue() + .replace("", "")); if (bkey < 0) throw new InvalidParameterException( "All bkeys MUST be positive"); diff --git a/src/be/nikiroo/jvcard/tui/StringUtils.java b/src/be/nikiroo/jvcard/tui/StringUtils.java index 3829226..569b06c 100644 --- a/src/be/nikiroo/jvcard/tui/StringUtils.java +++ b/src/be/nikiroo/jvcard/tui/StringUtils.java @@ -2,6 +2,9 @@ package be.nikiroo.jvcard.tui; import java.text.Normalizer; import java.text.Normalizer.Form; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Date; import java.util.regex.Pattern; import com.googlecode.lanterna.gui2.LinearLayout.Alignment; @@ -135,4 +138,36 @@ public class StringUtils { return input; } + + /** + * Convert between time in milliseconds to {@link String} in a "static" way + * (to exchange data over the wire, for instance). + * + * @param time + * the time in milliseconds + * + * @return the time as a {@link String} + */ + static public String fromTime(long time) { + SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + return sdf.format(new Date(time)); + } + + /** + * Convert between time as a {@link String} to milliseconds in a "static" + * way (to exchange data over the wire, for instance). + * + * @param time + * the time as a {@link String} + * + * @return the time in milliseconds + */ + static public long toTime(String display) { + SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + try { + return sdf.parse(display).getTime(); + } catch (ParseException e) { + return -1; + } + } } diff --git a/src/be/nikiroo/jvcard/tui/panes/ContactDetailsRaw.java b/src/be/nikiroo/jvcard/tui/panes/ContactDetailsRaw.java index d3bd18d..be74d1c 100644 --- a/src/be/nikiroo/jvcard/tui/panes/ContactDetailsRaw.java +++ b/src/be/nikiroo/jvcard/tui/panes/ContactDetailsRaw.java @@ -117,19 +117,27 @@ public class ContactDetailsRaw extends MainContentList { @Override public String getQuestion() { // TODO i18n - return "new data (xx = yy): "; + return "new data (xx.group = yy): "; } @Override public String callback(String answer) { - if (answer.length() > 0 && answer.contains("=")) { - String[] tab = answer.split("="); - Data data = new Data(null, tab[0].trim(), tab[1].trim(), - null); + int indexEq = answer.indexOf('='); + if (indexEq >= 0) { + String name = answer.substring(0, indexEq).trim(); + String value = answer.substring(indexEq + 1).trim(); + String group = null; + + int indexDt = name.indexOf('.'); + if (indexDt >= 0) { + group = name.substring(indexDt + 1).trim(); + name = name.substring(0, indexDt).trim(); + } + + Data data = new Data(null, name, value, group); getContact().add(data); addItem("x"); } - return null; } }); -- 2.27.0