/* * Copyright 2010-2015 Institut Pasteur. * * This file is part of Icy. * * Icy is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Icy is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Icy. If not, see <http://www.gnu.org/licenses/>. */ package icy.network; import icy.util.StringUtil; import java.awt.Color; import javax.swing.text.BadLocationException; import javax.swing.text.Document; import javax.swing.text.SimpleAttributeSet; import javax.swing.text.StyleConstants; /** * IRC utilities class. * * @author Stephane */ public class IRCUtil { public static final char CHAR_BOLD = 2; public static final char CHAR_ITALIC = 22; public static final char CHAR_UNDERLINE = 31; public static final char CHAR_COLOR = 3; public static final char CHAR_RESET = 15; public static class IRCAttribute { final static int UNKNOWN = -1; final static int NORMAL = 0; final static int BOLD = 1; final static int ITALIC = 2; final static int UNDERLINE = 4; final static int COLOR = 9; int type; int size; int arg1; int arg2; public IRCAttribute() { super(); type = NORMAL; size = 1; arg1 = -1; arg2 = -1; } } public static class IRCAttributeSet { int style; Color foreground; Color background; public IRCAttributeSet() { super(); // default style = IRCAttribute.NORMAL; foreground = null; background = null; } } /** * Insert the specified IRC string into specified Document. * * @param ircString * IRC string containing IRC code. * @param doc * doc when we want to insert the IRC styled string. * @param defaultAttributes * default string attributes. * @throws BadLocationException */ public static void insertString(String ircString, Document doc, SimpleAttributeSet defaultAttributes) throws BadLocationException { final IRCAttributeSet state = new IRCAttributeSet(); SimpleAttributeSet attr = new SimpleAttributeSet(defaultAttributes); final int len = ircString.length(); int curInd = 0; while (curInd < len) { int ctrlIndex = StringUtil.getNextCtrlCharIndex(ircString, curInd); // end of line if (ctrlIndex == -1) ctrlIndex = len; if (curInd != ctrlIndex) // insert styled string doc.insertString(doc.getLength(), ircString.substring(curInd, ctrlIndex), attr); // end of string --> terminate if (ctrlIndex >= len) break; // get IRC attribute final IRCAttribute ircAttr = getAttribute(ircString, ctrlIndex); // not an IRC attribute --> insert control character in document if (ircAttr.type == IRCAttribute.UNKNOWN) doc.insertString(doc.getLength(), ircString.substring(ctrlIndex, ctrlIndex + 1), attr); else { // apply attribute to current state applyAttribute(state, ircAttr); // create attributes from default attributes and current IRC attribute state attr = createAttributeSet(defaultAttributes, state); } // next... curInd = ctrlIndex + ircAttr.size; } } /** * Return the IRC attribute corresponding to the control code at specified index. */ public static IRCAttribute getAttribute(String ircString, int index) { final IRCAttribute result = new IRCAttribute(); final int len = ircString.length(); // no more text if (index >= len) return null; int offset = index + 1; int end; switch (ircString.charAt(index)) { case CHAR_RESET: // reset default result.type = IRCAttribute.NORMAL; break; case CHAR_BOLD: // switch bold result.type = IRCAttribute.BOLD; break; case CHAR_ITALIC: // switch italic result.type = IRCAttribute.ITALIC; break; case CHAR_UNDERLINE: // switch underline result.type = IRCAttribute.UNDERLINE; break; case CHAR_COLOR: // color end = StringUtil.getNextNonDigitCharIndex(ircString, offset); // no more than 2 digits to encode color if ((end == -1) || (end > (offset + 2))) end = Math.min(len, offset + 2); // color info ? if (end != offset) { // get foreground color result.arg1 = Integer.parseInt(ircString.substring(offset, end)); // update position offset = end; // search if we have background color if ((offset < len) && (ircString.charAt(offset) == ',')) { offset++; end = StringUtil.getNextNonDigitCharIndex(ircString, offset); // no more than 2 digits to encode color if ((end == -1) || (end > (offset + 2))) end = Math.min(len, offset + 2); // get background color if (end != offset) result.arg2 = Integer.parseInt(ircString.substring(offset, end)); } } result.size = end - index; break; default: // unknown result.type = IRCAttribute.UNKNOWN; // System.out.println("code " + Integer.toString(ircString.charAt(index))); break; } return result; } /** * Apply the specified IRC attribute on specified IRC attributes set.<br> * Some IRC attribute work as switch :<br> * If bold is already set and you apply bold again, then bold is removed from set. * * @param set * IRC attributes set. * @param attr * IRC single attribute. */ public static void applyAttribute(IRCAttributeSet set, IRCAttribute attr) { switch (attr.type) { case IRCAttribute.NORMAL: // reset attribute set.style = IRCAttribute.NORMAL; set.foreground = null; set.background = null; break; case IRCAttribute.BOLD: case IRCAttribute.ITALIC: case IRCAttribute.UNDERLINE: // switch-able attribute set.style ^= attr.type; break; case IRCAttribute.COLOR: // no color information if (attr.arg1 == -1) { // reset set.foreground = null; set.background = null; } else { set.foreground = getIRCColor(attr.arg1); // background color info ? if (attr.arg2 != -1) set.background = getIRCColor(attr.arg2); } break; } } /** * Return a new AttributeSet from the given default set and IRC attributes. * * @param defaultAttributes * default Attribute Set we use as base attributes. * @param ircAttributes * IRC attributes used to modifying default attributes. */ public static SimpleAttributeSet createAttributeSet(SimpleAttributeSet defaultAttributes, IRCAttributeSet ircAttributes) { final SimpleAttributeSet result = new SimpleAttributeSet(defaultAttributes); if ((ircAttributes.style & IRCAttribute.BOLD) != 0) StyleConstants.setBold(result, true); if ((ircAttributes.style & IRCAttribute.ITALIC) != 0) StyleConstants.setItalic(result, true); if ((ircAttributes.style & IRCAttribute.UNDERLINE) != 0) StyleConstants.setUnderline(result, true); if (ircAttributes.foreground != null) StyleConstants.setForeground(result, ircAttributes.foreground); if (ircAttributes.background != null) StyleConstants.setBackground(result, ircAttributes.background); return result; } /** * Return the color corresponding to the specified IRC color code. */ public static Color getIRCColor(int num) { switch (num) { case 0: case 16: // white return Color.white; case 1: return Color.black; case 2: return Color.blue; case 3: return Color.green; case 4: return Color.red; case 5: // brown return new Color(0x8b4513); case 6: // purple return new Color(0xa020f0); case 7: return Color.orange; case 8: return Color.yellow; case 9: // light green return new Color(0x80ff00); case 10: return Color.cyan; case 11: // light cyan return new Color(0x80ffff); case 12: // light blue return new Color(0x8080ff); case 13: return Color.pink; case 14: return Color.darkGray; case 15: return Color.lightGray; default: // transparent return new Color(0, true); } } /** * Returns IRC bold version of specified string. */ public static String getBoldString(String value) { return CHAR_BOLD + value + CHAR_BOLD; } /** * Returns IRC italic version of specified string. */ public static String getItalicString(String value) { return CHAR_ITALIC + value + CHAR_ITALIC; } /** * Returns IRC underline version of specified string. */ public static String getUnderlineString(String value) { return CHAR_UNDERLINE + value + CHAR_UNDERLINE; } }