Indexed colours, better image handling, lines cut at 74:
authorNiki Roo <niki@nikiroo.be>
Sun, 13 Mar 2016 11:12:32 +0000 (12:12 +0100)
committerNiki Roo <niki@nikiroo.be>
Sun, 13 Mar 2016 11:12:32 +0000 (12:12 +0100)
- 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
src/be/nikiroo/jvcard/Data.java
src/be/nikiroo/jvcard/TypeInfo.java
src/be/nikiroo/jvcard/parsers/Parser.java
src/be/nikiroo/jvcard/parsers/Vcard21Parser.java
src/be/nikiroo/jvcard/resources/Bundles.java
src/be/nikiroo/jvcard/resources/colors.properties
src/be/nikiroo/jvcard/tui/UiColors.java
src/be/nikiroo/jvcard/tui/panes/ContactDetails.java

index 986f81d17c0932cba2081d7586b0ce115ad25547..de5ab67a604207f0d294f3d9a7652a460c4754a3 100644 (file)
@@ -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<Contact> {
         *             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<Contact> {
         * 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<Contact> {
         * @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<Contact> {
                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<Contact> {
        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<Contact> load(File file, Format format)
-                       throws IOException {
-               List<String> lines = null;
-
-               if (file != null && file.exists()) {
-                       BufferedReader buffer = new BufferedReader(new InputStreamReader(
-                                       new FileInputStream(file), "UTF-8"));
-                       lines = new LinkedList<String>();
-                       for (String line = buffer.readLine(); line != null; line = buffer
-                                       .readLine()) {
-                               lines.add(line);
-                       }
-                       buffer.close();
-               }
-
-               if (lines == null)
-                       return new LinkedList<Contact>();
-
-               return Parser.parse(lines, format);
-       }
 }
index ef44813a0fca7d62dcaf1ed032434c97a0960be2..a0ef2e955889d3bd5ea7f5455ccd5ca0a36f48fb 100644 (file)
@@ -30,17 +30,17 @@ public class Data extends BaseClass<TypeInfo> {
         * @param types
         *            the types of this {@link Data}
         * @param name
-        *            its name
+        *            its name (<b>MUST NOT</b> be NULL)
         * @param value
-        *            its value
+        *            its value (<b>MUST NOT</b> be NULL)
         * @param group
-        *            its group if any
+        *            its group if any (or NULL if none)
         */
        public Data(List<TypeInfo> 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;
index a1cc306d64d33a692aec043f6cc068f05be71fa2..2585cfbdd4deb68c12152cfc592cc4274f543c71 100644 (file)
@@ -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} (<b>MUST NOT</b> be NULL)
+        * @param value
+        *            its value (<b>MUST NOT</b> 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;
        }
index 5ecad4a42abcb9fe1c8c34307b53270aa70e1f0c..5cdd25fee995dfe10aef8c6d4a5d00dcc18aa5ab 100644 (file)
@@ -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<Contact> parse(File file, Format format)
+                       throws IOException {
+               List<String> lines = null;
+
+               if (file != null && file.exists()) {
+                       BufferedReader buffer = new BufferedReader(new InputStreamReader(
+                                       new FileInputStream(file), "UTF-8"));
+                       lines = new LinkedList<String>();
+                       for (String line = buffer.readLine(); line != null; line = buffer
+                                       .readLine()) {
+                               lines.add(line);
+                       }
+                       buffer.close();
+               }
+
+               if (lines == null)
+                       return new LinkedList<Contact>();
+
+               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<Contact> parse(List<String> lines, Format format) {
                switch (format) {
                case VCard21:
index 6d8b2babc14ca9de578ab4d4b15157e628a7ecad..225915d7ca131a8a974a10ef7f1b9741d4b8cb2f 100644 (file)
@@ -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");
index 945e7f13fec0a73eea71d5080a6f7929bfa5b9c9..e105b7117e64a6aed042b8c22adaf40919c2823a 100644 (file)
@@ -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.
         * 
index 092247877c90b4dcbecf1ae18ae8d969163aa14f..b4cf41d8149e73071c0530dc1fffb19f4fd1143b 100644 (file)
@@ -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)
 
index 5c5d01eebcf32e3f1611a3daece2f14ae30f3d18..50c2bf4fafdb698d1d7dd5ac94f5bff99ae7857c 100644 (file)
@@ -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);
                        }
index 06c88fc9ec02a66f71011f6842ecb54d6e1e0603..090cf142dbbaf65fa717f5e9adae73b75100a1d9 100644 (file)
@@ -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"));
+                                       }
                                }
                        }
                }