This must have been done a hundred time before, but let me show you this JTextPane which allow the insertion of smiley in the text :
This is done with a styled document which use a document filter which will apply style on the fly when you insert text.
The code :
package org.clbproduction.cloud.core.gui.components;
import java.util.Enumeration;
import javax.swing.Icon;
import javax.swing.text.AttributeSet;
import javax.swing.text.BadLocationException;
import javax.swing.text.DefaultStyledDocument;
import javax.swing.text.DocumentFilter;
import javax.swing.text.Style;
import javax.swing.text.StyleConstants;
import javax.swing.text.StyleContext;
public class SmileyStyledDocument extends DefaultStyledDocument {
private static final String SMILEY_STYLE_PREFIX = "smiley_";
private JTextPane textPane;
public SmileyStyledDocument(JTextPane textPane) {
this.textPane = textPane;
this.setDocumentFilter(new MessageDocumentFilter());
}
public Style getSmileyStyle(String text) {
Icon icon = SmileyManager.getSmileyIcon(text); // load your icon here
if (icon != null) {
Style style = addStyle(SMILEY_STYLE_PREFIX + text, StyleContext.getDefaultStyleContext().getStyle(StyleContext.DEFAULT_STYLE));
StyleConstants.setAlignment(style, StyleConstants.ALIGN_CENTER);
StyleConstants.setIcon(style, icon);
return style;
} else
return StyleContext.getDefaultStyleContext().getStyle(StyleContext.DEFAULT_STYLE);
}
public class MessageDocumentFilter extends DocumentFilter {
@Override
public void remove(FilterBypass fb, int offs, int len) throws BadLocationException {
super.remove(fb, offs, len);
this.computeText(fb);
}
@Override
public void replace(FilterBypass fb, int offset, int length, String text, AttributeSet a) throws BadLocationException {
super.replace(fb, offset, length, text, a);
this.computeText(fb);
}
@Override
public void insertString(FilterBypass fb, int offset, String string, AttributeSet attr) throws BadLocationException {
super.insertString(fb, offset, string, attr);
this.computeText(fb);
}
public void computeText(FilterBypass fb) throws BadLocationException {
int caretPos = textPane.getCaretPosition();
for (int i = 0; i < getLength(); i++) {
fb.replace(i, 1, getText(i, 1), StyleContext.getDefaultStyleContext().getStyle(StyleContext.DEFAULT_STYLE););
Enumeration smileys = SmileyManager.getAllSmileys();
while (smileys.hasMoreElements()) {
String smiley = (String) smileys.nextElement();
if (getText(i, smiley.length()).equals(smiley)) {
fb.replace(i, smiley.length(), smiley, getSmileyStyle(smiley));
i = i + smiley.length() - 1;
break;
}
}
}
textPane.setCaretPosition(caretPos);
}
}
}
And how to use it :
JTextPane textPane = new JTextPane();
this.textPane.setStyledDocument(new SmileyStyledDocument(textPane));
I left the implementation of the "SmileyManager" class as an exercice to the reader :)
import java.util.Enumeration;
import javax.swing.Icon;
import javax.swing.ImageIcon;
public class SmileyManager {
public void addSmiley(String text, String icon) {
//...
}
public Icon getSmileyIcon(String text) {
//...
}
public void removeSmiley(String text) {
//...
}
public Enumeration getAllSmileys() {
//...
}
}
Work well with this smiley menu :)
Issues :
- if a smiley is the prefix of an other smiley then only the first one is displayed (for example :| and :|| )
- a new style is added each time a smiley is inserted. We could/should reuse the previously created style

0 comments:
Post a Comment