Fix --noutf, fix onAction being called to many times, lot of small fixes
[jvcard.git] / src / be / nikiroo / jvcard / Contact.java
index 08d5eee0fdcfe25588d37f466293225af6c17217..553ca7680f486f34b1a38e9753dff0b4f06edb99 100644 (file)
@@ -7,6 +7,7 @@ import java.util.Map;
 
 import be.nikiroo.jvcard.parsers.Format;
 import be.nikiroo.jvcard.parsers.Parser;
+import be.nikiroo.jvcard.tui.StringUtils;
 
 /**
  * A contact is the information that represent a contact person or organisation.
@@ -135,6 +136,29 @@ public class Contact {
                return Parser.toString(this, format, startingBKey);
        }
 
+       /**
+        * Return a {@link String} representation of this contact formated
+        * accordingly to the given format.
+        * 
+        * The format is basically a list of field names separated by a pipe and
+        * optionally parametrised. The parameters allows you to:
+        * <ul>
+        * <li>@x: show only a present/not present info</li>
+        * <li>@n: limit the size to a fixed value 'n'</li>
+        * <li>@+: expand the size of this field as much as possible</li>
+        * </ul>
+        * 
+        * Example: "N@10|FN@20|NICK@+|PHOTO@x"
+        * 
+        * @param format
+        *            the format to use
+        * 
+        * @return the {@link String} representation
+        */
+       public String toString(String format) {
+               return toString(format, "|", null, -1, true, false);
+       }
+
        /**
         * Return a {@link String} representation of this contact formated
         * accordingly to the given format.
@@ -153,13 +177,113 @@ public class Contact {
         *            the format to use
         * @param separator
         *            the separator {@link String} to use between fields
+        * @param padding
+        *            the {@link String} to use for left and right padding
         * @param width
         *            a fixed width or -1 for "as long as needed"
         * 
+        * @param unicode
+        *            allow Uniode or only ASCII characters
+        * 
+        * @return the {@link String} representation
+        */
+       public String toString(String format, String separator, String padding,
+                       int width, boolean unicode, boolean removeAccents) {
+               StringBuilder builder = new StringBuilder();
+
+               for (String str : toStringArray(format, separator, padding, width,
+                               unicode)) {
+                       builder.append(str);
+               }
+
+               return builder.toString();
+       }
+
+       /**
+        * Return a {@link String} representation of this contact formated
+        * accordingly to the given format, part by part.
+        * 
+        * The format is basically a list of field names separated by a pipe and
+        * optionally parametrised. The parameters allows you to:
+        * <ul>
+        * <li>@x: show only a present/not present info</li>
+        * <li>@n: limit the size to a fixed value 'n'</li>
+        * <li>@+: expand the size of this field as much as possible</li>
+        * </ul>
+        * 
+        * Example: "N@10|FN@20|NICK@+|PHOTO@x"
+        * 
+        * @param format
+        *            the format to use
+        * @param separator
+        *            the separator {@link String} to use between fields
+        * @param padding
+        *            the {@link String} to use for left and right padding
+        * @param width
+        *            a fixed width or -1 for "as long as needed"
+        * 
+        * @param unicode
+        *            allow Uniode or only ASCII characters
+        * 
+        * @return the {@link String} representation
+        */
+       public String[] toStringArray(String format, String separator,
+                       String padding, int width, boolean unicode) {
+               if (width > -1) {
+                       int numOfFields = format.split("\\|").length;
+                       if (separator != null)
+                               width -= (numOfFields - 1) * separator.length();
+                       if (padding != null)
+                               width -= (numOfFields) * (2 * padding.length());
+
+                       if (width < 0)
+                               width = 0;
+               }
+
+               List<String> str = new LinkedList<String>();
+
+               boolean first = true;
+               for (String s : toStringArray(format, width, unicode)) {
+                       if (!first) {
+                               str.add(separator);
+                       }
+
+                       if (padding != null)
+                               str.add(padding + s + padding);
+                       else
+                               str.add(s);
+
+                       first = false;
+               }
+
+               return str.toArray(new String[] {});
+       }
+
+       /**
+        * Return a {@link String} representation of this contact formated
+        * accordingly to the given format, part by part.
+        * 
+        * The format is basically a list of field names separated by a pipe and
+        * optionally parametrised. The parameters allows you to:
+        * <ul>
+        * <li>@x: show only a present/not present info</li>
+        * <li>@n: limit the size to a fixed value 'n'</li>
+        * <li>@+: expand the size of this field as much as possible</li>
+        * </ul>
+        * 
+        * Example: "N@10|FN@20|NICK@+|PHOTO@x"
+        * 
+        * @param format
+        *            the format to use
+        * @param width
+        *            a fixed width or -1 for "as long as needed"
+        * @param unicode
+        *            allow Uniode or only ASCII characters
+        *
         * @return the {@link String} representation
         */
