From 61a9ae412db91a866176ec50939faa0e88829590 Mon Sep 17 00:00:00 2001 From: Danny van Heumen Date: Sun, 24 Aug 2014 21:46:15 +0200 Subject: [PATCH] Extracted Replacer interface and moved replacers to a separate package. --- .../gui/main/chat/ChatConversationPanel.java | 307 ++---------------- .../impl/gui/main/chat/Replacer.java | 51 +++ .../main/chat/replacers/BrTagReplacer.java | 72 ++++ .../main/chat/replacers/ImgTagReplacer.java | 74 +++++ .../main/chat/replacers/KeywordReplacer.java | 83 +++++ .../main/chat/replacers/NewlineReplacer.java | 57 ++++ .../gui/main/chat/replacers/URLReplacer.java | 85 +++++ .../gui/main/chat/replacers/package-info.java | 14 + 8 files changed, 470 insertions(+), 273 deletions(-) create mode 100644 src/net/java/sip/communicator/impl/gui/main/chat/Replacer.java create mode 100644 src/net/java/sip/communicator/impl/gui/main/chat/replacers/BrTagReplacer.java create mode 100644 src/net/java/sip/communicator/impl/gui/main/chat/replacers/ImgTagReplacer.java create mode 100644 src/net/java/sip/communicator/impl/gui/main/chat/replacers/KeywordReplacer.java create mode 100644 src/net/java/sip/communicator/impl/gui/main/chat/replacers/NewlineReplacer.java create mode 100644 src/net/java/sip/communicator/impl/gui/main/chat/replacers/URLReplacer.java create mode 100644 src/net/java/sip/communicator/impl/gui/main/chat/replacers/package-info.java diff --git a/src/net/java/sip/communicator/impl/gui/main/chat/ChatConversationPanel.java b/src/net/java/sip/communicator/impl/gui/main/chat/ChatConversationPanel.java index 8bb5163e8..fd95a61e5 100644 --- a/src/net/java/sip/communicator/impl/gui/main/chat/ChatConversationPanel.java +++ b/src/net/java/sip/communicator/impl/gui/main/chat/ChatConversationPanel.java @@ -25,6 +25,7 @@ import net.java.sip.communicator.impl.gui.*; import net.java.sip.communicator.impl.gui.main.chat.history.*; import net.java.sip.communicator.impl.gui.main.chat.menus.*; +import net.java.sip.communicator.impl.gui.main.chat.replacers.*; import net.java.sip.communicator.impl.gui.utils.*; import net.java.sip.communicator.impl.gui.utils.Constants; import net.java.sip.communicator.plugin.desktoputil.*; @@ -55,6 +56,7 @@ * @author Yana Stamcheva * @author Lyubomir Marinov * @author Adam Netocny + * @author Danny van Heumen */ public class ChatConversationPanel extends SIPCommScrollPane @@ -73,6 +75,12 @@ public class ChatConversationPanel /** * The regular expression (in the form of compiled Pattern) which * matches URLs for the purposed of turning them into links. + * + * TODO Current pattern misses tailing '/' (slash) that is sometimes + * included in URL's. (Danny) + * + * TODO Current implementation misses # after ? has been encountered in URL. + * (Danny) */ private static final Pattern URL_PATTERN = Pattern.compile( @@ -1019,10 +1027,8 @@ private void deleteAllMessagesWithoutHeader() /** * Formats the given message. Processes all smiley chars, new lines and - * links. - * - * TODO correctly name this method: we only expect content in either HTML or - * PLAIN TEXT format. We DON'T WANT THE HEADER STUFF OF A HTML MESSAGE!!! + * links. This method expects only the message's body to be + * provided. * * @param message the message to be formatted * @param contentType the content type of the message to be formatted @@ -1038,7 +1044,7 @@ private String formatMessageAsHTML(final String original, return ""; } - // prepare initial message source + // prepare source message String source; if (ChatHtmlUtils.HTML_CONTENT_TYPE.equals(contentType)) { @@ -1049,23 +1055,36 @@ private String formatMessageAsHTML(final String original, source = StringEscapeUtils.escapeHtml4(original); } - final Replacer[] replacers = new Replacer[] - { + return processReplacers(source, new NewlineReplacer(), - new URLReplacer(), + new URLReplacer(URL_PATTERN), new KeywordReplacer(keyword), new BrTagReplacer(), - new ImgTagReplacer() - }; - - return processReplacers(source, replacers); + new ImgTagReplacer()); } - // FIXME decent comments - private String processReplacers(final String content, final Replacer... replacers) + /** + * Process provided replacers one by one sequentially. The output of the + * first replacer is then fed as input into the second replacer, and so on. + *

+ * {@link Replacer}s that expect HTML content ( + * {@link Replacer#expectsPlainText()}) will typically receive the complete + * message as an argument. {@linkplain Replacer}s that expect plain text + * content will typically receive small pieces that are found in between + * HTML tags. The pieces of plain text content cannot be predicted as + * results change when they are processed by other replacers. + *

+ * + * @param content the original content to process + * @param replacers the replacers to call + * @return returns the final result message content after it has been + * processed by all replacers + */ + private String processReplacers(final String content, + final Replacer... replacers) { StringBuilder source = new StringBuilder(content); - for (Replacer replacer : replacers) + for (final Replacer replacer : replacers) { final StringBuilder target = new StringBuilder(); if (replacer.expectsPlainText()) @@ -1118,236 +1137,6 @@ private String processReplacers(final String content, final Replacer... replacer return source.toString(); } - // TODO check all processors for correct html escaping! - // FIXME decent comments - private static abstract class Replacer - { - /** - * If a replacer expects plain text strings, then html content is - * automatically unescaped. The replacer is responsible for correctly - * escaping normal text. - * - * @return returns true if it needs plain text or false if it wants html - * content - */ - abstract boolean expectsPlainText(); - // FIXME javadoc - abstract void replace(StringBuilder target, String piece); - } - - private static final class URLReplacer - extends Replacer - { - - @Override - boolean expectsPlainText() - { - return true; - } - - @Override - void replace(final StringBuilder target, final String piece) - { - final Matcher m = URL_PATTERN.matcher(piece); - int prevEnd = 0; - - while (m.find()) - { - target.append(StringEscapeUtils.escapeHtml4(piece.substring( - prevEnd, m.start()))); - prevEnd = m.end(); - - String url = m.group().trim(); - target.append(""); - target.append(StringEscapeUtils.escapeHtml4(url)); - target.append(""); - } - target.append(StringEscapeUtils.escapeHtml4(piece - .substring(prevEnd))); - } - } - - private static final class NewlineReplacer - extends Replacer - { - - @Override - boolean expectsPlainText() - { - return false; - } - - @Override - void replace(final StringBuilder target, final String piece) - { - /* - *
tags are needed to visualize a new line in the html format, - * but when copied to the clipboard they are exported to the plain - * text format as ' ' and not as '\n'. - * - * See bug N4988885: - * http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4988885 - * - * To fix this we need " " - the HTML-Code for ASCII-Character - * No.10 (Line feed). - */ - target.append(piece.replaceAll("\n", "
")); - } - } - - private static final class KeywordReplacer - extends Replacer - { - private final String keyword; - - private KeywordReplacer(final String keyword) - { - this.keyword = keyword; - } - - @Override - boolean expectsPlainText() - { - return true; - } - - @Override - void replace(final StringBuilder target, final String piece) - { - if (this.keyword == null || this.keyword.isEmpty()) - { - target.append(StringEscapeUtils.escapeHtml4(piece)); - return; - } - - final Matcher m = - Pattern.compile(Pattern.quote(keyword), - Pattern.CASE_INSENSITIVE).matcher(piece); - int prevEnd = 0; - while (m.find()) - { - target.append(StringEscapeUtils.escapeHtml4(piece.substring( - prevEnd, m.start()))); - prevEnd = m.end(); - final String keywordMatch = m.group().trim(); - target.append(""); - target.append(StringEscapeUtils.escapeHtml4(keywordMatch)); - target.append(""); - } - target.append(StringEscapeUtils.escapeHtml4(piece - .substring(prevEnd))); - } - } - - private static final class BrTagReplacer extends Replacer { - - @Override - boolean expectsPlainText() - { - return false; - } - - @Override - void replace(final StringBuilder target, final String piece) - { - // Compile the regex to match something like
or
. - // This regex is case sensitive and keeps the style or other - // attributes of the
tag. - Matcher m = - Pattern.compile("<\\s*[bB][rR](.*?)(/\\s*>)").matcher(piece); - int start = 0; - - // while we find some
closing tags with a slash inside. - while (m.find()) - { - // First, we have to copy all the message preceding the
- // tag. - target.append(piece.substring(start, m.start())); - // Then, we find the position of the slash inside the tag. - final int slashIndex = m.group().lastIndexOf("/"); - // We copy the
tag till the slash exclude. - target.append(m.group().substring(0, slashIndex)); - // We copy all the end of the tag following the slash exclude. - target.append(m.group().substring(slashIndex + 1)); - start = m.end(); - } - // Finally, we have to add the end of the message following the last - //
tag, or the whole message if there is no
tag. - target.append(piece.substring(start)); - } - } - - private static final class ImgTagReplacer - extends Replacer - { - - @Override - boolean expectsPlainText() - { - return false; - } - - @Override - void replace(final StringBuilder target, final String piece) - { - // Compile the regex to match something like or - // . This regex is case sensitive and keeps the style, - // src or other attributes of the tag. - final Pattern p = Pattern.compile("<\\s*[iI][mM][gG](.*?)(/\\s*>)"); - final Matcher m = p.matcher(piece); - int slashIndex; - int start = 0; - - // while we find some self-closing tags with a slash inside. - while (m.find()) - { - // First, we have to copy all the message preceding the - // tag. - target.append(piece.substring(start, m.start())); - // Then, we find the position of the slash inside the tag. - slashIndex = m.group().lastIndexOf("/"); - // We copy the tag till the slash exclude. - target.append(m.group().substring(0, slashIndex)); - // We copy all the end of the tag following the slash exclude. - target.append(m.group().substring(slashIndex + 1)); - // We close the tag with a separate closing tag. - target.append(""); - start = m.end(); - } - // Finally, we have to add the end of the message following the last - // tag, or the whole message if there is no tag. - target.append(piece.substring(start)); - } - } - - // FIXME delete this after everything works - /** - * Formats all links in a given message and optionally escapes special HTML - * characters such as <, >, & and " in order to prevent HTML - * injection in plain-text messages such as writing - * </PLAINTEXT>, HTML which is going to be rendered as - * such and <PLAINTEXT>. The two procedures are carried - * out in one call in order to not break URLs which contain special HTML - * characters such as &. - * - * @param message The source message string. - * @param processHTMLChars true to escape the special HTML chars; - * otherwise, false - * @param contentType the message content type (html or plain text) - * @return The message string with properly formatted links. - */ -// processLinksAndHTMLChars(final String message, -// final boolean processHTMLChars, -// final String contentType) -// { -// } - /** * Opens a link in the default browser when clicked and shows link url in a * popup on mouseover. @@ -1644,34 +1433,6 @@ public Date getPageLastMsgTimestamp() return timestamp; } - // FIXME delete this after everything works - /** - * Formats HTML tags <br/> to <br> or <BR/> to <BR>. - * The reason of this function is that the ChatPanel does not support - * <br /> closing tags (XHTML syntax), thus we have to remove every - * slash from each <br /> tags. - * @param message The source message string. - * @return The message string with properly formatted <br> tags. - */ -// processBrTags(String message) -// { -// } - - // FIXME delete this after everything works - /** - * Formats HTML tags <img ... /> to < img ... ></img> or - * <IMG ... /> to <IMG></IMG>. - * The reason of this function is that the ChatPanel does not support - * <img /> tags (XHTML syntax). - * Thus, we remove every slash from each <img /> and close it with a - * separate closing tag. - * @param message The source message string. - * @return The message string with properly formatted <img> tags. - */ -// processImgTags(String message) -// { -// } - /** * Extend Editor pane to add URL tooltips. */ diff --git a/src/net/java/sip/communicator/impl/gui/main/chat/Replacer.java b/src/net/java/sip/communicator/impl/gui/main/chat/Replacer.java new file mode 100644 index 000000000..ad0fb0378 --- /dev/null +++ b/src/net/java/sip/communicator/impl/gui/main/chat/Replacer.java @@ -0,0 +1,51 @@ +/* + * Jitsi, the OpenSource Java VoIP and Instant Messaging client. + * + * Distributable under LGPL license. + * See terms of license at gnu.org. + */ +package net.java.sip.communicator.impl.gui.main.chat; + +/** + * The Replacer interface defines the expectations of message content replacers. + * Replacers get called with pieces of message content and can then perform + * appropriate modifications to the content before writing the result. + * + * @author Danny van Heumen + */ +public interface Replacer +{ + /** + * If a replacer expects plain text strings, then html content is + * automatically unescaped. The replacer is responsible for correctly + * escaping normal text. + * + * @return returns true if it needs plain text or false if it wants html + * content + */ + boolean expectsPlainText(); + + /** + * Actual replace operation. The replacer is called with a piece of text + * (either plain text or HTML dependening on the result of + * {@link #expectsPlainText()}) and the result should be written to + * target. If nothing gets written to target then that + * piece of text is lost, so the replacer has full control of the + * transformation of that particular piece of text. + *

+ * If {@link #expectsPlainText()} returns true, then replace is + * called with a piece of plain text. If expectsPlainText() returns + * false, then a piece of HTML content is provided. In both cases the + * replacer is expected to write HTML content into target. + *

+ *

+ * Note that the replacer has to do appropriate HTML escaping + * itself when necessary, because we cannot determine the nature of the + * replacer's specific implementation. + *

+ * + * @param target the target buffer to write the result to + * @param piece the piece of text that can be replaced + */ + void replace(StringBuilder target, String piece); +} diff --git a/src/net/java/sip/communicator/impl/gui/main/chat/replacers/BrTagReplacer.java b/src/net/java/sip/communicator/impl/gui/main/chat/replacers/BrTagReplacer.java new file mode 100644 index 000000000..ce6a7d644 --- /dev/null +++ b/src/net/java/sip/communicator/impl/gui/main/chat/replacers/BrTagReplacer.java @@ -0,0 +1,72 @@ +/* + * Jitsi, the OpenSource Java VoIP and Instant Messaging client. + * + * Distributable under LGPL license. + * See terms of license at gnu.org. + */ +package net.java.sip.communicator.impl.gui.main.chat.replacers; + +import java.util.regex.*; + +import net.java.sip.communicator.impl.gui.main.chat.*; + +/** + * Formats HTML tags <br/> to <br> or <BR/> to <BR>. + * The reason of this {@link Replacer} is that the ChatPanel does not support + * <br /> closing tags (XHTML syntax), thus we have to remove every + * slash from each <br /> tags. + * + * @author Danny van Heumen + */ +public class BrTagReplacer + implements Replacer +{ + + /** + * BrTagReplacer expects HTML content. + * + * @return false for HTML content + */ + @Override + public boolean expectsPlainText() + { + return false; + } + + /** + * Replace operation. "New-style" br-tags are processed and the result + * written to target. + * + * @param target destination of the replacer result + * @param piece piece of HTML content with properly formatted <br> + * tags. + */ + @Override + public void replace(final StringBuilder target, final String piece) + { + // Compile the regex to match something like
or
. + // This regex is case sensitive and keeps the style or other + // attributes of the
tag. + Matcher m = + Pattern.compile("<\\s*[bB][rR](.*?)(/\\s*>)").matcher(piece); + int start = 0; + + // while we find some
closing tags with a slash inside. + while (m.find()) + { + // First, we have to copy all the message preceding the
+ // tag. + target.append(piece.substring(start, m.start())); + // Then, we find the position of the slash inside the tag. + final int slashIndex = m.group().lastIndexOf("/"); + // We copy the
tag till the slash exclude. + target.append(m.group().substring(0, slashIndex)); + // We copy all the end of the tag following the slash exclude. + target.append(m.group().substring(slashIndex + 1)); + start = m.end(); + } + // Finally, we have to add the end of the message following the last + //
tag, or the whole message if there is no
tag. + target.append(piece.substring(start)); + } +} diff --git a/src/net/java/sip/communicator/impl/gui/main/chat/replacers/ImgTagReplacer.java b/src/net/java/sip/communicator/impl/gui/main/chat/replacers/ImgTagReplacer.java new file mode 100644 index 000000000..40314a28d --- /dev/null +++ b/src/net/java/sip/communicator/impl/gui/main/chat/replacers/ImgTagReplacer.java @@ -0,0 +1,74 @@ +/* + * Jitsi, the OpenSource Java VoIP and Instant Messaging client. + * + * Distributable under LGPL license. + * See terms of license at gnu.org. + */ +package net.java.sip.communicator.impl.gui.main.chat.replacers; + +import java.util.regex.*; + +import net.java.sip.communicator.impl.gui.main.chat.*; + +/** + * Formats HTML tags <img ... /> to < img ... ></img> or + * <IMG ... /> to <IMG></IMG>. The reason of this + * {@link Replacer} is that the ChatPanel does not support <img /> tags + * (XHTML syntax). Thus, we remove every slash from each <img /> and close + * it with a separate closing tag. + * + * @author Danny van Heumen + */ +public class ImgTagReplacer + implements Replacer +{ + + /** + * Img tag replacer expects HTML content. + * + * @return returns false for HTML content + */ + @Override + public boolean expectsPlainText() + { + return false; + } + + /** + * Replace operation that replaces img tags that immediately close. + * + * @param target destination to write the result to + * @param piece the piece of content to process + */ + @Override + public void replace(final StringBuilder target, final String piece) + { + // Compile the regex to match something like or + // . This regex is case sensitive and keeps the style, + // src or other attributes of the tag. + final Pattern p = Pattern.compile("<\\s*[iI][mM][gG](.*?)(/\\s*>)"); + final Matcher m = p.matcher(piece); + int slashIndex; + int start = 0; + + // while we find some self-closing tags with a slash inside. + while (m.find()) + { + // First, we have to copy all the message preceding the + // tag. + target.append(piece.substring(start, m.start())); + // Then, we find the position of the slash inside the tag. + slashIndex = m.group().lastIndexOf("/"); + // We copy the tag till the slash exclude. + target.append(m.group().substring(0, slashIndex)); + // We copy all the end of the tag following the slash exclude. + target.append(m.group().substring(slashIndex + 1)); + // We close the tag with a separate closing tag. + target.append(""); + start = m.end(); + } + // Finally, we have to add the end of the message following the last + // tag, or the whole message if there is no tag. + target.append(piece.substring(start)); + } +} diff --git a/src/net/java/sip/communicator/impl/gui/main/chat/replacers/KeywordReplacer.java b/src/net/java/sip/communicator/impl/gui/main/chat/replacers/KeywordReplacer.java new file mode 100644 index 000000000..fd78537f9 --- /dev/null +++ b/src/net/java/sip/communicator/impl/gui/main/chat/replacers/KeywordReplacer.java @@ -0,0 +1,83 @@ +/* + * Jitsi, the OpenSource Java VoIP and Instant Messaging client. + * + * Distributable under LGPL license. + * See terms of license at gnu.org. + */ +package net.java.sip.communicator.impl.gui.main.chat.replacers; + +import java.util.regex.*; + +import net.java.sip.communicator.impl.gui.main.chat.*; + +import org.apache.commons.lang3.*; + +/** + * The keyword replacer used for highlighting keywords. + * + * @author Danny van Heumen + */ +public class KeywordReplacer + implements Replacer +{ + /** + * The keyword to highlight. + */ + private final String keyword; + + /** + * The keyword replacer with parameter for providing the keyword to + * highlight. + * + * @param keyword the keyword to highlight when replacing + */ + public KeywordReplacer(final String keyword) + { + this.keyword = keyword; + } + + /** + * Type of content expected by the replacer. + * + * @return returns true for HTML content + */ + @Override + public boolean expectsPlainText() + { + return true; + } + + /** + * Replace operation. Searches for the keyword in the provided piece of + * content and replaces it with the piece of content surrounded by <b> + * tags. + * + * @param target the destination to write the result to + * @param piece the piece of content to process + */ + @Override + public void replace(final StringBuilder target, final String piece) + { + if (this.keyword == null || this.keyword.isEmpty()) + { + target.append(StringEscapeUtils.escapeHtml4(piece)); + return; + } + + final Matcher m = + Pattern.compile(Pattern.quote(keyword), Pattern.CASE_INSENSITIVE) + .matcher(piece); + int prevEnd = 0; + while (m.find()) + { + target.append(StringEscapeUtils.escapeHtml4(piece.substring( + prevEnd, m.start()))); + prevEnd = m.end(); + final String keywordMatch = m.group().trim(); + target.append(""); + target.append(StringEscapeUtils.escapeHtml4(keywordMatch)); + target.append(""); + } + target.append(StringEscapeUtils.escapeHtml4(piece.substring(prevEnd))); + } +} diff --git a/src/net/java/sip/communicator/impl/gui/main/chat/replacers/NewlineReplacer.java b/src/net/java/sip/communicator/impl/gui/main/chat/replacers/NewlineReplacer.java new file mode 100644 index 000000000..eb4019bb8 --- /dev/null +++ b/src/net/java/sip/communicator/impl/gui/main/chat/replacers/NewlineReplacer.java @@ -0,0 +1,57 @@ +/* + * Jitsi, the OpenSource Java VoIP and Instant Messaging client. + * + * Distributable under LGPL license. + * See terms of license at gnu.org. + */ +package net.java.sip.communicator.impl.gui.main.chat.replacers; + +import net.java.sip.communicator.impl.gui.main.chat.*; + +/** + * NewlineReplacer for replacing newlines with a combined version of a + * <br> tag and a \n character. This special treatment is + * necessary because copy-paste operations from the chat window do not recognize + * the <br> tags as line breaks. + * + * @author Danny van Heumen + */ +public class NewlineReplacer + implements Replacer +{ + + /** + * The NewlineReplacer expects HTML content. + * + * @return returns false + */ + @Override + public boolean expectsPlainText() + { + return false; + } + + /** + * New line characters are searched and replaced with a combination of + * newline and br tag. + * + * @param target the destination for to write the replacement result to + * @param piece the piece of content to process + */ + @Override + public void replace(final StringBuilder target, final String piece) + { + /* + *
tags are needed to visualize a new line in the html format, but + * when copied to the clipboard they are exported to the plain text + * format as ' ' and not as '\n'. + * + * See bug N4988885: + * http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4988885 + * + * To fix this we need " " - the HTML-Code for ASCII-Character No.10 + * (Line feed). + */ + target.append(piece.replaceAll("\n", "
")); + } +} diff --git a/src/net/java/sip/communicator/impl/gui/main/chat/replacers/URLReplacer.java b/src/net/java/sip/communicator/impl/gui/main/chat/replacers/URLReplacer.java new file mode 100644 index 000000000..6e69a15eb --- /dev/null +++ b/src/net/java/sip/communicator/impl/gui/main/chat/replacers/URLReplacer.java @@ -0,0 +1,85 @@ +/* + * Jitsi, the OpenSource Java VoIP and Instant Messaging client. + * + * Distributable under LGPL license. + * See terms of license at gnu.org. + */ +package net.java.sip.communicator.impl.gui.main.chat.replacers; + +import java.util.regex.*; + +import net.java.sip.communicator.impl.gui.main.chat.*; + +import org.apache.commons.lang3.*; + +/** + * The URL replacer used for replacing identified URL's with variations that are + * surrounded by A-tags (anchor tags). + * + * @author Danny van Heumen + */ +public class URLReplacer + implements Replacer +{ + /** + * The URL pattern to be used in matching. + */ + private final Pattern pattern; + + /** + * The URL Replacer. + * + * @param urlPattern the exact URL pattern to be applied + */ + public URLReplacer(final Pattern urlPattern) + { + if (urlPattern == null) + { + throw new IllegalArgumentException("urlPattern cannot be null"); + } + this.pattern = urlPattern; + } + + /** + * Plain text is expected. + * + * @return returns true for plain text expectation + */ + @Override + public boolean expectsPlainText() + { + return true; + } + + /** + * Replace operation for replacing URL's with a hyperlinked version. + * + * @param target destination to write the replacement result to + * @param piece the piece of content to be processed + */ + @Override + public void replace(final StringBuilder target, final String piece) + { + final Matcher m = this.pattern.matcher(piece); + int prevEnd = 0; + + while (m.find()) + { + target.append(StringEscapeUtils.escapeHtml4(piece.substring( + prevEnd, m.start()))); + prevEnd = m.end(); + + String url = m.group().trim(); + target.append(""); + target.append(StringEscapeUtils.escapeHtml4(url)); + target.append(""); + } + target.append(StringEscapeUtils.escapeHtml4(piece.substring(prevEnd))); + } +} diff --git a/src/net/java/sip/communicator/impl/gui/main/chat/replacers/package-info.java b/src/net/java/sip/communicator/impl/gui/main/chat/replacers/package-info.java new file mode 100644 index 000000000..f2f2f8360 --- /dev/null +++ b/src/net/java/sip/communicator/impl/gui/main/chat/replacers/package-info.java @@ -0,0 +1,14 @@ +/* + * Jitsi, the OpenSource Java VoIP and Instant Messaging client. + * + * Distributable under LGPL license. + * See terms of license at gnu.org. + */ +/** + * A package for replacer implementations for processing chat messages before + * they are sent to the chat conversation panel as HTML. + */ +/** + * @author Danny van Heumen + */ +package net.java.sip.communicator.impl.gui.main.chat.replacers;