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 clear()63 public Tabber clear() { 64 stops.clear(); 65 types.clear(); 66 minGap = 0; 67 return this; 68 } 69 toString()70 public String toString() { 71 StringBuffer buffer = new StringBuffer(); 72 for (int i = 0; i < stops.size(); ++i) { 73 if (i != 0) buffer.append("; "); 74 buffer 75 .append(ALIGNMENT_NAMES[((Integer) types.get(i)).intValue()]) 76 .append(",") 77 .append(stops.get(i)); 78 } 79 return buffer.toString(); 80 } 81 82 /** 83 * Adds tab stop and how to align the text UP TO that stop 84 * @param tabPos 85 * @param type 86 */ addAbsolute(int tabPos, int type)87 public MonoTabber addAbsolute(int tabPos, int type) { 88 stops.add(new Integer(tabPos)); 89 types.add(new Integer(type)); 90 return this; 91 } 92 93 /** 94 * Adds relative tab stop and how to align the text UP TO that stop 95 */ add(int fieldWidth, byte type)96 public Tabber add(int fieldWidth, byte type) { 97 int last = getStop(stops.size() - 1); 98 stops.add(new Integer(last + fieldWidth)); 99 types.add(new Integer(type)); 100 return this; 101 } 102 getStop(int fieldNumber)103 public int getStop(int fieldNumber) { 104 if (fieldNumber < 0) return 0; 105 if (fieldNumber >= stops.size()) fieldNumber = stops.size() - 1; 106 return ((Integer) stops.get(fieldNumber)).intValue(); 107 } 108 getType(int fieldNumber)109 public int getType(int fieldNumber) { 110 if (fieldNumber < 0) return LEFT; 111 if (fieldNumber >= stops.size()) return LEFT; 112 return ((Integer) types.get(fieldNumber)).intValue(); 113 } 114 process_field(int count, String source, int start, int limit, StringBuffer output)115 public void process_field(int count, String source, int start, int limit, StringBuffer output) { 116 String piece = source.substring(start, limit); 117 int startPos = getStop(count - 1); 118 int endPos = getStop(count) - minGap; 119 int type = getType(count); 120 final int pieceLength = getMonospaceWidth(piece); 121 switch (type) { 122 case LEFT: 123 break; 124 case RIGHT: 125 startPos = endPos - pieceLength; 126 break; 127 case CENTER: 128 startPos = (startPos + endPos - pieceLength + 1) / 2; 129 break; 130 } 131 132 int gap = startPos - getMonospaceWidth(output); 133 if (count != 0 && gap < minGap) gap = minGap; 134 if (gap > 0) output.append(repeat(" ", gap)); 135 output.append(piece); 136 } 137 138 static final UnicodeSet IGNOREABLE = new UnicodeSet("[:di:]"); 139 getMonospaceWidth(CharSequence piece)140 private int getMonospaceWidth(CharSequence piece) { 141 int len = 0; 142 for (int cp : CharSequences.codePoints(piece)) { 143 if (!IGNOREABLE.contains(cp)) { 144 ++len; 145 } 146 } 147 return len; 148 } 149 } 150 151 public static Tabber NULL_TABBER = new Tabber() { 152 public void process_field(int count, String source, int start, int limit, StringBuffer output) { 153 if (count > 0) output.append("\t"); 154 output.append(source.substring(start, limit)); 155 } 156 }; 157 158 public static class HTMLTabber extends Tabber { 159 private List<String> parameters = new ArrayList(); 160 private String element = "td"; 161 { 162 setPrefix("<tr>"); 163 setPostfix("</tr>"); 164 } 165 setParameters(int count, String params)166 public HTMLTabber setParameters(int count, String params) { 167 // fill in 168 while (parameters.size() <= count) { 169 parameters.add(null); 170 } 171 parameters.set(count, params); 172 return this; 173 } 174 getElement()175 public String getElement() { 176 return element; 177 } 178 setElement(String element)179 public HTMLTabber setElement(String element) { 180 this.element = element; 181 return this; 182 } 183 process_field(int count, String source, int start, int limit, StringBuffer output)184 public void process_field(int count, String source, int start, int limit, StringBuffer output) { 185 output.append("<" + element); 186 String params = null; 187 if (count < parameters.size()) { 188 params = parameters.get(count); 189 } 190 if (params != null) { 191 output.append(' '); 192 output.append(params); 193 } 194 output.append(">"); 195 output.append(source.substring(start, limit)); 196 // TODO Quote string 197 output.append("</" + element + ">"); 198 } 199 } 200 201 /** 202 */ getPostfix()203 public String getPostfix() { 204 return postfix; 205 } 206 207 /** 208 */ getPrefix()209 public String getPrefix() { 210 return prefix; 211 } 212 213 /** 214 * @param string 215 */ setPostfix(String string)216 public Tabber setPostfix(String string) { 217 postfix = string; 218 return this; 219 } 220 221 /** 222 * @param string 223 */ setPrefix(String string)224 public Tabber setPrefix(String string) { 225 prefix = string; 226 return this; 227 } 228 add(int i, byte left2)229 public Tabber add(int i, byte left2) { 230 // does nothing unless overridden 231 return this; 232 } 233 234 } 235