    001    /*
    002     * Licensed to the Apache Software Foundation (ASF) under one or more
    003     * contributor license agreements.  See the NOTICE file distributed with
    004     * this work for additional information regarding copyright ownership.
    005     * The ASF licenses this file to You under the Apache License, Version 2.0
    006     * (the "License"); you may not use this file except in compliance with
    007     * the License.  You may obtain a copy of the License at
    008     *
    009     *      http://www.apache.org/licenses/LICENSE-2.0
    010     *
    011     * Unless required by applicable law or agreed to in writing, software
    012     * distributed under the License is distributed on an "AS IS" BASIS,
    013     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    014     * See the License for the specific language governing permissions and
    015     * limitations under the License.
    016     */
    017
    018    package org.apache.commons.math3.fraction;
    019
    020    import java.io.Serializable;
    021    import java.text.FieldPosition;
    022    import java.text.NumberFormat;
    023    import java.text.ParsePosition;
    024    import java.util.Locale;
    025
    026    import org.apache.commons.math3.exception.NullArgumentException;
    027    import org.apache.commons.math3.exception.util.LocalizedFormats;
    028
    029    /**
    030     * Common part shared by both {@link FractionFormat} and {@link BigFractionFormat}.
    031     * @version $Id: AbstractFormat.java 1416643 2012-12-03 19:37:14Z tn $
    032     * @since 2.0
    033     */
    034    public abstract class AbstractFormat extends NumberFormat implements Serializable {
    035
    036        /** Serializable version identifier. */
    037        private static final long serialVersionUID = -6981118387974191891L;
    038
    039        /** The format used for the denominator. */
    040        private NumberFormat denominatorFormat;
    041
    042        /** The format used for the numerator. */
    043        private NumberFormat numeratorFormat;
    044
    045        /**
    046         * Create an improper formatting instance with the default number format
    047         * for the numerator and denominator.
    048         */
    049        protected AbstractFormat() {
    050            this(getDefaultNumberFormat());
    051        }
    052
    053        /**
    054         * Create an improper formatting instance with a custom number format for
    055         * both the numerator and denominator.
    056         * @param format the custom format for both the numerator and denominator.
    057         */
    058        protected AbstractFormat(final NumberFormat format) {
    059            this(format, (NumberFormat) format.clone());
    060        }
    061
    062        /**
    063         * Create an improper formatting instance with a custom number format for
    064         * the numerator and a custom number format for the denominator.
    065         * @param numeratorFormat the custom format for the numerator.
    066         * @param denominatorFormat the custom format for the denominator.
    067         */
    068        protected AbstractFormat(final NumberFormat numeratorFormat,
    069                                 final NumberFormat denominatorFormat) {
    070            this.numeratorFormat   = numeratorFormat;
    071            this.denominatorFormat = denominatorFormat;
    072        }
    073
    074        /**
    075         * Create a default number format.  The default number format is based on
    076         * {@link NumberFormat#getNumberInstance(java.util.Locale)}. The only
    077         * customization is the maximum number of BigFraction digits, which is set to 0.
    078         * @return the default number format.
    079         */
    080        protected static NumberFormat getDefaultNumberFormat() {
    081            return getDefaultNumberFormat(Locale.getDefault());
    082        }
    083
    084        /**
    085         * Create a default number format.  The default number format is based on
    086         * {@link NumberFormat#getNumberInstance(java.util.Locale)}. The only
    087         * customization is the maximum number of BigFraction digits, which is set to 0.
    088         * @param locale the specific locale used by the format.
    089         * @return the default number format specific to the given locale.
    090         */
    091        protected static NumberFormat getDefaultNumberFormat(final Locale locale) {
    092            final NumberFormat nf = NumberFormat.getNumberInstance(locale);
    093            nf.setMaximumFractionDigits(0);
    094            nf.setParseIntegerOnly(true);
    095            return nf;
    096        }
    097
    098        /**
    099         * Access the denominator format.
    100         * @return the denominator format.
    101         */
    102        public NumberFormat getDenominatorFormat() {
    103            return denominatorFormat;
    104        }
    105
    106        /**
    107         * Access the numerator format.
    108         * @return the numerator format.
    109         */
    110        public NumberFormat getNumeratorFormat() {
    111            return numeratorFormat;
    112        }
    113
    114        /**
    115         * Modify the denominator format.
    116         * @param format the new denominator format value.
    117         * @throws NullArgumentException if {@code format} is {@code null}.
    118         */
    119        public void setDenominatorFormat(final NumberFormat format) {
    120            if (format == null) {
    121                throw new NullArgumentException(LocalizedFormats.DENOMINATOR_FORMAT);
    122            }
    123            this.denominatorFormat = format;
    124        }
    125
    126        /**
    127         * Modify the numerator format.
    128         * @param format the new numerator format value.
    129         * @throws NullArgumentException if {@code format} is {@code null}.
    130         */
    131        public void setNumeratorFormat(final NumberFormat format) {
    132            if (format == null) {
    133                throw new NullArgumentException(LocalizedFormats.NUMERATOR_FORMAT);
    134            }
    135            this.numeratorFormat = format;
    136        }
    137
    138        /**
    139         * Parses <code>source</code> until a non-whitespace character is found.
    140         * @param source the string to parse
    141         * @param pos input/output parsing parameter.  On output, <code>pos</code>
    142         *        holds the index of the next non-whitespace character.
    143         */
    144        protected static void parseAndIgnoreWhitespace(final String source,
    145                                                       final ParsePosition pos) {
    146            parseNextCharacter(source, pos);
    147            pos.setIndex(pos.getIndex() - 1);
    148        }
    149
    150        /**
    151         * Parses <code>source</code> until a non-whitespace character is found.
    152         * @param source the string to parse
    153         * @param pos input/output parsing parameter.
    154         * @return the first non-whitespace character.
    155         */
    156        protected static char parseNextCharacter(final String source,
    157                                                 final ParsePosition pos) {
    158             int index = pos.getIndex();
    159             final int n = source.length();
    160             char ret = 0;
    161
    162             if (index < n) {
    163                 char c;
    164                 do {
    165                     c = source.charAt(index++);
    166                 } while (Character.isWhitespace(c) && index < n);
    167                 pos.setIndex(index);
    168
    169                 if (index < n) {
    170                     ret = c;
    171                 }
    172             }
    173
    174             return ret;
    175        }
    176
    177        /**
    178         * Formats a double value as a fraction and appends the result to a StringBuffer.
    179         *
    180         * @param value the double value to format
    181         * @param buffer StringBuffer to append to
    182         * @param position On input: an alignment field, if desired. On output: the
    183         *            offsets of the alignment field
    184         * @return a reference to the appended buffer
    185         * @see #format(Object, StringBuffer, FieldPosition)
    186         */
    187        @Override
    188        public StringBuffer format(final double value,
    189                                   final StringBuffer buffer, final FieldPosition position) {
    190            return format(Double.valueOf(value), buffer, position);
    191        }
    192
    193
    194        /**
    195         * Formats a long value as a fraction and appends the result to a StringBuffer.
    196         *
    197         * @param value the long value to format
    198         * @param buffer StringBuffer to append to
    199         * @param position On input: an alignment field, if desired. On output: the
    200         *            offsets of the alignment field
    201         * @return a reference to the appended buffer
    202         * @see #format(Object, StringBuffer, FieldPosition)
    203         */
    204        @Override
    205        public StringBuffer format(final long value,
    206                                   final StringBuffer buffer, final FieldPosition position) {
    207            return format(Long.valueOf(value), buffer, position);
    208        }
    209
    210    }