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