1 package be
.nikiroo
.jvcard
.tui
.panes
;
4 import java
.util
.LinkedList
;
6 import java
.util
.MissingResourceException
;
7 import java
.util
.ResourceBundle
;
9 import be
.nikiroo
.jvcard
.Contact
;
10 import be
.nikiroo
.jvcard
.Data
;
11 import be
.nikiroo
.jvcard
.TypeInfo
;
12 import be
.nikiroo
.jvcard
.resources
.Bundles
;
13 import be
.nikiroo
.jvcard
.resources
.StringUtils
;
14 import be
.nikiroo
.jvcard
.resources
.Trans
;
15 import be
.nikiroo
.jvcard
.tui
.ImageTextControl
;
16 import be
.nikiroo
.jvcard
.tui
.KeyAction
;
17 import be
.nikiroo
.jvcard
.tui
.KeyAction
.DataType
;
18 import be
.nikiroo
.jvcard
.tui
.KeyAction
.Mode
;
19 import be
.nikiroo
.jvcard
.tui
.UiColors
;
21 import com
.googlecode
.lanterna
.TerminalSize
;
22 import com
.googlecode
.lanterna
.gui2
.BorderLayout
;
23 import com
.googlecode
.lanterna
.gui2
.Borders
;
24 import com
.googlecode
.lanterna
.gui2
.Direction
;
25 import com
.googlecode
.lanterna
.gui2
.Label
;
26 import com
.googlecode
.lanterna
.gui2
.LinearLayout
;
27 import com
.googlecode
.lanterna
.gui2
.Panel
;
28 import com
.googlecode
.lanterna
.input
.KeyType
;
30 public class ContactDetails
extends MainContent
{
31 private Contact contact
;
33 private ImageTextControl txtImage
;
35 private boolean fullscreenImage
;
36 private Panel infoPanel
;
40 public ContactDetails(Contact contact
) {
41 map
= Bundles
.getBundle("display");
43 BorderLayout blayout
= new BorderLayout();
44 setLayoutManager(blayout
);
47 blayout
= new BorderLayout();
48 top
.setLayoutManager(blayout
);
50 infoPanel
= new Panel();
51 infoPanel
.setLayoutManager(new LinearLayout(Direction
.VERTICAL
));
52 top
.addComponent(infoPanel
, BorderLayout
.Location
.CENTER
);
54 Panel notePanel
= new Panel();
55 notePanel
.setLayoutManager(new LinearLayout(Direction
.HORIZONTAL
));
57 notePanel
.addComponent(UiColors
.Element
.VIEW_CONTACT_NOTES_TITLE
58 .createLabel("Notes:"));
59 note
= UiColors
.Element
.VIEW_CONTACT_NORMAL
.createLabel("");
60 notePanel
.addComponent(note
);
64 addComponent(top
.withBorder(Borders
.doubleLineBevel()),
65 BorderLayout
.Location
.TOP
);
66 addComponent(notePanel
.withBorder(Borders
.singleLineBevel()),
67 BorderLayout
.Location
.CENTER
);
71 * Change the enclosed {@link Contact} from this {@link ContactDetails}.
72 * Also re-set the image.
75 * the new {@link Contact}
77 public void setContact(Contact contact
) {
78 this.contact
= contact
;
81 if (contact
!= null) {
82 infoPanel
.removeAllComponents();
84 String name
= contact
.getPreferredDataValue("FN");
85 if (name
== null || name
.length() == 0) {
86 // TODO format it ourself
87 name
= contact
.getPreferredDataValue("N");
90 infoPanel
.addComponent(UiColors
.Element
.VIEW_CONTACT_NAME
92 infoPanel
.addComponent(UiColors
.Element
.VIEW_CONTACT_NORMAL
98 labelSize
= Integer
.parseInt(map
99 .getString("CONTACT_DETAILS_LABEL_WIDTH"));
101 } catch (NumberFormatException e
) {
104 } catch (MissingResourceException e
) {
108 String infoFormat
= "";
110 infoFormat
= map
.getString("CONTACT_DETAILS_INFO");
111 } catch (MissingResourceException e
) {
115 String
[] infos
= infoFormat
.split("\\|");
116 for (String info
: infos
) {
117 // # - "=FIELD" will take the preferred value for this field
118 // # - "+FIELD" will take the preferred value for this field and
120 // # - "#FIELD" will take all the values with this field's name
121 // # - "*FIELD" will take all the values with this field's name,
122 // highlighting the preferred one
127 if (info
.contains("+") || info
.contains("#"))
129 if (info
.contains("*") || info
.contains("#"))
132 if (all
|| hl
|| info
.contains("=")) {
133 UiColors
.Element el
= hl ? UiColors
.Element
.VIEW_CONTACT_HIGHLIGHT
134 : UiColors
.Element
.VIEW_CONTACT_NORMAL
;
136 int index
= info
.indexOf('=');
138 index
= info
.indexOf('+');
140 index
= info
.indexOf('#');
142 index
= info
.indexOf('*');
144 String label
= info
.substring(0, index
);
145 String field
= info
.substring(index
+ 1);
148 for (Data data
: contact
.getData(field
)) {
149 if (data
.isPreferred()) {
150 infoPanel
.addComponent(el
151 .createLabel(StringUtils
.padString(
156 .addComponent(UiColors
.Element
.VIEW_CONTACT_NORMAL
157 .createLabel(StringUtils
164 String val
= contact
.getPreferredDataValue(field
);
167 infoPanel
.addComponent(el
.createLabel(StringUtils
168 .padString(label
, labelSize
) + val
));
172 infoPanel
.addComponent(UiColors
.Element
.VIEW_CONTACT_NORMAL
173 .createLabel(StringUtils
174 .padString(label
, labelSize
)));
179 infoPanel
.addComponent(UiColors
.Element
.VIEW_CONTACT_NORMAL
182 String notes
= contact
.getPreferredDataValue("NOTE");
187 Data photo
= contact
.getPreferredData("PHOTO");
189 TypeInfo encoding
= null;
190 for (TypeInfo info
: photo
) {
191 if (info
.getName() != null) {
192 if (info
.getName().equalsIgnoreCase("ENCODING"))
194 // We don't check for the "TYPE" anymore, we just defer
199 if (encoding
!= null && encoding
.getValue() != null
200 && encoding
.getValue().equalsIgnoreCase("b")) {
203 image
= StringUtils
.toImage(photo
.getValue());
204 } catch (Exception e
) {
205 System
.err
.println("Cannot parse image for contact: "
206 + contact
.getPreferredDataValue("UID"));
216 public DataType
getDataType() {
217 return DataType
.DATA
;
221 public List
<KeyAction
> getKeyBindings() {
222 List
<KeyAction
> actions
= new LinkedList
<KeyAction
>();
224 actions
.add(new KeyAction(Mode
.NONE
, KeyType
.Tab
,
225 Trans
.StringId
.KEY_ACTION_SWITCH_FORMAT
) {
227 public boolean onAction() {
228 if (txtImage
!= null) {
229 txtImage
.switchMode();
235 actions
.add(new KeyAction(Mode
.NONE
, 'i',
236 Trans
.StringId
.KEY_ACTION_INVERT
) {
238 public boolean onAction() {
239 if (txtImage
!= null) {
240 txtImage
.invertColor();
246 actions
.add(new KeyAction(Mode
.NONE
, 'f',
247 Trans
.StringId
.KEY_ACTION_FULLSCREEN
) {
249 public boolean onAction() {
250 fullscreenImage
= !fullscreenImage
;
255 // TODO: add "normal" edit
256 actions
.add(new KeyAction(Mode
.CONTACT_DETAILS_RAW
, 'r',
257 Trans
.StringId
.KEY_ACTION_EDIT_CONTACT_RAW
) {
259 public Object
getObject() {
268 public synchronized Panel
setSize(TerminalSize size
) {
275 * Set the {@link Image} to render and refresh it to the current size
279 * the new {@link Image}
281 private void setImage(Image image
) {
284 if (txtImage
!= null && top
.containsComponent(txtImage
))
285 top
.removeComponent(txtImage
);
287 TerminalSize size
= getTxtSize();
289 if (txtImage
!= null)
290 txtImage
.setSize(size
);
292 txtImage
= new ImageTextControl(image
, size
);
296 top
.addComponent(txtImage
, BorderLayout
.Location
.LEFT
);
303 * Compute the size to use for the {@link Image} text rendering. Return NULL
306 * @return the {@link TerminalSize} to use or NULL if it is not possible
308 private TerminalSize
getTxtSize() {
309 if (image
!= null && getSize() != null && getSize().getColumns() > 0
310 && getSize().getRows() > 0) {
311 if (fullscreenImage
) {
314 // TODO: configure size?
315 int w
= getSize().getColumns() - 40;
316 int h
= getSize().getRows() - 9;
317 if (w
<= 0 || h
<= 0)
320 return new TerminalSize(w
, h
);