001/* 002 * Copyright 2010-2015 Institut Pasteur. 003 * 004 * This file is part of Icy. 005 * 006 * Icy is free software: you can redistribute it and/or modify 007 * it under the terms of the GNU General Public License as published by 008 * the Free Software Foundation, either version 3 of the License, or 009 * (at your option) any later version. 010 * 011 * Icy is distributed in the hope that it will be useful, 012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 014 * GNU General Public License for more details. 015 * 016 * You should have received a copy of the GNU General Public License 017 * along with Icy. If not, see <http://www.gnu.org/licenses/>. 018 */ 019package icy.network; 020 021import icy.util.StringUtil; 022 023import java.awt.Color; 024 025import javax.swing.text.BadLocationException; 026import javax.swing.text.Document; 027import javax.swing.text.SimpleAttributeSet; 028import javax.swing.text.StyleConstants; 029 030/** 031 * IRC utilities class. 032 * 033 * @author Stephane 034 */ 035public class IRCUtil 036{ 037 public static final char CHAR_BOLD = 2; 038 public static final char CHAR_ITALIC = 22; 039 public static final char CHAR_UNDERLINE = 31; 040 public static final char CHAR_COLOR = 3; 041 public static final char CHAR_RESET = 15; 042 043 public static class IRCAttribute 044 { 045 final static int UNKNOWN = -1; 046 final static int NORMAL = 0; 047 final static int BOLD = 1; 048 final static int ITALIC = 2; 049 final static int UNDERLINE = 4; 050 051 final static int COLOR = 9; 052 053 int type; 054 int size; 055 int arg1; 056 int arg2; 057 058 public IRCAttribute() 059 { 060 super(); 061 062 type = NORMAL; 063 size = 1; 064 arg1 = -1; 065 arg2 = -1; 066 } 067 } 068 069 public static class IRCAttributeSet 070 { 071 int style; 072 Color foreground; 073 Color background; 074 075 public IRCAttributeSet() 076 { 077 super(); 078 079 // default 080 style = IRCAttribute.NORMAL; 081 foreground = null; 082 background = null; 083 } 084 } 085 086 /** 087 * Insert the specified IRC string into specified Document. 088 * 089 * @param ircString 090 * IRC string containing IRC code. 091 * @param doc 092 * doc when we want to insert the IRC styled string. 093 * @param defaultAttributes 094 * default string attributes. 095 * @throws BadLocationException 096 */ 097 public static void insertString(String ircString, Document doc, SimpleAttributeSet defaultAttributes) 098 throws BadLocationException 099 { 100 final IRCAttributeSet state = new IRCAttributeSet(); 101 SimpleAttributeSet attr = new SimpleAttributeSet(defaultAttributes); 102 103 final int len = ircString.length(); 104 int curInd = 0; 105 106 while (curInd < len) 107 { 108 int ctrlIndex = StringUtil.getNextCtrlCharIndex(ircString, curInd); 109 // end of line 110 if (ctrlIndex == -1) 111 ctrlIndex = len; 112 113 if (curInd != ctrlIndex) 114 // insert styled string 115 doc.insertString(doc.getLength(), ircString.substring(curInd, ctrlIndex), attr); 116 117 // end of string --> terminate 118 if (ctrlIndex >= len) 119 break; 120 121 // get IRC attribute 122 final IRCAttribute ircAttr = getAttribute(ircString, ctrlIndex); 123 124 // not an IRC attribute --> insert control character in document 125 if (ircAttr.type == IRCAttribute.UNKNOWN) 126 doc.insertString(doc.getLength(), ircString.substring(ctrlIndex, ctrlIndex + 1), attr); 127 else 128 { 129 // apply attribute to current state 130 applyAttribute(state, ircAttr); 131 // create attributes from default attributes and current IRC attribute state 132 attr = createAttributeSet(defaultAttributes, state); 133 } 134 135 // next... 136 curInd = ctrlIndex + ircAttr.size; 137 } 138 } 139 140 /** 141 * Return the IRC attribute corresponding to the control code at specified index. 142 */ 143 public static IRCAttribute getAttribute(String ircString, int index) 144 { 145 final IRCAttribute result = new IRCAttribute(); 146 final int len = ircString.length(); 147 148 // no more text 149 if (index >= len) 150 return null; 151 152 int offset = index + 1; 153 int end; 154 155 switch (ircString.charAt(index)) 156 { 157 case CHAR_RESET: 158 // reset default 159 result.type = IRCAttribute.NORMAL; 160 break; 161 162 case CHAR_BOLD: 163 // switch bold 164 result.type = IRCAttribute.BOLD; 165 break; 166 167 case CHAR_ITALIC: 168 // switch italic 169 result.type = IRCAttribute.ITALIC; 170 break; 171 172 case CHAR_UNDERLINE: 173 // switch underline 174 result.type = IRCAttribute.UNDERLINE; 175 break; 176 177 case CHAR_COLOR: 178 // color 179 end = StringUtil.getNextNonDigitCharIndex(ircString, offset); 180 // no more than 2 digits to encode color 181 if ((end == -1) || (end > (offset + 2))) 182 end = Math.min(len, offset + 2); 183 184 // color info ? 185 if (end != offset) 186 { 187 // get foreground color 188 result.arg1 = Integer.parseInt(ircString.substring(offset, end)); 189 190 // update position 191 offset = end; 192 193 // search if we have background color 194 if ((offset < len) && (ircString.charAt(offset) == ',')) 195 { 196 offset++; 197 198 end = StringUtil.getNextNonDigitCharIndex(ircString, offset); 199 // no more than 2 digits to encode color 200 if ((end == -1) || (end > (offset + 2))) 201 end = Math.min(len, offset + 2); 202 203 // get background color 204 if (end != offset) 205 result.arg2 = Integer.parseInt(ircString.substring(offset, end)); 206 } 207 } 208 209 result.size = end - index; 210 break; 211 212 default: 213 // unknown 214 result.type = IRCAttribute.UNKNOWN; 215 // System.out.println("code " + Integer.toString(ircString.charAt(index))); 216 break; 217 } 218 219 return result; 220 } 221 222 /** 223 * Apply the specified IRC attribute on specified IRC attributes set.<br> 224 * Some IRC attribute work as switch :<br> 225 * If bold is already set and you apply bold again, then bold is removed from set. 226 * 227 * @param set 228 * IRC attributes set. 229 * @param attr 230 * IRC single attribute. 231 */ 232 public static void applyAttribute(IRCAttributeSet set, IRCAttribute attr) 233 { 234 switch (attr.type) 235 { 236 case IRCAttribute.NORMAL: 237 // reset attribute 238 set.style = IRCAttribute.NORMAL; 239 set.foreground = null; 240 set.background = null; 241 break; 242 243 case IRCAttribute.BOLD: 244 case IRCAttribute.ITALIC: 245 case IRCAttribute.UNDERLINE: 246 // switch-able attribute 247 set.style ^= attr.type; 248 break; 249 250 case IRCAttribute.COLOR: 251 // no color information 252 if (attr.arg1 == -1) 253 { 254 // reset 255 set.foreground = null; 256 set.background = null; 257 } 258 else 259 { 260 set.foreground = getIRCColor(attr.arg1); 261 // background color info ? 262 if (attr.arg2 != -1) 263 set.background = getIRCColor(attr.arg2); 264 } 265 break; 266 } 267 } 268 269 /** 270 * Return a new AttributeSet from the given default set and IRC attributes. 271 * 272 * @param defaultAttributes 273 * default Attribute Set we use as base attributes. 274 * @param ircAttributes 275 * IRC attributes used to modifying default attributes. 276 */ 277 public static SimpleAttributeSet createAttributeSet(SimpleAttributeSet defaultAttributes, 278 IRCAttributeSet ircAttributes) 279 { 280 final SimpleAttributeSet result = new SimpleAttributeSet(defaultAttributes); 281 282 if ((ircAttributes.style & IRCAttribute.BOLD) != 0) 283 StyleConstants.setBold(result, true); 284 if ((ircAttributes.style & IRCAttribute.ITALIC) != 0) 285 StyleConstants.setItalic(result, true); 286 if ((ircAttributes.style & IRCAttribute.UNDERLINE) != 0) 287 StyleConstants.setUnderline(result, true); 288 289 if (ircAttributes.foreground != null) 290 StyleConstants.setForeground(result, ircAttributes.foreground); 291 if (ircAttributes.background != null) 292 StyleConstants.setBackground(result, ircAttributes.background); 293 294 return result; 295 } 296 297 /** 298 * Return the color corresponding to the specified IRC color code. 299 */ 300 public static Color getIRCColor(int num) 301 { 302 switch (num) 303 { 304 case 0: 305 case 16: 306 // white 307 return Color.white; 308 case 1: 309 return Color.black; 310 case 2: 311 return Color.blue; 312 case 3: 313 return Color.green; 314 case 4: 315 return Color.red; 316 case 5: 317 // brown 318 return new Color(0x8b4513); 319 case 6: 320 // purple 321 return new Color(0xa020f0); 322 case 7: 323 return Color.orange; 324 case 8: 325 return Color.yellow; 326 case 9: 327 // light green 328 return new Color(0x80ff00); 329 case 10: 330 return Color.cyan; 331 case 11: 332 // light cyan 333 return new Color(0x80ffff); 334 case 12: 335 // light blue 336 return new Color(0x8080ff); 337 case 13: 338 return Color.pink; 339 case 14: 340 return Color.darkGray; 341 case 15: 342 return Color.lightGray; 343 default: 344 // transparent 345 return new Color(0, true); 346 } 347 } 348 349 /** 350 * Returns IRC bold version of specified string. 351 */ 352 public static String getBoldString(String value) 353 { 354 return CHAR_BOLD + value + CHAR_BOLD; 355 } 356 357 /** 358 * Returns IRC italic version of specified string. 359 */ 360 public static String getItalicString(String value) 361 { 362 return CHAR_ITALIC + value + CHAR_ITALIC; 363 } 364 365 /** 366 * Returns IRC underline version of specified string. 367 */ 368 public static String getUnderlineString(String value) 369 { 370 return CHAR_UNDERLINE + value + CHAR_UNDERLINE; 371 } 372 373}