-       public String toString(String format, String separator, int width) {
-               String str = null;
+       public String[] toStringArray(String format, int width, boolean unicode) {
+               List<String> str = new LinkedList<String>();
 
                String[] formatFields = format.split("\\|");
                String[] values = new String[formatFields.length];
@@ -169,22 +293,11 @@ public class Contact {
                int totalSize = 0;
 
                if (width == 0) {
-                       return "";
-               }
-
-               if (width > -1 && separator != null && separator.length() > 0
-                               && formatFields.length > 1) {
-                       int swidth = (formatFields.length - 1) * separator.length();
-                       if (swidth >= width) {
-                               str = separator;
-                               while (str.length() < width) {
-                                       str += separator;
-                               }
-
-                               return str.substring(0, width);
+                       for (int i = 0; i < formatFields.length; i++) {
+                               str.add("");
                        }
 
-                       width -= swidth;
+                       return str.toArray(new String[] {});
                }
 
                for (int i = 0; i < formatFields.length; i++) {
@@ -215,11 +328,14 @@ public class Contact {
                        }
 
                        String value = getPreferredDataValue(field);
-                       if (value == null)
+                       if (value == null) {
                                value = "";
+                       } else {
+                               value = StringUtils.sanitize(value, unicode);
+                       }
 
                        if (size > -1) {
-                               value = fixedString(value, size);
+                               value = StringUtils.padString(value, size);
                        }
 
                        expandedFields[i] = expand;
@@ -236,7 +352,7 @@ public class Contact {
                                totalSize += value.length();
                        }
                }
-               
+
                if (width > -1 && totalSize > width) {
                        int toDo = totalSize - width;
                        for (int i = fixedsizeFields.length - 1; toDo > 0 && i >= 0; i--) {
@@ -257,7 +373,7 @@ public class Contact {
 
                        totalSize = width + toDo;
                }
-               
+
                if (width > -1 && numOfFieldsToExpand > 0) {
                        int availablePadding = width - totalSize;
 
@@ -269,14 +385,12 @@ public class Contact {
                                        if (expandedFields[i]) {
                                                if (remainder > 0) {
                                                        values[i] = values[i]
-                                                                       + new String(new char[remainder]).replace(
-                                                                                       '\0', ' ');
+                                                                       + StringUtils.padString("", remainder);
                                                        remainder = 0;
                                                }
                                                if (padPerItem > 0) {
                                                        values[i] = values[i]
-                                                                       + new String(new char[padPerItem]).replace(
-                                                                                       '\0', ' ');
+                                                                       + StringUtils.padString("", padPerItem);
                                                }
                                        }
                                }
@@ -284,46 +398,45 @@ public class Contact {
                                totalSize = width;
                        }
                }
-               
-               for (String field : values) {
-                       if (str == null) {
-                               str = field;
-                       } else {
-                               str += separator + field;
-                       }
-               }
-
-               if (str == null)
-                       str = "";
 
-               if (width > -1) {
-                       str = fixedString(str, width);
+               int currentSize = 0;
+               for (int i = 0; i < values.length; i++) {
+                       currentSize += addToList(str, values[i], currentSize, width);
                }
 
-               return str;
+               return str.toArray(new String[] {});
        }
 
        /**
-        * Fix the size of the given {@link String} either with space-padding or by
-        * shortening it.
+        * Add a {@link String} to the given {@link List}, but make sure it does not
+        * exceed the maximum size, and truncate it if needed to fit.
         * 
-        * @param string
-        *            the {@link String} to fix
-        * @param size
-        *            the size of the resulting {@link String}
-        * 
-        * @return the fixed {@link String} of size <i>size</i>
+        * @param list
+        * @param add
+        * @param currentSize
+        * @param maxSize
+        * @return
         */
-       static private String fixedString(String string, int size) {
-               int length = string.length();
+       static private int addToList(List<String> list, String add,
+                       int currentSize, int maxSize) {
+               if (add == null || add.length() == 0) {
+                       if (add != null)
+                               list.add(add);
+                       return 0;
+               }
 
-               if (length > size)
-                       string = string.substring(0, size);
-               else if (length < size)
-                       string = string
-                                       + new String(new char[size - length]).replace('\0', ' ');
+               if (maxSize > -1) {
+                       if (currentSize < maxSize) {
+                               if (currentSize + add.length() >= maxSize) {
+                                       add = add.substring(0, maxSize - currentSize);
+                               }
+                       } else {
+                               add = "";
+                       }
+               }
 
-               return string;
+               list.add(add);
+               return add.length();
        }
 
        /**
@@ -404,10 +517,41 @@ public class Contact {
                        this.parent.setDirty();
        }
 
-       public void setParent(Card parent) {
+       void setParent(Card parent) {
                this.parent = parent;
                for (Data data : datas) {
                        data.setParent(this);
                }
        }
+
+       /**
+        * Delete this {@link Contact} from its parent {@link Card} if any.
+        * 
+        * @return TRUE in case of success
+        */
+       public boolean delete() {
+               if (parent != null) {
+                       List<Contact> list = parent.getContactsList();
+                       for (int i = 0; i < list.size(); i++) {
+                               if (list.get(i) == this) {
+                                       list.remove(i);
+                                       parent.setDirty();
+                                       return true;
+                               }
+                       }
+               }
+
+               return false;
+       }
+
+       /**
+        * Notify this element <i>and all its descendants</i> that it is in pristine
+        * state (as opposed to dirty).
+        */
+       void setPristine() {
+               dirty = false;
+               for (Data data : datas) {
+                       data.setPristine();
+               }
+       }
 }