/*
* 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;
}
}