Source Code Cross Referenced for TableWriter.java in  » GIS » GeoTools-2.4.1 » org » geotools » io » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » GIS » GeoTools 2.4.1 » org.geotools.io 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        /*
002:         *    GeoTools - OpenSource mapping toolkit
003:         *    http://geotools.org
004:         *    (C) 2003-2006, GeoTools Project Managment Committee (PMC)
005:         *    (C) 2001, Institut de Recherche pour le Développement
006:         *
007:         *    This library is free software; you can redistribute it and/or
008:         *    modify it under the terms of the GNU Lesser General Public
009:         *    License as published by the Free Software Foundation;
010:         *    version 2.1 of the License.
011:         *
012:         *    This library is distributed in the hope that it will be useful,
013:         *    but WITHOUT ANY WARRANTY; without even the implied warranty of
014:         *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
015:         *    Lesser General Public License for more details.
016:         */
017:        package org.geotools.io;
018:
019:        // Input/output
020:        import java.io.FilterWriter;
021:        import java.io.IOException;
022:        import java.io.StringWriter;
023:        import java.io.Writer;
024:        import java.util.ArrayList;
025:        import java.util.Arrays;
026:        import java.util.Iterator;
027:        import java.util.List;
028:        import java.util.StringTokenizer;
029:
030:        import javax.swing.text.StyleConstants;
031:
032:        import org.geotools.resources.Utilities;
033:        import org.geotools.resources.XArray;
034:
035:        /**
036:         * A character stream that can be used to format tables. Columns are separated
037:         * by tabulations (<code>'\t'</code>) and rows are separated by line terminators
038:         * (<code>'\r'</code>, <code>'\n'</code> or <code>"\r\n"</code>). Every table's
039:         * cells are stored in memory until {@link #flush()} is invoked. When invoked,
040:         * {@link #flush()} copy cell's contents to the underlying stream while replacing
041:         * tabulations by some amount of spaces. The exact number of spaces is computed
042:         * from cell's widths. {@code TableWriter} produces correct output when
043:         * displayed with a monospace font.
044:         * <br><br>
045:         * For example, the following code...
046:         *
047:         * <blockquote><pre>
048:         *     TableWriter out = new TableWriter(new OutputStreamWriter(System.out), 3);
049:         *     out.write("Prénom\tNom\n");
050:         *     out.nextLine('-');
051:         *     out.write("Idéphonse\tLaporte\nSarah\tCoursi\nYvan\tDubois");
052:         *     out.flush();
053:         * </pre></blockquote>
054:         *
055:         * ...produces the following output:
056:         *
057:         * <blockquote><pre>
058:         *      Prénom      Nom
059:         *      ---------   -------
060:         *      Idéphonse   Laporte
061:         *      Sarah       Coursi
062:         *      Yvan        Dubois
063:         * </pre></blockquote>
064:         *
065:         * @since 2.0
066:         * @source $URL: http://svn.geotools.org/geotools/tags/2.4.1/modules/library/metadata/src/main/java/org/geotools/io/TableWriter.java $
067:         * @version $Id: TableWriter.java 22691 2006-11-10 22:30:28Z desruisseaux $
068:         * @author Martin Desruisseaux
069:         */
070:        public class TableWriter extends FilterWriter {
071:            /**
072:             * A possible value for cell alignment. This
073:             * specifies that the text is aligned to the left
074:             * indent and extra whitespace should be placed on
075:             * the right.
076:             */
077:            public static final int ALIGN_LEFT = StyleConstants.ALIGN_LEFT;
078:
079:            /**
080:             * A possible value for cell alignment. This
081:             * specifies that the text is aligned to the right
082:             * indent and extra whitespace should be placed on
083:             * the left.
084:             */
085:            public static final int ALIGN_RIGHT = StyleConstants.ALIGN_RIGHT;
086:
087:            /**
088:             * A possible value for cell alignment. This
089:             * specifies that the text is aligned to the center
090:             * and extra whitespace should be placed equally on
091:             * the left and right.
092:             */
093:            public static final int ALIGN_CENTER = StyleConstants.ALIGN_CENTER;
094:
095:            /**
096:             * Drawing-box characters. The last two characters
097:             * are horizontal and vertical line respectively.
098:             */
099:            private static final char[][] BOX = new char[][] {
100:                    {// [0000]: single horizontal, single vertical
101:                    '\u250C', '\u252C', '\u2510', '\u251C', '\u253C', '\u2524',
102:                            '\u2514', '\u2534', '\u2518', '\u2500', '\u2502' },
103:                    {// [0001]: single horizontal, double vertical
104:                    '\u2553', '\u2565', '\u2556', '\u255F', '\u256B', '\u2562',
105:                            '\u2559', '\u2568', '\u255C', '\u2500', '\u2551' },
106:                    {// [0010]: double horizontal, single vertical
107:                    '\u2552', '\u2564', '\u2555', '\u255E', '\u256A', '\u2561',
108:                            '\u2558', '\u2567', '\u255B', '\u2550', '\u2502' },
109:                    {// [0011]: double horizontal, double vertical
110:                    '\u2554', '\u2566', '\u2557', '\u2560', '\u256C', '\u2563',
111:                            '\u255A', '\u2569', '\u255D', '\u2550', '\u2551' },
112:                    {// [0100]: ASCII characters only
113:                    '+', '+', '+', '+', '+', '+', '+', '+', '+', '-', '|' } };
114:
115:            /**
116:             * Default character for space.
117:             */
118:            private static final char SPACE = ' ';
119:
120:            /**
121:             * Temporary string buffer. This buffer
122:             * contains only one cell's content.
123:             */
124:            private final StringBuffer buffer = new StringBuffer();
125:
126:            /**
127:             * List of {@link Cell} objects, from left to right and top to bottom.
128:             * By convention, a {@code null} value or a {@link Cell} object
129:             * with <code>{@link Cell#text}==null</code> are move to the next line.
130:             */
131:            private final List cells = new ArrayList();
132:
133:            /**
134:             * Alignment for current and next cells.
135:             */
136:            private int alignment = ALIGN_LEFT;
137:
138:            /**
139:             * Column position of the cell currently being written. The field
140:             * is incremented each time {@link #nextColumn()} is invoked.
141:             */
142:            private int column;
143:
144:            /**
145:             * Line position of the cell currently being written. The field
146:             * is incremented each time {@link #nextLine()} is invoked.
147:             */
148:            private int row;
149:
150:            /**
151:             * Maximum width for each columns. This array's length must
152:             * be equals to the number of columns in this table.
153:             */
154:            private int width[] = new int[0];
155:
156:            /**
157:             * The column separator.
158:             */
159:            private final String separator;
160:
161:            /**
162:             * The left table border.
163:             */
164:            private final String leftBorder;
165:
166:            /**
167:             * The right table border.
168:             */
169:            private final String rightBorder;
170:
171:            /**
172:             * Tells if cells can span more than one line. If {@code true},
173:             * then EOL characters likes '\n' move to the next line <em>inside</em>
174:             * the current cell. If {@code false}, then EOL characters move to
175:             * the next table's row. Default value is {@code false}.
176:             */
177:            private boolean multiLinesCells;
178:
179:            /**
180:             * {@code true} if this {@code TableWriter}
181:             * has been constructed with the no-arg constructor.
182:             */
183:            private final boolean stringOnly;
184:
185:            /**
186:             * Tells if the next '\n' character must be ignored. This field
187:             * is used in order to avoid writing two EOL in place of "\r\n".
188:             */
189:            private boolean skipCR;
190:
191:            /**
192:             * Creates a new table writer with a default column separator.
193:             * Note: this writer may produces bad output on Windows console,
194:             * unless the underlying stream use the correct codepage (e.g.
195:             * <code>OutputStreamWriter(System.out,&nbsp;"Cp437")</code>).
196:             * To display the appropriate codepage for a Windows NT console,
197:             * type {@code chcp} on the command line.
198:             *
199:             * @param out Writer object to provide the underlying stream,
200:             *        or {@code null} if there is no underlying stream.
201:             *        If {@code out} is null, then the {@link #toString}
202:             *        method is the only way to get the table's content.
203:             */
204:            public TableWriter(final Writer out) {
205:                super (out != null ? out : new StringWriter());
206:                stringOnly = (out == null);
207:                leftBorder = "\u2551 ";
208:                rightBorder = " \u2551";
209:                separator = " \u2502 ";
210:            }
211:
212:            /**
213:             * Creates a new table writer with the specified
214:             * amount of spaces as column separator.
215:             *
216:             * @param out Writer object to provide the underlying stream,
217:             *        or {@code null} if there is no underlying stream.
218:             *        If {@code out} is null, then the {@link #toString}
219:             *        method is the only way to get the table's content.
220:             * @param spaces Amount of white spaces to use as column separator.
221:             */
222:            public TableWriter(final Writer out, final int spaces) {
223:                this (out, Utilities.spaces(spaces));
224:            }
225:
226:            /**
227:             * Creates a new table writer with the specified column separator.
228:             *
229:             * @param out Writer object to provide the underlying stream,
230:             *        or {@code null} if there is no underlying stream.
231:             *        If {@code out} is null, then the {@link #toString}
232:             *        method is the only way to get the table's content.
233:             * @param separator String to write between columns. Drawing box characters
234:             *        are treated specially. For example <code>" \\u2502 "</code> can be
235:             *        used for a single-line box.
236:             */
237:            public TableWriter(final Writer out, final String separator) {
238:                super (out != null ? out : new StringWriter());
239:                stringOnly = (out == null);
240:                final int length = separator.length();
241:                int lower = 0;
242:                int upper = length;
243:                while (lower < length
244:                        && Character.isSpaceChar(separator.charAt(lower)))
245:                    lower++;
246:                while (upper > 0
247:                        && Character.isSpaceChar(separator.charAt(upper - 1)))
248:                    upper--;
249:                this .leftBorder = separator.substring(lower);
250:                this .rightBorder = separator.substring(0, upper);
251:                this .separator = separator;
252:            }
253:
254:            /**
255:             * Writes a border or a corner to the specified stream.
256:             *
257:             * @param out              The destination stream.
258:             * @param horizontalBorder -1 for left border, +1 for right border,  0 for center.
259:             * @param verticalBorder   -1 for top  border, +1 for bottom border, 0 for center.
260:             * @param horizontalChar   Character to use for horizontal line.
261:             * @throws IOException     if the writting operation failed.
262:             */
263:            private void writeBorder(final Writer out,
264:                    final int horizontalBorder, final int verticalBorder,
265:                    final char horizontalChar) throws IOException {
266:                /*
267:                 * Obtiens les ensembles de caractères qui
268:                 * conviennent pour la ligne horizontale.
269:                 */
270:                int boxCount = 0;
271:                final char[][] box = new char[BOX.length][];
272:                for (int i = 0; i < BOX.length; i++) {
273:                    if (BOX[i][9] == horizontalChar) {
274:                        box[boxCount++] = BOX[i];
275:                    }
276:                }
277:                /*
278:                 * Obtient une chaine contenant les lignes verticales à
279:                 * dessiner à gauche, à droite ou au centre de la table.
280:                 */
281:                final String border;
282:                switch (horizontalBorder) {
283:                case -1:
284:                    border = leftBorder;
285:                    break;
286:                case +1:
287:                    border = rightBorder;
288:                    break;
289:                case 0:
290:                    border = separator;
291:                    break;
292:                default:
293:                    throw new IllegalArgumentException(String
294:                            .valueOf(horizontalBorder));
295:                }
296:                if (verticalBorder < -1 || verticalBorder > +1) {
297:                    throw new IllegalArgumentException(String
298:                            .valueOf(verticalBorder));
299:                }
300:                /*
301:                 * Remplace les espaces par la ligne horizontale,
302:                 * et les lignes verticales par une intersection.
303:                 */
304:                final int index = (horizontalBorder + 1) + (verticalBorder + 1)
305:                        * 3;
306:                final int borderLength = border.length();
307:                for (int i = 0; i < borderLength; i++) {
308:                    char c = border.charAt(i);
309:                    if (Character.isSpaceChar(c)) {
310:                        c = horizontalChar;
311:                    } else {
312:                        for (int j = 0; j < boxCount; j++) {
313:                            if (box[j][10] == c) {
314:                                c = box[j][index];
315:                                break;
316:                            }
317:                        }
318:                    }
319:                    out.write(c);
320:                }
321:            }
322:
323:            /**
324:             * Set the desired behavior for EOL and tabulations characters.
325:             * <ul>
326:             *   <li>If {@code true}, EOL (<code>'\r'</code>, <code>'\n'</code> or
327:             *       <code>"\r\n"</code>) and tabulations (<code>'\t'</code>) characters
328:             *       are copied straight into the current cell, which mean that next write
329:             *       operations will continue inside the same cell.</li>
330:             *   <li>If {@code false}, then tabulations move to next column and EOL move
331:             *       to the first cell of next row (i.e. tabulation and EOL are equivalent to
332:             *       {@link #nextColumn()} and {@link #nextLine()} calls respectively).</li>
333:             * </ul>
334:             * The default value is {@code false}.
335:             *
336:             * @param multiLines {@code true} true if EOL are used for line feeds inside
337:             *        current cells, or {@code false} if EOL move to the next row.
338:             */
339:            public void setMultiLinesCells(final boolean multiLines) {
340:                synchronized (lock) {
341:                    multiLinesCells = multiLines;
342:                }
343:            }
344:
345:            /**
346:             * Tells if EOL characters are used for line feeds inside current cells.
347:             */
348:            public boolean isMultiLinesCells() {
349:                synchronized (lock) {
350:                    return multiLinesCells;
351:                }
352:            }
353:
354:            /**
355:             * Set the alignment for all cells in the specified column. This method
356:             * overwrite the alignment for all previous cells in the specified column.
357:             *
358:             * @param column The 0-based column number.
359:             * @param alignment Cell alignment. Must be {@link #ALIGN_LEFT}
360:             *        {@link #ALIGN_RIGHT} or {@link #ALIGN_CENTER}.
361:             */
362:            public void setColumnAlignment(final int column, final int alignment) {
363:                if (alignment != ALIGN_LEFT && alignment != ALIGN_RIGHT
364:                        && alignment != ALIGN_CENTER) {
365:                    throw new IllegalArgumentException(String
366:                            .valueOf(alignment));
367:                }
368:                synchronized (lock) {
369:                    int current = 0;
370:                    for (final Iterator it = cells.iterator(); it.hasNext();) {
371:                        final Cell cell = (Cell) it.next();
372:                        if (cell == null || cell.text == null) {
373:                            current = 0;
374:                            continue;
375:                        }
376:                        if (current == column) {
377:                            cell.alignment = alignment;
378:                        }
379:                        current++;
380:                    }
381:                }
382:            }
383:
384:            /**
385:             * Set the alignment for current and next cells. Change to the
386:             * alignment doesn't affect the alignment of previous cells and
387:             * previous rows. The default alignment is {@link #ALIGN_LEFT}.
388:             *
389:             * @param alignment Cell alignment. Must be {@link #ALIGN_LEFT}
390:             *        {@link #ALIGN_RIGHT} or {@link #ALIGN_CENTER}.
391:             */
392:            public void setAlignment(final int alignment) {
393:                if (alignment != ALIGN_LEFT && alignment != ALIGN_RIGHT
394:                        && alignment != ALIGN_CENTER) {
395:                    throw new IllegalArgumentException(String
396:                            .valueOf(alignment));
397:                }
398:                synchronized (lock) {
399:                    this .alignment = alignment;
400:                }
401:            }
402:
403:            /**
404:             * Returns the alignment for current and next cells.
405:             *
406:             * @return Cell alignment: {@link #ALIGN_LEFT} (the default),
407:             *         {@link #ALIGN_RIGHT} or {@link #ALIGN_CENTER}.
408:             */
409:            public int getAlignment() {
410:                synchronized (lock) {
411:                    return alignment;
412:                }
413:            }
414:
415:            /**
416:             * Returns the number of rows in this table.
417:             * This count is reset to 0 by {@link #flush}.
418:             */
419:            private int getRowCount() {
420:                int count = row;
421:                if (column != 0) {
422:                    count++;
423:                }
424:                return count;
425:            }
426:
427:            /**
428:             * Returns the number of columns in this table.
429:             */
430:            private int getColumnCount() {
431:                return width.length;
432:            }
433:
434:            /**
435:             * Write a single character. If {@link #isMultiLinesCells()}
436:             * is false (which is the default), then:
437:             * <ul>
438:             *   <li>Tabulations (<code>'\t'</code>) are replaced
439:             *       by {@link #nextColumn()} invocations.</li>
440:             *   <li>Line separators (<code>'\r'</code>, <code>'\n'</code>
441:             *       or <code>"\r\n"</code>) are replaced
442:             *       by {@link #nextLine()} invocations.</li>
443:             * </ul>
444:             *
445:             * @param c Character to write.
446:             */
447:            public void write(final int c) {
448:                synchronized (lock) {
449:                    if (!multiLinesCells) {
450:                        switch (c) {
451:                        case '\t': {
452:                            nextColumn();
453:                            skipCR = false;
454:                            return;
455:                        }
456:                        case '\r': {
457:                            nextLine();
458:                            skipCR = true;
459:                            return;
460:                        }
461:                        case '\n': {
462:                            if (!skipCR) {
463:                                nextLine();
464:                            }
465:                            skipCR = false;
466:                            return;
467:                        }
468:                        }
469:                    }
470:                    if (c < Character.MIN_VALUE || c > Character.MAX_VALUE) {
471:                        throw new IllegalArgumentException(String.valueOf(c));
472:                    }
473:                    buffer.append((char) c);
474:                    skipCR = false;
475:                }
476:            }
477:
478:            /**
479:             * Write a string. Tabulations and line separators
480:             * are interpreted as by {@link #write(int)}.
481:             *
482:             * @param string String to write.
483:             */
484:            public void write(final String string) {
485:                write(string, 0, string.length());
486:            }
487:
488:            /**
489:             * Write a portion of a string. Tabulations and line
490:             * separators are interpreted as by {@link #write(int)}.
491:             *
492:             * @param string String to write.
493:             * @param offset Offset from which to start writing characters.
494:             * @param length Number of characters to write.
495:             */
496:            public void write(final String string, int offset, int length) {
497:                if (offset < 0 || length < 0
498:                        || (offset + length) > string.length()) {
499:                    throw new IndexOutOfBoundsException();
500:                }
501:                if (length == 0) {
502:                    return;
503:                }
504:                synchronized (lock) {
505:                    if (skipCR && string.charAt(offset) == '\n') {
506:                        offset++;
507:                        length--;
508:                    }
509:                    if (!multiLinesCells) {
510:                        int upper = offset;
511:                        for (; length != 0; length--) {
512:                            switch (string.charAt(upper++)) {
513:                            case '\t': {
514:                                buffer.append(string.substring(offset,
515:                                        upper - 1));
516:                                nextColumn();
517:                                offset = upper;
518:                                break;
519:                            }
520:                            case '\r': {
521:                                buffer.append(string.substring(offset,
522:                                        upper - 1));
523:                                nextLine();
524:                                if (length != 0 && string.charAt(upper) == '\n') {
525:                                    upper++;
526:                                    length--;
527:                                }
528:                                offset = upper;
529:                                break;
530:                            }
531:                            case '\n': {
532:                                buffer.append(string.substring(offset,
533:                                        upper - 1));
534:                                nextLine();
535:                                offset = upper;
536:                                break;
537:                            }
538:                            }
539:                        }
540:                        length = upper - offset;
541:                    }
542:                    skipCR = (string.charAt(offset + length - 1) == '\r');
543:                    buffer.append(string.substring(offset, offset + length));
544:                }
545:            }
546:
547:            /**
548:             * Write an array of characters. Tabulations and line
549:             * separators are interpreted as by {@link #write(int)}.
550:             *
551:             * @param cbuf Array of characters to be written.
552:             */
553:            public void write(final char cbuf[]) {
554:                write(cbuf, 0, cbuf.length);
555:            }
556:
557:            /**
558:             * Write a portion of an array of characters. Tabulations and
559:             * line separators are interpreted as by {@link #write(int)}.
560:             *
561:             * @param cbuf   Array of characters.
562:             * @param offset Offset from which to start writing characters.
563:             * @param length Number of characters to write.
564:             */
565:            public void write(final char cbuf[], int offset, int length) {
566:                if (offset < 0 || length < 0 || (offset + length) > cbuf.length) {
567:                    throw new IndexOutOfBoundsException();
568:                }
569:                if (length == 0) {
570:                    return;
571:                }
572:                synchronized (lock) {
573:                    if (skipCR && cbuf[offset] == '\n') {
574:                        offset++;
575:                        length--;
576:                    }
577:                    if (!multiLinesCells) {
578:                        int upper = offset;
579:                        for (; length != 0; length--) {
580:                            switch (cbuf[upper++]) {
581:                            case '\t': {
582:                                buffer.append(cbuf, offset, upper - offset - 1);
583:                                nextColumn();
584:                                offset = upper;
585:                                break;
586:                            }
587:                            case '\r': {
588:                                buffer.append(cbuf, offset, upper - offset - 1);
589:                                nextLine();
590:                                if (length != 0 && cbuf[upper] == '\n') {
591:                                    upper++;
592:                                    length--;
593:                                }
594:                                offset = upper;
595:                                break;
596:                            }
597:                            case '\n': {
598:                                buffer.append(cbuf, offset, upper - offset - 1);
599:                                nextLine();
600:                                offset = upper;
601:                                break;
602:                            }
603:                            }
604:                        }
605:                        length = upper - offset;
606:                    }
607:                    skipCR = (cbuf[offset + length - 1] == '\r');
608:                    buffer.append(cbuf, offset, length);
609:                }
610:            }
611:
612:            /**
613:             * Write an horizontal separator.
614:             */
615:            public void writeHorizontalSeparator() {
616:                synchronized (lock) {
617:                    if (column != 0 || buffer.length() != 0) {
618:                        nextLine();
619:                    }
620:                    nextLine('\u2500');
621:                }
622:            }
623:
624:            /**
625:             * Moves one column to the right. Next write
626:             * operations will occur in a new cell on the
627:             * same row.
628:             */
629:            public void nextColumn() {
630:                nextColumn(SPACE);
631:            }
632:
633:            /**
634:             * Moves one column to the right. Next write operations will occur in a
635:             * new cell on the same row.  This method fill every remaining space in
636:             * the current cell with the specified character. For example calling
637:             * <code>nextColumn('*')</code> from the first character of a cell is
638:             * a convenient way to put a pad value in this cell.
639:             *
640:             * @param  fill Character filling the cell (default to whitespace).
641:             */
642:            public void nextColumn(final char fill) {
643:                synchronized (lock) {
644:                    final String cellText = buffer.toString();
645:                    cells.add(new Cell(cellText, alignment, fill));
646:                    if (column >= width.length) {
647:                        width = XArray.resize(width, column + 1);
648:                    }
649:                    int length = 0;
650:                    final StringTokenizer tk = new StringTokenizer(cellText,
651:                            "\r\n");
652:                    while (tk.hasMoreTokens()) {
653:                        final int lg = tk.nextToken().length();
654:                        if (lg > length) {
655:                            length = lg;
656:                        }
657:                    }
658:                    if (length > width[column]) {
659:                        width[column] = length;
660:                    }
661:                    column++;
662:                    buffer.setLength(0);
663:                }
664:            }
665:
666:            /**
667:             * Moves to the first column on the next row.
668:             * Next write operations will occur on a new row.
669:             */
670:            public void nextLine() {
671:                nextLine(SPACE);
672:            }
673:
674:            /**
675:             * Moves to the first column on the next row. Next write operations will
676:             * occur on a new row. This method fill every remaining cell in the current
677:             * row with the specified character. Calling <code>nextLine('-')</code>
678:             * from the first column of a row is a convenient way to fill this row
679:             * with a line separator.
680:             *
681:             * @param  fill Character filling the rest of the line
682:             *         (default to whitespace). This caracter may
683:             *         be use as a row separator.
684:             */
685:            public void nextLine(final char fill) {
686:                synchronized (lock) {
687:                    if (buffer.length() != 0) {
688:                        nextColumn(fill);
689:                    }
690:                    assert buffer.length() == 0;
691:                    cells.add(!Character.isSpaceChar(fill) ? new Cell(null,
692:                            alignment, fill) : null);
693:                    column = 0;
694:                    row++;
695:                }
696:            }
697:
698:            /**
699:             * Flush the table content to the underlying stream.
700:             * This method should not be called before the table
701:             * is completed (otherwise, columns may have the
702:             * wrong width).
703:             *
704:             * @throws IOException if an output operation failed.
705:             */
706:            public void flush() throws IOException {
707:                synchronized (lock) {
708:                    if (buffer.length() != 0) {
709:                        nextLine();
710:                        assert buffer.length() == 0;
711:                    }
712:                    flushTo(out);
713:                    row = column = 0;
714:                    cells.clear();
715:                    if (!(out instanceof  TableWriter)) {
716:                        /*
717:                         * Flush only if this table is not included in an outer (bigger) table.
718:                         * This is because flushing the outer table would break its formatting.
719:                         */
720:                        out.flush();
721:                    }
722:                }
723:            }
724:
725:            /**
726:             * Flush the table content and close the underlying stream.
727:             *
728:             * @throws IOException if an output operation failed.
729:             */
730:            public void close() throws IOException {
731:                synchronized (lock) {
732:                    flush();
733:                    out.close();
734:                }
735:            }
736:
737:            /**
738:             * Ecrit vers le flot spécifié toutes les cellules qui avaient été disposées
739:             * dans le tableau. Ces cellules seront automatiquement alignées en colonnes.
740:             * Cette méthode peut être appelée plusieurs fois pour écrire le même tableau
741:             * par exemple vers plusieurs flots.
742:             *
743:             * @param  out Flot vers où écrire les données.
744:             * @throws IOException si une erreur est survenue lors de l'écriture dans
745:             *         {@code out}.
746:             */
747:            private void flushTo(final Writer out) throws IOException {
748:                final String columnSeparator = this .separator;
749:                final String lineSeparator = System.getProperty(
750:                        "line.separator", "\n");
751:                final Cell[] currentLine = new Cell[width.length];
752:                final int cellCount = cells.size();
753:                for (int cellIndex = 0; cellIndex < cellCount; cellIndex++) {
754:                    /*
755:                     * Copie dans  {@code currentLine}  toutes les données qui seront à écrire
756:                     * sur la ligne courante de la table. Ces données excluent le {@code null}
757:                     * terminal.  La liste {@code currentLine} ne contiendra donc initialement
758:                     * aucun élément nul, mais ses éléments seront progressivement modifiés (et mis
759:                     * à {@code null}) pendant l'écriture de la ligne dans la boucle qui suit.
760:                     */
761:                    Cell lineFill = null;
762:                    int currentCount = 0;
763:                    do {
764:                        final Cell cell = (Cell) cells.get(cellIndex);
765:                        if (cell == null) {
766:                            break;
767:                        }
768:                        if (cell.text == null) {
769:                            lineFill = new Cell("", cell.alignment, cell.fill);
770:                            break;
771:                        }
772:                        currentLine[currentCount++] = cell;
773:                    } while (++cellIndex < cellCount);
774:                    Arrays.fill(currentLine, currentCount, currentLine.length,
775:                            lineFill);
776:                    /*
777:                     * La boucle suivante sera exécutée tant qu'il reste des lignes à écrire
778:                     * (c'est-à-dire tant qu'au moins un élément de {@code currentLine}
779:                     * est non-nul). Si une cellule contient un texte avec des caractères EOL,
780:                     * alors cette cellule devra s'écrire sur plusieurs lignes dans la cellule
781:                     * courante.
782:                     */
783:                    while (!isEmpty(currentLine)) {
784:                        for (int j = 0; j < currentLine.length; j++) {
785:                            final boolean isFirstColumn = (j == 0);
786:                            final boolean isLastColumn = (j + 1 == currentLine.length);
787:                            final Cell cell = currentLine[j];
788:                            final int cellWidth = width[j];
789:                            if (cell == null) {
790:                                if (isFirstColumn) {
791:                                    out.write(leftBorder);
792:                                }
793:                                repeat(out, SPACE, cellWidth);
794:                                out.write(isLastColumn ? rightBorder
795:                                        : columnSeparator);
796:                                continue;
797:                            }
798:                            String cellText = cell.toString();
799:                            int endCR = cellText.indexOf('\r');
800:                            int endLF = cellText.indexOf('\n');
801:                            int end = (endCR < 0) ? endLF : (endLF < 0) ? endCR
802:                                    : Math.min(endCR, endLF);
803:                            if (end >= 0) {
804:                                /*
805:                                 * Si un retour chariot a été trouvé, n'écrit que la première
806:                                 * ligne de la cellule. L'élément {@code currentLine[j]}
807:                                 * sera modifié pour ne contenir que les lignes restantes qui
808:                                 * seront écrites lors d'un prochain passage dans la boucle.
809:                                 */
810:                                int top = end + 1;
811:                                if (endCR >= 0 && endCR + 1 == endLF)
812:                                    top++;
813:                                int scan = top;
814:                                final int textLength = cellText.length();
815:                                while (scan < textLength
816:                                        && Character.isWhitespace(cellText
817:                                                .charAt(scan))) {
818:                                    scan++;
819:                                }
820:                                currentLine[j] = (scan < textLength) ? cell
821:                                        .substring(top) : null;
822:                                cellText = cellText.substring(0, end);
823:                            } else
824:                                currentLine[j] = null;
825:                            final int textLength = cellText.length();
826:                            /*
827:                             * Si la cellule à écrire est en fait une bordure,
828:                             * on fera un traitement spécial pour utiliser les
829:                             * caractˆres de jointures {@link #BOX}.
830:                             */
831:                            if (currentCount == 0) {
832:                                assert textLength == 0;
833:                                final int verticalBorder;
834:                                if (cellIndex == 0)
835:                                    verticalBorder = -1;
836:                                else if (cellIndex >= cellCount - 1)
837:                                    verticalBorder = +1;
838:                                else
839:                                    verticalBorder = 0;
840:                                if (isFirstColumn) {
841:                                    writeBorder(out, -1, verticalBorder,
842:                                            cell.fill);
843:                                }
844:                                repeat(out, cell.fill, cellWidth);
845:                                writeBorder(out, isLastColumn ? +1 : 0,
846:                                        verticalBorder, cell.fill);
847:                                continue;
848:                            }
849:                            /*
850:                             * Si la cellule n'est pas une bordure, il s'agit
851:                             * d'une cellule "normale".  Procˆde maintenant à
852:                             * l'écriture d'une ligne de la cellule.
853:                             */
854:                            if (isFirstColumn) {
855:                                out.write(leftBorder);
856:                            }
857:                            final Writer tabExpander = (cellText.indexOf('\t') >= 0) ? new ExpandedTabWriter(
858:                                    out)
859:                                    : out;
860:                            switch (cell.alignment) {
861:                            default: {
862:                                // Should not happen.
863:                                throw new AssertionError(cell.alignment);
864:                            }
865:                            case ALIGN_LEFT: {
866:                                tabExpander.write(cellText);
867:                                repeat(tabExpander, cell.fill, cellWidth
868:                                        - textLength);
869:                                break;
870:                            }
871:                            case ALIGN_RIGHT: {
872:                                repeat(tabExpander, cell.fill, cellWidth
873:                                        - textLength);
874:                                tabExpander.write(cellText);
875:                                break;
876:                            }
877:                            case ALIGN_CENTER: {
878:                                final int rightMargin = (cellWidth - textLength) / 2;
879:                                repeat(tabExpander, cell.fill, rightMargin);
880:                                tabExpander.write(cellText);
881:                                repeat(tabExpander, cell.fill,
882:                                        (cellWidth - rightMargin) - textLength);
883:                                break;
884:                            }
885:                            }
886:                            out.write(isLastColumn ? rightBorder
887:                                    : columnSeparator);
888:                        }
889:                        out.write(lineSeparator);
890:                    }
891:                }
892:            }
893:
894:            /**
895:             * Checks if {@code array} contains
896:             * only {@code null} elements.
897:             */
898:            private static boolean isEmpty(final Object[] array) {
899:                for (int i = array.length; --i >= 0;) {
900:                    if (array[i] != null) {
901:                        return false;
902:                    }
903:                }
904:                return true;
905:            }
906:
907:            /**
908:             * Repeat a character.
909:             *
910:             * @param out   The destination stream.
911:             * @param car   Character to write (usually ' ').
912:             * @param count Number of repetition.
913:             */
914:            private static void repeat(final Writer out, final char car,
915:                    int count) throws IOException {
916:                while (--count >= 0) {
917:                    out.write(car);
918:                }
919:            }
920:
921:            /**
922:             * Returns the table content as a string.
923:             */
924:            public String toString() {
925:                synchronized (lock) {
926:                    int capacity = 2; // Room for EOL.
927:                    for (int i = 0; i < width.length; i++) {
928:                        capacity += width[i];
929:                    }
930:                    capacity *= getRowCount();
931:                    final StringWriter writer;
932:                    if (stringOnly) {
933:                        writer = (StringWriter) out;
934:                        final StringBuffer buffer = writer.getBuffer();
935:                        buffer.setLength(0);
936:                        buffer.ensureCapacity(capacity);
937:                    } else {
938:                        writer = new StringWriter(capacity);
939:                    }
940:                    try {
941:                        flushTo(writer);
942:                    } catch (IOException exception) {
943:                        // Should not happen
944:                        throw new AssertionError(exception);
945:                    }
946:                    return writer.toString();
947:                }
948:            }
949:
950:            /**
951:             * A class wrapping a cell's content and its text's alignment.
952:             * This class if for internal use only.
953:             *
954:             * @version $Id: TableWriter.java 22691 2006-11-10 22:30:28Z desruisseaux $
955:             * @author Martin Desruisseaux
956:             */
957:            private static final class Cell {
958:                /**
959:                 * The text to write inside the cell.
960:                 */
961:                public final String text;
962:
963:                /**
964:                 * The alignment for {@link #text} inside the cell.
965:                 */
966:                public int alignment;
967:
968:                /**
969:                 * The fill character, used for filling space inside the cell.
970:                 */
971:                public final char fill;
972:
973:                /**
974:                 * Returns a new cell wrapping the specified string with the
975:                 * specified alignment and fill character.
976:                 */
977:                public Cell(final String text, final int alignment,
978:                        final char fill) {
979:                    this .text = text;
980:                    this .alignment = alignment;
981:                    this .fill = fill;
982:                }
983:
984:                /**
985:                 * Returns a new cell which contains substring of this cell.
986:                 */
987:                public Cell substring(final int lower) {
988:                    return new Cell(text.substring(lower), alignment, fill);
989:                }
990:
991:                /**
992:                 * Returns the cell's content.
993:                 */
994:                public String toString() {
995:                    return text;
996:                }
997:            }
998:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.