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