08df4034165c761931a0fedebcf5eebf241d0058
[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
170 return actions;
171 }
172
173 @Override
174 public synchronized Panel setSize(TerminalSize size) {
175 super.setSize(size);
176 setImage(image);
177 return this;
178 }
179
180 /**
181 * Set the {@link Image} to render and refresh it to the current size
182 * constraints.
183 *
184 * @param image
185 * the new {@link Image}
186 */
187 private void setImage(Image image) {
188 this.image = image;
189
190 if (txtImage != null && top.containsComponent(txtImage))
191 top.removeComponent(txtImage);
192
193 TerminalSize size = getTxtSize();
194 if (size != null) {
195 if (txtImage != null)
196 txtImage.setSize(size);
197 else
198 txtImage = new ImageTextControl(image, size);
199 }
200
201 if (size != null) {
202 top.addComponent(txtImage, BorderLayout.Location.LEFT);
203 }
204
205 invalidate();
206 }
207
208 /**
209 * Compute the size to use for the {@link Image} text rendering. Return NULL
210 * in case of error.
211 *
212 * @return the {@link TerminalSize} to use or NULL if it is not possible
213 */
214 private TerminalSize getTxtSize() {
215 if (image != null && getSize() != null && getSize().getColumns() > 0
216 && getSize().getRows() > 0) {
217 if (fullscreenImage) {
218 return getSize();
219 } else {
220 // TODO: configure size?
221 int w = getSize().getColumns() - 40;
222 int h = getSize().getRows() - 5;
223 if (w <= 0 || h <= 0)
224 return null;
225
226 return new TerminalSize(w, h);
227 }
228 }
229
230 return null;
231 }
232 }