Commit | Line | Data |
---|---|---|
fae07ea7 NR |
1 | package be.nikiroo.jvcard.tui.panes; |
2 | ||
ae22c247 | 3 | import java.io.IOException; |
fae07ea7 NR |
4 | import java.util.LinkedList; |
5 | import java.util.List; | |
6 | ||
7 | import be.nikiroo.jvcard.Card; | |
0b0b2b0f | 8 | import be.nikiroo.jvcard.Contact; |
fae07ea7 NR |
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; | |
9c8baf0c | 14 | import be.nikiroo.jvcard.tui.UiColors.Element; |
fae07ea7 NR |
15 | |
16 | import com.googlecode.lanterna.input.KeyType; | |
17 | ||
18 | public class ContactList extends MainContentList { | |
19 | private Card card; | |
ae22c247 NR |
20 | private List<Contact> contacts; |
21 | private String filter; | |
fae07ea7 NR |
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 | /** | |
ae22c247 NR |
40 | * Change the currently displayed contacts card, only allowing those that |
41 | * satisfy the current filter. | |
fae07ea7 NR |
42 | * |
43 | * @param card | |
44 | * the new {@link Card} | |
ae22c247 NR |
45 | * @param filter |
46 | * the text filter or NULL for all contacts | |
fae07ea7 NR |
47 | */ |
48 | public void setCard(Card card) { | |
49 | clearItems(); | |
50 | this.card = card; | |
ae22c247 | 51 | this.contacts = new LinkedList<Contact>(); |
fae07ea7 NR |
52 | |
53 | if (card != null) { | |
54 | for (int i = 0; i < card.getContacts().size(); i++) { | |
ae22c247 NR |
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 | } | |
fae07ea7 NR |
62 | } |
63 | } | |
64 | ||
65 | setSelectedIndex(0); | |
66 | } | |
67 | ||
bcb54330 NR |
68 | @Override |
69 | public void refreshData() { | |
70 | int index = getSelectedIndex(); | |
71 | setCard(card); | |
ae22c247 NR |
72 | if (index >= contacts.size()) |
73 | index = contacts.size() - 1; | |
bcb54330 | 74 | setSelectedIndex(index); |
ae22c247 | 75 | |
bcb54330 NR |
76 | super.refreshData(); |
77 | } | |
78 | ||
fae07ea7 NR |
79 | @Override |
80 | public String getExitWarning() { | |
81 | if (card != null && card.isDirty()) { | |
bcb54330 | 82 | return "Ignore unsaved changes? [Y/N]"; |
fae07ea7 | 83 | } |
bcb54330 | 84 | |
fae07ea7 NR |
85 | return null; |
86 | } | |
87 | ||
88 | @Override | |
89 | public List<KeyAction> getKeyBindings() { | |
90 | List<KeyAction> actions = new LinkedList<KeyAction>(); | |
91 | ||
296a0b75 | 92 | // TODO add |
f04d8b1c | 93 | actions.add(new KeyAction(Mode.CONTACT_DETAILS_RAW, 'e', |
bcb54330 | 94 | Trans.StringId.KEY_ACTION_EDIT_CONTACT) { |
0b0b2b0f | 95 | @Override |
bcb54330 NR |
96 | public Object getObject() { |
97 | return getSelectedContact(); | |
0b0b2b0f NR |
98 | } |
99 | }); | |
ae22c247 | 100 | actions.add(new KeyAction(Mode.ASK_USER_KEY, 'd', |
bcb54330 NR |
101 | Trans.StringId.KEY_ACTION_DELETE_CONTACT) { |
102 | @Override | |
103 | public Object getObject() { | |
104 | return getSelectedContact(); | |
105 | } | |
ae22c247 NR |
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 | } | |
bcb54330 | 127 | }); |
ae22c247 | 128 | actions.add(new KeyAction(Mode.ASK_USER_KEY, 's', |
bcb54330 | 129 | Trans.StringId.KEY_ACTION_SAVE_CARD) { |
fae07ea7 NR |
130 | @Override |
131 | public Object getObject() { | |
bcb54330 | 132 | return card; |
fae07ea7 | 133 | } |
ae22c247 NR |
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 | ||
fae07ea7 NR |
159 | }); |
160 | actions.add(new KeyAction(Mode.CONTACT_DETAILS, KeyType.Enter, | |
161 | Trans.StringId.KEY_ACTION_VIEW_CONTACT) { | |
162 | @Override | |
163 | public Object getObject() { | |
bcb54330 | 164 | return getSelectedContact(); |
fae07ea7 NR |
165 | } |
166 | }); | |
bcb54330 | 167 | actions.add(new KeyAction(Mode.NONE, KeyType.Tab, |
fae07ea7 NR |
168 | Trans.StringId.KEY_ACTION_SWITCH_FORMAT) { |
169 | @Override | |
170 | public boolean onAction() { | |
171 | switchFormat(); | |
172 | return false; | |
173 | } | |
174 | }); | |
ae22c247 NR |
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 | }); | |
fae07ea7 NR |
195 | |
196 | return actions; | |
197 | } | |
198 | ||
199 | @Override | |
200 | public DataType getDataType() { | |
201 | return DataType.CARD; | |
202 | } | |
203 | ||
fae07ea7 NR |
204 | @Override |
205 | public String getTitle() { | |
0b0b2b0f | 206 | if (card != null) { |
ae22c247 NR |
207 | if (filter != null) |
208 | return card.getName() + " [" + filter + "]"; | |
0b0b2b0f NR |
209 | return card.getName(); |
210 | } | |
211 | ||
fae07ea7 NR |
212 | return null; |
213 | } | |
214 | ||
215 | @Override | |
9c8baf0c NR |
216 | protected List<TextPart> getLabel(int index, int width, boolean selected, |
217 | boolean focused) { | |
bcb54330 NR |
218 | List<TextPart> parts = new LinkedList<TextPart>(); |
219 | ||
220 | Contact contact = null; | |
ae22c247 NR |
221 | if (index > -1 && index < contacts.size()) |
222 | contact = contacts.get(index); | |
bcb54330 NR |
223 | |
224 | if (contact == null) | |
225 | return parts; | |
9c8baf0c NR |
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; | |
0b0b2b0f NR |
231 | Element elDirty = (focused && selected) ? Element.CONTACT_LINE_DIRTY_SELECTED |
232 | : Element.CONTACT_LINE_DIRTY; | |
9c8baf0c | 233 | |
0b0b2b0f | 234 | width -= 2; // dirty mark space |
9c8baf0c | 235 | |
bcb54330 | 236 | String[] array = contact.toStringArray(format, getSeparator(), " ", |
296a0b75 | 237 | width, UiColors.getInstance().isUnicode()); |
0b0b2b0f | 238 | |
bcb54330 | 239 | if (contact.isDirty()) { |
0b0b2b0f NR |
240 | parts.add(new TextPart(" ", el)); |
241 | parts.add(new TextPart("*", elDirty)); | |
242 | } else { | |
243 | parts.add(new TextPart(" ", elSep)); | |
9c8baf0c NR |
244 | } |
245 | ||
0b0b2b0f NR |
246 | boolean separator = false; |
247 | for (String str : array) { | |
248 | parts.add(new TextPart(str, (separator ? elSep : el))); | |
249 | separator = !separator; | |
250 | } | |
9c8baf0c NR |
251 | |
252 | return parts; | |
fae07ea7 NR |
253 | } |
254 | ||
bcb54330 NR |
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(); | |
ae22c247 NR |
262 | if (index > -1 && index < contacts.size()) |
263 | return contacts.get(index); | |
bcb54330 NR |
264 | return null; |
265 | } | |
266 | ||
fae07ea7 NR |
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 | } |