xref: /aosp_15_r20/external/cldr/tools/cldr-code/src/main/java/org/unicode/cldr/util/Tabber.java (revision 912701f9769bb47905792267661f0baf2b85bed5)
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