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