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; |
176a8327 | 9 | import be.nikiroo.jvcard.Data; |
7da41ecd | 10 | import be.nikiroo.jvcard.launcher.Main; |
d56a0ad4 | 11 | import be.nikiroo.jvcard.resources.Bundles; |
7da41ecd | 12 | import be.nikiroo.jvcard.resources.Trans; |
fae07ea7 | 13 | import be.nikiroo.jvcard.tui.KeyAction; |
fae07ea7 NR |
14 | import be.nikiroo.jvcard.tui.KeyAction.DataType; |
15 | import be.nikiroo.jvcard.tui.KeyAction.Mode; | |
9c8baf0c | 16 | import be.nikiroo.jvcard.tui.UiColors.Element; |
fae07ea7 NR |
17 | |
18 | import com.googlecode.lanterna.input.KeyType; | |
19 | ||
20 | public 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 NR |
58 | if (filter == null |
59 | || c.toString(format).toLowerCase() | |
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 | ||
133 | return Main.trans(Trans.StringId.CONFIRM_USER_DELETE_CONTACT, contactName); | |
ae22c247 NR |
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()) { | |
176a8327 | 141 | removeItem("x"); |
ae22c247 NR |
142 | return null; |
143 | } | |
144 | ||
9b8cb729 NR |
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); | |
ae22c247 NR |
151 | } |
152 | ||
153 | return null; | |
154 | } | |
bcb54330 | 155 | }); |
ae22c247 | 156 | actions.add(new KeyAction(Mode.ASK_USER_KEY, 's', |
bcb54330 | 157 | Trans.StringId.KEY_ACTION_SAVE_CARD) { |
fae07ea7 NR |
158 | @Override |
159 | public Object getObject() { | |
bcb54330 | 160 | return card; |
fae07ea7 | 161 | } |
ae22c247 NR |
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 | ||
fae07ea7 NR |
187 | }); |
188 | actions.add(new KeyAction(Mode.CONTACT_DETAILS, KeyType.Enter, | |
189 | Trans.StringId.KEY_ACTION_VIEW_CONTACT) { | |
190 | @Override | |
191 | public Object getObject() { | |
bcb54330 | 192 | return getSelectedContact(); |
fae07ea7 NR |
193 | } |
194 | }); | |
bcb54330 | 195 | actions.add(new KeyAction(Mode.NONE, KeyType.Tab, |
fae07ea7 NR |
196 | Trans.StringId.KEY_ACTION_SWITCH_FORMAT) { |
197 | @Override | |
198 | public boolean onAction() { | |
199 | switchFormat(); | |
200 | return false; | |
201 | } | |
202 | }); | |
ae22c247 NR |
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 | }); | |
fae07ea7 NR |
223 | |
224 | return actions; | |
225 | } | |
226 | ||
227 | @Override | |
228 | public DataType getDataType() { | |
229 | return DataType.CARD; | |
230 | } | |
231 | ||
fae07ea7 NR |
232 | @Override |
233 | public String getTitle() { | |
0b0b2b0f | 234 | if (card != null) { |
ae22c247 NR |
235 | if (filter != null) |
236 | return card.getName() + " [" + filter + "]"; | |
0b0b2b0f NR |
237 | return card.getName(); |
238 | } | |
239 | ||
fae07ea7 NR |
240 | return null; |
241 | } | |
242 | ||
243 | @Override | |
9c8baf0c NR |
244 | protected List<TextPart> getLabel(int index, int width, boolean selected, |
245 | boolean focused) { | |
bcb54330 NR |
246 | List<TextPart> parts = new LinkedList<TextPart>(); |
247 | ||
248 | Contact contact = null; | |
ae22c247 NR |
249 | if (index > -1 && index < contacts.size()) |
250 | contact = contacts.get(index); | |
bcb54330 NR |
251 | |
252 | if (contact == null) | |
253 | return parts; | |
9c8baf0c NR |
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; | |
0b0b2b0f NR |
259 | Element elDirty = (focused && selected) ? Element.CONTACT_LINE_DIRTY_SELECTED |
260 | : Element.CONTACT_LINE_DIRTY; | |
9c8baf0c | 261 | |
0b0b2b0f | 262 | width -= 2; // dirty mark space |
9c8baf0c | 263 | |
bcb54330 | 264 | String[] array = contact.toStringArray(format, getSeparator(), " ", |
7da41ecd | 265 | width, Main.isUnicode()); |
0b0b2b0f | 266 | |
bcb54330 | 267 | if (contact.isDirty()) { |
0b0b2b0f NR |
268 | parts.add(new TextPart(" ", el)); |
269 | parts.add(new TextPart("*", elDirty)); | |
270 | } else { | |
271 | parts.add(new TextPart(" ", elSep)); | |
9c8baf0c NR |
272 | } |
273 | ||
0b0b2b0f NR |
274 | boolean separator = false; |
275 | for (String str : array) { | |
276 | parts.add(new TextPart(str, (separator ? elSep : el))); | |
277 | separator = !separator; | |
278 | } | |
9c8baf0c NR |
279 | |
280 | return parts; | |
fae07ea7 NR |
281 | } |
282 | ||
bcb54330 NR |
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(); | |
ae22c247 NR |
290 | if (index > -1 && index < contacts.size()) |
291 | return contacts.get(index); | |
bcb54330 NR |
292 | return null; |
293 | } | |
294 | ||
fae07ea7 NR |
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 | } |