1 // Copyright (c) 2002 Per M.A. Bothner. 2 // This is free software; for terms and warranty disclaimer see ./COPYING. 3 4 package gnu.lists; 5 6 import gnu.kawa.io.OutPort; 7 import java.io.*; 8 import gnu.kawa.io.PrettyWriter; 9 10 /** A Consumer that extends a PrintWriter. Useful for formatting. */ 11 12 public class PrintConsumer extends PrintWriter 13 implements Appendable, XConsumer 14 { 15 protected boolean skipping; 16 protected Consumer base; 17 private static Writer dummyWriter = new ConsumerWriter(null); 18 PrintConsumer(Writer out)19 public PrintConsumer(Writer out) { 20 this(out, false); 21 } 22 PrintConsumer(Writer out, boolean autoFlush)23 public PrintConsumer(Writer out, boolean autoFlush) { 24 super(out==null ? dummyWriter : out, autoFlush); 25 if (out == null) { 26 this.lock = this; 27 this.out = null; 28 } else if (out instanceof Consumer) 29 this.base = (Consumer) out; 30 } 31 PrintConsumer(Consumer out, boolean autoFlush)32 public PrintConsumer(Consumer out, boolean autoFlush) { 33 this(out instanceof Writer ? (Writer) out 34 : new ConsumerWriter(out), 35 autoFlush); 36 this.base = out; 37 } 38 PrintConsumer(OutputStream out, boolean autoFlush)39 public PrintConsumer(OutputStream out, boolean autoFlush) { 40 super(out, autoFlush); 41 } 42 getPrettyWriter()43 public PrettyWriter getPrettyWriter() { 44 PrintConsumer cur = this; 45 for (;;) { 46 if (cur instanceof PrettyWriter) 47 return (PrettyWriter) cur; 48 Writer next = cur.out; 49 if (next instanceof PrintConsumer) 50 cur = (PrintConsumer) next; 51 else 52 return null; 53 } 54 } 55 startNumber()56 protected void startNumber() { 57 writeWordStart(); 58 } 59 endNumber()60 protected void endNumber() { 61 writeWordEnd(); 62 } 63 append(char c)64 public PrintConsumer append (char c) 65 { 66 print(c); 67 return this; 68 } 69 append(CharSequence csq)70 public PrintConsumer append (CharSequence csq) 71 { 72 if (csq == null) 73 csq = "null"; 74 append(csq, 0, csq.length()); 75 return this; 76 } 77 append(CharSequence csq, int start, int end)78 public PrintConsumer append (CharSequence csq, int start, int end) 79 { 80 write(csq == null ? "null" : csq, 81 start, end-start); 82 return this; 83 } 84 write(CharSequence csq, int start, int length)85 public void write(CharSequence csq, int start, int length) { 86 if (length == 0) 87 csq = ""; 88 if (csq instanceof String) 89 write((String) csq, start, length); 90 else { 91 synchronized (lock) { 92 int end = start+length; 93 for (int i = start; i < end; i++) 94 write(csq.charAt(i)); 95 } 96 } 97 } 98 freshLine()99 public void freshLine() { 100 if (base instanceof PrintConsumer) 101 ((PrintConsumer) base).freshLine(); 102 } 103 writeSpace(int kind)104 public void writeSpace(int kind) { 105 write(' '); 106 writeBreak(kind); 107 } 108 writeBreak(int kind)109 public void writeBreak(int kind) { 110 if (base instanceof PrintConsumer) 111 ((PrintConsumer) base).writeBreak(kind); 112 } 113 writeBreakFill(Consumer out)114 public static void writeBreakFill(Consumer out) { 115 if (out instanceof PrintConsumer) 116 ((PrintConsumer) out).writeBreakFill(); 117 } 118 writeBreakFill()119 public void writeBreakFill() { 120 writeBreak(PrettyWriter.NEWLINE_FILL); 121 } 122 writeSpaceFill(Consumer out)123 public static void writeSpaceFill(Consumer out) { 124 if (out instanceof PrintConsumer) 125 ((PrintConsumer) out).writeSpaceFill(); 126 else 127 out.write(' '); 128 } 129 writeSpaceFill()130 public void writeSpaceFill() { 131 writeSpace(PrettyWriter.NEWLINE_FILL); 132 } 133 writeSpaceLinear()134 public void writeSpaceLinear() { 135 writeSpace(PrettyWriter.NEWLINE_LINEAR); 136 } 137 138 /** Write a new-line iff the containing section cannot be printed 139 * on one line. Either all linear-style newlines in a logical 140 * block becomes spaces (if it all fits in a line), or none 141 * of them do. */ writeBreakLinear()142 public void writeBreakLinear() { 143 writeBreak(PrettyWriter.NEWLINE_LINEAR); 144 } 145 setIndentation(int amount, boolean current)146 public void setIndentation(int amount, boolean current) { 147 if (base instanceof PrintConsumer) 148 ((PrintConsumer) base).setIndentation(amount, current); 149 } 150 isDomTerm()151 public boolean isDomTerm() { return false; } 152 153 /** If supported (i.e. on DomTerm), "print" a show/hide button. */ writeShowHideButton(boolean show)154 public void writeShowHideButton(boolean show) { 155 if (base instanceof PrintConsumer 156 && ((PrintConsumer) base).isDomTerm()) { 157 String buttonChar = "\u25BC"; 158 writeRaw("\033[16u"+buttonChar+"\033[17u"); 159 } 160 } 161 162 /** Start section controled by a show/hide button. 163 * Must be properly nested within/around logical blocks. 164 * Current only supported on DomTerm. */ startHiderSection(boolean show)165 public void startHiderSection(boolean show) { 166 if (base instanceof PrintConsumer 167 && ((PrintConsumer) base).isDomTerm()) { 168 writeRaw(show ? "\033[83;1u" : "\033[83;2u"); 169 } 170 } 171 172 /** End section controled by a show/hide button */ endHiderSection()173 public void endHiderSection() { 174 if (base instanceof PrintConsumer 175 && ((PrintConsumer) base).isDomTerm()) { 176 writeRaw("\033[83;0u"); 177 } 178 } 179 startLogicalBlock(String prefix, boolean perLine, String suffix, Consumer out)180 public static void startLogicalBlock(String prefix, boolean perLine, 181 String suffix, Consumer out) { 182 if (out instanceof PrintConsumer) 183 ((PrintConsumer) out).startLogicalBlock(prefix, perLine, suffix); 184 else 185 out.write(prefix); 186 } 187 startLogicalBlock(String prefix, boolean perLine, String suffix)188 public void startLogicalBlock(String prefix, boolean perLine, 189 String suffix) { 190 if (base instanceof PrintConsumer) 191 ((PrintConsumer) base).startLogicalBlock(prefix, perLine, suffix); 192 else 193 writeRaw(prefix); 194 } startLogicalBlock(String prefix, String suffix, int indent)195 public void startLogicalBlock(String prefix, String suffix, 196 int indent) { 197 if (base instanceof PrintConsumer) 198 ((PrintConsumer) base).startLogicalBlock(prefix, suffix, indent); 199 else 200 writeRaw(prefix); 201 } 202 endLogicalBlock(String suffix, Consumer out)203 public static void endLogicalBlock(String suffix, Consumer out) { 204 if (out instanceof PrintConsumer) 205 ((PrintConsumer) out).endLogicalBlock(suffix); 206 else 207 out.write(suffix); 208 } 209 endLogicalBlock(String suffix)210 public void endLogicalBlock(String suffix) { 211 if (base instanceof PrintConsumer) 212 ((PrintConsumer) base).endLogicalBlock(suffix); 213 else 214 writeRaw(suffix); 215 } 216 beforeContent()217 protected void beforeContent() { 218 } 219 beforeNode()220 protected void beforeNode() { 221 } 222 writeWordStart()223 public void writeWordStart() { 224 if (out instanceof PrintConsumer) 225 ((PrintConsumer) out).writeWordStart(); 226 } 227 writeWordEnd()228 public void writeWordEnd() { 229 if (out instanceof PrintConsumer) 230 ((PrintConsumer) out).writeWordEnd(); 231 } 232 clearWordEnd()233 protected void clearWordEnd() { 234 if (out instanceof PrintConsumer) 235 ((PrintConsumer) out).clearWordEnd(); 236 } 237 writeBoolean(boolean v)238 public void writeBoolean(boolean v) { 239 if (skipping) 240 return; 241 synchronized (lock) { 242 writeWordStart(); 243 if (base != null) 244 base.writeBoolean(v); 245 else 246 print(v); 247 writeWordEnd(); 248 } 249 } 250 writeFloat(float v)251 public void writeFloat(float v) { 252 if (skipping) 253 return; 254 synchronized (lock) { 255 startNumber(); 256 if (base != null) 257 base.writeFloat(v); 258 else 259 print(v); 260 endNumber(); 261 } 262 } 263 writeDouble(double v)264 public void writeDouble(double v) { 265 if (skipping) 266 return; 267 synchronized (lock) { 268 startNumber(); 269 if (base != null) 270 base.writeDouble(v); 271 else 272 print(v); 273 endNumber(); 274 } 275 } 276 writeInt(int v)277 public void writeInt(int v) { 278 if (skipping) 279 return; 280 synchronized (lock) { 281 startNumber(); 282 if (base != null) 283 base.writeInt(v); 284 else 285 print(v); 286 endNumber(); 287 } 288 } 289 writeLong(long v)290 public void writeLong(long v) { 291 if (skipping) 292 return; 293 synchronized (lock) { 294 startNumber(); 295 if (base != null) 296 base.writeLong(v); 297 else 298 print(v); 299 endNumber(); 300 } 301 } 302 /* 303 public void print(Object v) { 304 if (out instanceof Consumer) 305 ((Consumer) out).writeObject(v); 306 else 307 super.print(v); 308 } 309 */ 310 startDocument()311 public void startDocument() { 312 if (base != null && ! skipping) 313 base.startDocument(); 314 } 315 endDocument()316 public void endDocument() { 317 if (base != null && ! skipping) 318 base.endDocument(); 319 } 320 startElement(Object type)321 public void startElement(Object type) { 322 if (base != null && ! skipping) 323 base.startElement(type); 324 } 325 endElement()326 public void endElement() { 327 if (base != null && ! skipping) 328 base.endElement(); 329 } 330 startAttribute(Object attrType)331 public void startAttribute (Object attrType) { } 332 endAttribute()333 public void endAttribute() { } 334 writeComment(char[] chars, int offset, int length)335 public void writeComment(char[] chars, int offset, int length) { 336 if (skipping) 337 return; 338 beforeNode(); 339 if (base instanceof XConsumer) 340 ((XConsumer) base).writeComment(chars, offset, length); 341 } writeProcessingInstruction(String target, char[] content, int offset, int length)342 public void writeProcessingInstruction(String target, char[] content, 343 int offset, int length) { 344 if (skipping) 345 return; 346 beforeNode(); 347 if (base instanceof XConsumer) 348 ((XConsumer) base) 349 .writeProcessingInstruction(target, content, offset, length); 350 } writeCDATA(char[] chars, int offset, int length)351 public void writeCDATA(char[] chars, int offset, int length) { 352 beforeContent(); 353 if (skipping) 354 return; 355 if (base instanceof XConsumer) 356 ((XConsumer) base).writeCDATA(chars, offset, length); 357 else 358 writeRaw(chars, offset, length); 359 } beginEntity(Object baseUri)360 public void beginEntity(Object baseUri) { 361 if (skipping) 362 return; 363 beforeNode(); 364 if (base instanceof XConsumer) 365 ((XConsumer) base).beginEntity(baseUri); 366 } endEntity()367 public void endEntity() { 368 if (skipping) 369 return; 370 if (base instanceof XConsumer) 371 ((XConsumer) base).endEntity(); 372 } 373 writeRaw(int v)374 protected void writeRaw(int v) { 375 try { 376 out.write(v); 377 } catch (IOException ex) { 378 setError(); 379 } 380 } 381 writeRaw(String str)382 protected void writeRaw(String str) { 383 try { 384 out.write(str, 0, str.length()); 385 } catch (IOException ex) { 386 setError(); 387 } 388 } 389 writeRaw(String str, int start, int length)390 protected void writeRaw(String str, int start, int length) { 391 try { 392 out.write(str, start, length); 393 } catch (IOException ex) { 394 setError(); 395 } 396 } 397 writeRaw(char[] chars, int start, int length)398 protected void writeRaw(char[] chars, int start, int length) { 399 try { 400 out.write(chars, start, length); 401 } catch (IOException ex) { 402 setError(); 403 } 404 } 405 writeObject(Object v)406 public void writeObject(Object v) { 407 if (out instanceof Consumer) 408 ((Consumer) out).writeObject(v); 409 else 410 print(v); 411 } 412 ignoring()413 public boolean ignoring() 414 { 415 return false; 416 } 417 } 418