From 9c8baf0c360173b864683176c567757429c4fb12 Mon Sep 17 00:00:00 2001 From: Niki Roo Date: Wed, 24 Feb 2016 16:50:28 +0100 Subject: [PATCH] Some changes to support Files --- src/be/nikiroo/jvcard/Contact.java | 124 +++++++++++++----- src/be/nikiroo/jvcard/i18n/Trans.java | 2 +- src/be/nikiroo/jvcard/tui/MainWindow.java | 124 +++++++++--------- src/be/nikiroo/jvcard/tui/UiColors.java | 9 +- .../nikiroo/jvcard/tui/panes/ContactList.java | 28 +++- src/be/nikiroo/jvcard/tui/panes/FileList.java | 36 ++++- .../jvcard/tui/panes/MainContentList.java | 95 ++++++++++---- 7 files changed, 297 insertions(+), 121 deletions(-) diff --git a/src/be/nikiroo/jvcard/Contact.java b/src/be/nikiroo/jvcard/Contact.java index 08d5eee..f2a8b01 100644 --- a/src/be/nikiroo/jvcard/Contact.java +++ b/src/be/nikiroo/jvcard/Contact.java @@ -159,34 +159,71 @@ public class Contact { * @return the {@link String} representation */ public String toString(String format, String separator, int width) { - String str = null; + StringBuilder builder = new StringBuilder(); String[] formatFields = format.split("\\|"); - String[] values = new String[formatFields.length]; - Boolean[] expandedFields = new Boolean[formatFields.length]; - Boolean[] fixedsizeFields = new Boolean[formatFields.length]; - int numOfFieldsToExpand = 0; - int totalSize = 0; - - if (width == 0) { - return ""; - } - if (width > -1 && separator != null && separator.length() > 0 && formatFields.length > 1) { int swidth = (formatFields.length - 1) * separator.length(); if (swidth >= width) { - str = separator; - while (str.length() < width) { - str += separator; + int num = width / separator.length(); + int remainder = width % separator.length(); + + if (remainder > 0) + num++; + + while (builder.length() < width) { + if (builder.length() + separator.length() <= width) + builder.append(separator); + else + builder.append(separator + .substring(0, (builder.length() + separator + .length()) + - width)); } - return str.substring(0, width); + return builder.toString(); } width -= swidth; } + for (String str : toStringArray(format, width)) { + builder.append(str); + } + + return builder.toString(); + } + + /** + * Return a {@link String} representation of this contact formated + * accordingly to the given format, part by part. + * + * The format is basically a list of field names separated by a pipe and + * optionally parametrised. See {@link Contact#toString} for more + * information about the format. + * + * @param format + * the format to use + * @param width + * a fixed width or -1 for "as long as needed" + * + * @return the {@link String} representation + */ + public String[] toStringArray(String format, int width) { + List str = new LinkedList(); + + String[] formatFields = format.split("\\|"); + String[] values = new String[formatFields.length]; + Boolean[] expandedFields = new Boolean[formatFields.length]; + Boolean[] fixedsizeFields = new Boolean[formatFields.length]; + int numOfFieldsToExpand = 0; + int totalSize = 0; + + if (width == 0) { + return str.toArray(new String[] {}); + } + for (int i = 0; i < formatFields.length; i++) { String field = formatFields[i]; @@ -236,7 +273,7 @@ public class Contact { totalSize += value.length(); } } - + if (width > -1 && totalSize > width) { int toDo = totalSize - width; for (int i = fixedsizeFields.length - 1; toDo > 0 && i >= 0; i--) { @@ -257,7 +294,7 @@ public class Contact { totalSize = width + toDo; } - + if (width > -1 && numOfFieldsToExpand > 0) { int availablePadding = width - totalSize; @@ -284,23 +321,13 @@ public class Contact { totalSize = width; } } - - for (String field : values) { - if (str == null) { - str = field; - } else { - str += separator + field; - } - } - - if (str == null) - str = ""; - if (width > -1) { - str = fixedString(str, width); + int currentSize = 0; + for (int i = 0; i < values.length; i++) { + currentSize += addToList(str, values[i], currentSize, width); } - return str; + return str.toArray(new String[] {}); } /** @@ -326,6 +353,41 @@ public class Contact { return string; } + /** + * Add a {@link String} to the given {@link List}, but make sure it does not + * exceed the maximum size, and truncate it if needed to fit. + * + * @param list + * @param add + * @param currentSize + * @param maxSize + * @return + */ + static private int addToList(List list, String add, + int currentSize, int maxSize) { + if (add == null || add.length() == 0) { + if (add != null) + list.add(add); + return 0; + } + + if (maxSize > -1) { + if (currentSize < maxSize) { + if (currentSize + add.length() >= maxSize) { + add = add.substring(0, maxSize - currentSize); + } + } else { + add = ""; + } + } + + if (add.length() > 0) { + list.add(add); + } + + return add.length(); + } + /** * Return a {@link String} representation of this contact, in vCard 2.1, * without BKeys. diff --git a/src/be/nikiroo/jvcard/i18n/Trans.java b/src/be/nikiroo/jvcard/i18n/Trans.java index 3ea9562..8c744d3 100644 --- a/src/be/nikiroo/jvcard/i18n/Trans.java +++ b/src/be/nikiroo/jvcard/i18n/Trans.java @@ -23,7 +23,7 @@ public class Trans { * */ public enum StringId { - KEY_ACTION_BACK, KEY_ACTION_HELP, KEY_ACTION_VIEW_CONTACT, KEY_ACTION_EDIT_CONTACT, KEY_ACTION_SWITCH_FORMAT, TITLE, NULL; + KEY_ACTION_BACK, KEY_ACTION_HELP, KEY_ACTION_VIEW_CONTACT, KEY_ACTION_VIEW_CARD, KEY_ACTION_EDIT_CONTACT, KEY_ACTION_SWITCH_FORMAT, TITLE, NULL; public String trans() { return Trans.getInstance().trans(this); diff --git a/src/be/nikiroo/jvcard/tui/MainWindow.java b/src/be/nikiroo/jvcard/tui/MainWindow.java index 7f438d9..aa99635 100644 --- a/src/be/nikiroo/jvcard/tui/MainWindow.java +++ b/src/be/nikiroo/jvcard/tui/MainWindow.java @@ -1,5 +1,6 @@ package be.nikiroo.jvcard.tui; +import java.io.File; import java.util.Arrays; import java.util.LinkedList; import java.util.List; @@ -122,13 +123,30 @@ public class MainWindow extends BasicWindow { actions = content.getKeyBindings(); contentPanel.addComponent(content, BorderLayout.Location.CENTER); this.content.add(content); + + Interactable focus = content.nextFocus(null); + if (focus != null) + focus.takeFocus(); } setTitle(title); setActions(actions, true, true); + invalidate(); } + public MainContent popContent() { + MainContent removed = null; + MainContent prev = null; + if (content.size() > 0) + removed = content.remove(content.size() - 1); + if (content.size() > 0) + prev = content.remove(content.size() - 1); + pushContent(prev); + + return removed; + } + /** * Set the application title. * @@ -152,6 +170,52 @@ public class MainWindow extends BasicWindow { .createLayoutData(LinearLayout.Alignment.Center)); } + /** + * Show the given message on screen. It will disappear at the next action. + * + * @param mess + * the message to display + * @param error + * TRUE for an error message, FALSE for an information message + */ + public void setMessage(String mess, boolean error) { + messagePanel.removeAllComponents(); + if (mess != null) { + Element element = (error ? UiColors.Element.LINE_MESSAGE_ERR + : UiColors.Element.LINE_MESSAGE); + Label lbl = element.createLabel(" " + mess + " "); + messagePanel.addComponent(lbl, LinearLayout + .createLayoutData(LinearLayout.Alignment.Center)); + } + } + + public void setQuestion(String mess, boolean oneKey) { + messagePanel.removeAllComponents(); + if (mess != null) { + waitForOneKeyAnswer = oneKey; + + Panel hpanel = new Panel(); + LinearLayout llayout = new LinearLayout(Direction.HORIZONTAL); + llayout.setSpacing(0); + hpanel.setLayoutManager(llayout); + + Label lbl = UiColors.Element.LINE_MESSAGE_QUESTION.createLabel(" " + + mess + " "); + text = new TextBox(new TerminalSize(getSize().getColumns() + - lbl.getSize().getColumns(), 1)); + + hpanel.addComponent(lbl, LinearLayout + .createLayoutData(LinearLayout.Alignment.Beginning)); + hpanel.addComponent(text, LinearLayout + .createLayoutData(LinearLayout.Alignment.Fill)); + + messagePanel.addComponent(hpanel, LinearLayout + .createLayoutData(LinearLayout.Alignment.Beginning)); + + text.takeFocus(); + } + } + @Override public void draw(TextGUIGraphics graphics) { setTitle(title); @@ -165,24 +229,12 @@ public class MainWindow extends BasicWindow { super.draw(graphics); } - public MainContent popContent() { - MainContent removed = null; - MainContent prev = null; - if (content.size() > 0) - removed = content.remove(content.size() - 1); - if (content.size() > 0) - prev = content.remove(content.size() - 1); - pushContent(prev); - - return removed; - } - private void setActions(List actions, boolean allowKeys, boolean enableDefaultactions) { this.actions.clear(); actionsPadded = false; - + if (enableDefaultactions) this.actions.addAll(defaultActions); @@ -233,52 +285,6 @@ public class MainWindow extends BasicWindow { } } - /** - * Show the given message on screen. It will disappear at the next action. - * - * @param mess - * the message to display - * @param error - * TRUE for an error message, FALSE for an information message - */ - public void setMessage(String mess, boolean error) { - messagePanel.removeAllComponents(); - if (mess != null) { - Element element = (error ? UiColors.Element.LINE_MESSAGE_ERR - : UiColors.Element.LINE_MESSAGE); - Label lbl = element.createLabel(" " + mess + " "); - messagePanel.addComponent(lbl, LinearLayout - .createLayoutData(LinearLayout.Alignment.Center)); - } - } - - public void setQuestion(String mess, boolean oneKey) { - messagePanel.removeAllComponents(); - if (mess != null) { - waitForOneKeyAnswer = oneKey; - - Panel hpanel = new Panel(); - LinearLayout llayout = new LinearLayout(Direction.HORIZONTAL); - llayout.setSpacing(0); - hpanel.setLayoutManager(llayout); - - Label lbl = UiColors.Element.LINE_MESSAGE_QUESTION.createLabel(" " - + mess + " "); - text = new TextBox(new TerminalSize(getSize().getColumns() - - lbl.getSize().getColumns(), 1)); - - hpanel.addComponent(lbl, LinearLayout - .createLayoutData(LinearLayout.Alignment.Beginning)); - hpanel.addComponent(text, LinearLayout - .createLayoutData(LinearLayout.Alignment.Fill)); - - messagePanel.addComponent(hpanel, LinearLayout - .createLayoutData(LinearLayout.Alignment.Beginning)); - - text.takeFocus(); - } - } - private String handleQuestion(KeyStroke key) { String answer = null; diff --git a/src/be/nikiroo/jvcard/tui/UiColors.java b/src/be/nikiroo/jvcard/tui/UiColors.java index 75c074a..0525a53 100644 --- a/src/be/nikiroo/jvcard/tui/UiColors.java +++ b/src/be/nikiroo/jvcard/tui/UiColors.java @@ -34,7 +34,7 @@ public class UiColors { } public enum Element { - ACTION_KEY, ACTION_DESC, LINE_MESSAGE, LINE_MESSAGE_ERR, LINE_MESSAGE_QUESTION, LINE_MESSAGE_ANS, CONTACT_LINE, CONTACT_LINE_SELECTED; + DEFAULT, ACTION_KEY, ACTION_DESC, LINE_MESSAGE, LINE_MESSAGE_ERR, LINE_MESSAGE_QUESTION, LINE_MESSAGE_ANS, CONTACT_LINE, CONTACT_LINE_SEPARATOR, CONTACT_LINE_SELECTED, CONTACT_LINE_SEPARATOR_SELECTED; /** * Get the foreground colour of this element. @@ -79,7 +79,7 @@ public class UiColors { return mapForegroundColor.get(el); } - return TextColor.ANSI.BLUE; + return TextColor.ANSI.BLACK; } private TextColor getBackgroundColor(Element el) { @@ -87,7 +87,7 @@ public class UiColors { return mapBackgroundColor.get(el); } - return TextColor.ANSI.BLUE; + return TextColor.ANSI.WHITE; } private UiColors() { @@ -101,6 +101,9 @@ public class UiColors { addEl(Element.CONTACT_LINE, TextColor.ANSI.WHITE, TextColor.ANSI.BLACK); addEl(Element.CONTACT_LINE_SELECTED, TextColor.ANSI.WHITE, TextColor.ANSI.BLUE); + addEl(Element.CONTACT_LINE_SEPARATOR, TextColor.ANSI.RED, TextColor.ANSI.BLACK); + addEl(Element.CONTACT_LINE_SEPARATOR_SELECTED, TextColor.ANSI.RED, + TextColor.ANSI.BLUE); addEl(Element.LINE_MESSAGE, TextColor.ANSI.BLUE, TextColor.ANSI.WHITE); addEl(Element.LINE_MESSAGE_ERR, TextColor.ANSI.RED, TextColor.ANSI.WHITE); diff --git a/src/be/nikiroo/jvcard/tui/panes/ContactList.java b/src/be/nikiroo/jvcard/tui/panes/ContactList.java index 3a943f9..7bb15dc 100644 --- a/src/be/nikiroo/jvcard/tui/panes/ContactList.java +++ b/src/be/nikiroo/jvcard/tui/panes/ContactList.java @@ -9,6 +9,8 @@ import be.nikiroo.jvcard.tui.KeyAction; import be.nikiroo.jvcard.tui.UiColors; import be.nikiroo.jvcard.tui.KeyAction.DataType; import be.nikiroo.jvcard.tui.KeyAction.Mode; +import be.nikiroo.jvcard.tui.UiColors.Element; +import be.nikiroo.jvcard.tui.panes.MainContentList.TextPart; import com.googlecode.lanterna.input.KeyType; @@ -108,9 +110,31 @@ public class ContactList extends MainContentList { } @Override - protected String getLabel(int index, int width) { + protected List getLabel(int index, int width, boolean selected, + boolean focused) { + List parts = new LinkedList(); + + Element el = (focused && selected) ? Element.CONTACT_LINE_SELECTED + : Element.CONTACT_LINE; + Element elSep = (focused && selected) ? Element.CONTACT_LINE_SEPARATOR_SELECTED + : Element.CONTACT_LINE_SEPARATOR; + + // TODO: width/separator to check + String separator = " ┃ "; + width -= (format.split("\\|").length + 1) * separator.length(); + String[] array = card.getContacts().get(index).toStringArray(format, + width); + // we could use: " ", "┃", "│"... - return card.getContacts().get(index).toString(format, " ┃ ", width); + for (String str : array) { + parts.add(new TextPart(str, el)); + parts.add(new TextPart(separator, elSep)); + } + + if (parts.size() > 0) + parts.remove(parts.get(parts.size() - 1)); + + return parts; } private void switchFormat() { diff --git a/src/be/nikiroo/jvcard/tui/panes/FileList.java b/src/be/nikiroo/jvcard/tui/panes/FileList.java index 9930070..79f530e 100644 --- a/src/be/nikiroo/jvcard/tui/panes/FileList.java +++ b/src/be/nikiroo/jvcard/tui/panes/FileList.java @@ -1,14 +1,19 @@ package be.nikiroo.jvcard.tui.panes; import java.io.File; +import java.io.IOException; +import java.util.LinkedList; import java.util.List; +import be.nikiroo.jvcard.Card; +import be.nikiroo.jvcard.i18n.Trans; +import be.nikiroo.jvcard.parsers.Format; import be.nikiroo.jvcard.tui.KeyAction; import be.nikiroo.jvcard.tui.UiColors; import be.nikiroo.jvcard.tui.KeyAction.DataType; import be.nikiroo.jvcard.tui.KeyAction.Mode; -import com.googlecode.lanterna.gui2.Label; +import com.googlecode.lanterna.input.KeyType; public class FileList extends MainContentList { private List files; @@ -51,8 +56,33 @@ public class FileList extends MainContentList { @Override public List getKeyBindings() { - // TODO Auto-generated method stub - return null; + List actions = new LinkedList(); + + // TODO del, save... + actions.add(new KeyAction(Mode.CONTACT_LIST, KeyType.Enter, + Trans.StringId.KEY_ACTION_VIEW_CARD) { + @Override + public Object getObject() { + File file = files.get(getSelectedIndex()); + Format format = Format.Abook; + String ext = file.getName(); + if (ext.contains(".")) { + String tab[] = ext.split("\\."); + if (tab.length > 1 + && tab[tab.length - 1].equalsIgnoreCase("vcf")) { + format = Format.VCard21; + } + } + try { + return new Card(file, format); + } catch (IOException ioe) { + ioe.printStackTrace(); + return null; + } + } + }); + + return actions; } @Override diff --git a/src/be/nikiroo/jvcard/tui/panes/MainContentList.java b/src/be/nikiroo/jvcard/tui/panes/MainContentList.java index 137a68d..79cfb2b 100644 --- a/src/be/nikiroo/jvcard/tui/panes/MainContentList.java +++ b/src/be/nikiroo/jvcard/tui/panes/MainContentList.java @@ -1,7 +1,12 @@ package be.nikiroo.jvcard.tui.panes; +import java.util.LinkedList; +import java.util.List; + import be.nikiroo.jvcard.tui.UiColors; +import be.nikiroo.jvcard.tui.UiColors.Element; +import com.googlecode.lanterna.TextColor; import com.googlecode.lanterna.gui2.ActionListBox; import com.googlecode.lanterna.gui2.Direction; import com.googlecode.lanterna.gui2.LinearLayout; @@ -11,6 +16,43 @@ import com.googlecode.lanterna.gui2.AbstractListBox.ListItemRenderer; abstract public class MainContentList extends MainContent implements Runnable { private ActionListBox lines; + /** + * This class represent a part of a text line to draw in this + * {@link MainContentList}. + * + * @author niki + * + */ + protected class TextPart { + private String text; + private Element element; + + public TextPart(String text, Element element) { + this.text = text; + this.element = element; + } + + public String getText() { + return text; + } + + public Element getElement() { + return element; + } + + public TextColor getForegroundColor() { + if (element != null) + return element.getForegroundColor(); + return Element.DEFAULT.getForegroundColor(); + } + + public TextColor getBackgroundColor() { + if (element != null) + return element.getBackgroundColor(); + return Element.DEFAULT.getBackgroundColor(); + } + } + public MainContentList(final UiColors.Element normalStyle, final UiColors.Element selectedStyle) { super(Direction.VERTICAL); @@ -51,27 +93,21 @@ abstract public class MainContentList extends MainContent implements Runnable { ActionListBox listBox, int index, Runnable item, boolean selected, boolean focused) { - if (selected && focused) { - graphics.setForegroundColor(selectedStyle - .getForegroundColor()); - graphics.setBackgroundColor(selectedStyle - .getBackgroundColor()); - } else { - graphics.setForegroundColor(normalStyle + // TODO: why +5 ?? padding problem? + List parts = MainContentList.this.getLabel( + index, lines.getSize().getColumns() + 5, + selected, focused); + + int position = 0; + for (TextPart part : parts) { + graphics.setForegroundColor(part .getForegroundColor()); - graphics.setBackgroundColor(normalStyle + graphics.setBackgroundColor(part .getBackgroundColor()); + String label = part.getText(); + graphics.putString(position, 0, label); + position += label.length(); } - - // original impl: - // String label = getLabel(listBox, index, item); - // label = TerminalTextUtils.fitString(label, - // graphics.getSize().getColumns()); - - // TODO: why +5 ?? padding problem? - String label = MainContentList.this.getLabel(index, - lines.getSize().getColumns() + 5); - graphics.putString(0, 0, label); } }); @@ -88,7 +124,7 @@ abstract public class MainContentList extends MainContent implements Runnable { public void addItem(String line) { lines.addItem(line, this); } - + /** * Clear all the items in this {@link MainContentList} */ @@ -129,16 +165,31 @@ abstract public class MainContentList extends MainContent implements Runnable { } /** - * Return the text representation of the selected line. + * Return the representation of the selected line, in {@link TextPart}s. * * @param index * the line index * @param width * the max width of the line + * @param selected + * TRUE if the item is selected + * @param focused + * TRUE if the item is focused * * @return the text representation */ - protected String getLabel(int index, int width) { - return "" + lines.getItems().get(index); + protected List getLabel(int index, int width, boolean selected, + boolean focused) { + List parts = new LinkedList(); + + if (selected && focused) { + parts.add(new TextPart("" + lines.getItems().get(index), + Element.CONTACT_LINE_SELECTED)); + } else { + parts.add(new TextPart("" + lines.getItems().get(index), + Element.CONTACT_LINE)); + } + + return parts; } } -- 2.27.0