sis-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From desruisse...@apache.org
Subject svn commit: r1425402 - in /sis/branches/JDK7/sis-utility/src: main/java/org/apache/sis/io/ main/java/org/apache/sis/math/ main/java/org/apache/sis/util/collection/ test/java/org/apache/sis/io/
Date Sun, 23 Dec 2012 04:03:29 GMT
Author: desruisseaux
Date: Sun Dec 23 04:03:29 2012
New Revision: 1425402

URL: http://svn.apache.org/viewvc?rev=1425402&view=rev
Log:
Factored out the setLineSeparator / setColumnSeparatorPattern from TreeTableFormat
to a new parent class (TabularFormat) in order to allow sharing by StatisticsFormat.

Added:
    sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/io/TabularFormat.java
      - copied, changed from r1425044, sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/collection/TreeTableFormat.java
Modified:
    sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/io/CompoundFormat.java
    sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/math/MathFunctions.java
    sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/math/StatisticsFormat.java
    sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/collection/TreeTableFormat.java
    sis/branches/JDK7/sis-utility/src/test/java/org/apache/sis/io/FormatterTestCase.java

Modified: sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/io/CompoundFormat.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/io/CompoundFormat.java?rev=1425402&r1=1425401&r2=1425402&view=diff
==============================================================================
--- sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/io/CompoundFormat.java (original)
+++ sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/io/CompoundFormat.java Sun Dec 23 04:03:29 2012
@@ -39,9 +39,6 @@ import org.apache.sis.util.ArgumentCheck
 import org.apache.sis.util.collection.BackingStoreException;
 import org.apache.sis.internal.util.LocalizedParseException;
 
-// Related to JDK7
-import java.util.Objects;
-
 
 /**
  * Base class of {@link Format} implementations which delegate part of their work to other
@@ -412,31 +409,11 @@ public abstract class CompoundFormat<T> 
         return clone;
     }
 
-    /**
-     * Compares this format with the given object for equality.
-     *
-     * @param  other The other object to compare with this.
-     * @return {@code true} if the other object is a format of the same class than this
-     *         and having the same configuration.
-     */
-    @Override
-    public boolean equals(final Object other) {
-        if (other == this) {
-            return true;
-        }
-        if (other != null && getClass() == other.getClass()) {
-            final CompoundFormat<?> that = (CompoundFormat<?>) other;
-            return Objects.equals(locale,   that.locale) &&
-                   Objects.equals(timezone, that.timezone);
-        }
-        return false;
-    }
-
-    /**
-     * Returns a hash code value for this format.
+    /*
+     * Do not override equals(Object) and hashCode(). They are unlikely to be needed since we
+     * do not expect CompoundFormats to be used as keys in HashMap, especially since they are
+     * mutable. Furthermore it is difficult to check for equality since the values in the
+     * 'formats' map are created only when needed and we don't know how subclasses will
+     * configure them.
      */
-    @Override
-    public int hashCode() {
-        return Objects.hash(locale, timezone);
-    }
 }

Copied: sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/io/TabularFormat.java (from r1425044, sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/collection/TreeTableFormat.java)
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/io/TabularFormat.java?p2=sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/io/TabularFormat.java&p1=sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/collection/TreeTableFormat.java&r1=1425044&r2=1425402&rev=1425402&view=diff
==============================================================================
--- sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/collection/TreeTableFormat.java (original)
+++ sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/io/TabularFormat.java Sun Dec 23 04:03:29 2012
@@ -14,129 +14,114 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.sis.util.collection;
+package org.apache.sis.io;
 
-import java.util.Arrays;
-import java.util.Map;
-import java.util.List;
 import java.util.Locale;
 import java.util.TimeZone;
-import java.io.IOException;
-import java.text.Format;
 import java.text.ParsePosition;
-import java.text.ParseException;
 import java.util.regex.Pattern;
 import java.util.regex.Matcher;
 import net.jcip.annotations.NotThreadSafe;
-import org.apache.sis.io.LineFormatter;
-import org.apache.sis.io.TableFormatter;
-import org.apache.sis.io.CompoundFormat;
-import org.apache.sis.util.Workaround;
-import org.apache.sis.util.CharSequences;
 import org.apache.sis.util.StringBuilders;
 import org.apache.sis.util.ArgumentChecks;
 import org.apache.sis.util.resources.Errors;
-import org.apache.sis.internal.util.LocalizedParseException;
-
-import static org.apache.sis.util.Characters.NO_BREAK_SPACE;
 
 
 /**
- * A parser and formatter for {@link TreeTable} instances.
- * This formatter is given an arbitrary number of {@link TableColumn}s
- * to use during the formatting. The first column is taken as the node label.
- * If a {@code TreeTable} is formatted with only that column,
- * then the {@link String} result is like the following example:
+ * Base class for parser and formatter of tabular data, providing control on line and column separators.
+ * The line separator is specified by a string. But the column separator is specified by a pattern which
+ * provide some control on the character to repeat, and on the strings to insert before and after the
+ * repeated character. See the following methods for details:
  *
- * {@preformat text
- *   Node #1
- *   ├───Node #2
- *   │   └───Node #4
- *   └───Node #3
- * }
+ * <ul>
+ *   <li>{@link #setLineSeparator(String)}</li>
+ *   <li>{@link #setColumnSeparatorPattern(String)}</li>
+ * </ul>
  *
- * If the same {@code TreeTable} is formatted with two columns,
- * then the {@link String} result is like the following example:
+ * For implementors, this base class takes care of splitting a column separator pattern into its
+ * components ({@link #columnSeparator}, {@link #separatorPrefix} and {@link #separatorSuffix})
+ * for easier usage in {@code format(…)} method implementations. Subclasses can use those fields
+ * like below:
  *
- * {@preformat text
- *   Node #1……………………… More #1
- *   ├───Node #2…………… More #2
- *   │   └───Node #4… More #4
- *   └───Node #3…………… More #3
+ * <table class="sis"><tr>
+ *   <th>Table with no border</th>
+ *   <th>Table with a border</th>
+ * </tr><tr><td>
+ * {@preformat java
+ *     TableFormatter table = new TableFormatter(out, "");
+ *     // ... do some work, then add a column separator:
+ *     table.append(separatorPrefix);
+ *     table.nextColumn(columnSeparator);
+ *     table.append(separatorSuffix);
  * }
+ * </td><td>
+ * {@preformat java
+ *     TableFormatter table = new TableFormatter(out, separatorSuffix);
+ *     // ... do some work, then add a column separator:
+ *     table.append(separatorPrefix);
+ *     table.nextColumn(columnSeparator);
+ * }
+ * </td></tr></table>
  *
- * This representation can be printed to the {@linkplain java.io.Console#writer() console output}
- * (for example) if the stream uses a monospaced font and supports Unicode characters.
- * Some formatting characteristics (indentation width, column where to draw the vertical line
- * below nodes) can be modified by calls to the setter methods defined in this formatter.
- *
- * @author  Martin Desruisseaux (IRD, Geomatys)
- * @since   0.3 (derived from geotk-2.0)
+ * @author  Martin Desruisseaux (Geomatys)
+ * @since   0.3
  * @version 0.3
  * @module
  *
- * @see org.apache.sis.io.TableFormatter
+ * @param <T> The base type of objects parsed and formatted by this class.
+ *
+ * @see TableFormatter
  */
 @NotThreadSafe
