From c3c6e2320349e3000405aab76c28b0e1b1345c77 Mon Sep 17 00:00:00 2001 From: Danny van Heumen Date: Tue, 18 Feb 2014 23:38:33 +0100 Subject: [PATCH] Working on formatted text builder for IRC control chars. --- .../protocol/irc/FormattedTextBuilder.java | 112 ++++++++++++++++++ .../communicator/impl/protocol/irc/Utils.java | 2 +- .../irc/FormattedTextBuilderTest.java | 49 ++++++++ .../impl/protocol/irc/UtilsTest.java | 14 +++ 4 files changed, 176 insertions(+), 1 deletion(-) create mode 100644 src/net/java/sip/communicator/impl/protocol/irc/FormattedTextBuilder.java create mode 100644 test/net/java/sip/communicator/impl/protocol/irc/FormattedTextBuilderTest.java diff --git a/src/net/java/sip/communicator/impl/protocol/irc/FormattedTextBuilder.java b/src/net/java/sip/communicator/impl/protocol/irc/FormattedTextBuilder.java new file mode 100644 index 000000000..67c0d63fd --- /dev/null +++ b/src/net/java/sip/communicator/impl/protocol/irc/FormattedTextBuilder.java @@ -0,0 +1,112 @@ +package net.java.sip.communicator.impl.protocol.irc; + +import java.util.*; + +/** + * Builder for constructing a formatted text. + * + * @author Danny van Heumen + */ +public class FormattedTextBuilder +{ + /** + * stack with formatting control chars + */ + private final Stack formatting = new Stack(); + + /** + * formatted text container + */ + private final StringBuilder text = new StringBuilder(); + + /** + * Append a string of text. + * + * @param text + */ + public void append(String text) + { + this.text.append(text); + } + + /** + * Apply a control char for formatting. + * + * @param c the control char + */ + public void apply(ControlChar c) + { + if (formatting.contains(c)) + { + // cancel active control char + cancel(c); + } + else + { + // start control char formatting + this.text.append(c.getHtmlStart()); + } + } + + /** + * Cancel the specified control char. + * + * @param c the control char + */ + private void cancel(ControlChar c) + { + final Stack unwind = new Stack(); + while (!this.formatting.empty()) + { + // unwind control chars looking for the cancelled control char + ControlChar current = this.formatting.pop(); + this.text.append(current.getHtmlEnd()); + if (current == c) + { + break; + } + else + { + unwind.push(current); + } + } + while (!unwind.empty()) + { + // rewind remaining control characters + ControlChar current = unwind.pop(); + this.text.append(current.getHtmlStart()); + this.formatting.push(current); + } + } + + /** + * Cancel all remaining control chars. + */ + private void cancelAll() + { + while (!this.formatting.empty()) + { + ControlChar c = this.formatting.pop(); + this.text.append(c.getHtmlEnd()); + } + } + + /** + * Finish building the text string. Close outstanding control char + * formatting and returns the result. + */ + public String done() + { + cancelAll(); + return this.text.toString(); + } + + /** + * Return the formatted string. If it is not yet finished (outstanding + * formatting) also finish up remaining control chars. + */ + public String toString() + { + return done(); + } +} diff --git a/src/net/java/sip/communicator/impl/protocol/irc/Utils.java b/src/net/java/sip/communicator/impl/protocol/irc/Utils.java index 008949d22..cbade22b3 100644 --- a/src/net/java/sip/communicator/impl/protocol/irc/Utils.java +++ b/src/net/java/sip/communicator/impl/protocol/irc/Utils.java @@ -100,7 +100,7 @@ public static String parse(String text) } catch (IllegalArgumentException e) { - LOGGER.debug("Invalid color code.", e); + LOGGER.trace("Invalid color code.", e); } formatting.push(control); String htmlTag = diff --git a/test/net/java/sip/communicator/impl/protocol/irc/FormattedTextBuilderTest.java b/test/net/java/sip/communicator/impl/protocol/irc/FormattedTextBuilderTest.java new file mode 100644 index 000000000..5f064e74e --- /dev/null +++ b/test/net/java/sip/communicator/impl/protocol/irc/FormattedTextBuilderTest.java @@ -0,0 +1,49 @@ +package net.java.sip.communicator.impl.protocol.irc; + +import junit.framework.*; + +public class FormattedTextBuilderTest + extends TestCase +{ + + public void testConstructFormattedTextBuilder() + { + new FormattedTextBuilder(); + } + + public void testFormatNothing() + { + FormattedTextBuilder formatted = new FormattedTextBuilder(); + Assert.assertEquals("", formatted.done()); + } + + public void testPlainText() + { + FormattedTextBuilder formatted = new FormattedTextBuilder(); + formatted.append("Hello world!"); + Assert.assertEquals("Hello world!", formatted.done()); + } + + public void testDoneWithoutFormatting() + { + FormattedTextBuilder formatted = new FormattedTextBuilder(); + formatted.append("Hello world!"); + Assert.assertEquals("Hello world!", formatted.done()); + } + + public void testDoneRepeatedly() + { + FormattedTextBuilder formatted = new FormattedTextBuilder(); + formatted.append("Hello world!"); + formatted.done(); + formatted.done(); + Assert.assertEquals("Hello world!", formatted.done()); + } + + public void testOnlyFormatting() + { + FormattedTextBuilder formatted = new FormattedTextBuilder(); + formatted.append("Hello world!"); + Assert.assertEquals("Hello world!", formatted.done()); + } +} diff --git a/test/net/java/sip/communicator/impl/protocol/irc/UtilsTest.java b/test/net/java/sip/communicator/impl/protocol/irc/UtilsTest.java index 283891e0f..83cfc0c81 100644 --- a/test/net/java/sip/communicator/impl/protocol/irc/UtilsTest.java +++ b/test/net/java/sip/communicator/impl/protocol/irc/UtilsTest.java @@ -153,4 +153,18 @@ public void testParseUnknownBackgroundCOlor() final String htmlMessage = ",99TEST"; Assert.assertEquals(htmlMessage, Utils.parse(ircMessage)); } + + public void testStackIncompatibleFormatToggling() + { + final String ircMessage = "\u0002\u001D\u001FHello\u0002 W\u001Dorld\u001F!"; + final String htmlMessage = "Hello World!"; + Assert.assertEquals(htmlMessage, Utils.parse(ircMessage)); + } + + public void testColorSwitch() + { + final String ircMessage = "\u000302,03Hello \u000308,09World\u000F!"; + final String htmlMessage = "Hello World!"; + Assert.assertEquals(htmlMessage, Utils.parse(ircMessage)); + } }