New launcher class to start all 3 modes:
[jvcard.git] / src / be / nikiroo / jvcard / tui / panes / ContactDetails.java
CommitLineData
f04d8b1c
NR
1package be.nikiroo.jvcard.tui.panes;
2
3import java.awt.Image;
1c03abaf 4import java.io.ByteArrayInputStream;
25232463 5import java.util.LinkedList;
f04d8b1c
NR
6import java.util.List;
7
1c03abaf 8import javax.imageio.ImageIO;
6b6a62ca 9import javax.xml.bind.DatatypeConverter;
f04d8b1c
NR
10
11import be.nikiroo.jvcard.Contact;
12import be.nikiroo.jvcard.Data;
13import be.nikiroo.jvcard.TypeInfo;
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;
f82bad11
NR
23import com.googlecode.lanterna.gui2.Direction;
24import com.googlecode.lanterna.gui2.Label;
25import com.googlecode.lanterna.gui2.LinearLayout;
f04d8b1c 26import com.googlecode.lanterna.gui2.Panel;
25232463 27import com.googlecode.lanterna.input.KeyType;
f04d8b1c
NR
28
29public class ContactDetails extends MainContent {
30 private Contact contact;
ae22c247 31 private Panel top;
f82bad11 32 private ImageTextControl txtImage;
ae22c247
NR
33 private Image image;
34 private boolean fullscreenImage;
f82bad11
NR
35 private Panel infoPanel;
36 private Label note;
f04d8b1c
NR
37
38 public ContactDetails(Contact contact) {
f04d8b1c
NR
39 BorderLayout blayout = new BorderLayout();
40 setLayoutManager(blayout);
41
ae22c247 42 top = new Panel();
f82bad11
NR
43 blayout = new BorderLayout();
44 top.setLayoutManager(blayout);
45
46 infoPanel = new Panel();
47 infoPanel.setLayoutManager(new LinearLayout(Direction.VERTICAL));
48 top.addComponent(infoPanel, BorderLayout.Location.CENTER);
49
50 Panel notePanel = new Panel();
51 notePanel.setLayoutManager(new LinearLayout(Direction.HORIZONTAL));
52
53 notePanel.addComponent(UiColors.Element.VIEW_CONTACT_NOTES_TITLE
54 .createLabel("Notes:"));
55 note = UiColors.Element.VIEW_CONTACT_NORMAL.createLabel("");
56 notePanel.addComponent(note);
57
ae22c247 58 setContact(contact);
f82bad11 59
ae22c247 60 addComponent(top, BorderLayout.Location.TOP);
f82bad11 61 addComponent(notePanel, BorderLayout.Location.CENTER);
ae22c247
NR
62 }
63
f82bad11
NR
64 /**
65 * Change the enclosed {@link Contact} from this {@link ContactDetails}.
2a96e7b2 66 * Also re-set the image.
f82bad11
NR
67 *
68 * @param contact
69 * the new {@link Contact}
70 */
ae22c247 71 public void setContact(Contact contact) {
ae22c247 72 this.contact = contact;
2a96e7b2 73 image = null;
ae22c247 74
2a96e7b2 75 if (contact != null) {
f82bad11
NR
76 infoPanel.removeAllComponents();
77
78 String name = contact.getPreferredDataValue("FN");
79 if (name == null || name.length() == 0) {
80 // TODO format it ourself
81 name = contact.getPreferredDataValue("N");
82 }
83
84 // TODO: i18n + do it properly
85 infoPanel.addComponent(UiColors.Element.VIEW_CONTACT_NAME
86 .createLabel(name));
87
88 infoPanel.addComponent(UiColors.Element.VIEW_CONTACT_NORMAL
89 .createLabel(""));
90 infoPanel.addComponent(UiColors.Element.VIEW_CONTACT_NORMAL
91 .createLabel("Phone: "
92 + contact.getPreferredDataValue("TEL")));
93 infoPanel.addComponent(UiColors.Element.VIEW_CONTACT_NORMAL
94 .createLabel("eMail: "
95 + contact.getPreferredDataValue("EMAIL")));
96 infoPanel.addComponent(UiColors.Element.VIEW_CONTACT_NORMAL
97 .createLabel(""));
98
99 String notes = contact.getPreferredDataValue("NOTE");
100 if (notes == null)
101 notes = "";
102 note.setText(notes.replaceAll("\\\\n", "\n"));
103
f04d8b1c
NR
104 Data photo = contact.getPreferredData("PHOTO");
105 if (photo != null) {
106 TypeInfo encoding = null;
78e4af97
NR
107 for (int index = 0; index < photo.size(); index++) {
108 TypeInfo info = photo.get(index);
f04d8b1c
NR
109 if (info.getName() != null) {
110 if (info.getName().equalsIgnoreCase("ENCODING"))
111 encoding = info;
2a96e7b2
NR
112 // We don't check for the "TYPE" anymore, we just defer
113 // it to ImageIcon
f04d8b1c
NR
114 }
115 }
116
117 if (encoding != null && encoding.getValue() != null
118 && encoding.getValue().equalsIgnoreCase("b")) {
119
1c03abaf
NR
120 try {
121 image = ImageIO.read(new ByteArrayInputStream(
122 DatatypeConverter.parseBase64Binary(photo
123 .getValue())));
124 image.toString();
125 } catch (Exception e) {
126 System.err.println("Cannot parse image for contact: "
127 + contact.getPreferredDataValue("UID"));
128 }
f04d8b1c
NR
129 }
130 }
131 }
132
f82bad11 133 setImage(image);
f04d8b1c 134 }
25232463
NR
135
136 @Override
137 public DataType getDataType() {
138 return DataType.DATA;
139 }
140
141 @Override
142 public List<KeyAction> getKeyBindings() {
143 List<KeyAction> actions = new LinkedList<KeyAction>();
144
145 // TODO
146 actions.add(new KeyAction(Mode.NONE, KeyType.Tab,
147 Trans.StringId.KEY_ACTION_SWITCH_FORMAT) {
148 @Override
149 public boolean onAction() {
f82bad11
NR
150 if (txtImage != null) {
151 txtImage.switchMode();
25232463
NR
152 }
153
154 return false;
155 }
156 });
157 actions.add(new KeyAction(Mode.NONE, 'i',
ae22c247 158 Trans.StringId.KEY_ACTION_INVERT) {
25232463
NR
159 @Override
160 public boolean onAction() {
f82bad11
NR
161 if (txtImage != null) {
162 txtImage.invertColor();
25232463
NR
163 }
164
165 return false;
166 }
167 });
ae22c247
NR
168 actions.add(new KeyAction(Mode.NONE, 'f',
169 Trans.StringId.KEY_ACTION_FULLSCREEN) {
170 @Override
171 public boolean onAction() {
172 fullscreenImage = !fullscreenImage;
173 setImage(image);
174 return false;
175 }
176 });
176a8327
NR
177 // TODO: add "normal" edit and remove this one into RAW edit
178 actions.add(new KeyAction(Mode.CONTACT_DETAILS_RAW, 'e',
179 Trans.StringId.KEY_ACTION_EDIT_CONTACT) {
180 @Override
181 public Object getObject() {
182 return contact;
183 }
184 });
25232463
NR
185
186 return actions;
187 }
ae22c247
NR
188
189 @Override
190 public synchronized Panel setSize(TerminalSize size) {
191 super.setSize(size);
192 setImage(image);
193 return this;
194 }
195
196 /**
f82bad11
NR
197 * Set the {@link Image} to render and refresh it to the current size
198 * constraints.
ae22c247
NR
199 *
200 * @param image
201 * the new {@link Image}
202 */
203 private void setImage(Image image) {
204 this.image = image;
205
f82bad11
NR
206 if (txtImage != null && top.containsComponent(txtImage))
207 top.removeComponent(txtImage);
208
ae22c247
NR
209 TerminalSize size = getTxtSize();
210 if (size != null) {
f82bad11
NR
211 if (txtImage != null)
212 txtImage.setSize(size);
ae22c247 213 else
f82bad11 214 txtImage = new ImageTextControl(image, size);
ae22c247
NR
215 }
216
f82bad11
NR
217 if (size != null) {
218 top.addComponent(txtImage, BorderLayout.Location.LEFT);
219 }
ae22c247 220
f82bad11 221 invalidate();
ae22c247
NR
222 }
223
224 /**
225 * Compute the size to use for the {@link Image} text rendering. Return NULL
226 * in case of error.
227 *
228 * @return the {@link TerminalSize} to use or NULL if it is not possible
229 */
230 private TerminalSize getTxtSize() {
231 if (image != null && getSize() != null && getSize().getColumns() > 0
232 && getSize().getRows() > 0) {
233 if (fullscreenImage) {
234 return getSize();
235 } else {
f82bad11
NR
236 // TODO: configure size?
237 int w = getSize().getColumns() - 40;
238 int h = getSize().getRows() - 5;
239 if (w <= 0 || h <= 0)
240 return null;
241
242 return new TerminalSize(w, h);
ae22c247
NR
243 }
244 }
245
246 return null;
247 }
f04d8b1c 248}