Fix FN when empty (with a configurable option) + some i18n
[jvcard.git] / src / be / nikiroo / jvcard / tui / panes / ContactDetails.java
CommitLineData
f04d8b1c
NR
1package be.nikiroo.jvcard.tui.panes;
2
3import java.awt.Image;
25232463 4import java.util.LinkedList;
f04d8b1c 5import java.util.List;
3634193b
NR
6import java.util.MissingResourceException;
7import java.util.ResourceBundle;
f04d8b1c 8
f04d8b1c
NR
9import be.nikiroo.jvcard.Contact;
10import be.nikiroo.jvcard.Data;
11import be.nikiroo.jvcard.TypeInfo;
3634193b
NR
12import be.nikiroo.jvcard.resources.Bundles;
13import be.nikiroo.jvcard.resources.StringUtils;
7da41ecd 14import be.nikiroo.jvcard.resources.Trans;
25232463 15import be.nikiroo.jvcard.tui.ImageTextControl;
f04d8b1c
NR
16import be.nikiroo.jvcard.tui.KeyAction;
17import be.nikiroo.jvcard.tui.KeyAction.DataType;
25232463 18import be.nikiroo.jvcard.tui.KeyAction.Mode;
f82bad11 19import be.nikiroo.jvcard.tui.UiColors;
f04d8b1c
NR
20
21import com.googlecode.lanterna.TerminalSize;
22import com.googlecode.lanterna.gui2.BorderLayout;
3634193b 23import com.googlecode.lanterna.gui2.Borders;
f82bad11
NR
24import com.googlecode.lanterna.gui2.Direction;
25import com.googlecode.lanterna.gui2.Label;
26import com.googlecode.lanterna.gui2.LinearLayout;
f04d8b1c 27import com.googlecode.lanterna.gui2.Panel;
25232463 28import com.googlecode.lanterna.input.KeyType;
f04d8b1c
NR
29
30public class ContactDetails extends MainContent {
31 private Contact contact;
ae22c247 32 private Panel top;
f82bad11 33 private ImageTextControl txtImage;
ae22c247
NR
34 private Image image;
35 private boolean fullscreenImage;
f82bad11
NR
36 private Panel infoPanel;
37 private Label note;
30a4aa17
NR
38
39 // from .properties file:
40 private int labelSize = -1;
41 private String infoFormat = "";
42 //
f04d8b1c
NR
43
44 public ContactDetails(Contact contact) {
30a4aa17
NR
45 // Get the .properties info:
46 ResourceBundle map = Bundles.getBundle("display");
47
48 try {
49 labelSize = Integer.parseInt(map
50 .getString("CONTACT_DETAILS_LABEL_WIDTH"));
51
52 } catch (NumberFormatException e) {
53 e.printStackTrace();
54 labelSize = -1;
55 } catch (MissingResourceException e) {
56 labelSize = -1;
57 }
58
59 try {
60 infoFormat = map.getString("CONTACT_DETAILS_INFO");
61 } catch (MissingResourceException e) {
62 e.printStackTrace();
63 }
64 //
3634193b 65
f04d8b1c
NR
66 BorderLayout blayout = new BorderLayout();
67 setLayoutManager(blayout);
68
ae22c247 69 top = new Panel();
f82bad11
NR
70 blayout = new BorderLayout();
71 top.setLayoutManager(blayout);
72
73 infoPanel = new Panel();
74 infoPanel.setLayoutManager(new LinearLayout(Direction.VERTICAL));
75 top.addComponent(infoPanel, BorderLayout.Location.CENTER);
76
77 Panel notePanel = new Panel();
78 notePanel.setLayoutManager(new LinearLayout(Direction.HORIZONTAL));
79
80 notePanel.addComponent(UiColors.Element.VIEW_CONTACT_NOTES_TITLE
81 .createLabel("Notes:"));
82 note = UiColors.Element.VIEW_CONTACT_NORMAL.createLabel("");
83 notePanel.addComponent(note);
84
ae22c247 85 setContact(contact);
f82bad11 86
3634193b
NR
87 addComponent(top.withBorder(Borders.doubleLineBevel()),
88 BorderLayout.Location.TOP);
89 addComponent(notePanel.withBorder(Borders.singleLineBevel()),
90 BorderLayout.Location.CENTER);
ae22c247
NR
91 }
92
f82bad11
NR
93 /**
94 * Change the enclosed {@link Contact} from this {@link ContactDetails}.
2a96e7b2 95 * Also re-set the image.
f82bad11
NR
96 *
97 * @param contact
98 * the new {@link Contact}
99 */
ae22c247 100 public void setContact(Contact contact) {
ae22c247 101 this.contact = contact;
2a96e7b2 102 image = null;
ae22c247 103
2a96e7b2 104 if (contact != null) {
f82bad11
NR
105 infoPanel.removeAllComponents();
106
107 String name = contact.getPreferredDataValue("FN");
f82bad11
NR
108 infoPanel.addComponent(UiColors.Element.VIEW_CONTACT_NAME
109 .createLabel(name));
f82bad11
NR
110 infoPanel.addComponent(UiColors.Element.VIEW_CONTACT_NORMAL
111 .createLabel(""));
3634193b
NR
112
113 // List of infos:
3634193b
NR
114 String[] infos = infoFormat.split("\\|");
115 for (String info : infos) {
116 // # - "=FIELD" will take the preferred value for this field
117 // # - "+FIELD" will take the preferred value for this field and
118 // highlight it
119 // # - "#FIELD" will take all the values with this field's name
120 // # - "*FIELD" will take all the values with this field's name,
121 // highlighting the preferred one
122 // #
123
124 boolean hl = false;
125 boolean all = false;
126 if (info.contains("+") || info.contains("#"))
127 hl = true;
128 if (info.contains("*") || info.contains("#"))
129 all = true;
130
131 if (all || hl || info.contains("=")) {
132 UiColors.Element el = hl ? UiColors.Element.VIEW_CONTACT_HIGHLIGHT
133 : UiColors.Element.VIEW_CONTACT_NORMAL;
134
135 int index = info.indexOf('=');
136 if (index < 0)
137 index = info.indexOf('+');
138 if (index < 0)
139 index = info.indexOf('#');
140 if (index < 0)
141 index = info.indexOf('*');
142
143 String label = info.substring(0, index);
144 String field = info.substring(index + 1);
145
146 if (all) {
147 for (Data data : contact.getData(field)) {
148 if (data.isPreferred()) {
aecb3399
NR
149 infoPanel.addComponent(el
150 .createLabel(StringUtils.padString(
151 label, labelSize)
152 + data.toString()));
3634193b
NR
153 } else {
154 infoPanel
aecb3399
NR
155 .addComponent(UiColors.Element.VIEW_CONTACT_NORMAL
156 .createLabel(StringUtils
157 .padString(label,
158 labelSize)
159 + data.toString()));
3634193b
NR
160 }
161 }
162 } else {
aecb3399
NR
163 String val = contact.getPreferredDataValue(field);
164 if (val == null)
165 val = "";
3634193b 166 infoPanel.addComponent(el.createLabel(StringUtils
aecb3399 167 .padString(label, labelSize) + val));
3634193b
NR
168 }
169 } else {
170 String label = info;
171 infoPanel.addComponent(UiColors.Element.VIEW_CONTACT_NORMAL
172 .createLabel(StringUtils
173 .padString(label, labelSize)));
174 }
175 }
176 // end of list
177
f82bad11
NR
178 infoPanel.addComponent(UiColors.Element.VIEW_CONTACT_NORMAL
179 .createLabel(""));
180
181 String notes = contact.getPreferredDataValue("NOTE");
182 if (notes == null)
183 notes = "";
aecb3399 184 note.setText(notes);
f82bad11 185
f04d8b1c
NR
186 Data photo = contact.getPreferredData("PHOTO");
187 if (photo != null) {
188 TypeInfo encoding = null;
26d254a3 189 for (TypeInfo info : photo) {
f04d8b1c
NR
190 if (info.getName() != null) {
191 if (info.getName().equalsIgnoreCase("ENCODING"))
192 encoding = info;
2a96e7b2
NR
193 // We don't check for the "TYPE" anymore, we just defer
194 // it to ImageIcon
f04d8b1c
NR
195 }
196 }
197
198 if (encoding != null && encoding.getValue() != null
199 && encoding.getValue().equalsIgnoreCase("b")) {
200
1c03abaf 201 try {
26d254a3 202 image = StringUtils.toImage(photo.getValue());
1c03abaf
NR
203 } catch (Exception e) {
204 System.err.println("Cannot parse image for contact: "
205 + contact.getPreferredDataValue("UID"));
206 }
f04d8b1c
NR
207 }
208 }
209 }
210
f82bad11 211 setImage(image);
f04d8b1c 212 }
25232463
NR
213
214 @Override
215 public DataType getDataType() {
216 return DataType.DATA;
217 }
218
219 @Override
220 public List<KeyAction> getKeyBindings() {
221 List<KeyAction> actions = new LinkedList<KeyAction>();
222
25232463
NR
223 actions.add(new KeyAction(Mode.NONE, KeyType.Tab,
224 Trans.StringId.KEY_ACTION_SWITCH_FORMAT) {
225 @Override
226 public boolean onAction() {
f82bad11
NR
227 if (txtImage != null) {
228 txtImage.switchMode();
25232463
NR
229 }
230
231 return false;
232 }
233 });
234 actions.add(new KeyAction(Mode.NONE, 'i',
ae22c247 235 Trans.StringId.KEY_ACTION_INVERT) {
25232463
NR
236 @Override
237 public boolean onAction() {
f82bad11
NR
238 if (txtImage != null) {
239 txtImage.invertColor();
25232463
NR
240 }
241
242 return false;
243 }
244 });
ae22c247
NR
245 actions.add(new KeyAction(Mode.NONE, 'f',
246 Trans.StringId.KEY_ACTION_FULLSCREEN) {
247 @Override
248 public boolean onAction() {
249 fullscreenImage = !fullscreenImage;
250 setImage(image);
251 return false;
252 }
253 });
3634193b
NR
254 // TODO: add "normal" edit
255 actions.add(new KeyAction(Mode.CONTACT_DETAILS_RAW, 'r',
256 Trans.StringId.KEY_ACTION_EDIT_CONTACT_RAW) {
176a8327
NR
257 @Override
258 public Object getObject() {
259 return contact;
260 }
261 });
25232463
NR
262
263 return actions;
264 }
ae22c247
NR
265
266 @Override
267 public synchronized Panel setSize(TerminalSize size) {
268 super.setSize(size);
269 setImage(image);
270 return this;
271 }
272
273 /**
f82bad11
NR
274 * Set the {@link Image} to render and refresh it to the current size
275 * constraints.
ae22c247
NR
276 *
277 * @param image
278 * the new {@link Image}
279 */
280 private void setImage(Image image) {
281 this.image = image;
282
f82bad11
NR
283 if (txtImage != null && top.containsComponent(txtImage))
284 top.removeComponent(txtImage);
285
ae22c247
NR
286 TerminalSize size = getTxtSize();
287 if (size != null) {
f82bad11
NR
288 if (txtImage != null)
289 txtImage.setSize(size);
ae22c247 290 else
f82bad11 291 txtImage = new ImageTextControl(image, size);
ae22c247
NR
292 }
293
f82bad11
NR
294 if (size != null) {
295 top.addComponent(txtImage, BorderLayout.Location.LEFT);
296 }
ae22c247 297
f82bad11 298 invalidate();
ae22c247
NR
299 }
300
301 /**
302 * Compute the size to use for the {@link Image} text rendering. Return NULL
303 * in case of error.
304 *
305 * @return the {@link TerminalSize} to use or NULL if it is not possible
306 */
307 private TerminalSize getTxtSize() {
308 if (image != null && getSize() != null && getSize().getColumns() > 0
309 && getSize().getRows() > 0) {
310 if (fullscreenImage) {
311 return getSize();
312 } else {
f82bad11
NR
313 // TODO: configure size?
314 int w = getSize().getColumns() - 40;
aecb3399 315 int h = getSize().getRows() - 9;
f82bad11
NR
316 if (w <= 0 || h <= 0)
317 return null;
318
319 return new TerminalSize(w, h);
ae22c247
NR
320 }
321 }
322
323 return null;
324 }
f04d8b1c 325}