1 2 /* 3 ******************************************************************************* 4 * Copyright (C) 2002-2012, International Business Machines Corporation and * 5 * others. All Rights Reserved. * 6 ******************************************************************************* 7 */ 8 package org.unicode.cldr.util; 9 10 import java.util.ArrayList; 11 import java.util.List; 12 13 import com.ibm.icu.lang.CharSequences; 14 import com.ibm.icu.text.UnicodeSet; 15 16 public abstract class Tabber { 17 public static final byte LEFT = 0, CENTER = 1, RIGHT = 2; 18 private static final String[] ALIGNMENT_NAMES = { "Left", "Center", "Right" }; 19 20 /** 21 * Repeats a string n times 22 * @param source 23 * @param times 24 */ 25 // TODO - optimize repeats using doubling? repeat(String source, int times)26 public static String repeat(String source, int times) { 27 if (times <= 0) return ""; 28 if (times == 1) return source; 29 StringBuffer result = new StringBuffer(); 30 for (; times > 0; --times) { 31 result.append(source); 32 } 33 return result.toString(); 34 } 35 process(String source)36 public String process(String source) { 37 StringBuffer result = new StringBuffer(); 38 int lastPos = 0; 39 for (int count = 0; lastPos < source.length(); ++count) { 40 int pos = source.indexOf('\t', lastPos); 41 if (pos < 0) pos = source.length(); 42 process_field(count, source, lastPos, pos, result); 43 lastPos = pos + 1; 44 } 45 return prefix + result.toString() + postfix; 46 } 47 48 private String prefix = ""; 49 private String postfix = ""; 50 process_field(int count, String source, int start, int limit, StringBuffer output)51 public abstract void process_field(int count, String source, int start, int limit, StringBuffer output); 52 clear()53 public Tabber clear() { 54 return this; 55 } 56 57 public static class MonoTabber extends Tabber { 58 int minGap = 0; 59 60 private List stops = new ArrayList(); 61 private List types = new ArrayList(); 62 63 @Override clear()64 public Tabber clear() { 65 stops.clear(); 66 types.clear(); 67 minGap = 0; 68 return this; 69 } 70 71 @Override toString()72 public String toString() { 73 StringBuffer buffer = new StringBuffer(); 74 for (int i = 0; i < stops.size(); ++i) { 75 if (i != 0) buffer.append("; "); 76 buffer 77 .append(ALIGNMENT_NAMES[((Integer) types.get(i)).intValue()]) 78 .append(",") 79 .append(stops.get(i)); 80 } 81 return buffer.toString(); 82 } 83 84 /** 85 * Adds tab stop and how to align the text UP TO that stop 86 * @param tabPos 87 * @param type 88 */ addAbsolute(int tabPos, int type)89 public MonoTabber addAbsolute(int tabPos, int type) { 90 stops.add(new Integer(tabPos)); 91 types.add(new Integer(type)); 92 return this; 93 } 94 95 /** 96 * Adds relative tab stop and how to align the text UP TO that stop 97 */ 98 @Override add(int fieldWidth, byte type)99 public Tabber add(int fieldWidth, byte type) { 100 int last = getStop(stops.size() - 1); 101 stops.add(new Integer(last + fieldWidth)); 102 types.add(new Integer(type)); 103 return this; 104 } 105 getStop(int fieldNumber)106 public int getStop(int fieldNumber) { 107 if (fieldNumber < 0) return 0; 108 if (fieldNumber >= stops.size()) fieldNumber = stops.size() - 1; 109 return ((Integer) stops.get(fieldNumber)).intValue(); 110 } 111 getType(int fieldNumber)112 public int getType(int fieldNumber) { 113 if (fieldNumber < 0) return LEFT; 114 if (fieldNumber >= stops.size()) return LEFT; 115 return ((Integer) types.get(fieldNumber)).intValue(); 116 } 117 118 @Override process_field(int count, String source, int start, int limit, StringBuffer output)119 public void process_field(int count, String source, int start, int limit, StringBuffer output) { 120 String piece = source.substring(start, limit); 121 int startPos = getStop(count - 1); 122 int endPos = getStop(count) - minGap; 123 int type = getType(count); 124 final int pieceLength = getMonospaceWidth(piece); 125 switch (type) { 126 case LEFT: 127 break; 128 case RIGHT: 129 startPos = endPos - pieceLength; 130 break; 131 case CENTER: 132 startPos = (startPos + endPos - pieceLength + 1) / 2; 133 break; 134 } 135 136 int gap = startPos - getMonospaceWidth(output); 137 if (count != 0 && gap < minGap) gap = minGap; 138 if (gap > 0) output.append(repeat(" ", gap)); 139 output.append(piece); 140 } 141 142 static final UnicodeSet IGNOREABLE = new UnicodeSet("[:di:]"); 143 getMonospaceWidth(CharSequence piece)144 private int getMonospaceWidth(CharSequence piece) { 145 int len = 0; 146 for (int cp : CharSequences.codePoints(piece)) { 147 if (!IGNOREABLE.contains(cp)) { 148 ++len; 149 } 150 } 151 return len; 152 } 153 } 154 155 public static Tabber NULL_TABBER = new Tabber() { 156 @Override 157 public void process_field(int count, String source, int start, int limit, StringBuffer output) { 158 if (count > 0) output.append("\t"); 159 output.append(source.substring(start, limit)); 160 } 161 }; 162 163 public static class HTMLTabber extends Tabber { 164 private List<String> parameters = new ArrayList(); 165 private String element = "td"; 166 { 167 setPrefix("<tr>"); 168 setPostfix("</tr>"); 169 } 170 setParameters(int count, String params)171 public HTMLTabber setParameters(int count, String params) { 172 // fill in 173 while (parameters.size() <= count) { 174 parameters.add(null); 175 } 176 parameters.set(count, params); 177 return this; 178 } 179 getElement()180 public String getElement() { 181 return element; 182 } 183 setElement(String element)184 public HTMLTabber setElement(String element) { 185 this.element = element; 186 return this; 187 } 188 189 @Override process_field(int count, String source, int start, int limit, StringBuffer output)190 public void process_field(int count, String source, int start, int limit, StringBuffer output) { 191 output.append("<" + element); 192 String params = null; 193 if (count < parameters.size()) { 194 params = parameters.get(count); 195 } 196 if (params != null) { 197 output.append(' '); 198 output.append(params); 199 } 200 output.append(">"); 201 output.append(source.substring(start, limit)); 202 // TODO Quote string 203 output.append("</" + element + ">"); 204 } 205 } 206 207 /** 208 */ getPostfix()209 public String getPostfix() { 210 return postfix; 211 } 212 213 /** 214 */ getPrefix()215 public String getPrefix() { 216 return prefix; 217 } 218 219 /** 220 * @param string 221 */ setPostfix(String string)222 public Tabber setPostfix(String string) { 223 postfix = string; 224 return this; 225 } 226 227 /** 228 * @param string 229 */ setPrefix(String string)230 public Tabber setPrefix(String string) { 231 prefix = string; 232 return this; 233 } 234 add(int i, byte left2)235 public Tabber add(int i, byte left2) { 236 // does nothing unless overridden 237 return this; 238 } 239 240 } 241