-public class TreeTableFormat extends CompoundFormat<TreeTable> {
+public abstract class TabularFormat<T> extends CompoundFormat<T> {
     /**
      * For cross-version compatibility.
      */
-    private static final long serialVersionUID = -4476366905386037025L;
+    private static final long serialVersionUID = -1599411687892965650L;
 
     /**
-     * The table columns to format, or {@code null} for formatting all of them.
-     * This map shall not be modified after creation, because it may be shared
-     * by many tables.
-     *
-     * @see #getColumns()
-     * @see #setColumns(TableColumn[])
-     */
-    private Map<TableColumn<?>,Integer> columnIndices;
-
-    /**
-     * The number of characters to add on the left side for each indentation level.
-     * The default value is 4.
+     * The line separator to use for formatting the tree.
+     * The default value is system-dependent.
      *
-     * @see #getIndentation()
-     * @see #setIndentation(int)
+     * @see #getLineSeparator()
+     * @see #setLineSeparator(String)
      */
-    private int indentation;
+    protected String lineSeparator;
 
     /**
-     * The position of the vertical line, relative to the position of the label of the parent node.
-     * The default value is 0, which means that the vertical line is drawn below the first letter
-     * of the node label.
+     * The column separator to use at formatting time if there is more than one column.
+     * This is the character between the "{@code [ ]}" pair of brackets in the pattern
+     * given to the {@link #setColumnSeparatorPattern(String)} method.
      *
-     * @see #getVerticalLinePosition()
-     * @see #setVerticalLinePosition(int)
+     * Subclasses will typically use this value in calls to {@link TableFormatter#nextColumn(char)}.
      */
-    private int verticalLinePosition;
+    protected char columnSeparator;
 
     /**
-     * The string to write before and after the {@link #columnSeparator},
-     * or an empty string if none.
+     * The string to write before the {@link #columnSeparator}, or an empty string if none.
+     * This is the sequence of characters before the "{@code [ ]}" pair of brackets in the
+     * pattern given to the {@link #setColumnSeparatorPattern(String)} method.
      */
-    String separatorPrefix, separatorSuffix;
+    protected String separatorPrefix;
 
     /**
-     * The column separator to use at formatting time if there is more than one column.
-     * This character will be repeated as many time as needed.
-     *
-     * @see #getColumnSeparatorPattern()
-     * @see #setColumnSeparatorPattern(String)
+     * The string to write after the {@link #columnSeparator}, or an empty string if none.
+     * This is the sequence of characters after the "{@code [ ]}" pair of brackets in the
+     * pattern given to the {@link #setColumnSeparatorPattern(String)} method.
      */
-    char columnSeparator;
+    protected String separatorSuffix;
 
     /**
      * {@code true} if the trailing {@code null} values shall be omitted at formatting time.
+     * This flag is controlled by the presence or absence of the {@code '?'} character at the
+     * beginning of the pattern given to the {@link #setColumnSeparatorPattern(String)} method.
      */
-    boolean omitTrailingNulls;
+    protected boolean omitTrailingNulls;
 
     /**
      * {@code true} if the user defined the parsing pattern explicitely.
      */
-    boolean isParsePatternDefined;
+    private boolean isParsePatternDefined;
 
     /**
      * The pattern used at parsing time for finding the column separators, or {@code null}
@@ -145,98 +130,36 @@ public class TreeTableFormat extends Com
     private Pattern parsePattern;
 
     /**
-     * The line separator to use for formatting the tree.
-     *
-     * @see #getLineSeparator()
-     * @see #setLineSeparator(String)
-     */
-    String lineSeparator;
-
-    /**
-     * The tree symbols to write in the left margin, or {@code null} if not yet computed.
-     * The default symbols are as below:
-     *
-     * <ul>
-     *   <li>{@code treeBlank} = {@code "    "}</li>
-     *   <li>{@code treeLine}  = {@code "│   "}</li>
-     *   <li>{@code treeCross} = {@code "├───"}</li>
-     *   <li>{@code treeEnd}   = {@code "└───"}</li>
-     * </ul>
-     *
-     * @see #clearTreeSymbols()
-     * @see #createTreeSymbols()
-     */
-    private transient String treeBlank, treeLine, treeCross, treeEnd;
-
-    /**
-     * Creates a new tree table format.
+     * Creates a new tabular format.
      *
      * @param locale   The locale to use for numbers, dates and angles formatting.
      * @param timezone The timezone, or {@code null} for UTC.
      */
-    public TreeTableFormat(final Locale locale, final TimeZone timezone) {
+    public TabularFormat(final Locale locale, final TimeZone timezone) {
         super(locale, timezone);
-        indentation       = 4;
-        separatorPrefix   = "……";
-        columnSeparator   = '…';
-        separatorSuffix   = " ";
-        omitTrailingNulls = true;
-        lineSeparator     = System.lineSeparator();
+        separatorPrefix = "";
+        columnSeparator = ' ';
+        separatorSuffix = " ";
+        lineSeparator   = System.lineSeparator();
     }
 
     /**
-     * Clears the symbols used when writing the tree.
-     * They will be computed again when first needed.
+     * Returns the current line separator. The default value is system-dependent.
      *
-     * @see #createTreeSymbols()
-     */
-    private void clearTreeSymbols() {
-        treeBlank = null;
-        treeLine  = null;
-        treeCross = null;
-        treeEnd   = null;
-    }
-
-    /**
-     * Returns the type of object formatted by this class, which is {@link TreeTable}.
+     * @return The current line separator.
      */
-    @Override
-    public final Class<TreeTable> getValueType() {
-        return TreeTable.class;
+    public String getLineSeparator() {
+        return lineSeparator;
     }
 
     /**
-     * Returns the table columns to parse and format, or {@code null} for the default list of
-     * columns. The default is:
-     *
-     * <ul>
-     *   <li>On parsing, a single column containing the node label as a {@link String}.</li>
-     *   <li>On formatting, {@linkplain TreeTable#getColumns() all <code>TreeTable</code> columns}.</li>
-     * </ul>
+     * Sets the line separator. Can not be a null or empty string.
      *
-     * @return The table columns to parse and format, or {@code null} for the default.
+     * @param separator The new line separator.
      */
-    public TableColumn<?>[] getColumns() {
-        return (columnIndices != null) ? DefaultTreeTable.getColumns(columnIndices) : null;
-    }
-
-    /**
-     * Sets the table columns to parse and format. A {@code null} value means to use the default
-     * list of columns, as defined in the {@link #getColumns()} method.
-     *
-     * @param  columns The table columns to parse and format, or {@code null} for the default.
-     * @throws IllegalArgumentException If the given array is empty, contains a null element
-     *         or a duplicated value.
-     */
-    public void setColumns(final TableColumn<?>... columns) throws IllegalArgumentException {
-        if (columns == null) {
-            columnIndices = null;
-        } else {
-            if (columns.length == 0) {
-                throw new IllegalArgumentException(Errors.format(Errors.Keys.EmptyArgument_1, "columns"));
-            }
-            columnIndices = DefaultTreeTable.createColumnIndices(columns);
-        }
+    public void setLineSeparator(final String separator) {
+        ArgumentChecks.ensureNonEmpty("separator", separator);
+        lineSeparator = separator;
     }
 
     /**
@@ -244,10 +167,6 @@ public class TreeTableFormat extends Com
      * only if more than one column is formatted. See {@link #setColumnSeparatorPattern(String)}
      * for a description of the pattern syntax.
      *
-     * <p>The default pattern is {@code "?……[…] "}, which means "<cite>If the next value is
-     * non-null, then insert the {@code "……"} string, repeat the {@code '…'} character as many
-     * time as needed (may be zero), and finally insert a space</cite>".</p>
-     *
      * @return The pattern of the current column separator.
      */
     public String getColumnSeparatorPattern() {
@@ -290,7 +209,7 @@ public class TreeTableFormat extends Com
      *   <tr><td>{@code '\\'}</td> <td>Escape any of the characters listed in this table.</td></tr>
      * </table>
      *
-     * Restrictions:
+     * {@section Restrictions}
      * <ul>
      *   <li>If present, {@code '?'} shall be the first character in the pattern.</li>
      *   <li>The repeated character (specified inside the pair of brackets) is mandatory.</li>
@@ -300,6 +219,11 @@ public class TreeTableFormat extends Com
      *       with the {@link Pattern} syntax.</li>
      * </ul>
      *
+     * {@section Example}
+     * The {@code "?……[…] "} pattern means "<cite>If the next value is non-null, then insert the
+     * {@code "……"} string, repeat the {@code '…'} character as many time as needed (may be zero),
+     * then insert a space</cite>".
+     *
      * @param  pattern The pattern of the new column separator.
      * @throws IllegalArgumentException If the given pattern is illegal.
      */
@@ -365,7 +289,7 @@ scan:   for (int i=0; i<length; i++) {
         }
         if (prefix == null) {
             throw new IllegalArgumentException(Errors.format(
-                    Errors.Keys.IllegalFormatPatternForClass_2, TreeTable.class, pattern));
+                    Errors.Keys.IllegalFormatPatternForClass_2, getValueType(), pattern));
         }
         /*
          * Finally store the result. The parsing pattern must be first because the call to
@@ -386,470 +310,24 @@ scan:   for (int i=0; i<length; i++) {
     }
 
     /**
-     * Returns the current line separator. The default value is system-dependent.
-     *
-     * @return The current line separator.
-     */
-    public String getLineSeparator() {
-        return lineSeparator;
-    }
-
-    /**
-     * Sets the line separator.
-     *
-     * @param separator The new line separator.
-     */
-    public void setLineSeparator(final String separator) {
-        ArgumentChecks.ensureNonEmpty("separator", separator);
-        lineSeparator = separator;
-    }
-
-    /**
-     * Returns the number of spaces to add on the left margin for each indentation level.
-     * The default value is 4.
-     *
-     * @return The current indentation.
-     */
-    public int getIndentation() {
-        return indentation;
-    }
-
-    /**
-     * Sets the number of spaces to add on the left margin for each indentation level.
-     * If the new indentation is smaller than the {@linkplain #getVerticalLinePosition()
-     * vertical line position}, then the later is also set to the given indentation value.
-     *
-     * @param  indentation The new indentation.
-     * @throws IllegalArgumentException If the given value is negative.
-     */
-    public void setIndentation(final int indentation) throws IllegalArgumentException {
-        ArgumentChecks.ensurePositive("indentation", indentation);
-        this.indentation = indentation;
-        if (verticalLinePosition > indentation) {
-            verticalLinePosition = indentation;
-        }
-        clearTreeSymbols();
-    }
-
-    /**
-     * Returns the position of the vertical line, relative to the position of the root label.
-     * The default value is 0, which means that the vertical line is drawn below the first
-     * letter of the root label.
-     *
-     * @return The current vertical line position.
-     */
-    public int getVerticalLinePosition() {
-        return verticalLinePosition;
-    }
-
-    /**
-     * Sets the position of the vertical line, relative to the position of the root label.
-     * The given value can not be greater than the {@linkplain #getIndentation() indentation}.
+     * Returns a matcher for the column separators in the given text.
+     * This method is invoked by subclasses in their {@code parse(…)} implementations.
      *
-     * @param  verticalLinePosition The new vertical line position.
-     * @throws IllegalArgumentException If the given value is negative or greater than the indentation.
+     * @param  text The text for which to get a matcher.
+     * @return A matcher for the column separators in the given text.
      */
-    public void setVerticalLinePosition(final int verticalLinePosition) throws IllegalArgumentException {
-        ArgumentChecks.ensureBetween("verticalLinePosition", 0, indentation, verticalLinePosition);
-        this.verticalLinePosition = verticalLinePosition;
-        clearTreeSymbols();
-    }
-
-    /**
-     * Returns the formats to use for parsing and formatting the values of each column.
-     * The returned array may contain {@code null} elements, which means that the values
-     * in that column can be stored as {@code String}s.
-     *
-     * @param  mandatoy {@code true} if an exception shall be thrown for unrecognized types,
-     *         or {@code false} for storing a {@code null} value in the array instead.
-     * @throws IllegalStateException If {@code mandatory} is {@code true} and a column
-     *         contains values of an unsupported type.
-     */
-    final Format[] getFormats(final TableColumn<?>[] columns, final boolean mandatory) throws IllegalStateException {
-        final Format[] formats = new Format[columns.length];
-        for (int i=0; i<formats.length; i++) {
-            final Class<?> valueType = columns[i].getElementType();
-            if ((formats[i] = getFormat(valueType)) == null) {
-                if (mandatory && !valueType.isAssignableFrom(String.class)) {
-                    throw new IllegalStateException(Errors.format(
-                            Errors.Keys.UnspecifiedFormatForClass_1, valueType));
-                }
-            }
-        }
-        return formats;
-    }
-
-    /**
-     * Creates a tree from the given character sequence,
-     * or returns {@code null} if an error occurred while parsing the characters.
-     * This method can parse the trees created by the {@code format(…)} methods
-     * defined in this class.
-     *
-     * {@section Parsing rules}
-     * <ul>
-     *   <li>Each node shall be represented by a single line made of two parts, in that order:
-     *     <ol>
-     *       <li>white spaces and tree drawing characters ({@code '│'}, {@code '├'}, {@code '└'} or {@code '─'});</li>
-     *       <li>string representations of node values, separated by the
-     *           {@linkplain #getColumnSeparatorPattern() colunm separator}.</li>
-     *     </ol>
-     *   </li>
-     *   <li>The number of spaces and drawing characters before the node values determines the node
-     *       indentation. This indentation doesn't need to be a factor of the {@link #getIndentation()}
-     *       value, but must be consistent across all the parsed tree.</li>
-     *   <li>The indentation determines the parent of each node.</li>
-     *   <li>Parsing stops at first empty line (ignoring whitespaces), or at the end of the given text.</li>
-     * </ul>
-     *
-     * @param  text The character sequence for the tree to parse.
-     * @param  pos  The position where to start the parsing.
-     * @return The parsed tree, or {@code null} if the given character sequence can not be parsed.
-     * @throws ParseException If an error occurred while parsing a node value.
-     */
-    @Override
-    public TreeTable parse(final CharSequence text, final ParsePosition pos) throws ParseException {
+    protected Matcher getColumnSeparatorMatcher(final CharSequence text) {
         if (parsePattern == null) {
-            parsePattern = Pattern.compile(
-                    Pattern.quote(separatorPrefix)
-                  + Pattern.quote(String.valueOf(columnSeparator)) + '*'
-                  + Pattern.quote(separatorSuffix));
-        }
-        final Matcher matcher = parsePattern.matcher(text);
-        final int length        = text.length();
-        int indexOfLineStart    = pos.getIndex();
-        int indentationLevel    = 0;                // Current index in the 'indentations' array.
-        int[] indentations      = new int[16];      // Number of spaces (ignoring drawing characters) for each level.
-        TreeTable.Node lastNode = null;             // Last parsed node, having 'indentation[level]' characters before its content.
-        TreeTable.Node root     = null;             // First node found while parsing.
-        final DefaultTreeTable table = new DefaultTreeTable(columnIndices != null ? columnIndices : TableColumn.NAME_MAP);
-        final TableColumn<?>[] columns = DefaultTreeTable.getColumns(table.columnIndices);
-        final Format[] formats = getFormats(columns, true);
-        do {
-            final int startNextLine = CharSequences.indexOfLineStart(text, 1, indexOfLineStart);
-            int endOfLine = startNextLine;
-            while (endOfLine > indexOfLineStart) {
-                final int c = text.charAt(endOfLine-1);
-                if (c != '\r' && c != '\n') break;
-                endOfLine--; // Skip trailing '\r' and '\n'.
-            }
-            /*
-             * Skip leading spaces using Character.isSpaceChar(…) instead than isWhitespace(…)
-             * because we need to skip non-breaking spaces as well as ordinary space. We don't
-             * need to consider line feeds since they were handled by the lines just above.
-             */
-            boolean hasChar = false;
-            int i; // The indentation of current line.
-            for (i=indexOfLineStart; i<endOfLine;) {
-                final int c = Character.codePointAt(text, i);
-                if (!Character.isSpaceChar(c)) {
-                    hasChar = true;
-                    if ("─│└├".indexOf(c) < 0) {
-                        break;
-                    }
-                }
-                i += Character.charCount(c);
-            }
-            if (!hasChar) {
-                break; // The line contains only whitespaces.
-            }
-            /*
-             * Go back to the fist non-space character (should be '─'). We do that in case the
-             * user puts some spaces in the text of the node label, since we don't want those
-             * user-spaces to interfer with the calculation of indentation.
-             */
-            int indexOfValue = i;
-            i = CharSequences.skipTrailingWhitespaces(text, indexOfLineStart, i) - indexOfLineStart;
-            /*
-             * Found the first character which is not part of the indentation. Create a new root
-             * (without parent for now) and parse the values for each column. Columns with empty
-             * text are not parsed (the value is left to null).
-             */
-            final TreeTable.Node node = new DefaultTreeTable.Node(table);
-            try {
-                matcher.region(indexOfValue, endOfLine);
-                for (int ci=0; ci<columns.length; ci++) {
-                    final boolean found = matcher.find();
-                    int endOfColumn = found ? matcher.start() : endOfLine;
-                    indexOfValue   = CharSequences.skipLeadingWhitespaces (text, indexOfValue, endOfColumn);
-                    int endOfValue = CharSequences.skipTrailingWhitespaces(text, indexOfValue, endOfColumn);
-                    if (endOfValue > indexOfValue) {
-                        parseValue(node, columns[ci], formats[ci], text.subSequence(indexOfValue, endOfValue).toString());
-                    }
-                    if (!found) break;
-                    // The end of this column will be the beginning of the next column,
-                    // after skipping the last character of the column separator.
-                    indexOfValue = matcher.end();
-                }
-            } catch (ParseException e) {
-                pos.setErrorIndex(indexOfValue);
-                throw e;
+            final StringBuilder pattern = new StringBuilder(separatorPrefix).append(columnSeparator);
+            String tmp = pattern.toString();
+            pattern.setLength(0);
+            pattern.append(Pattern.quote(tmp)).append('*');
+            tmp = separatorSuffix;
+            if (tmp.length() != 0) {
+                pattern.append(Pattern.quote(tmp));
             }
-            /*
-             * If this is the first node created so far, it will be the root.
-             */
-            if (root == null) {
-                indentations[0] = i;
-                root = node;
-            } else {
-                int p;
-                while (i < (p = indentations[indentationLevel])) {
-                    /*
-                     * Lower indentation level: go up in the tree until we find the new parent.
-                     * Note that lastNode.getParent() should never return null, since only the
-                     * node at 'indentationLevel == 0' has a null parent and we check that case.
-                     */
-                    if (--indentationLevel < 0) {
-                        pos.setErrorIndex(indexOfLineStart);
-                        throw new LocalizedParseException(locale,
-                                Errors.Keys.NodeHasNoParent_1, new Object[] {node}, 0);
-                    }
-                    lastNode = lastNode.getParent();
-                }
-                if (i == p) {
-                    /*
-                     * The node we just created is a sibling of the previous node. This is
-                     * illegal if level==0, in which case we have no parent. Otherwise add
-                     * the sibling to the common parent and let the indentation level unchanged.
-                     */
-                    final TreeTable.Node parent = lastNode.getParent();
-                    if (parent == null) {
-                        pos.setErrorIndex(indexOfLineStart);
-                        throw new LocalizedParseException(locale,
-                                Errors.Keys.NodeHasNoParent_1, new Object[] {node}, 0);
-                    }
-                    parent.getChildren().add(node);
-                } else if (i > p) {
-                    /*
-                     * The node we just created is a child of the previous node.
-                     * Add a new indentation level.
-                     */
-                    lastNode.getChildren().add(node);
-                    if (++indentationLevel == indentations.length) {
-                        indentations = Arrays.copyOf(indentations, indentationLevel*2);
-                    }
-                    indentations[indentationLevel] = i;
-                }
-            }
-            lastNode = node;
-            indexOfLineStart = startNextLine;
-        } while (indexOfLineStart != length);
-        if (root == null) {
-            return null;
-        }
-        pos.setIndex(indexOfLineStart);
-        table.setRoot(root);
-        return table;
-    }
-
-    /**
-     * Parses the given string using a format appropriate for the type of values in
-     * the given column, and stores the value in the given node.
-     *
-     * @param  V        The type of values in the given column.
-     * @param  node     The node in which to set the value.
-     * @param  column   The column in which to set the value.
-     * @param  format   The format to use for parsing the value, or {@code null}.
-     * @param  text     The textual representation of the value.
-     * @throws ParseException If an error occurred while parsing.
-     */
-    private <V> void parseValue(final TreeTable.Node node, final TableColumn<V> column,
-            final Format format, final String text) throws ParseException
-    {
-        final Object value;
-        if (format != null) {
-            value = format.parseObject(text);
-        } else {
-            value = text;
-        }
-        node.setValue(column, column.getElementType().cast(value));
-    }
-
-    /**
-     * Computes the {@code tree*} fields from the {@link #indentation} and
-     * {@link #verticalLinePosition} current values.
-     *
-     * @see #clearTreeSymbols()
-     */
-    private void createTreeSymbols() {
-        final int indentation = this.indentation;
-        final int verticalLinePosition = this.verticalLinePosition;
-        final char[] buffer = new char[indentation];
-        for (int k=0; k<4; k++) {
-            final char vc, hc;
-            if ((k & 2) == 0) {
-                // No horizontal line
-                vc = (k & 1) == 0 ? NO_BREAK_SPACE : '│';
-                hc = NO_BREAK_SPACE;
-            } else {
-                // With a horizontal line
-                vc = (k & 1) == 0 ? '└' : '├';
-                hc = '─';
-            }
-            Arrays.fill(buffer, 0, verticalLinePosition, NO_BREAK_SPACE);
-            buffer[verticalLinePosition] = vc;
-            Arrays.fill(buffer, verticalLinePosition + 1, indentation, hc);
-            final String symbols = String.valueOf(buffer);
-            switch (k) {
-                case 0: treeBlank = symbols; break;
-                case 1: treeLine  = symbols; break;
-                case 2: treeEnd   = symbols; break;
-                case 3: treeCross = symbols; break;
-                default: throw new AssertionError(k);
-            }
-        }
-    }
-
-    /**
-     * Returns the string to write before a node.
-     *
-     * @param isParent {@code true} for a parent node, or {@code false} for the actual node.
-     * @param isLast   {@code true} if the node is the last children of its parent node.
-     */
-    final String getTreeSymbols(final boolean isParent, final boolean isLast) {
-        return(isParent ? (isLast ? treeBlank : treeLine)
-                        : (isLast ? treeEnd   : treeCross));
-    }
-
-    /**
-     * Creates string representation of the node values. Tabulations are replaced by spaces,
-     * and line feeds are replaced by the Pilcrow character. This is necessary in order to
-     * avoid conflict with the characters expected by {@link TableFormatter}.
-     */
-    private final class Writer extends LineFormatter {
-        /**
-         * For each indentation level, {@code true} if the previous levels are writing the last node.
-         * This array will growth as needed.
-         */
-        private boolean[] isLast;
-
-        /**
-         * The columns to write.
-         */
-        private final TableColumn<?>[] columns;
-
-        /**
-         * The format to use for each column.
-         */
-        private final Format[] formats;
-
-        /**
-         * The node values to format.
-         */
-        private final Object[] values;
-
-        /**
-         * Creates a new instance which will write in the given appendable.
-         */
-        Writer(final Appendable out, final TableColumn<?>[] columns) {
-            super(columns.length >= 2 ? new TableFormatter(out, "") : out);
-            this.columns  = columns;
-            this.formats  = getFormats(columns, false);
-            this.values   = new Object[columns.length];
-            this.isLast   = new boolean[8];
-            setTabulationExpanded(true);
-            setLineSeparator(" ¶ ");
-        }
-
-        /**
-         * Appends a textual representation of the given value.
-         *
-         * @param  format The format to use.
-         * @param  value  The value to format (may be {@code null}).
-         */
-        private void formatValue(final Format format, final Object value) throws IOException {
-            final CharSequence text;
-            if (value == null) {
-                text = " "; // String for missing value.
-            } else if (format != null) {
-                if (format instanceof CompoundFormat<?>) {
-                    formatValue((CompoundFormat<?>) format, value);
-                    return;
-                }
-                text = format.format(value);
-            } else {
-                text = String.valueOf(value);
-            }
-            append(text);
-        }
-
-        /**
-         * Work around for the inability to define the variable {@code <V>} locally.
-         */
-        @Workaround(library="JDK", version="1.7")
-        private <V> void formatValue(final CompoundFormat<V> format, final Object value) throws IOException {
-            format.format(format.getValueType().cast(value), this);
-        }
-
-        /**
-         * Appends the string representation of the given node and all its children.
-         * This method invokes itself recursively.
-         *
-         * @param node  The node to format.
-         * @param level Indentation level. The first level is 0.
-         */
-        final void format(final TreeTable.Node node, final int level) throws IOException {
-            for (int i=0; i<level; i++) {
-                out.append(getTreeSymbols(i != level-1, isLast[i]));
-            }
-            int n = 0;
-            for (int i=0; i<columns.length; i++) {
-                if ((values[i] = node.getValue(columns[i])) != null) {
-                    n = i;
-                }
-            }
-            if (!omitTrailingNulls) {
-                n = values.length - 1;
-            }
-            for (int i=0; i<=n; i++) {
-                if (i != 0) {
-                    // We have a TableFormatter instance if and only if there is 2 or more columns.
-                    ((TableFormatter) out.append(separatorPrefix)).nextColumn(columnSeparator);
-                    out.append(separatorSuffix);
-                }
-                formatValue(formats[i], values[i]);
-                clear();
-            }
-            out.append(lineSeparator);
-            if (level >= isLast.length) {
-                isLast = Arrays.copyOf(isLast, level*2);
-            }
-            final List<? extends TreeTable.Node> children = node.getChildren();
-            final int count = children.size();
-            for (int i=0; i<count; i++) {
-                isLast[level] = (i == count-1);
-                format(children.get(i), level+1);
-            }
-        }
-    }
-
-    /**
-     * Writes a graphical representation of the specified tree table in the given stream or buffer.
-     * This method iterates recursively over all {@linkplain TreeTable.Node#getChildren() children}.
-     * For each {@linkplain #getColumns() column to format} in each node, this method gets a textual
-     * representation of the {@linkplain TreeTable.Node#getValue(TableColumn) value in that column}
-     * using the formatter obtained by a call to {@link #getFormat(Class)}.
-     *
-     * @param  tree        The tree to format.
-     * @param  toAppendTo  Where to format the tree.
-     * @throws IOException If an error occurred while writing in the given appender.
-     *
-     * @see TreeTables#toString(TreeTable)
-     */
-    @Override
-    public void format(final TreeTable tree, final Appendable toAppendTo) throws IOException {
-        ArgumentChecks.ensureNonNull("tree", tree);
-        if (treeBlank == null) {
-            createTreeSymbols();
-        }
-        TableColumn<?>[] columns;
-        if (columnIndices != null) {
-            columns = DefaultTreeTable.getColumns(columnIndices);
-        } else {
-            final List<TableColumn<?>> c = tree.getColumns();
-            columns = c.toArray(new TableColumn<?>[c.size()]);
+            parsePattern = Pattern.compile(pattern.toString());
         }
-        final Writer out = new Writer(toAppendTo, columns);
-        out.format(tree.getRoot(), 0);
-        out.flush();
+        return parsePattern.matcher(text);
     }
 }

Modified: sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/math/MathFunctions.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/math/MathFunctions.java?rev=1425402&r1=1425401&r2=1425402&view=diff
==============================================================================
--- sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/math/MathFunctions.java (original)
+++ sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/math/MathFunctions.java Sun Dec 23 04:03:29 2012
@@ -692,6 +692,8 @@ testNextNumber:         while (true) { /
      * @param  number The number for which to find the next prime.
      * @return The given number if it is a prime number, or the next prime number otherwise.
      * @throws IllegalArgumentException If the given value is outside the supported range.
+     *
+     * @see java.math.BigInteger#isProbablePrime(int)
      */
     public static int nextPrimeNumber(final int number) throws IllegalArgumentException {
         ArgumentChecks.ensureBetween("number", 2, HIGHEST_SUPPORTED_PRIME_NUMBER, number);

Modified: sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/math/StatisticsFormat.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/math/StatisticsFormat.java?rev=1425402&r1=1425401&r2=1425402&view=diff
==============================================================================
--- sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/math/StatisticsFormat.java (original)
+++ sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/math/StatisticsFormat.java Sun Dec 23 04:03:29 2012
@@ -16,8 +16,8 @@
  */
 package org.apache.sis.math;
 
-import java.util.ArrayList;
 import java.util.List;
+import java.util.ArrayList;
 import java.io.IOException;
 import java.util.Locale;
 import java.util.TimeZone;
@@ -28,7 +28,7 @@ import java.text.ParsePosition;
 import java.text.ParseException;
 
 import org.apache.sis.io.TableFormatter;
-import org.apache.sis.io.CompoundFormat;
+import org.apache.sis.io.TabularFormat;
 import org.apache.sis.util.resources.Vocabulary;
 
 import static java.lang.Math.*;
@@ -36,16 +36,24 @@ import static java.lang.Math.*;
 
 /**
  * Formats a {@link Statistics} object.
- * This is a package-private class for now - if we want to make it public, we may need to make it
- * a full-featured {@link java.text.Format} implementation.
+ * By default, newly created {@code StatisticsFormat} instances will format statistical values
+ * in a tabular format using spaces as the column separator. This default configuration matches
+ * the {@link Statistics#toString()} format.
+ *
+ * {@section Limitations}
+ * The current implementation can only format statistics - parsing is not yet implemented.
  *
  * @author  Martin Desruisseaux (MPO, IRD, Geomatys)
  * @since   0.3 (derived from geotk-1.0)
  * @version 0.3
  * @module
  */
-@SuppressWarnings("serial")
-final class StatisticsFormat extends CompoundFormat<Statistics> {
+public class StatisticsFormat extends TabularFormat<Statistics> {
+    /**
+     * For cross-version compatibility.
+     */
+    private static final long serialVersionUID = -7393669354879347985L;
+
     /**
      * Number of additional digits, to be added to the number of digits computed from the
      * range and the number of sample values. This is an arbitrary parameter.
@@ -67,12 +75,6 @@ final class StatisticsFormat extends Com
     private boolean allPopulation;
 
     /**
-     * The column separator, typically as a semicolon or tabulation character.
-     * If 0, then the values will be written in a tabular format using {@link TableFormatter}.
-     */
-    private char columnSeparator;
-
-    /**
      * Returns an instance for the current system default locale.
      *
      * @return A statistics format instance for the current default locale.
@@ -117,6 +119,33 @@ final class StatisticsFormat extends Com
     }
 
     /**
+     * Returns {@code true} if this formatter shall consider that the statistics where computed
+     * using the totality of the populations under study. This information impacts the standard
+     * deviation values to be formatted.
+     *
+     * @return {@code true} if the statistics to format where computed using the totality of
+     *         the populations under study.
+     *
+     * @see Statistics#standardDeviation(boolean)
+     */
+    public boolean isForAllPopulation() {
+        return allPopulation;
+    }
+
+    /**
+     * Sets whether this formatter shall consider that the statistics where computed using
+     * the totality of the populations under study. The default value is {@code false}.
+     *
+     * @param allPopulation {@code true} if the statistics to format where computed
+     *        using the totality of the populations under study.
+     *
+     * @see Statistics#standardDeviation(boolean)
+     */
+    public void setForAllPopulation(final boolean allPopulation) {
+        this.allPopulation = allPopulation;
+    }
+
+    /**
      * Not yet implemented.
      */
     @Override
@@ -126,7 +155,8 @@ final class StatisticsFormat extends Com
 
     /**
      * The resource keys of the rows to formats. Array index must be consistent with
-     * the switch statements inside the {@link #format(Statistics)} method.
+     * the switch statements inside the {@link #format(Statistics)} method (we define
+     * this static field close to the format methods for this purpose).
      */
     private static final int[] KEYS = {
         Vocabulary.Keys.NumberOfValues,
@@ -142,6 +172,10 @@ final class StatisticsFormat extends Com
      * Formats a localized string representation of the given statistics.
      * If statistics on {@linkplain Statistics#differences() differences}
      * are associated to the given object, they will be formatted too.
+     *
+     * @param  stats       The statistics to format.
+     * @param  toAppendTo  Where to format the object.
+     * @throws IOException If an error occurred while writing in the given appender.
      */
     @Override
     public void format(Statistics stats, final Appendable toAppendTo) throws IOException {
@@ -158,8 +192,7 @@ final class StatisticsFormat extends Com
      * for the statistics on {@linkplain Statistics#differences() differences} - if
      * such statistics are wanted, they must be included in the given array.
      */
-    private void format(final Statistics[] stats, Appendable toAppendTo) throws IOException {
-        final String lineSeparator = System.lineSeparator();
+    private void format(final Statistics[] stats, final Appendable toAppendTo) throws IOException {
         /*
          * Verify if we can omit the count of NaN values.
          */
@@ -170,17 +203,7 @@ final class StatisticsFormat extends Com
                 break;
             }
         }
-        /*
-         * This formatter can optionally use a column separator, typically a semi-colon.
-         * If no column separator was specified (which is the usual case), then we will
-         * format the values in a tabular format.
-         */
-        TableFormatter table = null;
-        char separator = columnSeparator;
-        if (separator == 0) {
-            toAppendTo = table = new TableFormatter(toAppendTo, " ");
-            separator = '\t'; // Will be handled especially by TableFormatter.
-        }
+        final TableFormatter table = new TableFormatter(toAppendTo, separatorSuffix);
         final Vocabulary resources = Vocabulary.getResources(labelLocale);
         /*
          * Initialize the NumberFormat for formatting integers without scientific notation.
@@ -209,10 +232,8 @@ final class StatisticsFormat extends Com
                 case 2: needsConfigure = true; break;
                 case 3: needsConfigure = (stats[0].differences() != null); break;
             }
-            if (table != null) {
-                table.setCellAlignment(TableFormatter.ALIGN_LEFT);
-            }
-            toAppendTo.append(resources.getString(KEYS[i])).append(':');
+            table.setCellAlignment(TableFormatter.ALIGN_LEFT);
+            table.append(resources.getString(KEYS[i])).append(':');
             for (final Statistics s : stats) {
                 final Number value;
                 switch (i) {
@@ -228,19 +249,17 @@ final class StatisticsFormat extends Com
                 if (needsConfigure) {
                     configure(format, s);
                 }
-                toAppendTo.append(separator).append(format.format(value));
-                if (table != null) {
-                    table.setCellAlignment(TableFormatter.ALIGN_RIGHT);
-                }
+                table.append(separatorPrefix);
+                table.nextColumn(columnSeparator);
+                table.append(format.format(value));
+                table.setCellAlignment(TableFormatter.ALIGN_RIGHT);
             }
-            toAppendTo.append(lineSeparator);
+            table.append(lineSeparator);
         }
         /*
          * TableFormatter needs to be explicitly flushed in order to format the values.
          */
-        if (table != null) {
-            table.flush();
-        }
+        table.flush();
     }
 
     /**

Modified: sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/collection/TreeTableFormat.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/collection/TreeTableFormat.java?rev=1425402&r1=1425401&r2=1425402&view=diff
==============================================================================
--- sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/collection/TreeTableFormat.java (original)
+++ sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/collection/TreeTableFormat.java Sun Dec 23 04:03:29 2012
@@ -25,15 +25,14 @@ import java.io.IOException;
 import java.text.Format;
 import java.text.ParsePosition;
 import java.text.ParseException;
-import java.util.regex.Pattern;
 import java.util.regex.Matcher;
 import net.jcip.annotations.NotThreadSafe;
 import org.apache.sis.io.LineFormatter;
 import org.apache.sis.io.TableFormatter;
+import org.apache.sis.io.TabularFormat;
 import org.apache.sis.io.CompoundFormat;
 import org.apache.sis.util.Workaround;
 import org.apache.sis.util.CharSequences;
-import org.apache.sis.util.StringBuilders;
 import org.apache.sis.util.ArgumentChecks;
 import org.apache.sis.util.resources.Errors;
 import org.apache.sis.internal.util.LocalizedParseException;
@@ -67,18 +66,23 @@ import static org.apache.sis.util.Charac
  *
  * This representation can be printed to the {@linkplain java.io.Console#writer() console output}
  * (for example) if the stream uses a monospaced font and supports Unicode characters.
+ *
+ * {@section Customization}
  * Some formatting characteristics (indentation width, column where to draw the vertical line
  * below nodes) can be modified by calls to the setter methods defined in this formatter.
+ * In particular, the dots joining the node labels to their values can be specified by the
+ * {@linkplain #setColumnSeparatorPattern(String) column separator pattern}.
+ * The default pattern is {@code "?……[…] "}, which means "<cite>If the next value is non-null,
+ * then insert the {@code "……"} string, repeat the {@code '…'} character as many time as needed
+ * (may be zero), and finally insert a space</cite>".
  *
  * @author  Martin Desruisseaux (IRD, Geomatys)
  * @since   0.3 (derived from geotk-2.0)
  * @version 0.3
  * @module
- *
- * @see org.apache.sis.io.TableFormatter
  */
 @NotThreadSafe
-public class TreeTableFormat extends CompoundFormat<TreeTable> {
+public class TreeTableFormat extends TabularFormat<TreeTable> {
     /**
      * For cross-version compatibility.
      */
@@ -114,45 +118,6 @@ public class TreeTableFormat extends Com
     private int verticalLinePosition;
 
     /**
-     * The string to write before and after the {@link #columnSeparator},
-     * or an empty string if none.
-     */
-    String separatorPrefix, separatorSuffix;
-
-    /**
-     * The column separator to use at formatting time if there is more than one column.
-     * This character will be repeated as many time as needed.
-     *
-     * @see #getColumnSeparatorPattern()
-     * @see #setColumnSeparatorPattern(String)
-     */
-    char columnSeparator;
-
-    /**
-     * {@code true} if the trailing {@code null} values shall be omitted at formatting time.
-     */
-    boolean omitTrailingNulls;
-
-    /**
-     * {@code true} if the user defined the parsing pattern explicitely.
-     */
-    boolean isParsePatternDefined;
-
-    /**
-     * The pattern used at parsing time for finding the column separators, or {@code null}
-     * if not yet constructed. This field is serialized because it may be a user-specified pattern.
-     */
-    private Pattern parsePattern;
-
-    /**
-     * The line separator to use for formatting the tree.
-     *
-     * @see #getLineSeparator()
-     * @see #setLineSeparator(String)
-     */
-    String lineSeparator;
-
-    /**
      * The tree symbols to write in the left margin, or {@code null} if not yet computed.
      * The default symbols are as below:
      *
@@ -181,7 +146,6 @@ public class TreeTableFormat extends Com
         columnSeparator   = '…';
         separatorSuffix   = " ";
         omitTrailingNulls = true;
-        lineSeparator     = System.lineSeparator();
     }
 
     /**
@@ -240,171 +204,6 @@ public class TreeTableFormat extends Com
     }
 
     /**
-     * Returns the pattern of characters used in column separators. Those characters will be used
-     * only if more than one column is formatted. See {@link #setColumnSeparatorPattern(String)}
-     * for a description of the pattern syntax.
-     *
-     * <p>The default pattern is {@code "?……[…] "}, which means "<cite>If the next value is
-     * non-null, then insert the {@code "……"} string, repeat the {@code '…'} character as many
-     * time as needed (may be zero), and finally insert a space</cite>".</p>
-     *
-     * @return The pattern of the current column separator.
-     */
-    public String getColumnSeparatorPattern() {
-        final StringBuilder buffer = new StringBuilder(8);
-        buffer.append(separatorPrefix).append('\uFFFF').append(separatorSuffix);
-        StringBuilders.replace(buffer, "\\", "\\\\");
-        StringBuilders.replace(buffer, "?",  "\\?");
-        StringBuilders.replace(buffer, "[",  "\\[");
-        StringBuilders.replace(buffer, "]",  "\\]");
-        StringBuilders.replace(buffer, "/",  "\\/");
-        if (omitTrailingNulls) {
-            buffer.insert(0, '?');
-        }
-        final int insertAt = buffer.indexOf("\uFFFF");
-        buffer.replace(insertAt, insertAt+1, "[\uFFFF]").setCharAt(insertAt+1, columnSeparator);
-        if (isParsePatternDefined) {
-            buffer.append('/').append(parsePattern.pattern());
-        }
-        return buffer.toString();
-    }
-
-    /**
-     * Sets the pattern of the characters to insert between the columns. The pattern shall contain
-     * exactly one occurrence of the {@code "[ ]"} pair of bracket, with exactly one character
-     * between them. This character will be repeated as many time as needed for columns alignment.
-     *
-     * <p>The formatting pattern can optionally be followed by a regular expression to be used at
-     * parsing time. If omitted, the parsing pattern will be inferred from the formatting pattern.
-     * If specified, then the {@link #parse(CharSequence, ParsePosition) parse} method will invoke
-     * the {@link Matcher#find()} method for determining the column boundaries.</p>
-     *
-     * <p>The characters listed below have special meaning in the pattern.
-     * Other characters are appended <cite>as-is</cite> between the columns.</p>
-     *
-     * <table class="sis">
-     *   <tr><th>Character(s)</th> <th>Meaning</th></tr>
-     *   <tr><td>{@code '?'}</td>  <td>Omit the column separator for trailing null values.</td></tr>
-     *   <tr><td>{@code "[ ]"}</td><td>Repeat the character between bracket as needed.</td></tr>
-     *   <tr><td>{@code '/'}</td>  <td>Separate the formatting pattern from the parsing pattern.</td></tr>
-     *   <tr><td>{@code '\\'}</td> <td>Escape any of the characters listed in this table.</td></tr>
-     * </table>
-     *
-     * Restrictions:
-     * <ul>
-     *   <li>If present, {@code '?'} shall be the first character in the pattern.</li>
-     *   <li>The repeated character (specified inside the pair of brackets) is mandatory.</li>
-     *   <li>In the current implementation, the repeated character must be in the
-     *       {@linkplain Character#isBmpCodePoint(int) Basic Multilanguage Plane}.</li>
-     *   <li>If {@code '/'} is present, anything on its right must be compliant
-     *       with the {@link Pattern} syntax.</li>
-     * </ul>
-     *
-     * @param  pattern The pattern of the new column separator.
-     * @throws IllegalArgumentException If the given pattern is illegal.
-     */
-    public void setColumnSeparatorPattern(final String pattern) throws IllegalArgumentException {
-        ArgumentChecks.ensureNonEmpty("pattern", pattern);
-        final int length = pattern.length();
-        final StringBuilder buffer = new StringBuilder(length);
-        boolean escape  = false;
-        boolean trim    = false;
-        String  prefix  = null;
-        String  regex   = null;
-        int separatorIndex = -1;
-scan:   for (int i=0; i<length; i++) {
-            final char c = pattern.charAt(i);
-            switch (c) {
-                case '\uFFFF': { // This "character" is reserved.
-                    prefix = null;
-                    break scan; // This will cause IllegalArgumentException to be thrown.
-                }
-                case '\\': {
-                    if (i != separatorIndex) {
-                        if (escape) break;
-                        escape = true;
-                    }
-                    continue;
-                }
-                case '?': {
-                    if (i != 0) {
-                        prefix = null;
-                        break scan;
-                    }
-                    trim = true;
-                    continue;
-                }
-                case '[': {
-                    if (escape) break;
-                    if (i != separatorIndex) {
-                        if (separatorIndex >= 0) {
-                            prefix = null;
-                            break scan; // This will cause IllegalArgumentException to be thrown.
-                        }
-                        separatorIndex = i+1;
-                    }
-                    continue;
-                }
-                case ']': {
-                    if (escape) break;
-                    switch (i - separatorIndex) {
-                        case 0:  continue;
-                        case 1:  prefix = buffer.toString(); buffer.setLength(0); continue;
-                        default: prefix = null; break scan;
-                    }
-                }
-                case '/': {
-                    if (escape) break;
-                    regex = pattern.substring(i+1);
-                    break scan;
-                }
-            }
-            if (i != separatorIndex) {
-                buffer.append(c);
-            }
-        }
-        if (prefix == null) {
-            throw new IllegalArgumentException(Errors.format(
-                    Errors.Keys.IllegalFormatPatternForClass_2, TreeTable.class, pattern));
-        }
-        /*
-         * Finally store the result. The parsing pattern must be first because the call to
-         * Pattern.compile(regex) may thrown PatternSyntaxException. In such case, we want
-         * it to happen before we modified anything else.
-         */
-        if (regex != null) {
-            parsePattern = Pattern.compile(regex);
-            isParsePatternDefined = true;
-        } else {
-            parsePattern = null;
-            isParsePatternDefined = false;
-        }
-        omitTrailingNulls = trim;
-        separatorPrefix   = prefix;
-        separatorSuffix   = buffer.toString();
-        columnSeparator   = pattern.charAt(separatorIndex);
-    }
-
-    /**
-     * Returns the current line separator. The default value is system-dependent.
-     *
-     * @return The current line separator.
-     */
-    public String getLineSeparator() {
-        return lineSeparator;
-    }
-
-    /**
-     * Sets the line separator.
-     *
-     * @param separator The new line separator.
-     */
-    public void setLineSeparator(final String separator) {
-        ArgumentChecks.ensureNonEmpty("separator", separator);
-        lineSeparator = separator;
-    }
-
-    /**
      * Returns the number of spaces to add on the left margin for each indentation level.
      * The default value is 4.
      *
@@ -508,13 +307,7 @@ scan:   for (int i=0; i<length; i++) {
      */
     @Override
     public TreeTable parse(final CharSequence text, final ParsePosition pos) throws ParseException {
-        if (parsePattern == null) {
-            parsePattern = Pattern.compile(
-                    Pattern.quote(separatorPrefix)
-                  + Pattern.quote(String.valueOf(columnSeparator)) + '*'
-                  + Pattern.quote(separatorSuffix));
-        }
-        final Matcher matcher = parsePattern.matcher(text);
+        final Matcher matcher   = getColumnSeparatorMatcher(text);
         final int length        = text.length();
         int indexOfLineStart    = pos.getIndex();
         int indentationLevel    = 0;                // Current index in the 'indentations' array.
@@ -711,18 +504,24 @@ scan:   for (int i=0; i<length; i++) {
     }
 
     /**
+     * Writes the column separator to the given appendable. This is a helper method for the
+     * {@link Writer} inner class,  defined here because it uses many protected fields from
+     * the superclass.  Accessing those fields from the inner class generate many synthetic
+     * methods, so we are better to define only one method here doing the work.
+     */
+    final void writeColumnSeparator(final Appendable out) throws IOException {
+        // We have a TableFormatter instance if and only if there is 2 or more columns.
+        ((TableFormatter) out.append(separatorPrefix)).nextColumn(columnSeparator);
+        out.append(separatorSuffix);
+    }
+
+    /**
      * Creates string representation of the node values. Tabulations are replaced by spaces,
      * and line feeds are replaced by the Pilcrow character. This is necessary in order to
      * avoid conflict with the characters expected by {@link TableFormatter}.
      */
     private final class Writer extends LineFormatter {
         /**
-         * For each indentation level, {@code true} if the previous levels are writing the last node.
-         * This array will growth as needed.
-         */
-        private boolean[] isLast;
-
-        /**
          * The columns to write.
          */
         private final TableColumn<?>[] columns;
@@ -738,14 +537,20 @@ scan:   for (int i=0; i<length; i++) {
         private final Object[] values;
 
         /**
+         * For each indentation level, {@code true} if the previous levels are writing the last node.
+         * This array will growth as needed.
+         */
+        private boolean[] isLast;
+
+        /**
          * Creates a new instance which will write in the given appendable.
          */
         Writer(final Appendable out, final TableColumn<?>[] columns) {
             super(columns.length >= 2 ? new TableFormatter(out, "") : out);
-            this.columns  = columns;
-            this.formats  = getFormats(columns, false);
-            this.values   = new Object[columns.length];
-            this.isLast   = new boolean[8];
+            this.columns = columns;
+            this.formats = getFormats(columns, false);
+            this.values  = new Object[columns.length];
+            this.isLast  = new boolean[8];
             setTabulationExpanded(true);
             setLineSeparator(" ¶ ");
         }
@@ -802,9 +607,7 @@ scan:   for (int i=0; i<length; i++) {
             }
             for (int i=0; i<=n; i++) {
                 if (i != 0) {
-                    // We have a TableFormatter instance if and only if there is 2 or more columns.
-                    ((TableFormatter) out.append(separatorPrefix)).nextColumn(columnSeparator);
-                    out.append(separatorSuffix);
+                    writeColumnSeparator(out);
                 }
                 formatValue(formats[i], values[i]);
                 clear();

Modified: sis/branches/JDK7/sis-utility/src/test/java/org/apache/sis/io/FormatterTestCase.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/sis-utility/src/test/java/org/apache/sis/io/FormatterTestCase.java?rev=1425402&r1=1425401&r2=1425402&view=diff
==============================================================================
--- sis/branches/JDK7/sis-utility/src/test/java/org/apache/sis/io/FormatterTestCase.java (original)
+++ sis/branches/JDK7/sis-utility/src/test/java/org/apache/sis/io/FormatterTestCase.java Sun Dec 23 04:03:29 2012
@@ -185,4 +185,15 @@ public abstract class FormatterTestCase 
     public void testSequencesWithUnicode() throws IOException {
         run("\u2028");
     }
+
+    /**
+     * Tests a few {@link java.io.Writer#write(String)} calls,
+     * with Unix line terminators in the sequences.
+     *
+     * @throws IOException Should never happen.
+     */
+    public void testSequencesToWriter() throws IOException {
+        formatter = IO.asWriter(formatter);
+        run("\n");
+    }
 }



Mime
View raw message