diff options
Diffstat (limited to 'kspread/kspread_numformat.cpp')
-rw-r--r-- | kspread/kspread_numformat.cpp | 1634 |
1 files changed, 1634 insertions, 0 deletions
diff --git a/kspread/kspread_numformat.cpp b/kspread/kspread_numformat.cpp new file mode 100644 index 000000000..e3a0bee7a --- /dev/null +++ b/kspread/kspread_numformat.cpp @@ -0,0 +1,1634 @@ +/* This file is part of the KDE project + Copyright (C) 2003 Norbert Andres, nandres@web.de + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +/* +The only function visible from the outside is formatNumber, whose +implementation is at the very bottom of this file. Its prototype +is declared in kspread_util.h. However, it is not used anywhere. +TODO: Find out whether it is supposed to be used instead of +something else (locale()->formatNumber() maybe?) and either use it +or get rid of it. +Tomas +*/ +#include <ctype.h> +#include <math.h> + +#include <tqdatetime.h> +#include <tqmap.h> +#include <tqstring.h> + +#include <kcalendarsystem.h> +#include <tdelocale.h> + +#include "kspread_util.h" +#include "kspread_value.h" + +namespace NumFormat_Local +{ + enum { Unknown, TimeDate, Number, Scientific, Fraction } Type; + + TQString g_Monday; + TQString g_Tuesday; + TQString g_Wednesday; + TQString g_Thursday; + TQString g_Friday; + TQString g_Saturday; + TQString g_Sunday; + TQString g_Mon; + TQString g_Tue; + TQString g_Wed; + TQString g_Thu; + TQString g_Fri; + TQString g_Sat; + TQString g_Sun; + TQString g_January; + TQString g_February; + TQString g_March; + TQString g_April; + TQString g_MayL; + TQString g_June; + TQString g_July; + TQString g_August; + TQString g_September; + TQString g_October; + TQString g_November; + TQString g_December; + TQString g_Jan; + TQString g_Feb; + TQString g_Mar; + TQString g_Apr; + TQString g_May; + TQString g_Jun; + TQString g_Jul; + TQString g_Aug; + TQString g_Sep; + TQString g_Oct; + TQString g_Nov; + TQString g_Dec; + + struct DateTime + { + int year; + int month; + int day; + int hour; + int minute; + int second; + }; + + struct ConvertionInfo + { + DateTime * dt; + + int rightOpt; + int rightReq; + int leftReq; + int rightSpace; + int leftSpace; + int upReq; + + int reqCounter; + int reqFirst; + int optFirst; + + bool ampm; + + bool thSet; + bool showMinus; + bool negRed; + bool negBr; + TQString postfix; + TQString prefix; + }; + + class BaseFormat + { + public: + int type; + + TQString postfix; + TQString prefix; + }; + + class NumberFormat : public BaseFormat + { + public: + bool thSet; + bool showMinus; + bool negRed; + bool negBr; + int rightOpt; + int rightReq; + int leftReq; + int rightSpace; + int leftSpace; + }; + + class FractionFormat : public BaseFormat + { + public: + bool thSet; + bool showMinus; + bool negRed; + bool negBr; + int optFirst; + int reqFirst; + int reqCounter; + int fraction; + int fractionDigists; + }; + + class DateTimeFormat : public BaseFormat + { + public: + bool ampm; + TQString format; + }; + + class ScientificFormat : public BaseFormat + { + public: + bool thSet; + int leftReq; + int rightReq; + int rightOpt; + int upReq; + bool showMinus; + bool negRed; + bool negBr; + int rightSpace; + int leftSpace; + }; + + class FormatStore + { + public: + + int getType( TQString const & format, BaseFormat * f ) const + { + FormatMap::const_iterator iter = m_formats.find( format ); + if ( iter == m_formats.end() ) + { + f = 0; + return -1; + } + + f = iter.data(); + return f->type; + } + + void addFraction( TQString const & format, FractionFormat * f ) + { + m_formats.insert( format, f ); + } + + void addNumber( TQString const & format, NumberFormat * n ) + { + m_formats.insert( format, n ); + } + + void addDateTime( TQString const & format, DateTimeFormat * d ) + { + m_formats.insert( format, d ); + } + + void addScientific( TQString const & format, ScientificFormat * d ) + { + m_formats.insert( format, d ); + } + + private: + class FormatMap : public TQMap<TQString, BaseFormat *> {}; + FormatMap m_formats; + }; + + TQChar g_dcSymbol; + TQChar g_thSymbol; + TQChar g_posSymbol; + TQChar g_negSymbol; + DateTime g_dateTime; + ConvertionInfo g_convertionInfo; + bool g_init = false; + + FormatStore g_formatStore; +} + +using namespace NumFormat_Local; +using namespace KSpread; + +void resetGlobals() +{ + g_convertionInfo.dt = 0; + g_convertionInfo.thSet = false; + g_convertionInfo.showMinus = true; + g_convertionInfo.negRed = false; + g_convertionInfo.negBr = false; + g_convertionInfo.reqCounter = 0; + g_convertionInfo.reqFirst = 0; + g_convertionInfo.prefix = ""; + g_convertionInfo.postfix = ""; + g_convertionInfo.rightOpt = 0; + g_convertionInfo.rightReq = 0; + g_convertionInfo.leftReq = 0; + g_convertionInfo.rightSpace = 0; + g_convertionInfo.leftSpace = 0; + g_convertionInfo.optFirst = 0; + g_convertionInfo.upReq = 0; + g_convertionInfo.ampm = false; +} + +void initGlobals( TDELocale const * const locale ) +{ + g_Monday = locale->calendar()->weekDayName( 1, false ); + g_Tuesday = locale->calendar()->weekDayName( 2, false ); + g_Wednesday = locale->calendar()->weekDayName( 3, false ); + g_Thursday = locale->calendar()->weekDayName( 4, false ); + g_Friday = locale->calendar()->weekDayName( 5, false ); + g_Saturday = locale->calendar()->weekDayName( 6, false ); + g_Sunday = locale->calendar()->weekDayName( 7, false ); + g_Mon = locale->calendar()->weekDayName( 1, true ); + g_Tue = locale->calendar()->weekDayName( 2, true ); + g_Wed = locale->calendar()->weekDayName( 3, true ); + g_Thu = locale->calendar()->weekDayName( 4, true ); + g_Fri = locale->calendar()->weekDayName( 5, true ); + g_Sat = locale->calendar()->weekDayName( 6, true ); + g_Sun = locale->calendar()->weekDayName( 7, true ); + g_January = locale->calendar()->monthName( 1, 2005, false ); + g_February = locale->calendar()->monthName( 2, 2005, false ); + g_March = locale->calendar()->monthName( 3, 2005, false ); + g_April = locale->calendar()->monthName( 4, 2005, false ); + g_MayL = locale->calendar()->monthName( 5, 2005, false ); + g_June = locale->calendar()->monthName( 6, 2005, false ); + g_July = locale->calendar()->monthName( 7, 2005, false ); + g_August = locale->calendar()->monthName( 8, 2005, false ); + g_September = locale->calendar()->monthName( 9, 2005, false ); + g_October = locale->calendar()->monthName( 10, 2005, false ); + g_November = locale->calendar()->monthName( 11, 2005, false ); + g_December = locale->calendar()->monthName( 12, 2005, false ); + g_Jan = locale->calendar()->monthName( 1, 2005, true ); + g_Feb = locale->calendar()->monthName( 2, 2005, true ); + g_Mar = locale->calendar()->monthName( 3, 2005, true ); + g_Apr = locale->calendar()->monthName( 4, 2005, true ); + g_May = locale->calendar()->monthName( 5, 2005, true ); + g_Jun = locale->calendar()->monthName( 6, 2005, true ); + g_Jul = locale->calendar()->monthName( 7, 2005, true ); + g_Aug = locale->calendar()->monthName( 8, 2005, true ); + g_Sep = locale->calendar()->monthName( 9, 2005, true ); + g_Oct = locale->calendar()->monthName( 10, 2005, true ); + g_Nov = locale->calendar()->monthName( 11, 2005, true ); + g_Dec = locale->calendar()->monthName( 12, 2005, true ); + + g_dcSymbol = locale->decimalSymbol()[0]; + g_thSymbol = locale->thousandsSeparator()[0]; + g_posSymbol = locale->positiveSign()[0]; + g_negSymbol = locale->negativeSign()[0]; + + g_init = true; +} + +void convertDateTime( Value const & value ) +{ + TQDateTime dt( value.asDateTime() ); + TQDate d( dt.date() ); + TQTime t( dt.time() ); + + g_dateTime.year = d.year(); + g_dateTime.month = d.month(); + g_dateTime.day = d.day(); + g_dateTime.hour = t.hour(); + g_dateTime.minute = t.minute(); + g_dateTime.second = t.second(); + + g_convertionInfo.dt = &g_dateTime; +} + +void parseNegativePart( TQString & format, int i, + int l, bool acceptDigits ) +{ + g_convertionInfo.showMinus = false; + g_convertionInfo.negRed = false; + g_convertionInfo.negRed = false; + bool end = false; + + while ( i < l && !end) + { + TQChar c( format[i] ); + switch( c ) + { + case '-': + g_convertionInfo.showMinus = true; + break; + case '(': + g_convertionInfo.negBr = true; + break; + case '[': + if ( format.find( "[red]", i, false ) == i ) + { + g_convertionInfo.negRed = true; + i += 5; + } + break; + default: + end = true; + } + ++i; + } + + // find postfix + bool quote = false; + for ( int j = l - 1; j > i; --j ) + { + if ( format[j] == '"' ) + { + quote = !quote; + continue; + } + + if ( !quote && ( format[j] == '0' || format[j] != '?' + || format[j] != '#' + || ( format[j].isDigit() && acceptDigits ) ) ) + { + g_convertionInfo.postfix = format.mid( j + 1 ); + format.remove( (unsigned int) (j + 1), (unsigned int) (l - j) ); + break; + } + } + + int p = g_convertionInfo.postfix.find( '"' ); + while ( p != -1 ) + { + g_convertionInfo.postfix.remove( p, 1 ); + + p = g_convertionInfo.postfix.find( '"', p ); + } +} + +void createNumberStruct( BaseFormat * data, TQString const & format, bool insert ) +{ + NumberFormat * d = new NumberFormat(); + d->type = Number; + d->prefix = g_convertionInfo.prefix; + d->postfix = g_convertionInfo.postfix; + d->thSet = g_convertionInfo.thSet; + d->showMinus = g_convertionInfo.showMinus; + d->negRed = g_convertionInfo.negRed; + d->negBr = g_convertionInfo.negBr; + d->rightOpt = g_convertionInfo.rightOpt; + d->rightReq = g_convertionInfo.rightReq; + d->leftReq = g_convertionInfo.leftReq; + d->rightSpace = g_convertionInfo.rightSpace; + d->leftSpace = g_convertionInfo.leftSpace; + + if ( insert ) + g_formatStore.addNumber( format, d ); + data = d; +} + +void createDateTimeStruct( BaseFormat * data, TQString const & format, + TQString const & optFormat, bool insert ) +{ + DateTimeFormat * d = new DateTimeFormat(); + d->type = TimeDate; + d->prefix = g_convertionInfo.prefix; + d->postfix = g_convertionInfo.postfix; + d->ampm = g_convertionInfo.ampm; + d->format = optFormat; + + if ( insert ) + g_formatStore.addDateTime( format, d ); + data = d; +} + +void createScientificStruct( BaseFormat * data, TQString const & format, bool insert ) +{ + ScientificFormat * d = new ScientificFormat(); + d->type = Scientific; + d->prefix = g_convertionInfo.prefix; + d->postfix = g_convertionInfo.postfix; + d->thSet = g_convertionInfo.thSet; + d->showMinus = g_convertionInfo.showMinus; + d->negRed = g_convertionInfo.negRed; + d->negBr = g_convertionInfo.negBr; + d->rightOpt = g_convertionInfo.rightOpt; + d->rightReq = g_convertionInfo.rightReq; + d->leftReq = g_convertionInfo.leftReq; + d->rightSpace = g_convertionInfo.rightSpace; + d->leftSpace = g_convertionInfo.leftSpace; + d->upReq = g_convertionInfo.upReq; + + if ( insert ) + g_formatStore.addScientific( format, d ); + data = d; +} + + +int doPreScan( TQString & format, TQString const & formatBack, TDELocale const * const /* locale */, + bool insert, BaseFormat * data ) +{ + int type = g_formatStore.getType( format, data ); + if ( data != 0 ) + return type; + + resetGlobals(); + + int l = format.length(); + int i = 0; + int thFound = false; + int leftReq = 0; + int leftOpt = 0; + int rightOpt = 0; + int spaceInNum = -1; + bool dcSeen = false; + bool endFixed = false; + + FractionFormat * df = 0; + int f = 0; + int d = 0; + int len = 0; + int n = 0; + bool ok = false; + TQString frac; + + while ( i < l ) + { + TQString s; + if ( endFixed ) + { + g_convertionInfo.postfix += format.mid( i ); + format.remove( i, l - i ); + break; + } + TQChar ch( format[i] ); + switch( ch ) + { + case '[': + if ( type == Number ) + endFixed = true; + + if ( format[ i + 1] == '$' ) + { + i += 2; + bool found = false; + while ( i < l && format[i] != ']' ) + { + if ( format[i] == '-' ) + found = true; + if ( !found ) + { + if ( !endFixed ) + g_convertionInfo.prefix += format[i]; + else + g_convertionInfo.postfix += format[i]; + format.remove( i, 1 ); + --i; --l; + } + ++i; + } + } + else + { + if ( i + 1 >= l ) + { + g_convertionInfo.postfix += '['; + format.remove( i, 1 ); + --l; --i; + } + else + if ( ( format[ i + 1].lower() != 's' ) + && ( format[ i + 1].lower() != 'm' ) + && ( format[ i + 1].lower() != 'h' ) ) + { + // strange! + + if ( endFixed ) + g_convertionInfo.postfix += format[i]; + else + g_convertionInfo.prefix += format[i]; + format.remove( i, 1 ); + --l; --i; + } + else + { + type = TimeDate; + ++i; + TQChar c( format[i] ); + ++i; + while ( i < l && format[i] != ']' ) + { + if ( format[i] != c ) + { + format.remove( i, 1 ); + --l; --i; + break; + } + ++i; + } + } + } + break; + + case '¤': + case '$': + case '¥': + case '£': + case '%': + if ( type == Number ) + endFixed = true; + + if ( endFixed ) + g_convertionInfo.postfix += format[i]; + else + g_convertionInfo.prefix += format[i]; + format.remove( i, 1 ); + --i; --l; + break; + + case '#': + type = Number; + if ( !dcSeen && leftReq > 0 ) + { // 00##.00 <= remove the '#' + format.remove( i, 1 ); + --l; --i; + } + if ( !dcSeen ) + ++leftOpt; + else + ++g_convertionInfo.rightOpt; + break; + + case '0': + if ( spaceInNum > 0 ) + { // for fractions + ++g_convertionInfo.reqCounter; + break; + } + type = Number; + if ( !dcSeen && rightOpt > 0 ) + { // 00##.##00 <= remove the '0' + format.remove( i, 1 ); + --l; --i; + } + if ( !dcSeen ) + ++g_convertionInfo.leftReq; + else + ++g_convertionInfo.rightReq; + break; + + case '/': + if ( ( i + 1 < l ) && ( format[i + 1] == ' ' ) ) + ++i; + while ( i < l ) + { + if ( format[i] != '?' && !format[i].isDigit() && format[i] != '#' ) + { + g_convertionInfo.postfix = format.mid(i); + format.remove( i, l - i ); + break; + } + else + { + ++d; + frac += format[i]; + } + ++i; + } + if ( i < l ) + { + if ( format[i] == ';' ) + { + ++i; + parseNegativePart( format, i, l, true ); + } + else + if ( i + 3 < l ) + { + if ( ( format[i + 1] == ')' ) && ( format[i + 2] == ';' ) ) + { + i += 3; + parseNegativePart( format, i, l, true ); + } + } + } + + ok = false; + f = frac.toInt( &ok ); + + df = new FractionFormat(); + if ( ok ) + df->fraction = f; + else + df->fraction = -1; + df->type = Fraction; + df->thSet = g_convertionInfo.thSet; + df->showMinus = g_convertionInfo.showMinus; + df->negRed = g_convertionInfo.negRed; + df->negBr = g_convertionInfo.negBr; + df->fractionDigists = d; + df->reqCounter = g_convertionInfo.reqCounter; + df->reqFirst = g_convertionInfo.reqFirst; + df->prefix = g_convertionInfo.prefix; + df->postfix = g_convertionInfo.postfix; + + if ( insert ) + g_formatStore.addFraction( formatBack, df ); + data = df; + + return Fraction; + break; + + case ',': + if ( type == Unknown ) + { + g_convertionInfo.prefix += ','; + } + else if ( type == Number ) + { + if ( dcSeen ) + { + g_convertionInfo.postfix += ','; + format.remove( i, 1 ); + --i; --l; + } + else + { + if ( thFound ) + { + format.remove( i, 1 ); + --l; --i; + } + else + thFound = true; + } + } + + case '.': // decimal point + if ( type == Unknown ) + { + int j = i + 1; + if ( ( j < l ) + && ( format[j] == '0' || format[j] == '#' ) ) + { + type = Number; + dcSeen = true; + } + else + { + if ( j == l ) + g_convertionInfo.postfix += '.'; + else + g_convertionInfo.prefix += '.'; + format.remove( i, 1 ); + --i; --l; + } + } + else if ( type == Number ) + { + dcSeen = true; + } + break; + + case '*': + break; + + case '"': + n = i; + ++i; + while ( i < l && format[i] != '"' ) + { + s += format[i]; + ++i; + } + if ( type == Unknown ) + g_convertionInfo.prefix += s; + else + { + g_convertionInfo.postfix += s; + } + len = s.length(); + format.remove( i, len ); + i -= len; l -= len; + break; + + case '_': + if ( type == Number ) + { + bool pr = false; + if ( i + 3 < l ) + { + if ( ( format[i + 1] != ')' ) || ( format[i + 2] != ';' ) ) + pr = true; + else + { + i += 3; + parseNegativePart( format, i, l, false ); + + createNumberStruct( data, formatBack, insert ); + + return Number; + } + } + + if ( pr ) + { + g_convertionInfo.postfix += format.mid( i ); + format.remove( i, l - i ); + + createNumberStruct( data, formatBack, insert ); + + return Number; + } + } + break; + + case ';': + if ( type == Unknown ) + { + g_convertionInfo.postfix += ';'; + format.remove( i, 1 ); + --i; --l; + } + else + { + if ( type == Number ) + { + ++i; + parseNegativePart( format, i, l, false ); + + createNumberStruct( data, formatBack, insert ); + + return Number; + } + else + if ( type == Scientific ) + { + ++i; + parseNegativePart( format, i, l, false ); + + createScientificStruct( data, formatBack, insert ); + + return Scientific; + } + } + + case ' ': + if ( type == Number ) + { + g_convertionInfo.optFirst = (leftOpt > 0 ? leftOpt : 0); + g_convertionInfo.reqFirst = (leftReq > 0 ? leftReq : 0); + + spaceInNum = i; + g_convertionInfo.postfix += ' '; + } + else if ( type == Unknown ) + { + g_convertionInfo.prefix += ' '; + format.remove( i, 1 ); + --i; --l; + } + break; + + case 'A': + case 'a': + if ( type == TimeDate || type == Unknown ) + { + if ( ( i + 1 < l ) && ( format[i + 1].lower() == 'm' ) ) + { + g_convertionInfo.ampm = true; + ++i; + if ( ( i + 3 < l ) && ( format[i + 1] == '/' ) + && ( format[i + 2].lower() == 'p' ) + && ( format[i + 3].lower() == 'm' ) ) + { + i += 3; + } + } + else if ( type == Unknown ) + { + g_convertionInfo.prefix += format[i]; + format.remove( i, 1 ); + --i; --l; + } + } + else + { + if ( !endFixed ) + endFixed = true; + g_convertionInfo.postfix += format[i]; + format.remove( i, 1 ); + --i; --l; + } + break; + + case 'P': + case 'p': + if ( type == TimeDate || type == Unknown ) + { + if ( ( i + 1 < l ) && ( format[i + 1].lower() == 'm' ) ) + { + g_convertionInfo.ampm = true; + i += 1; + } + else if ( type == Unknown ) + { + g_convertionInfo.prefix += format[i]; + format.remove( i, 1 ); + --i; --l; + } + } + else + { + if ( !endFixed ) + endFixed = true; + g_convertionInfo.postfix += format[i]; + format.remove( i, 1 ); + --i; --l; + } + break; + + case 'M': + case 'm': + if ( type == Unknown ) + type = TimeDate; + else if ( type != TimeDate ) + endFixed = true; + break; + + case 'S': + case 's': + case 'H': + case 'h': + if ( type != Unknown && type != TimeDate ) + endFixed = true; + else + type = TimeDate; + break; + + case 'D': + case 'd': + case 'Y': + case 'y': + if ( type != Unknown && type != TimeDate ) + endFixed = true; + else + type = TimeDate; + break; + + default: + if ( type == Unknown ) + { + g_convertionInfo.prefix += format[i]; + format.remove( i, 1 ); + --i; --l; + } + else if ( type == Number || type == Scientific + || type == Fraction ) + { + endFixed = true; + g_convertionInfo.postfix += format[i]; + format.remove( i, 1 ); + --l; --i; + } + } + + ++i; + } + + if ( type == Number ) + createNumberStruct( data, formatBack, insert ); + else if ( type == TimeDate ) + createDateTimeStruct( data, formatBack, format, insert ); + else if ( type == Scientific ) + createScientificStruct( data, formatBack, insert ); + + return type; +} + +void createNumber( TQString & result, Value const & value, + TQString const & /*format*/, bool & setRed, + NumberFormat const * const data ) +{ + int prec = data->rightReq + data->rightOpt; + double num = value.asFloat(); + double m[] = { 1, 10, 100, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 1e10 }; + double mm = ( prec > 10 ) ? pow( 10.0, prec ) : m[prec]; + + num = floor( fabs( num ) * mm + 0.5 ) / mm; + + bool negative = ( num < 0 ? true : false ); + double nnum = ( negative ? -num : num ); + + result = TQString::number( nnum, 'f', prec ); + + int pos = result.find( '.' ); + if ( pos >= 0 ) + { + result = result.replace( pos, 1, g_dcSymbol ); + + // remove '0' from the end if not required + if ( data->rightOpt > 0 ) + { + int i = result.length() - 1; // index + int n = result.length() - data->rightOpt; + + for ( ; i > n; --i ) + { + if ( result[i] != '0' ) + break; + } + result = result.left( i + 1 ); //length + + if ( i == pos ) // just decimal point + result = result.remove( i, 1 ); + } + + // prepend '0' if wanted + while ( data->leftReq > pos ) + { + result.prepend( '0' ); + ++pos; + } + + // put in thousand symbol if wanted + if ( data->thSet && pos > 3 ) + { + int l = pos - 3; + while ( 0 < l ) + { + result.insert( l, g_thSymbol ); + l -= 3; + } + } + } + + if ( data->leftSpace > 0 ) + { + for ( int i = 0; i < data->leftSpace; ++i ) + result.prepend( ' ' ); + } + if ( data->rightSpace > 0 ) + { + for ( int i = 0; i < data->rightSpace; ++i ) + result.append( ' ' ); + } + + if ( negative ) + { + if ( data->showMinus ) + result.prepend( g_negSymbol ); + + if ( data->negBr ) + { + result.prepend( '(' ); + result.append( ')' ); + } + + if ( data->negRed ) + setRed = true; + } + + result.prepend( data->prefix ); + result.append( data->postfix ); +} + +void createFraction( TQString & result, Value const & value, + TQString const & /*format*/, bool & setRed, + FractionFormat const * const data ) +{ + double num = value.asFloat(); + + bool negative = ( num < 0 ? true : false ); + + double fnum = floor( negative ? -num : num ); + + double dec = num - fnum; + double fraction; + int index = 0; + + if ( data->fraction <= 0 ) + { + // #,### ?/??? + double nnum = ( negative ? -num : num ); + double precision, denominator, numerator; + int index = 2 + data->fractionDigists; + int limit = 9; + if ( data->fractionDigists == 2 ) + limit += 90; + if ( data->fractionDigists >= 3 ) + limit += 990; + + do + { + double val1 = nnum; + double val2 = rint( nnum ); + double inter2 = 1; + double inter4, p, q; + inter4 = p = q = 0.0; + + precision = pow( 10.0, - index ); + numerator = val2; + denominator = 1; + + while ( fabs( numerator / denominator - nnum ) > precision ) + { + val1 = (1 / ( val1 - val2 ) ); + val2 = rint( val1 ); + p = val2 * numerator + inter2; + q = val2 * denominator + inter4; + inter2 = numerator; + inter4 = denominator; + + numerator = p; + denominator = q; + } + --index; + } while ( fabs( denominator ) > limit ); + + index = (int) fabs( numerator ); + fraction = (int) fabs( denominator ); + } + else + { + // # #/4 + fraction = data->fraction; + + double calc = 0.0; + double diff = dec; + double d; + for ( int i = 1; i <= fraction; ++i ) + { + calc = i * 1.0 / index; + d = fabs( dec - calc ); + if ( d < diff ) + { + index = i; + diff = d; + } + } + } + + // ? index/fraction + + // 2.25: #/4 => 9/4 + if ( data->optFirst == 0 && data->reqFirst == 0 && fnum > 0 ) + index += (int) (fnum * fraction); + + TQString frac; + TQString left; + if ( index > 0 ) + { + TQString numerator; + TQString denominator; + + numerator = TQString::number( index ); + int n = numerator.length() - data->reqCounter; + for ( int i = 0; i < n; ++i ) + { + numerator.prepend( '0' ); + } + + denominator = TQString::number( fraction ); + frac = numerator + '/' + denominator; + } + + if ( data->optFirst > 0 || data->reqFirst > 0 ) + { + if ( fnum == 0 && data->reqFirst > 0 ) + { + for ( int i = 0; i < data->reqFirst; ++i ) + left += '0'; + } + else if ( fnum > 0 ) + { + left = TQString::number( fnum ); + int n = data->reqFirst - left.length(); + if ( n > 0 ) + { + for ( int i = 0; i < n; ++i ) + { + left.prepend( '0' ); + } + } + } + } + + if ( data->thSet ) + { + int l = left.length() - 3; + while ( 0 < l ) + { + left.insert( l, g_thSymbol ); + l -= 3; + } + } + + left = left + ' ' + frac; + + if ( negative ) + { + if ( data->showMinus ) + left.prepend( g_negSymbol ); + + if ( data->negBr ) + { + left.prepend( '(' ); + left.append( ')' ); + } + + if ( data->negRed ) + setRed = true; + } + + result = left; +} + +void createScientific( TQString & result, Value const & value, + TQString const & /*format*/, bool & setRed, + ScientificFormat const * const data ) +{ + double num = value.asFloat(); + + bool negative = ( num < 0 ? true : false ); + double nnum = ( negative ? -num : num ); + + result = TQString::number( nnum, 'E', data->rightReq + data->rightOpt ); + + int pos = result.find( '.' ); + if ( pos >= 0 ) + { + result = result.replace( pos, 1, g_dcSymbol ); + if ( data->rightOpt > 0 ) + { + int i = result.find( 'E', pos, false ) - 1; + int n = result.length() - data->rightOpt; + + if ( i > 0 ) + { + int rem = 0; + for ( ; i > n; --i ) + { + if ( result[i] != '0' ) + break; + else + ++rem; + } + result = result.remove( i + 1, rem ); + } + } + + while ( data->leftReq > pos ) + { + result.prepend( '0' ); + ++pos; + } + + if ( data->thSet && pos > 3 ) + { + int l = pos - 3; + while ( 0 < l ) + { + result.insert( l, g_thSymbol ); + l -= 3; + } + } + } + + if ( negative ) + { + if ( data->showMinus ) + result.prepend( g_negSymbol ); + + if ( data->negBr ) + { + result.prepend( '(' ); + result.append( ')' ); + } + + if ( data->negRed ) + setRed = true; + } + + result.prepend( data->prefix ); + result.append( data->postfix ); +} + +void appendAMPM( TQString & result, Value const & value ) +{ + if ( !g_convertionInfo.dt ) + convertDateTime( value ); + + int hour = g_convertionInfo.dt->hour; + if ( hour > 12 ) + result.append( i18n("PM") ); + else + result.append( i18n("AM") ); +} + +void appendHour( TQString & result, Value const & value, + int digits, bool elapsed, bool ampm ) +{ + if ( !g_convertionInfo.dt ) + convertDateTime( value ); + + int hour = g_convertionInfo.dt->hour; + if ( elapsed ) + { + TQDate d1( g_convertionInfo.dt->year, g_convertionInfo.dt->month, g_convertionInfo.dt->day ); + TQDate d2( 1900, 1, 1 ); + hour += ( d2.daysTo( d1 ) * 24 ); + } + if ( hour < 10 && digits == 2 ) + result += '0'; + else + if ( hour > 12 && ampm ) + { + hour -= 12; + if ( digits == 2 && hour < 10 ) + result += '0'; + } + + result += TQString::number( hour ); +} + +void appendMinutes( TQString & result, Value const & value, + int digits, bool elapsed ) +{ + if ( !g_convertionInfo.dt ) + convertDateTime( value ); + + int minute = g_convertionInfo.dt->minute; + if ( elapsed ) + { + TQDate d1( g_convertionInfo.dt->year, g_convertionInfo.dt->month, g_convertionInfo.dt->day ); + TQDate d2( 1900, 1, 1 ); + minute += ( d2.daysTo( d1 ) * 24 * 60 ); + } + if ( minute < 10 && digits == 2 ) + result += '0'; + + result += TQString::number( minute ); +} + +void appendSecond( TQString & result, Value const & value, + int digits, bool elapsed ) +{ + if ( !g_convertionInfo.dt ) + convertDateTime( value ); + + int second = g_convertionInfo.dt->second; + if ( elapsed ) + { + TQDate d1( g_convertionInfo.dt->year, g_convertionInfo.dt->month, g_convertionInfo.dt->day ); + TQDate d2( 1900, 1, 1 ); + second += ( d2.daysTo( d1 ) * 24 * 60 * 60 ); + } + if ( second < 10 && digits == 2 ) + result += '0'; + + result += TQString::number( second ); +} + +void appendYear( TQString & result, Value const & value, + int digits ) +{ + if ( !g_convertionInfo.dt ) + convertDateTime( value ); + + int year = g_convertionInfo.dt->year; + if ( digits <= 2 ) + result += TQString::number( year ).right( 2 ); + else + result += TQString::number( year ); +} + +void appendMonth( TQString & result, Value const & value, + int digits ) +{ + if ( !g_convertionInfo.dt ) + convertDateTime( value ); + + int month = g_convertionInfo.dt->month; + if ( digits == 1 ) + result += TQString::number( month ); + else + if ( digits == 2 ) + { + if ( month < 10 ) + result += '0'; + + result += TQString::number( month ); + } + else + { + switch ( month ) + { + case 1: + result += ( digits != 3 ? g_January : g_Jan ); + break; + + case 2: + result += ( digits != 3 ? g_February : g_Feb ); + break; + + case 3: + result += ( digits != 3 ? g_March : g_Mar ); + break; + + case 4: + result += ( digits != 3 ? g_April : g_Apr ); + break; + + case 5: + result += ( digits != 3 ? g_MayL : g_May ); + break; + + case 6: + result += ( digits != 3 ? g_June : g_Jun ); + break; + + case 7: + result += ( digits != 3 ? g_July : g_Jul ); + break; + + case 8: + result += ( digits != 3 ? g_August : g_Aug ); + break; + + case 9: + result += ( digits != 3 ? g_September : g_Sep ); + break; + + case 10: + result += ( digits != 3 ? g_October : g_Oct ); + break; + + case 11: + result += ( digits != 3 ? g_November : g_Nov ); + break; + + case 12: + result += ( digits != 3 ? g_December : g_Dec ); + break; + } + } +} + +void appendDays( TQString & result, Value const & value, + int digits ) +{ + if ( !g_convertionInfo.dt ) + convertDateTime( value ); + + int day = g_convertionInfo.dt->day; + if ( digits == 1 ) + result += TQString::number( day ); + else + if ( digits == 2 ) + { + if ( day < 10 ) + result += '0'; + + result += TQString::number( day ); + } + else + { + TQDate date( g_convertionInfo.dt->year, g_convertionInfo.dt->month, g_convertionInfo.dt->day ); + int weekDay = date.dayOfWeek(); + switch ( weekDay ) + { + case 1: + result += ( digits != 3 ? g_Monday : g_Mon ); + break; + + case 2: + result += ( digits != 3 ? g_Tuesday : g_Tue ); + break; + + case 3: + result += ( digits != 3 ? g_Wednesday : g_Wed ); + break; + + case 4: + result += ( digits != 3 ? g_Thursday : g_Thu ); + break; + + case 5: + result += ( digits != 3 ? g_Friday : g_Fri ); + break; + + case 6: + result += ( digits != 3 ? g_Saturday : g_Sat ); + break; + + case 7: + result += ( digits != 3 ? g_Sunday : g_Sun ); + break; + } + } +} + +void createDateTime( TQString & result, Value const & value, + TQString const & /*format*/, + DateTimeFormat const * const data ) +{ + result = data->prefix; + bool elapsed = false; + bool elapsedFound = false; + bool minute = false; // how to interpret 'm' + int digits = 1; + int i = 0; + int l = (int) data->format.length(); + while ( i < l ) + { + switch( data->format[i].lower() ) + { + case '"': + ++i; + while ( i < l ) + { + if ( data->format[i] == '"' ) + break; + else + result += data->format[i]; + } + break; + + case '[': + if ( elapsedFound ) + result += '['; + else + { + elapsed = true; + elapsedFound = true; + } + break; + + case ']': + if ( elapsed ) + elapsed = false; + else + result += ']'; + break; + + case 'h': + minute = true; + if ( data->format[i + 1] == 'h' ) + { + appendHour( result, value, 2, elapsed, data->ampm ); + ++i; + } + else + appendHour( result, value, 1, elapsed, data->ampm ); + break; + + case 'm': + digits = 1; + + while ( data->format[i + 1] == 'm' ) + { + ++i; + ++digits; + } + + if ( minute ) + appendMinutes( result, value, digits, elapsed ); + else + appendMonth( result, value, digits ); + + break; + + case 's': + minute = true; + if ( data->format[i + 1] == 's' ) + { + appendSecond( result, value, 2, elapsed ); + ++i; + } + else + appendSecond( result, value, 1, elapsed ); + break; + + case 'd': + minute = false; + digits = 1; + + while ( data->format[i + 1] == 'd' ) + { + ++i; + ++digits; + } + appendDays( result, value, digits ); + break; + + case 'y': + minute = false; + digits = 1; + + while ( data->format[i + 1] == 'y' ) + { + ++i; + ++digits; + } + appendYear( result, value, digits ); + break; + + case 'a': + case 'p': + if ( data->format[i + 1] == 'm' ) + { + ++i; + if ( data->format[i + 1] == '/' + && data->format[i + 2].lower() == 'p' + && data->format[i + 3].lower() == 'm' ) + i += 3; + + appendAMPM( result, value ); + } + + default: + result += data->format[i]; + } + + ++i; + } + + result += data->postfix; +} + +TQString formatNumber( Value const & value, TQString format, bool & setRed, + TDELocale const * const locale, bool insert ) +{ + // need delocalized strings: dcSymbol: '.', thSymbol = ',' + if ( !g_init ) + initGlobals( locale ); + + TQString backup( format ); + TQString result; + BaseFormat * data = 0; + setRed = false; + + int t = doPreScan( format, backup, locale, insert, data ); + + if ( t == Number ) + { + createNumber( result, value, format, setRed, (NumberFormat *) data ); + + if ( !insert ) + delete (NumberFormat *) data; + + return result; + } + else if ( t == Fraction ) + { + createFraction( result, value, format, setRed, (FractionFormat *) data ); + + if ( !insert ) + delete (FractionFormat *) data; + + return result; + } + else if ( t == Scientific ) + { + createScientific( result, value, format, setRed, (ScientificFormat *) data ); + + if ( !insert ) + delete (ScientificFormat *) data; + + return result; + } + else if ( t == TimeDate ) + { + createDateTime( result, value, format, (DateTimeFormat *) data ); + + if ( !insert ) + delete (DateTimeFormat *) data; + + return result; + } + else if ( data != 0 ) + { + result = data->prefix + data->postfix; + + if ( !insert ) + delete data; + + return result; + } + + return result; +} |