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.poi.hssf.contrib.view;
019:
020: import java.text.*;
021:
022: /**
023: * This class is used to format cells into their fractional format.
024: *
025: * I cant be 100% sure that the same fractional value will be displayed as in
026: * excel but then again it is a lossy formating mode anyway
027: *
028: * @author Jason Height
029: * @since 15 July 2002
030: */
031: public class SVFractionalFormat extends Format {
032: private short ONE_DIGIT = 1;
033: private short TWO_DIGIT = 2;
034: private short THREE_DIGIT = 3;
035: private short UNITS = 4;
036: private int units = 1;
037: private short mode = -1;
038:
039: /** Constructs a new FractionalFormatter
040: *
041: * The formatStr defines how the number will be formatted
042: * # ?/? Up to one digit
043: * # ??/?? Up to two digits
044: * # ???/??? Up to three digits
045: * # ?/2 In halves
046: * # ?/4 In quarters
047: * # ?/8 In eighths
048: * # ?/16 In sixteenths
049: * # ?/10 In tenths
050: * # ?/100 In hundredths
051: */
052: public SVFractionalFormat(String formatStr) {
053: if ("# ?/?".equals(formatStr))
054: mode = ONE_DIGIT;
055: else if ("# ??/??".equals(formatStr))
056: mode = TWO_DIGIT;
057: else if ("# ???/???".equals(formatStr))
058: mode = THREE_DIGIT;
059: else if ("# ?/2".equals(formatStr)) {
060: mode = UNITS;
061: units = 2;
062: } else if ("# ?/4".equals(formatStr)) {
063: mode = UNITS;
064: units = 4;
065: } else if ("# ?/8".equals(formatStr)) {
066: mode = UNITS;
067: units = 8;
068: } else if ("# ?/16".equals(formatStr)) {
069: mode = UNITS;
070: units = 16;
071: } else if ("# ?/10".equals(formatStr)) {
072: mode = UNITS;
073: units = 10;
074: } else if ("# ?/100".equals(formatStr)) {
075: mode = UNITS;
076: units = 100;
077: }
078: }
079:
080: /**
081: * Returns a fractional string representation of a double to a maximum denominator size
082: *
083: * This code has been translated to java from the following web page.
084: * http://www.codeproject.com/cpp/fraction.asp
085: * Originally coded in c++ By Dean Wyant dwyant@mindspring.com
086: * The code on the web page is freely available.
087: *
088: * @param f Description of the Parameter
089: * @param MaxDen Description of the Parameter
090: * @return Description of the Return Value
091: */
092: private String format(final double f, final int MaxDen) {
093: long Whole = (long) f;
094: int sign = 1;
095: if (f < 0) {
096: sign = -1;
097: }
098: double Precision = 0.00001;
099: double AllowedError = Precision;
100: double d = Math.abs(f);
101: d -= Whole;
102: double Frac = d;
103: double Diff = Frac;
104: long Num = 1;
105: long Den = 0;
106: long A = 0;
107: long B = 0;
108: long i = 0;
109: if (Frac > Precision) {
110: while (true) {
111: d = 1.0 / d;
112: i = (long) (d + Precision);
113: d -= i;
114: if (A > 0) {
115: Num = i * Num + B;
116: }
117: Den = (long) (Num / Frac + 0.5);
118: Diff = Math.abs((double) Num / Den - Frac);
119: if (Den > MaxDen) {
120: if (A > 0) {
121: Num = A;
122: Den = (long) (Num / Frac + 0.5);
123: Diff = Math.abs((double) Num / Den - Frac);
124: } else {
125: Den = MaxDen;
126: Num = 1;
127: Diff = Math.abs((double) Num / Den - Frac);
128: if (Diff > Frac) {
129: Num = 0;
130: Den = 1;
131: // Keeps final check below from adding 1 and keeps Den from being 0
132: Diff = Frac;
133: }
134: }
135: break;
136: }
137: if ((Diff <= AllowedError) || (d < Precision)) {
138: break;
139: }
140: Precision = AllowedError / Diff;
141: // This calcualtion of Precision does not always provide results within
142: // Allowed Error. It compensates for loss of significant digits that occurs.
143: // It helps to round the inprecise reciprocal values to i.
144: B = A;
145: A = Num;
146: }
147: }
148: if (Num == Den) {
149: Whole++;
150: Num = 0;
151: Den = 0;
152: } else if (Den == 0) {
153: Num = 0;
154: }
155: if (sign < 0) {
156: if (Whole == 0) {
157: Num = -Num;
158: } else {
159: Whole = -Whole;
160: }
161: }
162: return new StringBuffer().append(Whole).append(" ").append(Num)
163: .append("/").append(Den).toString();
164: }
165:
166: /** This method formats the double in the units specified.
167: * The usints could be any number but in this current implementation it is
168: * halves (2), quaters (4), eigths (8) etc
169: */
170: private String formatUnit(double f, int units) {
171: long Whole = (long) f;
172: f -= Whole;
173: long Num = Math.round(f * units);
174:
175: return new StringBuffer().append(Whole).append(" ").append(Num)
176: .append("/").append(units).toString();
177: }
178:
179: public final String format(double val) {
180: if (mode == ONE_DIGIT) {
181: return format(val, 9);
182: } else if (mode == TWO_DIGIT) {
183: return format(val, 99);
184: } else if (mode == THREE_DIGIT) {
185: return format(val, 999);
186: } else if (mode == UNITS) {
187: return formatUnit(val, units);
188: }
189: throw new RuntimeException("Unexpected Case");
190: }
191:
192: public StringBuffer format(Object obj, StringBuffer toAppendTo,
193: FieldPosition pos) {
194: if (obj instanceof Number) {
195: toAppendTo.append(format(((Number) obj).doubleValue()));
196: return toAppendTo;
197: } else
198: throw new IllegalArgumentException(
199: "Can only handle Numbers");
200: }
201:
202: public Object parseObject(String source, ParsePosition status) {
203: //JMH TBD
204: return null;
205: }
206:
207: public Object parseObject(String source) throws ParseException {
208: //JMH TBD
209: return null;
210: }
211:
212: public Object clone() {
213: //JMH TBD
214: return null;
215: }
216:
217: }
|