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