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