From 59597d59aa262e31c2e1b7f66b4cb299f88ebd1b Mon Sep 17 00:00:00 2001 From: Niki Roo Date: Tue, 29 Mar 2016 20:49:35 +0200 Subject: [PATCH] Performance improvement: - much, much better at writing big ammount of data into VCF - uses compressed jpeg instead of uncompressed png with images - sends data over the wire in a much more efficient way - aBook format not improved (no binary, small ammount of text only) --- src/be/nikiroo/jvcard/Card.java | 31 ++--- src/be/nikiroo/jvcard/Contact.java | 29 +--- src/be/nikiroo/jvcard/launcher/Main.java | 6 +- .../nikiroo/jvcard/parsers/AbookParser.java | 41 ++++++ src/be/nikiroo/jvcard/parsers/Parser.java | 50 +++---- .../nikiroo/jvcard/parsers/Vcard21Parser.java | 126 ++++++++++-------- src/be/nikiroo/jvcard/remote/Server.java | 29 ++-- .../nikiroo/jvcard/remote/SimpleSocket.java | 68 +++++++++- src/be/nikiroo/jvcard/remote/Sync.java | 17 ++- .../nikiroo/jvcard/resources/StringUtils.java | 2 +- src/be/nikiroo/jvcard/tui/MainWindow.java | 9 +- .../jvcard/tui/panes/ContactDetailsRaw.java | 16 ++- .../nikiroo/jvcard/tui/panes/ContactList.java | 2 +- 13 files changed, 277 insertions(+), 149 deletions(-) diff --git a/src/be/nikiroo/jvcard/Card.java b/src/be/nikiroo/jvcard/Card.java index 5475358..0a405be 100644 --- a/src/be/nikiroo/jvcard/Card.java +++ b/src/be/nikiroo/jvcard/Card.java @@ -97,7 +97,7 @@ public class Card extends BaseClass { return false; BufferedWriter writer = new BufferedWriter(new FileWriter(file)); - writer.append(toString(format)); + Parser.write(writer, format, this); writer.close(); if (this.file != null @@ -140,24 +140,6 @@ public class Card extends BaseClass { return true; } - /** - * Return a {@link String} representation of this {@link Card} in the given - * {@link Format}. - * - * @param format - * the {@link Format} to use - * - * @return the {@link String} - */ - public String toString(Format format) { - StringBuilder builder = new StringBuilder(); - for (String line : Parser.toStrings(this, format)) { - builder.append(line); - builder.append("\r\n"); - } - return builder.toString(); - } - /** * Return the name of this card (the name of the {@link File} which it was * opened from). @@ -186,6 +168,15 @@ public class Card extends BaseClass { return file; } + /** + * Break the link between this {@link Card} and he {@link File} which was + * used to open it if any. + */ + public void unlink() { + file = null; + lastModified = -1; + } + /** * Return the date of the last modification for this {@link Card} (or -1 if * unknown/new). @@ -198,7 +189,7 @@ public class Card extends BaseClass { @Override public String toString() { - return toString(Format.VCard21); + return "[Card: " + name + "]"; } @Override diff --git a/src/be/nikiroo/jvcard/Contact.java b/src/be/nikiroo/jvcard/Contact.java index 4b46eab..9facbcd 100644 --- a/src/be/nikiroo/jvcard/Contact.java +++ b/src/be/nikiroo/jvcard/Contact.java @@ -88,27 +88,6 @@ public class Contact extends BaseClass { return found; } - /** - * Return a {@link String} representation of this contact. - * - * @param format - * the {@link Format} to use - * @param startingBKey - * the starting BKey or -1 for no BKeys - * @return the {@link String} representation - */ - public String toString(Format format, int startingBKey) { - updateBKeys(false); - - StringBuilder builder = new StringBuilder(); - for (String line : Parser.toStrings(this, format, startingBKey)) { - builder.append(line); - builder.append("\r\n"); - } - - return builder.toString(); - } - /** * Return a {@link String} representation of this contact formated * accordingly to the given format. @@ -400,7 +379,11 @@ public class Contact extends BaseClass { value = ff.get(fieldNum); } } else { - value = getPreferredDataValue(field); + // we don't need the *data* in binary mode... + if (binary) + value = getData(field).size() > 0 ? "x" : null; + else + value = getPreferredDataValue(field); } if (value == null) { @@ -527,7 +510,7 @@ public class Contact extends BaseClass { */ @Override public String toString() { - return toString(Format.VCard21, -1); + return "[Contact: " + getPreferredDataValue("FN") + "]"; } /** diff --git a/src/be/nikiroo/jvcard/launcher/Main.java b/src/be/nikiroo/jvcard/launcher/Main.java index 080223d..eeeae41 100644 --- a/src/be/nikiroo/jvcard/launcher/Main.java +++ b/src/be/nikiroo/jvcard/launcher/Main.java @@ -63,7 +63,7 @@ public class Main { * @return the translated text with the given value where required */ static public String trans(StringId id, Object... values) { - return transService.getString(id, (Object[]) values); + return transService.getString(id, values); } /** @@ -278,6 +278,7 @@ public class Main { new RemoteBundle().updateFile(dir); } catch (IOException e) { e.printStackTrace(); + System.err.flush(); System.exit(ERR_INTERNAL); } break; @@ -331,7 +332,7 @@ public class Main { List types = new LinkedList(); types.add(new TypeInfo("ENCODING", "b")); - types.add(new TypeInfo("TYPE", "png")); + types.add(new TypeInfo("TYPE", "jpeg")); Data photo = new Data(types, "PHOTO", b64, null); contact.add(photo); } catch (IOException e) { @@ -632,6 +633,7 @@ public class Main { else System.err.println(trans(err, trans(suberr, subvalues))); + System.err.flush(); System.exit(CODE); } } diff --git a/src/be/nikiroo/jvcard/parsers/AbookParser.java b/src/be/nikiroo/jvcard/parsers/AbookParser.java index cb4f667..b8e6e58 100644 --- a/src/be/nikiroo/jvcard/parsers/AbookParser.java +++ b/src/be/nikiroo/jvcard/parsers/AbookParser.java @@ -1,5 +1,6 @@ package be.nikiroo.jvcard.parsers; +import java.io.IOException; import java.util.Arrays; import java.util.LinkedList; import java.util.List; @@ -132,4 +133,44 @@ public class AbookParser { return lines; } + + /** + * Write the given {@link Contact} in the {@link Appendable}. + * + * @param writer + * the {@link Appendable} + * @param contact + * the {@link Contact} to write + * @param startingBKey + * the starting BKey number (all the other will follow) or -1 for + * no BKey + * + * @throws IOException + * in case of IO error + */ + public static void write(Appendable writer, Contact contact, + int startingBKey) throws IOException { + for (String s : toStrings(contact, startingBKey)) { + writer.append(s); + writer.append('\n'); + } + } + + /** + * Write the given {@link Card} in the {@link Appendable}. + * + * @param writer + * the {@link Appendable} + * @param card + * the {@link Card} to write + * + * @throws IOException + * in case of IO error + */ + public static void write(Appendable writer, Card card) throws IOException { + for (String s : toStrings(card)) { + writer.append(s); + writer.append('\n'); + } + } } diff --git a/src/be/nikiroo/jvcard/parsers/Parser.java b/src/be/nikiroo/jvcard/parsers/Parser.java index ceb35dc..040cd3e 100644 --- a/src/be/nikiroo/jvcard/parsers/Parser.java +++ b/src/be/nikiroo/jvcard/parsers/Parser.java @@ -73,24 +73,27 @@ public class Parser { } /** - * Return a {@link String} representation of the given {@link Card}, line by - * line. + * Write the given {@link Card} in the {@link Appendable}. * + * @param writer + * the {@link Appendable} * @param card - * the card to convert - * + * the {@link Card} to write * @param format - * the output {@link Format} to use + * the {@link Format} to export to * - * @return the {@link String} representation + * @throws IOException + * in case of IO error */ - public static List toStrings(Card card, Format format) { + public static void write(Appendable writer, Format format, Card card) + throws IOException { switch (format) { case VCard21: - return Vcard21Parser.toStrings(card); + Vcard21Parser.write(writer, card); + break; case Abook: - return AbookParser.toStrings(card); - + AbookParser.write(writer, card); + break; default: throw new InvalidParameterException("Unknown format: " + format.toString()); @@ -98,29 +101,30 @@ public class Parser { } /** - * Return a {@link String} representation of the given {@link Card}, line by - * line. - * - * @param card - * the card to convert + * Write the given {@link Contact} in the {@link Appendable}. * + * @param writer + * the {@link Appendable} + * @param contact + * the {@link Contact} to write * @param startingBKey * the starting BKey number (all the other will follow) or -1 for * no BKey - * * @param format - * the output {@link Format} to use + * the {@link Format} to export to * - * @return the {@link String} representation + * @throws IOException + * in case of IO error */ - public static List toStrings(Contact contact, Format format, - int startingBKey) { + public static void write(Appendable writer, Contact contact, Format format, + int startingBKey) throws IOException { switch (format) { case VCard21: - return Vcard21Parser.toStrings(contact, startingBKey); + Vcard21Parser.write(writer, contact, startingBKey); + break; case Abook: - return AbookParser.toStrings(contact, startingBKey); - + AbookParser.write(writer, contact, startingBKey); + break; default: throw new InvalidParameterException("Unknown format: " + format.toString()); diff --git a/src/be/nikiroo/jvcard/parsers/Vcard21Parser.java b/src/be/nikiroo/jvcard/parsers/Vcard21Parser.java index 5388783..5a07903 100644 --- a/src/be/nikiroo/jvcard/parsers/Vcard21Parser.java +++ b/src/be/nikiroo/jvcard/parsers/Vcard21Parser.java @@ -1,5 +1,8 @@ package be.nikiroo.jvcard.parsers; +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; import java.util.Iterator; import java.util.LinkedList; import java.util.List; @@ -134,62 +137,59 @@ public class Vcard21Parser { } /** - * Return a {@link String} representation of the given {@link Card}, line by - * line. + * Write the given {@link Card} in the {@link Appendable}. * + * @param writer + * the {@link Appendable} * @param card - * the card to convert + * the {@link Card} to write * - * @return the {@link String} representation + * @throws IOException + * in case of IO error */ - public static List toStrings(Card card) { - List lines = new LinkedList(); - + public static void write(Appendable writer, Card card) throws IOException { for (Contact contact : card) { - lines.addAll(toStrings(contact, -1)); + write(writer, contact, -1); } - - return lines; } /** - * Return a {@link String} representation of the given {@link Contact}, line - * by line. - * - * @param card - * the contact to convert + * Write the given {@link Contact} in the {@link Appendable}. * + * @param writer + * the {@link Appendable} + * @param contact + * the {@link Contact} to write * @param startingBKey * the starting BKey number (all the other will follow) or -1 for * no BKey * - * @return the {@link String} representation + * @throws IOException + * in case of IO error */ - public static List toStrings(Contact contact, int startingBKey) { - List lines = new LinkedList(); + public static void write(Appendable writer, Contact contact, + int startingBKey) throws IOException { - lines.add("BEGIN:VCARD"); - lines.add("VERSION:2.1"); + writer.append("BEGIN:VCARD\r\n"); + writer.append("VERSION:2.1\r\n"); for (Data data : contact) { - lines.addAll(toStrings(data)); + write(writer, data); } - lines.add("END:VCARD"); - - return lines; + writer.append("END:VCARD\r\n"); } /** - * Return a {@link String} representation of the given {@link Data}, line by - * line. + * Write the given {@link Data} in the {@link Appendable}. * + * @param writer + * the {@link Appendable} * @param data - * the data to convert + * the {@link Data} to write * - * @return the {@link String} representation + * @throws IOException + * in case of IO error */ - public static List toStrings(Data data) { - List lines = new LinkedList(); - + public static void write(Appendable writer, Data data) throws IOException { StringBuilder dataBuilder = new StringBuilder(); if (data.getGroup() != null && !data.getGroup().trim().equals("")) { dataBuilder.append(data.getGroup().trim()); @@ -212,31 +212,25 @@ public class Vcard21Parser { // RFC says: Content lines SHOULD be folded to a maximum width of 75 // octets -> since it is SHOULD, we will just cut it as 74/75 chars // depending if the last one fits in one char (note: chars != octet) - boolean continuation = false; - while (dataBuilder.length() > 0) { - int stop = 74; - if (continuation) - stop--; // the space takes 1 - if (dataBuilder.length() > stop) { - char car = dataBuilder.charAt(stop - 1); + int previous = 0; + for (int index = 0; index < dataBuilder.length(); previous = index) { + index += 74; + if (previous > 0) + index--; // the space takes 1 + if (dataBuilder.length() > index) { + char car = dataBuilder.charAt(index - 1); // RFC forbids cutting a character in 2 if (Character.isHighSurrogate(car)) { - stop++; + index++; } } - stop = Math.min(stop, dataBuilder.length()); - if (continuation) { - lines.add(' ' + dataBuilder.substring(0, stop)); - } else { - lines.add(dataBuilder.substring(0, stop)); - } - dataBuilder.delete(0, stop); - - continuation = true; + index = Math.min(index, dataBuilder.length()); + if (previous > 0) + writer.append(' '); + writer.append(dataBuilder, previous, index); + writer.append("\r\n"); } - - return lines; } /** @@ -248,7 +242,20 @@ public class Vcard21Parser { * @return the clone {@link Contact} */ public static Card clone(Card c) { - return new Card(parseContact(toStrings(c))); + try { + File tmp = File.createTempFile("clone", ".vcf"); + c.saveAs(tmp, Format.VCard21); + + Card clone = new Card(tmp, Format.VCard21); + clone.unlink(); + tmp.delete(); + + return clone; + } catch (IOException e) { + e.printStackTrace(); + } + + return null; } /** @@ -261,7 +268,22 @@ public class Vcard21Parser { * @return the clone {@link Contact} */ public static Contact clone(Contact c) { - return parseContact(toStrings(c, -1)).get(0); + try { + File tmp = File.createTempFile("clone", ".vcf"); + FileWriter writer = new FileWriter(tmp); + write(writer, c, -1); + writer.close(); + + Card clone = new Card(tmp, Format.VCard21); + clone.unlink(); + tmp.delete(); + + return clone.remove(0); + } catch (IOException e) { + e.printStackTrace(); + } + + return null; } /** diff --git a/src/be/nikiroo/jvcard/remote/Server.java b/src/be/nikiroo/jvcard/remote/Server.java index 962f2d0..ac29e97 100644 --- a/src/be/nikiroo/jvcard/remote/Server.java +++ b/src/be/nikiroo/jvcard/remote/Server.java @@ -17,6 +17,7 @@ import be.nikiroo.jvcard.Contact; import be.nikiroo.jvcard.Data; import be.nikiroo.jvcard.parsers.Format; import be.nikiroo.jvcard.parsers.Vcard21Parser; +import be.nikiroo.jvcard.remote.SimpleSocket.BlockAppendable; import be.nikiroo.jvcard.resources.StringUtils; import be.nikiroo.jvcard.resources.bundles.RemoteBundle; import be.nikiroo.jvcard.resources.enums.RemotingOption; @@ -323,7 +324,7 @@ public class Server implements Runnable { switch (command) { case GET_CARD: { - s.sendBlock(doGetCard(name)); + sendCardBlock(s, name); break; } case POST_CARD: { @@ -405,10 +406,13 @@ public class Server implements Runnable { switch (command) { case GET_CONTACT: { Contact contact = card.getById(cmd.getParam()); - if (contact != null) - s.sendBlock(Vcard21Parser.toStrings(contact, -1)); - else + if (contact != null) { + BlockAppendable app = s.createBlockAppendable(); + Vcard21Parser.write(app, contact, -1); + app.close(); + } else { s.sendBlock(); + } break; } case POST_CONTACT: { @@ -516,9 +520,9 @@ public class Server implements Runnable { case GET_DATA: { for (Data data : contact) { if (data.getName().equals(cmd.getParam())) { - for (String line : Vcard21Parser.toStrings(data)) { - s.send(line); - } + BlockAppendable app = s.createBlockAppendable(); + Vcard21Parser.write(app, data); + // note: we do NOT close 'app', since it would send an EOB } } s.sendBlock(); @@ -602,20 +606,19 @@ public class Server implements Runnable { * @throws IOException * in case of error */ - private List doGetCard(String name) throws IOException { - List lines = new LinkedList(); - + private void sendCardBlock(SimpleSocket s, String name) throws IOException { File vcf = getFile(name); + BlockAppendable app = s.createBlockAppendable(); if (vcf != null && vcf.exists()) { Card card = new Card(vcf, Format.VCard21); // timestamp + data - lines.add(StringUtils.fromTime(card.getLastModified())); - lines.addAll(Vcard21Parser.toStrings(card)); + app.append(StringUtils.fromTime(card.getLastModified()) + "\r\n"); + Vcard21Parser.write(app, card); } - return lines; + app.close(); } /** diff --git a/src/be/nikiroo/jvcard/remote/SimpleSocket.java b/src/be/nikiroo/jvcard/remote/SimpleSocket.java index d9dcb60..264fff5 100644 --- a/src/be/nikiroo/jvcard/remote/SimpleSocket.java +++ b/src/be/nikiroo/jvcard/remote/SimpleSocket.java @@ -1,6 +1,7 @@ package be.nikiroo.jvcard.remote; import java.io.BufferedReader; +import java.io.Closeable; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintWriter; @@ -19,6 +20,53 @@ import java.util.List; * @author niki */ public class SimpleSocket { + /** + * An {@link Appendable} that can be used to send data over a + * {@link SimpleSocket}. You must close it to send the end of block element. + * + * @author niki + * + */ + public class BlockAppendable implements Appendable, Closeable { + private SimpleSocket ss; + + /** + * Create a new {@link BlockAppendable} for the given + * {@link SimpleSocket}. + * + * @param ss + * the {@link SimpleSocket} + */ + public BlockAppendable(SimpleSocket ss) { + this.ss = ss; + } + + @Override + public Appendable append(CharSequence csq) throws IOException { + ss.send(csq); + return this; + } + + @Override + public Appendable append(char c) throws IOException { + ss.send("" + c); + return this; + } + + @Override + public Appendable append(CharSequence csq, int start, int end) + throws IOException { + ss.send(csq.subSequence(start, end)); + return this; + } + + @Override + public void close() throws IOException { + ss.sendBlock(); + } + + } + /** * The current version of the network protocol. */ @@ -141,12 +189,12 @@ public class SimpleSocket { * @throws IOException * in case of IO error */ - protected void send(String data) throws IOException { + protected void send(CharSequence data) throws IOException { if (data != null) { - out.write(data); + out.append(data); } - out.write("\n"); + out.append("\n"); if (out.checkError()) throw new IOException(); @@ -220,7 +268,19 @@ public class SimpleSocket { * in case of IO error */ public void sendCommand(Command command, String param) throws IOException { - sendLine(new CommandInstance(command, param, CURRENT_VERSION).toString()); + sendLine(new CommandInstance(command, param, CURRENT_VERSION) + .toString()); + } + + /** + * Create a new {@link Appendable} that can be used to send data on this + * {@link SimpleSocket}. When you are done, just call + * {@link BlockAppendable#close()}. + * + * @return the {@link Appendable} + */ + public BlockAppendable createBlockAppendable() { + return new BlockAppendable(this); } /** diff --git a/src/be/nikiroo/jvcard/remote/Sync.java b/src/be/nikiroo/jvcard/remote/Sync.java index 609041e..a1e5e24 100644 --- a/src/be/nikiroo/jvcard/remote/Sync.java +++ b/src/be/nikiroo/jvcard/remote/Sync.java @@ -24,6 +24,7 @@ import be.nikiroo.jvcard.launcher.CardResult; import be.nikiroo.jvcard.launcher.CardResult.MergeCallback; import be.nikiroo.jvcard.parsers.Format; import be.nikiroo.jvcard.parsers.Vcard21Parser; +import be.nikiroo.jvcard.remote.SimpleSocket.BlockAppendable; import be.nikiroo.jvcard.resources.StringUtils; import be.nikiroo.jvcard.resources.bundles.RemoteBundle; import be.nikiroo.jvcard.resources.enums.RemotingOption; @@ -276,7 +277,9 @@ public class Sync { } case POST_CARD: { s.sendCommand(Command.POST_CARD); - s.sendBlock(Vcard21Parser.toStrings(local)); + BlockAppendable app = s.createBlockAppendable(); + Vcard21Parser.write(app, local); + app.close(); local.saveAs(getCache(cacheDirOrig), Format.VCard21); setLastModified(s.receiveLine()); break; @@ -343,7 +346,9 @@ public class Sync { // ...but without starting with original since it is not // true here s.sendCommand(Command.POST_CARD); - s.sendBlock(Vcard21Parser.toStrings(merge)); + BlockAppendable app = s.createBlockAppendable(); + Vcard21Parser.write(app, merge); + app.close(); String serverLastModifTime = s.receiveLine(); // @@ -409,7 +414,9 @@ public class Sync { } for (Contact c : added) { s.sendCommand(Command.POST_CONTACT, c.getId()); - s.sendBlock(Vcard21Parser.toStrings(c, -1)); + BlockAppendable app = s.createBlockAppendable(); + Vcard21Parser.write(app, c, -1); + s.close(); } if (from.size() > 0) { for (int index = 0; index < from.size(); index++) { @@ -425,7 +432,9 @@ public class Sync { } for (Data d : subadded) { s.sendCommand(Command.POST_DATA, d.getContentState(true)); - s.sendBlock(Vcard21Parser.toStrings(d)); + BlockAppendable app = s.createBlockAppendable(); + Vcard21Parser.write(app, d); + app.close(); } s.sendCommand(Command.PUT_CONTACT); } diff --git a/src/be/nikiroo/jvcard/resources/StringUtils.java b/src/be/nikiroo/jvcard/resources/StringUtils.java index cee9fb6..e9203d5 100644 --- a/src/be/nikiroo/jvcard/resources/StringUtils.java +++ b/src/be/nikiroo/jvcard/resources/StringUtils.java @@ -194,7 +194,7 @@ public class StringUtils { ByteArrayOutputStream out = new ByteArrayOutputStream(); try { - ImageIO.write(image, "png", out); + ImageIO.write(image, "jpeg", out); byte[] imageBytes = out.toByteArray(); imageString = DatatypeConverter.printBase64Binary(imageBytes); diff --git a/src/be/nikiroo/jvcard/tui/MainWindow.java b/src/be/nikiroo/jvcard/tui/MainWindow.java index 1cbc014..a87b7ba 100644 --- a/src/be/nikiroo/jvcard/tui/MainWindow.java +++ b/src/be/nikiroo/jvcard/tui/MainWindow.java @@ -522,7 +522,8 @@ public class MainWindow extends BasicWindow { kPane.addComponent(UiColors.createLabel(ColorOption.ACTION_KEY, keyTrans)); - kPane.addComponent(UiColors.createLabel(ColorOption.ACTION_DESC, trans)); + kPane.addComponent(UiColors.createLabel(ColorOption.ACTION_DESC, + trans)); actionPanel.addComponent(kPane); } @@ -534,8 +535,8 @@ public class MainWindow extends BasicWindow { } if (width > 0) { - actionPanel.addComponent(UiColors.createLabel(ColorOption.ACTION_DESC, - StringUtils.padString("", width))); + actionPanel.addComponent(UiColors.createLabel( + ColorOption.ACTION_DESC, StringUtils.padString("", width))); } } @@ -627,7 +628,7 @@ public class MainWindow extends BasicWindow { setMessage(mess, action.isError()); } - if (action.onAction()) { + if (!action.isError() && action.onAction()) { handleAction(action, null); } diff --git a/src/be/nikiroo/jvcard/tui/panes/ContactDetailsRaw.java b/src/be/nikiroo/jvcard/tui/panes/ContactDetailsRaw.java index c477760..4a2712d 100644 --- a/src/be/nikiroo/jvcard/tui/panes/ContactDetailsRaw.java +++ b/src/be/nikiroo/jvcard/tui/panes/ContactDetailsRaw.java @@ -42,7 +42,13 @@ public class ContactDetailsRaw extends MainContentList { StringId.KEY_ACTION_EDIT_FIELD) { @Override public Object getObject() { - return getSelectedData(); + Data data = getSelectedData(); + if (data != null && data.getB64Key() != -1) { + setMessage("Cannot modify binary values in RAW mode", true); + data = null; + } + + return data; } @Override @@ -262,6 +268,7 @@ public class ContactDetailsRaw extends MainContentList { @Override protected List getLabel(int index, int width, boolean selected, boolean focused) { + // TODO: from ini file? int SIZE_COL_1 = 15; int SIZE_COL_2_OPT = 10; @@ -296,7 +303,12 @@ public class ContactDetailsRaw extends MainContentList { StringBuilder valueBuilder = new StringBuilder(" "); if (!extMode) { - valueBuilder.append(data.getValue().replaceAll("\n", "\\\\n")); + if (data.getB64Key() != -1) { + // TODO: i18n + valueBuilder.append(""); + } else { + valueBuilder.append(data.getValue().replaceAll("\n", "\\\\n")); + } if (data.getGroup() != null && data.getGroup().length() > 0) { valueBuilder.append("("); valueBuilder.append(data.getGroup()); diff --git a/src/be/nikiroo/jvcard/tui/panes/ContactList.java b/src/be/nikiroo/jvcard/tui/panes/ContactList.java index 9001c39..20d4944 100644 --- a/src/be/nikiroo/jvcard/tui/panes/ContactList.java +++ b/src/be/nikiroo/jvcard/tui/panes/ContactList.java @@ -268,7 +268,7 @@ public class ContactList extends MainContentList { String[] array = contact.toStringArray(format, getSeparator(), " ", width, Main.isUnicode()); - + if (contact.isDirty()) { parts.add(new TextPart(" ", el)); parts.add(new TextPart("*", elDirty)); -- 2.27.0