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