Version 2.0.0: update sources
[jvcard.git] / src / be / nikiroo / jvcard / tui / panes / ContactDetailsRaw.java
CommitLineData
fae07ea7
NR
1package be.nikiroo.jvcard.tui.panes;
2
bcb54330 3import java.util.LinkedList;
fae07ea7
NR
4import java.util.List;
5
6import be.nikiroo.jvcard.Contact;
7import be.nikiroo.jvcard.Data;
bcb54330 8import be.nikiroo.jvcard.TypeInfo;
7da41ecd 9import be.nikiroo.jvcard.launcher.Main;
f06c8100
NR
10import be.nikiroo.jvcard.resources.ColorOption;
11import be.nikiroo.jvcard.resources.StringId;
fae07ea7
NR
12import be.nikiroo.jvcard.tui.KeyAction;
13import be.nikiroo.jvcard.tui.KeyAction.DataType;
14import be.nikiroo.jvcard.tui.KeyAction.Mode;
d459d7e1 15import be.nikiroo.jvcard.tui.TuiLauncher;
f06c8100 16import be.nikiroo.utils.StringUtils;
fae07ea7 17
d459d7e1
NR
18import com.googlecode.lanterna.gui2.MultiWindowTextGUI;
19import com.googlecode.lanterna.gui2.dialogs.ActionListDialogBuilder;
78e4af97
NR
20import com.googlecode.lanterna.input.KeyType;
21
296a0b75 22public class ContactDetailsRaw extends MainContentList {
fae07ea7 23 private Contact contact;
176a8327 24 private boolean extMode;
fae07ea7 25
296a0b75 26 public ContactDetailsRaw(Contact contact) {
fae07ea7 27 this.contact = contact;
176a8327 28 this.extMode = false;
fae07ea7 29
78e4af97 30 for (int i = 0; i < contact.size(); i++) {
176a8327 31 addItem("x");
fae07ea7
NR
32 }
33 }
34
35 @Override
36 public DataType getDataType() {
bcb54330 37 return DataType.DATA;
fae07ea7 38 }
ae22c247 39
fae07ea7
NR
40 @Override
41 public List<KeyAction> getKeyBindings() {
bcb54330
NR
42 List<KeyAction> actions = new LinkedList<KeyAction>();
43
78e4af97 44 actions.add(new KeyAction(Mode.ASK_USER, KeyType.Enter,
88eb8122 45 StringId.KEY_ACTION_EDIT_FIELD) {
bcb54330
NR
46 @Override
47 public Object getObject() {
59597d59
NR
48 Data data = getSelectedData();
49 if (data != null && data.getB64Key() != -1) {
50 setMessage("Cannot modify binary values in RAW mode", true);
51 data = null;
52 }
bed93753 53
59597d59 54 return data;
bcb54330 55 }
ae22c247
NR
56
57 @Override
58 public String getQuestion() {
59 Data data = getData();
60 if (data != null) {
61 return data.getName();
62 }
63
64 return null;
65 }
66
67 @Override
68 public String getDefaultAnswer() {
69 Data data = getData();
70 if (data != null) {
30a4aa17 71 return data.getRawValue().replaceAll("\n", "\\\\n");
ae22c247
NR
72 }
73
74 return null;
75 }
76
77 @Override
78 public String callback(String answer) {
79 Data data = getData();
80 if (data != null) {
30a4aa17 81 data.setRawValue(answer.replaceAll("\\\\n", "\n"));
ae22c247
NR
82 return null;
83 }
84
85 // TODO: i18n
86 return "Cannot modify value";
87 }
bcb54330 88 });
88eb8122
NR
89 actions.add(new KeyAction(Mode.ASK_USER_KEY, 'd',
90 StringId.KEY_ACTION_DELETE) {
176a8327
NR
91 @Override
92 public Object getObject() {
93 return getSelectedData();
94 }
95
96 @Override
97 public String getQuestion() {
98 // TODO i18n
99 return "Delete data? [Y/N]";
100 }
101
102 @Override
103 public String callback(String answer) {
104 if (answer.equalsIgnoreCase("y")) {
105 Data data = getData();
106 if (data != null && data.delete()) {
107 removeItem("x");
108 return null;
109 }
110
111 // TODO i18n
112 return "Cannot delete data";
113 }
114
115 return null;
116 }
117 });
d459d7e1 118 // TODO: ui and i18n
88eb8122 119 actions.add(new KeyAction(Mode.ASK_USER, 'a', StringId.KEY_ACTION_ADD) {
d459d7e1
NR
120 private String name;
121
122 @Override
123 public boolean onAction() {
124 new ActionListDialogBuilder()
125 .setTitle("New data")
126 .setDescription("Choose a data type")
127 .addAction("Email address", new Runnable() {
128 @Override
129 public void run() {
130 name = "EMAIL";
131 }
132 })
133 .addAction("Telephone number", new Runnable() {
134 @Override
135 public void run() {
136 name = "TEL";
137 }
138 })
139 .addAction("Birthday", new Runnable() {
140 @Override
141 public void run() {
142 name = "BDAY";
143 }
144 })
145 .addAction("[other]", new Runnable() {
146 @Override
147 public void run() {
148 name = "";
149 }
150 })
151 .build()
152 .showDialog(
153 new MultiWindowTextGUI(TuiLauncher.getScreen()));
154
155 String name = this.name;
156 this.name = null;
157
158 if (name != null) {
159 if (name.length() > 0) {
160 Data data = new Data(null, name, "", null);
161 getContact().add(data);
162 addItem("x");
163 }
164
165 return (name.length() == 0);
166 }
167
168 return false;
169 }
170
176a8327
NR
171 @Override
172 public Object getObject() {
173 return contact;
174 }
175
176 @Override
177 public String getQuestion() {
178 // TODO i18n
d459d7e1
NR
179 if (name == null)
180 return "Data name: ";
181
182 return null;
176a8327
NR
183 }
184
185 @Override
186 public String callback(String answer) {
d459d7e1
NR
187 if (answer != null & answer.length() > 0) {
188 Data data = new Data(null, answer, "", null);
176a8327
NR
189 getContact().add(data);
190 addItem("x");
191 }
d459d7e1 192
176a8327
NR
193 return null;
194 }
195 });
196 // TODO: use a real UI for this, not a simple text box (a list or
197 // something, maybe a whole new pane?)
e119a1c1 198 actions.add(new KeyAction(Mode.ASK_USER, 't', StringId.DUMMY) {
176a8327
NR
199 private String previous;
200
201 @Override
202 public Object getObject() {
203 return getSelectedData();
204 }
205
206 @Override
207 public String getQuestion() {
208 Data data = getData();
209 if (data != null) {
210 return data.getName();
211 }
212
213 return null;
214 }
215
216 @Override
217 public String getDefaultAnswer() {
218 Data data = getData();
219 if (data != null) {
220 previous = typesToString(data, null).toString();
221 return previous;
222 }
223
224 return null;
225 }
226
227 @Override
228 public String callback(String answer) {
229 Data data = getData();
230 if (data != null) {
231 if (!answer.equals(previous)) {
26d2bd05 232 data.replaceListContent(stringToTypes(answer));
176a8327
NR
233 }
234 return null;
235 }
236
237 // TODO: i18n
238 return "Cannot modify value";
239 }
240 });
e119a1c1 241 actions.add(new KeyAction(Mode.ASK_USER, 'g', StringId.DUMMY) {
176a8327
NR
242 private String previous;
243
244 @Override
245 public Object getObject() {
246 return getSelectedData();
247 }
248
249 @Override
250 public String getQuestion() {
251 Data data = getData();
252 if (data != null) {
253 return data.getName();
254 }
255
256 return null;
257 }
258
259 @Override
260 public String getDefaultAnswer() {
261 Data data = getData();
262 if (data != null) {
263 previous = data.getGroup();
264 return previous;
265 }
266
267 return null;
268 }
269
270 @Override
271 public String callback(String answer) {
272 Data data = getData();
273 if (data != null) {
274 if (!answer.equals(previous)) {
275 data.setGroup(answer);
276 }
277 return null;
278 }
279
280 // TODO: i18n
281 return "Cannot modify group";
282 }
283 });
bcb54330 284 actions.add(new KeyAction(Mode.NONE, KeyType.Tab,
e119a1c1 285 StringId.KEY_ACTION_SWITCH_FORMAT) {
bcb54330
NR
286 @Override
287 public boolean onAction() {
176a8327 288 extMode = !extMode;
bcb54330
NR
289 return false;
290 }
291 });
292
293 return actions;
fae07ea7
NR
294 }
295
fae07ea7
NR
296 @Override
297 public String getTitle() {
0b0b2b0f
NR
298 String title = null;
299
300 if (contact != null) {
301 title = contact.getPreferredDataValue("FN");
302 if (title == null || title.length() == 0)
303 title = contact.getPreferredDataValue("N");
304 }
305
306 return title;
fae07ea7
NR
307 }
308
309 @Override
310 public String move(int x, int y) {
311 // TODO Auto-generated method stub
312 return null;
313 }
f82bad11
NR
314
315 @Override
316 protected List<TextPart> getLabel(int index, int width, boolean selected,
317 boolean focused) {
59597d59 318
f82bad11
NR
319 // TODO: from ini file?
320 int SIZE_COL_1 = 15;
176a8327
NR
321 int SIZE_COL_2_OPT = 10;
322
323 if (!extMode)
324 SIZE_COL_2_OPT = 0;
325
326 List<TextPart> parts = new LinkedList<TextPart>();
327 Data data = null;
328 if (index > -1 && index < contact.size())
329 data = contact.get(index);
330
331 if (data == null)
332 return parts;
f82bad11 333
e119a1c1
NR
334 ColorOption el = (focused && selected) ? ColorOption.CONTACT_LINE_SELECTED
335 : ColorOption.CONTACT_LINE;
336 ColorOption elSep = (focused && selected) ? ColorOption.CONTACT_LINE_SEPARATOR_SELECTED
337 : ColorOption.CONTACT_LINE_SEPARATOR;
338 ColorOption elDirty = (focused && selected) ? ColorOption.CONTACT_LINE_DIRTY_SELECTED
339 : ColorOption.CONTACT_LINE_DIRTY;
f82bad11 340
f82bad11
NR
341 if (data.isDirty()) {
342 parts.add(new TextPart(" ", el));
343 parts.add(new TextPart("*", elDirty));
344 } else {
345 parts.add(new TextPart(" ", elSep));
346 }
347 String name = " " + data.getName() + " ";
348 String value = null;
176a8327 349 String group = null;
f82bad11
NR
350
351 StringBuilder valueBuilder = new StringBuilder(" ");
176a8327 352 if (!extMode) {
59597d59
NR
353 if (data.getB64Key() != -1) {
354 // TODO: i18n
355 valueBuilder.append("<BKey " + data.getB64Key() + ">");
356 } else {
357 valueBuilder.append(data.getValue().replaceAll("\n", "\\\\n"));
358 }
f82bad11 359 if (data.getGroup() != null && data.getGroup().length() > 0) {
8002675f 360 valueBuilder.append(" (");
f82bad11
NR
361 valueBuilder.append(data.getGroup());
362 valueBuilder.append(")");
363 }
176a8327
NR
364 } else {
365 group = data.getGroup();
366 if (group == null)
367 group = "";
368
369 typesToString(data, valueBuilder);
f82bad11
NR
370 }
371 valueBuilder.append(" ");
372
373 value = valueBuilder.toString();
374
7da41ecd
NR
375 name = StringUtils.sanitize(name, Main.isUnicode());
376 value = StringUtils.sanitize(value, Main.isUnicode());
f82bad11
NR
377
378 name = StringUtils.padString(name, SIZE_COL_1);
176a8327 379 group = StringUtils.padString(group, SIZE_COL_2_OPT);
f82bad11 380 value = StringUtils.padString(value, width - SIZE_COL_1
176a8327
NR
381 - SIZE_COL_2_OPT - (extMode ? 2 : 1) * getSeparator().length()
382 - 2);
f82bad11
NR
383
384 parts.add(new TextPart(name, el));
385 parts.add(new TextPart(getSeparator(), elSep));
386 parts.add(new TextPart(value, el));
176a8327
NR
387 if (extMode) {
388 parts.add(new TextPart(getSeparator(), elSep));
389 parts.add(new TextPart(group, el));
390 }
f82bad11
NR
391
392 return parts;
176a8327
NR
393 }
394
395 /**
396 * Return the currently selected {@link Data}.
397 *
398 * @return the currently selected {@link Data}
399 */
400 private Data getSelectedData() {
401 int index = getSelectedIndex();
402 if (index > -1 && index < this.contact.size())
403 return contact.get(index);
404 return null;
405 }
406
407 /**
408 * Serialise the {@link TypeInfo}s in the given {@link Data}.
409 *
410 * @param data
411 * the {@link Data} from which to take the {@link TypeInfo}s
412 * @param builder
bed93753 413 * an optional {@link StringBuilder} to append the serialised
176a8327
NR
414 * version to
415 *
416 * @return the given {@link StringBuilder} or a new one if the given one is
417 * NULL
418 */
419 static private StringBuilder typesToString(Data data, StringBuilder builder) {
420 if (builder == null)
421 builder = new StringBuilder();
422
aecb3399 423 for (TypeInfo type : data) {
176a8327
NR
424 if (builder.length() > 1)
425 builder.append(", ");
426 builder.append(type.getName().replaceAll(",", "\\,"));
427 builder.append(": ");
428 builder.append(type.getValue().replaceAll(":", "\\:"));
429 }
430
431 return builder;
432 }
f82bad11 433
176a8327
NR
434 /**
435 * Unserialise a list of {@link TypeInfo}s.
436 *
437 * @param value
438 * the serialised value
439 *
440 * @return the {@link TypeInfo} in their object form
441 */
442 static private List<TypeInfo> stringToTypes(String value) {
443 List<TypeInfo> infos = new LinkedList<TypeInfo>();
444 if (value == null || value.length() == 0)
445 return infos;
446
447 char previous = '\0';
448 char car = '\0';
449 int done = 0;
450 for (int index = 0; index < value.length(); index++) {
451 car = value.charAt(index);
452 if (index == value.length() - 1) {
453 index++;
454 previous = '\0';
455 car = ',';
456 }
457
458 if (previous != '\\' && car == ',') {
bed93753
NR
459 String subValue = value.substring(done, index);
460 int indexColumn = subValue.indexOf(':');
461 while (indexColumn > 0
462 && subValue.charAt(indexColumn - 1) == '\\') {
463 if (indexColumn == subValue.length() - 1) {
464 indexColumn = -1;
465 } else {
466 indexColumn = subValue.indexOf(':', indexColumn + 1);
467 }
468 }
469
470 String n = "";
471 String v = "";
472 if (indexColumn >= 0) {
473 n = subValue.substring(0, indexColumn).trim();
474 v = subValue.substring(indexColumn + 1)
475 .replaceAll("\\\\:", ":").trim();
476 } else {
477 n = subValue.trim();
478 }
479
480 infos.add(new TypeInfo(n, v));
481
176a8327
NR
482 done = index + 1;
483 }
484
485 previous = car;
486 }
487
488 return infos;
489 }
fae07ea7 490}