Commit | Line | Data |
---|---|---|
a3b510ab NR |
1 | package be.nikiroo.jvcard; |
2 | ||
26d2bd05 NR |
3 | import java.io.File; |
4 | import java.io.IOException; | |
5 | import java.util.ArrayList; | |
a3b510ab NR |
6 | import java.util.HashMap; |
7 | import java.util.LinkedList; | |
8 | import java.util.List; | |
9 | import java.util.Map; | |
e253bd50 | 10 | import java.util.UUID; |
a3b510ab NR |
11 | |
12 | import be.nikiroo.jvcard.parsers.Format; | |
13 | import be.nikiroo.jvcard.parsers.Parser; | |
f06c8100 | 14 | import be.nikiroo.utils.StringUtils; |
a3b510ab NR |
15 | |
16 | /** | |
17 | * A contact is the information that represent a contact person or organisation. | |
f04a32e9 NR |
18 | * <p> |
19 | * Each {@link Data} inside can be binary encoded or not: if it is binary | |
20 | * encoded, it has an active BKey number (not -1) associated to it (of value 0 | |
21 | * if still not sorted, or unique for the whole {@link Contact} if already | |
22 | * processed). | |
a3b510ab NR |
23 | * |
24 | * @author niki | |
a3b510ab | 25 | */ |
26d2bd05 | 26 | public class Contact extends BaseClass<Data> { |
a3b510ab NR |
27 | private int nextBKey = 1; |
28 | private Map<Integer, Data> binaries; | |
a3b510ab NR |
29 | |
30 | /** | |
31 | * Create a new Contact from the given information. Note that the BKeys data | |
32 | * will be reset. | |
33 | * | |
34 | * @param content | |
35 | * the information about the contact | |
36 | */ | |
37 | public Contact(List<Data> content) { | |
26d2bd05 | 38 | super(load(content)); |
a3b510ab NR |
39 | updateBKeys(true); |
40 | } | |
41 | ||
a3b510ab | 42 | /** |
7671a249 NR |
43 | * Return the preferred Data field with the given name, the first one if |
44 | * none is preferred, or NULL if none at all. | |
a3b510ab NR |
45 | * |
46 | * @param name | |
47 | * the name to look for | |
7671a249 NR |
48 | * |
49 | * @return the {@link Data} field, or NULL | |
a3b510ab NR |
50 | */ |
51 | public Data getPreferredData(String name) { | |
7671a249 NR |
52 | Data pref = null; |
53 | int ipref = Integer.MAX_VALUE; | |
a3b510ab | 54 | for (Data data : getData(name)) { |
7671a249 NR |
55 | if (pref == null) |
56 | pref = data; | |
3634193b | 57 | |
7671a249 NR |
58 | if (data.getPreferred() < ipref) |
59 | pref = data; | |
a3b510ab NR |
60 | } |
61 | ||
7671a249 | 62 | return pref; |
a3b510ab NR |
63 | } |
64 | ||
65 | /** | |
66 | * Return the value of the preferred data field with this name, or NULL if | |
f04a32e9 NR |
67 | * none (you cannot differentiate a NULL value and no value with this method |
68 | * -- for that, check {@link Contact#getPreferredData(String)}). | |
a3b510ab NR |
69 | * |
70 | * @param name | |
71 | * the name to look for | |
72 | * @return the value (which can be NULL), or NULL | |
73 | */ | |
74 | public String getPreferredDataValue(String name) { | |
75 | Data data = getPreferredData(name); | |
76 | if (data != null && data.getValue() != null) | |
77 | return data.getValue().trim(); | |
78 | return null; | |
79 | } | |
80 | ||
81 | /** | |
82 | * Get the Data fields that share the given name. | |
83 | * | |
84 | * @param name | |
f04a32e9 | 85 | * the name to look for |
a3b510ab NR |
86 | * @return a list of Data fields with this name |
87 | */ | |
88 | public List<Data> getData(String name) { | |
89 | List<Data> found = new LinkedList<Data>(); | |
90 | ||
26d2bd05 | 91 | for (Data data : this) { |
a3b510ab NR |
92 | if (data.getName().equals(name)) |
93 | found.add(data); | |
94 | } | |
95 | ||
96 | return found; | |
97 | } | |
98 | ||
0b0b2b0f NR |
99 | /** |
100 | * Return a {@link String} representation of this contact formated | |
101 | * accordingly to the given format. | |
102 | * | |
26d254a3 | 103 | * <p> |
0b0b2b0f | 104 | * The format is basically a list of field names separated by a pipe and |
30a4aa17 NR |
105 | * optionally parametrised with the 'at' (@) symbol. The parameters allows |
106 | * you to: | |
0b0b2b0f NR |
107 | * <ul> |
108 | * <li>@x: show only a present/not present info</li> | |
109 | * <li>@n: limit the size to a fixed value 'n'</li> | |
110 | * <li>@+: expand the size of this field as much as possible</li> | |
111 | * </ul> | |
26d254a3 | 112 | * </p> |
0b0b2b0f | 113 | * |
26d254a3 | 114 | * <p> |
30a4aa17 NR |
115 | * In case of lists or multiple-fields values, you can select a specific |
116 | * list or field with: | |
117 | * <ul> | |
118 | * <li>FIELD@(0): select the first value in a list</li> | |
119 | * <li>FIELD@[1]: select the second field in a multiple-fields value</li> | |
120 | * </ul> | |
121 | * </p> | |
122 | * | |
123 | * <p> | |
26d254a3 NR |
124 | * You can also add a fixed text if it starts with a simple-quote ('). |
125 | * </p> | |
126 | * | |
127 | * <p> | |
128 | * Example: "'Contact: |N@10|FN@20|NICK@+|PHOTO@x" | |
129 | * </p> | |
0b0b2b0f NR |
130 | * |
131 | * @param format | |
132 | * the format to use | |
26d254a3 NR |
133 | * @param separator |
134 | * the separator {@link String} to use between fields | |
0b0b2b0f NR |
135 | * |
136 | * @return the {@link String} representation | |
137 | */ | |
26d254a3 | 138 | public String toString(String format, String separator) { |
d5260eeb | 139 | return toString(format, separator, null, -1, true); |
0b0b2b0f NR |
140 | } |
141 | ||
a3b510ab NR |
142 | /** |
143 | * Return a {@link String} representation of this contact formated | |
144 | * accordingly to the given format. | |
145 | * | |
26d254a3 | 146 | * <p> |
a3b510ab NR |
147 | * The format is basically a list of field names separated by a pipe and |
148 | * optionally parametrised. The parameters allows you to: | |
149 | * <ul> | |
26d254a3 | 150 | * <li>@x: show only a present/not present info</li> |
a3b510ab NR |
151 | * <li>@n: limit the size to a fixed value 'n'</li> |
152 | * <li>@+: expand the size of this field as much as possible</li> | |
153 | * </ul> | |
26d254a3 NR |
154 | * </p> |
155 | * | |
156 | * <p> | |
30a4aa17 NR |
157 | * In case of lists or multiple-fields values, you can select a specific |
158 | * list or field with: | |
159 | * <ul> | |
160 | * <li>FIELD@(0): select the first value in a list</li> | |
161 | * <li>FIELD@[1]: select the second field in a multiple-fields value</li> | |
162 | * </ul> | |
163 | * </p> | |
164 | * | |
165 | * <p> | |
26d254a3 NR |
166 | * You can also add a fixed text if it starts with a simple-quote ('). |
167 | * </p> | |
a3b510ab | 168 | * |
26d254a3 NR |
169 | * <p> |
170 | * Example: "'Contact: |N@10|FN@20|NICK@+|PHOTO@x" | |
171 | * </p> | |
a3b510ab NR |
172 | * |
173 | * @param format | |
174 | * the format to use | |
175 | * @param separator | |
176 | * the separator {@link String} to use between fields | |
0b0b2b0f NR |
177 | * @param padding |
178 | * the {@link String} to use for left and right padding | |
a3b510ab NR |
179 | * @param width |
180 | * a fixed width or -1 for "as long as needed" | |
296a0b75 | 181 | * @param unicode |
d5260eeb | 182 | * allow Unicode or only ASCII characters |
296a0b75 | 183 | * |
a3b510ab NR |
184 | * @return the {@link String} representation |
185 | */ | |
0b0b2b0f | 186 | public String toString(String format, String separator, String padding, |
d5260eeb | 187 | int width, boolean unicode) { |
9c8baf0c | 188 | StringBuilder builder = new StringBuilder(); |
a3b510ab | 189 | |
296a0b75 NR |
190 | for (String str : toStringArray(format, separator, padding, width, |
191 | unicode)) { | |
0b0b2b0f NR |
192 | builder.append(str); |
193 | } | |
a3b510ab | 194 | |
0b0b2b0f NR |
195 | return builder.toString(); |
196 | } | |
a3b510ab | 197 | |
0b0b2b0f NR |
198 | /** |
199 | * Return a {@link String} representation of this contact formated | |
200 | * accordingly to the given format, part by part. | |
201 | * | |
26d254a3 | 202 | * <p> |
0b0b2b0f NR |
203 | * The format is basically a list of field names separated by a pipe and |
204 | * optionally parametrised. The parameters allows you to: | |
205 | * <ul> | |
206 | * <li>@x: show only a present/not present info</li> | |
207 | * <li>@n: limit the size to a fixed value 'n'</li> | |
208 | * <li>@+: expand the size of this field as much as possible</li> | |
209 | * </ul> | |
26d254a3 | 210 | * </p> |
0b0b2b0f | 211 | * |
26d254a3 | 212 | * <p> |
30a4aa17 NR |
213 | * In case of lists or multiple-fields values, you can select a specific |
214 | * list or field with: | |
215 | * <ul> | |
216 | * <li>FIELD@(0): select the first value in a list</li> | |
217 | * <li>FIELD@[1]: select the second field in a multiple-fields value</li> | |
218 | * </ul> | |
219 | * </p> | |
220 | * | |
221 | * <p> | |
26d254a3 NR |
222 | * You can also add a fixed text if it starts with a simple-quote ('). |
223 | * </p> | |
224 | * | |
225 | * <p> | |
226 | * Example: "'Contact: |N@10|FN@20|NICK@+|PHOTO@x" | |
227 | * </p> | |
0b0b2b0f NR |
228 | * |
229 | * @param format | |
230 | * the format to use | |
231 | * @param separator | |
232 | * the separator {@link String} to use between fields | |
233 | * @param padding | |
234 | * the {@link String} to use for left and right padding | |
235 | * @param width | |
236 | * a fixed width or -1 for "as long as needed" | |
237 | * | |
296a0b75 NR |
238 | * @param unicode |
239 | * allow Uniode or only ASCII characters | |
240 | * | |
0b0b2b0f NR |
241 | * @return the {@link String} representation |
242 | */ | |
243 | public String[] toStringArray(String format, String separator, | |
296a0b75 | 244 | String padding, int width, boolean unicode) { |
0b0b2b0f NR |
245 | if (width > -1) { |
246 | int numOfFields = format.split("\\|").length; | |
247 | if (separator != null) | |
248 | width -= (numOfFields - 1) * separator.length(); | |
249 | if (padding != null) | |
250 | width -= (numOfFields) * (2 * padding.length()); | |
251 | ||
252 | if (width < 0) | |
253 | width = 0; | |
a3b510ab NR |
254 | } |
255 | ||
0b0b2b0f NR |
256 | List<String> str = new LinkedList<String>(); |
257 | ||
258 | boolean first = true; | |
296a0b75 | 259 | for (String s : toStringArray(format, width, unicode)) { |
0b0b2b0f NR |
260 | if (!first) { |
261 | str.add(separator); | |
262 | } | |
263 | ||
264 | if (padding != null) | |
265 | str.add(padding + s + padding); | |
266 | else | |
267 | str.add(s); | |
268 | ||
269 | first = false; | |
9c8baf0c NR |
270 | } |
271 | ||
0b0b2b0f | 272 | return str.toArray(new String[] {}); |
9c8baf0c NR |
273 | } |
274 | ||
275 | /** | |
276 | * Return a {@link String} representation of this contact formated | |
277 | * accordingly to the given format, part by part. | |
278 | * | |
26d254a3 | 279 | * <p> |
9c8baf0c | 280 | * The format is basically a list of field names separated by a pipe and |
0b0b2b0f NR |
281 | * optionally parametrised. The parameters allows you to: |
282 | * <ul> | |
283 | * <li>@x: show only a present/not present info</li> | |
284 | * <li>@n: limit the size to a fixed value 'n'</li> | |
285 | * <li>@+: expand the size of this field as much as possible</li> | |
286 | * </ul> | |
26d254a3 NR |
287 | * </p> |
288 | * | |
289 | * <p> | |
30a4aa17 NR |
290 | * In case of lists or multiple-fields values, you can select a specific |
291 | * list or field with: | |
292 | * <ul> | |
293 | * <li>FIELD@(0): select the first value in a list</li> | |
294 | * <li>FIELD@[1]: select the second field in a multiple-fields value</li> | |
295 | * </ul> | |
296 | * </p> | |
297 | * | |
298 | * <p> | |
26d254a3 NR |
299 | * You can also add a fixed text if it starts with a simple-quote ('). |
300 | * </p> | |
0b0b2b0f | 301 | * |
26d254a3 NR |
302 | * <p> |
303 | * Example: "'Contact: |N@10|FN@20|NICK@+|PHOTO@x" | |
304 | * </p> | |
9c8baf0c NR |
305 | * |
306 | * @param format | |
307 | * the format to use | |
308 | * @param width | |
309 | * a fixed width or -1 for "as long as needed" | |
296a0b75 NR |
310 | * @param unicode |
311 | * allow Uniode or only ASCII characters | |
d5260eeb | 312 | * |
9c8baf0c NR |
313 | * @return the {@link String} representation |
314 | */ | |
296a0b75 | 315 | public String[] toStringArray(String format, int width, boolean unicode) { |
9c8baf0c NR |
316 | List<String> str = new LinkedList<String>(); |
317 | ||
318 | String[] formatFields = format.split("\\|"); | |
319 | String[] values = new String[formatFields.length]; | |
320 | Boolean[] expandedFields = new Boolean[formatFields.length]; | |
321 | Boolean[] fixedsizeFields = new Boolean[formatFields.length]; | |
322 | int numOfFieldsToExpand = 0; | |
323 | int totalSize = 0; | |
324 | ||
325 | if (width == 0) { | |
0b0b2b0f NR |
326 | for (int i = 0; i < formatFields.length; i++) { |
327 | str.add(""); | |
328 | } | |
bcb54330 | 329 | |
9c8baf0c NR |
330 | return str.toArray(new String[] {}); |
331 | } | |
332 | ||
a3b510ab NR |
333 | for (int i = 0; i < formatFields.length; i++) { |
334 | String field = formatFields[i]; | |
335 | ||
336 | int size = -1; | |
337 | boolean binary = false; | |
338 | boolean expand = false; | |
30a4aa17 NR |
339 | int fieldNum = -1; |
340 | int valueNum = -1; | |
a3b510ab | 341 | |
26d254a3 NR |
342 | if (field.length() > 0 && field.charAt(0) != '\'' |
343 | && field.contains("@")) { | |
a3b510ab NR |
344 | String[] opts = field.split("@"); |
345 | if (opts.length > 0) | |
346 | field = opts[0]; | |
347 | for (int io = 1; io < opts.length; io++) { | |
348 | String opt = opts[io]; | |
349 | if (opt.equals("x")) { | |
350 | binary = true; | |
351 | } else if (opt.equals("+")) { | |
352 | expand = true; | |
353 | numOfFieldsToExpand++; | |
30a4aa17 NR |
354 | } else if (opt.length() > 0 && opt.charAt(0) == '(') { |
355 | try { | |
356 | opt = opt.substring(1, opt.length() - 1); | |
357 | valueNum = Integer.parseInt(opt); | |
358 | } catch (Exception e) { | |
359 | } | |
360 | } else if (opt.length() > 0 && opt.charAt(0) == '[') { | |
361 | try { | |
362 | opt = opt.substring(1, opt.length() - 1); | |
363 | fieldNum = Integer.parseInt(opt); | |
364 | } catch (Exception e) { | |
365 | } | |
a3b510ab NR |
366 | } else { |
367 | try { | |
368 | size = Integer.parseInt(opt); | |
30a4aa17 | 369 | } catch (NumberFormatException e) { |
a3b510ab NR |
370 | } |
371 | } | |
372 | } | |
373 | } | |
374 | ||
26d254a3 NR |
375 | String value = null; |
376 | if (field.length() > 0 && field.charAt(0) == '\'') { | |
377 | value = field.substring(1); | |
30a4aa17 NR |
378 | } else if (valueNum >= 0) { |
379 | List<String> vv = getPreferredData(field).getValues(); | |
380 | if (valueNum < vv.size()) { | |
381 | value = vv.get(valueNum); | |
382 | } | |
383 | } else if (fieldNum >= 0) { | |
384 | List<String> ff = getPreferredData(field).getFields(); | |
385 | if (fieldNum < ff.size()) { | |
386 | value = ff.get(fieldNum); | |
387 | } | |
26d254a3 | 388 | } else { |
59597d59 NR |
389 | // we don't need the *data* in binary mode... |
390 | if (binary) | |
391 | value = getData(field).size() > 0 ? "x" : null; | |
392 | else | |
393 | value = getPreferredDataValue(field); | |
26d254a3 NR |
394 | } |
395 | ||
296a0b75 | 396 | if (value == null) { |
a3b510ab | 397 | value = ""; |
296a0b75 NR |
398 | } else { |
399 | value = StringUtils.sanitize(value, unicode); | |
400 | } | |
a3b510ab NR |
401 | |
402 | if (size > -1) { | |
296a0b75 | 403 | value = StringUtils.padString(value, size); |
a3b510ab NR |
404 | } |
405 | ||
406 | expandedFields[i] = expand; | |
407 | fixedsizeFields[i] = (size > -1); | |
408 | ||
409 | if (binary) { | |
410 | if (value != null && !value.equals("")) | |
411 | values[i] = "x"; | |
412 | else | |
413 | values[i] = " "; | |
414 | totalSize++; | |
415 | } else { | |
416 | values[i] = value; | |
417 | totalSize += value.length(); | |
418 | } | |
419 | } | |
9c8baf0c | 420 | |
a3b510ab NR |
421 | if (width > -1 && totalSize > width) { |
422 | int toDo = totalSize - width; | |
423 | for (int i = fixedsizeFields.length - 1; toDo > 0 && i >= 0; i--) { | |
424 | if (!fixedsizeFields[i]) { | |
425 | int valueLength = values[i].length(); | |
426 | if (valueLength > 0) { | |
427 | if (valueLength >= toDo) { | |
428 | values[i] = values[i].substring(0, valueLength | |
429 | - toDo); | |
430 | toDo = 0; | |
431 | } else { | |
432 | values[i] = ""; | |
433 | toDo -= valueLength; | |
434 | } | |
435 | } | |
436 | } | |
437 | } | |
438 | ||
439 | totalSize = width + toDo; | |
440 | } | |
9c8baf0c | 441 | |
a3b510ab NR |
442 | if (width > -1 && numOfFieldsToExpand > 0) { |
443 | int availablePadding = width - totalSize; | |
444 | ||
445 | if (availablePadding > 0) { | |
446 | int padPerItem = availablePadding / numOfFieldsToExpand; | |
447 | int remainder = availablePadding % numOfFieldsToExpand; | |
448 | ||
449 | for (int i = 0; i < values.length; i++) { | |
450 | if (expandedFields[i]) { | |
451 | if (remainder > 0) { | |
296a0b75 NR |
452 | values[i] = values[i] |
453 | + StringUtils.padString("", remainder); | |
a3b510ab NR |
454 | remainder = 0; |
455 | } | |
456 | if (padPerItem > 0) { | |
296a0b75 NR |
457 | values[i] = values[i] |
458 | + StringUtils.padString("", padPerItem); | |
a3b510ab NR |
459 | } |
460 | } | |
461 | } | |
462 | ||
463 | totalSize = width; | |
464 | } | |
465 | } | |
a3b510ab | 466 | |
9c8baf0c NR |
467 | int currentSize = 0; |
468 | for (int i = 0; i < values.length; i++) { | |
469 | currentSize += addToList(str, values[i], currentSize, width); | |
a3b510ab NR |
470 | } |
471 | ||
9c8baf0c | 472 | return str.toArray(new String[] {}); |
a3b510ab NR |
473 | } |
474 | ||
a3b510ab NR |
475 | /** |
476 | * Update the information from this contact with the information in the | |
477 | * given contact. Non present fields will be removed, new fields will be | |
478 | * added, BKey'ed fields will be completed with the binary information known | |
479 | * by this contact. | |
480 | * | |
481 | * @param vc | |
482 | * the contact with the newer information and optional BKeys | |
483 | */ | |
484 | public void updateFrom(Contact vc) { | |
485 | updateBKeys(false); | |
486 | ||
26d2bd05 | 487 | List<Data> newDatas = new LinkedList<Data>(vc); |
a3b510ab NR |
488 | for (int i = 0; i < newDatas.size(); i++) { |
489 | Data data = newDatas.get(i); | |
490 | int bkey = Parser.getBKey(data); | |
491 | if (bkey >= 0) { | |
492 | if (binaries.containsKey(bkey)) { | |
493 | newDatas.set(i, binaries.get(bkey)); | |
494 | } | |
495 | } | |
496 | } | |
497 | ||
26d2bd05 | 498 | replaceListContent(newDatas); |
a3b510ab | 499 | this.nextBKey = vc.nextBKey; |
78e4af97 NR |
500 | } |
501 | ||
e253bd50 NR |
502 | @Override |
503 | public String getId() { | |
504 | return "" + getPreferredDataValue("UID"); | |
505 | } | |
506 | ||
507 | @Override | |
508 | public String getState() { | |
e4444b0b | 509 | return getId(); |
e253bd50 NR |
510 | } |
511 | ||
78e4af97 | 512 | /** |
f04a32e9 NR |
513 | * Return a simple {@link String} representation of this contact without |
514 | * BKeys. | |
78e4af97 NR |
515 | * |
516 | * @return the {@link String} representation | |
517 | */ | |
518 | @Override | |
519 | public String toString() { | |
59597d59 | 520 | return "[Contact: " + getPreferredDataValue("FN") + "]"; |
78e4af97 NR |
521 | } |
522 | ||
a3b510ab NR |
523 | /** |
524 | * Mark all the binary fields with a BKey number. | |
525 | * | |
526 | * @param force | |
527 | * force the marking, and reset all the numbers. | |
528 | */ | |
529 | protected void updateBKeys(boolean force) { | |
530 | if (force) { | |
531 | binaries = new HashMap<Integer, Data>(); | |
532 | nextBKey = 1; | |
533 | } | |
534 | ||
535 | if (binaries == null) { | |
536 | binaries = new HashMap<Integer, Data>(); | |
537 | } | |
538 | ||
26d2bd05 | 539 | for (Data data : this) { |
a3b510ab NR |
540 | if (data.isBinary() && (data.getB64Key() <= 0 || force)) { |
541 | binaries.put(nextBKey, data); | |
542 | data.resetB64Key(nextBKey++); | |
543 | } | |
544 | } | |
545 | } | |
546 | ||
a3b510ab | 547 | /** |
26d2bd05 NR |
548 | * Load the data from the given {@link File} under the given {@link Format}. |
549 | * | |
550 | * @param file | |
551 | * the {@link File} to load from | |
552 | * @param format | |
553 | * the {@link Format} to load as | |
554 | * | |
555 | * @return the list of elements | |
556 | * @throws IOException | |
557 | * in case of IO error | |
a3b510ab | 558 | */ |
26d2bd05 NR |
559 | static private List<Data> load(List<Data> content) { |
560 | List<Data> datas = new ArrayList<Data>(); | |
a3b510ab | 561 | |
26d2bd05 NR |
562 | boolean fn = false; |
563 | boolean n = false; | |
e253bd50 | 564 | boolean uid = false; |
26d2bd05 NR |
565 | if (content != null) { |
566 | for (Data data : content) { | |
567 | if (data.getName().equals("N")) { | |
568 | n = true; | |
569 | } else if (data.getName().equals("FN")) { | |
570 | fn = true; | |
e253bd50 NR |
571 | } else if (data.getName().equals("UID")) { |
572 | uid = true; | |
26d2bd05 NR |
573 | } |
574 | ||
575 | if (!data.getName().equals("VERSION")) { | |
576 | datas.add(data); | |
577 | } | |
578 | } | |
78e4af97 | 579 | } |
78e4af97 | 580 | |
26d2bd05 | 581 | // required fields: |
e253bd50 | 582 | if (!n) // required since vCard 3.0, supported in 2.1 |
26d2bd05 | 583 | datas.add(new Data(null, "N", "", null)); |
e253bd50 | 584 | if (!fn) // not required anymore but still supported in 4.0 |
26d2bd05 | 585 | datas.add(new Data(null, "FN", "", null)); |
e253bd50 NR |
586 | if (!uid) // supported by vCard, required by this program |
587 | datas.add(new Data(null, "UID", UUID.randomUUID().toString(), null)); | |
26d2bd05 NR |
588 | |
589 | return datas; | |
a3b510ab | 590 | } |
296a0b75 | 591 | |
bcb54330 | 592 | /** |
78e4af97 NR |
593 | * Add a {@link String} to the given {@link List}, but make sure it does not |
594 | * exceed the maximum size, and truncate it if needed to fit. | |
f04a32e9 NR |
595 | * <p> |
596 | * Will always add one and only one {@link String} (potentially empty) at | |
597 | * the end of <tt>list</tt>. | |
bcb54330 | 598 | * |
78e4af97 | 599 | * @param list |
f04a32e9 | 600 | * the list to add to |
78e4af97 | 601 | * @param add |
f04a32e9 | 602 | * the {@link String} to (either fully or partially) add |
78e4af97 | 603 | * @param currentSize |
f04a32e9 | 604 | * the current total size (managed outside of this method) |
78e4af97 | 605 | * @param maxSize |
f04a32e9 NR |
606 | * the maximum size that cannot be exceeded (or -1 for |
607 | * "no maximum") -- if the maximum size would be exceeded by | |
608 | * adding this {@link String}, only a part of it will be added; | |
609 | * if the maximum size is already reached or exceeded (should not | |
610 | * happen because of this method), an empty {@link String} will | |
611 | * be added | |
612 | * | |
613 | * @return the number of characters added (the size of the last | |
614 | * {@link String} in <tt>list</tt>) | |
bcb54330 | 615 | */ |
78e4af97 NR |
616 | static private int addToList(List<String> list, String add, |
617 | int currentSize, int maxSize) { | |
618 | if (add == null || add.length() == 0) { | |
619 | if (add != null) | |
620 | list.add(add); | |
621 | return 0; | |
622 | } | |
623 | ||
624 | if (maxSize > -1) { | |
625 | if (currentSize < maxSize) { | |
626 | if (currentSize + add.length() >= maxSize) { | |
627 | add = add.substring(0, maxSize - currentSize); | |
bcb54330 | 628 | } |
78e4af97 NR |
629 | } else { |
630 | add = ""; | |
bcb54330 NR |
631 | } |
632 | } | |
633 | ||
78e4af97 NR |
634 | list.add(add); |
635 | return add.length(); | |
bcb54330 | 636 | } |
a3b510ab | 637 | } |