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