New option: save/load contacts' photos
[jvcard.git] / src / be / nikiroo / jvcard / tui / panes / ContactList.java
CommitLineData
fae07ea7
NR
1package be.nikiroo.jvcard.tui.panes;
2
ae22c247 3import java.io.IOException;
fae07ea7
NR
4import java.util.LinkedList;
5import java.util.List;
6
7import be.nikiroo.jvcard.Card;
0b0b2b0f 8import be.nikiroo.jvcard.Contact;
176a8327 9import be.nikiroo.jvcard.Data;
7da41ecd 10import be.nikiroo.jvcard.launcher.Main;
d56a0ad4 11import be.nikiroo.jvcard.resources.Bundles;
7da41ecd 12import be.nikiroo.jvcard.resources.Trans;
fae07ea7 13import be.nikiroo.jvcard.tui.KeyAction;
fae07ea7
NR
14import be.nikiroo.jvcard.tui.KeyAction.DataType;
15import be.nikiroo.jvcard.tui.KeyAction.Mode;
9c8baf0c 16import be.nikiroo.jvcard.tui.UiColors.Element;
fae07ea7
NR
17
18import com.googlecode.lanterna.input.KeyType;
19
20public class ContactList extends MainContentList {
21 private Card card;
ae22c247
NR
22 private List<Contact> contacts;
23 private String filter;
fae07ea7 24
d56a0ad4
NR
25 private List<String> formats;
26 private int selectedFormat;
27 private String format;
fae07ea7
NR
28
29 public ContactList(Card card) {
d56a0ad4
NR
30 formats = new LinkedList<String>();
31 for (String format : Bundles.getBundle("display")
32 .getString("CONTACT_LIST_FORMAT").split(",")) {
33 formats.add(format);
34 }
35
36 selectedFormat = -1;
fae07ea7
NR
37 switchFormat();
38
39 setCard(card);
40 }
41
42 /**
ae22c247
NR
43 * Change the currently displayed contacts card, only allowing those that
44 * satisfy the current filter.
fae07ea7
NR
45 *
46 * @param card
47 * the new {@link Card}
ae22c247
NR
48 * @param filter
49 * the text filter or NULL for all contacts
fae07ea7
NR
50 */
51 public void setCard(Card card) {
52 clearItems();
53 this.card = card;
ae22c247 54 this.contacts = new LinkedList<Contact>();
fae07ea7
NR
55
56 if (card != null) {
26d2bd05 57 for (Contact c : card) {
ae22c247 58 if (filter == null
26d254a3 59 || c.toString(format, "|").toLowerCase()
ae22c247 60 .contains(filter.toLowerCase())) {
176a8327 61 addItem("x");
ae22c247
NR
62 contacts.add(c);
63 }
fae07ea7
NR
64 }
65 }
66
67 setSelectedIndex(0);
68 }
69
bcb54330
NR
70 @Override
71 public void refreshData() {
72 int index = getSelectedIndex();
73 setCard(card);
ae22c247
NR
74 if (index >= contacts.size())
75 index = contacts.size() - 1;
bcb54330 76 setSelectedIndex(index);
ae22c247 77
bcb54330
NR
78 super.refreshData();
79 }
80
fae07ea7
NR
81 @Override
82 public String getExitWarning() {
83 if (card != null && card.isDirty()) {
bcb54330 84 return "Ignore unsaved changes? [Y/N]";
fae07ea7 85 }
bcb54330 86
fae07ea7
NR
87 return null;
88 }
89
90 @Override
91 public List<KeyAction> getKeyBindings() {
92 List<KeyAction> actions = new LinkedList<KeyAction>();
93
176a8327 94 // TODO ui
9b8cb729
NR
95 actions.add(new KeyAction(Mode.ASK_USER, 'a',
96 Trans.StringId.KEY_ACTION_ADD) {
0b0b2b0f 97 @Override
bcb54330 98 public Object getObject() {
176a8327
NR
99 return card;
100 }
101
102 @Override
103 public String getQuestion() {
9b8cb729 104 return Main.trans(Trans.StringId.ASK_USER_CONTACT_NAME);
176a8327
NR
105 }
106
107 @Override
108 public String callback(String answer) {
109 if (answer.length() > 0) {
110 List<Data> datas = new LinkedList<Data>();
111 datas.add(new Data(null, "FN", answer, null));
112 getCard().add(new Contact(datas));
113 addItem("x");
114 }
115
116 return null;
0b0b2b0f
NR
117 }
118 });
ae22c247 119 actions.add(new KeyAction(Mode.ASK_USER_KEY, 'd',
bcb54330
NR
120 Trans.StringId.KEY_ACTION_DELETE_CONTACT) {
121 @Override
122 public Object getObject() {
123 return getSelectedContact();
124 }
ae22c247
NR
125
126 @Override
127 public String getQuestion() {
9b8cb729
NR
128 Contact contact = getSelectedContact();
129 String contactName = "null";
130 if (contact != null)
131 contactName = "" + contact.getPreferredDataValue("FN");
132
26d254a3
NR
133 return Main.trans(Trans.StringId.CONFIRM_USER_DELETE_CONTACT,
134 contactName);
ae22c247
NR
135 }
136
137 @Override
138 public String callback(String answer) {
139 if (answer.equalsIgnoreCase("y")) {
140 Contact contact = getSelectedContact();
141 if (contact != null && contact.delete()) {
176a8327 142 removeItem("x");
ae22c247
NR
143 return null;
144 }
145
9b8cb729
NR
146 String contactName = "null";
147 if (contact != null)
148 contactName = "" + contact.getPreferredDataValue("FN");
149
150 return Main.trans(Trans.StringId.ERR_CANNOT_DELETE_CONTACT,
151 contactName);
ae22c247
NR
152 }
153
154 return null;
155 }
bcb54330 156 });
ae22c247 157 actions.add(new KeyAction(Mode.ASK_USER_KEY, 's',
bcb54330 158 Trans.StringId.KEY_ACTION_SAVE_CARD) {
fae07ea7
NR
159 @Override
160 public Object getObject() {
bcb54330 161 return card;
fae07ea7 162 }
ae22c247
NR
163
164 @Override
165 public String getQuestion() {
166 return "Save changes? [Y/N]";
167 }
168
169 @Override
170 public String callback(String answer) {
171 if (answer.equalsIgnoreCase("y")) {
172 boolean ok = false;
173 try {
174 if (card != null && card.save())
175 ok = true;
176 } catch (IOException ioe) {
177 ioe.printStackTrace();
178 }
179
180 if (!ok) {
181 return "Cannot save to file";
182 }
183 }
184
185 return null;
186 }
187
fae07ea7
NR
188 });
189 actions.add(new KeyAction(Mode.CONTACT_DETAILS, KeyType.Enter,
190 Trans.StringId.KEY_ACTION_VIEW_CONTACT) {
191 @Override
192 public Object getObject() {
bcb54330 193 return getSelectedContact();
fae07ea7
NR
194 }
195 });
bcb54330 196 actions.add(new KeyAction(Mode.NONE, KeyType.Tab,
fae07ea7
NR
197 Trans.StringId.KEY_ACTION_SWITCH_FORMAT) {
198 @Override
199 public boolean onAction() {
200 switchFormat();
201 return false;
202 }
203 });
ae22c247
NR
204 actions.add(new KeyAction(Mode.ASK_USER, 'w',
205 Trans.StringId.KEY_ACTION_SEARCH) {
206
207 @Override
208 public String getQuestion() {
209 return "Search:";
210 }
211
212 @Override
213 public String getDefaultAnswer() {
214 return filter;
215 }
216
217 @Override
218 public String callback(String answer) {
219 filter = answer;
220 setCard(card);
221 return null;
222 }
223 });
fae07ea7
NR
224
225 return actions;
226 }
227
228 @Override
229 public DataType getDataType() {
230 return DataType.CARD;
231 }
232
fae07ea7
NR
233 @Override
234 public String getTitle() {
0b0b2b0f 235 if (card != null) {
ae22c247
NR
236 if (filter != null)
237 return card.getName() + " [" + filter + "]";
0b0b2b0f
NR
238 return card.getName();
239 }
240
fae07ea7
NR
241 return null;
242 }
243
244 @Override
9c8baf0c
NR
245 protected List<TextPart> getLabel(int index, int width, boolean selected,
246 boolean focused) {
bcb54330
NR
247 List<TextPart> parts = new LinkedList<TextPart>();
248
249 Contact contact = null;
ae22c247
NR
250 if (index > -1 && index < contacts.size())
251 contact = contacts.get(index);
bcb54330
NR
252
253 if (contact == null)
254 return parts;
9c8baf0c
NR
255
256 Element el = (focused && selected) ? Element.CONTACT_LINE_SELECTED
257 : Element.CONTACT_LINE;
258 Element elSep = (focused && selected) ? Element.CONTACT_LINE_SEPARATOR_SELECTED
259 : Element.CONTACT_LINE_SEPARATOR;
0b0b2b0f
NR
260 Element elDirty = (focused && selected) ? Element.CONTACT_LINE_DIRTY_SELECTED
261 : Element.CONTACT_LINE_DIRTY;
9c8baf0c 262
0b0b2b0f 263 width -= 2; // dirty mark space
9c8baf0c 264
bcb54330 265 String[] array = contact.toStringArray(format, getSeparator(), " ",
7da41ecd 266 width, Main.isUnicode());
0b0b2b0f 267
bcb54330 268 if (contact.isDirty()) {
0b0b2b0f
NR
269 parts.add(new TextPart(" ", el));
270 parts.add(new TextPart("*", elDirty));
271 } else {
272 parts.add(new TextPart(" ", elSep));
9c8baf0c
NR
273 }
274
0b0b2b0f
NR
275 boolean separator = false;
276 for (String str : array) {
277 parts.add(new TextPart(str, (separator ? elSep : el)));
278 separator = !separator;
279 }
9c8baf0c
NR
280
281 return parts;
fae07ea7
NR
282 }
283
bcb54330
NR
284 /**
285 * Return the currently selected {@link Contact}.
286 *
287 * @return the currently selected {@link Contact}
288 */
289 private Contact getSelectedContact() {
290 int index = getSelectedIndex();
ae22c247
NR
291 if (index > -1 && index < contacts.size())
292 return contacts.get(index);
bcb54330
NR
293 return null;
294 }
295
fae07ea7
NR
296 private void switchFormat() {
297 if (formats.size() == 0)
298 return;
299
300 selectedFormat++;
301 if (selectedFormat >= formats.size()) {
302 selectedFormat = 0;
303 }
304
305 format = formats.get(selectedFormat);
306
307 invalidate();
308 }
309}