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.

7349 lines
232KB

  1. /* This file is part of the KDE project
  2. Copyright 2006 Stefan Nikolaus <stefan.nikolaus@kdemail.net>
  3. Copyright 2005 Raphael Langerhorst <raphael.langerhorst@kdemail.net>
  4. Copyright 2004-2005 Tomas Mecir <mecirt@gmail.com>
  5. Copyright 2004-2006 Inge Wallin <inge@lysator.liu.se>
  6. Copyright 1999-2002,2004,2005 Laurent Montel <montel@kde.org>
  7. Copyright 2002-2005 Ariya Hidayat <ariya@kde.org>
  8. Copyright 2001-2003 Philipp Mueller <philipp.mueller@gmx.de>
  9. Copyright 2002-2003 Norbert Andres <nandres@web.de>
  10. Copyright 2003 Reinhart Geiser <geiseri@kde.org>
  11. Copyright 2003-2005 Meni Livne <livne@kde.org>
  12. Copyright 2003 Peter Simonsson <psn@linux.se>
  13. Copyright 1999-2002 David Faure <faure@kde.org>
  14. Copyright 2000-2002 Werner Trobin <trobin@kde.org>
  15. Copyright 1999,2002 Harri Porten <porten@kde.org>
  16. Copyright 2002 John Dailey <dailey@vt.edu>
  17. Copyright 1998-2000 Torben Weis <weis@kde.org>
  18. Copyright 2000 Bernd Wuebben <wuebben@kde.org>
  19. Copyright 2000 Simon Hausmann <hausmann@kde.org
  20. Copyright 1999 Stephan Kulow <coolo@kde.org>
  21. Copyright 1999 Michael Reiher <michael.reiher.gmx.de>
  22. Copyright 1999 Boris Wedl <boris.wedl@kfunigraz.ac.at>
  23. Copyright 1998-1999 Reginald Stadlbauer <reggie@kde.org>
  24. This library is free software; you can redistribute it and/or
  25. modify it under the terms of the GNU Library General Public
  26. License as published by the Free Software Foundation; either
  27. version 2 of the License, or (at your option) any later version.
  28. This library is distributed in the hope that it will be useful,
  29. but WITHOUT ANY WARRANTY; without even the implied warranty of
  30. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  31. Library General Public License for more details.
  32. You should have received a copy of the GNU Library General Public License
  33. along with this library; see the file COPYING.LIB. If not, write to
  34. the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
  35. * Boston, MA 02110-1301, USA.
  36. */
  37. #include <stdlib.h>
  38. #include <ctype.h>
  39. #include <float.h>
  40. #include <math.h>
  41. #include <tqapplication.h>
  42. #include <tqpopupmenu.h>
  43. #include <tqregexp.h>
  44. #include "kspread_canvas.h"
  45. #include "kspread_condition.h"
  46. #include "kspread_doc.h"
  47. #include "kspread_format.h"
  48. #include "kspread_global.h"
  49. #include "kspread_map.h"
  50. #include "kspread_sheet.h"
  51. #include "kspread_sheetprint.h"
  52. #include "kspread_style.h"
  53. #include "kspread_style_manager.h"
  54. #include "kspread_util.h"
  55. #include "ksploadinginfo.h"
  56. #include "kspread_genvalidationstyle.h"
  57. #include "kspread_locale.h"
  58. #include "kspread_value.h"
  59. #include "kspread_view.h"
  60. #include "kspread_value.h"
  61. #include "formula.h"
  62. #include "selection.h"
  63. #include "valueconverter.h"
  64. #include "valueformatter.h"
  65. #include "valueparser.h"
  66. #include <KoStyleStack.h>
  67. #include <KoRect.h>
  68. #include <KoXmlNS.h>
  69. #include <KoDom.h>
  70. #include <KoXmlWriter.h>
  71. #include <KoOasisStyles.h>
  72. #include <tdemessagebox.h>
  73. #include <kdebug.h>
  74. using namespace KSpread;
  75. #define BORDER_SPACE 1
  76. /**
  77. * A pointer to the decimal separator
  78. */
  79. namespace Cell_LNS
  80. {
  81. TQChar decimal_point = '\0';
  82. }
  83. using namespace Cell_LNS;
  84. // Some variables are placed in Cell::Extra because normally they're
  85. // not required in simple case of cell(s). For example, most plain
  86. // text cells don't need to store information about spanned columns
  87. // and rows, as this is only the case with merged cells.
  88. //
  89. // When the cell is getting complex (e.g. merged with other cells,
  90. // contains rich text, has validation criteria, etc), this Cell::Extra
  91. // is allocated by Cell::Private and starts to be
  92. // available. Otherwise, it won't exist at all.
  93. class Cell::Extra
  94. {
  95. public:
  96. Extra() {}
  97. // Not empty when the cell holds a link
  98. TQString link;
  99. // Number of cells explicitly merged by the user in X and Y directions.
  100. int mergedXCells;
  101. int mergedYCells;
  102. // Number of additional cells.
  103. int extraXCells;
  104. int extraYCells;
  105. // If this cell overlaps other cells, then we have the cells width and
  106. // height stored here. These values do not mean anything unless
  107. // extraXCells and/or extraYCells are different from 0.
  108. double extraWidth;
  109. double extraHeight;
  110. // A list of cells that obscure this one.
  111. // If this list is not empty, then this cell is obscured by another
  112. // enlarged object. This means that we have to call this object in order
  113. // of painting it for example instead of painting 'this'.
  114. //
  115. // FIXME (comment): If the list consists of more than one obscuring
  116. // element, then is there an order between them that
  117. // is important?
  118. TQValueList<Cell*> obscuringCells;
  119. // If non-NULL, contains a pointer to a condition or a validity test.
  120. Conditions *conditions;
  121. Validity *validity;
  122. // Store the number of line when multirow is used (default is 0)
  123. int nbLines;
  124. private:
  125. // Don't allow implicit copy.
  126. Extra& operator=( const Extra& );
  127. };
  128. class Cell::Private
  129. {
  130. public:
  131. Private();
  132. ~Private();
  133. public:
  134. // This cell's row and column. If either of them is 0, this is the
  135. // default cell and its row/column can not be determined. Note that
  136. // in the isDefault() method, only column is tested.
  137. int row;
  138. int column;
  139. // Value of the cell, either typed by user or as result of formula
  140. Value value;
  141. // Holds the user's input.
  142. //
  143. // FIXME:
  144. // Eventually, we'll want to get rid of strText and generate
  145. // user's input on-the-fly. Then, for normal cells, we'll generate
  146. // this string using converter()->asString
  147. // (value()).
  148. //
  149. // Here the problem is, that strText also holds the formula -
  150. // we'll need to provide some method to generate it from the
  151. // parsed version, created in KSpread::Formula. Hence, we won't be
  152. // able to get rid of strText until we switch to the new formula
  153. // parser and until we write some method that re-generates the
  154. // input formula...
  155. //
  156. // Alternately, we can keep using strText for formulas and
  157. // generate it dynamically for static cells...
  158. //
  159. // /Tomas
  160. //
  161. TQString strText;
  162. // This is the text we want to display. Not necessarily the same
  163. // as strText, e.g. strText="1" and strOutText="1.00" Also holds
  164. // value that we got from calculation, formerly known as
  165. // strFormulaOut
  166. TQString strOutText;
  167. // the Formula object for the cell
  168. KSpread::Formula *formula;
  169. // Position and dimension of displayed text.
  170. // FIXME (comment): Which coordinate system? pixels? mm/cm? zoom?
  171. double textX;
  172. double textY;
  173. double textWidth;
  174. double textHeight;
  175. // result of "fm.ascent()" in makeLayout. used in offsetAlign.
  176. int fmAscent;
  177. // Pointers to neighboring cells.
  178. // FIXME (comment): Which order?
  179. Cell *nextCell;
  180. Cell *previousCell;
  181. bool hasExtra() const { return (cellExtra != 0); };
  182. Extra *extra();
  183. Format *format;
  184. TQ_UINT32 flags;
  185. private:
  186. // "Extra stuff", see explanation for Cell::Extra.
  187. Extra *cellExtra;
  188. };
  189. Cell::Private::Private()
  190. {
  191. // Some basic data.
  192. row = 0;
  193. column = 0;
  194. value = Value::empty();
  195. formula = 0;
  196. // Formatting
  197. textX = 0.0;
  198. textY = 0.0;
  199. textWidth = 0.0;
  200. textHeight = 0.0;
  201. fmAscent = 0;
  202. nextCell = 0;
  203. previousCell = 0;
  204. // Default is to not have the "extra" stuff in a cell.
  205. cellExtra = 0;
  206. format = 0;
  207. flags = 0;
  208. }
  209. Cell::Private::~Private()
  210. {
  211. delete cellExtra;
  212. delete formula;
  213. }
  214. Cell::Extra* Cell::Private::extra()
  215. {
  216. if ( !cellExtra ) {
  217. cellExtra = new Extra;
  218. cellExtra->conditions = 0;
  219. cellExtra->validity = 0;
  220. cellExtra->mergedXCells = 0;
  221. cellExtra->mergedYCells = 0;
  222. cellExtra->extraXCells = 0;
  223. cellExtra->extraYCells = 0;
  224. cellExtra->extraWidth = 0.0;
  225. cellExtra->extraHeight = 0.0;
  226. cellExtra->nbLines = 0;
  227. // cellExtra->highlight = TQColor(0,0,0);
  228. }
  229. return cellExtra;
  230. }
  231. /*****************************************************************************
  232. *
  233. * Cell
  234. *
  235. *****************************************************************************/
  236. Cell::Cell( Sheet * _sheet, int _column, int _row )
  237. {
  238. d = new Private;
  239. d->row = _row;
  240. d->column = _column;
  241. d->format = new Format(_sheet, _sheet->doc()->styleManager()->defaultStyle());
  242. d->format->setCell(this);
  243. clearAllErrors();
  244. }
  245. Cell::Cell( Sheet * _sheet, Style * _style, int _column, int _row )
  246. {
  247. d = new Private;
  248. d->row = _row;
  249. d->column = _column;
  250. d->format = new Format( _sheet, _style );
  251. d->format->setCell(this);
  252. clearAllErrors();
  253. }
  254. Format* Cell::format() const
  255. {
  256. return d->format;
  257. }
  258. // Return the sheet that this cell belongs to.
  259. Sheet * Cell::sheet() const
  260. {
  261. return d->format->sheet();
  262. }
  263. // Return true if this is the default cell.
  264. bool Cell::isDefault() const
  265. {
  266. return ( d->column == 0 );
  267. }
  268. // Return the row number of this cell.
  269. int Cell::row() const
  270. {
  271. // Make sure this isn't called for the default cell. This assert
  272. // can save you (could have saved me!) the hassle of some very
  273. // obscure bugs.
  274. if ( isDefault() )
  275. {
  276. kdWarning(36001) << "Error: Calling Cell::row() for default cell" << endl;
  277. return 0;
  278. }
  279. return d->row;
  280. }
  281. // Return the column number of this cell.
  282. //
  283. int Cell::column() const
  284. {
  285. // Make sure this isn't called for the default cell. This assert
  286. // can save you (could have saved me!) the hassle of some very
  287. // obscure bugs.
  288. if ( isDefault() )
  289. {
  290. kdWarning(36001) << "Error: Calling Cell::column() for default cell" << endl;
  291. return 0;
  292. }
  293. return d->column;
  294. }
  295. // Return the name of this cell, i.e. the string that the user would
  296. // use to reference it. Example: A1, BZ16
  297. //
  298. TQString Cell::name() const
  299. {
  300. return name( d->column, d->row );
  301. }
  302. // Return the name of any cell given by (col, row).
  303. //
  304. TQString Cell::name( int col, int row )
  305. {
  306. return columnName( col ) + TQString::number( row );
  307. }
  308. // Return the name of this cell, including the sheet name.
  309. // Example: sheet1!A5
  310. //
  311. TQString Cell::fullName() const
  312. {
  313. return fullName( sheet(), d->column, d->row );
  314. }
  315. // Return the full name of any cell given a sheet and (col, row).
  316. //
  317. TQString Cell::fullName( const Sheet* s, int col, int row )
  318. {
  319. return s->sheetName() + "!" + name( col, row );
  320. }
  321. // Return the symbolic name of the column of this cell. Examples: A, BB.
  322. //
  323. TQString Cell::columnName() const
  324. {
  325. return columnName( d->column );
  326. }
  327. TDELocale* Cell::locale() const
  328. {
  329. return d->format->sheet()->doc()->locale();
  330. }
  331. // Return the symbolic name of any column.
  332. //
  333. TQString Cell::columnName( uint column )
  334. {
  335. TQString str;
  336. unsigned digits = 1;
  337. unsigned offset = 0;
  338. column--;
  339. if( column > 4058115285U ) return TQString("@@@");
  340. for( unsigned limit = 26; column >= limit+offset; limit *= 26, digits++ )
  341. offset += limit;
  342. for( unsigned c = column - offset; digits; --digits, c/=26 )
  343. str.prepend( TQChar( 'A' + (c%26) ) );
  344. return str;
  345. }
  346. // Return true if this cell is a formula.
  347. //
  348. bool Cell::isFormula() const
  349. {
  350. return d->strText[0] == '=';
  351. }
  352. // Return the input text of this cell. This could, for instance, be a
  353. // formula.
  354. //
  355. // FIXME: These two functions are inconsistently named. It should be
  356. // either text() and outText() or strText() and strOutText().
  357. //
  358. TQString Cell::text() const
  359. {
  360. return d->strText;
  361. }
  362. // Return the out text, i.e. the text that is visible in the cells
  363. // square when shown. This could, for instance, be the calculated
  364. // result of a formula.
  365. //
  366. TQString Cell::strOutText() const
  367. {
  368. return d->strOutText;
  369. }
  370. Formula *Cell::formula () const
  371. {
  372. return d->formula;
  373. }
  374. // Return the value of this cell.
  375. //
  376. const Value Cell::value() const
  377. {
  378. return d->value;
  379. }
  380. // Set the value of this cell. It also clears all errors if the value
  381. // itself is not an error.
  382. //
  383. // In addition to this, it calculates the outstring and sets the dirty
  384. // flags so that a redraw is forced.
  385. //
  386. void Cell::setValue( const Value& v )
  387. {
  388. if (v.type() != Value::Error)
  389. clearAllErrors();
  390. //If the value has not changed then we don't need to do anything
  391. //(ie. no need to relayout, update dependant cells etc.),
  392. //unless this cell contains a formula, in which case its dependancies might have changed
  393. //even though the value has not. For example, if this cell was previously empty (and its value is
  394. //therefore empty) and a new dependency upon an empty cell has been added. The new value would still
  395. //be empty, but the dependencies need to be updated (via the call to valueChanged() below).
  396. if ( ( d->value == v ) && ( !isFormula() ) )
  397. return;
  398. d->value = v;
  399. setFlag(Flag_LayoutDirty);
  400. setFlag(Flag_TextFormatDirty);
  401. // Format and set the outText.
  402. setOutputText();
  403. // Set the displayed text, if we hold an error value.
  404. if (d->value.type() == Value::Error)
  405. d->strOutText = d->value.errorMessage ();
  406. // Value of the cell has changed - trigger necessary actions
  407. valueChanged ();
  408. if ( !format()->sheet()->isLoading() )
  409. format()->sheet()->setRegionPaintDirty(cellRect());
  410. }
  411. void Cell::setCellValue (const Value &v, FormatType fmtType, const TQString &txt)
  412. {
  413. if ( !txt.isNull() )
  414. {
  415. d->strText = txt;
  416. if ( isFormula() )
  417. makeFormula();
  418. }
  419. else if ( !isFormula() )
  420. d->strText = sheet()->doc()->converter()->asString (v).asString();
  421. if (fmtType != No_format)
  422. format()->setFormatType (fmtType);
  423. setValue (v);
  424. }
  425. // FIXME: Continue commenting and cleaning here (ingwa)
  426. Cell* Cell::previousCell() const
  427. {
  428. return d->previousCell;
  429. }
  430. Cell* Cell::nextCell() const
  431. {
  432. return d->nextCell;
  433. }
  434. void Cell::setPreviousCell( Cell* c )
  435. {
  436. d->previousCell = c;
  437. }
  438. void Cell::setNextCell( Cell* c )
  439. {
  440. d->nextCell = c;
  441. }
  442. Validity* Cell::getValidity( int newStruct )
  443. {
  444. if ( (!newStruct) && (!d->hasExtra()))
  445. //we don't have validity struct and we don't want one
  446. return 0;
  447. if( ( d->extra()->validity == 0 ) && ( newStruct == -1 ) )
  448. d->extra()->validity = new Validity;
  449. return d->extra()->validity;
  450. }
  451. void Cell::removeValidity()
  452. {
  453. if (!d->hasExtra())
  454. return;
  455. delete d->extra()->validity;
  456. d->extra()->validity = 0;
  457. }
  458. void Cell::copyFormat( const int column , const int row )
  459. {
  460. const Cell * cell = format()->sheet()->cellAt( column , row );
  461. copyFormat( cell );
  462. }
  463. void Cell::copyFormat( const Cell* cell )
  464. {
  465. Q_ASSERT(cell);
  466. d->value.setFormat(cell->d->value.format());
  467. format()->copy(*(cell->format()));
  468. /*format()->setAlign( cell->format()->align( _column, _row ) );
  469. format()->setAlignY( cell->format()->alignY( _column, _row ) );
  470. format()->setTextFont( cell->format()->textFont( _column, _row ) );
  471. format()->setTextColor( cell->format()->textColor( _column, _row ) );
  472. format()->setBgColor( cell->bgColor( _column, _row) );
  473. setLeftBorderPen( cell->leftBorderPen( _column, _row ) );
  474. setTopBorderPen( cell->topBorderPen( _column, _row ) );
  475. setBottomBorderPen( cell->bottomBorderPen( _column, _row ) );
  476. setRightBorderPen( cell->rightBorderPen( _column, _row ) );
  477. format()->setFallDiagonalPen( cell->format()->fallDiagonalPen( _column, _row ) );
  478. format()->setGoUpDiagonalPen( cell->format()->goUpDiagonalPen( _column, _row ) );
  479. format()->setBackGroundBrush( cell->backGroundBrush( _column, _row) );
  480. format()->setPrecision( cell->format()->precision( _column, _row ) );
  481. format()->setPrefix( cell->format()->prefix( _column, _row ) );
  482. format()->setPostfix( cell->format()->postfix( _column, _row ) );
  483. format()->setFloatFormat( cell->format()->floatFormat( _column, _row ) );
  484. format()->setFloatColor( cell->format()->floatColor( _column, _row ) );
  485. format()->setMultiRow( cell->format()->multiRow( _column, _row ) );
  486. format()->setVerticalText( cell->format()->verticalText( _column, _row ) );
  487. format()->setDontPrintText( cell->format()->getDontprintText(_column, _row ) );
  488. format()->setNotProtected( cell->format()->notProtected(_column, _row ) );
  489. format()->setHideAll(cell->format()->isHideAll(_column, _row ) );
  490. format()->setHideFormula(cell->format()->isHideFormula(_column, _row ) );
  491. format()->setIndent( cell->format()->getIndent(_column, _row ) );
  492. format()->setAngle( cell->format()->getAngle(_column, _row) );
  493. format()->setFormatType( cell->format()->getFormatType(_column, _row) );
  494. Format::Currency c;
  495. if ( cell->format()->currencyInfo( c ) )
  496. format()->setCurrency( c );*/
  497. TQValueList<Conditional> conditionList = cell->conditionList();
  498. if (d->hasExtra())
  499. delete d->extra()->conditions;
  500. if ( cell->d->hasExtra() && cell->d->extra()->conditions )
  501. setConditionList( conditionList );
  502. else
  503. if (d->hasExtra())
  504. d->extra()->conditions = 0;
  505. /*format()->setComment( cell->format()->comment( _column, _row ) );*/
  506. }
  507. void Cell::copyAll( Cell *cell )
  508. {
  509. Q_ASSERT( !isDefault() ); // trouble ahead...
  510. copyFormat( cell );
  511. copyContent( cell );
  512. }
  513. void Cell::copyContent( const Cell* cell )
  514. {
  515. Q_ASSERT( !isDefault() ); // trouble ahead...
  516. if (cell->isFormula() && cell->column() > 0 && cell->row() > 0)
  517. {
  518. // change all the references, e.g. from A1 to A3 if copying
  519. // from e.g. B2 to B4
  520. TQString d = cell->encodeFormula();
  521. setCellText( cell->decodeFormula( d ) );
  522. }
  523. else
  524. setCellText( cell->text() );
  525. }
  526. void Cell::defaultStyle()
  527. {
  528. format()->defaultStyleFormat();
  529. if (!d->hasExtra())
  530. return;
  531. if ( d->extra()->conditions )
  532. {
  533. delete d->extra()->conditions;
  534. d->extra()->conditions = 0;
  535. }
  536. delete d->extra()->validity;
  537. d->extra()->validity = 0L;
  538. }
  539. // Merge a number of cells, i.e. make this cell obscure a number of
  540. // other cells. If _x and _y == 0, then the merging is removed.
  541. void Cell::mergeCells( int _col, int _row, int _x, int _y )
  542. {
  543. // Start by unobscuring the cells that we obscure right now
  544. int extraXCells = d->hasExtra() ? d->extra()->extraXCells : 0;
  545. int extraYCells = d->hasExtra() ? d->extra()->extraYCells : 0;
  546. for ( int x = _col; x <= _col + extraXCells; ++x ) {
  547. for ( int y = _row; y <= _row + extraYCells; ++y ) {
  548. if ( x != _col || y != _row )
  549. format()->sheet()->nonDefaultCell( x, y )->unobscure(this);
  550. }
  551. }
  552. // If no merging, then remove all traces, and return.
  553. if ( _x == 0 && _y == 0 ) {
  554. clearFlag( Flag_Merged );
  555. if (d->hasExtra()) {
  556. d->extra()->extraXCells = 0;
  557. d->extra()->extraYCells = 0;
  558. d->extra()->extraWidth = 0.0;
  559. d->extra()->extraHeight = 0.0;
  560. d->extra()->mergedXCells = 0;
  561. d->extra()->mergedYCells = 0;
  562. }
  563. // Refresh the layout
  564. setFlag( Flag_LayoutDirty );
  565. return;
  566. }
  567. // At this point, we know that we will merge some cells.
  568. setFlag(Flag_Merged);
  569. d->extra()->extraXCells = _x;
  570. d->extra()->extraYCells = _y;
  571. d->extra()->mergedXCells = _x;
  572. d->extra()->mergedYCells = _y;
  573. // Obscure the cells
  574. for ( int x = _col; x <= _col + _x; ++x ) {
  575. for ( int y = _row; y <= _row + _y; ++y ) {
  576. if ( x != _col || y != _row )
  577. format()->sheet()->nonDefaultCell( x, y )->obscure( this, true );
  578. }
  579. }
  580. // Refresh the layout
  581. setFlag( Flag_LayoutDirty );
  582. }
  583. void Cell::move( int col, int row )
  584. {
  585. setLayoutDirtyFlag();
  586. setCalcDirtyFlag();
  587. setDisplayDirtyFlag();
  588. //int ex = extraXCells();
  589. //int ey = d->extra()->extraYCells();
  590. if (d->hasExtra())
  591. d->extra()->obscuringCells.clear();
  592. // Unobscure the objects we obscure right now
  593. int extraXCells = d->hasExtra() ? d->extra()->extraXCells : 0;
  594. int extraYCells = d->hasExtra() ? d->extra()->extraYCells : 0;
  595. for( int x = d->column; x <= d->column + extraXCells; ++x )
  596. for( int y = d->row; y <= d->row + extraYCells; ++y )
  597. if ( x != d->column || y != d->row )
  598. {
  599. Cell *cell = format()->sheet()->nonDefaultCell( x, y );
  600. cell->unobscure(this);
  601. }
  602. d->column = col;
  603. d->row = row;
  604. if (d->hasExtra())
  605. {
  606. // d->extra()->extraXCells = 0;
  607. // d->extra()->extraYCells = 0;
  608. d->extra()->mergedXCells = 0;
  609. d->extra()->mergedYCells = 0;
  610. }
  611. // Cell value has been changed (because we're another cell now).
  612. valueChanged ();
  613. }
  614. void Cell::setLayoutDirtyFlag( bool format )
  615. {
  616. setFlag( Flag_LayoutDirty );
  617. if ( format )
  618. setFlag( Flag_TextFormatDirty );
  619. if (!d->hasExtra())
  620. return;
  621. TQValueList<Cell*>::iterator it = d->extra()->obscuringCells.begin();
  622. TQValueList<Cell*>::iterator end = d->extra()->obscuringCells.end();
  623. for ( ; it != end; ++it ) {
  624. (*it)->setLayoutDirtyFlag( format );
  625. }
  626. }
  627. bool Cell::needsPrinting() const
  628. {
  629. if ( isDefault() )
  630. return false;
  631. if ( !d->strText.stripWhiteSpace().isEmpty() ) {
  632. return true;
  633. }
  634. // Cell borders?
  635. if ( format()->hasProperty( Format::PTopBorder )
  636. || format()->hasProperty( Format::PLeftBorder )
  637. || format()->hasProperty( Format::PRightBorder )
  638. || format()->hasProperty( Format::PBottomBorder )
  639. || format()->hasProperty( Format::PFallDiagonal )
  640. || format()->hasProperty( Format::PGoUpDiagonal ) ) {
  641. return true;
  642. }
  643. // Background color or brush?
  644. if ( format()->hasProperty( Format::PBackgroundBrush ) ) {
  645. const TQBrush& brush=backGroundBrush(column(),row());
  646. //Only brushes that are visible (ie. they have a brush style and are not white)
  647. //need to be drawn
  648. if ( (brush.style() != TQt::NoBrush) &&
  649. (brush.color() != TQt::white || brush.pixmap()) )
  650. return true;
  651. }
  652. if ( format()->hasProperty( Format::PBackgroundColor ) ) {
  653. kdDebug() << "needsPrinting: Has background colour" << endl;
  654. TQColor backgroundColor=bgColor(column(),row());
  655. //We don't need to print anything if the background is white
  656. if (backgroundColor != TQt::white)
  657. return true;
  658. }
  659. return false;
  660. }
  661. bool Cell::isEmpty() const
  662. {
  663. return isDefault() || d->strText.isEmpty();
  664. }
  665. // Return true if this cell is obscured by some other cell.
  666. bool Cell::isObscured() const
  667. {
  668. if (!d->hasExtra())
  669. return false;
  670. return !( d->extra()->obscuringCells.isEmpty() );
  671. }
  672. // Return true if this cell is part of a merged cell, but not the
  673. // master cell.
  674. bool Cell::isPartOfMerged() const
  675. {
  676. if (!d->hasExtra())
  677. return false;
  678. TQValueList<Cell*>::const_iterator it = d->extra()->obscuringCells.begin();
  679. TQValueList<Cell*>::const_iterator end = d->extra()->obscuringCells.end();
  680. for ( ; it != end; ++it ) {
  681. Cell *cell = *it;
  682. if (cell->doesMergeCells()) {
  683. // The cell might merge extra cells, and then overlap even
  684. // beyond that so just knowing that the obscuring cell merges
  685. // extra isn't enough. We have to know that this cell is one of
  686. // the ones it is forcing over.
  687. if (column() <= cell->column() + cell->d->extra()->mergedXCells
  688. && row() <= cell->row() + cell->mergedYCells() )
  689. return true;
  690. }
  691. }
  692. return false;
  693. }
  694. // Return the cell that obscures this one. If no cell is obscuring,
  695. // then return this. This method is slightly complicated because we
  696. // can have several layers of obscuring.
  697. //
  698. // Update: it seems that if we do an actual merge, then the obscuring
  699. // cell is prepended and if just expanding, then it is appended. This
  700. // means that we should be able to just look at the first one.
  701. Cell *Cell::ultimateObscuringCell() const
  702. {
  703. if (!d->hasExtra())
  704. return (Cell *) this;
  705. else if (d->extra()->obscuringCells.isEmpty())
  706. return (Cell *) this;
  707. else
  708. return d->extra()->obscuringCells.first();
  709. #if 0
  710. TQValueList<Cell*>::const_iterator it = d->extra()->obscuringCells.begin();
  711. TQValueList<Cell*>::const_iterator end = d->extra()->obscuringCells.end();
  712. for ( ; it != end; ++it ) {
  713. Cell *cell = *it;
  714. if (cell->doesMergeCells()) {
  715. // The cell might merge extra cells, and then overlap even
  716. // beyond that so just knowing that the obscuring cell merges
  717. // extra isn't enough. We have to know that this cell is one of
  718. // the ones it is forcing over.
  719. if (column() <= cell->column() + cell->d->extra()->mergedXCells
  720. && row() <= cell->row() + cell->mergedYCells() )
  721. return true;
  722. }
  723. }
  724. return false;
  725. #endif
  726. }
  727. TQValueList<Cell*> Cell::obscuringCells() const
  728. {
  729. if (!d->hasExtra())
  730. {
  731. TQValueList<Cell*> empty;
  732. return empty;
  733. }
  734. return d->extra()->obscuringCells;
  735. }
  736. void Cell::clearObscuringCells()
  737. {
  738. if (!d->hasExtra())
  739. return;
  740. d->extra()->obscuringCells.clear();
  741. }
  742. void Cell::obscure( Cell *cell, bool isForcing )
  743. {
  744. if (d->hasExtra())
  745. {
  746. d->extra()->obscuringCells.remove( cell ); // removes *all* occurrences
  747. cell->clearObscuringCells();
  748. }
  749. if ( isForcing )
  750. {
  751. d->extra()->obscuringCells.prepend( cell );
  752. }
  753. else
  754. {
  755. d->extra()->obscuringCells.append( cell );
  756. }
  757. setFlag(Flag_LayoutDirty);
  758. format()->sheet()->setRegionPaintDirty( cellRect() );
  759. }
  760. void Cell::unobscure( Cell * cell )
  761. {
  762. if (d->hasExtra())
  763. d->extra()->obscuringCells.remove( cell );
  764. setFlag( Flag_LayoutDirty );
  765. format()->sheet()->setRegionPaintDirty( cellRect() );
  766. }
  767. TQString Cell::encodeFormula( bool _era, int _col, int _row ) const
  768. {
  769. if ( _col == -1 )
  770. _col = d->column;
  771. if ( _row == -1 )
  772. _row = d->row;
  773. TQString erg = "";
  774. if(d->strText.isEmpty())
  775. return d->strText;
  776. bool fix1 = false;
  777. bool fix2 = false;
  778. bool onNumber = false;
  779. unsigned int pos = 0;
  780. const unsigned int length = d->strText.length();
  781. // All this can surely be made 10 times faster, but I just "ported" it to TQString
  782. // without any attempt to optimize things -- this is really brittle (Werner)
  783. while ( pos < length )
  784. {
  785. if ( d->strText[pos] == '"' )
  786. {
  787. erg += d->strText[pos++];
  788. while ( pos < length && d->strText[pos] != '"' ) // till the end of the world^H^H^H "string"
  789. {
  790. erg += d->strText[pos++];
  791. // Allow escaped double quotes (\")
  792. if ( pos < length && d->strText[pos] == '\\' && d->strText[pos+1] == '"' )
  793. {
  794. erg += d->strText[pos++];
  795. erg += d->strText[pos++];
  796. }
  797. }
  798. if ( pos < length ) // also copy the trailing double quote
  799. erg += d->strText[pos++];
  800. onNumber = false;
  801. }
  802. else if ( d->strText[pos].isDigit() )
  803. {
  804. erg += d->strText[pos++];
  805. fix1 = fix2 = false;
  806. onNumber = true;
  807. }
  808. else if ( d->strText[pos] != '$' && !d->strText[pos].isLetter() )
  809. {
  810. erg += d->strText[pos++];
  811. fix1 = fix2 = false;
  812. onNumber = false;
  813. }
  814. else
  815. {
  816. TQString tmp = "";
  817. if ( d->strText[pos] == '$' )
  818. {
  819. tmp = "$";
  820. pos++;
  821. fix1 = true;
  822. }
  823. if ( d->strText[pos].isLetter() )
  824. {
  825. TQString buffer;
  826. unsigned int pos2 = 0;
  827. while ( pos < length && d->strText[pos].isLetter() )
  828. {
  829. tmp += d->strText[pos];
  830. buffer[pos2++] = d->strText[pos++];
  831. }
  832. if ( d->strText[pos] == '$' )
  833. {
  834. tmp += "$";
  835. pos++;
  836. fix2 = true;
  837. }
  838. if ( d->strText[pos].isDigit() )
  839. {
  840. const unsigned int oldPos = pos;
  841. while ( pos < length && d->strText[pos].isDigit() ) ++pos;
  842. int row = 0;
  843. if ( pos != oldPos )
  844. row = d->strText.mid(oldPos, pos-oldPos).toInt();
  845. // Is it a sheet name || is it a function name like DEC2HEX
  846. /* or if we're parsing a number, this could just be the
  847. exponential part of it (1.23E4) */
  848. if ( ( d->strText[pos] == '!' ) ||
  849. d->strText[pos].isLetter() ||
  850. onNumber )
  851. {
  852. erg += tmp;
  853. fix1 = fix2 = false;
  854. pos = oldPos;
  855. }
  856. else // It must be a cell identifier
  857. {
  858. //now calculate the row as integer value
  859. int col = 0;
  860. col = util_decodeColumnLabelText( buffer );
  861. if ( fix1 )
  862. erg += TQString( "$%1" ).arg( col );
  863. else
  864. if (_era)
  865. erg += TQChar(0xA7) + TQString( "%1" ).arg( col );
  866. else
  867. erg += TQString( "#%1" ).arg( col - _col );
  868. if ( fix2 )
  869. erg += TQString( "$%1#").arg( row );
  870. else
  871. if (_era)
  872. erg += TQChar(0xA7) + TQString( "%1#" ).arg( row );
  873. else
  874. erg += TQString( "#%1#" ).arg( row - _row );
  875. }
  876. }
  877. else
  878. {
  879. erg += tmp;
  880. fix1 = fix2 = false;
  881. }
  882. }
  883. else
  884. {
  885. erg += tmp;
  886. fix1 = false;
  887. }
  888. onNumber = false;
  889. }
  890. }
  891. return erg;
  892. }
  893. TQString Cell::decodeFormula( const TQString &_text, int _col, int _row) const
  894. {
  895. if ( _col == -1 )
  896. _col = d->column;
  897. if ( _row == -1 )
  898. _row = d->row;
  899. TQString erg = "";
  900. unsigned int pos = 0;
  901. const unsigned int length = _text.length();
  902. if ( _text.isEmpty() )
  903. return TQString();
  904. while ( pos < length )
  905. {
  906. if ( _text[pos] == '"' )
  907. {
  908. erg += _text[pos++];
  909. while ( pos < length && _text[pos] != '"' )
  910. {
  911. erg += _text[pos++];
  912. // Allow escaped double quotes (\")
  913. if ( pos < length && _text[pos] == '\\' && _text[pos+1] == '"' )
  914. {
  915. erg += _text[pos++];
  916. erg += _text[pos++];
  917. }
  918. }
  919. if ( pos < length )
  920. erg += _text[pos++];
  921. }
  922. else if ( _text[pos] == '#' || _text[pos] == '$' || _text[pos] == TQChar(0xA7))
  923. {
  924. bool abs1 = false;
  925. bool abs2 = false;
  926. bool era1 = false; // if 1st is relative but encoded absolutely
  927. bool era2 = false;
  928. TQChar _t = _text[pos++];
  929. if ( _t == '$' )
  930. abs1 = true;
  931. else if ( _t == TQChar(0xA7) )
  932. era1 = true;
  933. int col = 0;
  934. unsigned int oldPos = pos;
  935. while ( pos < length && ( _text[pos].isDigit() || _text[pos] == '-' ) ) ++pos;
  936. if ( pos != oldPos )
  937. col = _text.mid(oldPos, pos-oldPos).toInt();
  938. if ( !abs1 && !era1 )
  939. col += _col;
  940. // Skip '#' or '$'
  941. _t = _text[pos++];
  942. if ( _t == '$' )
  943. abs2 = true;
  944. else if ( _t == TQChar(0xA7) )
  945. era2 = true;
  946. int row = 0;
  947. oldPos = pos;
  948. while ( pos < length && ( _text[pos].isDigit() || _text[pos] == '-' ) ) ++pos;
  949. if ( pos != oldPos )
  950. row = _text.mid(oldPos, pos-oldPos).toInt();
  951. if ( !abs2 && !era2)
  952. row += _row;
  953. // Skip '#' or '$'
  954. ++pos;
  955. if ( row < 1 || col < 1 || row > KS_rowMax || col > KS_colMax )
  956. {
  957. kdDebug(36001) << "Cell::decodeFormula: row or column out of range (col: " << col << " | row: " << row << ")" << endl;
  958. erg = "=\"#### " + i18n("REFERENCE TO COLUMN OR ROW IS OUT OF RANGE") + "\"";
  959. return erg;
  960. }
  961. if ( abs1 )
  962. erg += "$";
  963. erg += Cell::columnName(col); //Get column text
  964. if ( abs2 )
  965. erg += "$";
  966. erg += TQString::number( row );
  967. }
  968. else
  969. erg += _text[pos++];
  970. }
  971. return erg;
  972. }
  973. void Cell::freeAllObscuredCells()
  974. {
  975. //
  976. // Free all obscured cells.
  977. //
  978. if (!d->hasExtra())
  979. return;
  980. for ( int x = d->column + d->extra()->mergedXCells;
  981. x <= d->column + d->extra()->extraXCells; ++x ) {
  982. for ( int y = d->row + d->extra()->mergedYCells;
  983. y <= d->row + d->extra()->extraYCells; ++y ) {
  984. if ( x != d->column || y != d->row ) {
  985. Cell *cell = format()->sheet()->cellAt( x, y );
  986. cell->unobscure(this);
  987. }
  988. }
  989. }
  990. d->extra()->extraXCells = d->extra()->mergedXCells;
  991. d->extra()->extraYCells = d->extra()->mergedYCells;
  992. }
  993. // ----------------------------------------------------------------
  994. // Layout
  995. // Recalculate the entire layout. This includes the following members:
  996. //
  997. // d->textX, d->textY
  998. // d->textWidth, d->textHeight
  999. // d->fmAscent
  1000. // d->extra()->extraXCells, d->extra()->extraYCells
  1001. // d->extra()->extraWidth, d->extra()->extraHeight
  1002. // d->extra()->nbLines (if multirow)
  1003. //
  1004. // and, of course,
  1005. //
  1006. // d->strOutText
  1007. //
  1008. void Cell::makeLayout( TQPainter &_painter, int _col, int _row )
  1009. {
  1010. // Are _col and _row really needed ?
  1011. //
  1012. // Yes they are: they are useful if this is the default layout, in
  1013. // which case d->row and d->column are 0 and 0, but _col and _row
  1014. // are the real coordinates of the cell.
  1015. // There is no need to remake the layout if it hasn't changed.
  1016. if ( !testFlag( Flag_LayoutDirty ) )
  1017. return;
  1018. // Some initializations.
  1019. if (d->hasExtra())
  1020. d->extra()->nbLines = 0;
  1021. clearFlag( Flag_CellTooShortX );
  1022. clearFlag( Flag_CellTooShortY );
  1023. // Initiate the cells that this one is obscuring to the ones that
  1024. // are actually merged.
  1025. freeAllObscuredCells();
  1026. if (d->hasExtra())
  1027. mergeCells( d->column, d->row,
  1028. d->extra()->mergedXCells, d->extra()->mergedYCells );
  1029. // If the column for this cell is hidden or the row is too low,
  1030. // there is no use in remaking the layout.
  1031. ColumnFormat *cl1 = format()->sheet()->columnFormat( _col );
  1032. RowFormat *rl1 = format()->sheet()->rowFormat( _row );
  1033. if ( cl1->isHide()
  1034. || ( rl1->dblHeight() <= format()->sheet()->doc()->unzoomItY( 2 ) ) ) {
  1035. clearFlag( Flag_LayoutDirty );
  1036. return;
  1037. }
  1038. // Recalculate the output text, d->strOutText.
  1039. setOutputText();
  1040. // Empty text? Reset the outstring and, if this is the default
  1041. // cell, return.
  1042. if ( d->strOutText.isEmpty() ) {
  1043. d->strOutText = TQString();
  1044. if ( isDefault() ) {
  1045. clearFlag( Flag_LayoutDirty );
  1046. return;
  1047. }
  1048. }
  1049. // Up to here, we have just cared about the contents, not the
  1050. // painting of it. Now it is time to see if the contents fits into
  1051. // the cell and, if not, maybe rearrange the outtext a bit.
  1052. //
  1053. // First, Determine the correct font with zoom taken into account,
  1054. // and apply it to _painter. Then calculate text dimensions, i.e.
  1055. // d->textWidth and d->textHeight.
  1056. applyZoomedFont( _painter, _col, _row );
  1057. textSize( _painter );
  1058. //
  1059. // Calculate the size of the cell
  1060. //
  1061. RowFormat *rl = format()->sheet()->rowFormat( d->row );
  1062. ColumnFormat *cl = format()->sheet()->columnFormat( d->column );
  1063. double width = cl->dblWidth();
  1064. double height = rl->dblHeight();
  1065. // Calculate extraWidth and extraHeight if we have a merged cell.
  1066. if ( testFlag( Flag_Merged ) ) {
  1067. int extraXCells = d->hasExtra() ? d->extra()->extraXCells : 0;
  1068. int extraYCells = d->hasExtra() ? d->extra()->extraYCells : 0;
  1069. // FIXME: Introduce double extraWidth/Height here and use them
  1070. // instead (see FIXME about this in paintCell()).
  1071. for ( int x = _col + 1; x <= _col + extraXCells; x++ )
  1072. width += format()->sheet()->columnFormat( x )->dblWidth();
  1073. for ( int y = _row + 1; y <= _row + extraYCells; y++ )
  1074. height += format()->sheet()->rowFormat( y )->dblHeight();
  1075. }
  1076. // Cache the newly calculated extraWidth and extraHeight if we have
  1077. // already allocated a struct for it. Otherwise it will be zero, so
  1078. // don't bother.
  1079. if (d->hasExtra()) {
  1080. d->extra()->extraWidth = width;
  1081. d->extra()->extraHeight = height;
  1082. }
  1083. TQFontMetrics fm = _painter.fontMetrics();
  1084. d->fmAscent = fm.ascent();
  1085. // Check if we need to break the line into multiple lines and are
  1086. // allowed to do so. If so, set `lines' to the number of lines that
  1087. // are needed to fit into the total width of the combined cell.
  1088. //
  1089. // Also recalculate d->textHeight, d->textWidth, d->extra->nbLines
  1090. // and d->strOutText.
  1091. //
  1092. int lines = 1;
  1093. if ( d->textWidth > (width - 2 * BORDER_SPACE
  1094. - format()->leftBorderWidth( _col, _row )
  1095. - format()->rightBorderWidth( _col, _row ) )
  1096. && format()->multiRow( _col, _row ) )
  1097. {
  1098. // Copy of d->strOutText but without the newlines.
  1099. // TQString o = d->strOutText.replace( TQChar('\n'), " " );
  1100. // don't remove the existing LF, these are intended line wraps (whishlist #9881)
  1101. TQString o = d->strOutText;
  1102. // Break the line at appropriate places, i.e. spaces, if
  1103. // necessary. This means to change the spaces where breaks occur
  1104. // into newlines.
  1105. if ( o.find(' ') != -1 )
  1106. {
  1107. d->strOutText = "";
  1108. // Make sure that we have a space at the end.
  1109. o += ' ';
  1110. int start = 0; // Start of the line we are handling now
  1111. int breakpos = 0; // The next candidate pos to break the string
  1112. int pos1 = 0;
  1113. int availableWidth = (int) ( width - 2 * BORDER_SPACE
  1114. - format()->leftBorderWidth( _col, _row )
  1115. - format()->rightBorderWidth( _col, _row ) );
  1116. do {
  1117. breakpos = o.find( ' ', breakpos );
  1118. int linefeed = o.find( '\n', pos1 );
  1119. // kdDebug() << "start: " << start << "; breakpos: " << breakpos << "; pos1: " << pos1 << "; linefeed: " << linefeed << endl;
  1120. //don't miss LF as a position to calculate current lineWidth
  1121. int work_breakpos = breakpos;
  1122. if (pos1 < linefeed && linefeed < breakpos)
  1123. work_breakpos = linefeed;
  1124. double lineWidth = format()->sheet()->doc()
  1125. ->unzoomItX( fm.width( d->strOutText.mid( start, (pos1 - start) )
  1126. + o.mid( pos1, work_breakpos - pos1 ) ) );
  1127. //linefeed could be -1 when no linefeed is found!
  1128. if (breakpos > linefeed && linefeed > 0)
  1129. {
  1130. // kdDebug() << "applying linefeed to start;" << endl;
  1131. start = linefeed;
  1132. lines++;
  1133. }
  1134. if ( lineWidth <= availableWidth ) {
  1135. // We have room for the rest of the line. End it here.
  1136. d->strOutText += o.mid( pos1, breakpos - pos1 );
  1137. pos1 = breakpos;
  1138. }
  1139. else {
  1140. // Still not enough room. Try to split further.
  1141. if ( o.at( pos1 ) == ' ' )
  1142. pos1++;
  1143. if ( pos1 != 0 && breakpos != -1 ) {
  1144. d->strOutText += "\n" + o.mid( pos1, breakpos - pos1 );
  1145. lines++;
  1146. }
  1147. else
  1148. d->strOutText += o.mid( pos1, breakpos - pos1 );
  1149. start = pos1;
  1150. pos1 = breakpos;
  1151. }
  1152. breakpos++;
  1153. } while( o.find( ' ', breakpos ) != -1 );
  1154. }
  1155. else
  1156. {
  1157. lines = o.contains('\n');
  1158. }
  1159. d->textHeight *= lines;
  1160. if (lines > 1)
  1161. d->extra()->nbLines = lines;
  1162. d->textX = 0.0;
  1163. // Calculate the maximum width, taking into account linebreaks,
  1164. // and put it in d->textWidth.
  1165. TQString t;
  1166. int i;
  1167. int pos = 0;
  1168. d->textWidth = 0.0;
  1169. do {
  1170. i = d->strOutText.find( "\n", pos );
  1171. if ( i == -1 )
  1172. t = d->strOutText.mid( pos, d->strOutText.length() - pos );
  1173. else {
  1174. t = d->strOutText.mid( pos, i - pos );
  1175. pos = i + 1;
  1176. }
  1177. double tw = format()->sheet()->doc()->unzoomItX( fm.width( t ) );
  1178. if ( tw > d->textWidth )
  1179. d->textWidth = tw;
  1180. } while ( i != -1 );
  1181. }
  1182. // Calculate d->textX and d->textY
  1183. offsetAlign( _col, _row );
  1184. int a = effAlignX();
  1185. // Get indentation. This is only used for left aligned text.
  1186. double indent = 0.0;
  1187. if ( a == Format::Left && !isEmpty() )
  1188. indent = format()->getIndent( _col, _row );
  1189. // Set Flag_CellTooShortX if the text is vertical or angled, and too
  1190. // high for the cell.
  1191. if ( format()->verticalText( _col, _row ) || format()->getAngle( _col, _row ) != 0 ) {
  1192. //RowFormat *rl = format()->sheet()->rowFormat( _row );
  1193. if ( d->textHeight >= height/*rl->dblHeight()*/ )
  1194. setFlag( Flag_CellTooShortX );
  1195. }
  1196. // Do we have to occupy additional cells to the right? This is only
  1197. // done for cells that have no merged cells in the Y direction.
  1198. //
  1199. // FIXME: Check if all cells along the merged edge to the right are
  1200. // empty and use the extra space? No, probably not.
  1201. //
  1202. if ( d->textWidth + indent > ( width - 2 * BORDER_SPACE
  1203. - format()->leftBorderWidth( _col, _row )
  1204. - format()->rightBorderWidth( _col, _row ) )
  1205. && ( !d->hasExtra() || d->extra()->mergedYCells == 0 ) )
  1206. {
  1207. int c = d->column;
  1208. // Find free cells to the right of this one.
  1209. int end = 0;
  1210. while ( !end ) {
  1211. ColumnFormat *cl2 = format()->sheet()->columnFormat( c + 1 );
  1212. Cell *cell = format()->sheet()->visibleCellAt( c + 1, d->row );
  1213. if ( cell->isEmpty() ) {
  1214. width += cl2->dblWidth() - 1;
  1215. c++;
  1216. // Enough space?
  1217. if ( d->textWidth + indent <= ( width - 2 * BORDER_SPACE
  1218. - format()->leftBorderWidth( _col, _row )
  1219. - format()->rightBorderWidth( _col, _row ) ) )
  1220. end = 1;
  1221. }
  1222. else
  1223. // Not enough space, but the next cell is not empty
  1224. end = -1;
  1225. }
  1226. // Try to use additional space from the neighboring cells that
  1227. // were calculated in the last step. This is the place that we
  1228. // set d->extra()->extraXCells and d->extra()->extraWidth.
  1229. //
  1230. // Currently this is only done for left aligned cells. We have to
  1231. // check to make sure we haven't already force-merged enough cells
  1232. //
  1233. // FIXME: Why not right/center aligned text?
  1234. //
  1235. // FIXME: Shouldn't we check to see if end == -1 here before
  1236. // setting Flag_CellTooShortX?
  1237. //
  1238. if ( format()->align( _col, _row ) == Format::Left
  1239. || ( format()->align( _col, _row ) == Format::Undefined
  1240. && !value().isNumber() ) )
  1241. {
  1242. if ( c - d->column > d->extra()->mergedXCells ) {
  1243. d->extra()->extraXCells = c - d->column;
  1244. d->extra()->extraWidth = width;
  1245. for ( int i = d->column + 1; i <= c; ++i ) {
  1246. Cell *cell = format()->sheet()->nonDefaultCell( i, d->row );
  1247. cell->obscure( this );
  1248. }
  1249. // Not enough space
  1250. if ( end == -1 )
  1251. setFlag( Flag_CellTooShortX );
  1252. }
  1253. else
  1254. setFlag( Flag_CellTooShortX );
  1255. }
  1256. else
  1257. setFlag( Flag_CellTooShortX );
  1258. }
  1259. // Do we have to occupy additional cells at the bottom ?
  1260. //
  1261. // FIXME: Setting to make the current cell grow.
  1262. //
  1263. if ( format()->multiRow( _col, _row )
  1264. && d->textHeight > ( height - 2 * BORDER_SPACE
  1265. - format()->topBorderWidth( _col, _row )
  1266. - format()->bottomBorderWidth( _col, _row ) ) )
  1267. {
  1268. int r = d->row;
  1269. int end = 0;
  1270. // Find free cells bottom to this one
  1271. while ( !end ) {
  1272. RowFormat *rl2 = format()->sheet()->rowFormat( r + 1 );
  1273. Cell *cell = format()->sheet()->visibleCellAt( d->column, r + 1 );
  1274. if ( cell->isEmpty() ) {
  1275. height += rl2->dblHeight() - 1.0;
  1276. r++;
  1277. // Enough space ?
  1278. if ( d->textHeight <= ( height - 2 * BORDER_SPACE
  1279. - format()->topBorderWidth( _col, _row )
  1280. - format()->bottomBorderWidth( _col, _row ) ) )
  1281. end = 1;
  1282. }
  1283. else
  1284. // Not enough space, but the next cell is not empty.
  1285. end = -1;
  1286. }
  1287. // Check to make sure we haven't already force-merged enough cells.
  1288. if ( r - d->row > d->extra()->mergedYCells )
  1289. {
  1290. d->extra()->extraYCells = r - d->row;
  1291. d->extra()->extraHeight = height;
  1292. for ( int i = d->row + 1; i <= r; ++i )
  1293. {
  1294. Cell *cell = format()->sheet()->nonDefaultCell( d->column, i );
  1295. cell->obscure( this );
  1296. }
  1297. // Not enough space?
  1298. if ( end == -1 )
  1299. setFlag( Flag_CellTooShortY );
  1300. }
  1301. else
  1302. setFlag( Flag_CellTooShortY );
  1303. }
  1304. clearFlag( Flag_LayoutDirty );
  1305. return;
  1306. }
  1307. void Cell::valueChanged ()
  1308. {
  1309. update();
  1310. format()->sheet()->valueChanged (this);
  1311. }
  1312. // Recalculate d->strOutText.
  1313. //
  1314. void Cell::setOutputText()
  1315. {
  1316. if ( isDefault() ) {
  1317. d->strOutText = TQString();
  1318. if ( d->hasExtra() && d->extra()->conditions )
  1319. d->extra()->conditions->checkMatches();
  1320. return;
  1321. }
  1322. // If nothing has changed, we don't need to remake the text layout.
  1323. if ( !testFlag(Flag_TextFormatDirty) )
  1324. return;
  1325. // We don't want to remake the layout unnecessarily.
  1326. clearFlag( Flag_TextFormatDirty );
  1327. // Display a formula if warranted. If not, display the value instead;
  1328. // this is the most common case.
  1329. if ( (!hasError()) && isFormula() && format()->sheet()->getShowFormula()
  1330. && !( format()->sheet()->isProtected() && format()->isHideFormula( d->column, d->row ) )
  1331. || isEmpty() )
  1332. d->strOutText = d->strText;
  1333. else {
  1334. d->strOutText = sheet()->doc()->formatter()->formatText (this,
  1335. formatType());
  1336. }
  1337. // Check conditions if needed.
  1338. if ( d->hasExtra() && d->extra()->conditions )
  1339. d->extra()->conditions->checkMatches();
  1340. }
  1341. // Recalculate d->textX and d->textY.
  1342. //
  1343. // Used in makeLayout() and calculateTextParameters().
  1344. //
  1345. void Cell::offsetAlign( int _col, int _row )
  1346. {
  1347. int a;
  1348. Format::AlignY ay;
  1349. int tmpAngle;
  1350. bool tmpVerticalText;
  1351. bool tmpMultiRow;
  1352. if ( d->hasExtra()
  1353. && d->extra()->conditions
  1354. && d->extra()->conditions->matchedStyle() )
  1355. {
  1356. Style *style = d->extra()->conditions->matchedStyle();
  1357. if ( style->hasFeature( Style::SAlignX, true ) )
  1358. a = style->alignX();
  1359. else
  1360. a = format()->align( _col, _row );
  1361. if ( style->hasFeature( Style::SVerticalText, true ) )
  1362. tmpVerticalText = style->hasProperty( Style::PVerticalText );
  1363. else
  1364. tmpVerticalText = format()->verticalText( _col, _row );
  1365. if ( style->hasFeature( Style::SMultiRow, true ) )
  1366. tmpMultiRow = style->hasProperty( Style::PMultiRow );
  1367. else
  1368. tmpMultiRow = format()->multiRow( _col, _row );
  1369. if ( style->hasFeature( Style::SAlignY, true ) )
  1370. ay = style->alignY();
  1371. else
  1372. ay = format()->alignY( _col, _row );
  1373. if ( style->hasFeature( Style::SAngle, true ) )
  1374. tmpAngle = style->rotateAngle();
  1375. else
  1376. tmpAngle = format()->getAngle( _col, _row );
  1377. }
  1378. else {
  1379. a = format()->align( _col, _row );
  1380. ay = format()->alignY( _col, _row );
  1381. tmpAngle = format()->getAngle( _col, _row );
  1382. tmpVerticalText = format()->verticalText( _col, _row );
  1383. tmpMultiRow = format()->multiRow( _col, _row );
  1384. }
  1385. RowFormat *rl = format()->sheet()->rowFormat( _row );
  1386. ColumnFormat *cl = format()->sheet()->columnFormat( _col );
  1387. double w = cl->dblWidth();
  1388. double h = rl->dblHeight();
  1389. if ( d->hasExtra() ) {
  1390. if ( d->extra()->extraXCells ) w = d->extra()->extraWidth;
  1391. if ( d->extra()->extraYCells ) h = d->extra()->extraHeight;
  1392. }
  1393. const double effTop = BORDER_SPACE + 0.5 * effTopBorderPen( _col, _row ).width();
  1394. const double effBottom = h - BORDER_SPACE - 0.5 * effBottomBorderPen( _col, _row ).width();
  1395. // Calculate d->textY based on the vertical alignment and a few
  1396. // other inputs.
  1397. switch( ay )
  1398. {
  1399. case Format::Top:
  1400. {
  1401. if ( tmpAngle == 0 )
  1402. {
  1403. d->textY = effTop + (double) d->fmAscent / format()->sheet()->doc()->zoomedResolutionY();
  1404. }
  1405. else if ( tmpAngle < 0 )
  1406. {
  1407. d->textY = effTop;
  1408. }
  1409. else
  1410. {
  1411. d->textY = effTop
  1412. + (double) d->fmAscent * cos( tmpAngle * M_PI / 180 ) / format()->sheet()->doc()->zoomedResolutionY();
  1413. }
  1414. break;
  1415. }
  1416. case Format::Bottom:
  1417. {
  1418. if ( !tmpVerticalText && !tmpMultiRow && !tmpAngle )
  1419. {
  1420. d->textY = effBottom;
  1421. }
  1422. else if ( tmpAngle != 0 )
  1423. {
  1424. // Is enough place available?
  1425. if ( effBottom - effTop - d->textHeight > 0 )
  1426. {
  1427. if ( tmpAngle < 0 )
  1428. {
  1429. d->textY = effBottom - d->textHeight;
  1430. }
  1431. else
  1432. {
  1433. d->textY = effBottom - d->textHeight
  1434. + ( (double) d->fmAscent * cos( tmpAngle * M_PI / 180 ) / format()->sheet()->doc()->zoomedResolutionY() );
  1435. }
  1436. }
  1437. else
  1438. {
  1439. if ( tmpAngle < 0 )
  1440. {
  1441. d->textY = effTop;
  1442. }
  1443. else
  1444. {
  1445. d->textY = effTop
  1446. + ( (double) d->fmAscent * cos( tmpAngle * M_PI / 180 )
  1447. / format()->sheet()->doc()->zoomedResolutionY() );
  1448. }
  1449. }
  1450. }
  1451. else if ( tmpMultiRow && !tmpVerticalText )
  1452. {
  1453. // Is enough place available?
  1454. if ( effBottom - effTop - d->textHeight > 0 )
  1455. {
  1456. d->textY = effBottom - d->textHeight
  1457. + (double)d->fmAscent / format()->sheet()->doc()->zoomedResolutionY();
  1458. }
  1459. else
  1460. {
  1461. d->textY = effTop
  1462. + (double) d->fmAscent / format()->sheet()->doc()->zoomedResolutionY();
  1463. }
  1464. }
  1465. else
  1466. {
  1467. // Is enough place available?
  1468. if ( effBottom - effTop - d->textHeight > 0 )
  1469. {
  1470. d->textY = effBottom - d->textHeight
  1471. + (double)d->fmAscent / format()->sheet()->doc()->zoomedResolutionY();
  1472. }
  1473. else
  1474. {
  1475. d->textY = effTop
  1476. + (double) d->fmAscent / format()->sheet()->doc()->zoomedResolutionY();
  1477. }
  1478. }
  1479. break;
  1480. }
  1481. case Format::Middle:
  1482. case Format::UndefinedY:
  1483. {
  1484. if ( !tmpVerticalText && !tmpMultiRow && !tmpAngle )
  1485. {
  1486. d->textY = ( h - d->textHeight ) / 2
  1487. + (double) d->fmAscent / format()->sheet()->doc()->zoomedResolutionY();
  1488. }
  1489. else if ( tmpAngle != 0 )
  1490. {
  1491. // Is enough place available?
  1492. if ( effBottom - effTop - d->textHeight > 0 )
  1493. {
  1494. if ( tmpAngle < 0 )
  1495. {
  1496. d->textY = ( h - d->textHeight ) / 2;
  1497. }
  1498. else
  1499. {
  1500. d->textY = ( h - d->textHeight ) / 2
  1501. + (double) d->fmAscent * cos( tmpAngle * M_PI / 180 ) / format()->sheet()->doc()->zoomedResolutionY();
  1502. }
  1503. }
  1504. else
  1505. {
  1506. if ( tmpAngle < 0 )
  1507. {
  1508. d->textY = effTop;
  1509. }
  1510. else
  1511. {
  1512. d->textY = effTop
  1513. + ( (double)d->fmAscent * cos( tmpAngle * M_PI / 180 ) / format()->sheet()->doc()->zoomedResolutionY() );
  1514. }
  1515. }
  1516. }
  1517. else if ( tmpMultiRow && !tmpVerticalText )
  1518. {
  1519. // Is enough place available?
  1520. if ( effBottom - effTop - d->textHeight > 0 )
  1521. {
  1522. d->textY = ( h - d->textHeight ) / 2
  1523. + (double) d->fmAscent / format()->sheet()->doc()->zoomedResolutionY();
  1524. }
  1525. else
  1526. {
  1527. d->textY = effTop
  1528. + (double) d->fmAscent / format()->sheet()->doc()->zoomedResolutionY();
  1529. }
  1530. }
  1531. else
  1532. {
  1533. // Is enough place available?
  1534. if ( effBottom - effTop - d->textHeight > 0 )
  1535. {
  1536. d->textY = ( h - d->textHeight ) / 2
  1537. + (double) d->fmAscent / format()->sheet()->doc()->zoomedResolutionY();
  1538. }
  1539. else
  1540. d->textY = effTop
  1541. + (double)d->fmAscent / format()->sheet()->doc()->zoomedResolutionY();
  1542. }
  1543. break;
  1544. }
  1545. }
  1546. a = effAlignX();
  1547. if ( format()->sheet()->getShowFormula() &&
  1548. !( format()->sheet()->isProtected() && format()->isHideFormula( _col, _row ) ) )
  1549. {
  1550. a = Format::Left;
  1551. }
  1552. // Calculate d->textX based on alignment and textwidth.
  1553. switch ( a ) {
  1554. case Format::Left:
  1555. d->textX = 0.5 * effLeftBorderPen( _col, _row ).width() + BORDER_SPACE;
  1556. break;
  1557. case Format::Right:
  1558. d->textX = w - BORDER_SPACE - d->textWidth
  1559. - 0.5 * effRightBorderPen( _col, _row ).width();
  1560. break;
  1561. case Format::Center:
  1562. d->textX = 0.5 * ( w - BORDER_SPACE - d->textWidth -
  1563. 0.5 * effRightBorderPen( _col, _row ).width() );
  1564. break;
  1565. }
  1566. }
  1567. // Recalculate the current text dimensions, i.e. d->textWidth and
  1568. // d->textHeight.
  1569. //
  1570. // Used in makeLayout() and calculateTextParameters().
  1571. //
  1572. void Cell::textSize( TQPainter &_paint )
  1573. {
  1574. TQFontMetrics fm = _paint.fontMetrics();
  1575. // Horizontal text ?
  1576. int tmpAngle;
  1577. int _row = row();
  1578. int _col = column();
  1579. bool tmpVerticalText;
  1580. bool fontUnderlined;
  1581. Format::AlignY ay;
  1582. // Set tmpAngle, tmpeVerticalText, ay and fontUnderlined according
  1583. // to if there is a matching condition or not.
  1584. if ( d->hasExtra()
  1585. && d->extra()->conditions
  1586. && d->extra()->conditions->matchedStyle() )
  1587. {
  1588. Style *style = d->extra()->conditions->matchedStyle();
  1589. if ( style->hasFeature( Style::SAngle, true ) )
  1590. tmpAngle = style->rotateAngle();
  1591. else
  1592. tmpAngle = format()->getAngle( _col, _row );
  1593. if ( style->hasFeature( Style::SVerticalText, true ) )
  1594. tmpVerticalText = style->hasProperty( Style::PVerticalText );
  1595. else
  1596. tmpVerticalText = format()->verticalText( _col, _row );
  1597. if ( style->hasFeature( Style::SAlignY, true ) )
  1598. ay = style->alignY();
  1599. else
  1600. ay = format()->alignY( _col, _row );
  1601. if ( style->hasFeature( Style::SFontFlag, true ) )
  1602. fontUnderlined = ( style->fontFlags() & (uint) Style::FUnderline );
  1603. else
  1604. fontUnderlined = format()->textFontUnderline( _col, _row );
  1605. }
  1606. else {
  1607. // The cell has no condition with a maxed style.
  1608. tmpAngle = format()->getAngle( _col, _row );
  1609. tmpVerticalText = format()->verticalText( _col, _row );
  1610. ay = format()->alignY( _col, _row );
  1611. fontUnderlined = format()->textFontUnderline( _col, _row );
  1612. }
  1613. // Set d->textWidth and d->textHeight to correct values according to
  1614. // if the text is horizontal, vertical or rotated.
  1615. if ( !tmpVerticalText && !tmpAngle ) {
  1616. // Horizontal text.
  1617. d->textWidth = format()->sheet()->doc()->unzoomItX( fm.width( d->strOutText ) );
  1618. int offsetFont = 0;
  1619. if ( ( ay == Format::Bottom ) && fontUnderlined ) {
  1620. offsetFont = fm.underlinePos() + 1;
  1621. }
  1622. d->textHeight = format()->sheet()->doc()->unzoomItY( fm.ascent() + fm.descent()
  1623. + offsetFont );
  1624. }
  1625. else if ( tmpAngle!= 0 ) {
  1626. // Rotated text.
  1627. d->textHeight = format()->sheet()->doc()
  1628. ->unzoomItY( int( cos( tmpAngle * M_PI / 180 )
  1629. * ( fm.ascent() + fm.descent() )
  1630. + abs( int( ( fm.width( d->strOutText )
  1631. * sin( tmpAngle * M_PI / 180 ) ) ) ) ) );
  1632. d->textWidth = format()->sheet()->doc()
  1633. ->unzoomItX( int( abs( int( ( sin( tmpAngle * M_PI / 180 )
  1634. * ( fm.ascent() + fm.descent() ) ) ) )
  1635. + fm.width( d->strOutText )
  1636. * cos ( tmpAngle * M_PI / 180 ) ) );
  1637. }
  1638. else {
  1639. // Vertical text.
  1640. int width = 0;
  1641. for ( unsigned int i = 0; i < d->strOutText.length(); i++ )
  1642. width = TQMAX( width, fm.width( d->strOutText.at( i ) ) );
  1643. d->textWidth = format()->sheet()->doc()->unzoomItX( width );
  1644. d->textHeight = format()->sheet()->doc()->unzoomItY( ( fm.ascent() + fm.descent() )
  1645. * d->strOutText.length() );
  1646. }
  1647. }
  1648. // Get the effective font to use after the zooming and apply it to `painter'.
  1649. //
  1650. // Used in makeLayout() and calculateTextParameters().
  1651. //
  1652. void Cell::applyZoomedFont( TQPainter &painter, int _col, int _row )
  1653. {
  1654. TQFont tmpFont( format()->textFont( _col, _row ) );
  1655. // If there is a matching condition on this cell then set the
  1656. // according style parameters.
  1657. if ( d->hasExtra()
  1658. && d->extra()->conditions
  1659. && d->extra()->conditions->matchedStyle() ) {
  1660. Style * s = d->extra()->conditions->matchedStyle();
  1661. // Other size?
  1662. if ( s->hasFeature( Style::SFontSize, true ) )
  1663. tmpFont.setPointSizeFloat( s->fontSize() );
  1664. // Other attributes?
  1665. if ( s->hasFeature( Style::SFontFlag, true ) ) {
  1666. uint flags = s->fontFlags();
  1667. tmpFont.setBold( flags & (uint) Style::FBold );
  1668. tmpFont.setUnderline( flags & (uint) Style::FUnderline );
  1669. tmpFont.setItalic( flags & (uint) Style::FItalic );
  1670. tmpFont.setStrikeOut( flags & (uint) Style::FStrike );
  1671. }
  1672. // Other family?
  1673. if ( s->hasFeature( Style::SFontFamily, true ) )
  1674. tmpFont.setFamily( s->fontFamily() );
  1675. }
  1676. #if 0
  1677. else
  1678. /*
  1679. * could somebody please explaint why we check for isProtected or isHideFormula here
  1680. */
  1681. if ( d->extra()->conditions
  1682. && d->extra()->conditions->currentCondition( condition )
  1683. && !(format()->sheet()->getShowFormula()
  1684. && !( format()->sheet()->isProtected()
  1685. && format()->isHideFormula( d->column, d->row ) ) ) )
  1686. {
  1687. if ( condition.fontcond )
  1688. tmpFont = *(condition.fontcond);
  1689. else
  1690. tmpFont = condition.style->font();
  1691. }
  1692. #endif
  1693. // Scale the font size according to the current zoom.
  1694. tmpFont.setPointSizeFloat( 0.01 * format()->sheet()->doc()->zoom()
  1695. * tmpFont.pointSizeFloat() );
  1696. painter.setFont( tmpFont );
  1697. }
  1698. //used in Sheet::adjustColumnHelper and Sheet::adjustRow
  1699. void Cell::calculateTextParameters( TQPainter &_painter,
  1700. int _col, int _row )
  1701. {
  1702. // Apply the correct font to _painter.
  1703. applyZoomedFont( _painter, _col, _row );
  1704. // Recalculate d->textWidth and d->textHeight
  1705. textSize( _painter );
  1706. // Recalculate d->textX and d->textY.
  1707. offsetAlign( _col, _row );
  1708. }
  1709. // ----------------------------------------------------------------
  1710. // Formula handling
  1711. bool Cell::makeFormula()
  1712. {
  1713. clearFormula ();
  1714. d->formula = new KSpread::Formula (sheet(), this);
  1715. d->formula->setExpression (d->strText);
  1716. if (!d->formula->isValid ()) {
  1717. // Did a syntax error occur ?
  1718. clearFormula();
  1719. if (format()->sheet()->doc()->getShowMessageError())
  1720. {
  1721. TQString tmp(i18n("Error in cell %1\n\n"));
  1722. tmp = tmp.arg( fullName() );
  1723. KMessageBox::error( (TQWidget*)0L, tmp);
  1724. }
  1725. setFlag(Flag_ParseError);
  1726. Value v;
  1727. v.setError ( "####" );
  1728. setValue (v);
  1729. return false;
  1730. }
  1731. // we must recalc
  1732. setCalcDirtyFlag ();
  1733. return true;
  1734. }
  1735. void Cell::clearFormula()
  1736. {
  1737. delete d->formula;
  1738. d->formula = 0L;
  1739. }
  1740. bool Cell::calc(bool delay)
  1741. {
  1742. if ( !isFormula() )
  1743. return true;
  1744. if (d->formula == 0)
  1745. {
  1746. if ( testFlag( Flag_ParseError ) ) // there was a parse error
  1747. return false;
  1748. else
  1749. {
  1750. /* we were probably at a "isLoading() = true" state when we originally
  1751. * parsed
  1752. */
  1753. makeFormula ();
  1754. if ( d->formula == 0 ) // there was a parse error
  1755. return false;
  1756. }
  1757. }
  1758. if ( !testFlag( Flag_CalcDirty ) )
  1759. return true;
  1760. if ( delay )
  1761. {
  1762. if ( format()->sheet()->doc()->delayCalculation() )
  1763. return true;
  1764. }
  1765. setFlag(Flag_LayoutDirty);
  1766. setFlag(Flag_TextFormatDirty);
  1767. clearFlag(Flag_CalcDirty);
  1768. Value result = d->formula->eval ();
  1769. setValue (result);
  1770. if (result.isNumber())
  1771. checkNumberFormat(); // auto-chooses number or scientific
  1772. clearFlag(Flag_CalcDirty);
  1773. setFlag(Flag_LayoutDirty);
  1774. return true;
  1775. }
  1776. // ================================================================
  1777. // Painting
  1778. // Paint the cell. This is the main function that calls a lot of
  1779. // helper functions.
  1780. //
  1781. // `rect' is the rectangle that we should paint on. If the cell
  1782. // does not overlap this rectangle, we can return immediately.
  1783. // `coordinate' is the origin (the upper left) of the cell in document
  1784. // coordinates.
  1785. //
  1786. void Cell::paintCell( const KoRect &rect, TQPainter & painter,
  1787. View *view,
  1788. const KoPoint &coordinate,
  1789. const TQPoint &cellRef,
  1790. int paintBorder,
  1791. TQPen & rightPen, TQPen & bottomPen,
  1792. TQPen & leftPen, TQPen & topPen,
  1793. TQValueList<TQPoint> &mergedCellsPainted,
  1794. bool drawCursor )
  1795. {
  1796. bool paintBorderRight = paintBorder & Border_Right;
  1797. bool paintBorderBottom = paintBorder & Border_Bottom;
  1798. bool paintBorderLeft = paintBorder & Border_Left;
  1799. bool paintBorderTop = paintBorder & Border_Top;
  1800. // If we are already painting this cell, then return immediately.
  1801. // This avoids infinite recursion.
  1802. if ( testFlag( Flag_PaintingCell ) )
  1803. return;
  1804. // Indicate that we are painting this cell now.
  1805. setFlag( Flag_PaintingCell );
  1806. // This flag indicates that we are working on drawing the cells that
  1807. // another cell is obscuring. The value is the number of levels down we
  1808. // are currently working -- i.e. a cell obscured by a cell which is
  1809. // obscured by a cell.
  1810. static int paintingObscured = 0;
  1811. #if 0
  1812. if (paintingObscured == 0)
  1813. kdDebug(36001) << "painting cell " << name() << endl;
  1814. else
  1815. kdDebug(36001) << " painting obscured cell " << name() << endl;
  1816. #endif
  1817. // Sanity check: If we're working on drawing an obscured cell, that
  1818. // means this cell should have a cell that obscures it.
  1819. Q_ASSERT(!(paintingObscured > 0 && d->extra()->obscuringCells.isEmpty()));
  1820. // The parameter cellref should be *this, unless this is the default cell.
  1821. Q_ASSERT(isDefault()
  1822. || (((cellRef.x() == d->column) && (cellRef.y() == d->row))));
  1823. Sheet::LayoutDirection sheetDir = format()->sheet()->layoutDirection();
  1824. double left = coordinate.x();
  1825. ColumnFormat * colFormat = format()->sheet()->columnFormat( cellRef.x() );
  1826. RowFormat * rowFormat = format()->sheet()->rowFormat( cellRef.y() );
  1827. // Set width, height to the total width and height that this cell
  1828. // covers, including obscured cells, and width0, height0 to the
  1829. // width and height of this cell, maybe merged but never implicitly
  1830. // extended.
  1831. double width0 = colFormat->dblWidth();
  1832. double height0 = rowFormat->dblHeight();
  1833. double width = width0;
  1834. double height = height0;
  1835. // Handle right-to-left layout.
  1836. // In an RTL sheet the cells have to be painted at their opposite horizontal
  1837. // location on the canvas, meaning that column A will be the rightmost column
  1838. // on screen, column B will be to the left of it and so on. Here we change
  1839. // the horizontal coordinate at which we start painting the cell in case the
  1840. // sheet's direction is RTL. We do this only if paintingObscured is 0,
  1841. // otherwise the cell's painting location will flip back and forth in
  1842. // consecutive calls to paintCell when painting obscured cells.
  1843. if ( sheetDir == Sheet::RightToLeft && paintingObscured == 0
  1844. && view && view->canvasWidget() )
  1845. {
  1846. double dwidth = view->doc()->unzoomItX(view->canvasWidget()->width());
  1847. left = dwidth - coordinate.x() - width;
  1848. }
  1849. // See if this cell is merged or has overflown into neighbor cells.
  1850. // In that case, the width/height is greater than just the cell
  1851. // itself.
  1852. if (d->hasExtra()) {
  1853. if (d->extra()->mergedXCells > 0 || d->extra()->mergedYCells > 0) {
  1854. // merged cell extends to the left if sheet is RTL
  1855. if ( sheetDir == Sheet::RightToLeft ) {
  1856. left -= d->extra()->extraWidth - width;
  1857. }
  1858. width0 = d->extra()->extraWidth;
  1859. height0 = d->extra()->extraHeight;
  1860. width = d->extra()->extraWidth;
  1861. height = d->extra()->extraHeight;
  1862. }
  1863. else {
  1864. #if 0
  1865. width += d->extra()->extraXCells ? d->extra()->extraWidth : 0;
  1866. height += d->extra()->extraYCells ? d->extra()->extraHeight : 0;
  1867. #else
  1868. // FIXME: Make extraWidth/Height really contain the *extra* width/height.
  1869. if ( d->extra()->extraXCells )
  1870. width = d->extra()->extraWidth;
  1871. if ( d->extra()->extraYCells )
  1872. height = d->extra()->extraHeight;
  1873. #endif
  1874. }
  1875. }
  1876. // Check if the cell is "selected", i.e. it should be drawn with the
  1877. // color that indicates selection (dark blue). If more than one
  1878. // square is selected, the last one uses the ordinary colors. In
  1879. // that case, "selected" will be set to false even though the cell
  1880. // itself really is selected.
  1881. bool selected = false;
  1882. if ( view != NULL ) {
  1883. selected = view->selectionInfo()->contains( cellRef );
  1884. // But the cell doesn't look selected if this is the marker cell.
  1885. Cell *cell = format()->sheet()->cellAt( view->selectionInfo()->marker() );
  1886. TQPoint bottomRight( view->selectionInfo()->marker().x() + cell->extraXCells(),
  1887. view->selectionInfo()->marker().y() + cell->extraYCells() );
  1888. TQRect markerArea( view->selectionInfo()->marker(), bottomRight );
  1889. selected = selected && !( markerArea.contains( cellRef ) );
  1890. // Don't draw any selection at all when printing.
  1891. if ( painter.device()->isExtDev() || !drawCursor )
  1892. selected = false;
  1893. }
  1894. // Need to make a new layout ?
  1895. //
  1896. // FIXME: We have already used (at least) extraWidth/Height above,
  1897. // and now we are recalculating the layout. This has to be
  1898. // moved up above all uses.
  1899. //
  1900. // FIXME: This needs to be taken out eventually - it is done in
  1901. // canvas::paintUpdates().
  1902. if ( testFlag( Flag_LayoutDirty ) )
  1903. makeLayout( painter, cellRef.x(), cellRef.y() );
  1904. // ---------------- Start the actual painting. ----------------
  1905. // If the rect of this cell doesn't intersect the rect that should
  1906. // be painted, we can skip the rest and return. (Note that we need
  1907. // to calculate `left' first before we can do this.)
  1908. const KoRect cellRect( left, coordinate.y(), width, height );
  1909. const KoRect cellRect0( left, coordinate.y(), width0, height0 );
  1910. if ( !cellRect.intersects( rect ) ) {
  1911. clearFlag( Flag_PaintingCell );
  1912. return;
  1913. }
  1914. // Get the background color.
  1915. //
  1916. // If there is a condition giving the background color for this cell
  1917. // (and it matches), use that one, otherwise get the standard
  1918. // background.
  1919. TQColor backgroundColor;
  1920. if ( d->hasExtra() && d->extra()->conditions
  1921. && d->extra()->conditions->matchedStyle()
  1922. && d->extra()->conditions->matchedStyle()->hasFeature( Style::SBackgroundColor, true ) )
  1923. backgroundColor = d->extra()->conditions->matchedStyle()->bgColor();
  1924. else
  1925. backgroundColor = bgColor( cellRef.x(), cellRef.y() );
  1926. // 1. Paint the background.
  1927. if ( !isPartOfMerged() )
  1928. paintBackground( painter, cellRect0, cellRef, selected, backgroundColor );
  1929. // 2. Paint the default borders if we are on screen or if we are printing
  1930. // and the checkbox to do this is checked.
  1931. if ( painter.device()->devType() != TQInternal::Printer
  1932. || format()->sheet()->print()->printGrid())
  1933. paintDefaultBorders( painter, rect, cellRect, cellRef,
  1934. paintBorderRight, paintBorderBottom,
  1935. paintBorderLeft, paintBorderTop,
  1936. rightPen, bottomPen, leftPen, topPen );
  1937. // 3. Paint all the cells that this one obscures. They may only be
  1938. // partially obscured.
  1939. //
  1940. // The `paintingObscured' variable is used to avoid infinite
  1941. // recursion since cells sometimes paint their obscuring cell as
  1942. // well.
  1943. paintingObscured++;
  1944. if (d->hasExtra() && (d->extra()->extraXCells > 0
  1945. || d->extra()->extraYCells > 0)) {
  1946. //kdDebug(36001) << "painting obscured cells for " << name() << endl;
  1947. paintObscuredCells( rect, painter, view, cellRect, cellRef,
  1948. paintBorderRight, paintBorderBottom,
  1949. paintBorderLeft, paintBorderTop,
  1950. rightPen, bottomPen, leftPen, topPen,
  1951. mergedCellsPainted);
  1952. // FIXME: Is this the right place for this?
  1953. if ( d->extra()->mergedXCells > 0 || d->extra()->mergedYCells > 0 )
  1954. mergedCellsPainted.prepend( cellRef );
  1955. }
  1956. paintingObscured--;
  1957. // 4. Paint the borders of the cell if no other cell is forcing this
  1958. // one, i.e. this cell is not part of a merged cell.
  1959. //
  1960. // If we print pages, then we disable clipping, otherwise borders are
  1961. // cut in the middle at the page borders.
  1962. if ( painter.device()->isExtDev() )
  1963. painter.setClipping( false );
  1964. // Paint the borders if this cell is not part of another merged cell.
  1965. if ( !isPartOfMerged() ) {
  1966. // if (!testFlag(Flag_Highlight))
  1967. paintCellBorders( painter, rect, cellRect0,
  1968. cellRef,
  1969. paintBorderRight, paintBorderBottom,
  1970. paintBorderLeft, paintBorderTop,
  1971. rightPen, bottomPen, leftPen, topPen );
  1972. }
  1973. // Turn clipping back on.
  1974. if ( painter.device()->isExtDev() )
  1975. painter.setClipping( true );
  1976. // 5. Paint diagonal lines and page borders.
  1977. paintCellDiagonalLines( painter, cellRect0, cellRef );
  1978. paintPageBorders( painter, cellRect0, cellRef,
  1979. paintBorderRight, paintBorderBottom );
  1980. // 6. Now paint the content, if this cell isn't obscured.
  1981. if ( !isObscured() ) {
  1982. // 6a. Paint possible comment indicator.
  1983. if ( !painter.device()->isExtDev()
  1984. || format()->sheet()->print()->printCommentIndicator() )
  1985. paintCommentIndicator( painter, cellRect, cellRef, backgroundColor );
  1986. // 6b. Paint possible formula indicator.
  1987. if ( !painter.device()->isExtDev()
  1988. || format()->sheet()->print()->printFormulaIndicator() )
  1989. paintFormulaIndicator( painter, cellRect, backgroundColor );
  1990. // 6c. Paint possible indicator for clipped text.
  1991. paintMoreTextIndicator( painter, cellRect, backgroundColor );
  1992. //6c. Paint cell highlight
  1993. #if 0
  1994. if (highlightBorder != Border_None)
  1995. paintCellHighlight ( painter, cellRect, cellRef, highlightBorder,
  1996. rightHighlightPen, bottomHighlightPen,
  1997. leftHighlightPen, topHighlightPen );
  1998. #endif
  1999. // 6d. Paint the text in the cell unless:
  2000. // a) it is empty
  2001. // b) something indicates that the text should not be painted
  2002. // c) the sheet is protected and the cell is hidden.
  2003. if ( !d->strOutText.isEmpty()
  2004. && ( !painter.device()->isExtDev()
  2005. || !format()->getDontprintText( cellRef.x(), cellRef.y() ) )
  2006. && !( format()->sheet()->isProtected()
  2007. && format()->isHideAll( cellRef.x(), cellRef.y() ) ) )
  2008. {
  2009. paintText( painter, cellRect, cellRef );
  2010. }
  2011. }
  2012. // 7. If this cell is obscured and we are not already painting obscured
  2013. // cells, then paint the obscuring cell(s). Otherwise don't do
  2014. // anything so that we don't cause an infinite loop.
  2015. if ( isObscured() && paintingObscured == 0 &&
  2016. !( sheetDir == Sheet::RightToLeft && painter.device()->isExtDev() ) )
  2017. {
  2018. //kdDebug(36001) << "painting cells that obscure " << name() << endl;
  2019. // Store the obscuringCells list in a list of TQPoint(column, row)
  2020. // This avoids crashes during the iteration through
  2021. // obscuringCells, when the cells may get non valid or the list
  2022. // itself gets changed during a call of obscuringCell->paintCell
  2023. // (this happens e.g. when there is an updateDepend)
  2024. if (d->hasExtra()) {
  2025. TQValueList<TQPoint> listPoints;
  2026. TQValueList<Cell*>::iterator it = d->extra()->obscuringCells.begin();
  2027. TQValueList<Cell*>::iterator end = d->extra()->obscuringCells.end();
  2028. for ( ; it != end; ++it ) {
  2029. Cell *obscuringCell = *it;
  2030. listPoints.append( TQPoint( obscuringCell->column(), obscuringCell->row() ) );
  2031. }
  2032. TQValueList<TQPoint>::iterator it1 = listPoints.begin();
  2033. TQValueList<TQPoint>::iterator end1 = listPoints.end();
  2034. for ( ; it1 != end1; ++it1 ) {
  2035. TQPoint obscuringCellRef = *it1;
  2036. // Only paint those obscuring cells that haven't been already
  2037. // painted yet.
  2038. //
  2039. // This optimization removes an O(n^4) behaviour where n is
  2040. // the number of cells on one edge in a merged cell.
  2041. if ( mergedCellsPainted.contains( obscuringCellRef ) )
  2042. continue;
  2043. Cell *obscuringCell = format()->sheet()->cellAt( obscuringCellRef.x(),
  2044. obscuringCellRef.y() );
  2045. if ( obscuringCell != 0 ) {
  2046. double x = format()->sheet()->dblColumnPos( obscuringCellRef.x() );
  2047. double y = format()->sheet()->dblRowPos( obscuringCellRef.y() );
  2048. if ( view != 0 ) {
  2049. x -= view->canvasWidget()->xOffset();
  2050. y -= view->canvasWidget()->yOffset();
  2051. }
  2052. KoPoint corner( x, y );
  2053. painter.save();
  2054. // Get the effective pens for the borders. These are
  2055. // determined by possible conditions on the cell with
  2056. // associated styles.
  2057. TQPen rp( obscuringCell->effRightBorderPen( obscuringCellRef.x(),
  2058. obscuringCellRef.y() ) );
  2059. TQPen bp( obscuringCell->effBottomBorderPen( obscuringCellRef.x(),
  2060. obscuringCellRef.y() ) );
  2061. TQPen lp( obscuringCell->effLeftBorderPen( obscuringCellRef.x(),
  2062. obscuringCellRef.y() ) );
  2063. TQPen tp( obscuringCell->effTopBorderPen( obscuringCellRef.x(),
  2064. obscuringCellRef.y() ) );
  2065. //kdDebug(36001) << " painting obscuring cell "
  2066. // << obscuringCell->name() << endl;
  2067. // TQPen highlightPen;
  2068. //Note: Painting of highlight isn't quite right. If several
  2069. // cells are merged, then the whole merged cell will be
  2070. // painted with the colour of the last cell referenced
  2071. // which is inside the merged range.
  2072. obscuringCell->paintCell( rect, painter, view,
  2073. corner, obscuringCellRef,
  2074. Border_Left|Border_Top|Border_Right|Border_Bottom,
  2075. rp, bp, lp, tp,
  2076. mergedCellsPainted); // new pens
  2077. painter.restore();
  2078. }
  2079. }
  2080. }
  2081. }
  2082. // We are done with the painting, so remove the flag on the cell.
  2083. clearFlag( Flag_PaintingCell );
  2084. }
  2085. // The following code was commented out in the above function. I'll
  2086. // leave it here in case this functionality is ever re-implemented and
  2087. // someone wants some code to start from.
  2088. //
  2089. #if 0
  2090. /**
  2091. * Modification for drawing the button
  2092. */
  2093. if ( d->style == Cell::ST_Button ) {
  2094. TQBrush fill( TQt::lightGray );
  2095. TQApplication::style().drawControl( TQStyle::CE_PushButton, &_painter, this,
  2096. TQRect( _tx + 1, _ty + 1, w2 - 1, h2 - 1 ),
  2097. defaultColorGroup ); //, selected, &fill );
  2098. }
  2099. /**
  2100. * Modification for drawing the combo box
  2101. */
  2102. else if ( d->style == Cell::ST_Select ) {
  2103. TQApplication::style().drawComboButton( &_painter, _tx + 1, _ty + 1,
  2104. w2 - 1, h2 - 1,
  2105. defaultColorGroup, selected );
  2106. }
  2107. #endif
  2108. #if 0
  2109. void Cell::paintCellHighlight(TQPainter& painter,
  2110. const KoRect& cellRect,
  2111. const TQPoint& cellRef,
  2112. const int highlightBorder,
  2113. const TQPen& rightPen,
  2114. const TQPen& bottomPen,
  2115. const TQPen& leftPen,
  2116. const TQPen& topPen
  2117. )
  2118. {
  2119. //painter.drawLine(cellRect.left(),cellRect.top(),cellRect.right(),cellRect.bottom());
  2120. //TQPen pen(d->extra()->highlight);
  2121. //painter.setPen(highlightPen);
  2122. TQBrush nullBrush;
  2123. painter.setBrush(nullBrush);
  2124. TQRect zoomedCellRect = sheet()->doc()->zoomRect( cellRect );
  2125. //The highlight rect is just inside the main cell rect
  2126. //This saves the hassle of repainting nearby cells when the highlight is changed as the highlight areas
  2127. //do not overlap
  2128. zoomedCellRect.setLeft(zoomedCellRect.left()+1);
  2129. //zoomedCellRect.setRight(zoomedCellRect.right()-1);
  2130. zoomedCellRect.setTop(zoomedCellRect.top()+1);
  2131. //zoomedCellRect.setBottom(zoomedCellRect.bottom()-1);
  2132. if ( cellRef.x() != KS_colMax )
  2133. zoomedCellRect.setWidth( zoomedCellRect.width() - 1 );
  2134. if ( cellRef.y() != KS_rowMax )
  2135. zoomedCellRect.setHeight( zoomedCellRect.height() - 1 );
  2136. if (highlightBorder & Border_Top)
  2137. {
  2138. painter.setPen(topPen);
  2139. painter.drawLine(zoomedCellRect.left(),zoomedCellRect.top(),zoomedCellRect.right(),zoomedCellRect.top());
  2140. }
  2141. if (highlightBorder & Border_Left)
  2142. {
  2143. painter.setPen(leftPen);
  2144. painter.drawLine(zoomedCellRect.left(),zoomedCellRect.top(),zoomedCellRect.left(),zoomedCellRect.bottom());
  2145. }
  2146. if (highlightBorder & Border_Right)
  2147. {
  2148. painter.setPen(rightPen);
  2149. painter.drawLine(zoomedCellRect.right(),zoomedCellRect.top(),zoomedCellRect.right(),zoomedCellRect.bottom());
  2150. }
  2151. if (highlightBorder & Border_Bottom)
  2152. {
  2153. painter.setPen(bottomPen);
  2154. painter.drawLine(zoomedCellRect.left(),zoomedCellRect.bottom(),zoomedCellRect.right(),zoomedCellRect.bottom());
  2155. }
  2156. if (highlightBorder & Border_SizeGrip)
  2157. {
  2158. TQBrush brush(rightPen.color());
  2159. painter.setBrush(brush);
  2160. painter.setPen(rightPen);
  2161. painter.drawRect(zoomedCellRect.right()-3,zoomedCellRect.bottom()-3,4,4);
  2162. }
  2163. //painter.drawRect(zoomedCellRect.left(),zoomedCellRect.top(),zoomedCellRect.width(),zoomedCellRect.height());
  2164. }
  2165. #endif
  2166. // Paint all the cells that this cell obscures (helper function to paintCell).
  2167. //
  2168. void Cell::paintObscuredCells(const KoRect& rect, TQPainter& painter,
  2169. View* view,
  2170. const KoRect &cellRect,
  2171. const TQPoint &cellRef,
  2172. bool paintBorderRight,
  2173. bool _paintBorderBottom,
  2174. bool paintBorderLeft,
  2175. bool _paintBorderTop,
  2176. TQPen & rightPen, TQPen & _bottomPen,
  2177. TQPen & leftPen, TQPen & _topPen,
  2178. TQValueList<TQPoint> &mergedCellsPainted)
  2179. {
  2180. // If there are no obscured cells, return.
  2181. if ( !extraXCells() && !extraYCells() )
  2182. return;
  2183. double ypos = cellRect.y();
  2184. int maxY = extraYCells();
  2185. int maxX = extraXCells();
  2186. // Loop through the rectangle of squares that we obscure and paint them.
  2187. for ( int y = 0; y <= maxY; ++y ) {
  2188. double xpos = cellRect.x();
  2189. RowFormat* rl = format()->sheet()->rowFormat( cellRef.y() + y );
  2190. for( int x = 0; x <= maxX; ++ x ) {
  2191. ColumnFormat * cl = format()->sheet()->columnFormat( cellRef.x() + x );
  2192. if ( y != 0 || x != 0 ) {
  2193. uint column = cellRef.x() + x;
  2194. uint row = cellRef.y() + y;
  2195. TQPen topPen;
  2196. TQPen bottomPen;
  2197. bool paintBorderTop;
  2198. bool paintBorderBottom;
  2199. Cell *cell = format()->sheet()->cellAt( column, row );
  2200. KoPoint corner( xpos, ypos );
  2201. // Check if the upper and lower borders should be painted, and
  2202. // if so which pens we should use. There used to be a nasty
  2203. // bug here (#61452).
  2204. // Check top pen. Only check if this is not on the top row.
  2205. topPen = _topPen;
  2206. paintBorderTop = _paintBorderTop;
  2207. if ( row > 1 && !cell->isPartOfMerged() ) {
  2208. Cell *cellUp = format()->sheet()->cellAt( column, row - 1 );
  2209. if ( cellUp->isDefault() )
  2210. paintBorderTop = false;
  2211. else {
  2212. // If the cell towards the top is part of a merged cell, get
  2213. // the pointer to the master cell.
  2214. cellUp = cellUp->ultimateObscuringCell();
  2215. topPen = cellUp->effBottomBorderPen( cellUp->column(),
  2216. cellUp->row() );
  2217. #if 0
  2218. int penWidth = TQMAX(1, sheet()->doc()->zoomItY( topPen.width() ));
  2219. topPen.setWidth( penWidth );
  2220. #endif
  2221. }
  2222. }
  2223. // FIXME: I thought we had to check bottom pen as well.
  2224. // However, it looks as if we don't need to. It works anyway.
  2225. bottomPen = _bottomPen;
  2226. paintBorderBottom = _paintBorderBottom;
  2227. int paintBorder = Border_None;
  2228. if (paintBorderLeft) paintBorder |= Cell::Border_Left;
  2229. if (paintBorderRight) paintBorder |= Cell::Border_Right;
  2230. if (paintBorderTop) paintBorder |= Cell::Border_Top;
  2231. if (paintBorderBottom) paintBorder |= Cell::Border_Bottom;
  2232. /*Cell::BorderSides highlightBorder = Border_None;
  2233. TQPen highlightPen;*/
  2234. //kdDebug(36001) << "calling paintcell for obscured cell "
  2235. // << cell->name() << endl;
  2236. cell->paintCell( rect, painter, view,
  2237. corner,
  2238. TQPoint( cellRef.x() + x, cellRef.y() + y ),
  2239. paintBorder,
  2240. rightPen, bottomPen, leftPen, topPen,
  2241. mergedCellsPainted);
  2242. }
  2243. xpos += cl->dblWidth();
  2244. }
  2245. ypos += rl->dblHeight();
  2246. }
  2247. }
  2248. // Paint the background of this cell.
  2249. //
  2250. void Cell::paintBackground( TQPainter& painter, const KoRect &cellRect,
  2251. const TQPoint &cellRef, bool selected,
  2252. TQColor &backgroundColor )
  2253. {
  2254. TQColorGroup defaultColorGroup = TQApplication::palette().active();
  2255. TQRect zoomedCellRect = sheet()->doc()->zoomRect( cellRect );
  2256. // If this is not the KS_rowMax and/or KS_colMax, then we reduce
  2257. // width and/or height by one. This is due to the fact that the
  2258. // right/bottom most pixel is shared with the left/top most pixel of
  2259. // the following cell. Only in the case of KS_colMax/KS_rowMax we
  2260. // need to draw even this pixel, as there isn't a following cell to
  2261. // draw the background pixel.
  2262. if ( cellRef.x() != KS_colMax )
  2263. zoomedCellRect.setWidth( zoomedCellRect.width() - 1 );
  2264. if ( cellRef.y() != KS_rowMax )
  2265. zoomedCellRect.setHeight( zoomedCellRect.height() - 1 );
  2266. // Determine the correct background color
  2267. if ( selected )
  2268. {
  2269. //If the cell's background color is too bright, use the default highlight color
  2270. //Otherwise use a lighter version of the cell's background color.
  2271. TQColor c;
  2272. int averageColor = (backgroundColor.red() + backgroundColor.green() + backgroundColor.blue()) / 3;
  2273. if (averageColor > 180)
  2274. if (averageColor > 225)
  2275. c = View::highlightColor();
  2276. else
  2277. c = backgroundColor.light( 115 ); //15% lighter
  2278. else
  2279. c = backgroundColor.light( 125 ); //25% lighter
  2280. painter.setBackgroundColor( c );
  2281. }
  2282. else {
  2283. TQColor bg( backgroundColor );
  2284. // Handle printers separately.
  2285. if ( !painter.device()->isExtDev() ) {
  2286. if ( bg.isValid() )
  2287. painter.setBackgroundColor( bg );
  2288. else
  2289. painter.setBackgroundColor( defaultColorGroup.base() );
  2290. }
  2291. else {
  2292. //bad hack but there is a qt bug
  2293. //so I can print backgroundcolor
  2294. TQBrush bb( bg );
  2295. if ( !bg.isValid() )
  2296. bb.setColor( TQt::white );
  2297. painter.fillRect( zoomedCellRect, bb );
  2298. return;
  2299. }
  2300. }
  2301. // Erase the background of the cell.
  2302. if ( !painter.device()->isExtDev() )
  2303. painter.eraseRect( zoomedCellRect );
  2304. // Get a background brush
  2305. TQBrush bb;
  2306. if ( d->hasExtra()
  2307. && d->extra()->conditions
  2308. && d->extra()->conditions->matchedStyle()
  2309. && d->extra()->conditions->matchedStyle()->hasFeature( Style::SBackgroundBrush, true ) )
  2310. bb = d->extra()->conditions->matchedStyle()->backGroundBrush();
  2311. else
  2312. bb = backGroundBrush( cellRef.x(), cellRef.y() );
  2313. // Draw background pattern if necessary.
  2314. if ( bb.style() != TQt::NoBrush )
  2315. painter.fillRect( zoomedCellRect, bb );
  2316. backgroundColor = painter.backgroundColor();
  2317. }
  2318. // Paint the standard light grey borders that are always visible.
  2319. //
  2320. void Cell::paintDefaultBorders( TQPainter& painter, const KoRect &rect,
  2321. const KoRect &cellRect,
  2322. const TQPoint &cellRef,
  2323. bool paintBorderRight, bool /*paintBorderBottom*/,
  2324. bool paintBorderLeft, bool paintBorderTop,
  2325. TQPen const & rightPen, TQPen const & /*bottomPen*/,
  2326. TQPen const & leftPen, TQPen const & topPen )
  2327. {
  2328. /*
  2329. *** Notes about optimisation ***
  2330. This function was painting the top , left , right & bottom lines in almost all cells previously, contrary to what the comment
  2331. below says should happen. There doesn't appear to be a UI option to enable or disable showing of the grid when printing at the moment,
  2332. so I have disabled drawing of right and bottom borders for all cells.
  2333. I also couldn't work out under what conditions the variables dt / db would come out as anything other than 0 in the code
  2334. for painting the various borders. The effTopBorderPen / effBottomBorderPen calls were taking up a lot of time
  2335. according some profiling I did. If that code really is necessary, we need to find a more efficient way of getting the widths
  2336. than grabbing the whole TQPen object and asking it.
  2337. --Robert Knight (robertknight@gmail.com)
  2338. */
  2339. Doc* doc = sheet()->doc();
  2340. Sheet::LayoutDirection sheetDir = format()->sheet()->layoutDirection();
  2341. bool paintingToExternalDevice = painter.device()->isExtDev();
  2342. // Each cell is responsible for drawing it's top and left portions
  2343. // of the "default" grid. --Or not drawing it if it shouldn't be
  2344. // there. It's also responsible to paint the right and bottom, if
  2345. // it is the last cell on a print out.
  2346. bool paintTop;
  2347. bool paintLeft;
  2348. bool paintBottom=false;
  2349. bool paintRight=false;
  2350. paintLeft = ( paintBorderLeft && leftPen.style() == TQt::NoPen
  2351. && sheet()->getShowGrid() && sheetDir==Sheet::LeftToRight );
  2352. paintRight = ( paintBorderRight && rightPen.style() == TQt::NoPen
  2353. && sheet()->getShowGrid() && sheetDir==Sheet::RightToLeft );
  2354. paintTop = ( paintBorderTop && topPen.style() == TQt::NoPen
  2355. && sheet()->getShowGrid() );
  2356. // paintBottom = ( paintBorderBottom && sheet()->getShowGrid()
  2357. // && bottomPen.style() == TQt::NoPen );
  2358. //Set the single-pixel with pen for drawing the borders with.
  2359. painter.setPen( TQPen( sheet()->doc()->gridColor(), 1, TQt::SolidLine ) );
  2360. // If there are extra cells, there might be more conditions.
  2361. if (d->hasExtra()) {
  2362. TQValueList<Cell*>::const_iterator it = d->extra()->obscuringCells.begin();
  2363. TQValueList<Cell*>::const_iterator end = d->extra()->obscuringCells.end();
  2364. for ( ; it != end; ++it ) {
  2365. Cell *cell = *it;
  2366. paintTop = paintTop && ( cell->row() == cellRef.y() );
  2367. paintBottom = false;
  2368. if ( sheetDir == Sheet::RightToLeft ) {
  2369. paintRight = paintRight && ( cell->column() == cellRef.x() );
  2370. paintLeft = false;
  2371. }
  2372. else {
  2373. paintLeft = paintLeft && ( cell->column() == cellRef.x() );
  2374. paintRight = false;
  2375. }
  2376. }
  2377. }
  2378. // The left border.
  2379. if ( paintLeft ) {
  2380. int dt = 0;
  2381. int db = 0;
  2382. #if 0
  2383. if ( cellRef.x() > 1 ) {
  2384. Cell *cell_west = format()->sheet()->cellAt( cellRef.x() - 1,
  2385. cellRef.y() );
  2386. TQPen t = cell_west->effTopBorderPen( cellRef.x() - 1, cellRef.y() );
  2387. TQPen b = cell_west->effBottomBorderPen( cellRef.x() - 1, cellRef.y() );
  2388. if ( t.style() != TQt::NoPen )
  2389. dt = ( t.width() + 1 )/2;
  2390. if ( b.style() != TQt::NoPen )
  2391. db = ( t.width() / 2);
  2392. }
  2393. #endif
  2394. // If we are on paper printout, we limit the length of the lines.
  2395. // On paper, we always have full cells, on screen not.
  2396. if ( paintingToExternalDevice ) {
  2397. if ( sheetDir == Sheet::RightToLeft )
  2398. painter.drawLine( doc->zoomItX( TQMAX( rect.left(), cellRect.right() ) ),
  2399. doc->zoomItY( TQMAX( rect.top(), cellRect.y() + dt ) ),
  2400. doc->zoomItX( TQMIN( rect.right(), cellRect.right() ) ),
  2401. doc->zoomItY( TQMIN( rect.bottom(), cellRect.bottom() - db ) ) );
  2402. else
  2403. painter.drawLine( doc->zoomItX( TQMAX( rect.left(), cellRect.x() ) ),
  2404. doc->zoomItY( TQMAX( rect.top(), cellRect.y() + dt ) ),
  2405. doc->zoomItX( TQMIN( rect.right(), cellRect.x() ) ),
  2406. doc->zoomItY( TQMIN( rect.bottom(), cellRect.bottom() - db ) ) );
  2407. }
  2408. else {
  2409. if ( sheetDir == Sheet::RightToLeft )
  2410. painter.drawLine( doc->zoomItX( cellRect.right() ),
  2411. doc->zoomItY( cellRect.y() + dt ),
  2412. doc->zoomItX( cellRect.right() ),
  2413. doc->zoomItY( cellRect.bottom() - db ) );
  2414. else
  2415. painter.drawLine( doc->zoomItX( cellRect.x() ),
  2416. doc->zoomItY( cellRect.y() + dt ),
  2417. doc->zoomItX( cellRect.x() ),
  2418. doc->zoomItY( cellRect.bottom() - db ) );
  2419. }
  2420. }
  2421. // The top border.
  2422. if ( paintTop ) {
  2423. int dl = 0;
  2424. int dr = 0;
  2425. #if 0
  2426. if ( cellRef.y() > 1 ) {
  2427. Cell *cell_north = format()->sheet()->cellAt( cellRef.x(),
  2428. cellRef.y() - 1 );
  2429. TQPen l = cell_north->effLeftBorderPen( cellRef.x(), cellRef.y() - 1 );
  2430. TQPen r = cell_north->effRightBorderPen( cellRef.x(), cellRef.y() - 1 );
  2431. if ( l.style() != TQt::NoPen )
  2432. dl = ( l.width() - 1 ) / 2 + 1;
  2433. if ( r.style() != TQt::NoPen )
  2434. dr = r.width() / 2;
  2435. }
  2436. #endif
  2437. // If we are on paper printout, we limit the length of the lines.
  2438. // On paper, we always have full cells, on screen not.
  2439. if ( paintingToExternalDevice ) {
  2440. painter.drawLine( doc->zoomItX( TQMAX( rect.left(), cellRect.x() + dl ) ),
  2441. doc->zoomItY( TQMAX( rect.top(), cellRect.y() ) ),
  2442. doc->zoomItX( TQMIN( rect.right(), cellRect.right() - dr ) ),
  2443. doc->zoomItY( TQMIN( rect.bottom(), cellRect.y() ) ) );
  2444. }
  2445. else {
  2446. painter.drawLine( doc->zoomItX( cellRect.x() + dl ),
  2447. doc->zoomItY( cellRect.y() ),
  2448. doc->zoomItX( cellRect.right() - dr ),
  2449. doc->zoomItY( cellRect.y() ) );
  2450. }
  2451. }
  2452. // The right border.
  2453. if ( paintRight ) {
  2454. int dt = 0;
  2455. int db = 0;
  2456. #if 0
  2457. if ( cellRef.x() < KS_colMax ) {
  2458. Cell *cell_east = format()->sheet()->cellAt( cellRef.x() + 1,
  2459. cellRef.y() );
  2460. TQPen t = cell_east->effTopBorderPen( cellRef.x() + 1, cellRef.y() );
  2461. TQPen b = cell_east->effBottomBorderPen( cellRef.x() + 1, cellRef.y() );
  2462. if ( t.style() != TQt::NoPen )
  2463. dt = ( t.width() + 1 ) / 2;
  2464. if ( b.style() != TQt::NoPen )
  2465. db = ( t.width() / 2);
  2466. }
  2467. #endif
  2468. //painter.setPen( TQPen( sheet()->doc()->gridColor(), 1, TQt::SolidLine ) );
  2469. // If we are on paper printout, we limit the length of the lines.
  2470. // On paper, we always have full cells, on screen not.
  2471. if ( painter.device()->isExtDev() ) {
  2472. if ( sheetDir == Sheet::RightToLeft )
  2473. painter.drawLine( doc->zoomItX( TQMAX( rect.left(), cellRect.x() ) ),
  2474. doc->zoomItY( TQMAX( rect.top(), cellRect.y() + dt ) ),
  2475. doc->zoomItX( TQMIN( rect.right(), cellRect.x() ) ),
  2476. doc->zoomItY( TQMIN( rect.bottom(), cellRect.bottom() - db ) ) );
  2477. else
  2478. painter.drawLine( doc->zoomItX( TQMAX( rect.left(), cellRect.right() ) ),
  2479. doc->zoomItY( TQMAX( rect.top(), cellRect.y() + dt ) ),
  2480. doc->zoomItX( TQMIN( rect.right(), cellRect.right() ) ),
  2481. doc->zoomItY( TQMIN( rect.bottom(), cellRect.bottom() - db ) ) );
  2482. }
  2483. else {
  2484. if ( sheetDir == Sheet::RightToLeft )
  2485. painter.drawLine( doc->zoomItX( cellRect.x() ),
  2486. doc->zoomItY( cellRect.y() + dt ),
  2487. doc->zoomItX( cellRect.x() ),
  2488. doc->zoomItY( cellRect.bottom() - db ) );
  2489. else
  2490. painter.drawLine( doc->zoomItX( cellRect.right() ),
  2491. doc->zoomItY( cellRect.y() + dt ),
  2492. doc->zoomItX( cellRect.right() ),
  2493. doc->zoomItY( cellRect.bottom() - db ) );
  2494. }
  2495. }
  2496. // The bottom border.
  2497. /*if ( paintBottom ) {
  2498. int dl = 0;
  2499. int dr = 0;
  2500. if ( cellRef.y() < KS_rowMax ) {
  2501. Cell *cell_south = format()->sheet()->cellAt( cellRef.x(),
  2502. cellRef.y() + 1 );
  2503. TQPen l = cell_south->effLeftBorderPen( cellRef.x(), cellRef.y() + 1 );
  2504. TQPen r = cell_south->effRightBorderPen( cellRef.x(), cellRef.y() + 1 );
  2505. if ( l.style() != TQt::NoPen )
  2506. dl = ( l.width() - 1 ) / 2 + 1;
  2507. if ( r.style() != TQt::NoPen )
  2508. dr = r.width() / 2;
  2509. }
  2510. painter.setPen( TQPen( sheet()->doc()->gridColor(), 1, TQt::SolidLine ) );
  2511. // If we are on paper printout, we limit the length of the lines.
  2512. // On paper, we always have full cells, on screen not.
  2513. if ( painter.device()->isExtDev() ) {
  2514. painter.drawLine( doc->zoomItX( TQMAX( rect.left(), cellRect.x() + dl ) ),
  2515. doc->zoomItY( TQMAX( rect.top(), cellRect.bottom() ) ),
  2516. doc->zoomItX( TQMIN( rect.right(), cellRect.right() - dr ) ),
  2517. doc->zoomItY( TQMIN( rect.bottom(), cellRect.bottom() ) ) );
  2518. }
  2519. else {
  2520. painter.drawLine( doc->zoomItX( cellRect.x() + dl ),
  2521. doc->zoomItY( cellRect.bottom() ),
  2522. doc->zoomItX( cellRect.right() - dr ),
  2523. doc->zoomItY( cellRect.bottom() ) );
  2524. }
  2525. }*/
  2526. }
  2527. // Paint a comment indicator if the cell has a comment.
  2528. //
  2529. void Cell::paintCommentIndicator( TQPainter& painter,
  2530. const KoRect &cellRect,
  2531. const TQPoint &/*cellRef*/,
  2532. TQColor &backgroundColor )
  2533. {
  2534. Doc * doc = sheet()->doc();
  2535. // Point the little corner if there is a comment attached
  2536. // to this cell.
  2537. if ( ( format()->propertiesMask() & (uint) Format::PComment )
  2538. && cellRect.width() > 10.0
  2539. && cellRect.height() > 10.0
  2540. && ( sheet()->print()->printCommentIndicator()
  2541. || ( !painter.device()->isExtDev() && sheet()->getShowCommentIndicator() ) ) ) {
  2542. TQColor penColor = TQt::red;
  2543. // If background has high red part, switch to blue.
  2544. if ( tqRed( backgroundColor.rgb() ) > 127 &&
  2545. tqGreen( backgroundColor.rgb() ) < 80 &&
  2546. tqBlue( backgroundColor.rgb() ) < 80 )
  2547. {
  2548. penColor = TQt::blue;
  2549. }
  2550. // Get the triangle.
  2551. TQPointArray point( 3 );
  2552. if ( format()->sheet()->layoutDirection()==Sheet::RightToLeft ) {
  2553. point.setPoint( 0, doc->zoomItX( cellRect.x() + 6.0 ),
  2554. doc->zoomItY( cellRect.y() ) );
  2555. point.setPoint( 1, doc->zoomItX( cellRect.x() ),
  2556. doc->zoomItY( cellRect.y() ) );
  2557. point.setPoint( 2, doc->zoomItX( cellRect.x() ),
  2558. doc->zoomItY( cellRect.y() + 6.0 ) );
  2559. }
  2560. else {
  2561. point.setPoint( 0, doc->zoomItX( cellRect.right() - 5.0 ),
  2562. doc->zoomItY( cellRect.y() ) );
  2563. point.setPoint( 1, doc->zoomItX( cellRect.right() ),
  2564. doc->zoomItY( cellRect.y() ) );
  2565. point.setPoint( 2, doc->zoomItX( cellRect.right() ),
  2566. doc->zoomItY( cellRect.y() + 5.0 ) );
  2567. }
  2568. // And draw it.
  2569. painter.setBrush( TQBrush( penColor ) );
  2570. painter.setPen( TQt::NoPen );
  2571. painter.drawPolygon( point );
  2572. }
  2573. }
  2574. // Paint a small rectangle if this cell holds a formula.
  2575. //
  2576. void Cell::paintFormulaIndicator( TQPainter& painter,
  2577. const KoRect &cellRect,
  2578. TQColor &backgroundColor )
  2579. {
  2580. if ( isFormula() &&
  2581. format()->sheet()->getShowFormulaIndicator() &&
  2582. cellRect.width() > 10.0 &&
  2583. cellRect.height() > 10.0 )
  2584. {
  2585. Doc* doc = sheet()->doc();
  2586. TQColor penColor = TQt::blue;
  2587. // If background has high blue part, switch to red.
  2588. if ( tqRed( backgroundColor.rgb() ) < 80 &&
  2589. tqGreen( backgroundColor.rgb() ) < 80 &&
  2590. tqBlue( backgroundColor.rgb() ) > 127 )
  2591. {
  2592. penColor = TQt::red;
  2593. }
  2594. // Get the triangle...
  2595. TQPointArray point( 3 );
  2596. if ( format()->sheet()->layoutDirection()==Sheet::RightToLeft ) {
  2597. point.setPoint( 0, doc->zoomItX( cellRect.right() - 6.0 ),
  2598. doc->zoomItY( cellRect.bottom() ) );
  2599. point.setPoint( 1, doc->zoomItX( cellRect.right() ),
  2600. doc->zoomItY( cellRect.bottom() ) );
  2601. point.setPoint( 2, doc->zoomItX( cellRect.right() ),
  2602. doc->zoomItY( cellRect.bottom() - 6.0 ) );
  2603. }
  2604. else {
  2605. point.setPoint( 0, doc->zoomItX( cellRect.x() ),
  2606. doc->zoomItY( cellRect.bottom() - 6.0 ) );
  2607. point.setPoint( 1, doc->zoomItX( cellRect.x() ),
  2608. doc->zoomItY( cellRect.bottom() ) );
  2609. point.setPoint( 2, doc->zoomItX( cellRect.x() + 6.0 ),
  2610. doc->zoomItY( cellRect.bottom() ) );
  2611. }
  2612. // ...and draw it.
  2613. painter.setBrush( TQBrush( penColor ) );
  2614. painter.setPen( TQt::NoPen );
  2615. painter.drawPolygon( point );
  2616. }
  2617. }
  2618. // Paint an indicator that the text in the cell is cut.
  2619. //
  2620. void Cell::paintMoreTextIndicator( TQPainter& painter,
  2621. const KoRect &cellRect,
  2622. TQColor &backgroundColor )
  2623. {
  2624. // Show a red triangle when it's not possible to write all text in cell.
  2625. // Don't print the red triangle if we're printing.
  2626. if( testFlag( Flag_CellTooShortX ) &&
  2627. !painter.device()->isExtDev() &&
  2628. cellRect.height() > 4.0 &&
  2629. cellRect.width() > 4.0 )
  2630. {
  2631. Doc* doc = sheet()->doc();
  2632. TQColor penColor = TQt::red;
  2633. // If background has high red part, switch to blue.
  2634. if ( tqRed( backgroundColor.rgb() ) > 127
  2635. && tqGreen( backgroundColor.rgb() ) < 80
  2636. && tqBlue( backgroundColor.rgb() ) < 80 )
  2637. {
  2638. penColor = TQt::blue;
  2639. }
  2640. // Get the triangle...
  2641. TQPointArray point( 3 );
  2642. if ( d->strOutText.isRightToLeft() ) {
  2643. point.setPoint( 0, doc->zoomItX( cellRect.left() + 4.0 ),
  2644. doc->zoomItY( cellRect.y() + cellRect.height() / 2.0 -4.0 ) );
  2645. point.setPoint( 1, doc->zoomItX( cellRect.left() ),
  2646. doc->zoomItY( cellRect.y() + cellRect.height() / 2.0 ));
  2647. point.setPoint( 2, doc->zoomItX( cellRect.left() + 4.0 ),
  2648. doc->zoomItY( cellRect.y() + cellRect.height() / 2.0 +4.0 ) );
  2649. }
  2650. else {
  2651. point.setPoint( 0, doc->zoomItX( cellRect.right() - 4.0 ),
  2652. doc->zoomItY( cellRect.y() + cellRect.height() / 2.0 - 4.0 ) );
  2653. point.setPoint( 1, doc->zoomItX( cellRect.right() ),
  2654. doc->zoomItY( cellRect.y() + cellRect.height() / 2.0 ) );
  2655. point.setPoint( 2, doc->zoomItX( cellRect.right() - 4.0 ),
  2656. doc->zoomItY( cellRect.y() + cellRect.height() / 2.0 + 4.0 ) );
  2657. }
  2658. // ...and paint it.
  2659. painter.setBrush( TQBrush( penColor ) );
  2660. painter.setPen( TQt::NoPen );
  2661. painter.drawPolygon( point );
  2662. }
  2663. }
  2664. // Paint the real contents of a cell - the text.
  2665. //
  2666. void Cell::paintText( TQPainter& painter,
  2667. const KoRect &cellRect,
  2668. const TQPoint &cellRef )
  2669. {
  2670. Doc *doc = sheet()->doc();
  2671. ColumnFormat *colFormat = format()->sheet()->columnFormat( cellRef.x() );
  2672. TQColorGroup defaultColorGroup = TQApplication::palette().active();
  2673. TQColor textColorPrint = effTextColor( cellRef.x(), cellRef.y() );
  2674. // Resolve the text color if invalid (=default).
  2675. if ( !textColorPrint.isValid() ) {
  2676. if ( painter.device()->isExtDev() )
  2677. textColorPrint = TQt::black;
  2678. else
  2679. textColorPrint = TQApplication::palette().active().text();
  2680. }
  2681. TQPen tmpPen( textColorPrint );
  2682. // Set the font according to the current zoom.
  2683. applyZoomedFont( painter, cellRef.x(), cellRef.y() );
  2684. // Check for red font color for negative values.
  2685. if ( !d->hasExtra()
  2686. || !d->extra()->conditions
  2687. || !d->extra()->conditions->matchedStyle() ) {
  2688. if ( value().isNumber()
  2689. && !( format()->sheet()->getShowFormula()
  2690. && !( format()->sheet()->isProtected()
  2691. && format()->isHideFormula( d->column, d->row ) ) ) )
  2692. {
  2693. double v = value().asFloat();
  2694. if ( format()->floatColor( cellRef.x(), cellRef.y()) == Format::NegRed
  2695. && v < 0.0 )
  2696. tmpPen.setColor( TQt::red );
  2697. }
  2698. }
  2699. // Check for blue color, for hyperlink.
  2700. if ( !link().isEmpty() ) {
  2701. tmpPen.setColor( TQApplication::palette().active().link() );
  2702. TQFont f = painter.font();
  2703. f.setUnderline( true );
  2704. painter.setFont( f );
  2705. }
  2706. #if 0
  2707. /****
  2708. For now I am commenting this out -- with the default color display you
  2709. can read normal text through a highlighted background. Maybe this isn't
  2710. always the case, though, and we can put the highlighted text color back in.
  2711. In that case, we need to somewhere in here figure out if the text overlaps
  2712. another cell outside of the selection, otherwise that portion of the text
  2713. will be printed white on white. So just that portion would need to be
  2714. painted again in the normal color.
  2715. This should probably be done eventually, anyway, because I like using the
  2716. reverse text color for highlighted cells. I just don't like extending the
  2717. cell 'highlight' background outside of the selection rectangle because it
  2718. looks REALLY ugly.
  2719. */
  2720. if ( selected && ( cellRef.x() != marker.x() || cellRef.y() != marker.y() ) )
  2721. {
  2722. TQPen p( tmpPen );
  2723. p.setColor( defaultColorGroup.highlightedText() );
  2724. painter.setPen( p );
  2725. }
  2726. else {
  2727. painter.setPen(tmpPen);
  2728. }
  2729. #endif
  2730. painter.setPen( tmpPen );
  2731. TQString tmpText = d->strOutText;
  2732. double tmpHeight = d->textHeight;
  2733. double tmpWidth = d->textWidth;
  2734. // If the cell is to narrow to paint the whole contents, then pick
  2735. // out a part of the content that we paint. The result of this is
  2736. // dependent on the data type of the content.
  2737. //
  2738. // FIXME: Make this dependent on the height as well.
  2739. //
  2740. if ( testFlag( Flag_CellTooShortX ) ) {
  2741. d->strOutText = textDisplaying( painter );
  2742. // Recalculate the text width and the offset.
  2743. textSize( painter );
  2744. offsetAlign( column(), row() );
  2745. }
  2746. // Hide zero.
  2747. if ( format()->sheet()->getHideZero()
  2748. && value().isNumber()
  2749. && value().asFloat() == 0 ) {
  2750. d->strOutText = TQString();
  2751. }
  2752. // Clear extra cell if column or row is hidden
  2753. //
  2754. // FIXME: I think this should be done before the call to
  2755. // textDisplaying() above.
  2756. //
  2757. if ( colFormat->isHide() || ( cellRect.height() <= 2 ) ) {
  2758. freeAllObscuredCells(); /* TODO: This looks dangerous...must check when I
  2759. have time */
  2760. d->strOutText = "";
  2761. }
  2762. double indent = 0.0;
  2763. double offsetCellTooShort = 0.0;
  2764. int a = effAlignX();
  2765. // Apply indent if text is align to left not when text is at right or middle.
  2766. if ( a == Format::Left && !isEmpty() ) {
  2767. // FIXME: The following condition should be remade into a call to
  2768. // a new convenience function:
  2769. // if ( hasConditionStyleFeature( Style::SIndent, true )...
  2770. // This should be done throughout the entire file.
  2771. //
  2772. if ( d->hasExtra()
  2773. && d->extra()->conditions
  2774. && d->extra()->conditions->matchedStyle()
  2775. && d->extra()->conditions->matchedStyle()->hasFeature( Style::SIndent, true ) )
  2776. indent = d->extra()->conditions->matchedStyle()->indent();
  2777. else
  2778. indent = format()->getIndent( column(), row() );
  2779. }
  2780. // Made an offset, otherwise ### is under red triangle.
  2781. if ( a == Format::Right && !isEmpty() && testFlag( Flag_CellTooShortX ) )
  2782. offsetCellTooShort = format()->sheet()->doc()->unzoomItX( 4 );
  2783. TQFontMetrics fm2 = painter.fontMetrics();
  2784. double offsetFont = 0.0;
  2785. if ( format()->alignY( column(), row() ) == Format::Bottom
  2786. && format()->textFontUnderline( column(), row() ) )
  2787. offsetFont = format()->sheet()->doc()->unzoomItX( fm2.underlinePos() + 1 );
  2788. int tmpAngle;
  2789. bool tmpMultiRow;
  2790. bool tmpVerticalText;
  2791. // Check for angled or vertical text.
  2792. if ( d->hasExtra()
  2793. && d->extra()->conditions
  2794. && d->extra()->conditions->matchedStyle() )
  2795. {
  2796. Style *matchedStyle = d->extra()->conditions->matchedStyle();
  2797. if ( matchedStyle->hasFeature( Style::SAngle, true ) )
  2798. tmpAngle = d->extra()->conditions->matchedStyle()->rotateAngle();
  2799. else
  2800. tmpAngle = format()->getAngle( cellRef.x(), cellRef.y() );
  2801. if ( matchedStyle->hasFeature( Style::SVerticalText, true ) )
  2802. tmpVerticalText = matchedStyle->hasProperty( Style::PVerticalText );
  2803. else
  2804. tmpVerticalText = format()->verticalText( cellRef.x(), cellRef.y() );
  2805. if ( matchedStyle->hasFeature( Style::SMultiRow, true ) )
  2806. tmpMultiRow = matchedStyle->hasProperty( Style::PMultiRow );
  2807. else
  2808. tmpMultiRow = format()->multiRow( cellRef.x(), cellRef.y() );
  2809. }
  2810. else {
  2811. tmpAngle = format()->getAngle( cellRef.x(), cellRef.y() );
  2812. tmpVerticalText = format()->verticalText( cellRef.x(), cellRef.y() );
  2813. tmpMultiRow = format()->multiRow( cellRef.x(), cellRef.y() );
  2814. }
  2815. // Actually paint the text.
  2816. // There are 4 possible cases:
  2817. // - One line of text , horizontal
  2818. // - Angled text
  2819. // - Multiple rows of text , horizontal
  2820. // - Vertical text
  2821. if ( !tmpMultiRow && !tmpVerticalText && !tmpAngle ) {
  2822. // Case 1: The simple case, one line, no angle.
  2823. painter.drawText( doc->zoomItX( indent + cellRect.x() + d->textX - offsetCellTooShort ),
  2824. doc->zoomItY( cellRect.y() + d->textY - offsetFont ), d->strOutText );
  2825. }
  2826. else if ( tmpAngle != 0 ) {
  2827. // Case 2: an angle.
  2828. int angle = tmpAngle;
  2829. TQFontMetrics fm = painter.fontMetrics();
  2830. painter.rotate( angle );
  2831. double x;
  2832. if ( angle > 0 )
  2833. x = indent + cellRect.x() + d->textX;
  2834. else
  2835. x = indent + cellRect.x() + d->textX
  2836. - doc->unzoomItX((int) (( fm.descent() + fm.ascent() ) * sin( angle * M_PI / 180 )));
  2837. double y;
  2838. if ( angle > 0 )
  2839. y = cellRect.y() + d->textY;
  2840. else
  2841. y = cellRect.y() + d->textY + d->textHeight;
  2842. painter.drawText( doc->zoomItX( x * cos( angle * M_PI / 180 ) +
  2843. y * sin( angle * M_PI / 180 ) ),
  2844. doc->zoomItY( -x * sin( angle * M_PI / 180 ) +
  2845. y * cos( angle * M_PI / 180 ) ),
  2846. d->strOutText );
  2847. painter.rotate( -angle );
  2848. }
  2849. else if ( tmpMultiRow && !tmpVerticalText ) {
  2850. // Case 3: Multiple rows, but horizontal.
  2851. TQString t;
  2852. int i;
  2853. int pos = 0;
  2854. double dy = 0.0;
  2855. TQFontMetrics fm = painter.fontMetrics();
  2856. do {
  2857. i = d->strOutText.find( "\n", pos );
  2858. if ( i == -1 )
  2859. t = d->strOutText.mid( pos, d->strOutText.length() - pos );
  2860. else {
  2861. t = d->strOutText.mid( pos, i - pos );
  2862. pos = i + 1;
  2863. }
  2864. int align = effAlignX();
  2865. if ( format()->sheet()->getShowFormula()
  2866. && !( format()->sheet()->isProtected()
  2867. && format()->isHideFormula( d->column, d->row ) ) )
  2868. align = Format::Left;
  2869. // #### Torben: This looks duplicated for me
  2870. switch ( align ) {
  2871. case Format::Left:
  2872. d->textX = effLeftBorderPen( cellRef.x(), cellRef.y() ).width() + BORDER_SPACE;
  2873. break;
  2874. case Format::Right:
  2875. d->textX = cellRect.width() - BORDER_SPACE - doc->unzoomItX( fm.width( t ) )
  2876. - effRightBorderPen( cellRef.x(), cellRef.y() ).width();
  2877. break;
  2878. case Format::Center:
  2879. d->textX = ( cellRect.width() - doc->unzoomItX( fm.width( t ) ) ) / 2;
  2880. }
  2881. painter.drawText( doc->zoomItX( indent + cellRect.x() + d->textX ),
  2882. doc->zoomItY( cellRect.y() + d->textY + dy ), t );
  2883. dy += doc->unzoomItY( fm.descent() + fm.ascent() );
  2884. } while ( i != -1 );
  2885. }
  2886. else if ( tmpVerticalText && !d->strOutText.isEmpty() ) {
  2887. // Case 4: Vertical text.
  2888. TQString t;
  2889. int i = 0;
  2890. int len = 0;
  2891. double dy = 0.0;
  2892. TQFontMetrics fm = painter.fontMetrics();
  2893. do {
  2894. len = d->strOutText.length();
  2895. t = d->strOutText.at( i );
  2896. painter.drawText( doc->zoomItX( indent + cellRect.x() + d->textX ),
  2897. doc->zoomItY( cellRect.y() + d->textY + dy ), t );
  2898. dy += doc->unzoomItY( fm.descent() + fm.ascent() );
  2899. i++;
  2900. } while ( i != len );
  2901. }
  2902. // Check for too short cell and set the outText for future reference.
  2903. if ( testFlag( Flag_CellTooShortX ) ) {
  2904. d->strOutText = tmpText;
  2905. d->textHeight = tmpHeight;
  2906. d->textWidth = tmpWidth;
  2907. }
  2908. if ( format()->sheet()->getHideZero() && value().isNumber()
  2909. && value().asFloat() == 0 )
  2910. d->strOutText = tmpText;
  2911. if ( colFormat->isHide() || ( cellRect.height() <= 2 ) )
  2912. d->strOutText = tmpText;
  2913. }
  2914. // Paint page borders on the page. Only do this on the screen.
  2915. //
  2916. void Cell::paintPageBorders( TQPainter& painter,
  2917. const KoRect &cellRect,
  2918. const TQPoint &cellRef,
  2919. bool paintBorderRight,
  2920. bool paintBorderBottom )
  2921. {
  2922. // Not screen? Return immediately.
  2923. if ( painter.device()->isExtDev() )
  2924. return;
  2925. if ( ! format()->sheet()->isShowPageBorders() )
  2926. return;
  2927. SheetPrint* print = format()->sheet()->print();
  2928. Sheet::LayoutDirection sheetDir = format()->sheet()->layoutDirection();
  2929. Doc* doc = sheet()->doc();
  2930. int zcellRect_left = doc->zoomItX (cellRect.left());
  2931. int zcellRect_right = doc->zoomItX (cellRect.right());
  2932. int zcellRect_top = doc->zoomItY (cellRect.top());
  2933. int zcellRect_bottom = doc->zoomItY (cellRect.bottom());
  2934. // Draw page borders
  2935. if ( cellRef.x() >= print->printRange().left()
  2936. && cellRef.x() <= print->printRange().right() + 1
  2937. && cellRef.y() >= print->printRange().top()
  2938. && cellRef.y() <= print->printRange().bottom() + 1 )
  2939. {
  2940. if ( print->isOnNewPageX( cellRef.x() )
  2941. && cellRef.y() <= print->printRange().bottom() )
  2942. {
  2943. painter.setPen( sheet()->doc()->pageBorderColor() );
  2944. if ( sheetDir == Sheet::RightToLeft )
  2945. painter.drawLine( zcellRect_right, zcellRect_top,
  2946. zcellRect_right, zcellRect_bottom );
  2947. else
  2948. painter.drawLine( zcellRect_left, zcellRect_top,
  2949. zcellRect_left, zcellRect_bottom );
  2950. }
  2951. if ( print->isOnNewPageY( cellRef.y() ) &&
  2952. ( cellRef.x() <= print->printRange().right() ) )
  2953. {
  2954. painter.setPen( sheet()->doc()->pageBorderColor() );
  2955. painter.drawLine( zcellRect_left, zcellRect_top,
  2956. zcellRect_right, zcellRect_top );
  2957. }
  2958. if ( paintBorderRight ) {
  2959. if ( print->isOnNewPageX( cellRef.x() + 1 )
  2960. && cellRef.y() <= print->printRange().bottom() ) {
  2961. painter.setPen( sheet()->doc()->pageBorderColor() );
  2962. if ( sheetDir == Sheet::RightToLeft )
  2963. painter.drawLine( zcellRect_left, zcellRect_top,
  2964. zcellRect_left, zcellRect_bottom );
  2965. else
  2966. painter.drawLine( zcellRect_right, zcellRect_top,
  2967. zcellRect_right, zcellRect_bottom );
  2968. }
  2969. }
  2970. if ( paintBorderBottom ) {
  2971. if ( print->isOnNewPageY( cellRef.y() + 1 )
  2972. && cellRef.x() <= print->printRange().right() ) {
  2973. painter.setPen( sheet()->doc()->pageBorderColor() );
  2974. painter.drawLine( zcellRect_left, zcellRect_bottom,
  2975. zcellRect_right, zcellRect_bottom );
  2976. }
  2977. }
  2978. }
  2979. }
  2980. // Paint the cell borders.
  2981. //
  2982. void Cell::paintCellBorders( TQPainter& painter, const KoRect& rect,
  2983. const KoRect &cellRect,
  2984. const TQPoint &cellRef,
  2985. bool paintRight, bool paintBottom,
  2986. bool paintLeft, bool paintTop,
  2987. TQPen & _rightPen, TQPen & _bottomPen,
  2988. TQPen & _leftPen, TQPen & _topPen )
  2989. {
  2990. //Sanity check: If we are not painting any of the borders then the function
  2991. //really shouldn't be called at all.
  2992. if ( (!paintLeft) && (!paintRight) && (!paintTop) && (!paintBottom) )
  2993. return;
  2994. Doc * doc = sheet()->doc();
  2995. Sheet::LayoutDirection sheetDir = format()->sheet()->layoutDirection();
  2996. // compute zoomed rectangles
  2997. // I don't use KoRect, because that ends up producing lots of warnings
  2998. // about double->int conversions in calls to painter.drawLine
  2999. int zrect_left (doc->zoomItX (rect.left()));
  3000. int zrect_right (doc->zoomItX (rect.right()));
  3001. int zrect_top (doc->zoomItY (rect.top()));
  3002. int zrect_bottom (doc->zoomItY (rect.bottom()));
  3003. int zcellRect_left (doc->zoomItX (cellRect.left()));
  3004. int zcellRect_right (doc->zoomItX (cellRect.right()));
  3005. int zcellRect_top (doc->zoomItY (cellRect.top()));
  3006. int zcellRect_bottom (doc->zoomItY (cellRect.bottom()));
  3007. /* we might not paint some borders if this cell is merged with another in
  3008. that direction
  3009. bool paintLeft = paintBorderLeft;
  3010. bool paintRight = paintBorderRight;
  3011. bool paintTop = paintBorderTop;
  3012. bool paintBottom = paintBorderBottom;
  3013. */
  3014. // paintRight = paintRight && ( extraXCells() == 0 );
  3015. // paintBottom = paintBottom && ( d->extra()->extraYCells() == 0 );
  3016. if (d->hasExtra()) {
  3017. TQValueList<Cell*>::const_iterator it = d->extra()->obscuringCells.begin();
  3018. TQValueList<Cell*>::const_iterator end = d->extra()->obscuringCells.end();
  3019. for ( ; it != end; ++it ) {
  3020. Cell* cell = *it;
  3021. int xDiff = cellRef.x() - cell->column();
  3022. int yDiff = cellRef.y() - cell->row();
  3023. paintLeft = paintLeft && xDiff == 0;
  3024. paintTop = paintTop && yDiff == 0;
  3025. // Paint the border(s) if either this one should or if we have a
  3026. // merged cell with this cell as its border.
  3027. paintRight = paintRight && cell->mergedXCells() == xDiff;
  3028. paintBottom = paintBottom && cell->mergedYCells() == yDiff;
  3029. }
  3030. }
  3031. // Must create copies of these since otherwise the zoomIt()
  3032. // operation will be performed on them repeatedly.
  3033. TQPen leftPen( _leftPen );
  3034. TQPen rightPen( _rightPen );
  3035. TQPen topPen( _topPen );
  3036. TQPen bottomPen( _bottomPen );
  3037. // Determine the pens that should be used for drawing
  3038. // the borders.
  3039. //
  3040. int left_penWidth = TQMAX( 1, doc->zoomItX( leftPen.width() ) );
  3041. int right_penWidth = TQMAX( 1, doc->zoomItX( rightPen.width() ) );
  3042. int top_penWidth = TQMAX( 1, doc->zoomItY( topPen.width() ) );
  3043. int bottom_penWidth = TQMAX( 1, doc->zoomItY( bottomPen.width() ) );
  3044. leftPen.setWidth( left_penWidth );
  3045. rightPen.setWidth( right_penWidth );
  3046. topPen.setWidth( top_penWidth );
  3047. bottomPen.setWidth( bottom_penWidth );
  3048. if ( paintLeft && leftPen.style() != TQt::NoPen ) {
  3049. int top = ( TQMAX( 0, -1 + top_penWidth ) ) / 2 +
  3050. ( ( TQMAX( 0, -1 + top_penWidth ) ) % 2 );
  3051. int bottom = ( TQMAX( 0, -1 + bottom_penWidth ) ) / 2 + 1;
  3052. painter.setPen( leftPen );
  3053. //kdDebug(36001) << " painting left border of cell " << name() << endl;
  3054. // If we are on paper printout, we limit the length of the lines.
  3055. // On paper, we always have full cells, on screen not.
  3056. if ( painter.device()->isExtDev() ) {
  3057. // FIXME: There is probably Cut&Paste bugs here as well as below.
  3058. // The TQMIN/TQMAX and left/right pairs don't really make sense.
  3059. //
  3060. // UPDATE: In fact, most of these TQMIN/TQMAX combinations
  3061. // are TOTALLY BOGUS. For one thing, the idea
  3062. // that we always have full cells on paper is wrong
  3063. // since we can have embedded sheets in e.g. kword,
  3064. // and those can be arbitrarily clipped. WE HAVE TO
  3065. // REVISE THIS WHOLE BORDER PAINTING SECTION!
  3066. //
  3067. if ( sheetDir == Sheet::RightToLeft )
  3068. painter.drawLine( TQMIN( zrect_right, zcellRect_right ),
  3069. TQMAX( zrect_top, zcellRect_top - top ),
  3070. TQMIN( zrect_right, zcellRect_right ),
  3071. TQMIN( zrect_bottom, zcellRect_bottom + bottom ) );
  3072. else
  3073. painter.drawLine( TQMAX( zrect_left, zcellRect_left ),
  3074. TQMAX( zrect_top, zcellRect_top - top ),
  3075. TQMAX( zrect_left, zcellRect_left ),
  3076. TQMIN( zrect_bottom, zcellRect_bottom + bottom ) );
  3077. }
  3078. else {
  3079. if ( sheetDir == Sheet::RightToLeft )
  3080. painter.drawLine( zcellRect_right,
  3081. zcellRect_top - top,
  3082. zcellRect_right,
  3083. zcellRect_bottom + bottom );
  3084. else
  3085. painter.drawLine( zcellRect_left,
  3086. zcellRect_top - top,
  3087. zcellRect_left,
  3088. zcellRect_bottom + bottom );
  3089. }
  3090. }
  3091. if ( paintRight && rightPen.style() != TQt::NoPen ) {
  3092. int top = ( TQMAX( 0, -1 + top_penWidth ) ) / 2 +
  3093. ( ( TQMAX( 0, -1 + top_penWidth ) ) % 2 );
  3094. int bottom = ( TQMAX( 0, -1 + bottom_penWidth ) ) / 2 + 1;
  3095. painter.setPen( rightPen );
  3096. //kdDebug(36001) << " painting right border of cell " << name() << endl;
  3097. // If we are on paper printout, we limit the length of the lines.
  3098. // On paper, we always have full cells, on screen not.
  3099. if ( painter.device()->isExtDev() ) {
  3100. if ( sheetDir == Sheet::RightToLeft )
  3101. painter.drawLine( TQMAX( zrect_left, zcellRect_left ),
  3102. TQMAX( zrect_top, zcellRect_top - top ),
  3103. TQMAX( zrect_left, zcellRect_left ),
  3104. TQMIN( zrect_bottom, zcellRect_bottom + bottom ) );
  3105. else {
  3106. // FIXME: This is the way all these things should look.
  3107. // Make it so.
  3108. //
  3109. // Only print the right border if it is visible.
  3110. if ( zcellRect_right <= zrect_right + right_penWidth / 2)
  3111. painter.drawLine( zcellRect_right,
  3112. TQMAX( zrect_top, zcellRect_top - top ),
  3113. zcellRect_right,
  3114. TQMIN( zrect_bottom, zcellRect_bottom + bottom ) );
  3115. }
  3116. }
  3117. else {
  3118. if ( sheetDir == Sheet::RightToLeft )
  3119. painter.drawLine( zcellRect_left,
  3120. zcellRect_top - top,
  3121. zcellRect_left,
  3122. zcellRect_bottom + bottom );
  3123. else
  3124. painter.drawLine( zcellRect_right,
  3125. zcellRect_top - top,
  3126. zcellRect_right,
  3127. zcellRect_bottom + bottom );
  3128. }
  3129. }
  3130. if ( paintTop && topPen.style() != TQt::NoPen ) {
  3131. painter.setPen( topPen );
  3132. //kdDebug(36001) << " painting top border of cell " << name()
  3133. // << " [" << zcellRect_left << "," << zcellRect_right
  3134. // << ": " << zcellRect_right - zcellRect_left << "]" << endl;
  3135. // If we are on paper printout, we limit the length of the lines.
  3136. // On paper, we always have full cells, on screen not.
  3137. if ( painter.device()->isExtDev() ) {
  3138. if ( zcellRect_top >= zrect_top + top_penWidth / 2)
  3139. painter.drawLine( TQMAX( zrect_left, zcellRect_left ),
  3140. zcellRect_top,
  3141. TQMIN( zrect_right, zcellRect_right ),
  3142. zcellRect_top );
  3143. }
  3144. else {
  3145. painter.drawLine( zcellRect_left, zcellRect_top,
  3146. zcellRect_right, zcellRect_top );
  3147. }
  3148. }
  3149. if ( paintBottom && bottomPen.style() != TQt::NoPen ) {
  3150. painter.setPen( bottomPen );
  3151. //kdDebug(36001) << " painting bottom border of cell " << name()
  3152. // << " [" << zcellRect_left << "," << zcellRect_right
  3153. // << ": " << zcellRect_right - zcellRect_left << "]" << endl;
  3154. // If we are on paper printout, we limit the length of the lines.
  3155. // On paper, we always have full cells, on screen not.
  3156. if ( painter.device()->isExtDev() ) {
  3157. if ( zcellRect_bottom <= zrect_bottom + bottom_penWidth / 2)
  3158. painter.drawLine( TQMAX( zrect_left, zcellRect_left ),
  3159. zcellRect_bottom,
  3160. TQMIN( zrect_right, zcellRect_right ),
  3161. zcellRect_bottom );
  3162. }
  3163. else {
  3164. painter.drawLine( zcellRect_left, zcellRect_bottom,
  3165. zcellRect_right, zcellRect_bottom );
  3166. }
  3167. }
  3168. // FIXME: Look very closely at when the following code is really needed.
  3169. // I can't really see any case, but I might be wrong.
  3170. // Since the code below is buggy, and incredibly complex,
  3171. // I am currently disabling it. If somebody wants to enable
  3172. // it again, then please also solve bug 68977: "Embedded KSpread
  3173. // document printing problem" at the same time.
  3174. return;
  3175. #if 0
  3176. // Look at the cells on our corners. It may happen that we
  3177. // just erased parts of their borders corner, so we might need
  3178. // to repaint these corners.
  3179. //
  3180. TQPen vert_pen, horz_pen;
  3181. int vert_penWidth, horz_penWidth;
  3182. // Some useful referenses.
  3183. Cell *cell_north = format()->sheet()->cellAt( cellRef.x(),
  3184. cellRef.y() - 1 );
  3185. Cell *cell_northwest = format()->sheet()->cellAt( cellRef.x() - 1,
  3186. cellRef.y() - 1 );
  3187. Cell *cell_west = format()->sheet()->cellAt( cellRef.x() - 1,
  3188. cellRef.y() );
  3189. Cell *cell_northeast = format()->sheet()->cellAt( cellRef.x() + 1,
  3190. cellRef.y() - 1 );
  3191. Cell *cell_east = format()->sheet()->cellAt( cellRef.x() + 1,
  3192. cellRef.y() );
  3193. Cell *cell_south = format()->sheet()->cellAt( cellRef.x(),
  3194. cellRef.y() + 1 );
  3195. Cell *cell_southwest = format()->sheet()->cellAt( cellRef.x() - 1,
  3196. cellRef.y() + 1 );
  3197. Cell *cell_southeast = format()->sheet()->cellAt( cellRef.x() + 1,
  3198. cellRef.y() + 1 );
  3199. // Fix the borders which meet at the top left corner
  3200. if ( cell_north->effLeftBorderValue( cellRef.x(), cellRef.y() - 1 )
  3201. >= cell_northwest->effRightBorderValue( cellRef.x() - 1, cellRef.y() - 1 ) )
  3202. vert_pen = cell_north->effLeftBorderPen( cellRef.x(), cellRef.y() - 1 );
  3203. else
  3204. vert_pen = cell_northwest->effRightBorderPen( cellRef.x() - 1,
  3205. cellRef.y() - 1 );
  3206. vert_penWidth = TQMAX( 1, doc->zoomItX( vert_pen.width() ) );
  3207. vert_pen.setWidth( vert_penWidth );
  3208. if ( vert_pen.style() != TQt::NoPen ) {
  3209. if ( cell_west->effTopBorderValue( cellRef.x() - 1, cellRef.y() )
  3210. >= cell_northwest->effBottomBorderValue( cellRef.x() - 1, cellRef.y() - 1 ) )
  3211. horz_pen = cell_west->effTopBorderPen( cellRef.x() - 1, cellRef.y() );
  3212. else
  3213. horz_pen = cell_northwest->effBottomBorderPen( cellRef.x() - 1,
  3214. cellRef.y() - 1 );
  3215. horz_penWidth = TQMAX( 1, doc->zoomItY( horz_pen.width() ) );
  3216. int bottom = ( TQMAX( 0, -1 + horz_penWidth ) ) / 2 + 1;
  3217. painter.setPen( vert_pen );
  3218. // If we are on paper printout, we limit the length of the lines.
  3219. // On paper, we always have full cells, on screen not.
  3220. if ( painter.device()->isExtDev() ) {
  3221. if ( sheetDir == Sheet::RightToLeft )
  3222. painter.drawLine( TQMAX( zrect_left, zcellRect_right ),
  3223. TQMAX( zrect_top, zcellRect_top ),
  3224. TQMIN( zrect_right, zcellRect_right ),
  3225. TQMIN( zrect_bottom, zcellRect_top + bottom ) );
  3226. else
  3227. painter.drawLine( TQMAX( zrect_left, zcellRect_left ),
  3228. TQMAX( zrect_top, zcellRect_top ),
  3229. TQMIN( zrect_right, zcellRect_left ),
  3230. TQMIN( zrect_bottom, zcellRect_top + bottom ) );
  3231. }
  3232. else {
  3233. if ( sheetDir == Sheet::RightToLeft )
  3234. painter.drawLine( zcellRect_right, zcellRect_top,
  3235. zcellRect_right, zcellRect_top + bottom );
  3236. else
  3237. painter.drawLine( zcellRect_left, zcellRect_top,
  3238. zcellRect_left, zcellRect_top + bottom );
  3239. }
  3240. }
  3241. // Fix the borders which meet at the top right corner
  3242. if ( cell_north->effRightBorderValue( cellRef.x(), cellRef.y() - 1 )
  3243. >= cell_northeast->effLeftBorderValue( cellRef.x() + 1,
  3244. cellRef.y() - 1 ) )
  3245. vert_pen = cell_north->effRightBorderPen( cellRef.x(), cellRef.y() - 1 );
  3246. else
  3247. vert_pen = cell_northeast->effLeftBorderPen( cellRef.x() + 1,
  3248. cellRef.y() - 1 );
  3249. // vert_pen = effRightBorderPen( cellRef.x(), cellRef.y() - 1 );
  3250. vert_penWidth = TQMAX( 1, doc->zoomItX( vert_pen.width() ) );
  3251. vert_pen.setWidth( vert_penWidth );
  3252. if ( ( vert_pen.style() != TQt::NoPen ) && ( cellRef.x() < KS_colMax ) ) {
  3253. if ( cell_east->effTopBorderValue( cellRef.x() + 1, cellRef.y() )
  3254. >= cell_northeast->effBottomBorderValue( cellRef.x() + 1,
  3255. cellRef.y() - 1 ) )
  3256. horz_pen = cell_east->effTopBorderPen( cellRef.x() + 1, cellRef.y() );
  3257. else
  3258. horz_pen = cell_northeast->effBottomBorderPen( cellRef.x() + 1,
  3259. cellRef.y() - 1 );
  3260. // horz_pen = effTopBorderPen( cellRef.x() + 1, cellRef.y() );
  3261. horz_penWidth = TQMAX( 1, doc->zoomItY( horz_pen.width() ) );
  3262. int bottom = ( TQMAX( 0, -1 + horz_penWidth ) ) / 2 + 1;
  3263. painter.setPen( vert_pen );
  3264. //If we are on paper printout, we limit the length of the lines
  3265. //On paper, we always have full cells, on screen not
  3266. if ( painter.device()->isExtDev() ) {
  3267. if ( sheetDir == Sheet::RightToLeft )
  3268. painter.drawLine( TQMAX( zrect_left, zcellRect_left ),
  3269. TQMAX( zrect_top, zcellRect_top ),
  3270. TQMIN( zrect_right, zcellRect_left ),
  3271. TQMIN( zrect_bottom, zcellRect_top + bottom ) );
  3272. else
  3273. painter.drawLine( TQMAX( zrect_left, zcellRect_right ),
  3274. TQMAX( zrect_top, zcellRect_top ),
  3275. TQMIN( zrect_right, zcellRect_right ),
  3276. TQMIN( zrect_bottom, zcellRect_top + bottom ) );
  3277. }
  3278. else {
  3279. if ( sheetDir == Sheet::RightToLeft )
  3280. painter.drawLine( zcellRect_left, zcellRect_top,
  3281. zcellRect_left, zcellRect_top + bottom );
  3282. else
  3283. painter.drawLine( zcellRect_right, zcellRect_top,
  3284. zcellRect_right, zcellRect_top + bottom );
  3285. }
  3286. }
  3287. // Bottom
  3288. if ( cellRef.y() < KS_rowMax ) {
  3289. // Fix the borders which meet at the bottom left corner
  3290. if ( cell_south->effLeftBorderValue( cellRef.x(), cellRef.y() + 1 )
  3291. >= cell_southwest->effRightBorderValue( cellRef.x() - 1,
  3292. cellRef.y() + 1 ) )
  3293. vert_pen = cell_south->effLeftBorderPen( cellRef.x(), cellRef.y() + 1 );
  3294. else
  3295. vert_pen = cell_southwest->effRightBorderPen( cellRef.x() - 1,
  3296. cellRef.y() + 1 );
  3297. // vert_pen = effLeftBorderPen( cellRef.x(), cellRef.y() + 1 );
  3298. vert_penWidth = TQMAX( 1, doc->zoomItY( vert_pen.width() ) );
  3299. vert_pen.setWidth( vert_penWidth );
  3300. if ( vert_pen.style() != TQt::NoPen ) {
  3301. if ( cell_west->effBottomBorderValue( cellRef.x() - 1, cellRef.y() )
  3302. >= cell_southwest->effTopBorderValue( cellRef.x() - 1,
  3303. cellRef.y() + 1 ) )
  3304. horz_pen = cell_west->effBottomBorderPen( cellRef.x() - 1,
  3305. cellRef.y() );
  3306. else
  3307. horz_pen = cell_southwest->effTopBorderPen( cellRef.x() - 1,
  3308. cellRef.y() + 1 );
  3309. // horz_pen = effBottomBorderPen( cellRef.x() - 1, cellRef.y() );
  3310. horz_penWidth = TQMAX( 1, doc->zoomItX( horz_pen.width() ) );
  3311. int bottom = ( TQMAX( 0, -1 + horz_penWidth ) ) / 2;
  3312. painter.setPen( vert_pen );
  3313. // If we are on paper printout, we limit the length of the lines.
  3314. // On paper, we always have full cells, on screen not.
  3315. if ( painter.device()->isExtDev() ) {
  3316. if ( sheetDir == Sheet::RightToLeft )
  3317. painter.drawLine( TQMAX( zrect_left, zcellRect_right ),
  3318. TQMAX( zrect_top, zcellRect_bottom - bottom ),
  3319. TQMIN( zrect_right, zcellRect_right ),
  3320. TQMIN( zrect_bottom, zcellRect_bottom ) );
  3321. else
  3322. painter.drawLine( TQMAX( zrect_left, zcellRect_left ),
  3323. TQMAX( zrect_top, zcellRect_bottom - bottom ),
  3324. TQMIN( zrect_right, zcellRect_left ),
  3325. TQMIN( zrect_bottom, zcellRect_bottom ) );
  3326. }
  3327. else {
  3328. if ( sheetDir == Sheet::RightToLeft )
  3329. painter.drawLine( zcellRect_right, zcellRect_bottom - bottom,
  3330. zcellRect_right, zcellRect_bottom );
  3331. else
  3332. painter.drawLine( zcellRect_left, zcellRect_bottom - bottom,
  3333. zcellRect_left, zcellRect_bottom );
  3334. }
  3335. }
  3336. // Fix the borders which meet at the bottom right corner
  3337. if ( cell_south->effRightBorderValue( cellRef.x(), cellRef.y() + 1 )
  3338. >= cell_southeast->effLeftBorderValue( cellRef.x() + 1,
  3339. cellRef.y() + 1 ) )
  3340. vert_pen = cell_south->effRightBorderPen( cellRef.x(), cellRef.y() + 1 );
  3341. else
  3342. vert_pen = cell_southeast->effLeftBorderPen( cellRef.x() + 1,
  3343. cellRef.y() + 1 );
  3344. // vert_pen = effRightBorderPen( cellRef.x(), cellRef.y() + 1 );
  3345. vert_penWidth = TQMAX( 1, doc->zoomItY( vert_pen.width() ) );
  3346. vert_pen.setWidth( vert_penWidth );
  3347. if ( ( vert_pen.style() != TQt::NoPen ) && ( cellRef.x() < KS_colMax ) ) {
  3348. if ( cell_east ->effBottomBorderValue( cellRef.x() + 1, cellRef.y() )
  3349. >= cell_southeast->effTopBorderValue( cellRef.x() + 1,
  3350. cellRef.y() + 1 ) )
  3351. horz_pen = format()->sheet()->cellAt( cellRef.x() + 1, cellRef.y() )
  3352. ->effBottomBorderPen( cellRef.x() + 1, cellRef.y() );
  3353. else
  3354. horz_pen = format()->sheet()->cellAt( cellRef.x() + 1, cellRef.y() + 1 )
  3355. ->effTopBorderPen( cellRef.x() + 1, cellRef.y() + 1 );
  3356. // horz_pen = effBottomBorderPen( cellRef.x() + 1, cellRef.y() );
  3357. horz_penWidth = TQMAX( 1, doc->zoomItX( horz_pen.width() ) );
  3358. int bottom = ( TQMAX( 0, -1 + horz_penWidth ) ) / 2;
  3359. painter.setPen( vert_pen );
  3360. // If we are on paper printout, we limit the length of the lines.
  3361. // On paper, we always have full cells, on screen not.
  3362. if ( painter.device()->isExtDev() ) {
  3363. if ( sheetDir == Sheet::RightToLeft )
  3364. painter.drawLine( TQMAX( zrect_left, zcellRect_left ),
  3365. TQMAX( zrect_top, zcellRect_bottom - bottom ),
  3366. TQMIN( zrect_right, zcellRect_left ),
  3367. TQMIN( zrect_bottom, zcellRect_bottom ) );
  3368. else
  3369. painter.drawLine( TQMAX( zrect_left, zcellRect_right ),
  3370. TQMAX( zrect_top, zcellRect_bottom - bottom ),
  3371. TQMIN( zrect_right, zcellRect_right ),
  3372. TQMIN( zrect_bottom, zcellRect_bottom ) );
  3373. }
  3374. else {
  3375. if ( sheetDir == Sheet::RightToLeft )
  3376. painter.drawLine( zcellRect_left, zcellRect_bottom - bottom,
  3377. zcellRect_left, zcellRect_bottom );
  3378. else
  3379. painter.drawLine( zcellRect_right, zcellRect_bottom - bottom,
  3380. zcellRect_right, zcellRect_bottom );
  3381. }
  3382. }
  3383. }
  3384. #endif
  3385. }
  3386. // Paint diagonal lines through the cell.
  3387. //
  3388. void Cell::paintCellDiagonalLines( TQPainter& painter,
  3389. const KoRect &cellRect,
  3390. const TQPoint &cellRef )
  3391. {
  3392. if ( isPartOfMerged() )
  3393. return;
  3394. Doc* doc = sheet()->doc();
  3395. if ( effFallDiagonalPen( cellRef.x(), cellRef.y() ).style() != TQt::NoPen ) {
  3396. painter.setPen( effFallDiagonalPen( cellRef.x(), cellRef.y() ) );
  3397. painter.drawLine( doc->zoomItX( cellRect.x() ),
  3398. doc->zoomItY( cellRect.y() ),
  3399. doc->zoomItX( cellRect.right() ),
  3400. doc->zoomItY( cellRect.bottom() ) );
  3401. }
  3402. if ( effGoUpDiagonalPen( cellRef.x(), cellRef.y() ).style() != TQt::NoPen ) {
  3403. painter.setPen( effGoUpDiagonalPen( cellRef.x(), cellRef.y() ) );
  3404. painter.drawLine( doc->zoomItX( cellRect.x() ),
  3405. doc->zoomItY( cellRect.bottom() ),
  3406. doc->zoomItX( cellRect.right() ),
  3407. doc->zoomItY( cellRect.y() ) );
  3408. }
  3409. }
  3410. // End of Painting
  3411. // ================================================================
  3412. int Cell::defineAlignX()
  3413. {
  3414. int a = format()->align( column(), row() );
  3415. if ( a == Format::Undefined )
  3416. {
  3417. //numbers should be right-aligned by default, as well as BiDi text
  3418. if ((formatType() == Text_format) || value().isString())
  3419. a = (d->strOutText.isRightToLeft()) ?
  3420. Format::Right : Format::Left;
  3421. else {
  3422. Value val = value();
  3423. while (val.isArray()) val = val.element (0, 0);
  3424. if (val.isBoolean() || val.isNumber())
  3425. a = Format::Right;
  3426. else
  3427. a = Format::Left;
  3428. }
  3429. }
  3430. return a;
  3431. }
  3432. int Cell::effAlignX()
  3433. {
  3434. if ( d->hasExtra() && d->extra()->conditions
  3435. && d->extra()->conditions->matchedStyle()
  3436. && d->extra()->conditions->matchedStyle()->hasFeature( Style::SAlignX, true ) )
  3437. return d->extra()->conditions->matchedStyle()->alignX();
  3438. return defineAlignX();
  3439. }
  3440. // Cut strOutText, so that it only holds the part that can be displayed.
  3441. //
  3442. // Used in paintText().
  3443. //
  3444. TQString Cell::textDisplaying( TQPainter &_painter )
  3445. {
  3446. TQFontMetrics fm = _painter.fontMetrics();
  3447. int a = format()->align( column(), row() );
  3448. bool isNumeric = value().isNumber();
  3449. if ( !format()->verticalText( column(),row() ) ) {
  3450. // Non-vertical text: the ordinary case.
  3451. // Not enough space but align to left
  3452. double len = 0.0;
  3453. int extraXCells = d->hasExtra() ? d->extra()->extraXCells : 0;
  3454. for ( int i = column(); i <= column() + extraXCells; i++ ) {
  3455. ColumnFormat *cl2 = format()->sheet()->columnFormat( i );
  3456. len += cl2->dblWidth() - 1.0; //-1.0 because the pixel in between 2 cells is shared between both cells
  3457. }
  3458. TQString tmp;
  3459. double tmpIndent = 0.0;
  3460. if ( !isEmpty() )
  3461. tmpIndent = format()->getIndent( column(), row() );
  3462. // Start out with the whole text, cut one character at a time, and
  3463. // when the text finally fits, return it.
  3464. for ( int i = d->strOutText.length(); i != 0; i-- )
  3465. {
  3466. //Note that numbers are always treated as left-aligned since if we have to cut digits off, they should
  3467. //always be the least significant ones at the end of the string
  3468. if ( a == Format::Left || a == Format::Undefined || isNumeric)
  3469. tmp = d->strOutText.left(i);
  3470. else if ( a == Format::Right)
  3471. tmp = d->strOutText.right(i);
  3472. else
  3473. tmp = d->strOutText.mid( ( d->strOutText.length() - i ) / 2, i);
  3474. if (isNumeric)
  3475. {
  3476. //For numeric values, we can cut off digits after the decimal point to make it fit,
  3477. //but not the integer part of the number.
  3478. //If this number still contains a fraction part then we don't need to do anything, if we have run
  3479. //out of space to fit even the integer part of the number then display #########
  3480. //TODO Perhaps try to display integer part in standard form if there is not enough room for it?
  3481. if (!tmp.contains('.'))
  3482. d->strOutText=TQString().fill('#',20);
  3483. }
  3484. // 4 equal length of red triangle +1 point.
  3485. if ( format()->sheet()->doc()->unzoomItX( fm.width( tmp ) ) + tmpIndent
  3486. < len - 4.0 - 1.0 )
  3487. {
  3488. if ( format()->getAngle( column(), row() ) != 0 )
  3489. {
  3490. TQString tmp2;
  3491. RowFormat *rl = format()->sheet()->rowFormat( row() );
  3492. if ( d->textHeight > rl->dblHeight() )
  3493. {
  3494. for ( int j = d->strOutText.length(); j != 0; j-- )
  3495. {
  3496. tmp2 = d->strOutText.left( j );
  3497. if ( format()->sheet()->doc()->unzoomItY( fm.width( tmp2 ) ) < rl->dblHeight() - 1.0 )
  3498. {
  3499. return d->strOutText.left( TQMIN( tmp.length(), tmp2.length() ) );
  3500. }
  3501. }
  3502. }
  3503. else
  3504. return tmp;
  3505. }
  3506. else
  3507. return tmp;
  3508. }
  3509. }
  3510. return TQString( "" );
  3511. }
  3512. else if ( format()->verticalText( column(), row() ) ) {
  3513. // Vertical text.
  3514. RowFormat *rl = format()->sheet()->rowFormat( row() );
  3515. double tmpIndent = 0.0;
  3516. // Not enough space but align to left.
  3517. double len = 0.0;
  3518. int extraXCells = d->hasExtra() ? d->extra()->extraXCells : 0;
  3519. for ( int i = column(); i <= column() + extraXCells; i++ ) {
  3520. ColumnFormat *cl2 = format()->sheet()->columnFormat( i );
  3521. // -1.0 because the pixel in between 2 cells is shared between both cells
  3522. len += cl2->dblWidth() - 1.0;
  3523. }
  3524. if ( !isEmpty() )
  3525. tmpIndent = format()->getIndent( column(), row() );
  3526. if ( ( d->textWidth + tmpIndent > len ) || d->textWidth == 0.0 )
  3527. return TQString( "" );
  3528. for ( int i = d->strOutText.length(); i != 0; i-- ) {
  3529. if ( format()->sheet()->doc()->unzoomItY( fm.ascent() + fm.descent() ) * i
  3530. < rl->dblHeight() - 1.0 )
  3531. return d->strOutText.left( i );
  3532. }
  3533. return TQString( "" );
  3534. }
  3535. ColumnFormat *cl = format()->sheet()->columnFormat( column() );
  3536. double w = cl->dblWidth();
  3537. if ( d->hasExtra() && (d->extra()->extraWidth != 0.0) )
  3538. w = d->extra()->extraWidth;
  3539. TQString tmp;
  3540. for ( int i = d->strOutText.length(); i != 0; i-- ) {
  3541. tmp = d->strOutText.left( i );
  3542. // 4 equals length of red triangle +1 pixel
  3543. if ( format()->sheet()->doc()->unzoomItX( fm.width( tmp ) ) < w - 4.0 - 1.0 )
  3544. return tmp;
  3545. }
  3546. return TQString();
  3547. }
  3548. double Cell::dblWidth( int _col, const Canvas *_canvas ) const
  3549. {
  3550. if ( _col < 0 )
  3551. _col = d->column;
  3552. if ( _canvas )
  3553. {
  3554. if ( testFlag(Flag_Merged) )
  3555. return d->extra()->extraWidth;
  3556. const ColumnFormat *cl = format()->sheet()->columnFormat( _col );
  3557. return cl->dblWidth( _canvas );
  3558. }
  3559. if ( testFlag(Flag_Merged) )
  3560. return d->extra()->extraWidth;
  3561. const ColumnFormat *cl = format()->sheet()->columnFormat( _col );
  3562. return cl->dblWidth();
  3563. }
  3564. int Cell::width( int _col, const Canvas *_canvas ) const
  3565. {
  3566. return int( dblWidth( _col, _canvas ) );
  3567. }
  3568. double Cell::dblHeight( int _row, const Canvas *_canvas ) const
  3569. {
  3570. if ( _row < 0 )
  3571. _row = d->row;
  3572. if ( _canvas )
  3573. {
  3574. if ( testFlag(Flag_Merged) )
  3575. return d->extra()->extraHeight;
  3576. const RowFormat *rl = format()->sheet()->rowFormat( _row );
  3577. return rl->dblHeight( _canvas );
  3578. }
  3579. if ( testFlag(Flag_Merged) )
  3580. return d->extra()->extraHeight;
  3581. const RowFormat *rl = format()->sheet()->rowFormat( _row );
  3582. return rl->dblHeight();
  3583. }
  3584. int Cell::height( int _row, const Canvas *_canvas ) const
  3585. {
  3586. return int( dblHeight( _row, _canvas ) );
  3587. }
  3588. ///////////////////////////////////////////
  3589. //
  3590. // Misc Properties.
  3591. // Reimplementation of Format methods.
  3592. //
  3593. ///////////////////////////////////////////
  3594. const TQBrush& Cell::backGroundBrush( int _col, int _row ) const
  3595. {
  3596. if ( d->hasExtra() && (!d->extra()->obscuringCells.isEmpty()) )
  3597. {
  3598. const Cell* cell = d->extra()->obscuringCells.first();
  3599. return cell->backGroundBrush( cell->column(), cell->row() );
  3600. }
  3601. return format()->backGroundBrush( _col, _row );
  3602. }
  3603. const TQColor& Cell::bgColor( int _col, int _row ) const
  3604. {
  3605. if ( d->hasExtra() && (!d->extra()->obscuringCells.isEmpty()) )
  3606. {
  3607. const Cell* cell = d->extra()->obscuringCells.first();
  3608. return cell->bgColor( cell->column(), cell->row() );
  3609. }
  3610. return format()->bgColor( _col, _row );
  3611. }
  3612. ///////////////////////////////////////////
  3613. //
  3614. // Borders.
  3615. // Reimplementation of Format methods.
  3616. //
  3617. ///////////////////////////////////////////
  3618. void Cell::setLeftBorderPen( const TQPen& p )
  3619. {
  3620. if ( column() == 1 )
  3621. {
  3622. Cell* cell = format()->sheet()->cellAt( column() - 1, row() );
  3623. if ( cell && cell->format()->hasProperty( Format::PRightBorder )
  3624. && format()->sheet()->cellAt( column(), row() ) == this )
  3625. cell->format()->clearProperty( Format::PRightBorder );
  3626. }
  3627. format()->setLeftBorderPen( p );
  3628. }
  3629. void Cell::setTopBorderPen( const TQPen& p )
  3630. {
  3631. if ( row() == 1 )
  3632. {
  3633. Cell* cell = format()->sheet()->cellAt( column(), row() - 1 );
  3634. if ( cell && cell->format()->hasProperty( Format::PBottomBorder )
  3635. && format()->sheet()->cellAt( column(), row() ) == this )
  3636. cell->format()->clearProperty( Format::PBottomBorder );
  3637. }
  3638. format()->setTopBorderPen( p );
  3639. }
  3640. void Cell::setRightBorderPen( const TQPen& p )
  3641. {
  3642. Cell* cell = 0L;
  3643. if ( column() < KS_colMax )
  3644. cell = format()->sheet()->cellAt( column() + 1, row() );
  3645. if ( cell && cell->format()->hasProperty( Format::PLeftBorder )
  3646. && format()->sheet()->cellAt( column(), row() ) == this )
  3647. cell->format()->clearProperty( Format::PLeftBorder );
  3648. format()->setRightBorderPen( p );
  3649. }
  3650. void Cell::setBottomBorderPen( const TQPen& p )
  3651. {
  3652. Cell* cell = 0L;
  3653. if ( row() < KS_rowMax )
  3654. cell = format()->sheet()->cellAt( column(), row() + 1 );
  3655. if ( cell && cell->format()->hasProperty( Format::PTopBorder )
  3656. && format()->sheet()->cellAt( column(), row() ) == this )
  3657. cell->format()->clearProperty( Format::PTopBorder );
  3658. format()->setBottomBorderPen( p );
  3659. }
  3660. const TQPen& Cell::rightBorderPen( int _col, int _row ) const
  3661. {
  3662. if ( !format()->hasProperty( Format::PRightBorder ) && ( _col < KS_colMax ) )
  3663. {
  3664. Cell * cell = format()->sheet()->cellAt( _col + 1, _row );
  3665. if ( cell && cell->format()->hasProperty( Format::PLeftBorder ) )
  3666. return cell->leftBorderPen( _col + 1, _row );
  3667. }
  3668. return format()->rightBorderPen( _col, _row );
  3669. }
  3670. const TQPen& Cell::leftBorderPen( int _col, int _row ) const
  3671. {
  3672. if ( !format()->hasProperty( Format::PLeftBorder ) )
  3673. {
  3674. const Cell * cell = format()->sheet()->cellAt( _col - 1, _row );
  3675. if ( cell && cell->format()->hasProperty( Format::PRightBorder ) )
  3676. return cell->rightBorderPen( _col - 1, _row );
  3677. }
  3678. return format()->leftBorderPen( _col, _row );
  3679. }
  3680. const TQPen& Cell::bottomBorderPen( int _col, int _row ) const
  3681. {
  3682. if ( !format()->hasProperty( Format::PBottomBorder ) && ( _row < KS_rowMax ) )
  3683. {
  3684. const Cell * cell = format()->sheet()->cellAt( _col, _row + 1 );
  3685. if ( cell && cell->format()->hasProperty( Format::PTopBorder ) )
  3686. return cell->topBorderPen( _col, _row + 1 );
  3687. }
  3688. return format()->bottomBorderPen( _col, _row );
  3689. }
  3690. const TQPen& Cell::topBorderPen( int _col, int _row ) const
  3691. {
  3692. if ( !format()->hasProperty( Format::PTopBorder ) )
  3693. {
  3694. const Cell * cell = format()->sheet()->cellAt( _col, _row - 1 );
  3695. if ( cell->format()->hasProperty( Format::PBottomBorder ) )
  3696. return cell->bottomBorderPen( _col, _row - 1 );
  3697. }
  3698. return format()->topBorderPen( _col, _row );
  3699. }
  3700. const TQColor & Cell::effTextColor( int col, int row ) const
  3701. {
  3702. if ( d->hasExtra() && d->extra()->conditions
  3703. && d->extra()->conditions->matchedStyle()
  3704. && d->extra()->conditions->matchedStyle()->hasFeature( Style::STextPen, true ) )
  3705. return d->extra()->conditions->matchedStyle()->pen().color();
  3706. return format()->textColor( col, row );
  3707. }
  3708. const TQPen& Cell::effLeftBorderPen( int col, int row ) const
  3709. {
  3710. if ( isPartOfMerged() )
  3711. {
  3712. Cell * cell = d->extra()->obscuringCells.first();
  3713. return cell->effLeftBorderPen( cell->column(), cell->row() );
  3714. }
  3715. if ( d->hasExtra() && d->extra()->conditions
  3716. && d->extra()->conditions->matchedStyle()
  3717. && d->extra()->conditions->matchedStyle()->hasFeature( Style::SLeftBorder, true ) )
  3718. return d->extra()->conditions->matchedStyle()->leftBorderPen();
  3719. return leftBorderPen( col, row );
  3720. }
  3721. const TQPen& Cell::effTopBorderPen( int col, int row ) const
  3722. {
  3723. if ( isPartOfMerged() )
  3724. {
  3725. Cell * cell = d->extra()->obscuringCells.first();
  3726. return cell->effTopBorderPen( cell->column(), cell->row() );
  3727. }
  3728. if ( d->hasExtra() && d->extra()->conditions
  3729. && d->extra()->conditions->matchedStyle()
  3730. && d->extra()->conditions->matchedStyle()->hasFeature( Style::STopBorder, true ) )
  3731. return d->extra()->conditions->matchedStyle()->topBorderPen();
  3732. return topBorderPen( col, row );
  3733. }
  3734. const TQPen& Cell::effRightBorderPen( int col, int row ) const
  3735. {
  3736. if ( isPartOfMerged() )
  3737. {
  3738. Cell * cell = d->extra()->obscuringCells.first();
  3739. return cell->effRightBorderPen( cell->column(), cell->row() );
  3740. }
  3741. if ( d->hasExtra() && d->extra()->conditions
  3742. && d->extra()->conditions->matchedStyle()
  3743. && d->extra()->conditions->matchedStyle()->hasFeature( Style::SRightBorder, true ) )
  3744. return d->extra()->conditions->matchedStyle()->rightBorderPen();
  3745. return rightBorderPen( col, row );
  3746. }
  3747. const TQPen& Cell::effBottomBorderPen( int col, int row ) const
  3748. {
  3749. if ( isPartOfMerged() )
  3750. {
  3751. Cell * cell = d->extra()->obscuringCells.first();
  3752. return cell->effBottomBorderPen( cell->column(), cell->row() );
  3753. }
  3754. if ( d->hasExtra() && d->extra()->conditions
  3755. && d->extra()->conditions->matchedStyle()
  3756. && d->extra()->conditions->matchedStyle()->hasFeature( Style::SBottomBorder, true ) )
  3757. return d->extra()->conditions->matchedStyle()->bottomBorderPen();
  3758. return bottomBorderPen( col, row );
  3759. }
  3760. const TQPen & Cell::effGoUpDiagonalPen( int col, int row ) const
  3761. {
  3762. if ( d->hasExtra() && d->extra()->conditions
  3763. && d->extra()->conditions->matchedStyle()
  3764. && d->extra()->conditions->matchedStyle()->hasFeature( Style::SGoUpDiagonal, true ) )
  3765. return d->extra()->conditions->matchedStyle()->goUpDiagonalPen();
  3766. return format()->goUpDiagonalPen( col, row );
  3767. }
  3768. const TQPen & Cell::effFallDiagonalPen( int col, int row ) const
  3769. {
  3770. if ( d->hasExtra() && d->extra()->conditions
  3771. && d->extra()->conditions->matchedStyle()
  3772. && d->extra()->conditions->matchedStyle()->hasFeature( Style::SFallDiagonal, true ) )
  3773. return d->extra()->conditions->matchedStyle()->fallDiagonalPen();
  3774. return format()->fallDiagonalPen( col, row );
  3775. }
  3776. uint Cell::effBottomBorderValue( int col, int row ) const
  3777. {
  3778. if ( isPartOfMerged() )
  3779. {
  3780. Cell * cell = d->extra()->obscuringCells.first();
  3781. return cell->effBottomBorderValue( cell->column(), cell->row() );
  3782. }
  3783. if ( d->hasExtra() && d->extra()->conditions
  3784. && d->extra()->conditions->matchedStyle() )
  3785. return d->extra()->conditions->matchedStyle()->bottomPenValue();
  3786. return format()->bottomBorderValue( col, row );
  3787. }
  3788. uint Cell::effRightBorderValue( int col, int row ) const
  3789. {
  3790. if ( isPartOfMerged() )
  3791. {
  3792. Cell * cell = d->extra()->obscuringCells.first();
  3793. return cell->effRightBorderValue( cell->column(), cell->row() );
  3794. }
  3795. if ( d->hasExtra() && d->extra()->conditions
  3796. && d->extra()->conditions->matchedStyle() )
  3797. return d->extra()->conditions->matchedStyle()->rightPenValue();
  3798. return format()->rightBorderValue( col, row );
  3799. }
  3800. uint Cell::effLeftBorderValue( int col, int row ) const
  3801. {
  3802. if ( isPartOfMerged() )
  3803. {
  3804. Cell * cell = d->extra()->obscuringCells.first();
  3805. return cell->effLeftBorderValue( cell->column(), cell->row() );
  3806. }
  3807. if ( d->hasExtra() && d->extra()->conditions
  3808. && d->extra()->conditions->matchedStyle() )
  3809. return d->extra()->conditions->matchedStyle()->leftPenValue();
  3810. return format()->leftBorderValue( col, row );
  3811. }
  3812. uint Cell::effTopBorderValue( int col, int row ) const
  3813. {
  3814. if ( isPartOfMerged() )
  3815. {
  3816. Cell * cell = d->extra()->obscuringCells.first();
  3817. return cell->effTopBorderValue( cell->column(), cell->row() );
  3818. }
  3819. if ( d->hasExtra() && d->extra()->conditions
  3820. && d->extra()->conditions->matchedStyle() )
  3821. return d->extra()->conditions->matchedStyle()->topPenValue();
  3822. return format()->topBorderValue( col, row );
  3823. }
  3824. ///////////////////////////////////////////
  3825. //
  3826. // Precision
  3827. //
  3828. ///////////////////////////////////////////
  3829. void Cell::incPrecision()
  3830. {
  3831. //TODO: This is ugly. Why not simply regenerate the text to display? Tomas
  3832. if ( !value().isNumber() )
  3833. return;
  3834. int tmpPreci = format()->precision( column(), row() );
  3835. if ( tmpPreci == -1 )
  3836. {
  3837. int pos = d->strOutText.find(decimal_point);
  3838. if ( pos == -1 )
  3839. pos = d->strOutText.find('.');
  3840. if ( pos == -1 )
  3841. format()->setPrecision(1);
  3842. else
  3843. {
  3844. int start = 0;
  3845. if ( d->strOutText.find('%') != -1 )
  3846. start = 2;
  3847. else if ( d->strOutText.find(locale()->currencySymbol()) == ((int)(d->strOutText.length()-locale()->currencySymbol().length())) )
  3848. start = locale()->currencySymbol().length() + 1;
  3849. else if ( (start=d->strOutText.find('E')) != -1 )
  3850. start = d->strOutText.length() - start;
  3851. //kdDebug(36001) << "start=" << start << " pos=" << pos << " length=" << d->strOutText.length() << endl;
  3852. format()->setPrecision( TQMAX( 0, (int)d->strOutText.length() - start - pos ) );
  3853. }
  3854. }
  3855. else if ( tmpPreci < 10 )
  3856. {
  3857. format()->setPrecision( ++tmpPreci );
  3858. }
  3859. setFlag(Flag_LayoutDirty);
  3860. }
  3861. void Cell::decPrecision()
  3862. {
  3863. //TODO: This is ugly. Why not simply regenerate the text to display? Tomas
  3864. if ( !value().isNumber() )
  3865. return;
  3866. int preciTmp = format()->precision( column(), row() );
  3867. // kdDebug(36001) << "decPrecision: tmpPreci = " << tmpPreci << endl;
  3868. if ( format()->precision(column(),row()) == -1 )
  3869. {
  3870. int pos = d->strOutText.find( decimal_point );
  3871. int start = 0;
  3872. if ( d->strOutText.find('%') != -1 )
  3873. start = 2;
  3874. else if ( d->strOutText.find(locale()->currencySymbol()) == ((int)(d->strOutText.length()-locale()->currencySymbol().length())) )
  3875. start = locale()->currencySymbol().length() + 1;
  3876. else if ( (start = d->strOutText.find('E')) != -1 )
  3877. start = d->strOutText.length() - start;
  3878. else
  3879. start = 0;
  3880. if ( pos == -1 )
  3881. return;
  3882. format()->setPrecision(d->strOutText.length() - pos - 2 - start);
  3883. // if ( preciTmp < 0 )
  3884. // format()->setPrecision( preciTmp );
  3885. }
  3886. else if ( preciTmp > 0 )
  3887. {
  3888. format()->setPrecision( --preciTmp );
  3889. }
  3890. setFlag( Flag_LayoutDirty );
  3891. }
  3892. //set numerical value
  3893. //used in Sheet::setSeries (nowhere else yet)
  3894. void Cell::setNumber( double number )
  3895. {
  3896. setValue( Value( number ) );
  3897. d->strText.setNum( number );
  3898. setDisplayText(d->strText);
  3899. checkNumberFormat();
  3900. }
  3901. void Cell::setCellText( const TQString& _text, bool asText )
  3902. {
  3903. // TQString ctext = _text;
  3904. // (Tomas) is this trim necessary for anything ?
  3905. // if( ctext.length() > 5000 )
  3906. // ctext = ctext.left( 5000 );
  3907. // empty string ?
  3908. if (_text.length() == 0) {
  3909. d->strOutText = d->strText = "";
  3910. setValue (Value::empty());
  3911. return;
  3912. }
  3913. // as text ?
  3914. if (asText) {
  3915. d->strOutText = _text;
  3916. d->strText = _text;
  3917. setValue (Value (_text));
  3918. return;
  3919. }
  3920. TQString oldText = d->strText;
  3921. setDisplayText( _text );
  3922. if(!format()->sheet()->isLoading() && !testValidity() )
  3923. {
  3924. //reapply old value if action == stop
  3925. setDisplayText( oldText );
  3926. }
  3927. }
  3928. void Cell::setDisplayText( const TQString& _text )
  3929. {
  3930. bool isLoading = format()->sheet()->isLoading();
  3931. if (!isLoading)
  3932. format()->sheet()->doc()->emitBeginOperation( false );
  3933. d->strText = _text;
  3934. /**
  3935. * A real formula "=A1+A2*3" was entered.
  3936. */
  3937. if ( !d->strText.isEmpty() && d->strText[0] == '=' )
  3938. {
  3939. setFlag(Flag_LayoutDirty);
  3940. setFlag(Flag_TextFormatDirty);
  3941. if ( !makeFormula() )
  3942. kdError(36001) << "ERROR: Syntax ERROR" << endl;
  3943. setCalcDirtyFlag ();
  3944. }
  3945. /**
  3946. * Some numeric value or a string.
  3947. */
  3948. else
  3949. {
  3950. // Find out what data type it is
  3951. checkTextInput();
  3952. setFlag(Flag_LayoutDirty);
  3953. setFlag(Flag_TextFormatDirty);
  3954. }
  3955. if ( !isLoading )
  3956. format()->sheet()->doc()->emitEndOperation( TQRect( d->column, d->row, 1, 1 ) );
  3957. }
  3958. void Cell::setLink( const TQString& link )
  3959. {
  3960. d->extra()->link = link;
  3961. if( !link.isEmpty() && d->strText.isEmpty() )
  3962. setCellText( link );
  3963. }
  3964. TQString Cell::link() const
  3965. {
  3966. return d->hasExtra() ? d->extra()->link : TQString();
  3967. }
  3968. void Cell::update()
  3969. {
  3970. /* those obscuring us need to redo their layout cause they can't obscure us
  3971. now that we've got text.
  3972. This includes cells obscuring cells that we are obscuring
  3973. */
  3974. for (int x = d->column; x <= d->column + extraXCells(); x++)
  3975. {
  3976. for (int y = d->row; y <= d->row + extraYCells(); y++)
  3977. {
  3978. Cell* cell = format()->sheet()->cellAt(x,y);
  3979. cell->setLayoutDirtyFlag();
  3980. }
  3981. }
  3982. setCalcDirtyFlag();
  3983. /* TODO - is this a good place for this? */
  3984. updateChart(true);
  3985. }
  3986. bool Cell::testValidity() const
  3987. {
  3988. bool valid = false;
  3989. if( d->hasExtra() && d->extra()->validity && d->extra()->validity->m_restriction != Restriction::None )
  3990. {
  3991. //fixme
  3992. if ( d->extra()->validity->allowEmptyCell && d->strText.isEmpty() )
  3993. return true;
  3994. if( value().isNumber() &&
  3995. (d->extra()->validity->m_restriction == Restriction::Number ||
  3996. (d->extra()->validity->m_restriction == Restriction::Integer &&
  3997. value().asFloat() == ceil(value().asFloat()))))
  3998. {
  3999. switch( d->extra()->validity->m_cond)
  4000. {
  4001. case Conditional::Equal:
  4002. valid = ( value().asFloat() - d->extra()->validity->valMin < DBL_EPSILON
  4003. && value().asFloat() - d->extra()->validity->valMin >
  4004. (0.0 - DBL_EPSILON));
  4005. break;
  4006. case Conditional::DifferentTo:
  4007. valid = !( ( value().asFloat() - d->extra()->validity->valMin < DBL_EPSILON
  4008. && value().asFloat() - d->extra()->validity->valMin >
  4009. (0.0 - DBL_EPSILON)) );
  4010. break;
  4011. case Conditional::Superior:
  4012. valid = ( value().asFloat() > d->extra()->validity->valMin);
  4013. break;
  4014. case Conditional::Inferior:
  4015. valid = ( value().asFloat() <d->extra()->validity->valMin);
  4016. break;
  4017. case Conditional::SuperiorEqual:
  4018. valid = ( value().asFloat() >= d->extra()->validity->valMin);
  4019. break;
  4020. case Conditional::InferiorEqual:
  4021. valid = (value().asFloat() <= d->extra()->validity->valMin);
  4022. break;
  4023. case Conditional::Between:
  4024. valid = ( value().asFloat() >= d->extra()->validity->valMin &&
  4025. value().asFloat() <= d->extra()->validity->valMax);
  4026. break;
  4027. case Conditional::Different:
  4028. valid = (value().asFloat() < d->extra()->validity->valMin ||
  4029. value().asFloat() > d->extra()->validity->valMax);
  4030. break;
  4031. default :
  4032. break;
  4033. }
  4034. }
  4035. else if(d->extra()->validity->m_restriction==Restriction::Text)
  4036. {
  4037. valid = value().isString();
  4038. }
  4039. else if ( d->extra()->validity->m_restriction == Restriction::List )
  4040. {
  4041. //test int value
  4042. if ( value().isString() && d->extra()->validity->listValidity.contains( value().asString() ) )
  4043. valid = true;
  4044. }
  4045. else if(d->extra()->validity->m_restriction==Restriction::TextLength)
  4046. {
  4047. if( value().isString() )
  4048. {
  4049. int len = d->strOutText.length();
  4050. switch( d->extra()->validity->m_cond)
  4051. {
  4052. case Conditional::Equal:
  4053. if (len == d->extra()->validity->valMin)
  4054. valid = true;
  4055. break;
  4056. case Conditional::DifferentTo:
  4057. if (len != d->extra()->validity->valMin)
  4058. valid = true;
  4059. break;
  4060. case Conditional::Superior:
  4061. if(len > d->extra()->validity->valMin)
  4062. valid = true;
  4063. break;
  4064. case Conditional::Inferior:
  4065. if(len < d->extra()->validity->valMin)
  4066. valid = true;
  4067. break;
  4068. case Conditional::SuperiorEqual:
  4069. if(len >= d->extra()->validity->valMin)
  4070. valid = true;
  4071. break;
  4072. case Conditional::InferiorEqual:
  4073. if(len <= d->extra()->validity->valMin)
  4074. valid = true;
  4075. break;
  4076. case Conditional::Between:
  4077. if(len >= d->extra()->validity->valMin && len <= d->extra()->validity->valMax)
  4078. valid = true;
  4079. break;
  4080. case Conditional::Different:
  4081. if(len <d->extra()->validity->valMin || len >d->extra()->validity->valMax)
  4082. valid = true;
  4083. break;
  4084. default :
  4085. break;
  4086. }
  4087. }
  4088. }
  4089. else if(d->extra()->validity->m_restriction == Restriction::Time && isTime())
  4090. {
  4091. switch( d->extra()->validity->m_cond)
  4092. {
  4093. case Conditional::Equal:
  4094. valid = (value().asTime() == d->extra()->validity->timeMin);
  4095. break;
  4096. case Conditional::DifferentTo:
  4097. valid = (value().asTime() != d->extra()->validity->timeMin);
  4098. break;
  4099. case Conditional::Superior:
  4100. valid = (value().asTime() > d->extra()->validity->timeMin);
  4101. break;
  4102. case Conditional::Inferior:
  4103. valid = (value().asTime() < d->extra()->validity->timeMin);
  4104. break;
  4105. case Conditional::SuperiorEqual:
  4106. valid = (value().asTime() >= d->extra()->validity->timeMin);
  4107. break;
  4108. case Conditional::InferiorEqual:
  4109. valid = (value().asTime() <= d->extra()->validity->timeMin);
  4110. break;
  4111. case Conditional::Between:
  4112. valid = (value().asTime() >= d->extra()->validity->timeMin &&
  4113. value().asTime() <= d->extra()->validity->timeMax);
  4114. break;
  4115. case Conditional::Different:
  4116. valid = (value().asTime() < d->extra()->validity->timeMin ||
  4117. value().asTime() > d->extra()->validity->timeMax);
  4118. break;
  4119. default :
  4120. break;
  4121. }
  4122. }
  4123. else if(d->extra()->validity->m_restriction == Restriction::Date && isDate())
  4124. {
  4125. switch( d->extra()->validity->m_cond)
  4126. {
  4127. case Conditional::Equal:
  4128. valid = (value().asDate() == d->extra()->validity->dateMin);
  4129. break;
  4130. case Conditional::DifferentTo:
  4131. valid = (value().asDate() != d->extra()->validity->dateMin);
  4132. break;
  4133. case Conditional::Superior:
  4134. valid = (value().asDate() > d->extra()->validity->dateMin);
  4135. break;
  4136. case Conditional::Inferior:
  4137. valid = (value().asDate() < d->extra()->validity->dateMin);
  4138. break;
  4139. case Conditional::SuperiorEqual:
  4140. valid = (value().asDate() >= d->extra()->validity->dateMin);
  4141. break;
  4142. case Conditional::InferiorEqual:
  4143. valid = (value().asDate() <= d->extra()->validity->dateMin);
  4144. break;
  4145. case Conditional::Between:
  4146. valid = (value().asDate() >= d->extra()->validity->dateMin &&
  4147. value().asDate() <= d->extra()->validity->dateMax);
  4148. break;
  4149. case Conditional::Different:
  4150. valid = (value().asDate() < d->extra()->validity->dateMin ||
  4151. value().asDate() > d->extra()->validity->dateMax);
  4152. break;
  4153. default :
  4154. break;
  4155. }
  4156. }
  4157. }
  4158. else
  4159. {
  4160. valid= true;
  4161. }
  4162. if(!valid &&d->extra()->validity != NULL && d->extra()->validity->displayMessage)
  4163. {
  4164. switch (d->extra()->validity->m_action )
  4165. {
  4166. case Action::Stop:
  4167. KMessageBox::error((TQWidget*)0L, d->extra()->validity->message,
  4168. d->extra()->validity->title);
  4169. break;
  4170. case Action::Warning:
  4171. KMessageBox::warningYesNo((TQWidget*)0L, d->extra()->validity->message,
  4172. d->extra()->validity->title);
  4173. break;
  4174. case Action::Information:
  4175. KMessageBox::information((TQWidget*)0L, d->extra()->validity->message,
  4176. d->extra()->validity->title);
  4177. break;
  4178. }
  4179. }
  4180. if (!d->hasExtra())
  4181. return true; //okay if there's no validity
  4182. return (valid || d->extra()->validity == NULL || d->extra()->validity->m_action != Action::Stop);
  4183. }
  4184. FormatType Cell::formatType() const
  4185. {
  4186. return format()->getFormatType( d->column, d->row );
  4187. }
  4188. double Cell::textWidth() const
  4189. {
  4190. return d->textWidth;
  4191. }
  4192. double Cell::textHeight() const
  4193. {
  4194. return d->textHeight;
  4195. }
  4196. int Cell::mergedXCells() const
  4197. {
  4198. return d->hasExtra() ? d->extra()->mergedXCells : 0;
  4199. }
  4200. int Cell::mergedYCells() const
  4201. {
  4202. return d->hasExtra() ? d->extra()->mergedYCells : 0;
  4203. }
  4204. int Cell::extraXCells() const
  4205. {
  4206. return d->hasExtra() ? d->extra()->extraXCells : 0;
  4207. }
  4208. int Cell::extraYCells() const
  4209. {
  4210. return d->hasExtra() ? d->extra()->extraYCells : 0;
  4211. }
  4212. double Cell::extraWidth() const
  4213. {
  4214. return d->hasExtra() ? d->extra()->extraWidth : 0;
  4215. }
  4216. double Cell::extraHeight() const
  4217. {
  4218. return d->hasExtra() ? d->extra()->extraHeight : 0;
  4219. }
  4220. bool Cell::isDate() const
  4221. {
  4222. FormatType ft = formatType();
  4223. return (formatIsDate (ft) || ((ft == Generic_format) &&
  4224. (value().format() == Value::fmt_Date)));
  4225. }
  4226. bool Cell::isTime() const
  4227. {
  4228. FormatType ft = formatType();
  4229. return (formatIsTime (ft) || ((ft == Generic_format) &&
  4230. (value().format() == Value::fmt_Time)));
  4231. }
  4232. void Cell::setCalcDirtyFlag()
  4233. {
  4234. if ( !isFormula() )
  4235. {
  4236. //don't set the flag if we don't hold a formula
  4237. clearFlag(Flag_CalcDirty);
  4238. return;
  4239. }
  4240. setFlag(Flag_CalcDirty);
  4241. format()->sheet()->setRegionPaintDirty(cellRect());
  4242. }
  4243. bool Cell::updateChart(bool refresh)
  4244. {
  4245. // Update a chart for example if it depends on this cell.
  4246. if ( d->row != 0 && d->column != 0 )
  4247. {
  4248. CellBinding *bind;
  4249. for ( bind = format()->sheet()->firstCellBinding(); bind != 0L; bind = format()->sheet()->nextCellBinding() )
  4250. {
  4251. if ( bind->contains( d->column, d->row ) )
  4252. {
  4253. if (!refresh)
  4254. return true;
  4255. bind->cellChanged( this );
  4256. }
  4257. }
  4258. return true;
  4259. }
  4260. return false;
  4261. }
  4262. double Cell::getDouble ()
  4263. {
  4264. if (isDefault())
  4265. return 0.0;
  4266. //(Tomas) umm can't we simply call value().asFloat() ?
  4267. if (isDate())
  4268. {
  4269. TQDate date = value().asDate();
  4270. TQDate dummy (1900, 1, 1);
  4271. return (dummy.daysTo (date) + 1);
  4272. }
  4273. if (isTime())
  4274. {
  4275. TQTime time = value().asTime();
  4276. TQTime dummy;
  4277. return dummy.secsTo( time );
  4278. }
  4279. if (value().isNumber())
  4280. return value().asFloat();
  4281. return 0.0;
  4282. }
  4283. void Cell::convertToDouble ()
  4284. {
  4285. if (isDefault())
  4286. return;
  4287. setValue (getDouble ());
  4288. }
  4289. void Cell::convertToPercent ()
  4290. {
  4291. if (isDefault())
  4292. return;
  4293. setValue (getDouble ());
  4294. d->value.setFormat (Value::fmt_Percent);
  4295. }
  4296. void Cell::convertToMoney ()
  4297. {
  4298. if (isDefault())
  4299. return;
  4300. setValue (getDouble ());
  4301. d->value.setFormat (Value::fmt_Money);
  4302. format()->setPrecision (locale()->fracDigits());
  4303. }
  4304. void Cell::convertToTime ()
  4305. {
  4306. //(Tomas) This is weird. And I mean *REALLY* weird. First, we
  4307. //generate a time (TQTime), then we convert it to text, then
  4308. //we give the text to the cell and ask it to parse it. Weird...
  4309. if (isDefault() || isEmpty())
  4310. return;
  4311. setValue (getDouble ());
  4312. TQTime time = value().asDateTime().time();
  4313. int msec = (int) ( (value().asFloat() - (int) value().asFloat()) * 1000 );
  4314. time = time.addMSecs( msec );
  4315. setCellText( time.toString() );
  4316. }
  4317. void Cell::convertToDate ()
  4318. {
  4319. //(Tomas) This is weird. And I mean *REALLY* weird. First, we
  4320. //generate a date (TQDate), then we convert it to text, then
  4321. //we give the text to the cell and ask it to parse it. Weird...
  4322. if (isDefault() || isEmpty())
  4323. return;
  4324. setValue (getDouble ());
  4325. //TODO: why did we call setValue(), when we override it here?
  4326. TQDate date(1900, 1, 1);
  4327. date = date.addDays( (int) value().asFloat() - 1 );
  4328. date = value().asDateTime().date();
  4329. setCellText (locale()->formatDate (date, true));
  4330. }
  4331. void Cell::checkTextInput()
  4332. {
  4333. // Goal of this method: determine the value of the cell
  4334. clearAllErrors();
  4335. d->value = Value::empty();
  4336. // Get the text from that cell
  4337. TQString str = d->strText;
  4338. sheet()->doc()->parser()->parse (str, this);
  4339. // Parsing as time acts like an autoformat: we even change d->strText
  4340. // [h]:mm:ss -> might get set by ValueParser
  4341. if (isTime() && (formatType() != Time_format7))
  4342. d->strText = locale()->formatTime( value().asDateTime().time(), true);
  4343. // convert first letter to uppercase ?
  4344. if (format()->sheet()->getFirstLetterUpper() && value().isString() &&
  4345. (!d->strText.isEmpty()))
  4346. {
  4347. TQString str = value().asString();
  4348. setValue( Value( str[0].upper() + str.right( str.length()-1 ) ) );
  4349. }
  4350. }
  4351. //used in calc, setNumber, ValueParser
  4352. void Cell::checkNumberFormat()
  4353. {
  4354. if ( formatType() == Number_format && value().isNumber() )
  4355. {
  4356. if ( value().asFloat() > 1e+10 )
  4357. format()->setFormatType( Scientific_format );
  4358. }
  4359. }
  4360. // ================================================================
  4361. // Saving and loading
  4362. TQDomElement Cell::save( TQDomDocument& doc,
  4363. int _x_offset, int _y_offset,
  4364. bool force, bool copy, bool era )
  4365. {
  4366. // Save the position of this cell
  4367. TQDomElement cell = doc.createElement( "cell" );
  4368. cell.setAttribute( "row", d->row - _y_offset );
  4369. cell.setAttribute( "column", d->column - _x_offset );
  4370. //
  4371. // Save the formatting information
  4372. //
  4373. TQDomElement formatElement = format()->save( doc, d->column, d->row, force, copy );
  4374. if ( formatElement.hasChildNodes() || formatElement.attributes().length() ) // don't save empty tags
  4375. cell.appendChild( formatElement );
  4376. if ( doesMergeCells() )
  4377. {
  4378. if ( extraXCells() )
  4379. formatElement.setAttribute( "colspan", extraXCells() );
  4380. if ( extraYCells() )
  4381. formatElement.setAttribute( "rowspan", extraYCells() );
  4382. }
  4383. if ( d->hasExtra() && d->extra()->conditions )
  4384. {
  4385. TQDomElement conditionElement = d->extra()->conditions->saveConditions( doc );
  4386. if ( !conditionElement.isNull() )
  4387. cell.appendChild( conditionElement );
  4388. }
  4389. if ( d->hasExtra() && (d->extra()->validity != 0) )
  4390. {
  4391. TQDomElement validity = doc.createElement("validity");
  4392. TQDomElement param=doc.createElement("param");
  4393. param.setAttribute("cond",(int)d->extra()->validity->m_cond);
  4394. param.setAttribute("action",(int)d->extra()->validity->m_action);
  4395. param.setAttribute("allow",(int)d->extra()->validity->m_restriction);
  4396. param.setAttribute("valmin",d->extra()->validity->valMin);
  4397. param.setAttribute("valmax",d->extra()->validity->valMax);
  4398. param.setAttribute("displaymessage",d->extra()->validity->displayMessage);
  4399. param.setAttribute("displayvalidationinformation",d->extra()->validity->displayValidationInformation);
  4400. param.setAttribute("allowemptycell",d->extra()->validity->allowEmptyCell);
  4401. if ( !d->extra()->validity->listValidity.isEmpty() )
  4402. param.setAttribute( "listvalidity", d->extra()->validity->listValidity.join( ";" ) );
  4403. validity.appendChild(param);
  4404. TQDomElement title = doc.createElement( "title" );
  4405. title.appendChild( doc.createTextNode( d->extra()->validity->title ) );
  4406. validity.appendChild( title );
  4407. TQDomElement message = doc.createElement( "message" );
  4408. message.appendChild( doc.createCDATASection( d->extra()->validity->message ) );
  4409. validity.appendChild( message );
  4410. TQDomElement inputTitle = doc.createElement( "inputtitle" );
  4411. inputTitle.appendChild( doc.createTextNode( d->extra()->validity->titleInfo ) );
  4412. validity.appendChild( inputTitle );
  4413. TQDomElement inputMessage = doc.createElement( "inputmessage" );
  4414. inputMessage.appendChild( doc.createTextNode( d->extra()->validity->messageInfo ) );
  4415. validity.appendChild( inputMessage );
  4416. TQString tmp;
  4417. if ( d->extra()->validity->timeMin.isValid() )
  4418. {
  4419. TQDomElement timeMin = doc.createElement( "timemin" );
  4420. tmp=d->extra()->validity->timeMin.toString();
  4421. timeMin.appendChild( doc.createTextNode( tmp ) );
  4422. validity.appendChild( timeMin );
  4423. }
  4424. if ( d->extra()->validity->timeMax.isValid() )
  4425. {
  4426. TQDomElement timeMax = doc.createElement( "timemax" );
  4427. tmp=d->extra()->validity->timeMax.toString();
  4428. timeMax.appendChild( doc.createTextNode( tmp ) );
  4429. validity.appendChild( timeMax );
  4430. }
  4431. if ( d->extra()->validity->dateMin.isValid() )
  4432. {
  4433. TQDomElement dateMin = doc.createElement( "datemin" );
  4434. TQString tmp("%1/%2/%3");
  4435. tmp = tmp.arg(d->extra()->validity->dateMin.year()).arg(d->extra()->validity->dateMin.month()).arg(d->extra()->validity->dateMin.day());
  4436. dateMin.appendChild( doc.createTextNode( tmp ) );
  4437. validity.appendChild( dateMin );
  4438. }
  4439. if ( d->extra()->validity->dateMax.isValid() )
  4440. {
  4441. TQDomElement dateMax = doc.createElement( "datemax" );
  4442. TQString tmp("%1/%2/%3");
  4443. tmp = tmp.arg(d->extra()->validity->dateMax.year()).arg(d->extra()->validity->dateMax.month()).arg(d->extra()->validity->dateMax.day());
  4444. dateMax.appendChild( doc.createTextNode( tmp ) );
  4445. validity.appendChild( dateMax );
  4446. }
  4447. cell.appendChild( validity );
  4448. }
  4449. if ( format()->comment() )
  4450. {
  4451. TQDomElement comment = doc.createElement( "comment" );
  4452. comment.appendChild( doc.createCDATASection( *format()->comment() ) );
  4453. cell.appendChild( comment );
  4454. }
  4455. //
  4456. // Save the text
  4457. //
  4458. if ( !d->strText.isEmpty() )
  4459. {
  4460. // Formulas need to be encoded to ensure that they
  4461. // are position independent.
  4462. if ( isFormula() )
  4463. {
  4464. TQDomElement text = doc.createElement( "text" );
  4465. // if we are cutting to the clipboard, relative references need to be encoded absolutely
  4466. text.appendChild( doc.createTextNode( encodeFormula( era ) ) );
  4467. cell.appendChild( text );
  4468. /* we still want to save the results of the formula */
  4469. TQDomElement formulaResult = doc.createElement( "result" );
  4470. saveCellResult( doc, formulaResult, d->strOutText );
  4471. cell.appendChild( formulaResult );
  4472. }
  4473. else if ( !link().isEmpty() )
  4474. {
  4475. // KSpread pre 1.4 saves link as rich text, marked with first char '
  4476. // Have to be saved in some CDATA section because of too many special charatcers.
  4477. TQDomElement text = doc.createElement( "text" );
  4478. TQString qml = "!<a href=\"" + link() + "\">" + d->strText + "</a>";
  4479. text.appendChild( doc.createCDATASection( qml ) );
  4480. cell.appendChild( text );
  4481. }
  4482. else
  4483. {
  4484. // Save the cell contents (in a locale-independent way)
  4485. TQDomElement text = doc.createElement( "text" );
  4486. saveCellResult( doc, text, d->strText );
  4487. cell.appendChild( text );
  4488. }
  4489. }
  4490. if ( cell.hasChildNodes() || cell.attributes().length() > 2 ) // don't save empty tags
  4491. // (the >2 is due to "row" and "column" attributes)
  4492. return cell;
  4493. else
  4494. return TQDomElement();
  4495. }
  4496. bool Cell::saveCellResult( TQDomDocument& doc, TQDomElement& result,
  4497. TQString str )
  4498. {
  4499. TQString dataType = "Other"; // fallback
  4500. if ( value().isNumber() )
  4501. {
  4502. if ( isDate() )
  4503. {
  4504. // serial number of date
  4505. TQDate dd = value().asDateTime().date();
  4506. dataType = "Date";
  4507. str = "%1/%2/%3";
  4508. str = str.arg(dd.year()).arg(dd.month()).arg(dd.day());
  4509. }
  4510. else if( isTime() )
  4511. {
  4512. // serial number of time
  4513. dataType = "Time";
  4514. str = value().asDateTime().time().toString();
  4515. }
  4516. else
  4517. {
  4518. // real number
  4519. dataType = "Num";
  4520. if (value().isInteger())
  4521. str = TQString::number(value().asInteger());
  4522. else
  4523. str = TQString::number(value().asFloat(), 'g', DBL_DIG);
  4524. }
  4525. }
  4526. if ( value().isBoolean() )
  4527. {
  4528. dataType = "Bool";
  4529. str = value().asBoolean() ? "true" : "false";
  4530. }
  4531. if ( value().isString() )
  4532. {
  4533. dataType = "Str";
  4534. str = value().asString();
  4535. }
  4536. result.setAttribute( "dataType", dataType );
  4537. if ( !d->strOutText.isEmpty() )
  4538. result.setAttribute( "outStr", d->strOutText );
  4539. result.appendChild( doc.createTextNode( str ) );
  4540. return true; /* really isn't much of a way for this function to fail */
  4541. }
  4542. void Cell::saveOasisAnnotation( KoXmlWriter &xmlwriter )
  4543. {
  4544. if ( format()->comment() )
  4545. {
  4546. //<office:annotation draw:style-name="gr1" draw:text-style-name="P1" svg:width="2.899cm" svg:height="2.691cm" svg:x="2.858cm" svg:y="0.001cm" draw:caption-point-x="-2.858cm" draw:caption-point-y="-0.001cm">
  4547. xmlwriter.startElement( "office:annotation" );
  4548. TQStringList text = TQStringList::split( "\n", *format()->comment() );
  4549. for ( TQStringList::Iterator it = text.begin(); it != text.end(); ++it ) {
  4550. xmlwriter.startElement( "text:p" );
  4551. xmlwriter.addTextNode( *it );
  4552. xmlwriter.endElement();
  4553. }
  4554. xmlwriter.endElement();
  4555. }
  4556. }
  4557. TQString Cell::saveOasisCellStyle( KoGenStyle &currentCellStyle, KoGenStyles &mainStyles )
  4558. {
  4559. if ( d->hasExtra() && d->extra()->conditions )
  4560. {
  4561. // this has to be an automatic style
  4562. currentCellStyle = KoGenStyle( Doc::STYLE_CELL_AUTO, "table-cell" );
  4563. d->extra()->conditions->saveOasisConditions( currentCellStyle );
  4564. }
  4565. return format()->saveOasisCellStyle( currentCellStyle, mainStyles );
  4566. }
  4567. bool Cell::saveOasis( KoXmlWriter& xmlwriter, KoGenStyles &mainStyles,
  4568. int row, int column, int &repeated,
  4569. GenValidationStyles &valStyle )
  4570. {
  4571. if ( !isPartOfMerged() )
  4572. xmlwriter.startElement( "table:table-cell" );
  4573. else
  4574. xmlwriter.startElement( "table:covered-table-cell" );
  4575. #if 0
  4576. //add font style
  4577. TQFont font;
  4578. Value const value( cell->value() );
  4579. if ( !cell->isDefault() )
  4580. {
  4581. font = cell->format()->textFont( i, row );
  4582. m_styles.addFont( font );
  4583. if ( cell->format()->hasProperty( Format::PComment ) )
  4584. hasComment = true;
  4585. }
  4586. #endif
  4587. // NOTE save the value before the style as long as the Formatter does not work correctly
  4588. if ( link().isEmpty() )
  4589. saveOasisValue (xmlwriter);
  4590. KoGenStyle currentCellStyle; // the type determined in saveOasisCellStyle
  4591. saveOasisCellStyle( currentCellStyle,mainStyles );
  4592. // skip 'table:style-name' attribute for the default style
  4593. if ( !currentCellStyle.isDefaultStyle() )
  4594. xmlwriter.addAttribute( "table:style-name", mainStyles.styles()[currentCellStyle] );
  4595. // group empty cells with the same style
  4596. if ( isEmpty() && !format()->hasProperty( Format::PComment ) &&
  4597. !isPartOfMerged() && !doesMergeCells() )
  4598. {
  4599. bool refCellIsDefault = isDefault();
  4600. int j = column + 1;
  4601. Cell *nextCell = format()->sheet()->getNextCellRight( column, row );
  4602. while ( nextCell )
  4603. {
  4604. // if
  4605. // the next cell is not the adjacent one
  4606. // or
  4607. // the next cell is not empty
  4608. if ( nextCell->column() != j || !nextCell->isEmpty() )
  4609. {
  4610. if ( refCellIsDefault )
  4611. {
  4612. // if the origin cell was a default cell,
  4613. // we count the default cells
  4614. repeated = nextCell->column() - j + 1;
  4615. }
  4616. // otherwise we just stop here to process the adjacent
  4617. // cell in the next iteration of the outer loop
  4618. // (in Sheet::saveOasisCells)
  4619. break;
  4620. }
  4621. KoGenStyle nextCellStyle; // the type is determined in saveOasisCellStyle
  4622. nextCell->saveOasisCellStyle( nextCellStyle,mainStyles );
  4623. if ( nextCell->isPartOfMerged() || nextCell->doesMergeCells() ||
  4624. nextCell->format()->hasProperty( Format::PComment ) ||
  4625. !(nextCellStyle == currentCellStyle) )
  4626. {
  4627. break;
  4628. }
  4629. ++repeated;
  4630. // get the next cell and set the index to the adjacent cell
  4631. nextCell = format()->sheet()->getNextCellRight( j++, row );
  4632. }
  4633. kdDebug() << "Cell::saveOasis: empty cell in column " << column << " "
  4634. << "repeated " << repeated << " time(s)" << endl;
  4635. if ( repeated > 1 )
  4636. xmlwriter.addAttribute( "table:number-columns-repeated", TQString::number( repeated ) );
  4637. }
  4638. if (d->hasExtra() && d->extra()->validity)
  4639. {
  4640. GenValidationStyle styleVal(d->extra()->validity);
  4641. xmlwriter.addAttribute( "table:validation-name", valStyle.lookup( styleVal ) );
  4642. }
  4643. if ( isFormula() )
  4644. {
  4645. //kdDebug() << "Formula found" << endl;
  4646. TQString formula( convertFormulaToOasisFormat( text() ) );
  4647. xmlwriter.addAttribute( "table:formula", formula );
  4648. }
  4649. else if ( !link().isEmpty() )
  4650. {
  4651. //kdDebug()<<"Link found \n";
  4652. xmlwriter.startElement( "text:p" );
  4653. xmlwriter.startElement( "text:a" );
  4654. //Reference cell is started by "#"
  4655. if ( localReferenceAnchor( link() ) )
  4656. xmlwriter.addAttribute( " xlink:href", ( "#"+link() ) );
  4657. else
  4658. xmlwriter.addAttribute( " xlink:href", link() );
  4659. xmlwriter.addTextNode( text() );
  4660. xmlwriter.endElement();
  4661. xmlwriter.endElement();
  4662. }
  4663. if ( doesMergeCells() )
  4664. {
  4665. int colSpan = mergedXCells() + 1;
  4666. int rowSpan = mergedYCells() + 1;
  4667. if ( colSpan > 1 )
  4668. xmlwriter.addAttribute( "table:number-columns-spanned", TQString::number( colSpan ) );
  4669. if ( rowSpan > 1 )
  4670. xmlwriter.addAttribute( "table:number-rows-spanned", TQString::number( rowSpan ) );
  4671. }
  4672. if ( !isEmpty() && link().isEmpty() )
  4673. {
  4674. xmlwriter.startElement( "text:p" );
  4675. xmlwriter.addTextNode( strOutText().utf8() );
  4676. xmlwriter.endElement();
  4677. }
  4678. saveOasisAnnotation( xmlwriter );
  4679. xmlwriter.endElement();
  4680. return true;
  4681. }
  4682. void Cell::saveOasisValue (KoXmlWriter &xmlWriter)
  4683. {
  4684. switch (value().format())
  4685. {
  4686. case Value::fmt_None: break; //NOTHING HERE
  4687. case Value::fmt_Boolean:
  4688. {
  4689. xmlWriter.addAttribute( "office:value-type", "boolean" );
  4690. xmlWriter.addAttribute( "office:boolean-value", ( value().asBoolean() ?
  4691. "true" : "false" ) );
  4692. break;
  4693. }
  4694. case Value::fmt_Number:
  4695. {
  4696. xmlWriter.addAttribute( "office:value-type", "float" );
  4697. if (value().isInteger())
  4698. xmlWriter.addAttribute( "office:value", TQString::number( value().asInteger() ) );
  4699. else
  4700. xmlWriter.addAttribute( "office:value", TQString::number( value().asFloat(), 'g', DBL_DIG ) );
  4701. break;
  4702. }
  4703. case Value::fmt_Percent:
  4704. {
  4705. xmlWriter.addAttribute( "office:value-type", "percentage" );
  4706. xmlWriter.addAttribute( "office:value",
  4707. TQString::number( value().asFloat() ) );
  4708. break;
  4709. }
  4710. case Value::fmt_Money:
  4711. {
  4712. xmlWriter.addAttribute( "office:value-type", "currency" );
  4713. Format::Currency currency;
  4714. if (format()->currencyInfo(currency))
  4715. xmlWriter.addAttribute( "office:currency", Currency::getCurrencyCode(currency.type) );
  4716. xmlWriter.addAttribute( "office:value",
  4717. TQString::number( value().asFloat() ) );
  4718. break;
  4719. }
  4720. case Value::fmt_DateTime: break; //NOTHING HERE
  4721. case Value::fmt_Date:
  4722. {
  4723. xmlWriter.addAttribute( "office:value-type", "date" );
  4724. xmlWriter.addAttribute( "office:date-value",
  4725. value().asDate().toString( Qt::ISODate ) );
  4726. break;
  4727. }
  4728. case Value::fmt_Time:
  4729. {
  4730. xmlWriter.addAttribute( "office:value-type", "time" );
  4731. xmlWriter.addAttribute( "office:time-value",
  4732. value().asTime().toString( "PThhHmmMssS" ) );
  4733. break;
  4734. }
  4735. case Value::fmt_String:
  4736. {
  4737. xmlWriter.addAttribute( "office:value-type", "string" );
  4738. xmlWriter.addAttribute( "office:string-value", value().asString() );
  4739. break;
  4740. }
  4741. };
  4742. }
  4743. TQString Cell::convertFormulaToOasisFormat( const TQString & formula ) const
  4744. {
  4745. TQString s;
  4746. TQRegExp exp("(\\$?)([a-zA-Z]+)(\\$?)([0-9]+)");
  4747. int n = exp.search( formula, 0 );
  4748. kdDebug() << "Exp: " << formula << ", n: " << n << ", Length: " << formula.length()
  4749. << ", Matched length: " << exp.matchedLength() << endl;
  4750. bool inQuote1 = false;
  4751. bool inQuote2 = false;
  4752. int i = 0;
  4753. int l = (int) formula.length();
  4754. if ( l <= 0 )
  4755. return formula;
  4756. while ( i < l )
  4757. {
  4758. if ( ( n != -1 ) && ( n < i ) )
  4759. {
  4760. n = exp.search( formula, i );
  4761. kdDebug() << "Exp: " << formula.right( l - i ) << ", n: " << n << endl;
  4762. }
  4763. if ( formula[i] == '"' )
  4764. {
  4765. inQuote1 = !inQuote1;
  4766. s += formula[i];
  4767. ++i;
  4768. continue;
  4769. }
  4770. if ( formula[i] == '\'' )
  4771. {
  4772. // named area
  4773. inQuote2 = !inQuote2;
  4774. ++i;
  4775. continue;
  4776. }
  4777. if ( inQuote1 || inQuote2 )
  4778. {
  4779. s += formula[i];
  4780. ++i;
  4781. continue;
  4782. }
  4783. if ( ( formula[i] == '=' ) && ( formula[i + 1] == '=' ) )
  4784. {
  4785. s += '=';
  4786. ++i;++i;
  4787. continue;
  4788. }
  4789. if ( formula[i] == '!' )
  4790. {
  4791. insertBracket( s );
  4792. s += '.';
  4793. ++i;
  4794. continue;
  4795. }
  4796. if ( formula[i] == ',' )
  4797. {
  4798. s += '.';
  4799. ++i;
  4800. continue;
  4801. }
  4802. if ( n == i )
  4803. {
  4804. int ml = exp.matchedLength();
  4805. if ( formula[ i + ml ] == '!' )
  4806. {
  4807. kdDebug() << "No cell ref but sheet name" << endl;
  4808. s += formula[i];
  4809. ++i;
  4810. continue;
  4811. }
  4812. if ( ( i > 0 ) && ( formula[i - 1] != '!' ) )
  4813. s += "[.";
  4814. for ( int j = 0; j < ml; ++j )
  4815. {
  4816. s += formula[i];
  4817. ++i;
  4818. }
  4819. s += ']';
  4820. continue;
  4821. }
  4822. s += formula[i];
  4823. ++i;
  4824. }
  4825. return s;
  4826. }
  4827. void Cell::loadOasisConditional( TQDomElement * style )
  4828. {
  4829. if ( style )//safe
  4830. {
  4831. TQDomElement e;
  4832. forEachElement( e, style->toElement() )
  4833. {
  4834. if ( e.localName() == "map" && e.namespaceURI() == KoXmlNS::style )
  4835. {
  4836. if (d->hasExtra())
  4837. delete d->extra()->conditions;
  4838. d->extra()->conditions = new Conditions( this );
  4839. d->extra()->conditions->loadOasisConditions( e );
  4840. d->extra()->conditions->checkMatches();
  4841. // break here
  4842. // Conditions::loadOasisConditions finishes the iteration
  4843. break;
  4844. }
  4845. }
  4846. }
  4847. }
  4848. bool Cell::loadOasis( const TQDomElement& element , KoOasisLoadingContext& oasisContext , Style* style )
  4849. {
  4850. kdDebug() << "*** Loading cell properties ***** at " << column() << "," << row () << endl;
  4851. if ( element.hasAttributeNS( KoXmlNS::table, "style-name" ) )
  4852. {
  4853. kdDebug()<<" table:style-name: "<<element.attributeNS( KoXmlNS::table, "style-name", TQString() )<<endl;
  4854. oasisContext.fillStyleStack( element, KoXmlNS::table, "styleName", "table-cell" );
  4855. TQString str = element.attributeNS( KoXmlNS::table, "style-name", TQString() );
  4856. const TQDomElement* cellStyle = oasisContext.oasisStyles().findStyle( str, "table-cell" );
  4857. if ( cellStyle )
  4858. loadOasisConditional( const_cast<TQDomElement *>( cellStyle ) );
  4859. }
  4860. if (style)
  4861. {
  4862. format()->setStyle( style );
  4863. }
  4864. //Search and load each paragraph of text. Each paragraph is separated by a line break.
  4865. loadOasisCellText( element );
  4866. //
  4867. // formula
  4868. //
  4869. bool isFormula = false;
  4870. if ( element.hasAttributeNS( KoXmlNS::table, "formula" ) )
  4871. {
  4872. kdDebug()<<" formula :"<<element.attributeNS( KoXmlNS::table, "formula", TQString() )<<endl;
  4873. isFormula = true;
  4874. TQString oasisFormula( element.attributeNS( KoXmlNS::table, "formula", TQString() ) );
  4875. //necessary to remove it to load formula from oocalc2.0 (use namespace)
  4876. if (oasisFormula.startsWith( "oooc:" ) )
  4877. oasisFormula= oasisFormula.mid( 5 );
  4878. else if (oasisFormula.startsWith( "kspr:" ) )
  4879. oasisFormula= oasisFormula.mid( 5 );
  4880. // TODO Stefan: merge this into Oasis::decodeFormula
  4881. checkForNamedAreas( oasisFormula );
  4882. oasisFormula = Oasis::decodeFormula( oasisFormula, locale() );
  4883. setCellText( oasisFormula );
  4884. }
  4885. else if ( d->strText.at(0) == '=' ) //prepend ' to the text to avoid = to be painted
  4886. d->strText.prepend('\'');
  4887. //
  4888. // validation
  4889. //
  4890. if ( element.hasAttributeNS( KoXmlNS::table, "validation-name" ) )
  4891. {
  4892. kdDebug()<<" validation-name: "<<element.attributeNS( KoXmlNS::table, "validation-name", TQString() )<<endl;
  4893. loadOasisValidation( element.attributeNS( KoXmlNS::table, "validation-name", TQString() ) );
  4894. }
  4895. //
  4896. // value type
  4897. //
  4898. if( element.hasAttributeNS( KoXmlNS::office, "value-type" ) )
  4899. {
  4900. TQString valuetype = element.attributeNS( KoXmlNS::office, "value-type", TQString() );
  4901. kdDebug()<<" value-type: " << valuetype << endl;
  4902. if( valuetype == "boolean" )
  4903. {
  4904. TQString val = element.attributeNS( KoXmlNS::office, "boolean-value", TQString() ).lower();
  4905. if( ( val == "true" ) || ( val == "false" ) )
  4906. {
  4907. bool value = val == "true";
  4908. setCellValue( value );
  4909. }
  4910. }
  4911. // integer and floating-point value
  4912. else if( valuetype == "float" )
  4913. {
  4914. bool ok = false;
  4915. double value = element.attributeNS( KoXmlNS::office, "value", TQString() ).toDouble( &ok );
  4916. if( ok )
  4917. setCellValue( value );
  4918. if ( !isFormula && d->strText.isEmpty())
  4919. {
  4920. TQString str = locale()->formatNumber( value, 15 );
  4921. setCellText( str );
  4922. }
  4923. }
  4924. // currency value
  4925. else if( valuetype == "currency" )
  4926. {
  4927. bool ok = false;
  4928. double value = element.attributeNS( KoXmlNS::office, "value", TQString() ).toDouble( &ok );
  4929. if( ok )
  4930. {
  4931. setCellValue( value, Money_format );
  4932. if (element.hasAttributeNS( KoXmlNS::office, "currency" ) )
  4933. {
  4934. Currency currency(element.attributeNS( KoXmlNS::office, "currency", TQString() ) );
  4935. format()->setCurrency( currency.getIndex(), currency.getDisplayCode() );
  4936. }
  4937. }
  4938. }
  4939. else if( valuetype == "percentage" )
  4940. {
  4941. bool ok = false;
  4942. double v = element.attributeNS( KoXmlNS::office, "value", TQString() ).toDouble( &ok );
  4943. if( ok )
  4944. {
  4945. Value value;
  4946. value.setValue (v);
  4947. value.setFormat (Value::fmt_Percent);
  4948. setCellValue( value );
  4949. if ( !isFormula && d->strText.isEmpty())
  4950. {
  4951. TQString str = locale()->formatNumber( v, 15 );
  4952. setCellText( str );
  4953. }
  4954. format()->setFormatType (Percentage_format);
  4955. }
  4956. }
  4957. else if ( valuetype == "date" )
  4958. {
  4959. TQString value = element.attributeNS( KoXmlNS::office, "value", TQString() );
  4960. if ( value.isEmpty() )
  4961. value = element.attributeNS( KoXmlNS::office, "date-value", TQString() );
  4962. kdDebug() << "Type: date, value: " << value << endl;
  4963. // "1980-10-15"
  4964. int year = 0, month = 0, day = 0;
  4965. bool ok = false;
  4966. int p1 = value.find( '-' );
  4967. if ( p1 > 0 )
  4968. year = value.left( p1 ).toInt( &ok );
  4969. kdDebug() << "year: " << value.left( p1 ) << endl;
  4970. int p2 = value.find( '-', ++p1 );
  4971. if ( ok )
  4972. month = value.mid( p1, p2 - p1 ).toInt( &ok );
  4973. kdDebug() << "month: " << value.mid( p1, p2 - p1 ) << endl;
  4974. if ( ok )
  4975. day = value.right( value.length() - p2 - 1 ).toInt( &ok );
  4976. kdDebug() << "day: " << value.right( value.length() - p2 ) << endl;
  4977. if ( ok )
  4978. {
  4979. setCellValue( TQDate( year, month, day ) );
  4980. if ( style )
  4981. format()->setFormatType (style->formatType());
  4982. kdDebug() << "Set TQDate: " << year << " - " << month << " - " << day << endl;
  4983. }
  4984. }
  4985. else if ( valuetype == "time" )
  4986. {
  4987. TQString value = element.attributeNS( KoXmlNS::office, "value", TQString() );
  4988. if ( value.isEmpty() )
  4989. value = element.attributeNS( KoXmlNS::office, "time-value", TQString() );
  4990. kdDebug() << "Type: time: " << value << endl;
  4991. // "PT15H10M12S"
  4992. int hours = 0, minutes = 0, seconds = 0;
  4993. int l = value.length();
  4994. TQString num;
  4995. bool ok = false;
  4996. for ( int i = 0; i < l; ++i )
  4997. {
  4998. if ( value[i].isNumber() )
  4999. {
  5000. num += value[i];
  5001. continue;
  5002. }
  5003. else if ( value[i] == 'H' )
  5004. hours = num.toInt( &ok );
  5005. else if ( value[i] == 'M' )
  5006. minutes = num.toInt( &ok );
  5007. else if ( value[i] == 'S' )
  5008. seconds = num.toInt( &ok );
  5009. else
  5010. continue;
  5011. kdDebug() << "Num: " << num << endl;
  5012. num = "";
  5013. if ( !ok )
  5014. break;
  5015. }
  5016. kdDebug() << "Hours: " << hours << ", " << minutes << ", " << seconds << endl;
  5017. if ( ok )
  5018. {
  5019. // Value kval( timeToNum( hours, minutes, seconds ) );
  5020. // cell->setValue( kval );
  5021. setCellValue( TQTime( hours % 24, minutes, seconds ) );
  5022. if ( style )
  5023. format()->setFormatType (style->formatType());
  5024. }
  5025. }
  5026. else if( valuetype == "string" )
  5027. {
  5028. TQString value = element.attributeNS( KoXmlNS::office, "value", TQString() );
  5029. if ( value.isEmpty() && element.hasAttributeNS( KoXmlNS::office, "string-value" ))
  5030. {
  5031. //if there is not string-value entry don't overwrite value stored into <text:p>
  5032. value = element.attributeNS( KoXmlNS::office, "string-value", TQString() );
  5033. setCellValue( value );
  5034. }
  5035. format()->setFormatType (Text_format);
  5036. }
  5037. else
  5038. kdDebug()<<" type of value found : "<<valuetype<<endl;
  5039. }
  5040. //
  5041. // merged cells ?
  5042. //
  5043. int colSpan = 1;
  5044. int rowSpan = 1;
  5045. if ( element.hasAttributeNS( KoXmlNS::table, "number-columns-spanned" ) )
  5046. {
  5047. bool ok = false;
  5048. int span = element.attributeNS( KoXmlNS::table, "number-columns-spanned", TQString() ).toInt( &ok );
  5049. if( ok ) colSpan = span;
  5050. }
  5051. if ( element.hasAttributeNS( KoXmlNS::table, "number-rows-spanned" ) )
  5052. {
  5053. bool ok = false;
  5054. int span = element.attributeNS( KoXmlNS::table, "number-rows-spanned", TQString() ).toInt( &ok );
  5055. if( ok ) rowSpan = span;
  5056. }
  5057. if ( colSpan > 1 || rowSpan > 1 )
  5058. mergeCells( d->column, d->row, colSpan - 1, rowSpan - 1 );
  5059. //
  5060. // cell comment/annotation
  5061. //
  5062. TQDomElement annotationElement = KoDom::namedItemNS( element, KoXmlNS::office, "annotation" );
  5063. if ( !annotationElement.isNull() )
  5064. {
  5065. TQString comment;
  5066. TQDomNode node = annotationElement.firstChild();
  5067. while( !node.isNull() )
  5068. {
  5069. TQDomElement commentElement = node.toElement();
  5070. if( !commentElement.isNull() )
  5071. if( commentElement.localName() == "p" && commentElement.namespaceURI() == KoXmlNS::text )
  5072. {
  5073. if( !comment.isEmpty() ) comment.append( '\n' );
  5074. comment.append( commentElement.text() );
  5075. }
  5076. node = node.nextSibling();
  5077. }
  5078. if( !comment.isEmpty() )
  5079. format()->setComment( comment );
  5080. }
  5081. TQDomElement frame = KoDom::namedItemNS( element, KoXmlNS::draw, "frame" );
  5082. if ( !frame.isNull() )
  5083. loadOasisObjects( frame, oasisContext );
  5084. if (isFormula)
  5085. setCalcDirtyFlag (); // formulas must be recalculated
  5086. return true;
  5087. }
  5088. void Cell::loadOasisCellText( const TQDomElement& parent )
  5089. {
  5090. //Search and load each paragraph of text. Each paragraph is separated by a line break
  5091. TQDomElement textParagraphElement;
  5092. TQString cellText;
  5093. bool multipleTextParagraphsFound=false;
  5094. forEachElement( textParagraphElement , parent )
  5095. {
  5096. if ( textParagraphElement.localName()=="p" &&
  5097. textParagraphElement.namespaceURI()== KoXmlNS::text )
  5098. {
  5099. // our text, could contain formating for value or result of formul
  5100. if (cellText.isEmpty())
  5101. cellText = textParagraphElement.text();
  5102. else
  5103. {
  5104. cellText += "\n"+textParagraphElement.text();
  5105. multipleTextParagraphsFound=true;
  5106. }
  5107. TQDomElement textA = KoDom::namedItemNS( textParagraphElement, KoXmlNS::text, "a" );
  5108. if( !textA.isNull() )
  5109. {
  5110. if ( textA.hasAttributeNS( KoXmlNS::xlink, "href" ) )
  5111. {
  5112. TQString link = textA.attributeNS( KoXmlNS::xlink, "href", TQString() );
  5113. cellText = textA.text();
  5114. setCellText( cellText );
  5115. setValue( cellText );
  5116. if ( link[0]=='#' )
  5117. link=link.remove( 0, 1 );
  5118. setLink( link );
  5119. }
  5120. }
  5121. }
  5122. }
  5123. if (!cellText.isNull())
  5124. {
  5125. setCellText( cellText );
  5126. setValue( cellText );
  5127. }
  5128. //Enable word wrapping if multiple lines of text have been found.
  5129. if ( multipleTextParagraphsFound )
  5130. {
  5131. format()->setMultiRow(true);
  5132. }
  5133. }
  5134. void Cell::loadOasisObjects( const TQDomElement &parent, KoOasisLoadingContext& oasisContext )
  5135. {
  5136. for( TQDomElement e = parent; !e.isNull(); e = e.nextSibling().toElement() )
  5137. {
  5138. if ( e.localName() == "frame" && e.namespaceURI() == KoXmlNS::draw )
  5139. {
  5140. EmbeddedObject *obj = 0;
  5141. TQDomNode object = KoDom::namedItemNS( e, KoXmlNS::draw, "object" );
  5142. if ( !object.isNull() )
  5143. {
  5144. if ( !object.toElement().attributeNS( KoXmlNS::draw, "notify-on-update-of-ranges", TQString()).isNull() )
  5145. obj = new EmbeddedChart( sheet()->doc(), sheet() );
  5146. else
  5147. obj = new EmbeddedKOfficeObject( sheet()->doc(), sheet() );
  5148. }
  5149. else
  5150. {
  5151. TQDomNode image = KoDom::namedItemNS( e, KoXmlNS::draw, "image" );
  5152. if ( !image.isNull() )
  5153. obj = new EmbeddedPictureObject( sheet(), sheet()->doc()->pictureCollection() );
  5154. else
  5155. kdDebug() << "Object type wasn't loaded!" << endl;
  5156. }
  5157. if ( obj )
  5158. {
  5159. obj->loadOasis( e, oasisContext );
  5160. sheet()->doc()->insertObject( obj );
  5161. TQString ref = e.attributeNS( KoXmlNS::table, "end-cell-address", TQString() );
  5162. if ( ref.isNull() )
  5163. continue;
  5164. ref = Oasis::decodeFormula( ref );
  5165. Point point( ref );
  5166. if ( !point.isValid() )
  5167. continue;
  5168. KoRect geometry = obj->geometry();
  5169. geometry.setLeft( geometry.left() + sheet()->columnPos( d->column, 0 ) );
  5170. geometry.setTop( geometry.top() + sheet()->rowPos( d->row, 0 ) );
  5171. TQString str = e.attributeNS( KoXmlNS::table, "end-x", TQString() );
  5172. if ( !str.isNull() )
  5173. {
  5174. uint end_x = (uint) KoUnit::parseValue( str );
  5175. geometry.setRight( sheet()->columnPos( point.column(), 0) + end_x );
  5176. }
  5177. str = e.attributeNS( KoXmlNS::table, "end-y", TQString() );
  5178. if ( !str.isNull() )
  5179. {
  5180. uint end_y = (uint) KoUnit::parseValue( str );
  5181. geometry.setBottom( sheet()->rowPos( point.row(), 0) + end_y );
  5182. }
  5183. obj->setGeometry( geometry );
  5184. }
  5185. }
  5186. }
  5187. }
  5188. void Cell::loadOasisValidation( const TQString& validationName )
  5189. {
  5190. TQDomElement element = sheet()->doc()->loadingInfo()->validation( validationName);
  5191. if (d->hasExtra())
  5192. delete d->extra()->validity;
  5193. d->extra()->validity = new Validity;
  5194. if ( element.hasAttributeNS( KoXmlNS::table, "condition" ) )
  5195. {
  5196. TQString valExpression = element.attributeNS( KoXmlNS::table, "condition", TQString() );
  5197. kdDebug()<<" element.attribute( table:condition ) "<<valExpression<<endl;
  5198. //Condition ::= ExtendedTrueCondition | TrueFunction 'and' TrueCondition
  5199. //TrueFunction ::= cell-content-is-whole-number() | cell-content-is-decimal-number() | cell-content-is-date() | cell-content-is-time()
  5200. //ExtendedTrueCondition ::= ExtendedGetFunction | cell-content-text-length() Operator Value
  5201. //TrueCondition ::= GetFunction | cell-content() Operator Value
  5202. //GetFunction ::= cell-content-is-between(Value, Value) | cell-content-is-not-between(Value, Value)
  5203. //ExtendedGetFunction ::= cell-content-text-length-is-between(Value, Value) | cell-content-text-length-is-not-between(Value, Value)
  5204. //Operator ::= '<' | '>' | '<=' | '>=' | '=' | '!='
  5205. //Value ::= NumberValue | String | Formula
  5206. //A Formula is a formula without an equals (=) sign at the beginning. See section 8.1.3 for more information.
  5207. //A String comprises one or more characters surrounded by quotation marks.
  5208. //A NumberValue is a whole or decimal number. It must not contain comma separators for numbers of 1000 or greater.
  5209. //ExtendedTrueCondition
  5210. if ( valExpression.contains( "cell-content-text-length()" ) )
  5211. {
  5212. //"cell-content-text-length()>45"
  5213. valExpression = valExpression.remove("oooc:cell-content-text-length()" );
  5214. kdDebug()<<" valExpression = :"<<valExpression<<endl;
  5215. d->extra()->validity->m_restriction = Restriction::TextLength;
  5216. loadOasisValidationCondition( valExpression );
  5217. }
  5218. else if ( valExpression.contains( "cell-content-is-text()" ) )
  5219. {
  5220. d->extra()->validity->m_restriction = Restriction::Text;
  5221. }
  5222. //cell-content-text-length-is-between(Value, Value) | cell-content-text-length-is-not-between(Value, Value) | cell-content-is-in-list( StringList )
  5223. else if ( valExpression.contains( "cell-content-text-length-is-between" ) )
  5224. {
  5225. d->extra()->validity->m_restriction = Restriction::TextLength;
  5226. d->extra()->validity->m_cond = Conditional::Between;
  5227. valExpression = valExpression.remove( "oooc:cell-content-text-length-is-between(" );
  5228. kdDebug()<<" valExpression :"<<valExpression<<endl;
  5229. valExpression = valExpression.remove( ")" );
  5230. TQStringList listVal = TQStringList::split( ",", valExpression );
  5231. loadOasisValidationValue( listVal );
  5232. }
  5233. else if ( valExpression.contains( "cell-content-text-length-is-not-between" ) )
  5234. {
  5235. d->extra()->validity->m_restriction = Restriction::TextLength;
  5236. d->extra()->validity->m_cond = Conditional::Different;
  5237. valExpression = valExpression.remove( "oooc:cell-content-text-length-is-not-between(" );
  5238. kdDebug()<<" valExpression :"<<valExpression<<endl;
  5239. valExpression = valExpression.remove( ")" );
  5240. kdDebug()<<" valExpression :"<<valExpression<<endl;
  5241. TQStringList listVal = TQStringList::split( ",", valExpression );
  5242. loadOasisValidationValue( listVal );
  5243. }
  5244. else if ( valExpression.contains( "cell-content-is-in-list(" ) )
  5245. {
  5246. d->extra()->validity->m_restriction = Restriction::List;
  5247. valExpression = valExpression.remove( "oooc:cell-content-is-in-list(" );
  5248. kdDebug()<<" valExpression :"<<valExpression<<endl;
  5249. valExpression = valExpression.remove( ")" );
  5250. d->extra()->validity->listValidity = TQStringList::split( ";", valExpression );
  5251. }
  5252. //TrueFunction ::= cell-content-is-whole-number() | cell-content-is-decimal-number() | cell-content-is-date() | cell-content-is-time()
  5253. else
  5254. {
  5255. if (valExpression.contains( "cell-content-is-whole-number()" ) )
  5256. {
  5257. d->extra()->validity->m_restriction = Restriction::Number;
  5258. valExpression = valExpression.remove( "oooc:cell-content-is-whole-number() and " );
  5259. }
  5260. else if (valExpression.contains( "cell-content-is-decimal-number()" ) )
  5261. {
  5262. d->extra()->validity->m_restriction = Restriction::Integer;
  5263. valExpression = valExpression.remove( "oooc:cell-content-is-decimal-number() and " );
  5264. }
  5265. else if (valExpression.contains( "cell-content-is-date()" ) )
  5266. {
  5267. d->extra()->validity->m_restriction = Restriction::Date;
  5268. valExpression = valExpression.remove( "oooc:cell-content-is-date() and " );
  5269. }
  5270. else if (valExpression.contains( "cell-content-is-time()" ) )
  5271. {
  5272. d->extra()->validity->m_restriction = Restriction::Time;
  5273. valExpression = valExpression.remove( "oooc:cell-content-is-time() and " );
  5274. }
  5275. kdDebug()<<"valExpression :"<<valExpression<<endl;
  5276. if ( valExpression.contains( "cell-content()" ) )
  5277. {
  5278. valExpression = valExpression.remove( "cell-content()" );
  5279. loadOasisValidationCondition( valExpression );
  5280. }
  5281. //GetFunction ::= cell-content-is-between(Value, Value) | cell-content-is-not-between(Value, Value)
  5282. //for the moment we support just int/double value, not text/date/time :(
  5283. if ( valExpression.contains( "cell-content-is-between(" ) )
  5284. {
  5285. valExpression = valExpression.remove( "cell-content-is-between(" );
  5286. valExpression = valExpression.remove( ")" );
  5287. TQStringList listVal = TQStringList::split( "," , valExpression );
  5288. loadOasisValidationValue( listVal );
  5289. d->extra()->validity->m_cond = Conditional::Between;
  5290. }
  5291. if ( valExpression.contains( "cell-content-is-not-between(" ) )
  5292. {
  5293. valExpression = valExpression.remove( "cell-content-is-not-between(" );
  5294. valExpression = valExpression.remove( ")" );
  5295. TQStringList listVal = TQStringList::split( ",", valExpression );
  5296. loadOasisValidationValue( listVal );
  5297. d->extra()->validity->m_cond = Conditional::Different;
  5298. }
  5299. }
  5300. }
  5301. if ( element.hasAttributeNS( KoXmlNS::table, "allow-empty-cell" ) )
  5302. {
  5303. kdDebug()<<" element.hasAttribute( table:allow-empty-cell ) :"<<element.hasAttributeNS( KoXmlNS::table, "allow-empty-cell" )<<endl;
  5304. d->extra()->validity->allowEmptyCell = ( ( element.attributeNS( KoXmlNS::table, "allow-empty-cell", TQString() )=="true" ) ? true : false );
  5305. }
  5306. if ( element.hasAttributeNS( KoXmlNS::table, "base-cell-address" ) )
  5307. {
  5308. //todo what is it ?
  5309. }
  5310. TQDomElement help = KoDom::namedItemNS( element, KoXmlNS::table, "help-message" );
  5311. if ( !help.isNull() )
  5312. {
  5313. if ( help.hasAttributeNS( KoXmlNS::table, "title" ) )
  5314. {
  5315. kdDebug()<<"help.attribute( table:title ) :"<<help.attributeNS( KoXmlNS::table, "title", TQString() )<<endl;
  5316. d->extra()->validity->titleInfo = help.attributeNS( KoXmlNS::table, "title", TQString() );
  5317. }
  5318. if ( help.hasAttributeNS( KoXmlNS::table, "display" ) )
  5319. {
  5320. kdDebug()<<"help.attribute( table:display ) :"<<help.attributeNS( KoXmlNS::table, "display", TQString() )<<endl;
  5321. d->extra()->validity->displayValidationInformation = ( ( help.attributeNS( KoXmlNS::table, "display", TQString() )=="true" ) ? true : false );
  5322. }
  5323. TQDomElement attrText = KoDom::namedItemNS( help, KoXmlNS::text, "p" );
  5324. if ( !attrText.isNull() )
  5325. {
  5326. kdDebug()<<"help text :"<<attrText.text()<<endl;
  5327. d->extra()->validity->messageInfo = attrText.text();
  5328. }
  5329. }
  5330. TQDomElement error = KoDom::namedItemNS( element, KoXmlNS::table, "error-message" );
  5331. if ( !error.isNull() )
  5332. {
  5333. if ( error.hasAttributeNS( KoXmlNS::table, "title" ) )
  5334. d->extra()->validity->title = error.attributeNS( KoXmlNS::table, "title", TQString() );
  5335. if ( error.hasAttributeNS( KoXmlNS::table, "message-type" ) )
  5336. {
  5337. TQString str = error.attributeNS( KoXmlNS::table, "message-type", TQString() );
  5338. if ( str == "warning" )
  5339. d->extra()->validity->m_action = Action::Warning;
  5340. else if ( str == "information" )
  5341. d->extra()->validity->m_action = Action::Information;
  5342. else if ( str == "stop" )
  5343. d->extra()->validity->m_action = Action::Stop;
  5344. else
  5345. kdDebug()<<"validation : message type unknown :"<<str<<endl;
  5346. }
  5347. if ( error.hasAttributeNS( KoXmlNS::table, "display" ) )
  5348. {
  5349. kdDebug()<<" display message :"<<error.attributeNS( KoXmlNS::table, "display", TQString() )<<endl;
  5350. d->extra()->validity->displayMessage = (error.attributeNS( KoXmlNS::table, "display", TQString() )=="true");
  5351. }
  5352. TQDomElement attrText = KoDom::namedItemNS( error, KoXmlNS::text, "p" );
  5353. if ( !attrText.isNull() )
  5354. d->extra()->validity->message = attrText.text();
  5355. }
  5356. }
  5357. void Cell::loadOasisValidationValue( const TQStringList &listVal )
  5358. {
  5359. bool ok = false;
  5360. kdDebug()<<" listVal[0] :"<<listVal[0]<<" listVal[1] :"<<listVal[1]<<endl;
  5361. if ( d->extra()->validity->m_restriction == Restriction::Date )
  5362. {
  5363. d->extra()->validity->dateMin = TQDate::fromString( listVal[0] );
  5364. d->extra()->validity->dateMax = TQDate::fromString( listVal[1] );
  5365. }
  5366. else if ( d->extra()->validity->m_restriction == Restriction::Time )
  5367. {
  5368. d->extra()->validity->timeMin = TQTime::fromString( listVal[0] );
  5369. d->extra()->validity->timeMax = TQTime::fromString( listVal[1] );
  5370. }
  5371. else
  5372. {
  5373. d->extra()->validity->valMin = listVal[0].toDouble(&ok);
  5374. if ( !ok )
  5375. {
  5376. d->extra()->validity->valMin = listVal[0].toInt(&ok);
  5377. if ( !ok )
  5378. kdDebug()<<" Try to parse this value :"<<listVal[0]<<endl;
  5379. #if 0
  5380. if ( !ok )
  5381. d->extra()->validity->valMin = listVal[0];
  5382. #endif
  5383. }
  5384. ok=false;
  5385. d->extra()->validity->valMax = listVal[1].toDouble(&ok);
  5386. if ( !ok )
  5387. {
  5388. d->extra()->validity->valMax = listVal[1].toInt(&ok);
  5389. if ( !ok )
  5390. kdDebug()<<" Try to parse this value :"<<listVal[1]<<endl;
  5391. #if 0
  5392. if ( !ok )
  5393. d->extra()->validity->valMax = listVal[1];
  5394. #endif
  5395. }
  5396. }
  5397. }
  5398. void Cell::loadOasisValidationCondition( TQString &valExpression )
  5399. {
  5400. TQString value;
  5401. if (valExpression.find( "<=" )==0 )
  5402. {
  5403. value = valExpression.remove( 0,2 );
  5404. d->extra()->validity->m_cond = Conditional::InferiorEqual;
  5405. }
  5406. else if (valExpression.find( ">=" )==0 )
  5407. {
  5408. value = valExpression.remove( 0,2 );
  5409. d->extra()->validity->m_cond = Conditional::SuperiorEqual;
  5410. }
  5411. else if (valExpression.find( "!=" )==0 )
  5412. {
  5413. //add Differentto attribute
  5414. value = valExpression.remove( 0,2 );
  5415. d->extra()->validity->m_cond = Conditional::DifferentTo;
  5416. }
  5417. else if ( valExpression.find( "<" )==0 )
  5418. {
  5419. value = valExpression.remove( 0,1 );
  5420. d->extra()->validity->m_cond = Conditional::Inferior;
  5421. }
  5422. else if(valExpression.find( ">" )==0 )
  5423. {
  5424. value = valExpression.remove( 0,1 );
  5425. d->extra()->validity->m_cond = Conditional::Superior;
  5426. }
  5427. else if (valExpression.find( "=" )==0 )
  5428. {
  5429. value = valExpression.remove( 0,1 );
  5430. d->extra()->validity->m_cond = Conditional::Equal;
  5431. }
  5432. else
  5433. kdDebug()<<" I don't know how to parse it :"<<valExpression<<endl;
  5434. if ( d->extra()->validity->m_restriction == Restriction::Date )
  5435. {
  5436. d->extra()->validity->dateMin = TQDate::fromString( value );
  5437. }
  5438. else if (d->extra()->validity->m_restriction == Restriction::Date )
  5439. {
  5440. d->extra()->validity->timeMin = TQTime::fromString( value );
  5441. }
  5442. else
  5443. {
  5444. bool ok = false;
  5445. d->extra()->validity->valMin = value.toDouble(&ok);
  5446. if ( !ok )
  5447. {
  5448. d->extra()->validity->valMin = value.toInt(&ok);
  5449. if ( !ok )
  5450. kdDebug()<<" Try to parse this value :"<<value<<endl;
  5451. #if 0
  5452. if ( !ok )
  5453. d->extra()->validity->valMin = value;
  5454. #endif
  5455. }
  5456. }
  5457. }
  5458. bool Cell::load( const TQDomElement & cell, int _xshift, int _yshift,
  5459. Paste::Mode pm, Paste::Operation op, bool paste )
  5460. {
  5461. bool ok;
  5462. //
  5463. // First of all determine in which row and column this
  5464. // cell belongs.
  5465. //
  5466. d->row = cell.attribute( "row" ).toInt( &ok ) + _yshift;
  5467. if ( !ok ) return false;
  5468. d->column = cell.attribute( "column" ).toInt( &ok ) + _xshift;
  5469. if ( !ok ) return false;
  5470. // Validation
  5471. if ( d->row < 1 || d->row > KS_rowMax )
  5472. {
  5473. kdDebug(36001) << "Cell::load: Value out of Range Cell:row=" << d->row << endl;
  5474. return false;
  5475. }
  5476. if ( d->column < 1 || d->column > KS_colMax )
  5477. {
  5478. kdDebug(36001) << "Cell::load: Value out of Range Cell:column=" << d->column << endl;
  5479. return false;
  5480. }
  5481. //
  5482. // Load formatting information.
  5483. //
  5484. TQDomElement f = cell.namedItem( "format" ).toElement();
  5485. if ( !f.isNull()
  5486. && ( (pm == Paste::Normal) || (pm == Paste::Format) || (pm == Paste::NoBorder) ) )
  5487. {
  5488. // send pm parameter. Didn't load Borders if pm==NoBorder
  5489. if ( !format()->load( f, pm, paste ) )
  5490. return false;
  5491. if ( f.hasAttribute( "colspan" ) )
  5492. {
  5493. int i = f.attribute("colspan").toInt( &ok );
  5494. if ( !ok ) return false;
  5495. // Validation
  5496. if ( i < 0 || i > KS_spanMax )
  5497. {
  5498. kdDebug(36001) << "Value out of range Cell::colspan=" << i << endl;
  5499. return false;
  5500. }
  5501. if (i || d->hasExtra())
  5502. d->extra()->extraXCells = i;
  5503. if ( i > 0 )
  5504. {
  5505. setFlag(Flag_Merged);
  5506. }
  5507. }
  5508. if ( f.hasAttribute( "rowspan" ) )
  5509. {
  5510. int i = f.attribute("rowspan").toInt( &ok );
  5511. if ( !ok ) return false;
  5512. // Validation
  5513. if ( i < 0 || i > KS_spanMax )
  5514. {
  5515. kdDebug(36001) << "Value out of range Cell::rowspan=" << i << endl;
  5516. return false;
  5517. }
  5518. if (i || d->hasExtra())
  5519. d->extra()->extraYCells = i;
  5520. if ( i > 0 )
  5521. {
  5522. setFlag(Flag_Merged);
  5523. }
  5524. }
  5525. if ( testFlag( Flag_Merged ) )
  5526. {
  5527. if (d->hasExtra())
  5528. mergeCells( d->column, d->row, d->extra()->extraXCells, d->extra()->extraYCells );
  5529. }
  5530. }
  5531. //
  5532. // Load the condition section of a cell.
  5533. //
  5534. TQDomElement conditionsElement = cell.namedItem( "condition" ).toElement();
  5535. if ( !conditionsElement.isNull())
  5536. {
  5537. if (d->hasExtra())
  5538. delete d->extra()->conditions;
  5539. d->extra()->conditions = new Conditions( this );
  5540. d->extra()->conditions->loadConditions( conditionsElement );
  5541. d->extra()->conditions->checkMatches();
  5542. }
  5543. else if ((pm == Paste::Normal) || (pm == Paste::NoBorder))
  5544. {
  5545. //clear the conditional formatting
  5546. if (d->hasExtra())
  5547. {
  5548. delete d->extra()->conditions;
  5549. d->extra()->conditions = 0;
  5550. }
  5551. }
  5552. TQDomElement validity = cell.namedItem( "validity" ).toElement();
  5553. if ( !validity.isNull())
  5554. {
  5555. TQDomElement param = validity.namedItem( "param" ).toElement();
  5556. if(!param.isNull())
  5557. {
  5558. d->extra()->validity = new Validity;
  5559. if ( param.hasAttribute( "cond" ) )
  5560. {
  5561. d->extra()->validity->m_cond = (Conditional::Type) param.attribute("cond").toInt( &ok );
  5562. if ( !ok )
  5563. return false;
  5564. }
  5565. if ( param.hasAttribute( "action" ) )
  5566. {
  5567. d->extra()->validity->m_action = (Action::Type) param.attribute("action").toInt( &ok );
  5568. if ( !ok )
  5569. return false;
  5570. }
  5571. if ( param.hasAttribute( "allow" ) )
  5572. {
  5573. d->extra()->validity->m_restriction = (Restriction::Type) param.attribute("allow").toInt( &ok );
  5574. if ( !ok )
  5575. return false;
  5576. }
  5577. if ( param.hasAttribute( "valmin" ) )
  5578. {
  5579. d->extra()->validity->valMin = param.attribute("valmin").toDouble( &ok );
  5580. if ( !ok )
  5581. return false;
  5582. }
  5583. if ( param.hasAttribute( "valmax" ) )
  5584. {
  5585. d->extra()->validity->valMax = param.attribute("valmax").toDouble( &ok );
  5586. if ( !ok )
  5587. return false;
  5588. }
  5589. if ( param.hasAttribute( "displaymessage" ) )
  5590. {
  5591. d->extra()->validity->displayMessage = ( bool )param.attribute("displaymessage").toInt();
  5592. }
  5593. if ( param.hasAttribute( "displayvalidationinformation" ) )
  5594. {
  5595. d->extra()->validity->displayValidationInformation = ( bool )param.attribute("displayvalidationinformation").toInt();
  5596. }
  5597. if ( param.hasAttribute( "allowemptycell" ) )
  5598. {
  5599. d->extra()->validity->allowEmptyCell = ( bool )param.attribute("allowemptycell").toInt();
  5600. }
  5601. if ( param.hasAttribute("listvalidity") )
  5602. {
  5603. d->extra()->validity->listValidity=TQStringList::split(";", param.attribute("listvalidity") );
  5604. }
  5605. }
  5606. TQDomElement inputTitle = validity.namedItem( "inputtitle" ).toElement();
  5607. if (!inputTitle.isNull())
  5608. {
  5609. d->extra()->validity->titleInfo = inputTitle.text();
  5610. }
  5611. TQDomElement inputMessage = validity.namedItem( "inputmessage" ).toElement();
  5612. if (!inputMessage.isNull())
  5613. {
  5614. d->extra()->validity->messageInfo = inputMessage.text();
  5615. }
  5616. TQDomElement title = validity.namedItem( "title" ).toElement();
  5617. if (!title.isNull())
  5618. {
  5619. d->extra()->validity->title = title.text();
  5620. }
  5621. TQDomElement message = validity.namedItem( "message" ).toElement();
  5622. if (!message.isNull())
  5623. {
  5624. d->extra()->validity->message = message.text();
  5625. }
  5626. TQDomElement timeMin = validity.namedItem( "timemin" ).toElement();
  5627. if ( !timeMin.isNull() )
  5628. {
  5629. d->extra()->validity->timeMin = toTime(timeMin);
  5630. }
  5631. TQDomElement timeMax = validity.namedItem( "timemax" ).toElement();
  5632. if ( !timeMax.isNull() )
  5633. {
  5634. d->extra()->validity->timeMax = toTime(timeMax);
  5635. }
  5636. TQDomElement dateMin = validity.namedItem( "datemin" ).toElement();
  5637. if ( !dateMin.isNull() )
  5638. {
  5639. d->extra()->validity->dateMin = toDate(dateMin);
  5640. }
  5641. TQDomElement dateMax = validity.namedItem( "datemax" ).toElement();
  5642. if ( !dateMax.isNull() )
  5643. {
  5644. d->extra()->validity->dateMax = toDate(dateMax);
  5645. }
  5646. }
  5647. else if ((pm == Paste::Normal) || (pm == Paste::NoBorder))
  5648. {
  5649. // clear the validity
  5650. removeValidity();
  5651. }
  5652. //
  5653. // Load the comment
  5654. //
  5655. TQDomElement comment = cell.namedItem( "comment" ).toElement();
  5656. if ( !comment.isNull() && ( pm == Paste::Normal || pm == Paste::Comment || pm == Paste::NoBorder ))
  5657. {
  5658. TQString t = comment.text();
  5659. //t = t.stripWhiteSpace();
  5660. format()->setComment( t );
  5661. }
  5662. //
  5663. // The real content of the cell is loaded here. It is stored in
  5664. // the "text" tag, which contains either a text or a CDATA section.
  5665. //
  5666. // TODO: make this suck less. We set data twice, in loadCellData, and
  5667. // also here. Not good.
  5668. TQDomElement text = cell.namedItem( "text" ).toElement();
  5669. if ( !text.isNull() &&
  5670. ( pm == Paste::Normal || pm == Paste::Text || pm == Paste::NoBorder || pm == Paste::Result ) )
  5671. {
  5672. /* older versions mistakenly put the datatype attribute on the cell
  5673. instead of the text. Just move it over in case we're parsing
  5674. an old document */
  5675. if ( cell.hasAttribute( "dataType" ) ) // new docs
  5676. text.setAttribute( "dataType", cell.attribute( "dataType" ) );
  5677. TQDomElement result = cell.namedItem( "result" ).toElement();
  5678. TQString txt = text.text();
  5679. if ((pm == Paste::Result) && (txt[0] == '='))
  5680. // paste text of the element, if we want to paste result
  5681. // and the source cell contains a formula
  5682. // note that we mustn't use setCellValue after this, or else we lose
  5683. // all the formulas ...
  5684. d->strText = result.text();
  5685. else
  5686. //otherwise copy everything
  5687. loadCellData(text, op);
  5688. if ( !result.isNull() )
  5689. {
  5690. TQString dataType;
  5691. TQString t = result.text();
  5692. if ( result.hasAttribute( "dataType" ) )
  5693. dataType = result.attribute( "dataType" );
  5694. if ( result.hasAttribute( "outStr" ) )
  5695. {
  5696. d->strOutText = result.attribute( "outStr" );
  5697. if ( !d->strOutText.isEmpty() )
  5698. clearFlag( Flag_TextFormatDirty );
  5699. }
  5700. bool clear = true;
  5701. // boolean ?
  5702. if( dataType == "Bool" )
  5703. {
  5704. if ( t == "false" )
  5705. setValue( false );
  5706. else if ( t == "true" )
  5707. setValue( true );
  5708. else
  5709. clear = false;
  5710. }
  5711. else if( dataType == "Num" )
  5712. {
  5713. bool ok = false;
  5714. double dd = t.toDouble( &ok );
  5715. if ( ok )
  5716. setValue ( dd );
  5717. else
  5718. clear = false;
  5719. }
  5720. else if( dataType == "Date" )
  5721. {
  5722. bool ok = false;
  5723. double dd = t.toDouble( &ok );
  5724. if ( ok )
  5725. setValue ( dd );
  5726. else
  5727. {
  5728. int pos = t.find( '/' );
  5729. int year = t.mid( 0, pos ).toInt();
  5730. int pos1 = t.find( '/', pos + 1 );
  5731. int month = t.mid( pos + 1, ( ( pos1 - 1 ) - pos ) ).toInt();
  5732. int day = t.right( t.length() - pos1 - 1 ).toInt();
  5733. TQDate date( year, month, day );
  5734. if ( date.isValid() )
  5735. setValue( date );
  5736. else
  5737. clear = false;
  5738. }
  5739. }
  5740. else if( dataType == "Time" )
  5741. {
  5742. bool ok = false;
  5743. double dd = t.toDouble( &ok );
  5744. if ( ok )
  5745. setCellValue( dd );
  5746. else
  5747. {
  5748. int hours = -1;
  5749. int minutes = -1;
  5750. int second = -1;
  5751. int pos, pos1;
  5752. pos = t.find( ':' );
  5753. hours = t.mid( 0, pos ).toInt();
  5754. pos1 = t.find( ':', pos + 1 );
  5755. minutes = t.mid( pos + 1, ( ( pos1 - 1 ) - pos ) ).toInt();
  5756. second = t.right( t.length() - pos1 - 1 ).toInt();
  5757. TQTime time( hours, minutes, second );
  5758. if ( time.isValid() )
  5759. setValue( time );
  5760. else
  5761. clear = false;
  5762. }
  5763. }
  5764. else
  5765. {
  5766. setValue( t );
  5767. }
  5768. // if ( clear )
  5769. // clearFlag( Flag_CalcDirty );
  5770. }
  5771. }
  5772. return true;
  5773. }
  5774. bool Cell::loadCellData(const TQDomElement & text, Paste::Operation op )
  5775. {
  5776. //TODO: use converter()->asString() to generate strText
  5777. TQString t = text.text();
  5778. t = t.stripWhiteSpace();
  5779. setFlag(Flag_LayoutDirty);
  5780. setFlag(Flag_TextFormatDirty);
  5781. // A formula like =A1+A2 ?
  5782. if( t[0] == '=' )
  5783. {
  5784. t = decodeFormula( t, d->column, d->row );
  5785. setCellText (pasteOperation( t, d->strText, op ));
  5786. setFlag(Flag_CalcDirty);
  5787. clearAllErrors();
  5788. if ( !makeFormula() )
  5789. kdError(36001) << "ERROR: Syntax ERROR" << endl;
  5790. }
  5791. // rich text ?
  5792. else if (t[0] == '!' )
  5793. {
  5794. // KSpread pre 1.4 stores hyperlink as rich text (first char is '!')
  5795. // extract the link and the correspoding text
  5796. // This is a rather dirty hack, but enough for KSpread generated XML
  5797. bool inside_tag = false;
  5798. TQString qml_text;
  5799. TQString tag;
  5800. TQString qml_link;
  5801. for( unsigned i = 1; i < t.length(); i++ )
  5802. {
  5803. TQChar ch = t[i];
  5804. if( ch == '<' )
  5805. {
  5806. if( !inside_tag )
  5807. {
  5808. inside_tag = true;
  5809. tag = TQString();
  5810. }
  5811. }
  5812. else if( ch == '>' )
  5813. {
  5814. if( inside_tag )
  5815. {
  5816. inside_tag = false;
  5817. if( tag.startsWith( "a href=\"", true ) )
  5818. if( tag.endsWith( "\"" ) )
  5819. qml_link = tag.mid( 8, tag.length()-9 );
  5820. tag = TQString();
  5821. }
  5822. }
  5823. else
  5824. {
  5825. if( !inside_tag )
  5826. qml_text += ch;
  5827. else
  5828. tag += ch;
  5829. }
  5830. }
  5831. if( !qml_link.isEmpty() )
  5832. d->extra()->link = qml_link;
  5833. d->strText = qml_text;
  5834. setValue( d->strText );
  5835. }
  5836. else
  5837. {
  5838. bool newStyleLoading = true;
  5839. TQString dataType;
  5840. if ( text.hasAttribute( "dataType" ) ) // new docs
  5841. {
  5842. dataType = text.attribute( "dataType" );
  5843. }
  5844. else // old docs: do the ugly solution of calling checkTextInput to parse the text
  5845. {
  5846. // ...except for date/time
  5847. if (isDate() && ( t.contains('/') == 2 ))
  5848. dataType = "Date";
  5849. else if (isTime() && ( t.contains(':') == 2 ) )
  5850. dataType = "Time";
  5851. else
  5852. {
  5853. d->strText = pasteOperation( t, d->strText, op );
  5854. checkTextInput();
  5855. //kdDebug(36001) << "Cell::load called checkTextInput, got dataType=" << dataType << " t=" << t << endl;
  5856. newStyleLoading = false;
  5857. }
  5858. }
  5859. if ( newStyleLoading )
  5860. {
  5861. d->value = Value::empty();
  5862. clearAllErrors();
  5863. // boolean ?
  5864. if( dataType == "Bool" )
  5865. {
  5866. bool val = (t.lower() == "true");
  5867. setCellValue (val);
  5868. }
  5869. // number ?
  5870. else if( dataType == "Num" )
  5871. {
  5872. bool ok = false;
  5873. if (t.contains('.'))
  5874. setValue ( Value( t.toDouble(&ok) ) ); // We save in non-localized format
  5875. else
  5876. setValue ( Value( t.toLong(&ok) ) );
  5877. if ( !ok )
  5878. {
  5879. kdWarning(36001) << "Couldn't parse '" << t << "' as number." << endl;
  5880. }
  5881. /* We will need to localize the text version of the number */
  5882. TDELocale* locale = format()->sheet()->doc()->locale();
  5883. /* TDELocale::formatNumber requires the precision we want to return.
  5884. */
  5885. int precision = t.length() - t.find('.') - 1;
  5886. if ( formatType() == Percentage_format )
  5887. {
  5888. if (value().isInteger())
  5889. t = locale->formatNumber( value().asInteger() * 100 );
  5890. else
  5891. t = locale->formatNumber( value().asFloat() * 100.0, precision );
  5892. d->strText = pasteOperation( t, d->strText, op );
  5893. d->strText += '%';
  5894. }
  5895. else
  5896. {
  5897. if (value().isInteger())
  5898. t = locale->formatLong(value().asInteger());
  5899. else
  5900. t = locale->formatNumber(value().asFloat(), precision);
  5901. d->strText = pasteOperation( t, d->strText, op );
  5902. }
  5903. }
  5904. // date ?
  5905. else if( dataType == "Date" )
  5906. {
  5907. int pos = t.find('/');
  5908. int year = t.mid(0,pos).toInt();
  5909. int pos1 = t.find('/',pos+1);
  5910. int month = t.mid(pos+1,((pos1-1)-pos)).toInt();
  5911. int day = t.right(t.length()-pos1-1).toInt();
  5912. setValue( TQDate(year,month,day) );
  5913. if ( value().asDate().isValid() ) // Should always be the case for new docs
  5914. d->strText = locale()->formatDate( value().asDate(), true );
  5915. else // This happens with old docs, when format is set wrongly to date
  5916. {
  5917. d->strText = pasteOperation( t, d->strText, op );
  5918. checkTextInput();
  5919. }
  5920. }
  5921. // time ?
  5922. else if( dataType == "Time" )
  5923. {
  5924. int hours = -1;
  5925. int minutes = -1;
  5926. int second = -1;
  5927. int pos, pos1;
  5928. pos = t.find(':');
  5929. hours = t.mid(0,pos).toInt();
  5930. pos1 = t.find(':',pos+1);
  5931. minutes = t.mid(pos+1,((pos1-1)-pos)).toInt();
  5932. second = t.right(t.length()-pos1-1).toInt();
  5933. setValue( TQTime(hours,minutes,second) );
  5934. if ( value().asTime().isValid() ) // Should always be the case for new docs
  5935. d->strText = locale()->formatTime( value().asTime(), true );
  5936. else // This happens with old docs, when format is set wrongly to time
  5937. {
  5938. d->strText = pasteOperation( t, d->strText, op );
  5939. checkTextInput();
  5940. }
  5941. }
  5942. else
  5943. {
  5944. // Set the cell's text
  5945. d->strText = pasteOperation( t, d->strText, op );
  5946. setValue( d->strText );
  5947. }
  5948. }
  5949. }
  5950. if ( text.hasAttribute( "outStr" ) ) // very new docs
  5951. {
  5952. d->strOutText = text.attribute( "outStr" );
  5953. if ( !d->strOutText.isEmpty() )
  5954. clearFlag( Flag_TextFormatDirty );
  5955. }
  5956. if ( !format()->sheet()->isLoading() )
  5957. setCellText( d->strText );
  5958. if ( d->hasExtra() && d->extra()->conditions )
  5959. d->extra()->conditions->checkMatches();
  5960. return true;
  5961. }
  5962. TQTime Cell::toTime(const TQDomElement &element)
  5963. {
  5964. //TODO: can't we use tryParseTime (after modification) instead?
  5965. TQString t = element.text();
  5966. t = t.stripWhiteSpace();
  5967. int hours = -1;
  5968. int minutes = -1;
  5969. int second = -1;
  5970. int pos, pos1;
  5971. pos = t.find(':');
  5972. hours = t.mid(0,pos).toInt();
  5973. pos1 = t.find(':',pos+1);
  5974. minutes = t.mid(pos+1,((pos1-1)-pos)).toInt();
  5975. second = t.right(t.length()-pos1-1).toInt();
  5976. setValue( Value( TQTime(hours,minutes,second)) );
  5977. return value().asTime();
  5978. }
  5979. TQDate Cell::toDate(const TQDomElement &element)
  5980. {
  5981. TQString t = element.text();
  5982. int pos;
  5983. int pos1;
  5984. int year = -1;
  5985. int month = -1;
  5986. int day = -1;
  5987. pos = t.find('/');
  5988. year = t.mid(0,pos).toInt();
  5989. pos1 = t.find('/',pos+1);
  5990. month = t.mid(pos+1,((pos1-1)-pos)).toInt();
  5991. day = t.right(t.length()-pos1-1).toInt();
  5992. setValue( Value( TQDate(year,month,day) ) );
  5993. return value().asDate();
  5994. }
  5995. TQString Cell::pasteOperation( const TQString &new_text, const TQString &old_text, Paste::Operation op )
  5996. {
  5997. if ( op == Paste::OverWrite )
  5998. return new_text;
  5999. TQString tmp_op;
  6000. TQString tmp;
  6001. TQString old;
  6002. if( !new_text.isEmpty() && new_text[0] == '=' )
  6003. {
  6004. tmp = new_text.right( new_text.length() - 1 );
  6005. }
  6006. else
  6007. {
  6008. tmp = new_text;
  6009. }
  6010. if ( old_text.isEmpty() &&
  6011. ( op == Paste::Add || op == Paste::Mul || op == Paste::Sub || op == Paste::Div ) )
  6012. {
  6013. old = "=0";
  6014. }
  6015. if( !old_text.isEmpty() && old_text[0] == '=' )
  6016. {
  6017. old = old_text.right( old_text.length() - 1 );
  6018. }
  6019. else
  6020. {
  6021. old = old_text;
  6022. }
  6023. bool b1, b2;
  6024. tmp.toDouble( &b1 );
  6025. old.toDouble( &b2 );
  6026. if (b1 && !b2 && old.length() == 0)
  6027. {
  6028. old = "0";
  6029. b2 = true;
  6030. }
  6031. if( b1 && b2 )
  6032. {
  6033. switch( op )
  6034. {
  6035. case Paste::Add:
  6036. tmp_op = TQString::number(old.toDouble()+tmp.toDouble());
  6037. break;
  6038. case Paste::Mul :
  6039. tmp_op = TQString::number(old.toDouble()*tmp.toDouble());
  6040. break;
  6041. case Paste::Sub:
  6042. tmp_op = TQString::number(old.toDouble()-tmp.toDouble());
  6043. break;
  6044. case Paste::Div:
  6045. tmp_op = TQString::number(old.toDouble()/tmp.toDouble());
  6046. break;
  6047. default:
  6048. Q_ASSERT( 0 );
  6049. }
  6050. setFlag(Flag_LayoutDirty);
  6051. clearAllErrors();
  6052. return tmp_op;
  6053. }
  6054. else if ( ( new_text[0] == '=' && old_text[0] == '=' ) ||
  6055. ( b1 && old_text[0] == '=' ) || ( new_text[0] == '=' && b2 ) )
  6056. {
  6057. switch( op )
  6058. {
  6059. case Paste::Add :
  6060. tmp_op="=("+old+")+"+"("+tmp+")";
  6061. break;
  6062. case Paste::Mul :
  6063. tmp_op="=("+old+")*"+"("+tmp+")";
  6064. break;
  6065. case Paste::Sub:
  6066. tmp_op="=("+old+")-"+"("+tmp+")";
  6067. break;
  6068. case Paste::Div:
  6069. tmp_op="=("+old+")/"+"("+tmp+")";
  6070. break;
  6071. default :
  6072. Q_ASSERT( 0 );
  6073. }
  6074. tmp_op = decodeFormula( tmp_op, d->column, d->row );
  6075. setFlag(Flag_LayoutDirty);
  6076. clearAllErrors();
  6077. return tmp_op;
  6078. }
  6079. tmp = decodeFormula( new_text, d->column, d->row );
  6080. setFlag(Flag_LayoutDirty);
  6081. clearAllErrors();
  6082. return tmp;
  6083. }
  6084. TQString Cell::testAnchor( int x, int y ) const
  6085. {
  6086. if( link().isEmpty() )
  6087. return TQString();
  6088. const Doc* doc = format()->sheet()->doc();
  6089. int x1 = doc->zoomItX( d->textX );
  6090. int y1 = doc->zoomItX( d->textY - d->textHeight );
  6091. int x2 = doc->zoomItX( d->textX + d->textWidth );
  6092. int y2 = doc->zoomItX( d->textY );
  6093. if( x > x1 ) if( x < x2 )
  6094. if( y > y1 ) if( y < y2 )
  6095. return link();
  6096. return TQString();
  6097. }
  6098. void Cell::sheetDies()
  6099. {
  6100. // Avoid unobscuring the cells in the destructor.
  6101. if (d->hasExtra())
  6102. {
  6103. d->extra()->extraXCells = 0;
  6104. d->extra()->extraYCells = 0;
  6105. d->extra()->mergedXCells = 0;
  6106. d->extra()->mergedYCells = 0;
  6107. }
  6108. //d->nextCell = 0;
  6109. //d->previousCell = 0;
  6110. }
  6111. Cell::~Cell()
  6112. {
  6113. if ( d->nextCell )
  6114. d->nextCell->setPreviousCell( d->previousCell );
  6115. if ( d->previousCell )
  6116. d->previousCell->setNextCell( d->nextCell );
  6117. if (d->hasExtra())
  6118. {
  6119. delete d->extra()->validity;
  6120. }
  6121. // Unobscure cells.
  6122. int extraXCells = d->hasExtra() ? d->extra()->extraXCells : 0;
  6123. int extraYCells = d->hasExtra() ? d->extra()->extraYCells : 0;
  6124. for( int x = 0; x <= extraXCells; ++x )
  6125. for( int y = (x == 0) ? 1 : 0; // avoid looking at (+0,+0)
  6126. y <= extraYCells; ++y )
  6127. {
  6128. Cell* cell = format()->sheet()->cellAt( d->column + x, d->row + y );
  6129. if ( cell )
  6130. cell->unobscure(this);
  6131. }
  6132. d->value = Value::empty();
  6133. if (!isDefault())
  6134. valueChanged (); //our value has been changed (is now null), but only if we aren't default
  6135. delete d->format;
  6136. delete d;
  6137. }
  6138. bool Cell::operator > ( const Cell & cell ) const
  6139. {
  6140. if ( value().isNumber() ) // ### what about bools ?
  6141. {
  6142. if ( cell.value().isNumber() )
  6143. return value().asFloat() > cell.value().asFloat();
  6144. else
  6145. return false; // numbers are always < than texts
  6146. }
  6147. else if(isDate())
  6148. {
  6149. if( cell.isDate() )
  6150. return value().asDate() > cell.value().asDate();
  6151. else if (cell.value().isNumber())
  6152. return true;
  6153. else
  6154. return false; //date are always < than texts and time
  6155. }
  6156. else if(isTime())
  6157. {
  6158. if( cell.isTime() )
  6159. return value().asTime() > cell.value().asTime();
  6160. else if( cell.isDate())
  6161. return true; //time are always > than date
  6162. else if( cell.value().isNumber())
  6163. return true;
  6164. else
  6165. return false; //time are always < than texts
  6166. }
  6167. else
  6168. {
  6169. if ( Map::respectCase )
  6170. return value().asString().compare(cell.value().asString()) > 0;
  6171. else
  6172. return ( value().asString() ).lower().compare(cell.value().asString().lower()) > 0;
  6173. }
  6174. }
  6175. bool Cell::operator < ( const Cell & cell ) const
  6176. {
  6177. if ( value().isNumber() )
  6178. {
  6179. if ( cell.value().isNumber() )
  6180. return value().asFloat() < cell.value().asFloat();
  6181. else
  6182. return true; // numbers are always < than texts
  6183. }
  6184. else if(isDate())
  6185. {
  6186. if( cell.isDate() )
  6187. return value().asDateTime().date() < cell.value().asDateTime().date();
  6188. else if( cell.value().isNumber())
  6189. return false;
  6190. else
  6191. return true; //date are always < than texts and time
  6192. }
  6193. else if(isTime())
  6194. {
  6195. if( cell.isTime() )
  6196. return value().asDateTime().time() < cell.value().asDateTime().time();
  6197. else if(cell.isDate())
  6198. return false; //time are always > than date
  6199. else if( cell.value().isNumber())
  6200. return false;
  6201. else
  6202. return true; //time are always < than texts
  6203. }
  6204. else
  6205. {
  6206. if ( Map::respectCase )
  6207. return value().asString().compare(cell.value().asString()) < 0;
  6208. else
  6209. return ( value().asString() ).lower().compare(cell.value().asString().lower()) < 0;
  6210. }
  6211. }
  6212. bool Cell::operator==( const Cell& other ) const
  6213. {
  6214. if ( d->strText != other.d->strText )
  6215. return false;
  6216. if ( d->value != other.d->value )
  6217. return false;
  6218. if ( *d->format != *other.d->format )
  6219. return false;
  6220. if ( d->hasExtra() )
  6221. {
  6222. if ( !other.d->hasExtra() )
  6223. return false;
  6224. if ( d->extra()->link != other.d->extra()->link )
  6225. return false;
  6226. if ( d->extra()->mergedXCells != other.d->extra()->mergedXCells )
  6227. return false;
  6228. if ( d->extra()->mergedYCells != other.d->extra()->mergedYCells )
  6229. return false;
  6230. if ( d->extra()->conditions )
  6231. {
  6232. if ( !other.d->extra()->conditions )
  6233. return false;
  6234. if ( *d->extra()->conditions != *other.d->extra()->conditions )
  6235. return false;
  6236. }
  6237. if ( d->extra()->validity )
  6238. {
  6239. if ( !other.d->extra()->validity )
  6240. return false;
  6241. if ( *d->extra()->validity != *other.d->extra()->validity )
  6242. return false;
  6243. }
  6244. }
  6245. return true;
  6246. }
  6247. TQRect Cell::cellRect()
  6248. {
  6249. Q_ASSERT(!isDefault());
  6250. return TQRect(TQPoint(d->column, d->row), TQPoint(d->column, d->row));
  6251. }
  6252. TQValueList<Conditional> Cell::conditionList() const
  6253. {
  6254. if ( !d->hasExtra() || !d->extra()->conditions )
  6255. {
  6256. TQValueList<Conditional> emptyList;
  6257. return emptyList;
  6258. }
  6259. return d->extra()->conditions->conditionList();
  6260. }
  6261. void Cell::setConditionList( const TQValueList<Conditional> & newList )
  6262. {
  6263. if (d->hasExtra())
  6264. delete d->extra()->conditions;
  6265. d->extra()->conditions = new Conditions( this );
  6266. d->extra()->conditions->setConditionList( newList );
  6267. d->extra()->conditions->checkMatches();
  6268. }
  6269. bool Cell::hasError() const
  6270. {
  6271. return ( testFlag(Flag_ParseError) ||
  6272. testFlag(Flag_CircularCalculation) ||
  6273. testFlag(Flag_DependancyError));
  6274. }
  6275. void Cell::clearAllErrors()
  6276. {
  6277. clearFlag( Flag_ParseError );
  6278. clearFlag( Flag_CircularCalculation );
  6279. clearFlag( Flag_DependancyError );
  6280. }
  6281. bool Cell::calcDirtyFlag()
  6282. {
  6283. return isFormula() ? testFlag( Flag_CalcDirty ) : false;
  6284. }
  6285. bool Cell::layoutDirtyFlag() const
  6286. {
  6287. return testFlag( Flag_LayoutDirty );
  6288. }
  6289. void Cell::clearDisplayDirtyFlag()
  6290. {
  6291. clearFlag( Flag_DisplayDirty );
  6292. }
  6293. void Cell::setDisplayDirtyFlag()
  6294. {
  6295. setFlag( Flag_DisplayDirty );
  6296. }
  6297. bool Cell::doesMergeCells() const
  6298. {
  6299. return testFlag( Flag_Merged );
  6300. }
  6301. void Cell::clearFlag( CellFlags flag )
  6302. {
  6303. d->flags &= ~(TQ_UINT32)flag;
  6304. }
  6305. void Cell::setFlag( CellFlags flag )
  6306. {
  6307. d->flags |= (TQ_UINT32)flag;
  6308. }
  6309. bool Cell::testFlag( CellFlags flag ) const
  6310. {
  6311. return ( d->flags & (TQ_UINT32)flag );
  6312. }
  6313. void Cell::checkForNamedAreas( TQString & formula ) const
  6314. {
  6315. KSPLoadingInfo* loadinginfo = sheet()->doc()->loadingInfo();
  6316. if(! loadinginfo) {
  6317. kdDebug() << "Cell::checkForNamedAreas loadinginfo is NULL" << endl;
  6318. return;
  6319. }
  6320. int l = formula.length();
  6321. int i = 0;
  6322. TQString word;
  6323. int start = 0;
  6324. while ( i < l )
  6325. {
  6326. if ( formula[i].isLetterOrNumber() )
  6327. {
  6328. word += formula[i];
  6329. ++i;
  6330. continue;
  6331. }
  6332. if ( !word.isEmpty() )
  6333. {
  6334. if ( loadinginfo->findWordInAreaList(word) )
  6335. {
  6336. formula = formula.replace( start, word.length(), "'" + word + "'" );
  6337. l = formula.length();
  6338. ++i;
  6339. kdDebug() << "Formula: " << formula << ", L: " << l << ", i: " << i + 1 <<endl;
  6340. }
  6341. }
  6342. ++i;
  6343. word = "";
  6344. start = i;
  6345. }
  6346. if ( !word.isEmpty() )
  6347. {
  6348. if ( loadinginfo->findWordInAreaList(word) )
  6349. {
  6350. formula = formula.replace( start, word.length(), "'" + word + "'" );
  6351. l = formula.length();
  6352. ++i;
  6353. kdDebug() << "Formula: " << formula << ", L: " << l << ", i: " << i + 1 <<endl;
  6354. }
  6355. }
  6356. }