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.
}
/**
- * Return the informations (note: this is the actual list, be careful).
+ * Return the number of {@link Data} present in this {@link Contact}.
*
- * @return the list of data anout this contact
+ * @return the number of {@link Data}s
*/
- public List<Data> getContent() {
- return datas;
+ public int size() {
+ return datas.size();
+ }
+
+ /**
+ * Return the {@link Data} at index <i>index</i>.
+ *
+ * @param index
+ * the index of the {@link Data} to find
+ *
+ * @return the {@link Data}
+ *
+ * @throws IndexOutOfBoundsException
+ * if the index is < 0 or >= {@link Contact#size()}
+ */
+ public Data get(int index) {
+ return datas.get(index);
}
/**
for (Data data : getData(name)) {
if (first == null)
first = data;
- for (TypeInfo type : data.getTypes()) {
+ for (int index = 0; index < data.size(); index++) {
+ TypeInfo type = data.get(index);
if (type.getName().equals("TYPE")
&& type.getValue().equals("pref")) {
return data;
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.
* 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];
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++) {
}
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;
totalSize += value.length();
}
}
-
+
if (width > -1 && totalSize > width) {
int toDo = totalSize - width;
for (int i = fixedsizeFields.length - 1; toDo > 0 && i >= 0; i--) {
totalSize = width + toDo;
}
-
+
if (width > -1 && numOfFieldsToExpand > 0) {
int availablePadding = width - totalSize;
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);
}
}
}
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;
- }
-
- /**
- * Fix the size of the given {@link String} either with space-padding or by
- * shortening it.
- *
- * @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>
- */
- static private String fixedString(String string, int size) {
- int length = string.length();
-
- if (length > size)
- string = string.substring(0, size);
- else if (length < size)
- string = string
- + new String(new char[size - length]).replace('\0', ' ');
-
- return string;
- }
-
- /**
- * Return a {@link String} representation of this contact, in vCard 2.1,
- * without BKeys.
- *
- * @return the {@link String} representation
- */
- public String toString() {
- return toString(Format.VCard21, -1);
+ return str.toArray(new String[] {});
}
/**
setDirty();
}
+ /**
+ * 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;
+ }
+
+ /**
+ * Check if this {@link Contact} has unsaved changes.
+ *
+ * @return TRUE if it has
+ */
+ public boolean isDirty() {
+ return dirty;
+ }
+
+ /**
+ * Return a {@link String} representation of this contact, in vCard 2.1,
+ * without BKeys.
+ *
+ * @return the {@link String} representation
+ */
+ @Override
+ public String toString() {
+ return toString(Format.VCard21, -1);
+ }
+
/**
* Mark all the binary fields with a BKey number.
*
}
}
- public boolean isDirty() {
- return dirty;
- }
-
/**
* Notify that this element has unsaved changes, and notify its parent of
* the same if any.
this.parent.setDirty();
}
- public void setParent(Card parent) {
+ /**
+ * 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();
+ }
+ }
+
+ /**
+ * Set the parent of this {@link Contact} <i>and all its descendants</i>.
+ *
+ * @param parent
+ * the new parent
+ */
+ void setParent(Card parent) {
this.parent = parent;
for (Data data : datas) {
data.setParent(this);
}
}
+
+ /**
+ * 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 list
+ * @param add
+ * @param currentSize
+ * @param maxSize
+ * @return
+ */
+ 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 (maxSize > -1) {
+ if (currentSize < maxSize) {
+ if (currentSize + add.length() >= maxSize) {
+ add = add.substring(0, maxSize - currentSize);
+ }
+ } else {
+ add = "";
+ }
+ }
+
+ list.add(add);
+ return add.length();
+ }
+
}