KOffice – TDE office suite
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1635 lines
37KB

  1. /* This file is part of the KDE project
  2. Copyright (C) 2003 Norbert Andres, nandres@web.de
  3. This library is free software; you can redistribute it and/or
  4. modify it under the terms of the GNU Library General Public
  5. License as published by the Free Software Foundation; either
  6. version 2 of the License, or (at your option) any later version.
  7. This library is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  10. Library General Public License for more details.
  11. You should have received a copy of the GNU Library General Public License
  12. along with this library; see the file COPYING.LIB. If not, write to
  13. the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
  14. * Boston, MA 02110-1301, USA.
  15. */
  16. /*
  17. The only function visible from the outside is formatNumber, whose
  18. implementation is at the very bottom of this file. Its prototype
  19. is declared in kspread_util.h. However, it is not used anywhere.
  20. TODO: Find out whether it is supposed to be used instead of
  21. something else (locale()->formatNumber() maybe?) and either use it
  22. or get rid of it.
  23. Tomas
  24. */
  25. #include <ctype.h>
  26. #include <math.h>
  27. #include <tqdatetime.h>
  28. #include <tqmap.h>
  29. #include <tqstring.h>
  30. #include <kcalendarsystem.h>
  31. #include <tdelocale.h>
  32. #include "kspread_util.h"
  33. #include "kspread_value.h"
  34. namespace NumFormat_Local
  35. {
  36. enum { Unknown, TimeDate, Number, Scientific, Fraction } Type;
  37. TQString g_Monday;
  38. TQString g_Tuesday;
  39. TQString g_Wednesday;
  40. TQString g_Thursday;
  41. TQString g_Friday;
  42. TQString g_Saturday;
  43. TQString g_Sunday;
  44. TQString g_Mon;
  45. TQString g_Tue;
  46. TQString g_Wed;
  47. TQString g_Thu;
  48. TQString g_Fri;
  49. TQString g_Sat;
  50. TQString g_Sun;
  51. TQString g_January;
  52. TQString g_February;
  53. TQString g_March;
  54. TQString g_April;
  55. TQString g_MayL;
  56. TQString g_June;
  57. TQString g_July;
  58. TQString g_August;
  59. TQString g_September;
  60. TQString g_October;
  61. TQString g_November;
  62. TQString g_December;
  63. TQString g_Jan;
  64. TQString g_Feb;
  65. TQString g_Mar;
  66. TQString g_Apr;
  67. TQString g_May;
  68. TQString g_Jun;
  69. TQString g_Jul;
  70. TQString g_Aug;
  71. TQString g_Sep;
  72. TQString g_Oct;
  73. TQString g_Nov;
  74. TQString g_Dec;
  75. struct DateTime
  76. {
  77. int year;
  78. int month;
  79. int day;
  80. int hour;
  81. int minute;
  82. int second;
  83. };
  84. struct ConvertionInfo
  85. {
  86. DateTime * dt;
  87. int rightOpt;
  88. int rightReq;
  89. int leftReq;
  90. int rightSpace;
  91. int leftSpace;
  92. int upReq;
  93. int reqCounter;
  94. int reqFirst;
  95. int optFirst;
  96. bool ampm;
  97. bool thSet;
  98. bool showMinus;
  99. bool negRed;
  100. bool negBr;
  101. TQString postfix;
  102. TQString prefix;
  103. };
  104. class BaseFormat
  105. {
  106. public:
  107. int type;
  108. TQString postfix;
  109. TQString prefix;
  110. };
  111. class NumberFormat : public BaseFormat
  112. {
  113. public:
  114. bool thSet;
  115. bool showMinus;
  116. bool negRed;
  117. bool negBr;
  118. int rightOpt;
  119. int rightReq;
  120. int leftReq;
  121. int rightSpace;
  122. int leftSpace;
  123. };
  124. class FractionFormat : public BaseFormat
  125. {
  126. public:
  127. bool thSet;
  128. bool showMinus;
  129. bool negRed;
  130. bool negBr;
  131. int optFirst;
  132. int reqFirst;
  133. int reqCounter;
  134. int fraction;
  135. int fractionDigists;
  136. };
  137. class DateTimeFormat : public BaseFormat
  138. {
  139. public:
  140. bool ampm;
  141. TQString format;
  142. };
  143. class ScientificFormat : public BaseFormat
  144. {
  145. public:
  146. bool thSet;
  147. int leftReq;
  148. int rightReq;
  149. int rightOpt;
  150. int upReq;
  151. bool showMinus;
  152. bool negRed;
  153. bool negBr;
  154. int rightSpace;
  155. int leftSpace;
  156. };
  157. class FormatStore
  158. {
  159. public:
  160. int getType( TQString const & format, BaseFormat * f ) const
  161. {
  162. FormatMap::const_iterator iter = m_formats.find( format );
  163. if ( iter == m_formats.end() )
  164. {
  165. f = 0;
  166. return -1;
  167. }
  168. f = iter.data();
  169. return f->type;
  170. }
  171. void addFraction( TQString const & format, FractionFormat * f )
  172. {
  173. m_formats.insert( format, f );
  174. }
  175. void addNumber( TQString const & format, NumberFormat * n )
  176. {
  177. m_formats.insert( format, n );
  178. }
  179. void addDateTime( TQString const & format, DateTimeFormat * d )
  180. {
  181. m_formats.insert( format, d );
  182. }
  183. void addScientific( TQString const & format, ScientificFormat * d )
  184. {
  185. m_formats.insert( format, d );
  186. }
  187. private:
  188. class FormatMap : public TQMap<TQString, BaseFormat *> {};
  189. FormatMap m_formats;
  190. };
  191. TQChar g_dcSymbol;
  192. TQChar g_thSymbol;
  193. TQChar g_posSymbol;
  194. TQChar g_negSymbol;
  195. DateTime g_dateTime;
  196. ConvertionInfo g_convertionInfo;
  197. bool g_init = false;
  198. FormatStore g_formatStore;
  199. }
  200. using namespace NumFormat_Local;
  201. using namespace KSpread;
  202. void resetGlobals()
  203. {
  204. g_convertionInfo.dt = 0;
  205. g_convertionInfo.thSet = false;
  206. g_convertionInfo.showMinus = true;
  207. g_convertionInfo.negRed = false;
  208. g_convertionInfo.negBr = false;
  209. g_convertionInfo.reqCounter = 0;
  210. g_convertionInfo.reqFirst = 0;
  211. g_convertionInfo.prefix = "";
  212. g_convertionInfo.postfix = "";
  213. g_convertionInfo.rightOpt = 0;
  214. g_convertionInfo.rightReq = 0;
  215. g_convertionInfo.leftReq = 0;
  216. g_convertionInfo.rightSpace = 0;
  217. g_convertionInfo.leftSpace = 0;
  218. g_convertionInfo.optFirst = 0;
  219. g_convertionInfo.upReq = 0;
  220. g_convertionInfo.ampm = false;
  221. }
  222. void initGlobals( TDELocale const * const locale )
  223. {
  224. g_Monday = locale->calendar()->weekDayName( 1, false );
  225. g_Tuesday = locale->calendar()->weekDayName( 2, false );
  226. g_Wednesday = locale->calendar()->weekDayName( 3, false );
  227. g_Thursday = locale->calendar()->weekDayName( 4, false );
  228. g_Friday = locale->calendar()->weekDayName( 5, false );
  229. g_Saturday = locale->calendar()->weekDayName( 6, false );
  230. g_Sunday = locale->calendar()->weekDayName( 7, false );
  231. g_Mon = locale->calendar()->weekDayName( 1, true );
  232. g_Tue = locale->calendar()->weekDayName( 2, true );
  233. g_Wed = locale->calendar()->weekDayName( 3, true );
  234. g_Thu = locale->calendar()->weekDayName( 4, true );
  235. g_Fri = locale->calendar()->weekDayName( 5, true );
  236. g_Sat = locale->calendar()->weekDayName( 6, true );
  237. g_Sun = locale->calendar()->weekDayName( 7, true );
  238. g_January = locale->calendar()->monthName( 1, 2005, false );
  239. g_February = locale->calendar()->monthName( 2, 2005, false );
  240. g_March = locale->calendar()->monthName( 3, 2005, false );
  241. g_April = locale->calendar()->monthName( 4, 2005, false );
  242. g_MayL = locale->calendar()->monthName( 5, 2005, false );
  243. g_June = locale->calendar()->monthName( 6, 2005, false );
  244. g_July = locale->calendar()->monthName( 7, 2005, false );
  245. g_August = locale->calendar()->monthName( 8, 2005, false );
  246. g_September = locale->calendar()->monthName( 9, 2005, false );
  247. g_October = locale->calendar()->monthName( 10, 2005, false );
  248. g_November = locale->calendar()->monthName( 11, 2005, false );
  249. g_December = locale->calendar()->monthName( 12, 2005, false );
  250. g_Jan = locale->calendar()->monthName( 1, 2005, true );
  251. g_Feb = locale->calendar()->monthName( 2, 2005, true );
  252. g_Mar = locale->calendar()->monthName( 3, 2005, true );
  253. g_Apr = locale->calendar()->monthName( 4, 2005, true );
  254. g_May = locale->calendar()->monthName( 5, 2005, true );
  255. g_Jun = locale->calendar()->monthName( 6, 2005, true );
  256. g_Jul = locale->calendar()->monthName( 7, 2005, true );
  257. g_Aug = locale->calendar()->monthName( 8, 2005, true );
  258. g_Sep = locale->calendar()->monthName( 9, 2005, true );
  259. g_Oct = locale->calendar()->monthName( 10, 2005, true );
  260. g_Nov = locale->calendar()->monthName( 11, 2005, true );
  261. g_Dec = locale->calendar()->monthName( 12, 2005, true );
  262. g_dcSymbol = locale->decimalSymbol()[0];
  263. g_thSymbol = locale->thousandsSeparator()[0];
  264. g_posSymbol = locale->positiveSign()[0];
  265. g_negSymbol = locale->negativeSign()[0];
  266. g_init = true;
  267. }
  268. void convertDateTime( Value const & value )
  269. {
  270. TQDateTime dt( value.asDateTime() );
  271. TQDate d( dt.date() );
  272. TQTime t( dt.time() );
  273. g_dateTime.year = d.year();
  274. g_dateTime.month = d.month();
  275. g_dateTime.day = d.day();
  276. g_dateTime.hour = t.hour();
  277. g_dateTime.minute = t.minute();
  278. g_dateTime.second = t.second();
  279. g_convertionInfo.dt = &g_dateTime;
  280. }
  281. void parseNegativePart( TQString & format, int i,
  282. int l, bool acceptDigits )
  283. {
  284. g_convertionInfo.showMinus = false;
  285. g_convertionInfo.negRed = false;
  286. g_convertionInfo.negRed = false;
  287. bool end = false;
  288. while ( i < l && !end)
  289. {
  290. TQChar c( format[i] );
  291. switch( c )
  292. {
  293. case '-':
  294. g_convertionInfo.showMinus = true;
  295. break;
  296. case '(':
  297. g_convertionInfo.negBr = true;
  298. break;
  299. case '[':
  300. if ( format.find( "[red]", i, false ) == i )
  301. {
  302. g_convertionInfo.negRed = true;
  303. i += 5;
  304. }
  305. break;
  306. default:
  307. end = true;
  308. }
  309. ++i;
  310. }
  311. // find postfix
  312. bool quote = false;
  313. for ( int j = l - 1; j > i; --j )
  314. {
  315. if ( format[j] == '"' )
  316. {
  317. quote = !quote;
  318. continue;
  319. }
  320. if ( !quote && ( format[j] == '0' || format[j] != '?'
  321. || format[j] != '#'
  322. || ( format[j].isDigit() && acceptDigits ) ) )
  323. {
  324. g_convertionInfo.postfix = format.mid( j + 1 );
  325. format.remove( (unsigned int) (j + 1), (unsigned int) (l - j) );
  326. break;
  327. }
  328. }
  329. int p = g_convertionInfo.postfix.find( '"' );
  330. while ( p != -1 )
  331. {
  332. g_convertionInfo.postfix.remove( p, 1 );
  333. p = g_convertionInfo.postfix.find( '"', p );
  334. }
  335. }
  336. void createNumberStruct( BaseFormat * data, TQString const & format, bool insert )
  337. {
  338. NumberFormat * d = new NumberFormat();
  339. d->type = Number;
  340. d->prefix = g_convertionInfo.prefix;
  341. d->postfix = g_convertionInfo.postfix;
  342. d->thSet = g_convertionInfo.thSet;
  343. d->showMinus = g_convertionInfo.showMinus;
  344. d->negRed = g_convertionInfo.negRed;
  345. d->negBr = g_convertionInfo.negBr;
  346. d->rightOpt = g_convertionInfo.rightOpt;
  347. d->rightReq = g_convertionInfo.rightReq;
  348. d->leftReq = g_convertionInfo.leftReq;
  349. d->rightSpace = g_convertionInfo.rightSpace;
  350. d->leftSpace = g_convertionInfo.leftSpace;
  351. if ( insert )
  352. g_formatStore.addNumber( format, d );
  353. data = d;
  354. }
  355. void createDateTimeStruct( BaseFormat * data, TQString const & format,
  356. TQString const & optFormat, bool insert )
  357. {
  358. DateTimeFormat * d = new DateTimeFormat();
  359. d->type = TimeDate;
  360. d->prefix = g_convertionInfo.prefix;
  361. d->postfix = g_convertionInfo.postfix;
  362. d->ampm = g_convertionInfo.ampm;
  363. d->format = optFormat;
  364. if ( insert )
  365. g_formatStore.addDateTime( format, d );
  366. data = d;
  367. }
  368. void createScientificStruct( BaseFormat * data, TQString const & format, bool insert )
  369. {
  370. ScientificFormat * d = new ScientificFormat();
  371. d->type = Scientific;
  372. d->prefix = g_convertionInfo.prefix;
  373. d->postfix = g_convertionInfo.postfix;
  374. d->thSet = g_convertionInfo.thSet;
  375. d->showMinus = g_convertionInfo.showMinus;
  376. d->negRed = g_convertionInfo.negRed;
  377. d->negBr = g_convertionInfo.negBr;
  378. d->rightOpt = g_convertionInfo.rightOpt;
  379. d->rightReq = g_convertionInfo.rightReq;
  380. d->leftReq = g_convertionInfo.leftReq;
  381. d->rightSpace = g_convertionInfo.rightSpace;
  382. d->leftSpace = g_convertionInfo.leftSpace;
  383. d->upReq = g_convertionInfo.upReq;
  384. if ( insert )
  385. g_formatStore.addScientific( format, d );
  386. data = d;
  387. }
  388. int doPreScan( TQString & format, TQString const & formatBack, TDELocale const * const /* locale */,
  389. bool insert, BaseFormat * data )
  390. {
  391. int type = g_formatStore.getType( format, data );
  392. if ( data != 0 )
  393. return type;
  394. resetGlobals();
  395. int l = format.length();
  396. int i = 0;
  397. int thFound = false;
  398. int leftReq = 0;
  399. int leftOpt = 0;
  400. int rightOpt = 0;
  401. int spaceInNum = -1;
  402. bool dcSeen = false;
  403. bool endFixed = false;
  404. FractionFormat * df = 0;
  405. int f = 0;
  406. int d = 0;
  407. int len = 0;
  408. int n = 0;
  409. bool ok = false;
  410. TQString frac;
  411. while ( i < l )
  412. {
  413. TQString s;
  414. if ( endFixed )
  415. {
  416. g_convertionInfo.postfix += format.mid( i );
  417. format.remove( i, l - i );
  418. break;
  419. }
  420. TQChar ch( format[i] );
  421. switch( ch )
  422. {
  423. case '[':
  424. if ( type == Number )
  425. endFixed = true;
  426. if ( format[ i + 1] == '$' )
  427. {
  428. i += 2;
  429. bool found = false;
  430. while ( i < l && format[i] != ']' )
  431. {
  432. if ( format[i] == '-' )
  433. found = true;
  434. if ( !found )
  435. {
  436. if ( !endFixed )
  437. g_convertionInfo.prefix += format[i];
  438. else
  439. g_convertionInfo.postfix += format[i];
  440. format.remove( i, 1 );
  441. --i; --l;
  442. }
  443. ++i;
  444. }
  445. }
  446. else
  447. {
  448. if ( i + 1 >= l )
  449. {
  450. g_convertionInfo.postfix += '[';
  451. format.remove( i, 1 );
  452. --l; --i;
  453. }
  454. else
  455. if ( ( format[ i + 1].lower() != 's' )
  456. && ( format[ i + 1].lower() != 'm' )
  457. && ( format[ i + 1].lower() != 'h' ) )
  458. {
  459. // strange!
  460. if ( endFixed )
  461. g_convertionInfo.postfix += format[i];
  462. else
  463. g_convertionInfo.prefix += format[i];
  464. format.remove( i, 1 );
  465. --l; --i;
  466. }
  467. else
  468. {
  469. type = TimeDate;
  470. ++i;
  471. TQChar c( format[i] );
  472. ++i;
  473. while ( i < l && format[i] != ']' )
  474. {
  475. if ( format[i] != c )
  476. {
  477. format.remove( i, 1 );
  478. --l; --i;
  479. break;
  480. }
  481. ++i;
  482. }
  483. }
  484. }
  485. break;
  486. case '¤':
  487. case '$':
  488. case '¥':
  489. case '£':
  490. case '%':
  491. if ( type == Number )
  492. endFixed = true;
  493. if ( endFixed )
  494. g_convertionInfo.postfix += format[i];
  495. else
  496. g_convertionInfo.prefix += format[i];
  497. format.remove( i, 1 );
  498. --i; --l;
  499. break;
  500. case '#':
  501. type = Number;
  502. if ( !dcSeen && leftReq > 0 )
  503. { // 00##.00 <= remove the '#'
  504. format.remove( i, 1 );
  505. --l; --i;
  506. }
  507. if ( !dcSeen )
  508. ++leftOpt;
  509. else
  510. ++g_convertionInfo.rightOpt;
  511. break;
  512. case '0':
  513. if ( spaceInNum > 0 )
  514. { // for fractions
  515. ++g_convertionInfo.reqCounter;
  516. break;
  517. }
  518. type = Number;
  519. if ( !dcSeen && rightOpt > 0 )
  520. { // 00##.##00 <= remove the '0'
  521. format.remove( i, 1 );
  522. --l; --i;
  523. }
  524. if ( !dcSeen )
  525. ++g_convertionInfo.leftReq;
  526. else
  527. ++g_convertionInfo.rightReq;
  528. break;
  529. case '/':
  530. if ( ( i + 1 < l ) && ( format[i + 1] == ' ' ) )
  531. ++i;
  532. while ( i < l )
  533. {
  534. if ( format[i] != '?' && !format[i].isDigit() && format[i] != '#' )
  535. {
  536. g_convertionInfo.postfix = format.mid(i);
  537. format.remove( i, l - i );
  538. break;
  539. }
  540. else
  541. {
  542. ++d;
  543. frac += format[i];
  544. }
  545. ++i;
  546. }
  547. if ( i < l )
  548. {
  549. if ( format[i] == ';' )
  550. {
  551. ++i;
  552. parseNegativePart( format, i, l, true );
  553. }
  554. else
  555. if ( i + 3 < l )
  556. {
  557. if ( ( format[i + 1] == ')' ) && ( format[i + 2] == ';' ) )
  558. {
  559. i += 3;
  560. parseNegativePart( format, i, l, true );
  561. }
  562. }
  563. }
  564. ok = false;
  565. f = frac.toInt( &ok );
  566. df = new FractionFormat();
  567. if ( ok )
  568. df->fraction = f;
  569. else
  570. df->fraction = -1;
  571. df->type = Fraction;
  572. df->thSet = g_convertionInfo.thSet;
  573. df->showMinus = g_convertionInfo.showMinus;
  574. df->negRed = g_convertionInfo.negRed;
  575. df->negBr = g_convertionInfo.negBr;
  576. df->fractionDigists = d;
  577. df->reqCounter = g_convertionInfo.reqCounter;
  578. df->reqFirst = g_convertionInfo.reqFirst;
  579. df->prefix = g_convertionInfo.prefix;
  580. df->postfix = g_convertionInfo.postfix;
  581. if ( insert )
  582. g_formatStore.addFraction( formatBack, df );
  583. data = df;
  584. return Fraction;
  585. break;
  586. case ',':
  587. if ( type == Unknown )
  588. {
  589. g_convertionInfo.prefix += ',';
  590. }
  591. else if ( type == Number )
  592. {
  593. if ( dcSeen )
  594. {
  595. g_convertionInfo.postfix += ',';
  596. format.remove( i, 1 );
  597. --i; --l;
  598. }
  599. else
  600. {
  601. if ( thFound )
  602. {
  603. format.remove( i, 1 );
  604. --l; --i;
  605. }
  606. else
  607. thFound = true;
  608. }
  609. }
  610. case '.': // decimal point
  611. if ( type == Unknown )
  612. {
  613. int j = i + 1;
  614. if ( ( j < l )
  615. && ( format[j] == '0' || format[j] == '#' ) )
  616. {
  617. type = Number;
  618. dcSeen = true;
  619. }
  620. else
  621. {
  622. if ( j == l )
  623. g_convertionInfo.postfix += '.';
  624. else
  625. g_convertionInfo.prefix += '.';
  626. format.remove( i, 1 );
  627. --i; --l;
  628. }
  629. }
  630. else if ( type == Number )
  631. {
  632. dcSeen = true;
  633. }
  634. break;
  635. case '*':
  636. break;
  637. case '"':
  638. n = i;
  639. ++i;
  640. while ( i < l && format[i] != '"' )
  641. {
  642. s += format[i];
  643. ++i;
  644. }
  645. if ( type == Unknown )
  646. g_convertionInfo.prefix += s;
  647. else
  648. {
  649. g_convertionInfo.postfix += s;
  650. }
  651. len = s.length();
  652. format.remove( i, len );
  653. i -= len; l -= len;
  654. break;
  655. case '_':
  656. if ( type == Number )
  657. {
  658. bool pr = false;
  659. if ( i + 3 < l )
  660. {
  661. if ( ( format[i + 1] != ')' ) || ( format[i + 2] != ';' ) )
  662. pr = true;
  663. else
  664. {
  665. i += 3;
  666. parseNegativePart( format, i, l, false );
  667. createNumberStruct( data, formatBack, insert );
  668. return Number;
  669. }
  670. }
  671. if ( pr )
  672. {
  673. g_convertionInfo.postfix += format.mid( i );
  674. format.remove( i, l - i );
  675. createNumberStruct( data, formatBack, insert );
  676. return Number;
  677. }
  678. }
  679. break;
  680. case ';':
  681. if ( type == Unknown )
  682. {
  683. g_convertionInfo.postfix += ';';
  684. format.remove( i, 1 );
  685. --i; --l;
  686. }
  687. else
  688. {
  689. if ( type == Number )
  690. {
  691. ++i;
  692. parseNegativePart( format, i, l, false );
  693. createNumberStruct( data, formatBack, insert );
  694. return Number;
  695. }
  696. else
  697. if ( type == Scientific )
  698. {
  699. ++i;
  700. parseNegativePart( format, i, l, false );
  701. createScientificStruct( data, formatBack, insert );
  702. return Scientific;
  703. }
  704. }
  705. case ' ':
  706. if ( type == Number )
  707. {
  708. g_convertionInfo.optFirst = (leftOpt > 0 ? leftOpt : 0);
  709. g_convertionInfo.reqFirst = (leftReq > 0 ? leftReq : 0);
  710. spaceInNum = i;
  711. g_convertionInfo.postfix += ' ';
  712. }
  713. else if ( type == Unknown )
  714. {
  715. g_convertionInfo.prefix += ' ';
  716. format.remove( i, 1 );
  717. --i; --l;
  718. }
  719. break;
  720. case 'A':
  721. case 'a':
  722. if ( type == TimeDate || type == Unknown )
  723. {
  724. if ( ( i + 1 < l ) && ( format[i + 1].lower() == 'm' ) )
  725. {
  726. g_convertionInfo.ampm = true;
  727. ++i;
  728. if ( ( i + 3 < l ) && ( format[i + 1] == '/' )
  729. && ( format[i + 2].lower() == 'p' )
  730. && ( format[i + 3].lower() == 'm' ) )
  731. {
  732. i += 3;
  733. }
  734. }
  735. else if ( type == Unknown )
  736. {
  737. g_convertionInfo.prefix += format[i];
  738. format.remove( i, 1 );
  739. --i; --l;
  740. }
  741. }
  742. else
  743. {
  744. if ( !endFixed )
  745. endFixed = true;
  746. g_convertionInfo.postfix += format[i];
  747. format.remove( i, 1 );
  748. --i; --l;
  749. }
  750. break;
  751. case 'P':
  752. case 'p':
  753. if ( type == TimeDate || type == Unknown )
  754. {
  755. if ( ( i + 1 < l ) && ( format[i + 1].lower() == 'm' ) )
  756. {
  757. g_convertionInfo.ampm = true;
  758. i += 1;
  759. }
  760. else if ( type == Unknown )
  761. {
  762. g_convertionInfo.prefix += format[i];
  763. format.remove( i, 1 );
  764. --i; --l;
  765. }
  766. }
  767. else
  768. {
  769. if ( !endFixed )
  770. endFixed = true;
  771. g_convertionInfo.postfix += format[i];
  772. format.remove( i, 1 );
  773. --i; --l;
  774. }
  775. break;
  776. case 'M':
  777. case 'm':
  778. if ( type == Unknown )
  779. type = TimeDate;
  780. else if ( type != TimeDate )
  781. endFixed = true;
  782. break;
  783. case 'S':
  784. case 's':
  785. case 'H':
  786. case 'h':
  787. if ( type != Unknown && type != TimeDate )
  788. endFixed = true;
  789. else
  790. type = TimeDate;
  791. break;
  792. case 'D':
  793. case 'd':
  794. case 'Y':
  795. case 'y':
  796. if ( type != Unknown && type != TimeDate )
  797. endFixed = true;
  798. else
  799. type = TimeDate;
  800. break;
  801. default:
  802. if ( type == Unknown )
  803. {
  804. g_convertionInfo.prefix += format[i];
  805. format.remove( i, 1 );
  806. --i; --l;
  807. }
  808. else if ( type == Number || type == Scientific
  809. || type == Fraction )
  810. {
  811. endFixed = true;
  812. g_convertionInfo.postfix += format[i];
  813. format.remove( i, 1 );
  814. --l; --i;
  815. }
  816. }
  817. ++i;
  818. }
  819. if ( type == Number )
  820. createNumberStruct( data, formatBack, insert );
  821. else if ( type == TimeDate )
  822. createDateTimeStruct( data, formatBack, format, insert );
  823. else if ( type == Scientific )
  824. createScientificStruct( data, formatBack, insert );
  825. return type;
  826. }
  827. void createNumber( TQString & result, Value const & value,
  828. TQString const & /*format*/, bool & setRed,
  829. NumberFormat const * const data )
  830. {
  831. int prec = data->rightReq + data->rightOpt;
  832. double num = value.asFloat();
  833. double m[] = { 1, 10, 100, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 1e10 };
  834. double mm = ( prec > 10 ) ? pow( 10.0, prec ) : m[prec];
  835. num = floor( fabs( num ) * mm + 0.5 ) / mm;
  836. bool negative = ( num < 0 ? true : false );
  837. double nnum = ( negative ? -num : num );
  838. result = TQString::number( nnum, 'f', prec );
  839. int pos = result.find( '.' );
  840. if ( pos >= 0 )
  841. {
  842. result = result.replace( pos, 1, g_dcSymbol );
  843. // remove '0' from the end if not required
  844. if ( data->rightOpt > 0 )
  845. {
  846. int i = result.length() - 1; // index
  847. int n = result.length() - data->rightOpt;
  848. for ( ; i > n; --i )
  849. {
  850. if ( result[i] != '0' )
  851. break;
  852. }
  853. result = result.left( i + 1 ); //length
  854. if ( i == pos ) // just decimal point
  855. result = result.remove( i, 1 );
  856. }
  857. // prepend '0' if wanted
  858. while ( data->leftReq > pos )
  859. {
  860. result.prepend( '0' );
  861. ++pos;
  862. }
  863. // put in thousand symbol if wanted
  864. if ( data->thSet && pos > 3 )
  865. {
  866. int l = pos - 3;
  867. while ( 0 < l )
  868. {
  869. result.insert( l, g_thSymbol );
  870. l -= 3;
  871. }
  872. }
  873. }
  874. if ( data->leftSpace > 0 )
  875. {
  876. for ( int i = 0; i < data->leftSpace; ++i )
  877. result.prepend( ' ' );
  878. }
  879. if ( data->rightSpace > 0 )
  880. {
  881. for ( int i = 0; i < data->rightSpace; ++i )
  882. result.append( ' ' );
  883. }
  884. if ( negative )
  885. {
  886. if ( data->showMinus )
  887. result.prepend( g_negSymbol );
  888. if ( data->negBr )
  889. {
  890. result.prepend( '(' );
  891. result.append( ')' );
  892. }
  893. if ( data->negRed )
  894. setRed = true;
  895. }
  896. result.prepend( data->prefix );
  897. result.append( data->postfix );
  898. }
  899. void createFraction( TQString & result, Value const & value,
  900. TQString const & /*format*/, bool & setRed,
  901. FractionFormat const * const data )
  902. {
  903. double num = value.asFloat();
  904. bool negative = ( num < 0 ? true : false );
  905. double fnum = floor( negative ? -num : num );
  906. double dec = num - fnum;
  907. double fraction;
  908. int index = 0;
  909. if ( data->fraction <= 0 )
  910. {
  911. // #,### ?/???
  912. double nnum = ( negative ? -num : num );
  913. double precision, denominator, numerator;
  914. int index = 2 + data->fractionDigists;
  915. int limit = 9;
  916. if ( data->fractionDigists == 2 )
  917. limit += 90;
  918. if ( data->fractionDigists >= 3 )
  919. limit += 990;
  920. do
  921. {
  922. double val1 = nnum;
  923. double val2 = rint( nnum );
  924. double inter2 = 1;
  925. double inter4, p, q;
  926. inter4 = p = q = 0.0;
  927. precision = pow( 10.0, - index );
  928. numerator = val2;
  929. denominator = 1;
  930. while ( fabs( numerator / denominator - nnum ) > precision )
  931. {
  932. val1 = (1 / ( val1 - val2 ) );
  933. val2 = rint( val1 );
  934. p = val2 * numerator + inter2;
  935. q = val2 * denominator + inter4;
  936. inter2 = numerator;
  937. inter4 = denominator;
  938. numerator = p;
  939. denominator = q;
  940. }
  941. --index;
  942. } while ( fabs( denominator ) > limit );
  943. index = (int) fabs( numerator );
  944. fraction = (int) fabs( denominator );
  945. }
  946. else
  947. {
  948. // # #/4
  949. fraction = data->fraction;
  950. double calc = 0.0;
  951. double diff = dec;
  952. double d;
  953. for ( int i = 1; i <= fraction; ++i )
  954. {
  955. calc = i * 1.0 / index;
  956. d = fabs( dec - calc );
  957. if ( d < diff )
  958. {
  959. index = i;
  960. diff = d;
  961. }
  962. }
  963. }
  964. // ? index/fraction
  965. // 2.25: #/4 => 9/4
  966. if ( data->optFirst == 0 && data->reqFirst == 0 && fnum > 0 )
  967. index += (int) (fnum * fraction);
  968. TQString frac;
  969. TQString left;
  970. if ( index > 0 )
  971. {
  972. TQString numerator;
  973. TQString denominator;
  974. numerator = TQString::number( index );
  975. int n = numerator.length() - data->reqCounter;
  976. for ( int i = 0; i < n; ++i )
  977. {
  978. numerator.prepend( '0' );
  979. }
  980. denominator = TQString::number( fraction );
  981. frac = numerator + '/' + denominator;
  982. }
  983. if ( data->optFirst > 0 || data->reqFirst > 0 )
  984. {
  985. if ( fnum == 0 && data->reqFirst > 0 )
  986. {
  987. for ( int i = 0; i < data->reqFirst; ++i )
  988. left += '0';
  989. }
  990. else if ( fnum > 0 )
  991. {
  992. left = TQString::number( fnum );
  993. int n = data->reqFirst - left.length();
  994. if ( n > 0 )
  995. {
  996. for ( int i = 0; i < n; ++i )
  997. {
  998. left.prepend( '0' );
  999. }
  1000. }
  1001. }
  1002. }
  1003. if ( data->thSet )
  1004. {
  1005. int l = left.length() - 3;
  1006. while ( 0 < l )
  1007. {
  1008. left.insert( l, g_thSymbol );
  1009. l -= 3;
  1010. }
  1011. }
  1012. left = left + ' ' + frac;
  1013. if ( negative )
  1014. {
  1015. if ( data->showMinus )
  1016. left.prepend( g_negSymbol );
  1017. if ( data->negBr )
  1018. {
  1019. left.prepend( '(' );
  1020. left.append( ')' );
  1021. }
  1022. if ( data->negRed )
  1023. setRed = true;
  1024. }
  1025. result = left;
  1026. }
  1027. void createScientific( TQString & result, Value const & value,
  1028. TQString const & /*format*/, bool & setRed,
  1029. ScientificFormat const * const data )
  1030. {
  1031. double num = value.asFloat();
  1032. bool negative = ( num < 0 ? true : false );
  1033. double nnum = ( negative ? -num : num );
  1034. result = TQString::number( nnum, 'E', data->rightReq + data->rightOpt );
  1035. int pos = result.find( '.' );
  1036. if ( pos >= 0 )
  1037. {
  1038. result = result.replace( pos, 1, g_dcSymbol );
  1039. if ( data->rightOpt > 0 )
  1040. {
  1041. int i = result.find( 'E', pos, false ) - 1;
  1042. int n = result.length() - data->rightOpt;
  1043. if ( i > 0 )
  1044. {
  1045. int rem = 0;
  1046. for ( ; i > n; --i )
  1047. {
  1048. if ( result[i] != '0' )
  1049. break;
  1050. else
  1051. ++rem;
  1052. }
  1053. result = result.remove( i + 1, rem );
  1054. }
  1055. }
  1056. while ( data->leftReq > pos )
  1057. {
  1058. result.prepend( '0' );
  1059. ++pos;
  1060. }
  1061. if ( data->thSet && pos > 3 )
  1062. {
  1063. int l = pos - 3;
  1064. while ( 0 < l )
  1065. {
  1066. result.insert( l, g_thSymbol );
  1067. l -= 3;
  1068. }
  1069. }
  1070. }
  1071. if ( negative )
  1072. {
  1073. if ( data->showMinus )
  1074. result.prepend( g_negSymbol );
  1075. if ( data->negBr )
  1076. {
  1077. result.prepend( '(' );
  1078. result.append( ')' );
  1079. }
  1080. if ( data->negRed )
  1081. setRed = true;
  1082. }
  1083. result.prepend( data->prefix );
  1084. result.append( data->postfix );
  1085. }
  1086. void appendAMPM( TQString & result, Value const & value )
  1087. {
  1088. if ( !g_convertionInfo.dt )
  1089. convertDateTime( value );
  1090. int hour = g_convertionInfo.dt->hour;
  1091. if ( hour > 12 )
  1092. result.append( i18n("PM") );
  1093. else
  1094. result.append( i18n("AM") );
  1095. }
  1096. void appendHour( TQString & result, Value const & value,
  1097. int digits, bool elapsed, bool ampm )
  1098. {
  1099. if ( !g_convertionInfo.dt )
  1100. convertDateTime( value );
  1101. int hour = g_convertionInfo.dt->hour;
  1102. if ( elapsed )
  1103. {
  1104. TQDate d1( g_convertionInfo.dt->year, g_convertionInfo.dt->month, g_convertionInfo.dt->day );
  1105. TQDate d2( 1900, 1, 1 );
  1106. hour += ( d2.daysTo( d1 ) * 24 );
  1107. }
  1108. if ( hour < 10 && digits == 2 )
  1109. result += '0';
  1110. else
  1111. if ( hour > 12 && ampm )
  1112. {
  1113. hour -= 12;
  1114. if ( digits == 2 && hour < 10 )
  1115. result += '0';
  1116. }
  1117. result += TQString::number( hour );
  1118. }
  1119. void appendMinutes( TQString & result, Value const & value,
  1120. int digits, bool elapsed )
  1121. {
  1122. if ( !g_convertionInfo.dt )
  1123. convertDateTime( value );
  1124. int minute = g_convertionInfo.dt->minute;
  1125. if ( elapsed )
  1126. {
  1127. TQDate d1( g_convertionInfo.dt->year, g_convertionInfo.dt->month, g_convertionInfo.dt->day );
  1128. TQDate d2( 1900, 1, 1 );
  1129. minute += ( d2.daysTo( d1 ) * 24 * 60 );
  1130. }
  1131. if ( minute < 10 && digits == 2 )
  1132. result += '0';
  1133. result += TQString::number( minute );
  1134. }
  1135. void appendSecond( TQString & result, Value const & value,
  1136. int digits, bool elapsed )
  1137. {
  1138. if ( !g_convertionInfo.dt )
  1139. convertDateTime( value );
  1140. int second = g_convertionInfo.dt->second;
  1141. if ( elapsed )
  1142. {
  1143. TQDate d1( g_convertionInfo.dt->year, g_convertionInfo.dt->month, g_convertionInfo.dt->day );
  1144. TQDate d2( 1900, 1, 1 );
  1145. second += ( d2.daysTo( d1 ) * 24 * 60 * 60 );
  1146. }
  1147. if ( second < 10 && digits == 2 )
  1148. result += '0';
  1149. result += TQString::number( second );
  1150. }
  1151. void appendYear( TQString & result, Value const & value,
  1152. int digits )
  1153. {
  1154. if ( !g_convertionInfo.dt )
  1155. convertDateTime( value );
  1156. int year = g_convertionInfo.dt->year;
  1157. if ( digits <= 2 )
  1158. result += TQString::number( year ).right( 2 );
  1159. else
  1160. result += TQString::number( year );
  1161. }
  1162. void appendMonth( TQString & result, Value const & value,
  1163. int digits )
  1164. {
  1165. if ( !g_convertionInfo.dt )
  1166. convertDateTime( value );
  1167. int month = g_convertionInfo.dt->month;
  1168. if ( digits == 1 )
  1169. result += TQString::number( month );
  1170. else
  1171. if ( digits == 2 )
  1172. {
  1173. if ( month < 10 )
  1174. result += '0';
  1175. result += TQString::number( month );
  1176. }
  1177. else
  1178. {
  1179. switch ( month )
  1180. {
  1181. case 1:
  1182. result += ( digits != 3 ? g_January : g_Jan );
  1183. break;
  1184. case 2:
  1185. result += ( digits != 3 ? g_February : g_Feb );
  1186. break;
  1187. case 3:
  1188. result += ( digits != 3 ? g_March : g_Mar );
  1189. break;
  1190. case 4:
  1191. result += ( digits != 3 ? g_April : g_Apr );
  1192. break;
  1193. case 5:
  1194. result += ( digits != 3 ? g_MayL : g_May );
  1195. break;
  1196. case 6:
  1197. result += ( digits != 3 ? g_June : g_Jun );
  1198. break;
  1199. case 7:
  1200. result += ( digits != 3 ? g_July : g_Jul );
  1201. break;
  1202. case 8:
  1203. result += ( digits != 3 ? g_August : g_Aug );
  1204. break;
  1205. case 9:
  1206. result += ( digits != 3 ? g_September : g_Sep );
  1207. break;
  1208. case 10:
  1209. result += ( digits != 3 ? g_October : g_Oct );
  1210. break;
  1211. case 11:
  1212. result += ( digits != 3 ? g_November : g_Nov );
  1213. break;
  1214. case 12:
  1215. result += ( digits != 3 ? g_December : g_Dec );
  1216. break;
  1217. }
  1218. }
  1219. }
  1220. void appendDays( TQString & result, Value const & value,
  1221. int digits )
  1222. {
  1223. if ( !g_convertionInfo.dt )
  1224. convertDateTime( value );
  1225. int day = g_convertionInfo.dt->day;
  1226. if ( digits == 1 )
  1227. result += TQString::number( day );
  1228. else
  1229. if ( digits == 2 )
  1230. {
  1231. if ( day < 10 )
  1232. result += '0';
  1233. result += TQString::number( day );
  1234. }
  1235. else
  1236. {
  1237. TQDate date( g_convertionInfo.dt->year, g_convertionInfo.dt->month, g_convertionInfo.dt->day );
  1238. int weekDay = date.dayOfWeek();
  1239. switch ( weekDay )
  1240. {
  1241. case 1:
  1242. result += ( digits != 3 ? g_Monday : g_Mon );
  1243. break;
  1244. case 2:
  1245. result += ( digits != 3 ? g_Tuesday : g_Tue );
  1246. break;
  1247. case 3:
  1248. result += ( digits != 3 ? g_Wednesday : g_Wed );
  1249. break;
  1250. case 4:
  1251. result += ( digits != 3 ? g_Thursday : g_Thu );
  1252. break;
  1253. case 5:
  1254. result += ( digits != 3 ? g_Friday : g_Fri );
  1255. break;
  1256. case 6:
  1257. result += ( digits != 3 ? g_Saturday : g_Sat );
  1258. break;
  1259. case 7:
  1260. result += ( digits != 3 ? g_Sunday : g_Sun );
  1261. break;
  1262. }
  1263. }
  1264. }
  1265. void createDateTime( TQString & result, Value const & value,
  1266. TQString const & /*format*/,
  1267. DateTimeFormat const * const data )
  1268. {
  1269. result = data->prefix;
  1270. bool elapsed = false;
  1271. bool elapsedFound = false;
  1272. bool minute = false; // how to interpret 'm'
  1273. int digits = 1;
  1274. int i = 0;
  1275. int l = (int) data->format.length();
  1276. while ( i < l )
  1277. {
  1278. switch( data->format[i].lower() )
  1279. {
  1280. case '"':
  1281. ++i;
  1282. while ( i < l )
  1283. {
  1284. if ( data->format[i] == '"' )
  1285. break;
  1286. else
  1287. result += data->format[i];
  1288. }
  1289. break;
  1290. case '[':
  1291. if ( elapsedFound )
  1292. result += '[';
  1293. else
  1294. {
  1295. elapsed = true;
  1296. elapsedFound = true;
  1297. }
  1298. break;
  1299. case ']':
  1300. if ( elapsed )
  1301. elapsed = false;
  1302. else
  1303. result += ']';
  1304. break;
  1305. case 'h':
  1306. minute = true;
  1307. if ( data->format[i + 1] == 'h' )
  1308. {
  1309. appendHour( result, value, 2, elapsed, data->ampm );
  1310. ++i;
  1311. }
  1312. else
  1313. appendHour( result, value, 1, elapsed, data->ampm );
  1314. break;
  1315. case 'm':
  1316. digits = 1;
  1317. while ( data->format[i + 1] == 'm' )
  1318. {
  1319. ++i;
  1320. ++digits;
  1321. }
  1322. if ( minute )
  1323. appendMinutes( result, value, digits, elapsed );
  1324. else
  1325. appendMonth( result, value, digits );
  1326. break;
  1327. case 's':
  1328. minute = true;
  1329. if ( data->format[i + 1] == 's' )
  1330. {
  1331. appendSecond( result, value, 2, elapsed );
  1332. ++i;
  1333. }
  1334. else
  1335. appendSecond( result, value, 1, elapsed );
  1336. break;
  1337. case 'd':
  1338. minute = false;
  1339. digits = 1;
  1340. while ( data->format[i + 1] == 'd' )
  1341. {
  1342. ++i;
  1343. ++digits;
  1344. }
  1345. appendDays( result, value, digits );
  1346. break;
  1347. case 'y':
  1348. minute = false;
  1349. digits = 1;
  1350. while ( data->format[i + 1] == 'y' )
  1351. {
  1352. ++i;
  1353. ++digits;
  1354. }
  1355. appendYear( result, value, digits );
  1356. break;
  1357. case 'a':
  1358. case 'p':
  1359. if ( data->format[i + 1] == 'm' )
  1360. {
  1361. ++i;
  1362. if ( data->format[i + 1] == '/'
  1363. && data->format[i + 2].lower() == 'p'
  1364. && data->format[i + 3].lower() == 'm' )
  1365. i += 3;
  1366. appendAMPM( result, value );
  1367. }
  1368. default:
  1369. result += data->format[i];
  1370. }
  1371. ++i;
  1372. }
  1373. result += data->postfix;
  1374. }
  1375. TQString formatNumber( Value const & value, TQString format, bool & setRed,
  1376. TDELocale const * const locale, bool insert )
  1377. {
  1378. // need delocalized strings: dcSymbol: '.', thSymbol = ','
  1379. if ( !g_init )
  1380. initGlobals( locale );
  1381. TQString backup( format );
  1382. TQString result;
  1383. BaseFormat * data = 0;
  1384. setRed = false;
  1385. int t = doPreScan( format, backup, locale, insert, data );
  1386. if ( t == Number )
  1387. {
  1388. createNumber( result, value, format, setRed, (NumberFormat *) data );
  1389. if ( !insert )
  1390. delete (NumberFormat *) data;
  1391. return result;
  1392. }
  1393. else if ( t == Fraction )
  1394. {
  1395. createFraction( result, value, format, setRed, (FractionFormat *) data );
  1396. if ( !insert )
  1397. delete (FractionFormat *) data;
  1398. return result;
  1399. }
  1400. else if ( t == Scientific )
  1401. {
  1402. createScientific( result, value, format, setRed, (ScientificFormat *) data );
  1403. if ( !insert )
  1404. delete (ScientificFormat *) data;
  1405. return result;
  1406. }
  1407. else if ( t == TimeDate )
  1408. {
  1409. createDateTime( result, value, format, (DateTimeFormat *) data );
  1410. if ( !insert )
  1411. delete (DateTimeFormat *) data;
  1412. return result;
  1413. }
  1414. else if ( data != 0 )
  1415. {
  1416. result = data->prefix + data->postfix;
  1417. if ( !insert )
  1418. delete data;
  1419. return result;
  1420. }
  1421. return result;
  1422. }