From 1c03abafc3987d93fa682e7b8758e51bed8a4faf Mon Sep 17 00:00:00 2001 From: Niki Roo Date: Sun, 13 Mar 2016 12:12:32 +0100 Subject: [PATCH] Indexed colours, better image handling, lines cut at 74: - now supports indexed colours by number (fot theme colours) - fix a freeze when the image data was not correct - now cuts line at the 74/75 position when saving vcf --- src/be/nikiroo/jvcard/Card.java | 53 +++--------------- src/be/nikiroo/jvcard/Data.java | 10 ++-- src/be/nikiroo/jvcard/TypeInfo.java | 22 +++++++- src/be/nikiroo/jvcard/parsers/Parser.java | 50 +++++++++++++++++ .../nikiroo/jvcard/parsers/Vcard21Parser.java | 56 +++++++++++++------ src/be/nikiroo/jvcard/resources/Bundles.java | 4 ++ .../jvcard/resources/colors.properties | 1 + src/be/nikiroo/jvcard/tui/UiColors.java | 2 + .../jvcard/tui/panes/ContactDetails.java | 14 ++++- 9 files changed, 141 insertions(+), 71 deletions(-) diff --git a/src/be/nikiroo/jvcard/Card.java b/src/be/nikiroo/jvcard/Card.java index 986f81d..de5ab67 100644 --- a/src/be/nikiroo/jvcard/Card.java +++ b/src/be/nikiroo/jvcard/Card.java @@ -1,14 +1,10 @@ package be.nikiroo.jvcard; -import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.File; -import java.io.FileInputStream; import java.io.FileWriter; import java.io.IOException; -import java.io.InputStreamReader; import java.security.InvalidParameterException; -import java.util.LinkedList; import java.util.List; import be.nikiroo.jvcard.parsers.Format; @@ -44,7 +40,7 @@ public class Card extends BaseClass { * if format is NULL */ public Card(File file, Format format) throws IOException { - this(load(file, format)); + this(Parser.parse(file, format)); if (file != null) { if (file.exists()) { @@ -89,7 +85,7 @@ public class Card extends BaseClass { * Save the {@link Card} to the given {@link File} with the given * {@link Format}. * - * @param output + * @param file * the output to save to * @param format * the {@link Format} to use @@ -99,15 +95,16 @@ public class Card extends BaseClass { * @throws IOException * in case of IO errors */ - public boolean saveAs(File output, Format format) throws IOException { - if (output == null) + public boolean saveAs(File file, Format format) throws IOException { + if (file == null) return false; - BufferedWriter writer = new BufferedWriter(new FileWriter(output)); + BufferedWriter writer = new BufferedWriter(new FileWriter(file)); writer.append(toString(format)); writer.close(); - if (output.getCanonicalPath().equals(this.file.getCanonicalPath())) { + if (this.file != null + && file.getCanonicalPath().equals(this.file.getCanonicalPath())) { setPristine(); } @@ -138,7 +135,7 @@ public class Card extends BaseClass { if (file == null) return false; - this.replaceListContent(load(file, format)); + this.replaceListContent(Parser.parse(file, format)); setPristine(); return true; } @@ -227,38 +224,4 @@ public class Card extends BaseClass { public String getState() { return "" + name + format; } - - /** - * Load the data from the given {@link File} under the given {@link Format}. - * - * @param file - * 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 - */ - private static List load(File file, Format format) - throws IOException { - 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(); - } - - if (lines == null) - return new LinkedList(); - - return Parser.parse(lines, format); - } } diff --git a/src/be/nikiroo/jvcard/Data.java b/src/be/nikiroo/jvcard/Data.java index ef44813..a0ef2e9 100644 --- a/src/be/nikiroo/jvcard/Data.java +++ b/src/be/nikiroo/jvcard/Data.java @@ -30,17 +30,17 @@ public class Data extends BaseClass { * @param types * the types of this {@link Data} * @param name - * its name + * its name (MUST NOT be NULL) * @param value - * its value + * its value (MUST NOT be NULL) * @param group - * its group if any + * its group if any (or NULL if none) */ public Data(List types, String name, String value, String group) { super(types); - this.name = name; - this.value = value; + this.name = name.toUpperCase(); + this.value = value.toString(); // crash NOW if null this.group = group; b64 = -1; diff --git a/src/be/nikiroo/jvcard/TypeInfo.java b/src/be/nikiroo/jvcard/TypeInfo.java index a1cc306..2585cfb 100644 --- a/src/be/nikiroo/jvcard/TypeInfo.java +++ b/src/be/nikiroo/jvcard/TypeInfo.java @@ -11,18 +11,36 @@ public class TypeInfo extends BaseClass { private String name; private String value; + /** + * Create a new {@link TypeInfo}. + * + * @param name + * the name of this {@link TypeInfo} (MUST NOT be NULL) + * @param value + * its value (MUST NOT be NULL) + */ @SuppressWarnings("unchecked") public TypeInfo(String name, String value) { super(null); - this.name = name; - this.value = value; + this.name = name.toUpperCase(); + this.value = value.toString(); // crash NOW if null } + /** + * Return the name. + * + * @return the name + */ public String getName() { return name; } + /** + * Return the value. + * + * @return the value + */ public String getValue() { return value; } diff --git a/src/be/nikiroo/jvcard/parsers/Parser.java b/src/be/nikiroo/jvcard/parsers/Parser.java index 5ecad4a..5cdd25f 100644 --- a/src/be/nikiroo/jvcard/parsers/Parser.java +++ b/src/be/nikiroo/jvcard/parsers/Parser.java @@ -1,6 +1,12 @@ package be.nikiroo.jvcard.parsers; +import java.io.BufferedReader; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStreamReader; import java.security.InvalidParameterException; +import java.util.LinkedList; import java.util.List; import be.nikiroo.jvcard.Card; @@ -9,6 +15,50 @@ import be.nikiroo.jvcard.Data; public class Parser { + /** + * Load the data from the given {@link File} under the given {@link Format}. + * + * @param file + * 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 + */ + public static List parse(File file, Format format) + throws IOException { + 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(); + } + + if (lines == null) + return new LinkedList(); + + return parse(lines, format); + } + + /** + * Load the given data from under the given {@link Format}. + * + * @param lines + * the input to load from + * @param format + * the {@link Format} to load as + * + * @return the list of elements + */ public static List parse(List lines, Format format) { switch (format) { case VCard21: diff --git a/src/be/nikiroo/jvcard/parsers/Vcard21Parser.java b/src/be/nikiroo/jvcard/parsers/Vcard21Parser.java index 6d8b2ba..225915d 100644 --- a/src/be/nikiroo/jvcard/parsers/Vcard21Parser.java +++ b/src/be/nikiroo/jvcard/parsers/Vcard21Parser.java @@ -113,28 +113,52 @@ public class Vcard21Parser { builder.append("\r\n"); builder.append("VERSION:2.1"); builder.append("\r\n"); - for (int indexData = 0; indexData < contact.size(); indexData++) { - Data data = contact.get(indexData); + for (Data data : contact) { + StringBuilder dataBuilder = new StringBuilder(); if (data.getGroup() != null && !data.getGroup().trim().equals("")) { - builder.append(data.getGroup().trim()); - builder.append('.'); + dataBuilder.append(data.getGroup().trim()); + dataBuilder.append('.'); } - builder.append(data.getName()); - for (int indexType = 0; indexType < data.size(); indexType++) { - TypeInfo type = data.get(indexType); - builder.append(';'); - builder.append(type.getName()); + dataBuilder.append(data.getName()); + for (TypeInfo type : data) { + dataBuilder.append(';'); + dataBuilder.append(type.getName()); if (type.getValue() != null && !type.getValue().trim().equals("")) { - builder.append('='); - builder.append(type.getValue()); + dataBuilder.append('='); + dataBuilder.append(type.getValue()); } } - builder.append(':'); + dataBuilder.append(':'); // TODO: bkey! - builder.append(data.getValue()); - builder.append("\r\n"); + dataBuilder.append(data.getValue()); + + // RFC says: Content lines SHOULD be folded to a maximum width of 75 + // octets -> since it is SHOULD, we will just cut it as 74/75 chars + // depending if the last one fits in one char (note: chars != octet) + boolean continuation = false; + while (dataBuilder.length() > 0) { + int stop = 74; + if (continuation) + stop--; // the space takes 1 + if (dataBuilder.length() > stop) { + char car = dataBuilder.charAt(stop - 1); + // RFC forbids cutting a character in 2 + if (Character.isHighSurrogate(car)) { + stop++; + } + } + + stop = Math.min(stop, dataBuilder.length()); + if (continuation) + builder.append(' '); + builder.append(dataBuilder, 0, stop); + builder.append("\r\n"); + dataBuilder.delete(0, stop); + + continuation = true; + } } builder.append("END:VCARD"); builder.append("\r\n"); @@ -145,8 +169,8 @@ public class Vcard21Parser { public static String toString(Card card) { StringBuilder builder = new StringBuilder(); - for (int index = 0; index < card.size(); index++) { - builder.append(toString(card.get(index), -1)); + for (Contact contact : card) { + builder.append(toString(contact, -1)); } builder.append("\r\n"); diff --git a/src/be/nikiroo/jvcard/resources/Bundles.java b/src/be/nikiroo/jvcard/resources/Bundles.java index 945e7f1..e105b71 100644 --- a/src/be/nikiroo/jvcard/resources/Bundles.java +++ b/src/be/nikiroo/jvcard/resources/Bundles.java @@ -12,6 +12,10 @@ import java.util.ResourceBundle; public class Bundles { static private String confDir = getConfDir(); + // TODO: rename to bundle, use it as base for i18n.Trans, create one for + // each resource + private int TODO; + /** * Return the non-localised bundle of the given name. * diff --git a/src/be/nikiroo/jvcard/resources/colors.properties b/src/be/nikiroo/jvcard/resources/colors.properties index 0922478..b4cf41d 100644 --- a/src/be/nikiroo/jvcard/resources/colors.properties +++ b/src/be/nikiroo/jvcard/resources/colors.properties @@ -4,6 +4,7 @@ # - WHITE: one of the ANSI colour names, in upper case # - @RRGGBB: a RGB code we will try to match using one of the 256 Terminal colours # - #RRGGBB: an exact RGB colour (please make sure your terminal supports this) +# - 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) diff --git a/src/be/nikiroo/jvcard/tui/UiColors.java b/src/be/nikiroo/jvcard/tui/UiColors.java index 5c5d01e..50c2bf4 100644 --- a/src/be/nikiroo/jvcard/tui/UiColors.java +++ b/src/be/nikiroo/jvcard/tui/UiColors.java @@ -220,6 +220,8 @@ public class UiColors { int g = Integer.parseInt(value.substring(3, 5), 16); int b = Integer.parseInt(value.substring(5, 7), 16); return new TextColor.RGB(r, g, b); + } else if (value.replaceAll("[0-9]*", "").length() == 0) { + return new TextColor.Indexed(Integer.parseInt(value)); } else { return TextColor.ANSI.valueOf(value); } diff --git a/src/be/nikiroo/jvcard/tui/panes/ContactDetails.java b/src/be/nikiroo/jvcard/tui/panes/ContactDetails.java index 06c88fc..090cf14 100644 --- a/src/be/nikiroo/jvcard/tui/panes/ContactDetails.java +++ b/src/be/nikiroo/jvcard/tui/panes/ContactDetails.java @@ -1,11 +1,12 @@ package be.nikiroo.jvcard.tui.panes; import java.awt.Image; +import java.io.ByteArrayInputStream; import java.util.LinkedList; import java.util.List; +import javax.imageio.ImageIO; import javax.xml.bind.DatatypeConverter; -import javax.swing.ImageIcon; import be.nikiroo.jvcard.Contact; import be.nikiroo.jvcard.Data; @@ -116,8 +117,15 @@ public class ContactDetails extends MainContent { if (encoding != null && encoding.getValue() != null && encoding.getValue().equalsIgnoreCase("b")) { - image = new ImageIcon(DatatypeConverter.parseBase64Binary( - photo.getValue())).getImage(); + try { + image = ImageIO.read(new ByteArrayInputStream( + DatatypeConverter.parseBase64Binary(photo + .getValue()))); + image.toString(); + } catch (Exception e) { + System.err.println("Cannot parse image for contact: " + + contact.getPreferredDataValue("UID")); + } } } } -- 2.27.0