00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 package com.realtime.crossfire.jxclient.gui.log;
00023
00024 import java.awt.Color;
00025 import java.util.HashMap;
00026 import java.util.Map;
00027 import java.util.regex.Pattern;
00028 import org.jetbrains.annotations.NotNull;
00029 import org.jetbrains.annotations.Nullable;
00030
00036 public class Parser {
00037
00041 @NotNull
00042 private static final Map<String, FontID> FONTS = new HashMap<String, FontID>();
00043
00044 static {
00045 FONTS.put("print", FontID.PRINT);
00046 FONTS.put("fixed", FontID.FIXED);
00047 FONTS.put("arcane", FontID.ARCANE);
00048 FONTS.put("hand", FontID.HAND);
00049 FONTS.put("strange", FontID.STRANGE);
00050 }
00051
00055 @NotNull
00056 private static final Map<String, Color> COLORS = new HashMap<String, Color>();
00057
00058 static {
00059 COLORS.put("black", Color.BLACK);
00060 COLORS.put("blue", Color.BLUE);
00061 COLORS.put("green", Color.GREEN);
00062 COLORS.put("red", Color.RED);
00063 COLORS.put("white", Color.WHITE);
00064 }
00065
00069 @NotNull
00070 private static final Pattern WORD_SEPARATOR_PATTERN = Pattern.compile(" ");
00071
00075 @NotNull
00076 private static final Pattern END_OF_LINE_PATTERN = Pattern.compile(" *\n");
00077
00081 private boolean bold = false;
00082
00086 private boolean italic = false;
00087
00091 private boolean underline = false;
00092
00096 private FontID font = FontID.PRINT;
00097
00101 @Nullable
00102 private Color color = null;
00103
00110 public void parse(@NotNull final CharSequence text, @Nullable final Color defaultColor, @NotNull final Buffer buffer) {
00111 resetAttributes(defaultColor);
00112 for (final String line : END_OF_LINE_PATTERN.split(text, -1)) {
00113 parseLine(line, defaultColor, buffer);
00114 }
00115 buffer.prune();
00116 }
00117
00124 public void parseWithoutMediaTags(@NotNull final CharSequence text, @NotNull final Color color, @NotNull final Buffer buffer) {
00125 if (text.length() == 0) {
00126 return;
00127 }
00128
00129 resetAttributes(color);
00130 for (final String line : END_OF_LINE_PATTERN.split(text, -1)) {
00131 parseLineWithoutMediaTags(line, buffer);
00132 }
00133 buffer.prune();
00134 }
00135
00142 private void parseLine(@NotNull final String text, @Nullable final Color defaultColor, @NotNull final Buffer buffer) {
00143 if (buffer.mergeLines(text, defaultColor)) {
00144 buffer.replaceLine(parseLine(text+" [["+buffer.getLastCount()+" times]", defaultColor));
00145 } else {
00146 buffer.addLine(parseLine(text, defaultColor));
00147 }
00148 }
00149
00156 @NotNull
00157 private Line parseLine(@NotNull final String text, @Nullable final Color defaultColor) {
00158 final Line line = new Line();
00159
00160 int begin = 0;
00161 boolean active = false;
00162 final int iMax = text.length();
00163 for (int i = 0; i < iMax; i++) {
00164 final char ch = text.charAt(i);
00165 if (active) {
00166 if (ch == ']') {
00167 processTag(text.substring(begin, i), defaultColor);
00168 begin = i+1;
00169 active = false;
00170 } else if (ch == '[' && i == begin) {
00171 processText("[", line);
00172 begin = i+1;
00173 active = false;
00174 }
00175 } else {
00176 if (ch == '[') {
00177 processText(text.substring(begin, i), line);
00178 begin = i+1;
00179 active = true;
00180 }
00181 }
00182 }
00183 if (!active) {
00184 processText(text.substring(begin, iMax), line);
00185 }
00186
00187 return line;
00188 }
00189
00195 private void parseLineWithoutMediaTags(@NotNull final String text, @NotNull final Buffer buffer) {
00196 final Line line = new Line();
00197 if (buffer.mergeLines(text, null)) {
00198 processText(text+" ["+buffer.getLastCount()+" times]", line);
00199 buffer.replaceLine(line);
00200 } else {
00201 processText(text, line);
00202 buffer.addLine(line);
00203 }
00204 }
00205
00210 private void resetAttributes(@Nullable final Color defaultColor) {
00211 bold = false;
00212 italic = false;
00213 underline = false;
00214 font = FontID.PRINT;
00215 color = defaultColor;
00216 }
00217
00224 private void processTag(@NotNull final String tag, @Nullable final Color defaultColor) {
00225 if (tag.length() == 0) {
00226 return;
00227 }
00228
00229 if (tag.equals("b")) {
00230 bold = true;
00231 } else if (tag.equals("/b")) {
00232 bold = false;
00233 } else if (tag.equals("i")) {
00234 italic = true;
00235 } else if (tag.equals("/i")) {
00236 italic = false;
00237 } else if (tag.equals("ul")) {
00238 underline = true;
00239 } else if (tag.equals("/ul")) {
00240 underline = false;
00241 } else if (FONTS.containsKey(tag)) {
00242 font = FONTS.get(tag);
00243 assert font != null;
00244 } else if (tag.startsWith("color=")) {
00245 final String colorName = tag.substring(6).toLowerCase();
00246 if (COLORS.containsKey(colorName)) {
00247 color = COLORS.get(colorName);
00248 assert color != null;
00249
00250
00251 }
00252 } else if (tag.equals("/color")) {
00253 color = defaultColor;
00254
00255
00256 }
00257 }
00258
00264 private void processText(@NotNull final String text, @NotNull final Line line) {
00265 if (text.length() == 0) {
00266 return;
00267 }
00268
00269 final CharSequence newText;
00270 final Segment prevSegment = line.getLastSegment();
00271 if (prevSegment == null || !(prevSegment instanceof TextSegment)) {
00272 newText = text;
00273 } else {
00274 final TextSegment prevTextSegment = (TextSegment)prevSegment;
00275 if (prevTextSegment.matches(bold, italic, underline, font, color)) {
00276 newText = prevTextSegment.getText()+text;
00277 line.removeLastSegment();
00278 } else {
00279 newText = text;
00280 }
00281 }
00282
00283 final String[] words = WORD_SEPARATOR_PATTERN.split(newText, -1);
00284 for (int i = 0; i < words.length-1; i++) {
00285 line.addSegment(words[i]+" ", bold, italic, underline, font, color);
00286 }
00287 if (words[words.length-1].length() > 0) {
00288 line.addSegment(words[words.length-1], bold, italic, underline, font, color);
00289 }
00290 }
00291
00297 @NotNull
00298 public static String toString(@NotNull final Color color) {
00299
00300
00301 for (final Map.Entry<String, Color> e : COLORS.entrySet()) {
00302 if (e.getValue() == color) {
00303 return e.getKey();
00304 }
00305 }
00306
00307 return "unknown";
00308 }
00309
00310 }