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.

8578 lines
250KB

  1. /* This file is part of the KDE project
  2. Copyright 1998, 1999 Torben Weis <weis@kde.org>
  3. Copyright 1999- 2006 The KSpread Team
  4. www.koffice.org/kspread
  5. This library is free software; you can redistribute it and/or
  6. modify it under the terms of the GNU Library General Public
  7. License as published by the Free Software Foundation; either
  8. version 2 of the License, or (at your option) any later version.
  9. This library is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  12. Library General Public License for more details.
  13. You should have received a copy of the GNU Library General Public License
  14. along with this library; see the file COPYING.LIB. If not, write to
  15. the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
  16. * Boston, MA 02110-1301, USA.
  17. */
  18. #include <assert.h>
  19. #include <ctype.h>
  20. #include <float.h>
  21. #include <math.h>
  22. #include <pwd.h>
  23. #include <stdlib.h>
  24. #include <unistd.h>
  25. #include <tqapplication.h>
  26. #include <tqcheckbox.h>
  27. #include <tqclipboard.h>
  28. #include <tqlabel.h>
  29. #include <tqlayout.h>
  30. #include <tqlineedit.h>
  31. #include <tqpicture.h>
  32. #include <tqregexp.h>
  33. #include <tqvbox.h>
  34. #include <tqmap.h>
  35. #include <kdebug.h>
  36. #include <kmdcodec.h>
  37. #include <kfind.h>
  38. #include <kfinddialog.h>
  39. #include <tdemessagebox.h>
  40. #include <kreplace.h>
  41. #include <kreplacedialog.h>
  42. #include <kprinter.h>
  43. #include <kurl.h>
  44. #include <koChart.h>
  45. #include <KoDom.h>
  46. #include <KoDocumentInfo.h>
  47. #include <KoOasisLoadingContext.h>
  48. #include <KoOasisSettings.h>
  49. #include <KoOasisStyles.h>
  50. #include <KoQueryTrader.h>
  51. #include <KoStyleStack.h>
  52. #include <KoUnit.h>
  53. #include <KoXmlNS.h>
  54. #include <KoXmlWriter.h>
  55. #include "commands.h"
  56. #include "dependencies.h"
  57. #include "selection.h"
  58. #include "ksploadinginfo.h"
  59. #include "ksprsavinginfo.h"
  60. #include "kspread_canvas.h"
  61. #include "kspread_cluster.h"
  62. #include "kspread_condition.h"
  63. #include "kspread_doc.h"
  64. #include "kspread_global.h"
  65. #include "kspread_locale.h"
  66. #include "kspread_map.h"
  67. #include "kspread_object.h"
  68. #include "kspread_sheetprint.h"
  69. #include "kspread_style.h"
  70. #include "kspread_style_manager.h"
  71. #include "kspread_undo.h"
  72. #include "kspread_util.h"
  73. #include "kspread_view.h"
  74. #include "manipulator.h"
  75. #include "manipulator_data.h"
  76. #include "KSpreadTableIface.h"
  77. #include "kspread_sheet.h"
  78. #include "kspread_sheet.moc"
  79. #define NO_MODIFICATION_POSSIBLE \
  80. do { \
  81. KMessageBox::error( 0, i18n ( "You cannot change a protected sheet" ) ); return; \
  82. } while(0)
  83. namespace KSpread {
  84. /*****************************************************************************
  85. *
  86. * CellBinding
  87. *
  88. *****************************************************************************/
  89. CellBinding::CellBinding( Sheet *_sheet, const TQRect& _area )
  90. {
  91. m_rctDataArea = _area;
  92. m_pSheet = _sheet;
  93. m_pSheet->addCellBinding( this );
  94. m_bIgnoreChanges = false;
  95. }
  96. CellBinding::~CellBinding()
  97. {
  98. m_pSheet->removeCellBinding( this );
  99. }
  100. void CellBinding::cellChanged( Cell *_cell )
  101. {
  102. if ( m_bIgnoreChanges )
  103. return;
  104. emit changed( _cell );
  105. }
  106. bool CellBinding::contains( int _x, int _y )
  107. {
  108. return m_rctDataArea.contains( TQPoint( _x, _y ) );
  109. }
  110. /*****************************************************************************
  111. *
  112. * ChartBinding
  113. *
  114. *****************************************************************************/
  115. ChartBinding::ChartBinding( Sheet *_sheet, const TQRect& _area, EmbeddedChart *_child )
  116. : CellBinding( _sheet, _area )
  117. {
  118. m_child = _child;
  119. }
  120. ChartBinding::~ChartBinding()
  121. {
  122. }
  123. void ChartBinding::cellChanged( Cell* /*changedCell*/ )
  124. {
  125. if ( m_bIgnoreChanges )
  126. return;
  127. //Ensure display gets updated by marking all cells underneath the chart as
  128. //dirty
  129. const TQRect chartGeometry = m_child->geometry().toTQRect();
  130. double tmp;
  131. int left = sheet()->leftColumn( chartGeometry.left() , tmp );
  132. int top = sheet()->topRow( chartGeometry.top() , tmp );
  133. int right = sheet()->rightColumn( chartGeometry.right() );
  134. int bottom = sheet()->bottomRow( chartGeometry.bottom() );
  135. sheet()->setRegionPaintDirty( TQRect(left,top,right-left,bottom-top) );
  136. //kdDebug(36001) << m_rctDataArea << endl;
  137. // Get the chart and resize its data if necessary.
  138. //
  139. // FIXME: Only do this if he data actually changed size.
  140. KoChart::Part *chart = m_child->chart();
  141. chart->resizeData( m_rctDataArea.height(), m_rctDataArea.width() );
  142. // Reset all the data, i.e. retransfer them to the chart.
  143. // This is definitely not the most efficient way to do this.
  144. //
  145. // FIXME: Find a way to do it with just the data that changed.
  146. Cell* cell;
  147. for ( int row = 0; row < m_rctDataArea.height(); row++ ) {
  148. for ( int col = 0; col < m_rctDataArea.width(); col++ ) {
  149. cell = m_pSheet->cellAt( m_rctDataArea.left() + col,
  150. m_rctDataArea.top() + row );
  151. if ( cell && cell->value().isNumber() )
  152. chart->setCellData( row, col, cell->value().asFloat() );
  153. else if ( cell )
  154. chart->setCellData( row, col, cell->value().asString() );
  155. else
  156. chart->setCellData( row, col, KoChart::Value() );
  157. }
  158. }
  159. chart->analyzeHeaders( );
  160. // ######### Kalle may be interested in that, too
  161. #if 0
  162. Chart::Range range;
  163. range.top = m_rctDataArea.top();
  164. range.left = m_rctDataArea.left();
  165. range.right = m_rctDataArea.right();
  166. range.bottom = m_rctDataArea.bottom();
  167. range.sheet = m_pSheet->name(); */
  168. //m_child->chart()->setData( matrix );
  169. // Force a redraw of the chart on all views
  170. /** TODO - replace the call below with something that will repaint this chart */
  171. #endif
  172. // sheet()->emit_polygonInvalidated( m_child->framePointArray() );
  173. }
  174. /******************************************************************/
  175. /* Class: TextDrag */
  176. /******************************************************************/
  177. TextDrag::TextDrag( TQWidget * dragSource, const char * name )
  178. : TQTextDrag( dragSource, name )
  179. {
  180. }
  181. TextDrag::~TextDrag()
  182. {
  183. }
  184. TQByteArray TextDrag::encodedData( const char * mime ) const
  185. {
  186. if ( strcmp( selectionMimeType(), mime ) == 0)
  187. return m_kspread;
  188. else
  189. return TQTextDrag::encodedData( mime );
  190. }
  191. bool TextDrag::canDecode( TQMimeSource* e )
  192. {
  193. if ( e->provides( selectionMimeType() ) )
  194. return true;
  195. return TQTextDrag::canDecode(e);
  196. }
  197. const char * TextDrag::format( int i ) const
  198. {
  199. if ( i < 4 ) // HACK, but how to do otherwise ??
  200. return TQTextDrag::format(i);
  201. else if ( i == 4 )
  202. return selectionMimeType();
  203. else return 0;
  204. }
  205. const char * TextDrag::selectionMimeType()
  206. {
  207. return "application/x-kspread-snippet";
  208. }
  209. /*****************************************************************************
  210. *
  211. * Sheet
  212. *
  213. *****************************************************************************/
  214. class Sheet::Private
  215. {
  216. public:
  217. Map* workbook;
  218. DCOPObject* dcop;
  219. TQString name;
  220. int id;
  221. Sheet::LayoutDirection layoutDirection;
  222. // true if sheet is hidden
  223. bool hide;
  224. // password of protected sheet
  225. TQCString password;
  226. bool showGrid;
  227. bool showFormula;
  228. bool showFormulaIndicator;
  229. bool showCommentIndicator;
  230. bool autoCalc;
  231. bool lcMode;
  232. bool showColumnNumber;
  233. bool hideZero;
  234. bool firstLetterUpper;
  235. // clusters to hold objects
  236. Cluster cells;
  237. RowCluster rows;
  238. ColumnCluster columns;
  239. // default objects
  240. Cell* defaultCell;
  241. Format* defaultFormat;
  242. RowFormat* defaultRowFormat;
  243. ColumnFormat* defaultColumnFormat;
  244. // hold the print object
  245. SheetPrint* print;
  246. // cells that need painting
  247. Region paintDirtyList;
  248. // to get font metrics
  249. TQPainter *painter;
  250. TQWidget *widget;
  251. // List of all cell bindings. For example charts use bindings to get
  252. // informed about changing cell contents.
  253. TQPtrList<CellBinding> cellBindings;
  254. // Indicates whether the sheet should paint the page breaks.
  255. // Doing so costs some time, so by default it should be turned off.
  256. bool showPageBorders;
  257. // List of all embedded objects. FIXME unused ??
  258. // TQPtrList<Child> m_lstChildren;
  259. // The highest row and column ever accessed by the user.
  260. int maxRow;
  261. int maxColumn;
  262. // Max range of canvas in x and ye direction.
  263. // Depends on KS_colMax/KS_rowMax and the width/height of all columns/rows
  264. double sizeMaxX;
  265. double sizeMaxY;
  266. bool scrollBarUpdates;
  267. TQPen emptyPen;
  268. TQBrush emptyBrush;
  269. TQColor emptyColor;
  270. int scrollPosX;
  271. int scrollPosY;
  272. KSpread::DependencyManager *dependencies;
  273. };
  274. int Sheet::s_id = 0L;
  275. TQIntDict<Sheet>* Sheet::s_mapSheets;
  276. Sheet* Sheet::find( int _id )
  277. {
  278. if ( !s_mapSheets )
  279. return 0L;
  280. return (*s_mapSheets)[ _id ];
  281. }
  282. Sheet::Sheet (Map* map,
  283. const TQString &sheetName, const char *_name )
  284. : TQObject( map, _name )
  285. {
  286. if ( s_mapSheets == 0L )
  287. s_mapSheets = new TQIntDict<Sheet>;
  288. d = new Private;
  289. d->workbook = map;
  290. d->id = s_id++;
  291. s_mapSheets->insert( d->id, this );
  292. d->layoutDirection = LeftToRight;
  293. d->defaultFormat = new Format (this, d->workbook->doc()->styleManager()->defaultStyle());
  294. d->emptyPen.setStyle( Qt::NoPen );
  295. d->dcop = 0;
  296. d->name = sheetName;
  297. dcopObject();
  298. d->cellBindings.setAutoDelete( false );
  299. // m_lstChildren.setAutoDelete( true );
  300. d->cells.setAutoDelete( true );
  301. d->rows.setAutoDelete( true );
  302. d->columns.setAutoDelete( true );
  303. d->defaultCell = new Cell( this, d->workbook->doc()->styleManager()->defaultStyle(), 0, 0);
  304. d->defaultRowFormat = new RowFormat( this, 0 );
  305. d->defaultRowFormat->setDefault();
  306. d->defaultColumnFormat = new ColumnFormat( this, 0 );
  307. d->defaultColumnFormat->setDefault();
  308. d->widget = new TQWidget();
  309. d->painter = new TQPainter;
  310. d->painter->begin( d->widget );
  311. d->maxColumn = 256;
  312. d->maxRow = 256;
  313. d->sizeMaxX = KS_colMax * d->defaultColumnFormat->dblWidth(); // default is max cols * default width
  314. d->sizeMaxY = KS_rowMax * d->defaultRowFormat->dblHeight(); // default is max rows * default height
  315. d->scrollBarUpdates = true;
  316. setHidden( false );
  317. d->showGrid=true;
  318. d->showFormula=false;
  319. d->showFormulaIndicator=true;
  320. d->showCommentIndicator=true;
  321. d->showPageBorders = false;
  322. d->lcMode=false;
  323. d->showColumnNumber=false;
  324. d->hideZero=false;
  325. d->firstLetterUpper=false;
  326. d->autoCalc=true;
  327. // Get a unique name so that we can offer scripting
  328. if ( !_name )
  329. {
  330. TQCString s;
  331. s.sprintf("Sheet%i", s_id );
  332. TQObject::setName( s.data() );
  333. }
  334. d->print = new SheetPrint( this );
  335. // initialize dependencies
  336. d->dependencies = new KSpread::DependencyManager (this);
  337. // connect to named area slots
  338. TQObject::connect( doc(), TQT_SIGNAL( sig_addAreaName( const TQString & ) ),
  339. this, TQT_SLOT( slotAreaModified( const TQString & ) ) );
  340. TQObject::connect( doc(), TQT_SIGNAL( sig_removeAreaName( const TQString & ) ),
  341. this, TQT_SLOT( slotAreaModified( const TQString & ) ) );
  342. }
  343. TQString Sheet::sheetName() const
  344. {
  345. return d->name;
  346. }
  347. Map* Sheet::workbook() const
  348. {
  349. return d->workbook;
  350. }
  351. Doc* Sheet::doc() const
  352. {
  353. return d->workbook->doc();
  354. }
  355. int Sheet::id() const
  356. {
  357. return d->id;
  358. }
  359. Sheet::LayoutDirection Sheet::layoutDirection() const
  360. {
  361. return d->layoutDirection;
  362. }
  363. void Sheet::setLayoutDirection( LayoutDirection dir )
  364. {
  365. d->layoutDirection = dir;
  366. }
  367. bool Sheet::isRightToLeft() const
  368. {
  369. return d->layoutDirection == RightToLeft;
  370. }
  371. bool Sheet::isHidden() const
  372. {
  373. return d->hide;
  374. }
  375. void Sheet::setHidden( bool hidden )
  376. {
  377. d->hide = hidden;
  378. }
  379. bool Sheet::getShowGrid() const
  380. {
  381. return d->showGrid;
  382. }
  383. void Sheet::setShowGrid( bool _showGrid )
  384. {
  385. d->showGrid=_showGrid;
  386. }
  387. bool Sheet::getShowFormula() const
  388. {
  389. return d->showFormula;
  390. }
  391. void Sheet::setShowFormula( bool _showFormula )
  392. {
  393. d->showFormula=_showFormula;
  394. }
  395. bool Sheet::getShowFormulaIndicator() const
  396. {
  397. return d->showFormulaIndicator;
  398. }
  399. void Sheet::setShowFormulaIndicator( bool _showFormulaIndicator )
  400. {
  401. d->showFormulaIndicator=_showFormulaIndicator;
  402. }
  403. bool Sheet::getShowCommentIndicator() const
  404. {
  405. return d->showCommentIndicator;
  406. }
  407. void Sheet::setShowCommentIndicator(bool _indic)
  408. {
  409. d->showCommentIndicator=_indic;
  410. }
  411. bool Sheet::getLcMode() const
  412. {
  413. return d->lcMode;
  414. }
  415. void Sheet::setLcMode( bool _lcMode )
  416. {
  417. d->lcMode=_lcMode;
  418. }
  419. bool Sheet::getAutoCalc() const
  420. {
  421. return d->autoCalc;
  422. }
  423. void Sheet::setAutoCalc( bool _AutoCalc )
  424. {
  425. //Avoid possible recalculation of dependancies if the auto calc setting hasn't changed
  426. if (d->autoCalc == _AutoCalc)
  427. return;
  428. //If enabling automatic calculation, make sure that the dependencies are up-to-date
  429. if (_AutoCalc == true)
  430. {
  431. updateAllDependencies();
  432. recalc();
  433. }
  434. d->autoCalc=_AutoCalc;
  435. }
  436. bool Sheet::getShowColumnNumber() const
  437. {
  438. return d->showColumnNumber;
  439. }
  440. void Sheet::setShowColumnNumber( bool _showColumnNumber )
  441. {
  442. d->showColumnNumber=_showColumnNumber;
  443. }
  444. bool Sheet::getHideZero() const
  445. {
  446. return d->hideZero;
  447. }
  448. void Sheet::setHideZero( bool _hideZero )
  449. {
  450. d->hideZero=_hideZero;
  451. }
  452. bool Sheet::getFirstLetterUpper() const
  453. {
  454. return d->firstLetterUpper;
  455. }
  456. void Sheet::setFirstLetterUpper( bool _firstUpper )
  457. {
  458. d->firstLetterUpper=_firstUpper;
  459. }
  460. bool Sheet::isShowPageBorders() const
  461. {
  462. return d->showPageBorders;
  463. }
  464. bool Sheet::isEmpty( unsigned long int x, unsigned long int y ) const
  465. {
  466. const Cell* c = cellAt( x, y );
  467. if ( !c || c->isEmpty() )
  468. return true;
  469. return false;
  470. }
  471. Cell* Sheet::defaultCell() const
  472. {
  473. return d->defaultCell;
  474. }
  475. Format* Sheet::defaultFormat()
  476. {
  477. return d->defaultFormat;
  478. }
  479. const Format* Sheet::defaultFormat() const
  480. {
  481. return d->defaultFormat;
  482. }
  483. const ColumnFormat* Sheet::columnFormat( int _column ) const
  484. {
  485. const ColumnFormat *p = d->columns.lookup( _column );
  486. if ( p != 0L )
  487. return p;
  488. return d->defaultColumnFormat;
  489. }
  490. ColumnFormat* Sheet::columnFormat( int _column )
  491. {
  492. ColumnFormat *p = d->columns.lookup( _column );
  493. if ( p != 0L )
  494. return p;
  495. return d->defaultColumnFormat;
  496. }
  497. const RowFormat* Sheet::rowFormat( int _row ) const
  498. {
  499. const RowFormat *p = d->rows.lookup( _row );
  500. if ( p != 0L )
  501. return p;
  502. return d->defaultRowFormat;
  503. }
  504. RowFormat* Sheet::rowFormat( int _row )
  505. {
  506. RowFormat *p = d->rows.lookup( _row );
  507. if ( p != 0L )
  508. return p;
  509. return d->defaultRowFormat;
  510. }
  511. Value Sheet::value (int col, int row) const
  512. {
  513. Cell *cell = d->cells.lookup (col, row);
  514. if (cell)
  515. return cell->value ();
  516. Value empty;
  517. return empty;
  518. }
  519. Value Sheet::valueRange (int col1, int row1,
  520. int col2, int row2) const
  521. {
  522. return d->cells.valueRange (col1, row1, col2, row2);
  523. }
  524. void Sheet::password( TQCString & passwd ) const
  525. {
  526. passwd = d->password;
  527. }
  528. bool Sheet::isProtected() const
  529. {
  530. return !d->password.isNull();
  531. }
  532. void Sheet::setProtected( TQCString const & passwd )
  533. {
  534. d->password = passwd;
  535. }
  536. bool Sheet::checkPassword( TQCString const & passwd ) const
  537. {
  538. return ( passwd == d->password );
  539. }
  540. SheetPrint* Sheet::print() const
  541. {
  542. return d->print;
  543. }
  544. TQPainter& Sheet::painter()
  545. {
  546. return *d->painter;
  547. }
  548. TQWidget* Sheet::widget()const
  549. {
  550. return d->widget;
  551. }
  552. CellBinding* Sheet::firstCellBinding()
  553. {
  554. return d->cellBindings.first();
  555. }
  556. CellBinding* Sheet::nextCellBinding()
  557. {
  558. return d->cellBindings.next();
  559. }
  560. void Sheet::setDefaultHeight( double height )
  561. {
  562. if ( isProtected() )
  563. NO_MODIFICATION_POSSIBLE;
  564. d->defaultRowFormat->setDblHeight( height );
  565. }
  566. void Sheet::setDefaultWidth( double width )
  567. {
  568. if ( isProtected() )
  569. NO_MODIFICATION_POSSIBLE;
  570. d->defaultColumnFormat->setDblWidth( width );
  571. }
  572. double Sheet::sizeMaxX() const
  573. {
  574. return d->sizeMaxX;
  575. }
  576. double Sheet::sizeMaxY() const
  577. {
  578. return d->sizeMaxY;
  579. }
  580. int Sheet::maxColumn() const
  581. {
  582. return d->maxColumn;
  583. }
  584. int Sheet::maxRow() const
  585. {
  586. return d->maxRow;
  587. }
  588. const TQPen& Sheet::emptyPen() const
  589. {
  590. return d->emptyPen;
  591. }
  592. const TQBrush& Sheet::emptyBrush() const
  593. {
  594. return d->emptyBrush;
  595. }
  596. const TQColor& Sheet::emptyColor() const
  597. {
  598. return d->emptyColor;
  599. }
  600. KSpread::DependencyManager *Sheet::dependencies ()
  601. {
  602. return d->dependencies;
  603. }
  604. int Sheet::numSelected() const
  605. {
  606. int num = 0;
  607. TQPtrListIterator<EmbeddedObject> it( d->workbook->doc()->embeddedObjects() );
  608. for ( ; it.current() ; ++it )
  609. {
  610. if( it.current()->sheet() == this && it.current()->isSelected() )
  611. num++;
  612. }
  613. return num;
  614. }
  615. int Sheet::leftColumn( double _xpos, double &_left,
  616. const Canvas *_canvas ) const
  617. {
  618. if ( _canvas )
  619. {
  620. _xpos += _canvas->xOffset();
  621. _left = -_canvas->xOffset();
  622. }
  623. else
  624. _left = 0.0;
  625. int col = 1;
  626. double x = columnFormat( col )->dblWidth( _canvas );
  627. while ( x < _xpos )
  628. {
  629. // Should never happen
  630. if ( col >= KS_colMax )
  631. {
  632. kdDebug(36001) << "Sheet:leftColumn: invalid column (col: " << col + 1 << ")" << endl;
  633. return KS_colMax + 1; //Return out of range value, so other code can react on this
  634. }
  635. _left += columnFormat( col )->dblWidth( _canvas );
  636. col++;
  637. x += columnFormat( col )->dblWidth( _canvas );
  638. }
  639. return col;
  640. }
  641. int Sheet::rightColumn( double _xpos, const Canvas *_canvas ) const
  642. {
  643. if ( _canvas )
  644. _xpos += _canvas->xOffset();
  645. int col = 1;
  646. double x = 0.0;
  647. while ( x < _xpos )
  648. {
  649. // Should never happen
  650. if ( col > KS_colMax )
  651. {
  652. kdDebug(36001) << "Sheet:rightColumn: invalid column (col: " << col << ")" << endl;
  653. return KS_colMax + 1; //Return out of range value, so other code can react on this
  654. }
  655. x += columnFormat( col )->dblWidth( _canvas );
  656. col++;
  657. }
  658. return col - 1;
  659. }
  660. TQRect Sheet::visibleRect( Canvas const * const _canvas ) const
  661. {
  662. int top = 0;
  663. int left = 0;
  664. double x = 0;
  665. double y = 0;
  666. double width = 0;
  667. double height = 0;
  668. if ( _canvas )
  669. {
  670. y += _canvas->yOffset() * _canvas->zoom();
  671. x += _canvas->xOffset() * _canvas->zoom();
  672. width = _canvas->width();
  673. height = _canvas->height();
  674. }
  675. double yn = rowFormat( top )->dblHeight( _canvas );
  676. while ( yn < y )
  677. {
  678. if ( top >= KS_rowMax ) // Should never happen
  679. break;
  680. ++top;
  681. yn += rowFormat( top )->dblHeight( _canvas );
  682. }
  683. int bottom = top + 1;
  684. y += height;
  685. while ( yn < y )
  686. {
  687. if ( bottom > KS_rowMax ) // Should never happen
  688. break;
  689. ++bottom;
  690. yn += rowFormat( bottom )->dblHeight( _canvas );
  691. }
  692. double xn = columnFormat( left )->dblWidth( _canvas );
  693. while ( xn < x )
  694. {
  695. if ( left >= KS_colMax ) // Should never happen
  696. break;
  697. ++left;
  698. xn += columnFormat( left )->dblWidth( _canvas );
  699. }
  700. x += width;
  701. int right = left + 1;
  702. while ( xn < x )
  703. {
  704. if ( right > KS_colMax ) // Should never happen
  705. break;
  706. ++right;
  707. xn += columnFormat( right )->dblWidth( _canvas );
  708. }
  709. x += width;
  710. return TQRect( left, top, right - left + 1, bottom - top + 1 );
  711. }
  712. int Sheet::topRow( double _ypos, double & _top,
  713. const Canvas *_canvas ) const
  714. {
  715. if ( _canvas )
  716. {
  717. _ypos += _canvas->yOffset();
  718. _top = -_canvas->yOffset();
  719. }
  720. else
  721. _top = 0.0;
  722. int row = 1;
  723. double y = rowFormat( row )->dblHeight( _canvas );
  724. while ( y < _ypos )
  725. {
  726. // Should never happen
  727. if ( row >= KS_rowMax )
  728. {
  729. kdDebug(36001) << "Sheet:topRow: invalid row (row: " << row + 1 << ")" << endl;
  730. return KS_rowMax + 1; //Return out of range value, so other code can react on this
  731. }
  732. _top += rowFormat( row )->dblHeight( _canvas );
  733. row++;
  734. y += rowFormat( row )->dblHeight( _canvas );
  735. }
  736. return row;
  737. }
  738. int Sheet::bottomRow( double _ypos, const Canvas *_canvas ) const
  739. {
  740. if ( _canvas )
  741. _ypos += _canvas->yOffset();
  742. int row = 1;
  743. double y = 0.0;
  744. while ( y < _ypos )
  745. {
  746. // Should never happen
  747. if ( row > KS_rowMax )
  748. {
  749. kdDebug(36001) << "Sheet:bottomRow: invalid row (row: " << row << ")" << endl;
  750. return KS_rowMax + 1; //Return out of range value, so other code can react on this
  751. }
  752. y += rowFormat( row )->dblHeight( _canvas );
  753. row++;
  754. }
  755. return row - 1;
  756. }
  757. double Sheet::dblColumnPos( int _col, const Canvas *_canvas ) const
  758. {
  759. double x = 0.0;
  760. if ( _canvas )
  761. x -= _canvas->xOffset();
  762. for ( int col = 1; col < _col; col++ )
  763. {
  764. // Should never happen
  765. if ( col > KS_colMax )
  766. {
  767. kdDebug(36001) << "Sheet:columnPos: invalid column (col: " << col << ")" << endl;
  768. return x;
  769. }
  770. x += columnFormat( col )->dblWidth( _canvas );
  771. }
  772. return x;
  773. }
  774. int Sheet::columnPos( int _col, const Canvas *_canvas ) const
  775. {
  776. return (int)dblColumnPos( _col, _canvas );
  777. }
  778. double Sheet::dblRowPos( int _row, const Canvas *_canvas ) const
  779. {
  780. double y = 0.0;
  781. if ( _canvas )
  782. y -= _canvas->yOffset();
  783. for ( int row = 1 ; row < _row ; row++ )
  784. {
  785. // Should never happen
  786. if ( row > KS_rowMax )
  787. {
  788. kdDebug(36001) << "Sheet:rowPos: invalid row (row: " << row << ")" << endl;
  789. return y;
  790. }
  791. y += rowFormat( row )->dblHeight( _canvas );
  792. }
  793. return y;
  794. }
  795. int Sheet::rowPos( int _row, const Canvas *_canvas ) const
  796. {
  797. return (int)dblRowPos( _row, _canvas );
  798. }
  799. void Sheet::adjustSizeMaxX ( double _x )
  800. {
  801. d->sizeMaxX += _x;
  802. }
  803. void Sheet::adjustSizeMaxY ( double _y )
  804. {
  805. d->sizeMaxY += _y;
  806. }
  807. Cell* Sheet::visibleCellAt( int _column, int _row, bool _scrollbar_update )
  808. {
  809. Cell* cell = cellAt( _column, _row, _scrollbar_update );
  810. if ( cell->obscuringCells().isEmpty() )
  811. return cell;
  812. else
  813. return cell->obscuringCells().last();
  814. }
  815. Cell* Sheet::firstCell() const
  816. {
  817. return d->cells.firstCell();
  818. }
  819. RowFormat* Sheet::firstRow() const
  820. {
  821. return d->rows.first();
  822. }
  823. ColumnFormat* Sheet::firstCol() const
  824. {
  825. return d->columns.first();
  826. }
  827. Cell* Sheet::cellAt( int _column, int _row ) const
  828. {
  829. Cell *p = d->cells.lookup( _column, _row );
  830. if ( p != 0L )
  831. return p;
  832. return d->defaultCell;
  833. }
  834. Cell* Sheet::cellAt( int _column, int _row, bool _scrollbar_update )
  835. {
  836. if ( _scrollbar_update && d->scrollBarUpdates )
  837. {
  838. checkRangeHBorder( _column );
  839. checkRangeVBorder( _row );
  840. }
  841. Cell *p = d->cells.lookup( _column, _row );
  842. if ( p != 0L )
  843. return p;
  844. return d->defaultCell;
  845. }
  846. ColumnFormat* Sheet::nonDefaultColumnFormat( int _column, bool force_creation )
  847. {
  848. ColumnFormat *p = d->columns.lookup( _column );
  849. if ( p != 0L || !force_creation )
  850. return p;
  851. p = new ColumnFormat( this, _column );
  852. // TODO: copy the default ColumnFormat here!!
  853. p->setDblWidth( d->defaultColumnFormat->dblWidth() );
  854. d->columns.insertElement( p, _column );
  855. return p;
  856. }
  857. RowFormat* Sheet::nonDefaultRowFormat( int _row, bool force_creation )
  858. {
  859. RowFormat *p = d->rows.lookup( _row );
  860. if ( p != 0L || !force_creation )
  861. return p;
  862. p = new RowFormat( this, _row );
  863. // TODO: copy the default RowLFormat here!!
  864. p->setDblHeight( d->defaultRowFormat->dblHeight() );
  865. d->rows.insertElement( p, _row );
  866. return p;
  867. }
  868. Cell* Sheet::nonDefaultCell( int _column, int _row,
  869. bool _scrollbar_update, Style * _style )
  870. {
  871. // NOTE Stefan: _scrollbar_update defaults to false and this function
  872. // is never called with it being true. So, this here is
  873. // actually never processed. I'll leave this in here for the
  874. // case I'm mistaken, but will remove it for 2.0.
  875. if ( _scrollbar_update && d->scrollBarUpdates )
  876. {
  877. checkRangeHBorder( _column );
  878. checkRangeVBorder( _row );
  879. }
  880. Cell * p = d->cells.lookup( _column, _row );
  881. if ( p != 0L )
  882. return p;
  883. Cell * cell = 0;
  884. if ( _style )
  885. cell = new Cell( this, _style, _column, _row );
  886. else
  887. cell = new Cell( this, _column, _row );
  888. insertCell( cell );
  889. return cell;
  890. }
  891. void Sheet::setText( int _row, int _column, const TQString& _text, bool asString )
  892. {
  893. ProtectedCheck prot;
  894. prot.setSheet (this);
  895. prot.add (TQPoint (_column, _row));
  896. if (prot.check())
  897. NO_MODIFICATION_POSSIBLE;
  898. DataManipulator *dm = new DataManipulator ();
  899. dm->setSheet (this);
  900. dm->setValue (_text);
  901. dm->setParsing (!asString);
  902. dm->add (TQPoint (_column, _row));
  903. dm->execute ();
  904. /* PRE-MANIPULATOR CODE looked like this:
  905. TODO remove this after the new code works
  906. if ( !doc()->undoLocked() )
  907. {
  908. UndoSetText *undo = new UndoSetText( doc(), this, cell->text(), _column, _row,cell->formatType() );
  909. doc()->addCommand( undo );
  910. }
  911. // The cell will force a display refresh itself, so we dont have to care here.
  912. cell->setCellText( _text, asString );
  913. */
  914. //refresh anchor
  915. if(_text.at(0)=='!')
  916. emit sig_updateView( this, Region(_column,_row,_column,_row) );
  917. }
  918. void Sheet::setArrayFormula (Selection *selectionInfo, const TQString &_text)
  919. {
  920. // check protection
  921. ProtectedCheck prot;
  922. prot.setSheet (this);
  923. prot.add (*selectionInfo);
  924. if (prot.check())
  925. NO_MODIFICATION_POSSIBLE;
  926. // create and call the manipulator
  927. ArrayFormulaManipulator *afm = new ArrayFormulaManipulator;
  928. afm->setSheet (this);
  929. afm->setText (_text);
  930. afm->add (*selectionInfo);
  931. afm->execute ();
  932. /* PRE-MANIPULATOR CODE LOOKED LIKE THIS
  933. TODO remove this when the above code works
  934. // add undo
  935. if ( !doc()->undoLocked() )
  936. {
  937. UndoChangeAreaTextCell *undo =
  938. new UndoChangeAreaTextCell (doc(), this,
  939. TQRect (_column, _row, cols, rows));
  940. doc()->addCommand( undo );
  941. }
  942. // fill in the cells ... top-left one gets the formula, the rest gets =INDEX
  943. // TODO: also fill in information about cells being a part of a range
  944. Cell *cell = nonDefaultCell (_column, _row);
  945. cell->setCellText (_text, false);
  946. TQString cellRef = cell->name();
  947. for (int row = 0; row < rows; ++row)
  948. for (int col = 0; col < cols; col++)
  949. if (col || row)
  950. {
  951. Cell *cell = nonDefaultCell (_column + col, _row + row);
  952. cell->setCellText ("=INDEX(" + cellRef + ";" + TQString::number (row+1)
  953. + ";" + TQString::number (col+1) + ")", false);
  954. }
  955. */
  956. }
  957. void Sheet::setLayoutDirtyFlag()
  958. {
  959. Cell * c = d->cells.firstCell();
  960. for( ; c; c = c->nextCell() )
  961. c->setLayoutDirtyFlag();
  962. }
  963. void Sheet::setCalcDirtyFlag()
  964. {
  965. Cell* c = d->cells.firstCell();
  966. for( ; c; c = c->nextCell() )
  967. {
  968. if ( !(c->isObscured() && c->isPartOfMerged()) )
  969. c->setCalcDirtyFlag();
  970. }
  971. }
  972. void Sheet::updateAllDependencies()
  973. {
  974. for (Cell* cell = d->cells.firstCell() ; cell ; cell = cell->nextCell())
  975. {
  976. Point cellLocation;
  977. cellLocation.setSheet(cell->sheet());
  978. cellLocation.setRow(cell->row());
  979. cellLocation.setColumn(cell->column());
  980. d->dependencies->cellChanged(cellLocation);
  981. }
  982. }
  983. void Sheet::recalc()
  984. {
  985. recalc(false);
  986. }
  987. void Sheet::recalc( bool force )
  988. {
  989. ElapsedTime et( "Recalculating " + d->name, ElapsedTime::PrintOnlyTime );
  990. // emitBeginOperation(true);
  991. // setRegionPaintDirty(TQRect(TQPoint(1,1), TQPoint(KS_colMax, KS_rowMax)));
  992. setCalcDirtyFlag();
  993. //If automatic calculation is disabled, don't recalculate unless the force flag has been
  994. //set.
  995. if ( !getAutoCalc() && !force )
  996. return;
  997. //If automatic calculation is disabled, the dependencies won't be up to date, so they need
  998. //to be recalculated.
  999. //FIXME: Tomas, is there a more efficient way to do this?
  1000. if ( !getAutoCalc() )
  1001. updateAllDependencies();
  1002. // (Tomas): actually recalc each cell
  1003. // this is FAR from being perfect, dependencies will cause some to be
  1004. // recalculated a LOT, but it's still better than otherwise, where
  1005. // we get no recalc if the result stored in a file differs from the
  1006. // current one - then we only obtain the correct result AFTER we scroll
  1007. // to the cell ... recalc should actually ... recalc :)
  1008. Cell* c;
  1009. int count = 0;
  1010. c = d->cells.firstCell();
  1011. for( ; c; c = c->nextCell() )
  1012. ++count;
  1013. int cur = 0;
  1014. int percent = -1;
  1015. c = d->cells.firstCell();
  1016. for( ; c; c = c->nextCell() )
  1017. {
  1018. c->calc (false);
  1019. cur++;
  1020. // some debug output to get some idea how damn slow this is ...
  1021. if (cur*100/count != percent) {
  1022. percent = cur*100/count;
  1023. // kdDebug() << "Recalc: " << percent << "%" << endl;
  1024. }
  1025. }
  1026. // emitEndOperation();
  1027. emit sig_updateView( this );
  1028. }
  1029. void Sheet::valueChanged (Cell *cell)
  1030. {
  1031. //TODO: call cell updating, when cell damaging implemented
  1032. //prepare the Point structure
  1033. Point c;
  1034. c.setRow (cell->row());
  1035. c.setColumn (cell->column());
  1036. c.setSheet( this );
  1037. //update dependencies
  1038. if ( getAutoCalc() )
  1039. d->dependencies->cellChanged (c);
  1040. //REMOVED - modification change - this was causing modified flag to be set inappropriately.
  1041. //nobody else seems to be setting the modified flag, so we do it here
  1042. // doc()->setModified (true);
  1043. }
  1044. /*
  1045. Methods working on selections:
  1046. TYPE A:
  1047. { columns selected:
  1048. for all rows with properties X,X':
  1049. if default-cell create new cell
  1050. }
  1051. post undo object (always a UndoCellLayout; difference in title only)
  1052. { rows selected:
  1053. if condition Y clear properties X,X' of cells;
  1054. set properties X,X' of rowformats
  1055. emit complete update;
  1056. }
  1057. { columns selected:
  1058. if condition Y clear properties X,X' of cells;
  1059. set properties X,X' of columnformats;
  1060. for all rows with properties X,X':
  1061. create cells if necessary and set properties X,X'
  1062. emit complete update;
  1063. }
  1064. { cells selected:
  1065. for all cells with condition Y:
  1066. create if necessary and set properties X,X' and do Z;
  1067. emit update on selected region;
  1068. }
  1069. USED in:
  1070. setSelectionFont
  1071. setSelectionSize
  1072. setSelectionAngle
  1073. setSelectionTextColor
  1074. setSelectionBgColor
  1075. setSelectionPercent
  1076. borderAll
  1077. borderRemove (exceptions: ### creates cells (why?), ### changes default cell if cell-regions selected?)
  1078. setSelectionAlign
  1079. setSelectionAlignY
  1080. setSelectionMoneyFormat
  1081. increaseIndent
  1082. decreaseIndent
  1083. TYPE B:
  1084. post undo object
  1085. { rows selected:
  1086. if condition Y do X with cells;
  1087. emit update on selection;
  1088. }
  1089. { columns selected:
  1090. if condition Y do X with cells;
  1091. emit update on selection;
  1092. }
  1093. { cells selected:
  1094. if condition Y do X with cells; create cell if non-default;
  1095. emit update on selection;
  1096. }
  1097. USED in:
  1098. setSelectionUpperLower (exceptions: no undo; no create-if-default; ### modifies default-cell?)
  1099. setSelectionFirstLetterUpper (exceptions: no undo; no create-if-default; ### modifies default-cell?)
  1100. setSelectionVerticalText
  1101. setSelectionComment
  1102. setSelectionRemoveComment (exeception: no create-if-default and work only on non-default-cells for cell regions)
  1103. setSelectionBorderColor (exeception: no create-if-default and work only on non-default-cells for cell regions)
  1104. setSelectionMultiRow
  1105. setSelectionPrecision
  1106. clearTextSelection (exception: all only if !areaIsEmpty())
  1107. clearValiditySelection (exception: all only if !areaIsEmpty())
  1108. clearConditionalSelection (exception: all only if !areaIsEmpty())
  1109. setConditional (exception: conditional after create-if-default for cell regions)
  1110. setValidity (exception: conditional after create-if-default for cell regions)
  1111. OTHERS:
  1112. borderBottom
  1113. borderRight
  1114. borderLeft
  1115. borderTop
  1116. borderOutline
  1117. => these work only on some cells (at the border); undo only if cells affected; rest is similar to type A
  1118. --> better not use CellWorker/workOnCells()
  1119. defaultSelection
  1120. => similar to TYPE B, but works on columns/rows if complete columns/rows selected
  1121. --> use emit_signal=false and return value of workOnCells to finish
  1122. getWordSpelling
  1123. => returns text, no signal emitted, no cell-create, similar to TYPE B
  1124. --> use emit_signal=false, create_if_default=false and type B
  1125. setWordSpelling
  1126. => no signal emitted, no cell-create, similar to type B
  1127. --> use emit_signal=false, create_if_default=false and type B
  1128. */
  1129. class UndoAction* Sheet::CellWorkerTypeA::createUndoAction( Doc* doc, Sheet* sheet, const KSpread::Region& region )
  1130. {
  1131. TQString title = getUndoTitle();
  1132. return new UndoCellFormat( doc, sheet, region, title );
  1133. }
  1134. /*
  1135. Sheet::SelectionType Sheet::workOnCells( const TQPoint& _marker, CellWorker& worker )
  1136. {
  1137. // see what is selected; if nothing, take marker position
  1138. bool selected = ( m_rctSelection.left() != 0 );
  1139. TQRect r( m_rctSelection );
  1140. if ( !selected )
  1141. r.setCoords( _marker.x(), _marker.y(), _marker.x(), _marker.y() );
  1142. // create cells in rows if complete columns selected
  1143. Cell *cell;
  1144. if ( !worker.type_B && selected && isColumnSelected() )
  1145. {
  1146. for ( RowFormat* rw =d->rows.first(); rw; rw = rw->next() )
  1147. {
  1148. if ( !rw->isDefault() && worker.testCondition( rw ) )
  1149. {
  1150. for ( int i=m_rctSelection.left(); i<=m_rctSelection.right(); i++ )
  1151. {
  1152. cell = cellAt( i, rw->row() );
  1153. if ( cell == d->defaultCell )
  1154. // '&& worker.create_if_default' unnecessary as never used in type A
  1155. {
  1156. cell = new Cell( this, i, rw->row() );
  1157. insertCell( cell );
  1158. }
  1159. }
  1160. }
  1161. }
  1162. }
  1163. // create an undo action
  1164. if ( !doc()->undoLocked() )
  1165. {
  1166. UndoAction *undo = worker.createUndoAction( doc(), this, r );
  1167. // test if the worker has an undo action
  1168. if ( undo != 0L )
  1169. doc()->addCommand( undo );
  1170. }
  1171. // complete rows selected ?
  1172. if ( selected && isRowSelected() )
  1173. {
  1174. int row;
  1175. for ( Cell* cell = d->cells.firstCell(); cell; cell = cell->nextCell() )
  1176. {
  1177. row = cell->row();
  1178. if ( m_rctSelection.top() <= row && m_rctSelection.bottom() >= row
  1179. && worker.testCondition( cell ) )
  1180. if ( worker.type_B )
  1181. worker.doWork( cell, false, cell->column(), row );
  1182. else
  1183. worker.prepareCell( cell );
  1184. }
  1185. if ( worker.type_B ) {
  1186. // for type B there's nothing left to do
  1187. if ( worker.emit_signal )
  1188. emit sig_updateView( this, r );
  1189. } else {
  1190. // for type A now work on row formats
  1191. for ( int i=m_rctSelection.top(); i<=m_rctSelection.bottom(); i++ )
  1192. {
  1193. RowFormat *rw=nonDefaultRowFormat(i);
  1194. worker.doWork( rw );
  1195. }
  1196. if ( worker.emit_signal )
  1197. emit sig_updateView( this );
  1198. }
  1199. return CompleteRows;
  1200. }
  1201. // complete columns selected ?
  1202. else if ( selected && isColumnSelected() )
  1203. {
  1204. int col;
  1205. for ( Cell* cell = d->cells.firstCell(); cell; cell = cell->nextCell() )
  1206. {
  1207. col = cell->column();
  1208. if ( m_rctSelection.left() <= col && m_rctSelection.right() >= col
  1209. && worker.testCondition( cell ) )
  1210. if ( worker.type_B )
  1211. worker.doWork( cell, false, col, cell->row() );
  1212. else
  1213. worker.prepareCell( cell );
  1214. }
  1215. if ( worker.type_B ) {
  1216. if ( worker.emit_signal )
  1217. emit sig_updateView( this, r );
  1218. } else {
  1219. // for type A now work on column formats
  1220. for ( int i=m_rctSelection.left(); i<=m_rctSelection.right(); i++ )
  1221. {
  1222. ColumnFormat *cl=nonDefaultColumnFormat(i);
  1223. worker.doWork( cl );
  1224. }
  1225. Cell *cell;
  1226. for ( RowFormat* rw =d->rows.first(); rw; rw = rw->next() )
  1227. {
  1228. if ( !rw->isDefault() && worker.testCondition( rw ) )
  1229. {
  1230. for ( int i=m_rctSelection.left(); i<=m_rctSelection.right(); i++ )
  1231. {
  1232. cell = cellAt( i, rw->row() );
  1233. // ### this if should be not necessary; cells are created
  1234. // before the undo object is created, aren't they?
  1235. if ( cell == d->defaultCell )
  1236. {
  1237. cell = new Cell( this, i, rw->row() );
  1238. insertCell( cell );
  1239. }
  1240. worker.doWork( cell, false, i, rw->row() );
  1241. }
  1242. }
  1243. }
  1244. if ( worker.emit_signal )
  1245. emit sig_updateView( this );
  1246. }
  1247. return CompleteColumns;
  1248. }
  1249. // cell region selected
  1250. else
  1251. {
  1252. Cell *cell;
  1253. for ( int x = r.left(); x <= r.right(); x++ )
  1254. for ( int y = r.top(); y <= r.bottom(); y++ )
  1255. {
  1256. cell = cellAt( x, y );
  1257. if ( worker.testCondition( cell ) )
  1258. {
  1259. if ( worker.create_if_default && cell == d->defaultCell )
  1260. {
  1261. cell = new Cell( this, x, y );
  1262. insertCell( cell );
  1263. }
  1264. if ( cell != d->defaultCell )
  1265. worker.doWork( cell, true, x, y );
  1266. }
  1267. }
  1268. if ( worker.emit_signal )
  1269. emit sig_updateView( this, r );
  1270. return CellRegion;
  1271. }
  1272. }
  1273. */
  1274. Sheet::SelectionType Sheet::workOnCells( Selection* selectionInfo, CellWorker & worker )
  1275. {
  1276. Sheet::SelectionType result;
  1277. doc()->emitBeginOperation();
  1278. // see what is selected; if nothing, take marker position
  1279. bool selected = !(selectionInfo->isSingular());
  1280. // create an undo action
  1281. if ( !doc()->undoLocked() )
  1282. {
  1283. UndoAction* undo = worker.createUndoAction(doc(), this, *selectionInfo);
  1284. // test if the worker has an undo action
  1285. if ( undo != 0 )
  1286. {
  1287. doc()->addCommand( undo );
  1288. }
  1289. }
  1290. Region::ConstIterator endOfList(selectionInfo->constEnd());
  1291. for (Region::ConstIterator it = selectionInfo->constBegin(); it != endOfList; ++it)
  1292. {
  1293. // see what is selected; if nothing, take marker position
  1294. TQRect range = (*it)->rect().normalize();
  1295. int top = range.top();
  1296. int left = range.left();
  1297. int bottom = range.bottom();
  1298. int right = range.right();
  1299. // create cells in rows if complete columns selected
  1300. Cell * cell;
  1301. Style * s = doc()->styleManager()->defaultStyle();
  1302. if ( !worker.type_B && selected && util_isColumnSelected(range) )
  1303. {
  1304. for ( RowFormat * rw = d->rows.first(); rw; rw = rw->next() )
  1305. {
  1306. if ( worker.testCondition( rw ) )
  1307. {
  1308. for ( int col = left; col <= right; ++col )
  1309. {
  1310. cell = nonDefaultCell( col, rw->row(), false, s );
  1311. }
  1312. }
  1313. }
  1314. }
  1315. // complete rows selected ?
  1316. if ( selected && util_isRowSelected(range) )
  1317. {
  1318. for ( int row = top; row <= bottom; ++row )
  1319. {
  1320. cell = getFirstCellRow( row );
  1321. while ( cell )
  1322. {
  1323. if ( worker.testCondition( cell ) )
  1324. {
  1325. if ( worker.type_B )
  1326. worker.doWork( cell, false, cell->column(), row );
  1327. else
  1328. worker.prepareCell( cell );
  1329. }
  1330. cell = getNextCellRight( cell->column(), row );
  1331. }
  1332. }
  1333. if ( worker.type_B )
  1334. {
  1335. // for type B there's nothing left to do
  1336. ;
  1337. }
  1338. else
  1339. {
  1340. // for type A now work on row formats
  1341. for ( int i = top; i <= bottom; ++i )
  1342. {
  1343. RowFormat * rw = nonDefaultRowFormat(i);
  1344. worker.doWork( rw );
  1345. }
  1346. for ( int row = top; row <= bottom; ++row )
  1347. {
  1348. cell = getFirstCellRow( row );
  1349. while ( cell )
  1350. {
  1351. if ( worker.testCondition( cell ) )
  1352. {
  1353. worker.doWork( cell, false, cell->column(), row );
  1354. }
  1355. cell = getNextCellRight( cell->column(), row );
  1356. }
  1357. }
  1358. }
  1359. result = CompleteRows;
  1360. }
  1361. // complete columns selected ?
  1362. else if ( selected && util_isColumnSelected(range) )
  1363. {
  1364. for ( int col = range.left(); col <= right; ++col )
  1365. {
  1366. cell = getFirstCellColumn( col );
  1367. while ( cell )
  1368. {
  1369. if ( worker.testCondition( cell ) )
  1370. {
  1371. if ( worker.type_B )
  1372. worker.doWork( cell, false, col, cell->row() );
  1373. else
  1374. worker.prepareCell( cell );
  1375. }
  1376. cell = getNextCellDown( col, cell->row() );
  1377. }
  1378. }
  1379. if ( worker.type_B )
  1380. {
  1381. ;
  1382. }
  1383. else
  1384. {
  1385. // for type A now work on column formats
  1386. for ( int i = left; i <= right; ++i )
  1387. {
  1388. ColumnFormat * cl = nonDefaultColumnFormat( i );
  1389. worker.doWork( cl );
  1390. }
  1391. for ( RowFormat * rw = d->rows.first(); rw; rw = rw->next() )
  1392. {
  1393. if ( worker.testCondition( rw ) )
  1394. {
  1395. for ( int i = left; i <= right; ++i )
  1396. {
  1397. cell = nonDefaultCell( i, rw->row(), false, s );
  1398. worker.doWork( cell, false, i, rw->row() );
  1399. }
  1400. }
  1401. }
  1402. }
  1403. result = CompleteColumns;
  1404. }
  1405. // cell region selected
  1406. else
  1407. {
  1408. for ( int x = left; x <= right; ++x )
  1409. {
  1410. enableScrollBarUpdates(false);
  1411. for ( int y = top; y <= bottom; ++y )
  1412. {
  1413. cell = cellAt( x, y );
  1414. if ( worker.testCondition( cell ) )
  1415. {
  1416. if ( cell == d->defaultCell && worker.create_if_default )
  1417. {
  1418. cell = new Cell( this, s, x, y );
  1419. insertCell( cell );
  1420. }
  1421. if ( cell != d->defaultCell )
  1422. {
  1423. // kdDebug() << "not default" << endl;
  1424. worker.doWork( cell, true, x, y );
  1425. }
  1426. }
  1427. }
  1428. enableScrollBarUpdates(true);
  1429. checkRangeVBorder(bottom);
  1430. }
  1431. checkRangeHBorder(right);
  1432. result = CellRegion;
  1433. }
  1434. } // for Region::Elements
  1435. // emitEndOperation();
  1436. emit sig_updateView( this );
  1437. if (worker.emit_signal)
  1438. {
  1439. emit sig_updateView( this, *selectionInfo );
  1440. }
  1441. return result;
  1442. }
  1443. void Sheet::setSelectionFont( Selection* selectionInfo,
  1444. const char *_font, int _size,
  1445. signed char _bold, signed char _italic,
  1446. signed char _underline, signed char _strike)
  1447. {
  1448. FontManipulator* manipulator = new FontManipulator();
  1449. manipulator->setSheet(this);
  1450. manipulator->setProperty(Format::PFont);
  1451. manipulator->setFontFamily(_font);
  1452. manipulator->setFontSize(_size);
  1453. manipulator->setFontBold(_bold);
  1454. manipulator->setFontItalic(_italic);
  1455. manipulator->setFontStrike(_strike);
  1456. manipulator->setFontUnderline(_underline);
  1457. manipulator->add(*selectionInfo);
  1458. manipulator->execute();
  1459. }
  1460. void Sheet::setSelectionSize(Selection* selectionInfo,
  1461. int _size)
  1462. {
  1463. // TODO Stefan: Increase/Decrease font size still used?
  1464. int size;
  1465. Cell* c;
  1466. TQPoint marker(selectionInfo->marker());
  1467. c = cellAt(marker);
  1468. size = c->format()->textFontSize(marker.x(), marker.y());
  1469. FontManipulator* manipulator = new FontManipulator();
  1470. manipulator->setSheet(this);
  1471. manipulator->setProperty(Format::PFont);
  1472. manipulator->setFontSize(_size+size);
  1473. manipulator->add(*selectionInfo);
  1474. manipulator->execute();
  1475. }
  1476. struct SetSelectionUpperLowerWorker : public Sheet::CellWorker {
  1477. int _type;
  1478. Sheet * _s;
  1479. SetSelectionUpperLowerWorker( int type, Sheet * s )
  1480. : Sheet::CellWorker( false ), _type( type ), _s( s ) { }
  1481. class UndoAction* createUndoAction( Doc* doc, Sheet* sheet, const KSpread::Region& region )
  1482. {
  1483. return new UndoChangeAreaTextCell( doc, sheet, region );
  1484. }
  1485. bool testCondition( Cell* c ) {
  1486. return ( !c->value().isNumber() && !c->value().isBoolean() &&!c->isFormula() && !c->isDefault()
  1487. && !c->text().isEmpty() && c->text()[0] != '*' && c->text()[0] != '!'
  1488. && !c->isPartOfMerged() );
  1489. }
  1490. void doWork( Cell* cell, bool, int, int )
  1491. {
  1492. cell->setDisplayDirtyFlag();
  1493. if ( _type == -1 )
  1494. cell->setCellText( (cell->text().lower()));
  1495. else if ( _type == 1 )
  1496. cell->setCellText( (cell->text().upper()));
  1497. cell->clearDisplayDirtyFlag();
  1498. }
  1499. };
  1500. void Sheet::setSelectionUpperLower( Selection* selectionInfo,
  1501. int _type )
  1502. {
  1503. SetSelectionUpperLowerWorker w( _type, this );
  1504. workOnCells( selectionInfo, w );
  1505. }
  1506. struct SetSelectionFirstLetterUpperWorker : public Sheet::CellWorker
  1507. {
  1508. Changes * _c;
  1509. Sheet * _s;
  1510. SetSelectionFirstLetterUpperWorker( Sheet * s )
  1511. : Sheet::CellWorker( false ), _s( s ) { }
  1512. class UndoAction* createUndoAction( Doc* doc, Sheet* sheet, const KSpread::Region& region ) {
  1513. return new UndoChangeAreaTextCell( doc, sheet, region );
  1514. }
  1515. bool testCondition( Cell* c ) {
  1516. return ( !c->value().isNumber() && !c->value().isBoolean() &&!c->isFormula() && !c->isDefault()
  1517. && !c->text().isEmpty() && c->text()[0] != '*' && c->text()[0] != '!'
  1518. && !c->isPartOfMerged() );
  1519. }
  1520. void doWork( Cell* cell, bool, int, int )
  1521. {
  1522. cell->setDisplayDirtyFlag();
  1523. TQString tmp = cell->text();
  1524. int len = tmp.length();
  1525. cell->setCellText( (tmp.at(0).upper()+tmp.right(len-1)) );
  1526. cell->clearDisplayDirtyFlag();
  1527. }
  1528. };
  1529. void Sheet::setSelectionfirstLetterUpper( Selection* selectionInfo)
  1530. {
  1531. SetSelectionFirstLetterUpperWorker w( this );
  1532. workOnCells( selectionInfo, w );
  1533. }
  1534. struct SetSelectionVerticalTextWorker : public Sheet::CellWorker {
  1535. bool _b;
  1536. SetSelectionVerticalTextWorker( bool b ) : Sheet::CellWorker( ), _b( b ) { }
  1537. class UndoAction* createUndoAction( Doc* doc, Sheet* sheet, const KSpread::Region& region ) {
  1538. TQString title=i18n("Vertical Text");
  1539. return new UndoCellFormat( doc, sheet, region, title );
  1540. }
  1541. bool testCondition( Cell* cell ) {
  1542. return ( !cell->isPartOfMerged() );
  1543. }
  1544. void doWork( Cell* cell, bool, int, int ) {
  1545. cell->setDisplayDirtyFlag();
  1546. cell->format()->setVerticalText( _b );
  1547. cell->format()->setMultiRow( false );
  1548. cell->format()->setAngle( 0 );
  1549. cell->clearDisplayDirtyFlag();
  1550. }
  1551. };
  1552. void Sheet::setSelectionVerticalText( Selection* selectionInfo,
  1553. bool _b )
  1554. {
  1555. SetSelectionVerticalTextWorker w( _b );
  1556. workOnCells( selectionInfo, w );
  1557. }
  1558. struct SetSelectionCommentWorker : public Sheet::CellWorker {
  1559. TQString _comment;
  1560. SetSelectionCommentWorker( TQString comment ) : Sheet::CellWorker( ), _comment( comment ) { }
  1561. class UndoAction* createUndoAction( Doc* doc, Sheet* sheet, const KSpread::Region& region ) {
  1562. TQString title=i18n("Add Comment");
  1563. return new UndoCellFormat( doc, sheet, region, title );
  1564. }
  1565. bool testCondition( Cell* cell ) {
  1566. return ( !cell->isPartOfMerged() );
  1567. }
  1568. void doWork( Cell* cell, bool, int, int ) {
  1569. cell->setDisplayDirtyFlag();
  1570. cell->format()->setComment( _comment );
  1571. cell->clearDisplayDirtyFlag();
  1572. }
  1573. };
  1574. void Sheet::setSelectionComment( Selection* selectionInfo,
  1575. const TQString &_comment)
  1576. {
  1577. SetSelectionCommentWorker w( _comment );
  1578. workOnCells( selectionInfo, w );
  1579. }
  1580. void Sheet::setSelectionAngle( Selection* selectionInfo,
  1581. int _value )
  1582. {
  1583. AngleManipulator* manipulator = new AngleManipulator();
  1584. manipulator->setSheet(this);
  1585. manipulator->setProperty(Format::PAngle);
  1586. manipulator->setAngle(_value);
  1587. manipulator->add(*selectionInfo);
  1588. manipulator->execute();
  1589. }
  1590. struct SetSelectionRemoveCommentWorker : public Sheet::CellWorker {
  1591. SetSelectionRemoveCommentWorker( ) : Sheet::CellWorker( false ) { }
  1592. class UndoAction* createUndoAction( Doc* doc, Sheet* sheet, const KSpread::Region& region ) {
  1593. TQString title=i18n("Remove Comment");
  1594. return new UndoCellFormat( doc, sheet, region, title );
  1595. }
  1596. bool testCondition( Cell* cell ) {
  1597. return ( !cell->isPartOfMerged() );
  1598. }
  1599. void doWork( Cell* cell, bool, int, int ) {
  1600. cell->setDisplayDirtyFlag();
  1601. cell->format()->setComment( "" );
  1602. cell->clearDisplayDirtyFlag();
  1603. }
  1604. };
  1605. void Sheet::setSelectionRemoveComment( Selection* selectionInfo )
  1606. {
  1607. if (areaIsEmpty(*selectionInfo, Comment))
  1608. return;
  1609. SetSelectionRemoveCommentWorker w;
  1610. workOnCells( selectionInfo, w );
  1611. }
  1612. void Sheet::setSelectionTextColor( Selection* selectionInfo,
  1613. const TQColor &tb_Color )
  1614. {
  1615. FontColorManipulator* manipulator = new FontColorManipulator();
  1616. manipulator->setSheet(this);
  1617. manipulator->setProperty(Format::PTextPen);
  1618. manipulator->setTextColor(tb_Color);
  1619. manipulator->add(*selectionInfo);
  1620. manipulator->execute();
  1621. }
  1622. void Sheet::setSelectionbgColor( Selection* selectionInfo,
  1623. const TQColor &bg_Color )
  1624. {
  1625. BackgroundColorManipulator* manipulator = new BackgroundColorManipulator();
  1626. manipulator->setSheet(this);
  1627. manipulator->setProperty(Format::PBackgroundColor);
  1628. manipulator->setBackgroundColor(bg_Color);
  1629. manipulator->add(*selectionInfo);
  1630. manipulator->execute();
  1631. }
  1632. struct SetSelectionBorderColorWorker : public Sheet::CellWorker {
  1633. const TQColor& bd_Color;
  1634. SetSelectionBorderColorWorker( const TQColor& _bd_Color ) : Sheet::CellWorker( false ), bd_Color( _bd_Color ) { }
  1635. class UndoAction* createUndoAction( Doc* doc, Sheet* sheet, const KSpread::Region& region ) {
  1636. TQString title=i18n("Change Border Color");
  1637. return new UndoCellFormat( doc, sheet, region, title );
  1638. }
  1639. bool testCondition( Cell* cell ) {
  1640. return ( !cell->isPartOfMerged() );
  1641. }
  1642. void doWork( Cell* cell, bool, int, int ) {
  1643. cell->setDisplayDirtyFlag();
  1644. int it_Row = cell->row();
  1645. int it_Col = cell->column();
  1646. if ( cell->format()->topBorderStyle( it_Row, it_Col )!=TQt::NoPen )
  1647. cell->format()->setTopBorderColor( bd_Color );
  1648. if ( cell->format()->leftBorderStyle( it_Row, it_Col )!=TQt::NoPen )
  1649. cell->format()->setLeftBorderColor( bd_Color );
  1650. if ( cell->format()->fallDiagonalStyle( it_Row, it_Col )!=TQt::NoPen )
  1651. cell->format()->setFallDiagonalColor( bd_Color );
  1652. if ( cell->format()->goUpDiagonalStyle( it_Row, it_Col )!=TQt::NoPen )
  1653. cell->format()->setGoUpDiagonalColor( bd_Color );
  1654. if ( cell->format()->bottomBorderStyle( it_Row, it_Col )!=TQt::NoPen )
  1655. cell->format()->setBottomBorderColor( bd_Color );
  1656. if ( cell->format()->rightBorderStyle( it_Row, it_Col )!=TQt::NoPen )
  1657. cell->format()->setRightBorderColor( bd_Color );
  1658. cell->clearDisplayDirtyFlag();
  1659. }
  1660. };
  1661. void Sheet::setSelectionBorderColor( Selection* selectionInfo,
  1662. const TQColor &bd_Color )
  1663. {
  1664. SetSelectionBorderColorWorker w( bd_Color );
  1665. workOnCells( selectionInfo, w );
  1666. }
  1667. void Sheet::setSeries( const TQPoint &_marker, double start, double end, double step, Series mode, Series type)
  1668. {
  1669. doc()->emitBeginOperation();
  1670. TQString cellText;
  1671. int x,y; /* just some loop counters */
  1672. /* the actual number of columns or rows that the series will span.
  1673. i.e. this will count 3 cells for a single cell that spans three rows
  1674. */
  1675. int numberOfCells;
  1676. if (end > start)
  1677. numberOfCells = (int) ((end - start) / step + 1); /*initialize for linear*/
  1678. else if ( end <start )
  1679. numberOfCells = (int) ((start - end) / step + 1); /*initialize for linear*/
  1680. else //equal ! => one cell fix infini loop
  1681. numberOfCells = 1;
  1682. if (type == Geometric)
  1683. {
  1684. /* basically, A(n) = start ^ n
  1685. * so when does end = start ^ n ??
  1686. * when n = ln(end) / ln(start)
  1687. */
  1688. numberOfCells = (int)( (log((double)end) / log((double)start)) +
  1689. DBL_EPSILON) + 1;
  1690. }
  1691. Cell * cell = NULL;
  1692. /* markers for the top-left corner of the undo region. It'll probably
  1693. * be the top left corner of where the series is, but if something in front
  1694. * is obscuring the cell, then it needs to be part of the undo region */
  1695. TQRect undoRegion;
  1696. undoRegion.setLeft(_marker.x());
  1697. undoRegion.setTop(_marker.y());
  1698. /* this whole block is used to find the correct size for the undo region.
  1699. We're checking for two different things (in these examples,
  1700. mode==column):
  1701. 1. cells are vertically merged. This means that one value in the
  1702. series will span multiple cells.
  1703. 2. a cell in the column is merged to a cell to its left. In this case
  1704. the cell value will be stored in the left most cell so we need to
  1705. extend the undo range to include that column.
  1706. */
  1707. if ( mode == Column )
  1708. {
  1709. for ( y = _marker.y(); y <= (_marker.y() + numberOfCells - 1) && y <= KS_rowMax; y++ )
  1710. {
  1711. cell = cellAt( _marker.x(), y );
  1712. if ( cell->isPartOfMerged() )
  1713. {
  1714. /* case 2. */
  1715. cell = cell->obscuringCells().first();
  1716. undoRegion.setLeft(TQMIN(undoRegion.left(), cell->column()));
  1717. }
  1718. /* case 1. Add the extra space to numberOfCells and then skip
  1719. over the region. Note that because of the above if block 'cell'
  1720. points to the correct cell in the case where both case 1 and 2
  1721. are true
  1722. */
  1723. numberOfCells += cell->extraYCells();
  1724. y += cell->extraYCells();
  1725. }
  1726. undoRegion.setRight( _marker.x() );
  1727. undoRegion.setBottom( y - 1 );
  1728. checkRangeVBorder( undoRegion.bottom() );
  1729. }
  1730. else if(mode == Row)
  1731. {
  1732. for ( x = _marker.x(); x <=(_marker.x() + numberOfCells - 1) && x <= KS_colMax; x++ )
  1733. {
  1734. /* see the code above for a column series for a description of
  1735. what is going on here. */
  1736. cell = cellAt( x,_marker.y(), false );
  1737. if ( cell->isPartOfMerged() )
  1738. {
  1739. cell = cell->obscuringCells().first();
  1740. undoRegion.setTop(TQMIN(undoRegion.top(), cell->row()));
  1741. }
  1742. numberOfCells += cell->extraXCells();
  1743. x += cell->extraXCells();
  1744. }
  1745. undoRegion.setBottom( _marker.y() );
  1746. undoRegion.setRight( x - 1 );
  1747. checkRangeHBorder( undoRegion.right() );
  1748. }
  1749. kdDebug() << "Saving undo information" << endl;
  1750. if ( !doc()->undoLocked() )
  1751. {
  1752. UndoChangeAreaTextCell *undo = new
  1753. UndoChangeAreaTextCell( doc(), this, undoRegion );
  1754. doc()->addCommand( undo );
  1755. }
  1756. kdDebug() << "Saving undo information done" << endl;
  1757. setRegionPaintDirty( undoRegion );
  1758. x = _marker.x();
  1759. y = _marker.y();
  1760. /* now we're going to actually loop through and set the values */
  1761. double incr;
  1762. Style * s = doc()->styleManager()->defaultStyle();
  1763. if (step >= 0 && start < end)
  1764. {
  1765. for ( incr = start; incr <= end; )
  1766. {
  1767. cell = nonDefaultCell( x, y, false, s );
  1768. if ( cell->isPartOfMerged() )
  1769. {
  1770. cell = cell->obscuringCells().first();
  1771. }
  1772. // cell->setCellText(cellText.setNum( incr ));
  1773. cell->setNumber( incr );
  1774. if (mode == Column)
  1775. {
  1776. ++y;
  1777. if (cell->doesMergeCells())
  1778. {
  1779. y += cell->extraYCells();
  1780. }
  1781. if ( y > KS_rowMax )
  1782. {
  1783. break;
  1784. }
  1785. }
  1786. else if (mode == Row)
  1787. {
  1788. ++x;
  1789. if (cell->doesMergeCells())
  1790. {
  1791. x += cell->extraXCells();
  1792. }
  1793. if ( x > KS_colMax )
  1794. {
  1795. break;
  1796. }
  1797. }
  1798. else
  1799. {
  1800. kdDebug(36001) << "Error in Series::mode" << endl;
  1801. return;
  1802. }
  1803. if (type == Linear)
  1804. incr = incr + step;
  1805. else if (type == Geometric)
  1806. incr = incr * step;
  1807. else
  1808. {
  1809. kdDebug(36001) << "Error in Series::type" << endl;
  1810. return;
  1811. }
  1812. }
  1813. }
  1814. else
  1815. if (step >= 0 && start > end)
  1816. {
  1817. for ( incr = start; incr >= end; )
  1818. {
  1819. cell = nonDefaultCell( x, y, false, s );
  1820. if (cell->isPartOfMerged())
  1821. {
  1822. cell = cell->obscuringCells().first();
  1823. }
  1824. // cell->setCellText(cellText.setNum( incr ));
  1825. cell->setNumber( incr );
  1826. if (mode == Column)
  1827. {
  1828. ++y;
  1829. if (cell->doesMergeCells())
  1830. {
  1831. y += cell->extraYCells();
  1832. }
  1833. if ( y > KS_rowMax )
  1834. {
  1835. break;
  1836. }
  1837. }
  1838. else if (mode == Row)
  1839. {
  1840. ++x;
  1841. if (cell->doesMergeCells())
  1842. {
  1843. x += cell->extraXCells();
  1844. }
  1845. if ( x > KS_colMax )
  1846. {
  1847. break;
  1848. }
  1849. }
  1850. else
  1851. {
  1852. kdDebug(36001) << "Error in Series::mode" << endl;
  1853. return;
  1854. }
  1855. if (type == Linear)
  1856. incr = incr + step;
  1857. else if (type == Geometric)
  1858. incr = incr * step;
  1859. else
  1860. {
  1861. kdDebug(36001) << "Error in Series::type" << endl;
  1862. return;
  1863. }
  1864. }
  1865. }
  1866. else
  1867. {
  1868. for ( incr = start; incr <= end; )
  1869. {
  1870. cell = nonDefaultCell( x, y, false, s );
  1871. if (cell->isPartOfMerged())
  1872. {
  1873. cell = cell->obscuringCells().first();
  1874. }
  1875. //cell->setCellText(cellText.setNum( incr ));
  1876. cell->setNumber( incr );
  1877. if (mode == Column)
  1878. {
  1879. ++y;
  1880. if (cell->doesMergeCells())
  1881. {
  1882. y += cell->extraYCells();
  1883. }
  1884. if ( y > KS_rowMax )
  1885. {
  1886. break;
  1887. }
  1888. }
  1889. else if (mode == Row)
  1890. {
  1891. ++x;
  1892. if (cell->doesMergeCells())
  1893. {
  1894. x += cell->extraXCells();
  1895. }
  1896. if ( x > KS_colMax )
  1897. {
  1898. break;
  1899. }
  1900. }
  1901. else
  1902. {
  1903. kdDebug(36001) << "Error in Series::mode" << endl;
  1904. return;
  1905. }
  1906. if (type == Linear)
  1907. incr = incr + step;
  1908. else if (type == Geometric)
  1909. {
  1910. incr = incr * step;
  1911. //a step = 1 into geometric serie is not good
  1912. //we don't increase value => infini loop
  1913. if (step == 1)
  1914. return;
  1915. }
  1916. else
  1917. {
  1918. kdDebug(36001) << "Error in Series::type" << endl;
  1919. return;
  1920. }
  1921. }
  1922. }
  1923. // doc()->emitEndOperation();
  1924. emit sig_updateView( this );
  1925. }
  1926. struct SetSelectionPercentWorker : public Sheet::CellWorkerTypeA
  1927. {
  1928. bool b;
  1929. SetSelectionPercentWorker( bool _b ) : b( _b ) { }
  1930. TQString getUndoTitle() { return i18n("Format Percent"); }
  1931. bool testCondition( RowFormat* ) {
  1932. //TODO: no idea what to put here, now that factor's gone :(
  1933. return ( true );
  1934. }
  1935. void doWork( RowFormat* rw ) {
  1936. //rw->setPrecision( 0 );
  1937. rw->setFormatType( b ? Percentage_format : Generic_format);
  1938. }
  1939. void doWork( ColumnFormat* cl ) {
  1940. cl->setFormatType( b ? Percentage_format : Generic_format);
  1941. }
  1942. void prepareCell( Cell* cell ) {
  1943. cell->format()->clearProperty(Format::PFormatType);
  1944. cell->format()->clearNoFallBackProperties( Format::PFormatType );
  1945. }
  1946. bool testCondition( Cell* cell ) {
  1947. return ( !cell->isPartOfMerged() );
  1948. }
  1949. void doWork( Cell* cell, bool cellRegion, int, int ) {
  1950. if ( cellRegion )
  1951. cell->setDisplayDirtyFlag();
  1952. cell->format()->setFormatType( b ? Percentage_format : Generic_format);
  1953. if ( cellRegion )
  1954. cell->clearDisplayDirtyFlag();
  1955. }
  1956. };
  1957. void Sheet::setSelectionPercent( Selection* selectionInfo, bool b )
  1958. {
  1959. SetSelectionPercentWorker w( b );
  1960. workOnCells( selectionInfo, w );
  1961. }
  1962. void Sheet::slotAreaModified (const TQString &name)
  1963. {
  1964. d->dependencies->areaModified (name);
  1965. }
  1966. void Sheet::refreshRemoveAreaName(const TQString & _areaName)
  1967. {
  1968. Cell * c = d->cells.firstCell();
  1969. TQString tmp = "'" + _areaName + "'";
  1970. for( ;c ; c = c->nextCell() )
  1971. {
  1972. if ( c->isFormula() )
  1973. {
  1974. if (c->text().find(tmp) != -1)
  1975. {
  1976. if ( !c->makeFormula() )
  1977. kdError(36001) << "ERROR: Syntax ERROR" << endl;
  1978. }
  1979. }
  1980. }
  1981. }
  1982. void Sheet::refreshChangeAreaName(const TQString & _areaName)
  1983. {
  1984. Cell * c = d->cells.firstCell();
  1985. TQString tmp = "'" + _areaName + "'";
  1986. for( ;c ; c = c->nextCell() )
  1987. {
  1988. if ( c->isFormula() )
  1989. {
  1990. if (c->text().find(tmp) != -1)
  1991. {
  1992. if ( !c->makeFormula() )
  1993. kdError(36001) << "ERROR: Syntax ERROR" << endl;
  1994. else
  1995. {
  1996. /* setting a cell calc dirty also sets it paint dirty */
  1997. c->setCalcDirtyFlag();
  1998. }
  1999. }
  2000. }
  2001. }
  2002. }
  2003. void Sheet::changeCellTabName( TQString const & old_name, TQString const & new_name )
  2004. {
  2005. Cell* c = d->cells.firstCell();
  2006. for( ;c; c = c->nextCell() )
  2007. {
  2008. if( c->isFormula() )
  2009. {
  2010. if(c->text().find(old_name)!=-1)
  2011. {
  2012. int nb = c->text().contains(old_name+"!");
  2013. TQString tmp=old_name+"!";
  2014. int len = tmp.length();
  2015. tmp=c->text();
  2016. for( int i=0; i<nb; i++ )
  2017. {
  2018. int pos = tmp.find( old_name+"!" );
  2019. tmp.replace( pos, len, new_name+"!" );
  2020. }
  2021. c->setCellText(tmp);
  2022. }
  2023. }
  2024. }
  2025. }
  2026. bool Sheet::shiftRow( const TQRect &rect,bool makeUndo )
  2027. {
  2028. UndoInsertCellRow * undo = 0;
  2029. if ( !doc()->undoLocked() &&makeUndo)
  2030. {
  2031. undo = new UndoInsertCellRow( doc(), this, rect );
  2032. doc()->addCommand( undo );
  2033. }
  2034. bool res=true;
  2035. bool result;
  2036. for( int i=rect.top(); i<=rect.bottom(); i++ )
  2037. {
  2038. for( int j=0; j<=(rect.right()-rect.left()); j++ )
  2039. {
  2040. result = d->cells.shiftRow( TQPoint(rect.left(),i) );
  2041. if( !result )
  2042. res=false;
  2043. }
  2044. }
  2045. TQPtrListIterator<Sheet> it( workbook()->sheetList() );
  2046. for( ; it.current(); ++it )
  2047. {
  2048. for(int i = rect.top(); i <= rect.bottom(); i++ )
  2049. it.current()->changeNameCellRef( TQPoint( rect.left(), i ), false,
  2050. Sheet::ColumnInsert, name(),
  2051. ( rect.right() - rect.left() + 1),
  2052. undo);
  2053. }
  2054. refreshChart(TQPoint(rect.left(),rect.top()), false, Sheet::ColumnInsert);
  2055. refreshMergedCell();
  2056. recalc();
  2057. emit sig_updateView( this );
  2058. return res;
  2059. }
  2060. bool Sheet::shiftColumn( const TQRect& rect,bool makeUndo )
  2061. {
  2062. UndoInsertCellCol * undo = 0;
  2063. if ( !doc()->undoLocked() &&makeUndo)
  2064. {
  2065. undo = new UndoInsertCellCol( doc(), this,rect);
  2066. doc()->addCommand( undo );
  2067. }
  2068. bool res=true;
  2069. bool result;
  2070. for( int i =rect.left(); i<=rect.right(); i++ )
  2071. {
  2072. for( int j=0; j<=(rect.bottom()-rect.top()); j++ )
  2073. {
  2074. result = d->cells.shiftColumn( TQPoint(i,rect.top()) );
  2075. if(!result)
  2076. res=false;
  2077. }
  2078. }
  2079. TQPtrListIterator<Sheet> it( workbook()->sheetList() );
  2080. for( ; it.current(); ++it )
  2081. {
  2082. for(int i=rect.left();i<=rect.right();i++)
  2083. it.current()->changeNameCellRef( TQPoint( i, rect.top() ), false,
  2084. Sheet::RowInsert, name(),
  2085. ( rect.bottom() - rect.top() + 1 ),
  2086. undo );
  2087. }
  2088. refreshChart(/*marker*/TQPoint(rect.left(),rect.top()), false, Sheet::RowInsert);
  2089. refreshMergedCell();
  2090. recalc();
  2091. emit sig_updateView( this );
  2092. return res;
  2093. }
  2094. void Sheet::unshiftColumn( const TQRect & rect,bool makeUndo )
  2095. {
  2096. UndoRemoveCellCol * undo = 0;
  2097. if ( !doc()->undoLocked() && makeUndo )
  2098. {
  2099. undo = new UndoRemoveCellCol( doc(), this, rect );
  2100. doc()->addCommand( undo );
  2101. }
  2102. for(int i =rect.top();i<=rect.bottom();i++)
  2103. for(int j=rect.left();j<=rect.right();j++)
  2104. d->cells.remove(j,i);
  2105. for(int i =rect.left();i<=rect.right();i++)
  2106. for(int j=0;j<=(rect.bottom()-rect.top());j++)
  2107. d->cells.unshiftColumn( TQPoint(i,rect.top()) );
  2108. TQPtrListIterator<Sheet> it( workbook()->sheetList() );
  2109. for( ; it.current(); ++it )
  2110. for(int i=rect.left();i<=rect.right();i++)
  2111. it.current()->changeNameCellRef( TQPoint( i, rect.top() ), false,
  2112. Sheet::RowRemove, name(),
  2113. ( rect.bottom() - rect.top() + 1 ),
  2114. undo );
  2115. refreshChart( TQPoint(rect.left(),rect.top()), false, Sheet::RowRemove );
  2116. refreshMergedCell();
  2117. recalc();
  2118. emit sig_updateView( this );
  2119. }
  2120. void Sheet::unshiftRow( const TQRect & rect,bool makeUndo )
  2121. {
  2122. UndoRemoveCellRow * undo = 0;
  2123. if ( !doc()->undoLocked() && makeUndo )
  2124. {
  2125. undo = new UndoRemoveCellRow( doc(), this, rect );
  2126. doc()->addCommand( undo );
  2127. }
  2128. for(int i =rect.top();i<=rect.bottom();i++)
  2129. for(int j=rect.left();j<=rect.right();j++)
  2130. d->cells.remove(j,i);
  2131. for(int i =rect.top();i<=rect.bottom();i++)
  2132. for(int j=0;j<=(rect.right()-rect.left());j++)
  2133. d->cells.unshiftRow( TQPoint(rect.left(),i) );
  2134. TQPtrListIterator<Sheet> it( workbook()->sheetList() );
  2135. for( ; it.current(); ++it )
  2136. for(int i=rect.top();i<=rect.bottom();i++)
  2137. it.current()->changeNameCellRef( TQPoint( rect.left(), i ), false,
  2138. Sheet::ColumnRemove, name(),
  2139. ( rect.right() - rect.left() + 1 ),
  2140. undo);
  2141. refreshChart(TQPoint(rect.left(),rect.top()), false, Sheet::ColumnRemove );
  2142. refreshMergedCell();
  2143. recalc();
  2144. emit sig_updateView( this );
  2145. }
  2146. bool Sheet::insertColumn( int col, int nbCol, bool makeUndo )
  2147. {
  2148. UndoInsertColumn * undo = 0;
  2149. if ( !doc()->undoLocked() && makeUndo)
  2150. {
  2151. undo = new UndoInsertColumn( doc(), this, col, nbCol );
  2152. doc()->addCommand( undo );
  2153. }
  2154. bool res=true;
  2155. bool result;
  2156. for( int i=0; i<=nbCol; i++ )
  2157. {
  2158. // Recalculate range max (minus size of last column)
  2159. d->sizeMaxX -= columnFormat( KS_colMax )->dblWidth();
  2160. result = d->cells.insertColumn( col );
  2161. d->columns.insertColumn( col );
  2162. if(!result)
  2163. res = false;
  2164. //Recalculate range max (plus size of new column)
  2165. d->sizeMaxX += columnFormat( col+i )->dblWidth();
  2166. }
  2167. TQPtrListIterator<Sheet> it( workbook()->sheetList() );
  2168. for( ; it.current(); ++it )
  2169. it.current()->changeNameCellRef( TQPoint( col, 1 ), true,
  2170. Sheet::ColumnInsert, name(),
  2171. nbCol + 1, undo );
  2172. //update print settings
  2173. d->print->insertColumn( col, nbCol );
  2174. refreshChart( TQPoint( col, 1 ), true, Sheet::ColumnInsert );
  2175. refreshMergedCell();
  2176. recalc();
  2177. emit sig_updateHBorder( this );
  2178. emit sig_updateView( this );
  2179. return res;
  2180. }
  2181. bool Sheet::insertRow( int row, int nbRow, bool makeUndo )
  2182. {
  2183. UndoInsertRow *undo = 0;
  2184. if ( !doc()->undoLocked() && makeUndo)
  2185. {
  2186. undo = new UndoInsertRow( doc(), this, row, nbRow );
  2187. doc()->addCommand( undo );
  2188. }
  2189. bool res=true;
  2190. bool result;
  2191. for( int i=0; i<=nbRow; i++ )
  2192. {
  2193. // Recalculate range max (minus size of last row)
  2194. d->sizeMaxY -= rowFormat( KS_rowMax )->dblHeight();
  2195. result = d->cells.insertRow( row );
  2196. d->rows.insertRow( row );
  2197. if( !result )
  2198. res = false;
  2199. //Recalculate range max (plus size of new row)
  2200. d->sizeMaxY += rowFormat( row )->dblHeight();
  2201. }
  2202. TQPtrListIterator<Sheet> it( workbook()->sheetList() );
  2203. for( ; it.current(); ++it )
  2204. it.current()->changeNameCellRef( TQPoint( 1, row ), true,
  2205. Sheet::RowInsert, name(),
  2206. nbRow + 1, undo );
  2207. //update print settings
  2208. d->print->insertRow( row, nbRow );
  2209. refreshChart( TQPoint( 1, row ), true, Sheet::RowInsert );
  2210. refreshMergedCell();
  2211. recalc();
  2212. emit sig_updateVBorder( this );
  2213. emit sig_updateView( this );
  2214. return res;
  2215. }
  2216. void Sheet::removeColumn( int col, int nbCol, bool makeUndo )
  2217. {
  2218. UndoRemoveColumn *undo = 0;
  2219. if ( !doc()->undoLocked() && makeUndo)
  2220. {
  2221. undo = new UndoRemoveColumn( doc(), this, col, nbCol );
  2222. doc()->addCommand( undo );
  2223. }
  2224. for ( int i = 0; i <= nbCol; ++i )
  2225. {
  2226. // Recalculate range max (minus size of removed column)
  2227. d->sizeMaxX -= columnFormat( col )->dblWidth();
  2228. d->cells.removeColumn( col );
  2229. d->columns.removeColumn( col );
  2230. //Recalculate range max (plus size of new column)
  2231. d->sizeMaxX += columnFormat( KS_colMax )->dblWidth();
  2232. }
  2233. TQPtrListIterator<Sheet> it( workbook()->sheetList() );
  2234. for( ; it.current(); ++it )
  2235. it.current()->changeNameCellRef( TQPoint( col, 1 ), true,
  2236. Sheet::ColumnRemove, name(),
  2237. nbCol + 1, undo );
  2238. //update print settings
  2239. d->print->removeColumn( col, nbCol );
  2240. refreshChart( TQPoint( col, 1 ), true, Sheet::ColumnRemove );
  2241. refreshMergedCell();
  2242. recalc();
  2243. emit sig_updateHBorder( this );
  2244. emit sig_updateView( this );
  2245. }
  2246. void Sheet::removeRow( int row, int nbRow, bool makeUndo )
  2247. {
  2248. UndoRemoveRow *undo = 0;
  2249. if ( !doc()->undoLocked() && makeUndo )
  2250. {
  2251. undo = new UndoRemoveRow( doc(), this, row, nbRow );
  2252. doc()->addCommand( undo );
  2253. }
  2254. for( int i=0; i<=nbRow; i++ )
  2255. {
  2256. // Recalculate range max (minus size of removed row)
  2257. d->sizeMaxY -= rowFormat( row )->dblHeight();
  2258. d->cells.removeRow( row );
  2259. d->rows.removeRow( row );
  2260. //Recalculate range max (plus size of new row)
  2261. d->sizeMaxY += rowFormat( KS_rowMax )->dblHeight();
  2262. }
  2263. TQPtrListIterator<Sheet> it( workbook()->sheetList() );
  2264. for( ; it.current(); ++it )
  2265. it.current()->changeNameCellRef( TQPoint( 1, row ), true,
  2266. Sheet::RowRemove, name(),
  2267. nbRow + 1, undo );
  2268. //update print settings
  2269. d->print->removeRow( row, nbRow );
  2270. refreshChart( TQPoint( 1, row ), true, Sheet::RowRemove );
  2271. refreshMergedCell();
  2272. recalc();
  2273. emit sig_updateVBorder( this );
  2274. emit sig_updateView( this );
  2275. }
  2276. void Sheet::hideRow(const Region& region)
  2277. {
  2278. HideShowManipulator* manipulator = new HideShowManipulator();
  2279. manipulator->setSheet(this);
  2280. manipulator->setManipulateRows(true);
  2281. manipulator->add(region);
  2282. manipulator->execute();
  2283. }
  2284. void Sheet::emitHideRow()
  2285. {
  2286. emit sig_updateVBorder( this );
  2287. emit sig_updateView( this );
  2288. }
  2289. void Sheet::showRow(const Region& region)
  2290. {
  2291. HideShowManipulator* manipulator = new HideShowManipulator();
  2292. manipulator->setSheet(this);
  2293. manipulator->setManipulateRows(true);
  2294. manipulator->setReverse(true);
  2295. manipulator->add(region);
  2296. manipulator->execute();
  2297. }
  2298. void Sheet::hideColumn(const Region& region)
  2299. {
  2300. HideShowManipulator* manipulator = new HideShowManipulator();
  2301. manipulator->setSheet(this);
  2302. manipulator->setManipulateColumns(true);
  2303. manipulator->add(region);
  2304. manipulator->execute();
  2305. }
  2306. void Sheet::emitHideColumn()
  2307. {
  2308. emit sig_updateHBorder( this );
  2309. emit sig_updateView( this );
  2310. }
  2311. void Sheet::showColumn(const Region& region)
  2312. {
  2313. HideShowManipulator* manipulator = new HideShowManipulator();
  2314. manipulator->setSheet(this);
  2315. manipulator->setManipulateColumns(true);
  2316. manipulator->setReverse(true);
  2317. manipulator->add(region);
  2318. manipulator->execute();
  2319. }
  2320. void Sheet::refreshChart(const TQPoint & pos, bool fullRowOrColumn, ChangeRef ref)
  2321. {
  2322. Cell * c = d->cells.firstCell();
  2323. for( ;c; c = c->nextCell() )
  2324. {
  2325. if ( (ref == ColumnInsert || ref == ColumnRemove) && fullRowOrColumn
  2326. && c->column() >= (pos.x() - 1))
  2327. {
  2328. if (c->updateChart())
  2329. return;
  2330. }
  2331. else if ( (ref == ColumnInsert || ref == ColumnRemove )&& !fullRowOrColumn
  2332. && c->column() >= (pos.x() - 1) && c->row() == pos.y() )
  2333. {
  2334. if (c->updateChart())
  2335. return;
  2336. }
  2337. else if ((ref == RowInsert || ref == RowRemove) && fullRowOrColumn
  2338. && c->row() >= (pos.y() - 1))
  2339. {
  2340. if (c->updateChart())
  2341. return;
  2342. }
  2343. else if ( (ref == RowInsert || ref == RowRemove) && !fullRowOrColumn
  2344. && c->column() == pos.x() && c->row() >= (pos.y() - 1) )
  2345. {
  2346. if (c->updateChart())
  2347. return;
  2348. }
  2349. }
  2350. //refresh chart when there is a chart and you remove
  2351. //all cells
  2352. if (c == 0L)
  2353. {
  2354. CellBinding * bind;
  2355. for ( bind = firstCellBinding(); bind != 0L; bind = nextCellBinding() )
  2356. {
  2357. bind->cellChanged( 0 );
  2358. }
  2359. // CellBinding * bind = firstCellBinding();
  2360. // if ( bind != 0L )
  2361. // bind->cellChanged( 0 );
  2362. }
  2363. }
  2364. void Sheet::refreshMergedCell()
  2365. {
  2366. Cell* c = d->cells.firstCell();
  2367. for( ;c; c = c->nextCell() )
  2368. {
  2369. if(c->doesMergeCells())
  2370. c->mergeCells( c->column(), c->row(), c->extraXCells(), c->extraYCells() );
  2371. }
  2372. }
  2373. void Sheet::changeNameCellRef( const TQPoint & pos, bool fullRowOrColumn,
  2374. ChangeRef ref, TQString tabname, int nbCol,
  2375. UndoInsertRemoveAction * undo )
  2376. {
  2377. bool correctDefaultSheetName = (tabname == name()); // for cells without sheet ref (eg "A1")
  2378. Cell* c = d->cells.firstCell();
  2379. for( ;c; c = c->nextCell() )
  2380. {
  2381. if( c->isFormula() )
  2382. {
  2383. TQString origText = c->text();
  2384. unsigned int i = 0;
  2385. bool error = false;
  2386. TQString newText;
  2387. bool correctSheetName = correctDefaultSheetName;
  2388. //bool previousCorrectSheetName = false;
  2389. TQChar origCh;
  2390. for ( ; i < origText.length(); ++i )
  2391. {
  2392. origCh = origText[i];
  2393. if ( origCh != ':' && origCh != '$' && !origCh.isLetter() )
  2394. {
  2395. newText += origCh;
  2396. // Reset the "correct table indicator"
  2397. correctSheetName = correctDefaultSheetName;
  2398. }
  2399. else // Letter or dollar : maybe start of cell name/range
  2400. // (or even ':', like in a range - note that correctSheet is kept in this case)
  2401. {
  2402. // Collect everything that forms a name (cell name or sheet name)
  2403. TQString str;
  2404. bool sheetNameFound = false; //Sheet names need spaces
  2405. for( ; ( i < origText.length() ) && // until the end
  2406. ( ( origText[i].isLetter() || origText[i].isDigit() || origText[i] == '$' ) || // all text and numbers are welcome
  2407. ( sheetNameFound && origText[i].isSpace() ) ) //in case of a sheet name, we include spaces too
  2408. ; ++i )
  2409. {
  2410. str += origText[i];
  2411. if ( origText[i] == '!' )
  2412. sheetNameFound = true;
  2413. }
  2414. // Was it a sheet name ?
  2415. if ( origText[i] == '!' )
  2416. {
  2417. newText += str + '!'; // Copy it (and the '!')
  2418. // Look for the sheet name right before that '!'
  2419. correctSheetName = ( newText.right( tabname.length()+1 ) == tabname+"!" );
  2420. }
  2421. else // It must be a cell identifier
  2422. {
  2423. // Parse it
  2424. Point point( str );
  2425. if ( point.isValid() )
  2426. {
  2427. int col = point.pos().x();
  2428. int row = point.pos().y();
  2429. TQString newPoint;
  2430. // Update column
  2431. if ( point.columnFixed() )
  2432. newPoint = '$';
  2433. if( ref == ColumnInsert
  2434. && correctSheetName
  2435. && col + nbCol <= KS_colMax
  2436. && col >= pos.x() // Column after the new one : +1
  2437. && ( fullRowOrColumn || row == pos.y() ) ) // All rows or just one
  2438. {
  2439. newPoint += Cell::columnName( col + nbCol );
  2440. }
  2441. else if( ref == ColumnRemove
  2442. && correctSheetName
  2443. && col > pos.x() // Column after the deleted one : -1
  2444. && ( fullRowOrColumn || row == pos.y() ) ) // All rows or just one
  2445. {
  2446. newPoint += Cell::columnName( col - nbCol );
  2447. }
  2448. else
  2449. newPoint += Cell::columnName( col );
  2450. // Update row
  2451. if ( point.rowFixed() )
  2452. newPoint += '$';
  2453. if( ref == RowInsert
  2454. && correctSheetName
  2455. && row + nbCol <= KS_rowMax
  2456. && row >= pos.y() // Row after the new one : +1
  2457. && ( fullRowOrColumn || col == pos.x() ) ) // All columns or just one
  2458. {
  2459. newPoint += TQString::number( row + nbCol );
  2460. }
  2461. else if( ref == RowRemove
  2462. && correctSheetName
  2463. && row > pos.y() // Row after the deleted one : -1
  2464. && ( fullRowOrColumn || col == pos.x() ) ) // All columns or just one
  2465. {
  2466. newPoint += TQString::number( row - nbCol );
  2467. }
  2468. else
  2469. newPoint += TQString::number( row );
  2470. if( correctSheetName &&
  2471. ( ( ref == ColumnRemove
  2472. && col == pos.x() // Column is the deleted one : error
  2473. && ( fullRowOrColumn || row == pos.y() ) ) ||
  2474. ( ref == RowRemove
  2475. && row == pos.y() // Row is the deleted one : error
  2476. && ( fullRowOrColumn || col == pos.x() ) ) ||
  2477. ( ref == ColumnInsert
  2478. && col + nbCol > KS_colMax
  2479. && col >= pos.x() // Column after the new one : +1
  2480. && ( fullRowOrColumn || row == pos.y() ) ) ||
  2481. ( ref == RowInsert
  2482. && row + nbCol > KS_rowMax
  2483. && row >= pos.y() // Row after the new one : +1
  2484. && ( fullRowOrColumn || col == pos.x() ) ) ) )
  2485. {
  2486. newPoint = "#" + i18n("Dependency") + "!";
  2487. error = true;
  2488. }
  2489. newText += newPoint;
  2490. }
  2491. else // Not a cell ref
  2492. {
  2493. kdDebug(36001) << "Copying (unchanged) : '" << str << "'" << endl;
  2494. newText += str;
  2495. }
  2496. // Copy the char that got us to stop
  2497. if ( i < origText.length() ) {
  2498. newText += origText[i];
  2499. if( origText[i] != ':' )
  2500. correctSheetName = correctDefaultSheetName;
  2501. }
  2502. }
  2503. }
  2504. }
  2505. if ( error && undo != 0 ) //Save the original formula, as we cannot calculate the undo of broken formulas
  2506. {
  2507. TQString formulaText = c->text();
  2508. int origCol = c->column();
  2509. int origRow = c->row();
  2510. if ( ref == ColumnInsert && origCol >= pos.x() )
  2511. origCol -= nbCol;
  2512. if ( ref == RowInsert && origRow >= pos.y() )
  2513. origRow -= nbCol;
  2514. if ( ref == ColumnRemove && origCol >= pos.x() )
  2515. origCol += nbCol;
  2516. if ( ref == RowRemove && origRow >= pos.y() )
  2517. origRow += nbCol;
  2518. undo->saveFormulaReference( this, origCol, origRow, formulaText );
  2519. }
  2520. c->setCellText( newText );
  2521. }
  2522. }
  2523. }
  2524. #if 0
  2525. void Sheet::replace( const TQString &_find, const TQString &_replace, long options,
  2526. Canvas *canvas )
  2527. {
  2528. Selection* selectionInfo = canvas->view()->selectionInfo();
  2529. // Identify the region of interest.
  2530. TQRect region( selectionInfo->selection() );
  2531. TQPoint marker( selectionInfo->marker() );
  2532. if (options & KReplaceDialog::SelectedText)
  2533. {
  2534. // Complete rows selected ?
  2535. if ( util_isRowSelected(region) )
  2536. {
  2537. }
  2538. // Complete columns selected ?
  2539. else if ( util_isColumnSelected(region) )
  2540. {
  2541. }
  2542. }
  2543. else
  2544. {
  2545. // All cells.
  2546. region.setCoords( 1, 1, d->maxRow, d->maxColumn );
  2547. }
  2548. // Create the class that handles all the actual replace stuff, and connect it to its
  2549. // local slots.
  2550. KReplace dialog( _find, _replace, options );
  2551. TQObject::connect(
  2552. &dialog, TQT_SIGNAL( highlight( const TQString &, int, int, const TQRect & ) ),
  2553. canvas, TQT_SLOT( highlight( const TQString &, int, int, const TQRect & ) ) );
  2554. TQObject::connect(
  2555. &dialog, TQT_SIGNAL( replace( const TQString &, int, int,int, const TQRect & ) ),
  2556. canvas, TQT_SLOT( replace( const TQString &, int, int,int, const TQRect & ) ) );
  2557. // Now do the replacing...
  2558. if ( !doc()->undoLocked() )
  2559. {
  2560. UndoChangeAreaTextCell *undo = new UndoChangeAreaTextCell( doc(), this, region );
  2561. doc()->addCommand( undo );
  2562. }
  2563. TQRect cellRegion( 0, 0, 0, 0 );
  2564. bool bck = options & KFindDialog::FindBackwards;
  2565. int colStart = !bck ? region.left() : region.right();
  2566. int colEnd = !bck ? region.right() : region.left();
  2567. int rowStart = !bck ? region.top() :region.bottom();
  2568. int rowEnd = !bck ? region.bottom() : region.top();
  2569. if ( options & KFindDialog::FromCursor ) {
  2570. colStart = marker.x();
  2571. rowStart = marker.y();
  2572. }
  2573. Cell *cell;
  2574. for (int row = rowStart ; !bck ? row < rowEnd : row > rowEnd ; !bck ? ++row : --row )
  2575. {
  2576. for(int col = colStart ; !bck ? col < colEnd : col > colEnd ; !bck ? ++col : --col )
  2577. {
  2578. cell = cellAt( col, row );
  2579. if ( !cell->isDefault() && !cell->isObscured() && !cell->isFormula() )
  2580. {
  2581. TQString text = cell->text();
  2582. cellRegion.setTop( row );
  2583. cellRegion.setLeft( col );
  2584. if (!dialog.replace( text, cellRegion ))
  2585. return;
  2586. }
  2587. }
  2588. }
  2589. }
  2590. #endif
  2591. void Sheet::borderBottom( Selection* selectionInfo, const TQColor &_color )
  2592. {
  2593. BorderManipulator* manipulator = new BorderManipulator();
  2594. manipulator->setSheet(this);
  2595. manipulator->setBottomBorderPen(TQPen(_color, 1, TQt::SolidLine));
  2596. manipulator->add(*selectionInfo);
  2597. manipulator->execute();
  2598. }
  2599. void Sheet::borderRight( Selection* selectionInfo, const TQColor &_color )
  2600. {
  2601. BorderManipulator* manipulator = new BorderManipulator();
  2602. manipulator->setSheet(this);
  2603. manipulator->setRightBorderPen(TQPen(_color, 1, TQt::SolidLine));
  2604. manipulator->add(*selectionInfo);
  2605. manipulator->execute();
  2606. }
  2607. void Sheet::borderLeft( Selection* selectionInfo, const TQColor &_color )
  2608. {
  2609. BorderManipulator* manipulator = new BorderManipulator();
  2610. manipulator->setSheet(this);
  2611. manipulator->setLeftBorderPen(TQPen(_color, 1, TQt::SolidLine));
  2612. manipulator->add(*selectionInfo);
  2613. manipulator->execute();
  2614. }
  2615. void Sheet::borderTop( Selection* selectionInfo, const TQColor &_color )
  2616. {
  2617. BorderManipulator* manipulator = new BorderManipulator();
  2618. manipulator->setSheet(this);
  2619. manipulator->setTopBorderPen(TQPen(_color, 1, TQt::SolidLine));
  2620. manipulator->add(*selectionInfo);
  2621. manipulator->execute();
  2622. }
  2623. void Sheet::borderOutline( Selection* selectionInfo, const TQColor &_color )
  2624. {
  2625. BorderManipulator* manipulator = new BorderManipulator();
  2626. manipulator->setSheet(this);
  2627. manipulator->setTopBorderPen(TQPen(_color, 1, TQt::SolidLine));
  2628. manipulator->setBottomBorderPen(TQPen(_color, 1, TQt::SolidLine));
  2629. manipulator->setLeftBorderPen(TQPen(_color, 1, TQt::SolidLine));
  2630. manipulator->setRightBorderPen(TQPen(_color, 1, TQt::SolidLine));
  2631. manipulator->add(*selectionInfo);
  2632. manipulator->execute();
  2633. }
  2634. void Sheet::borderAll( Selection * selectionInfo,
  2635. const TQColor & _color )
  2636. {
  2637. BorderManipulator* manipulator = new BorderManipulator();
  2638. manipulator->setSheet(this);
  2639. manipulator->setTopBorderPen(TQPen(_color, 1, TQt::SolidLine));
  2640. manipulator->setBottomBorderPen(TQPen(_color, 1, TQt::SolidLine));
  2641. manipulator->setLeftBorderPen(TQPen(_color, 1, TQt::SolidLine));
  2642. manipulator->setRightBorderPen(TQPen(_color, 1, TQt::SolidLine));
  2643. manipulator->setHorizontalPen(TQPen(_color, 1, TQt::SolidLine));
  2644. manipulator->setVerticalPen(TQPen(_color, 1, TQt::SolidLine));
  2645. manipulator->add(*selectionInfo);
  2646. manipulator->execute();
  2647. }
  2648. void Sheet::borderRemove( Selection* selectionInfo )
  2649. {
  2650. BorderManipulator* manipulator = new BorderManipulator();
  2651. manipulator->setSheet(this);
  2652. manipulator->setTopBorderPen(TQPen(TQt::NoPen));
  2653. manipulator->setBottomBorderPen(TQPen(TQt::NoPen));
  2654. manipulator->setLeftBorderPen(TQPen(TQt::NoPen));
  2655. manipulator->setRightBorderPen(TQPen(TQt::NoPen));
  2656. manipulator->setHorizontalPen(TQPen(TQt::NoPen));
  2657. manipulator->setVerticalPen(TQPen(TQt::NoPen));
  2658. manipulator->add(*selectionInfo);
  2659. manipulator->execute();
  2660. }
  2661. void Sheet::sortByRow( const TQRect &area, int ref_row, SortingOrder mode )
  2662. {
  2663. Point point;
  2664. point.setSheet(this);
  2665. point.setSheetName (d->name);
  2666. point.setPos(area.topLeft());
  2667. point.setColumnFixed(false);
  2668. point.setRowFixed(false);
  2669. sortByRow( area, ref_row, 0, 0, mode, mode, mode, 0, false, false, point,true );
  2670. }
  2671. void Sheet::sortByColumn( const TQRect &area, int ref_column, SortingOrder mode )
  2672. {
  2673. Point point;
  2674. point.setSheet(this);
  2675. point.setSheetName(d->name);
  2676. point.setPos(area.topLeft());
  2677. point.setColumnFixed(false);
  2678. point.setRowFixed(false);
  2679. sortByColumn( area, ref_column, 0, 0, mode, mode, mode, 0, false, false,
  2680. point,true );
  2681. }
  2682. void Sheet::checkCellContent(Cell * cell1, Cell * cell2, int & ret)
  2683. {
  2684. if ( cell1->isEmpty() )
  2685. {
  2686. ret = 1;
  2687. return;
  2688. }
  2689. else if ( cell1->isObscured() && cell1->isPartOfMerged() )
  2690. {
  2691. ret = 1;
  2692. return;
  2693. }
  2694. else if ( cell2->isEmpty() )
  2695. {
  2696. ret = 2;
  2697. return;
  2698. }
  2699. ret = 0;
  2700. }
  2701. void Sheet::sortByRow( const TQRect &area, int key1, int key2, int key3,
  2702. SortingOrder order1, SortingOrder order2,
  2703. SortingOrder order3,
  2704. TQStringList const * firstKey, bool copyFormat,
  2705. bool headerRow, Point const & outputPoint, bool respectCase )
  2706. {
  2707. TQRect r( area );
  2708. Map::respectCase = respectCase;
  2709. Q_ASSERT( order1 == Increase || order1 == Decrease );
  2710. // It may not happen that entire columns are selected.
  2711. Q_ASSERT( util_isColumnSelected(r) == false );
  2712. // Are entire rows selected ?
  2713. if ( util_isRowSelected(r) )
  2714. {
  2715. r.setLeft( KS_colMax );
  2716. r.setRight( 0 );
  2717. // Determine a correct left and right.
  2718. // Iterate over all cells to find out which cells are
  2719. // located in the selected rows.
  2720. for ( int row = r.top(); row <= r.bottom(); ++row )
  2721. {
  2722. Cell * c = getFirstCellRow( row );
  2723. int col;
  2724. while ( c )
  2725. {
  2726. col = c->column();
  2727. if ( !c->isEmpty() )
  2728. {
  2729. if ( col > r.right() )
  2730. r.rRight() = col;
  2731. if ( col < r.left() )
  2732. r.rLeft() = col;
  2733. }
  2734. c = getNextCellRight( col, row );
  2735. }
  2736. }
  2737. // Any cells to sort here ?
  2738. if ( r.right() < r.left() )
  2739. {
  2740. Map::respectCase = true;
  2741. return;
  2742. }
  2743. }
  2744. TQRect target( outputPoint.pos().x(), outputPoint.pos().y(), r.width(), r.height() );
  2745. doc()->emitBeginOperation();
  2746. if ( !doc()->undoLocked() )
  2747. {
  2748. UndoSort *undo = new UndoSort( doc(), this, target );
  2749. doc()->addCommand( undo );
  2750. }
  2751. if (target.topLeft() != r.topLeft())
  2752. {
  2753. int targetLeft = target.left();
  2754. int targetTop = target.top();
  2755. int sourceTop = r.top();
  2756. int sourceLeft = r.left();
  2757. key1 = key1 - sourceTop + targetTop;
  2758. key2 = key2 - sourceTop + targetTop;
  2759. key3 = key3 - sourceTop + targetTop;
  2760. for ( int x = 0; x < r.width(); ++x)
  2761. {
  2762. for ( int y = 0; y < r.height(); ++y )
  2763. {
  2764. // from - to
  2765. copyCells( sourceLeft + x, sourceTop + y,
  2766. targetLeft + x, targetTop + y, copyFormat );
  2767. }
  2768. }
  2769. }
  2770. // Sorting algorithm: David's :). Well, I guess it's called minmax or so.
  2771. // For each column, we look for all cells right hand of it and we find the one to swap with it.
  2772. // Much faster than the awful bubbleSort...
  2773. Cell * cell;
  2774. Cell * cell1;
  2775. Cell * cell2;
  2776. Cell * bestCell;
  2777. int status = 0;
  2778. for ( int d = target.left(); d <= target.right(); ++d )
  2779. {
  2780. cell1 = cellAt( d, key1 );
  2781. if ( cell1->isObscured() && cell1->isPartOfMerged() )
  2782. {
  2783. Cell* obscuring = cell1->obscuringCells().first();
  2784. cell = cellAt( obscuring->column(), key1 );
  2785. cell1 = cellAt( obscuring->column() + cell->extraXCells() + 1,
  2786. obscuring->column());
  2787. d = obscuring->column() + cell->extraXCells() + 1;
  2788. }
  2789. // Look for which column we want to swap with the one number d
  2790. bestCell = cell1;
  2791. int bestX = d;
  2792. for ( int x = d + 1 ; x <= target.right(); x++ )
  2793. {
  2794. cell2 = cellAt( x, key1 );
  2795. checkCellContent(cell2, bestCell, status);
  2796. if (status == 1)
  2797. continue;
  2798. else if (status == 2)
  2799. {
  2800. // empty cells are always shifted to the end
  2801. bestCell = cell2;
  2802. bestX = x;
  2803. continue;
  2804. }
  2805. if ( firstKey )
  2806. {
  2807. int i1 = firstKey->findIndex( cell2->text() );
  2808. int i2 = firstKey->findIndex( bestCell->text() );
  2809. if ( i1 != -1 && i2 != -1 )
  2810. {
  2811. if ( (order1 == Increase && i1 < i2 )
  2812. || (order1 == Decrease && i1 > i2) )
  2813. {
  2814. bestCell = cell2;
  2815. bestX = x;
  2816. continue;
  2817. }
  2818. if ( i1 == i2 )
  2819. {
  2820. // check 2nd key
  2821. if (key2 <= 0)
  2822. continue;
  2823. Cell * cell22 = cellAt( x, key2 );
  2824. Cell * bestCell2 = cellAt( bestX, key2 );
  2825. if ( cell22->isEmpty() )
  2826. {
  2827. /* No need to swap */
  2828. continue;
  2829. }
  2830. else if ( cell22->isObscured() && cell22->isPartOfMerged() )
  2831. {
  2832. /* No need to swap */
  2833. continue;
  2834. }
  2835. else if ( bestCell2->isEmpty() )
  2836. {
  2837. // empty cells are always shifted to the end
  2838. bestCell = cell2;
  2839. bestX = x;
  2840. continue;
  2841. }
  2842. if ( (order2 == Increase && *cell22 < *bestCell2)
  2843. || (order2 == Decrease && *cell22 > *bestCell2) )
  2844. {
  2845. bestCell = cell2;
  2846. bestX = x;
  2847. continue;
  2848. }
  2849. else if ( (order2 == Increase && *cell22 > *bestCell2)
  2850. || (order2 == Decrease && *cell22 < *bestCell2) )
  2851. {
  2852. // already in right order
  2853. continue;
  2854. }
  2855. else
  2856. {
  2857. // they are equal, check 3rd key
  2858. if (key3 <= 0)
  2859. continue;
  2860. Cell * cell23 = cellAt( x, key3 );
  2861. Cell * bestCell3 = cellAt( bestX, key3 );
  2862. if ( cell23->isEmpty() )
  2863. {
  2864. /* No need to swap */
  2865. continue;
  2866. }
  2867. else if ( cell23->isObscured() && cell23->isPartOfMerged() )
  2868. {
  2869. /* No need to swap */
  2870. continue;
  2871. }
  2872. else if ( bestCell3->isEmpty() )
  2873. {
  2874. // empty cells are always shifted to the end
  2875. bestCell = cell2;
  2876. bestX = x;
  2877. continue;
  2878. }
  2879. if ( (order3 == Increase && *cell23 < *bestCell3)
  2880. || (order3 == Decrease && *cell23 > *bestCell3) )
  2881. {
  2882. // they are really equal or in the right order
  2883. // no swap necessary
  2884. continue;
  2885. }
  2886. else
  2887. {
  2888. bestCell = cell2;
  2889. bestX = x;
  2890. continue;
  2891. }
  2892. }
  2893. }
  2894. continue;
  2895. }
  2896. else if ( i1 != -1 && i2 == -1 )
  2897. {
  2898. // if not in the key list, the cell is shifted to the end - always
  2899. bestCell = cell2;
  2900. bestX = x;
  2901. continue;
  2902. }
  2903. else if ( i2 != -1 && i1 == -1 )
  2904. {
  2905. // only text of cell2 is in the list so it is smaller than bestCell
  2906. /* No need to swap */
  2907. continue;
  2908. }
  2909. // if i1 and i2 are equals -1 go on:
  2910. } // end if (firstKey)
  2911. // Here we use the operators < and > for cells, which do it all.
  2912. if ( (order1 == Increase && *cell2 < *bestCell)
  2913. || (order1 == Decrease && *cell2 > *bestCell) )
  2914. {
  2915. bestCell = cell2;
  2916. bestX = x;
  2917. continue;
  2918. }
  2919. else if ( (order1 == Increase && *cell2 > *bestCell)
  2920. || (order1 == Decrease && *cell2 < *bestCell) )
  2921. {
  2922. // no change necessary
  2923. continue;
  2924. }
  2925. else
  2926. {
  2927. // *cell2 equals *bestCell
  2928. // check 2nd key
  2929. if (key2 <= 0)
  2930. continue;
  2931. Cell * cell22 = cellAt( d, key2 );
  2932. Cell * bestCell2 = cellAt( x, key2 );
  2933. checkCellContent(cell2, bestCell, status);
  2934. if (status == 1)
  2935. continue;
  2936. else if (status == 2)
  2937. {
  2938. // empty cells are always shifted to the end
  2939. bestCell = cell2;
  2940. bestX = x;
  2941. continue;
  2942. }
  2943. if ( (order2 == Increase && *cell22 > *bestCell2)
  2944. || (order2 == Decrease && *cell22 < *bestCell2) )
  2945. {
  2946. bestCell = cell2;
  2947. bestX = x;
  2948. continue;
  2949. }
  2950. else
  2951. if ( (order2 == Increase && *cell22 > *bestCell2)
  2952. || (order2 == Decrease && *cell22 < *bestCell2) )
  2953. {
  2954. // already in right order
  2955. continue;
  2956. }
  2957. else
  2958. {
  2959. // they are equal, check 3rd key
  2960. if (key3 == 0)
  2961. continue;
  2962. Cell * cell23 = cellAt( d, key3 );
  2963. Cell * bestCell3 = cellAt( x, key3 );
  2964. checkCellContent(cell2, bestCell, status);
  2965. if (status == 1)
  2966. continue;
  2967. else if (status == 2)
  2968. {
  2969. // empty cells are always shifted to the end
  2970. bestCell = cell2;
  2971. bestX = x;
  2972. continue;
  2973. }
  2974. if ( (order3 == Increase && *cell23 > *bestCell3)
  2975. || (order3 == Decrease && *cell23 < *bestCell3) )
  2976. {
  2977. bestCell = cell2;
  2978. bestX = x;
  2979. continue;
  2980. }
  2981. else
  2982. {
  2983. // they are really equal
  2984. // no swap necessary
  2985. continue;
  2986. }
  2987. }
  2988. }
  2989. }
  2990. // Swap columns cell1 and bestCell (i.e. d and bestX)
  2991. if ( d != bestX )
  2992. {
  2993. int top = target.top();
  2994. if (headerRow)
  2995. ++top;
  2996. for( int y = target.bottom(); y >= top; --y )
  2997. {
  2998. if ( y != key1 && y != key2 && y != key3 )
  2999. swapCells( d, y, bestX, y, copyFormat );
  3000. }
  3001. if (key3 > 0)
  3002. swapCells( d, key3, bestX, key3, copyFormat );
  3003. if (key2 > 0)
  3004. swapCells( d, key2, bestX, key2, copyFormat );
  3005. swapCells( d, key1, bestX, key1, copyFormat );
  3006. }
  3007. } // for (d = ...; ...; ++d)
  3008. Map::respectCase = true;
  3009. // doc()->emitEndOperation();
  3010. emit sig_updateView( this );
  3011. }
  3012. void Sheet::sortByColumn( const TQRect &area, int key1, int key2, int key3,
  3013. SortingOrder order1, SortingOrder order2,
  3014. SortingOrder order3,
  3015. TQStringList const * firstKey, bool copyFormat,
  3016. bool headerRow,
  3017. Point const & outputPoint, bool respectCase )
  3018. {
  3019. TQRect r( area );
  3020. Map::respectCase = respectCase;
  3021. Q_ASSERT( order1 == Increase || order1 == Decrease );
  3022. // It may not happen that entire rows are selected.
  3023. Q_ASSERT( util_isRowSelected(r) == false );
  3024. // Are entire columns selected ?
  3025. if ( util_isColumnSelected(r) )
  3026. {
  3027. r.setTop( KS_rowMax );
  3028. r.setBottom( 0 );
  3029. // Determine a correct top and bottom.
  3030. // Iterate over all cells to find out which cells are
  3031. // located in the selected columns.
  3032. for ( int col = r.left(); col <= r.right(); ++col )
  3033. {
  3034. Cell * c = getFirstCellColumn( col );
  3035. int row;
  3036. while ( c )
  3037. {
  3038. row = c->row();
  3039. if ( !c->isEmpty() )
  3040. {
  3041. if ( row > r.bottom() )
  3042. r.rBottom() = row;
  3043. if ( row < r.top() )
  3044. r.rTop() = row;
  3045. }
  3046. c = getNextCellDown( col, row );
  3047. }
  3048. }
  3049. // Any cells to sort here ?
  3050. if ( r.bottom() < r.top() )
  3051. {
  3052. Map::respectCase = true;
  3053. return;
  3054. }
  3055. }
  3056. TQRect target( outputPoint.pos().x(), outputPoint.pos().y(), r.width(), r.height() );
  3057. if ( !doc()->undoLocked() )
  3058. {
  3059. UndoSort *undo = new UndoSort( doc(), this, target );
  3060. doc()->addCommand( undo );
  3061. }
  3062. doc()->emitBeginOperation();
  3063. if (target.topLeft() != r.topLeft())
  3064. {
  3065. int targetLeft = target.left();
  3066. int targetTop = target.top();
  3067. int sourceTop = r.top();
  3068. int sourceLeft = r.left();
  3069. key1 = key1 - sourceLeft + targetLeft;
  3070. key2 = key2 - sourceLeft + targetLeft;
  3071. key3 = key3 - sourceLeft + targetLeft;
  3072. for ( int x = 0; x < r.width(); ++x)
  3073. {
  3074. for ( int y = 0; y < r.height(); ++y )
  3075. {
  3076. // from - to
  3077. copyCells( sourceLeft + x, sourceTop + y,
  3078. targetLeft + x, targetTop + y, copyFormat );
  3079. }
  3080. }
  3081. }
  3082. // Sorting algorithm: David's :). Well, I guess it's called minmax or so.
  3083. // For each row, we look for all rows under it and we find the one to swap with it.
  3084. // Much faster than the awful bubbleSort...
  3085. // Torben: Asymptotically it is alltogether O(n^2) :-)
  3086. Cell * cell;
  3087. Cell * cell1;
  3088. Cell * cell2;
  3089. Cell * bestCell;
  3090. int status = 0;
  3091. int d = target.top();
  3092. if (headerRow)
  3093. ++d;
  3094. for ( ; d <= target.bottom(); ++d )
  3095. {
  3096. // Look for which row we want to swap with the one number d
  3097. cell1 = cellAt( key1, d );
  3098. if ( cell1->isObscured() && cell1->isPartOfMerged() )
  3099. {
  3100. Cell* obscuring = cell1->obscuringCells().first();
  3101. cell = cellAt( key1, obscuring->row() );
  3102. cell1 = cellAt( key1, obscuring->row() + cell->extraYCells() + 1 );
  3103. d = obscuring->row() + cell->extraYCells() + 1;
  3104. }
  3105. bestCell = cell1;
  3106. int bestY = d;
  3107. for ( int y = d + 1 ; y <= target.bottom(); ++y )
  3108. {
  3109. cell2 = cellAt( key1, y );
  3110. if ( cell2->isEmpty() )
  3111. {
  3112. /* No need to swap */
  3113. continue;
  3114. }
  3115. else if ( cell2->isObscured() && cell2->isPartOfMerged() )
  3116. {
  3117. /* No need to swap */
  3118. continue;
  3119. }
  3120. else if ( bestCell->isEmpty() )
  3121. {
  3122. // empty cells are always shifted to the end
  3123. bestCell = cell2;
  3124. bestY = y;
  3125. continue;
  3126. }
  3127. if ( firstKey )
  3128. {
  3129. int i1 = firstKey->findIndex( cell2->text() );
  3130. int i2 = firstKey->findIndex( bestCell->text() );
  3131. if ( i1 != -1 && i2 != -1 )
  3132. {
  3133. if ( (order1 == Increase && i1 < i2 )
  3134. || (order1 == Decrease && i1 > i2) )
  3135. {
  3136. bestCell = cell2;
  3137. bestY = y;
  3138. continue;
  3139. }
  3140. if ( i1 == i2 )
  3141. {
  3142. // check 2nd key
  3143. if (key2 <= 0)
  3144. continue;
  3145. Cell * cell22 = cellAt( key2, d );
  3146. Cell * bestCell2 = cellAt( key2, y );
  3147. if ( cell22->isEmpty() )
  3148. {
  3149. /* No need to swap */
  3150. continue;
  3151. }
  3152. else if ( cell22->isObscured() && cell22->isPartOfMerged() )
  3153. {
  3154. /* No need to swap */
  3155. continue;
  3156. }
  3157. else if ( bestCell2->isEmpty() )
  3158. {
  3159. // empty cells are always shifted to the end
  3160. bestCell = cell2;
  3161. bestY = y;
  3162. continue;
  3163. }
  3164. if ( (order2 == Increase && *cell22 > *bestCell2)
  3165. || (order2 == Decrease && *cell22 < *bestCell2) )
  3166. {
  3167. bestCell = cell2;
  3168. bestY = y;
  3169. continue;
  3170. }
  3171. else if ( (order2 == Increase && *cell22 < *bestCell2)
  3172. || (order2 == Decrease && *cell22 > *bestCell2) )
  3173. {
  3174. // already in right order
  3175. continue;
  3176. }
  3177. else
  3178. {
  3179. // they are equal, check 3rd key
  3180. if (key3 <= 0)
  3181. continue;
  3182. Cell * cell23 = cellAt( key3, d );
  3183. Cell * bestCell3 = cellAt( key3, y );
  3184. checkCellContent(cell2, bestCell, status);
  3185. if (status == 1)
  3186. continue;
  3187. else if (status == 2)
  3188. {
  3189. // empty cells are always shifted to the end
  3190. bestCell = cell2;
  3191. bestY = y;
  3192. continue;
  3193. }
  3194. if ( (order3 == Increase && *cell23 < *bestCell3)
  3195. || (order3 == Decrease && *cell23 > *bestCell3) )
  3196. {
  3197. bestCell = cell2;
  3198. bestY = y;
  3199. continue;
  3200. }
  3201. else
  3202. {
  3203. // they are really equal or in the correct order
  3204. // no swap necessary
  3205. continue;
  3206. }
  3207. }
  3208. }
  3209. continue;
  3210. }
  3211. else if ( i1 != -1 && i2 == -1 )
  3212. {
  3213. // if not in the key list, the cell is shifted to the end - always
  3214. bestCell = cell2;
  3215. bestY = y;
  3216. continue;
  3217. }
  3218. else if ( i2 != -1 && i1 == -1 )
  3219. {
  3220. // only text of cell2 is in the list so it is smaller than bestCell
  3221. /* No need to swap */
  3222. continue;
  3223. }
  3224. // if i1 and i2 are equals -1 go on:
  3225. } // if (firstKey)
  3226. // Here we use the operators < and > for cells, which do it all.
  3227. if ( (order1 == Increase && *cell2 < *bestCell)
  3228. || (order1 == Decrease && *cell2 > *bestCell) )
  3229. {
  3230. bestCell = cell2;
  3231. bestY = y;
  3232. }
  3233. else if ( (order1 == Increase && *cell2 > *bestCell)
  3234. || (order1 == Decrease && *cell2 < *bestCell) )
  3235. {
  3236. // no change necessary
  3237. continue;
  3238. }
  3239. else
  3240. {
  3241. // *cell2 equals *bestCell
  3242. // check 2nd key
  3243. if (key2 == 0)
  3244. continue;
  3245. Cell * cell22 = cellAt( key2, y );
  3246. Cell * bestCell2 = cellAt( key2, bestY );
  3247. if ( cell22->isEmpty() )
  3248. {
  3249. /* No need to swap */
  3250. continue;
  3251. }
  3252. else if ( cell22->isObscured() && cell22->isPartOfMerged() )
  3253. {
  3254. /* No need to swap */
  3255. continue;
  3256. }
  3257. else if ( bestCell2->isEmpty() )
  3258. {
  3259. // empty cells are always shifted to the end
  3260. bestCell = cell2;
  3261. bestY = y;
  3262. continue;
  3263. }
  3264. if ( (order2 == Increase && *cell22 < *bestCell2)
  3265. || (order2 == Decrease && *cell22 > *bestCell2) )
  3266. {
  3267. bestCell = cell2;
  3268. bestY = y;
  3269. continue;
  3270. }
  3271. else if ( (order2 == Increase && *cell22 > *bestCell2)
  3272. || (order2 == Decrease && *cell22 < *bestCell2) )
  3273. {
  3274. continue;
  3275. }
  3276. else
  3277. {
  3278. // they are equal, check 3rd key
  3279. if (key3 == 0)
  3280. continue;
  3281. Cell * cell23 = cellAt( key3, y );
  3282. Cell * bestCell3 = cellAt( key3, bestY );
  3283. if ( cell23->isEmpty() )
  3284. {
  3285. /* No need to swap */
  3286. continue;
  3287. }
  3288. else if ( cell23->isObscured() && cell23->isPartOfMerged() )
  3289. {
  3290. /* No need to swap */
  3291. continue;
  3292. }
  3293. else if ( bestCell3->isEmpty() )
  3294. {
  3295. // empty cells are always shifted to the end
  3296. bestCell = cell2;
  3297. bestY = y;
  3298. continue;
  3299. }
  3300. if ( (order3 == Increase && *cell23 < *bestCell3)
  3301. || (order3 == Decrease && *cell23 > *bestCell3) )
  3302. {
  3303. bestCell = cell2;
  3304. bestY = y;
  3305. continue;
  3306. }
  3307. else
  3308. {
  3309. // they are really equal or already in the correct order
  3310. // no swap necessary
  3311. continue;
  3312. }
  3313. }
  3314. }
  3315. }
  3316. // Swap rows cell1 and bestCell (i.e. d and bestY)
  3317. if ( d != bestY )
  3318. {
  3319. for (int x = target.left(); x <= target.right(); ++x)
  3320. {
  3321. if ( x != key1 && x != key2 && x != key3)
  3322. swapCells( x, d, x, bestY, copyFormat );
  3323. }
  3324. if (key3 > 0)
  3325. swapCells( key3, d, key3, bestY, copyFormat );
  3326. if (key2 > 0)
  3327. swapCells( key2, d, key2, bestY, copyFormat );
  3328. swapCells( key1, d, key1, bestY, copyFormat );
  3329. }
  3330. } // for (d = ...; ...; ++d)
  3331. // doc()->emitEndOperation();
  3332. Map::respectCase = true;
  3333. emit sig_updateView( this );
  3334. }
  3335. // from - to - copyFormat
  3336. void Sheet::copyCells( int x1, int y1, int x2, int y2, bool cpFormat )
  3337. {
  3338. Cell * sourceCell = cellAt( x1, y1 );
  3339. Cell * targetCell = cellAt( x2, y2 );
  3340. if ( sourceCell->isDefault() && targetCell->isDefault())
  3341. {
  3342. // if the source and target is default there is nothing to copy
  3343. return;
  3344. }
  3345. targetCell = nonDefaultCell(x2, y2);
  3346. // TODO: check if this enough
  3347. targetCell->copyContent( sourceCell );
  3348. /*
  3349. if ( !sourceCell->isFormula() )
  3350. {
  3351. targetCell->copyContent( sourceCell );
  3352. }
  3353. else
  3354. {
  3355. targetCell->setCellText( targetCell->decodeFormula( sourceCell->encodeFormula() ) );
  3356. targetCell->setCalcDirtyFlag();
  3357. targetCell->calc(false);
  3358. }
  3359. */
  3360. if (cpFormat)
  3361. {
  3362. targetCell->copyFormat( sourceCell );
  3363. /*
  3364. targetCell->setAlign( sourceCell->format()->align( x1, y1 ) );
  3365. targetCell->setAlignY( sourceCell->format()->alignY( x1, y1 ) );
  3366. targetCell->setTextFont( sourceCell->format()->textFont( x1, y1 ) );
  3367. targetCell->setTextColor( sourceCell->textColor( x1, y1 ) );
  3368. targetCell->setBgColor( sourceCell->bgColor( x1, y1 ) );
  3369. targetCell->setLeftBorderPen( sourceCell->leftBorderPen( x1, y1 ) );
  3370. targetCell->setTopBorderPen( sourceCell->topBorderPen( x1, y1 ) );
  3371. targetCell->setBottomBorderPen( sourceCell->bottomBorderPen( x1, y1 ) );
  3372. targetCell->setRightBorderPen( sourceCell->rightBorderPen( x1, y1 ) );
  3373. targetCell->setFallDiagonalPen( sourceCell->fallDiagonalPen( x1, y1 ) );
  3374. targetCell->setGoUpDiagonalPen( sourceCell->goUpDiagonalPen( x1, y1 ) );
  3375. targetCell->setBackGroundBrush( sourceCell->backGroundBrush( x1, y1 ) );
  3376. targetCell->setPrecision( sourceCell->precision( x1, y1 ) );
  3377. targetCell->format()->setPrefix( sourceCell->prefix( x1, y1 ) );
  3378. targetCell->format()->setPostfix( sourceCell->postfix( x1, y1 ) );
  3379. targetCell->setFloatFormat( sourceCell->floatFormat( x1, y1 ) );
  3380. targetCell->setFloatColor( sourceCell->floatColor( x1, y1 ) );
  3381. targetCell->setMultiRow( sourceCell->multiRow( x1, y1 ) );
  3382. targetCell->setVerticalText( sourceCell->verticalText( x1, y1 ) );
  3383. targetCell->setStyle( sourceCell->style() );
  3384. targetCell->setDontPrintText( sourceCell->getDontprintText( x1, y1 ) );
  3385. targetCell->setIndent( sourceCell->getIndent( x1, y1 ) );
  3386. targetCell->SetConditionList(sourceCell->GetConditionList());
  3387. targetCell->setComment( sourceCell->comment( x1, y1 ) );
  3388. targetCell->setAngle( sourceCell->getAngle( x1, y1 ) );
  3389. targetCell->setFormatType( sourceCell->getFormatType( x1, y1 ) );
  3390. */
  3391. }
  3392. }
  3393. void Sheet::swapCells( int x1, int y1, int x2, int y2, bool cpFormat )
  3394. {
  3395. Cell * ref1 = cellAt( x1, y1 );
  3396. Cell * ref2 = cellAt( x2, y2 );
  3397. if ( ref1->isDefault() )
  3398. {
  3399. if ( !ref2->isDefault() )
  3400. {
  3401. ref1 = nonDefaultCell( x1, y1 );
  3402. // TODO : make ref2 default instead of copying a default cell into it
  3403. }
  3404. else
  3405. return; // nothing to do
  3406. }
  3407. else
  3408. if ( ref2->isDefault() )
  3409. {
  3410. ref2 = nonDefaultCell( x2, y2 );
  3411. // TODO : make ref1 default instead of copying a default cell into it
  3412. }
  3413. // Dummy cell used for swapping cells.
  3414. // In fact we copy only content and no layout
  3415. // information. Imagine sorting in a sheet. Swapping
  3416. // the format while sorting is not what you would expect
  3417. // as a user.
  3418. if (!ref1->isFormula() && !ref2->isFormula())
  3419. {
  3420. Cell *tmp = new Cell( this, -1, -1 );
  3421. tmp->copyContent( ref1 );
  3422. ref1->copyContent( ref2 );
  3423. ref2->copyContent( tmp );
  3424. delete tmp;
  3425. }
  3426. else
  3427. if ( ref1->isFormula() && ref2->isFormula() )
  3428. {
  3429. TQString d = ref1->encodeFormula();
  3430. ref1->setCellText( ref1->decodeFormula( ref2->encodeFormula( ) ) );
  3431. ref1->setCalcDirtyFlag();
  3432. ref1->calc(false);
  3433. ref2->setCellText( ref2->decodeFormula( d ) );
  3434. ref2->setCalcDirtyFlag();
  3435. ref2->calc(false);
  3436. }
  3437. else
  3438. if (ref1->isFormula() && !ref2->isFormula() )
  3439. {
  3440. TQString d = ref1->encodeFormula();
  3441. ref1->setCellText(ref2->text());
  3442. ref2->setCellText(ref2->decodeFormula(d));
  3443. ref2->setCalcDirtyFlag();
  3444. ref2->calc(false);
  3445. }
  3446. else
  3447. if (!ref1->isFormula() && ref2->isFormula() )
  3448. {
  3449. TQString d = ref2->encodeFormula();
  3450. ref2->setCellText(ref1->text());
  3451. ref1->setCellText(ref1->decodeFormula(d));
  3452. ref1->setCalcDirtyFlag();
  3453. ref1->calc(false);
  3454. }
  3455. if (cpFormat)
  3456. {
  3457. Format::Align a = ref1->format()->align( ref1->column(), ref1->row() );
  3458. ref1->format()->setAlign( ref2->format()->align( ref2->column(), ref2->row() ) );
  3459. ref2->format()->setAlign(a);
  3460. Format::AlignY ay = ref1->format()->alignY( ref1->column(), ref1->row() );
  3461. ref1->format()->setAlignY( ref2->format()->alignY( ref2->column(), ref2->row() ) );
  3462. ref2->format()->setAlignY(ay);
  3463. TQFont textFont = ref1->format()->textFont( ref1->column(), ref1->row() );
  3464. ref1->format()->setTextFont( ref2->format()->textFont( ref2->column(), ref2->row() ) );
  3465. ref2->format()->setTextFont(textFont);
  3466. TQColor textColor = ref1->format()->textColor( ref1->column(), ref1->row() );
  3467. ref1->format()->setTextColor( ref2->format()->textColor( ref2->column(), ref2->row() ) );
  3468. ref2->format()->setTextColor(textColor);
  3469. TQColor bgColor = ref1->bgColor( ref1->column(), ref1->row() );
  3470. ref1->format()->setBgColor( ref2->bgColor( ref2->column(), ref2->row() ) );
  3471. ref2->format()->setBgColor(bgColor);
  3472. TQPen lbp = ref1->leftBorderPen( ref1->column(), ref1->row() );
  3473. ref1->setLeftBorderPen( ref2->leftBorderPen( ref2->column(), ref2->row() ) );
  3474. ref2->setLeftBorderPen(lbp);
  3475. TQPen tbp = ref1->topBorderPen( ref1->column(), ref1->row() );
  3476. ref1->setTopBorderPen( ref2->topBorderPen( ref2->column(), ref2->row() ) );
  3477. ref2->setTopBorderPen(tbp);
  3478. TQPen bbp = ref1->bottomBorderPen( ref1->column(), ref1->row() );
  3479. ref1->setBottomBorderPen( ref2->bottomBorderPen( ref2->column(), ref2->row() ) );
  3480. ref2->setBottomBorderPen(bbp);
  3481. TQPen rbp = ref1->rightBorderPen( ref1->column(), ref1->row() );
  3482. ref1->setRightBorderPen( ref2->rightBorderPen( ref2->column(), ref2->row() ) );
  3483. ref2->setRightBorderPen(rbp);
  3484. TQPen fdp = ref1->format()->fallDiagonalPen( ref1->column(), ref1->row() );
  3485. ref1->format()->setFallDiagonalPen( ref2->format()->fallDiagonalPen( ref2->column(), ref2->row() ) );
  3486. ref2->format()->setFallDiagonalPen(fdp);
  3487. TQPen udp = ref1->format()->goUpDiagonalPen( ref1->column(), ref1->row() );
  3488. ref1->format()->setGoUpDiagonalPen( ref2->format()->goUpDiagonalPen( ref2->column(), ref2->row() ) );
  3489. ref2->format()->setGoUpDiagonalPen(udp);
  3490. TQBrush bgBrush = ref1->backGroundBrush( ref1->column(), ref1->row() );
  3491. ref1->format()->setBackGroundBrush( ref2->backGroundBrush( ref2->column(), ref2->row() ) );
  3492. ref2->format()->setBackGroundBrush(bgBrush);
  3493. int pre = ref1->format()->precision( ref1->column(), ref1->row() );
  3494. ref1->format()->setPrecision( ref2->format()->precision( ref2->column(), ref2->row() ) );
  3495. ref2->format()->setPrecision(pre);
  3496. TQString prefix = ref1->format()->prefix( ref1->column(), ref1->row() );
  3497. ref1->format()->setPrefix( ref2->format()->prefix( ref2->column(), ref2->row() ) );
  3498. ref2->format()->setPrefix(prefix);
  3499. TQString postfix = ref1->format()->postfix( ref1->column(), ref1->row() );
  3500. ref1->format()->setPostfix( ref2->format()->postfix( ref2->column(), ref2->row() ) );
  3501. ref2->format()->setPostfix(postfix);
  3502. Format::FloatFormat f = ref1->format()->floatFormat( ref1->column(), ref1->row() );
  3503. ref1->format()->setFloatFormat( ref2->format()->floatFormat( ref2->column(), ref2->row() ) );
  3504. ref2->format()->setFloatFormat(f);
  3505. Format::FloatColor c = ref1->format()->floatColor( ref1->column(), ref1->row() );
  3506. ref1->format()->setFloatColor( ref2->format()->floatColor( ref2->column(), ref2->row() ) );
  3507. ref2->format()->setFloatColor(c);
  3508. bool multi = ref1->format()->multiRow( ref1->column(), ref1->row() );
  3509. ref1->format()->setMultiRow( ref2->format()->multiRow( ref2->column(), ref2->row() ) );
  3510. ref2->format()->setMultiRow(multi);
  3511. bool vert = ref1->format()->verticalText( ref1->column(), ref1->row() );
  3512. ref1->format()->setVerticalText( ref2->format()->verticalText( ref2->column(), ref2->row() ) );
  3513. ref2->format()->setVerticalText(vert);
  3514. bool print = ref1->format()->getDontprintText( ref1->column(), ref1->row() );
  3515. ref1->format()->setDontPrintText( ref2->format()->getDontprintText( ref2->column(), ref2->row() ) );
  3516. ref2->format()->setDontPrintText(print);
  3517. double ind = ref1->format()->getIndent( ref1->column(), ref1->row() );
  3518. ref1->format()->setIndent( ref2->format()->getIndent( ref2->column(), ref2->row() ) );
  3519. ref2->format()->setIndent( ind );
  3520. TQValueList<Conditional> conditionList = ref1->conditionList();
  3521. ref1->setConditionList(ref2->conditionList());
  3522. ref2->setConditionList(conditionList);
  3523. TQString com = ref1->format()->comment( ref1->column(), ref1->row() );
  3524. ref1->format()->setComment( ref2->format()->comment( ref2->column(), ref2->row() ) );
  3525. ref2->format()->setComment(com);
  3526. int angle = ref1->format()->getAngle( ref1->column(), ref1->row() );
  3527. ref1->format()->setAngle( ref2->format()->getAngle( ref2->column(), ref2->row() ) );
  3528. ref2->format()->setAngle(angle);
  3529. FormatType form = ref1->format()->getFormatType( ref1->column(), ref1->row() );
  3530. ref1->format()->setFormatType( ref2->format()->getFormatType( ref2->column(), ref2->row() ) );
  3531. ref2->format()->setFormatType(form);
  3532. }
  3533. }
  3534. void Sheet::refreshPreference()
  3535. {
  3536. if ( getAutoCalc() )
  3537. recalc();
  3538. emit sig_updateHBorder( this );
  3539. emit sig_updateView( this );
  3540. }
  3541. bool Sheet::areaIsEmpty(const Region& region, TestType _type)
  3542. {
  3543. Region::ConstIterator endOfList = region.constEnd();
  3544. for (Region::ConstIterator it = region.constBegin(); it != endOfList; ++it)
  3545. {
  3546. TQRect range = (*it)->rect().normalize();
  3547. // Complete rows selected ?
  3548. if ((*it)->isRow())
  3549. {
  3550. for ( int row = range.top(); row <= range.bottom(); ++row )
  3551. {
  3552. Cell * c = getFirstCellRow( row );
  3553. while ( c )
  3554. {
  3555. if ( !c->isPartOfMerged())
  3556. {
  3557. switch( _type )
  3558. {
  3559. case Text :
  3560. if ( !c->text().isEmpty())
  3561. return false;
  3562. break;
  3563. case Validity:
  3564. if ( c->getValidity(0))
  3565. return false;
  3566. break;
  3567. case Comment:
  3568. if ( !c->format()->comment(c->column(), row).isEmpty())
  3569. return false;
  3570. break;
  3571. case ConditionalCellAttribute:
  3572. if ( c->conditionList().count()> 0)
  3573. return false;
  3574. break;
  3575. }
  3576. }
  3577. c = getNextCellRight( c->column(), row );
  3578. }
  3579. }
  3580. }
  3581. // Complete columns selected ?
  3582. else if ((*it)->isColumn())
  3583. {
  3584. for ( int col = range.left(); col <= range.right(); ++col )
  3585. {
  3586. Cell * c = getFirstCellColumn( col );
  3587. while ( c )
  3588. {
  3589. if ( !c->isPartOfMerged() )
  3590. {
  3591. switch( _type )
  3592. {
  3593. case Text :
  3594. if ( !c->text().isEmpty())
  3595. return false;
  3596. break;
  3597. case Validity:
  3598. if ( c->getValidity(0))
  3599. return false;
  3600. break;
  3601. case Comment:
  3602. if ( !c->format()->comment(col, c->row()).isEmpty())
  3603. return false;
  3604. break;
  3605. case ConditionalCellAttribute:
  3606. if ( c->conditionList().count()> 0)
  3607. return false;
  3608. break;
  3609. }
  3610. }
  3611. c = getNextCellDown( col, c->row() );
  3612. }
  3613. }
  3614. }
  3615. else
  3616. {
  3617. Cell * cell;
  3618. int right = range.right();
  3619. int bottom = range.bottom();
  3620. for ( int x = range.left(); x <= right; ++x )
  3621. for ( int y = range.top(); y <= bottom; ++y )
  3622. {
  3623. cell = cellAt( x, y );
  3624. if (!cell->isPartOfMerged() )
  3625. {
  3626. switch( _type )
  3627. {
  3628. case Text :
  3629. if ( !cell->text().isEmpty())
  3630. return false;
  3631. break;
  3632. case Validity:
  3633. if ( cell->getValidity(0))
  3634. return false;
  3635. break;
  3636. case Comment:
  3637. if ( !cell->format()->comment(x, y).isEmpty())
  3638. return false;
  3639. break;
  3640. case ConditionalCellAttribute:
  3641. if ( cell->conditionList().count()> 0)
  3642. return false;
  3643. break;
  3644. }
  3645. }
  3646. }
  3647. }
  3648. }
  3649. return true;
  3650. }
  3651. struct SetSelectionMultiRowWorker : public Sheet::CellWorker
  3652. {
  3653. bool enable;
  3654. SetSelectionMultiRowWorker( bool _enable )
  3655. : Sheet::CellWorker( ), enable( _enable ) { }
  3656. class UndoAction* createUndoAction( Doc * doc, Sheet * sheet, const KSpread::Region& region )
  3657. {
  3658. TQString title = i18n("Multirow");
  3659. return new UndoCellFormat( doc, sheet, region, title );
  3660. }
  3661. bool testCondition( Cell * cell )
  3662. {
  3663. return ( !cell->isPartOfMerged() );
  3664. }
  3665. void doWork( Cell * cell, bool, int, int )
  3666. {
  3667. cell->setDisplayDirtyFlag();
  3668. cell->format()->setMultiRow( enable );
  3669. cell->format()->setVerticalText( false );
  3670. cell->format()->setAngle( 0 );
  3671. cell->clearDisplayDirtyFlag();
  3672. }
  3673. };
  3674. void Sheet::setSelectionMultiRow( Selection* selectionInfo,
  3675. bool enable )
  3676. {
  3677. SetSelectionMultiRowWorker w( enable );
  3678. workOnCells( selectionInfo, w );
  3679. }
  3680. TQString Sheet::guessColumnTitle(TQRect& area, int col)
  3681. {
  3682. //Verify range
  3683. Range rg;
  3684. rg.setRange(area);
  3685. rg.setSheet(this);
  3686. if ( (!rg.isValid()) || (col < area.left()) || (col > area.right()))
  3687. return TQString();
  3688. //The current guess logic is fairly simple - if the top row of the given area
  3689. //appears to contain headers (ie. there is text in each column) the text in the column at
  3690. //the top row of the area is returned.
  3691. /* for (int i=area.left();i<=area.right();i++)
  3692. {
  3693. Value cellValue=value(i,area.top());
  3694. if (!cellValue.isString())
  3695. return TQString();
  3696. }*/
  3697. Value cellValue=value(col,area.top());
  3698. return cellValue.asString();
  3699. }
  3700. TQString Sheet::guessRowTitle(TQRect& area, int row)
  3701. {
  3702. //Verify range
  3703. Range rg;
  3704. rg.setRange(area);
  3705. rg.setSheet(this);
  3706. if ( (!rg.isValid()) || (row < area.top()) || (row > area.bottom()) )
  3707. return TQString();
  3708. //The current guess logic is fairly simple - if the leftmost column of the given area
  3709. //appears to contain headers (ie. there is text in each row) the text in the row at
  3710. //the leftmost column of the area is returned.
  3711. /*for (int i=area.top();i<=area.bottom();i++)
  3712. {
  3713. Value cellValue=value(area.left(),i);
  3714. if (!cellValue.isString())
  3715. return TQString();
  3716. }*/
  3717. Value cellValue=value(area.left(),row);
  3718. return cellValue.asString();
  3719. }
  3720. void Sheet::setSelectionAlign( Selection* selectionInfo,
  3721. Format::Align _align )
  3722. {
  3723. HorAlignManipulator* manipulator = new HorAlignManipulator();
  3724. manipulator->setSheet(this);
  3725. manipulator->setProperty(Format::PAlign);
  3726. manipulator->setHorizontalAlignment(_align);
  3727. manipulator->add(*selectionInfo);
  3728. manipulator->execute();
  3729. }
  3730. void Sheet::setSelectionAlignY( Selection* selectionInfo,
  3731. Format::AlignY _alignY )
  3732. {
  3733. VerAlignManipulator* manipulator = new VerAlignManipulator();
  3734. manipulator->setSheet(this);
  3735. manipulator->setProperty(Format::PAlignY);
  3736. manipulator->setVerticalAlignment(_alignY);
  3737. manipulator->add(*selectionInfo);
  3738. manipulator->execute();
  3739. }
  3740. struct SetSelectionPrecisionWorker : public Sheet::CellWorker {
  3741. int _delta;
  3742. SetSelectionPrecisionWorker( int delta ) : Sheet::CellWorker( ), _delta( delta ) { }
  3743. class UndoAction* createUndoAction( Doc* doc, Sheet* sheet, const KSpread::Region& region ) {
  3744. TQString title=i18n("Change Precision");
  3745. return new UndoCellFormat( doc, sheet, region, title );
  3746. }
  3747. bool testCondition( Cell* cell ) {
  3748. return ( !cell->isPartOfMerged() );
  3749. }
  3750. void doWork( Cell* cell, bool, int, int ) {
  3751. cell->setDisplayDirtyFlag();
  3752. if ( _delta == 1 )
  3753. cell->incPrecision();
  3754. else
  3755. cell->decPrecision();
  3756. cell->clearDisplayDirtyFlag();
  3757. }
  3758. };
  3759. void Sheet::setSelectionPrecision( Selection* selectionInfo,
  3760. int _delta )
  3761. {
  3762. SetSelectionPrecisionWorker w( _delta );
  3763. workOnCells( selectionInfo, w );
  3764. }
  3765. struct SetSelectionStyleWorker : public Sheet::CellWorkerTypeA
  3766. {
  3767. Style * m_style;
  3768. SetSelectionStyleWorker( Style * style )
  3769. : m_style( style )
  3770. {
  3771. }
  3772. TQString getUndoTitle()
  3773. {
  3774. return i18n("Apply Style");
  3775. }
  3776. void doWork( RowFormat* rw )
  3777. {
  3778. rw->setStyle( m_style );
  3779. }
  3780. void doWork( ColumnFormat* cl )
  3781. {
  3782. cl->setStyle( m_style );
  3783. }
  3784. bool testCondition( Cell* cell )
  3785. {
  3786. return ( !cell->isPartOfMerged() && cell->format()->style() != m_style );
  3787. }
  3788. void doWork( Cell* cell, bool cellRegion, int, int )
  3789. {
  3790. if ( cellRegion )
  3791. cell->setDisplayDirtyFlag();
  3792. cell->format()->setStyle( m_style );
  3793. if ( cellRegion )
  3794. cell->clearDisplayDirtyFlag();
  3795. }
  3796. };
  3797. void Sheet::setSelectionStyle( Selection * selectionInfo, Style * style )
  3798. {
  3799. SetSelectionStyleWorker w( style );
  3800. workOnCells( selectionInfo, w );
  3801. }
  3802. struct SetSelectionMoneyFormatWorker : public Sheet::CellWorkerTypeA
  3803. {
  3804. bool b;
  3805. Doc *m_pDoc;
  3806. SetSelectionMoneyFormatWorker( bool _b,Doc* _doc ) : b( _b ), m_pDoc(_doc) { }
  3807. TQString getUndoTitle() { return i18n("Format Money"); }
  3808. bool testCondition( RowFormat* rw ) {
  3809. return ( rw->hasProperty( Format::PFormatType )
  3810. || rw->hasProperty( Format::PPrecision ) );
  3811. }
  3812. void doWork( RowFormat* rw ) {
  3813. rw->setFormatType( b ? Money_format : Generic_format );
  3814. rw->setPrecision( b ? m_pDoc->locale()->fracDigits() : 0 );
  3815. }
  3816. void doWork( ColumnFormat* cl ) {
  3817. cl->setFormatType( b ? Money_format : Generic_format );
  3818. cl->setPrecision( b ? m_pDoc->locale()->fracDigits() : 0 );
  3819. }
  3820. void prepareCell( Cell* c ) {
  3821. c->format()->clearProperty( Format::PPrecision );
  3822. c->format()->clearNoFallBackProperties( Format::PPrecision );
  3823. c->format()->clearProperty( Format::PFormatType );
  3824. c->format()->clearNoFallBackProperties( Format::PFormatType );
  3825. }
  3826. bool testCondition( Cell* cell ) {
  3827. return ( !cell->isPartOfMerged() );
  3828. }
  3829. void doWork( Cell* cell, bool cellRegion, int, int ) {
  3830. if ( cellRegion )
  3831. cell->setDisplayDirtyFlag();
  3832. cell->format()->setFormatType( b ? Money_format : Generic_format );
  3833. cell->format()->setPrecision( b ? m_pDoc->locale()->fracDigits() : 0 );
  3834. if ( cellRegion )
  3835. cell->clearDisplayDirtyFlag();
  3836. }
  3837. };
  3838. void Sheet::setSelectionMoneyFormat( Selection* selectionInfo,
  3839. bool b )
  3840. {
  3841. SetSelectionMoneyFormatWorker w( b,doc() );
  3842. workOnCells( selectionInfo, w );
  3843. }
  3844. struct IncreaseIndentWorker : public Sheet::CellWorkerTypeA {
  3845. double tmpIndent;
  3846. double valIndent;
  3847. IncreaseIndentWorker( double _tmpIndent, double _valIndent )
  3848. : tmpIndent( _tmpIndent ), valIndent( _valIndent ) { }
  3849. TQString getUndoTitle() { return i18n("Increase Indent"); }
  3850. bool testCondition( RowFormat* rw ) {
  3851. return ( rw->hasProperty( Format::PIndent ) );
  3852. }
  3853. void doWork( RowFormat* rw ) {
  3854. rw->setIndent( tmpIndent+valIndent );
  3855. //rw->setAlign( Format::Left );
  3856. }
  3857. void doWork( ColumnFormat* cl ) {
  3858. cl->setIndent( tmpIndent+valIndent );
  3859. //cl->setAlign( Format::Left );
  3860. }
  3861. void prepareCell( Cell* c ) {
  3862. c->format()->clearProperty( Format::PIndent );
  3863. c->format()->clearNoFallBackProperties( Format::PIndent );
  3864. //c->format()->clearProperty( Format::PAlign );
  3865. //c->format()->clearNoFallBackProperties( Format::PAlign );
  3866. }
  3867. bool testCondition( Cell* cell ) {
  3868. return ( !cell->isPartOfMerged() );
  3869. }
  3870. void doWork( Cell* cell, bool cellRegion, int x, int y ) {
  3871. if ( cellRegion ) {
  3872. if(cell->format()->align(x,y)!=Format::Left)
  3873. {
  3874. //cell->setAlign(Format::Left);
  3875. //cell->format()->setIndent( 0.0 );
  3876. }
  3877. cell->setDisplayDirtyFlag();
  3878. cell->format()->setIndent( /* ### ??? --> */ cell->format()->getIndent(x,y) /* <-- */ +valIndent );
  3879. cell->clearDisplayDirtyFlag();
  3880. } else {
  3881. cell->format()->setIndent( tmpIndent+valIndent);
  3882. //cell->setAlign( Format::Left);
  3883. }
  3884. }
  3885. };
  3886. void Sheet::increaseIndent(Selection* selectionInfo)
  3887. {
  3888. TQPoint marker(selectionInfo->marker());
  3889. double valIndent = doc()->getIndentValue();
  3890. Cell *c = cellAt( marker );
  3891. double tmpIndent = c->format()->getIndent( marker.x(), marker.y() );
  3892. IncreaseIndentWorker w( tmpIndent, valIndent );
  3893. workOnCells( selectionInfo, w );
  3894. }
  3895. struct DecreaseIndentWorker : public Sheet::CellWorkerTypeA {
  3896. double tmpIndent, valIndent;
  3897. DecreaseIndentWorker( double _tmpIndent, double _valIndent ) : tmpIndent( _tmpIndent ), valIndent( _valIndent ) { }
  3898. TQString getUndoTitle() { return i18n("Decrease Indent"); }
  3899. bool testCondition( RowFormat* rw ) {
  3900. return ( rw->hasProperty( Format::PIndent ) );
  3901. }
  3902. void doWork( RowFormat* rw ) {
  3903. rw->setIndent( TQMAX( 0.0, tmpIndent - valIndent ) );
  3904. }
  3905. void doWork( ColumnFormat* cl ) {
  3906. cl->setIndent( TQMAX( 0.0, tmpIndent - valIndent ) );
  3907. }
  3908. void prepareCell( Cell* c ) {
  3909. c->format()->clearProperty( Format::PIndent );
  3910. c->format()->clearNoFallBackProperties( Format::PIndent );
  3911. }
  3912. bool testCondition( Cell* cell ) {
  3913. return ( !cell->isPartOfMerged() );
  3914. }
  3915. void doWork( Cell* cell, bool cellRegion, int x, int y ) {
  3916. if ( cellRegion ) {
  3917. cell->setDisplayDirtyFlag();
  3918. cell->format()->setIndent( TQMAX( 0.0, cell->format()->getIndent( x, y ) - valIndent ) );
  3919. cell->clearDisplayDirtyFlag();
  3920. } else {
  3921. cell->format()->setIndent( TQMAX( 0.0, tmpIndent - valIndent ) );
  3922. }
  3923. }
  3924. };
  3925. void Sheet::decreaseIndent( Selection* selectionInfo )
  3926. {
  3927. double valIndent = doc()->getIndentValue();
  3928. TQPoint marker(selectionInfo->marker());
  3929. Cell* c = cellAt( marker );
  3930. double tmpIndent = c->format()->getIndent( marker.x(), marker.y() );
  3931. DecreaseIndentWorker w( tmpIndent, valIndent );
  3932. workOnCells( selectionInfo, w );
  3933. }
  3934. int Sheet::adjustColumnHelper( Cell * c, int _col, int _row )
  3935. {
  3936. double long_max = 0.0;
  3937. c->calculateTextParameters( painter(), _col, _row );
  3938. if ( c->textWidth() > long_max )
  3939. {
  3940. double indent = 0.0;
  3941. int a = c->format()->align( c->column(), c->row() );
  3942. if ( a == Format::Undefined )
  3943. {
  3944. if ( c->value().isNumber() || c->isDate() || c->isTime())
  3945. a = Format::Right;
  3946. else
  3947. a = Format::Left;
  3948. }
  3949. if ( a == Format::Left )
  3950. indent = c->format()->getIndent( c->column(), c->row() );
  3951. long_max = indent + c->textWidth()
  3952. + c->format()->leftBorderWidth( c->column(), c->row() )
  3953. + c->format()->rightBorderWidth( c->column(), c->row() );
  3954. }
  3955. return (int)long_max;
  3956. }
  3957. void Sheet::adjustArea(const Region& region)
  3958. {
  3959. AdjustColumnRowManipulator* manipulator = new AdjustColumnRowManipulator();
  3960. manipulator->setSheet(this);
  3961. manipulator->setAdjustColumn(true);
  3962. manipulator->setAdjustRow(true);
  3963. manipulator->add(region);
  3964. manipulator->execute();
  3965. }
  3966. void Sheet::adjustColumn(const Region& region)
  3967. {
  3968. AdjustColumnRowManipulator* manipulator = new AdjustColumnRowManipulator();
  3969. manipulator->setSheet(this);
  3970. manipulator->setAdjustColumn(true);
  3971. manipulator->add(region);
  3972. manipulator->execute();
  3973. }
  3974. void Sheet::adjustRow(const Region& region)
  3975. {
  3976. AdjustColumnRowManipulator* manipulator = new AdjustColumnRowManipulator();
  3977. manipulator->setSheet(this);
  3978. manipulator->setAdjustRow(true);
  3979. manipulator->add(region);
  3980. manipulator->execute();
  3981. }
  3982. struct ClearTextSelectionWorker : public Sheet::CellWorker {
  3983. Sheet * _s;
  3984. ClearTextSelectionWorker( Sheet * s )
  3985. : Sheet::CellWorker( ), _s( s ) { }
  3986. class UndoAction* createUndoAction( Doc* doc, Sheet* sheet, const KSpread::Region& region ) {
  3987. return new UndoChangeAreaTextCell( doc, sheet, region );
  3988. }
  3989. bool testCondition( Cell* cell ) {
  3990. return ( !cell->isObscured() );
  3991. }
  3992. void doWork( Cell* cell, bool, int, int )
  3993. {
  3994. cell->setCellText( "" );
  3995. }
  3996. };
  3997. void Sheet::clearTextSelection( Selection* selectionInfo )
  3998. {
  3999. if (areaIsEmpty(*selectionInfo))
  4000. return;
  4001. ClearTextSelectionWorker w( this );
  4002. workOnCells( selectionInfo, w );
  4003. }
  4004. struct ClearValiditySelectionWorker : public Sheet::CellWorker {
  4005. ClearValiditySelectionWorker( ) : Sheet::CellWorker( ) { }
  4006. class UndoAction* createUndoAction( Doc* doc, Sheet* sheet, const KSpread::Region& region ) {
  4007. return new UndoConditional( doc, sheet, region );
  4008. }
  4009. bool testCondition( Cell* cell ) {
  4010. return ( !cell->isObscured() );
  4011. }
  4012. void doWork( Cell* cell, bool, int, int ) {
  4013. cell->removeValidity();
  4014. }
  4015. };
  4016. void Sheet::clearValiditySelection( Selection* selectionInfo )
  4017. {
  4018. if (areaIsEmpty(*selectionInfo, Validity))
  4019. return;
  4020. ClearValiditySelectionWorker w;
  4021. workOnCells( selectionInfo, w );
  4022. }
  4023. struct ClearConditionalSelectionWorker : public Sheet::CellWorker
  4024. {
  4025. ClearConditionalSelectionWorker( ) : Sheet::CellWorker( ) { }
  4026. class UndoAction* createUndoAction( Doc* doc,
  4027. Sheet* sheet,
  4028. const KSpread::Region& region )
  4029. {
  4030. return new UndoConditional( doc, sheet, region );
  4031. }
  4032. bool testCondition( Cell* cell )
  4033. {
  4034. return ( !cell->isObscured() );
  4035. }
  4036. void doWork( Cell* cell, bool, int, int )
  4037. {
  4038. TQValueList<Conditional> emptyList;
  4039. cell->setConditionList(emptyList);
  4040. }
  4041. };
  4042. void Sheet::clearConditionalSelection( Selection* selectionInfo )
  4043. {
  4044. ClearConditionalSelectionWorker w;
  4045. workOnCells( selectionInfo, w );
  4046. }
  4047. void Sheet::fillSelection( Selection * selectionInfo, int direction )
  4048. {
  4049. TQRect rct( selectionInfo->selection() );
  4050. int right = rct.right();
  4051. int bottom = rct.bottom();
  4052. int left = rct.left();
  4053. int top = rct.top();
  4054. int width = rct.width();
  4055. int height = rct.height();
  4056. TQDomDocument undoDoc = saveCellRegion( rct );
  4057. loadSelectionUndo( undoDoc, rct, left - 1, top - 1, false, 0 );
  4058. TQDomDocument doc;
  4059. switch( direction )
  4060. {
  4061. case Right:
  4062. doc = saveCellRegion( TQRect( left, top, 1, height ) );
  4063. break;
  4064. case Up:
  4065. doc = saveCellRegion( TQRect( left, bottom, width, 1 ) );
  4066. break;
  4067. case Left:
  4068. doc = saveCellRegion( TQRect( right, top, 1, height ) );
  4069. break;
  4070. case Down:
  4071. doc = saveCellRegion( TQRect( left, top, width, 1 ) );
  4072. break;
  4073. };
  4074. // Save to buffer
  4075. TQBuffer buffer;
  4076. buffer.open( IO_WriteOnly );
  4077. TQTextStream str( &buffer );
  4078. str.setEncoding( TQTextStream::UnicodeUTF8 );
  4079. str << doc;
  4080. buffer.close();
  4081. int i;
  4082. switch( direction )
  4083. {
  4084. case Right:
  4085. for ( i = left + 1; i <= right; ++i )
  4086. {
  4087. paste( buffer.buffer(), TQRect( i, top, 1, 1 ), false );
  4088. }
  4089. break;
  4090. case Up:
  4091. for ( i = bottom + 1; i >= top; --i )
  4092. {
  4093. paste( buffer.buffer(), TQRect( left, i, 1, 1 ), false );
  4094. }
  4095. break;
  4096. case Left:
  4097. for ( i = right - 1; i >= left; --i )
  4098. {
  4099. paste( buffer.buffer(), TQRect( i, top, 1, 1 ), false );
  4100. }
  4101. break;
  4102. case Down:
  4103. for ( i = top + 1; i <= bottom; ++i )
  4104. {
  4105. paste( buffer.buffer(), TQRect( left, i, 1, 1 ), false );
  4106. }
  4107. break;
  4108. }
  4109. this->doc()->setModified( true );
  4110. }
  4111. struct DefaultSelectionWorker : public Sheet::CellWorker {
  4112. DefaultSelectionWorker( ) : Sheet::CellWorker( true, false, true ) { }
  4113. class UndoAction* createUndoAction( Doc* doc, Sheet* sheet, const KSpread::Region& region ) {
  4114. TQString title=i18n("Default Parameters");
  4115. return new UndoCellFormat( doc, sheet, region, title );
  4116. }
  4117. bool testCondition( Cell* ) {
  4118. return true;
  4119. }
  4120. void doWork( Cell* cell, bool, int, int ) {
  4121. cell->defaultStyle();
  4122. }
  4123. };
  4124. void Sheet::defaultSelection( Selection* selectionInfo )
  4125. {
  4126. TQRect selection(selectionInfo->selection());
  4127. DefaultSelectionWorker w;
  4128. SelectionType st = workOnCells( selectionInfo, w );
  4129. switch ( st ) {
  4130. case CompleteRows:
  4131. RowFormat *rw;
  4132. for ( int i = selection.top(); i <= selection.bottom(); i++ ) {
  4133. rw = nonDefaultRowFormat( i );
  4134. rw->defaultStyleFormat();
  4135. }
  4136. emit sig_updateView( this, *selectionInfo );
  4137. return;
  4138. case CompleteColumns:
  4139. ColumnFormat *cl;
  4140. for ( int i = selection.left(); i <= selection.right(); i++ ) {
  4141. cl=nonDefaultColumnFormat( i );
  4142. cl->defaultStyleFormat();
  4143. }
  4144. emit sig_updateView( this, *selectionInfo );
  4145. return;
  4146. case CellRegion:
  4147. emit sig_updateView( this, *selectionInfo );
  4148. return;
  4149. }
  4150. }
  4151. struct SetConditionalWorker : public Sheet::CellWorker
  4152. {
  4153. TQValueList<Conditional> conditionList;
  4154. SetConditionalWorker( TQValueList<Conditional> _tmp ) :
  4155. Sheet::CellWorker( ), conditionList( _tmp ) { }
  4156. class UndoAction* createUndoAction( Doc* doc,
  4157. Sheet* sheet, const KSpread::Region& region )
  4158. {
  4159. return new UndoConditional( doc, sheet, region );
  4160. }
  4161. bool testCondition( Cell* )
  4162. {
  4163. return true;
  4164. }
  4165. void doWork( Cell* cell, bool, int, int )
  4166. {
  4167. if ( !cell->isObscured() ) // TODO: isPartOfMerged()???
  4168. {
  4169. cell->setConditionList(conditionList);
  4170. cell->setDisplayDirtyFlag();
  4171. }
  4172. }
  4173. };
  4174. void Sheet::setConditional( Selection* selectionInfo,
  4175. TQValueList<Conditional> const & newConditions)
  4176. {
  4177. if ( !doc()->undoLocked() )
  4178. {
  4179. UndoConditional * undo = new UndoConditional(doc(), this, *selectionInfo);
  4180. doc()->addCommand( undo );
  4181. }
  4182. Region::ConstIterator endOfList = selectionInfo->constEnd();
  4183. for (Region::ConstIterator it = selectionInfo->constBegin(); it != endOfList; ++it)
  4184. {
  4185. TQRect range = (*it)->rect().normalize();
  4186. int l = range.left();
  4187. int r = range.right();
  4188. int t = range.top();
  4189. int b = range.bottom();
  4190. Cell * cell;
  4191. Style * s = doc()->styleManager()->defaultStyle();
  4192. for (int x = l; x <= r; ++x)
  4193. {
  4194. for (int y = t; y <= b; ++y)
  4195. {
  4196. cell = nonDefaultCell( x, y, false, s );
  4197. cell->setConditionList( newConditions );
  4198. cell->setDisplayDirtyFlag();
  4199. }
  4200. }
  4201. }
  4202. emit sig_updateView( this, *selectionInfo );
  4203. }
  4204. struct SetValidityWorker : public Sheet::CellWorker {
  4205. Validity tmp;
  4206. SetValidityWorker( Validity _tmp ) : Sheet::CellWorker( ), tmp( _tmp ) { }
  4207. class UndoAction* createUndoAction( Doc* doc, Sheet* sheet, const KSpread::Region& region ) {
  4208. return new UndoConditional( doc, sheet, region );
  4209. }
  4210. bool testCondition( Cell* ) {
  4211. return true;
  4212. }
  4213. void doWork( Cell* cell, bool, int, int ) {
  4214. if ( !cell->isObscured() ) {
  4215. cell->setDisplayDirtyFlag();
  4216. if ( tmp.m_restriction==Restriction::None )
  4217. cell->removeValidity();
  4218. else
  4219. {
  4220. Validity *tmpValidity = cell->getValidity();
  4221. tmpValidity->message=tmp.message;
  4222. tmpValidity->title=tmp.title;
  4223. tmpValidity->valMin=tmp.valMin;
  4224. tmpValidity->valMax=tmp.valMax;
  4225. tmpValidity->m_cond=tmp.m_cond;
  4226. tmpValidity->m_action=tmp.m_action;
  4227. tmpValidity->m_restriction=tmp.m_restriction;
  4228. tmpValidity->timeMin=tmp.timeMin;
  4229. tmpValidity->timeMax=tmp.timeMax;
  4230. tmpValidity->dateMin=tmp.dateMin;
  4231. tmpValidity->dateMax=tmp.dateMax;
  4232. tmpValidity->displayMessage=tmp.displayMessage;
  4233. tmpValidity->allowEmptyCell=tmp.allowEmptyCell;
  4234. tmpValidity->displayValidationInformation=tmp.displayValidationInformation;
  4235. tmpValidity->titleInfo=tmp.titleInfo;
  4236. tmpValidity->messageInfo=tmp.messageInfo;
  4237. tmpValidity->listValidity=tmp.listValidity;
  4238. }
  4239. cell->clearDisplayDirtyFlag();
  4240. }
  4241. }
  4242. };
  4243. void Sheet::setValidity(Selection* selectionInfo,
  4244. KSpread::Validity tmp )
  4245. {
  4246. SetValidityWorker w( tmp );
  4247. workOnCells( selectionInfo, w );
  4248. }
  4249. struct GetWordSpellingWorker : public Sheet::CellWorker {
  4250. TQString& listWord;
  4251. GetWordSpellingWorker( TQString& _listWord ) : Sheet::CellWorker( false, false, true ), listWord( _listWord ) { }
  4252. class UndoAction* createUndoAction( Doc*, Sheet*, const KSpread::Region& ) {
  4253. return 0;
  4254. }
  4255. bool testCondition( Cell* ) {
  4256. return true;
  4257. }
  4258. void doWork( Cell* c, bool cellRegion, int, int ) {
  4259. if ( !c->isObscured() || cellRegion /* ### ??? */ ) {
  4260. if ( !c->isFormula() && !c->value().isNumber() && !c->value().asString().isEmpty() && !c->isTime()
  4261. && !c->isDate()
  4262. && !c->text().isEmpty())
  4263. {
  4264. listWord+=c->text()+'\n';
  4265. }
  4266. }
  4267. }
  4268. };
  4269. TQString Sheet::getWordSpelling(Selection* selectionInfo )
  4270. {
  4271. TQString listWord;
  4272. GetWordSpellingWorker w( listWord );
  4273. workOnCells( selectionInfo, w );
  4274. return listWord;
  4275. }
  4276. struct SetWordSpellingWorker : public Sheet::CellWorker {
  4277. TQStringList& list;
  4278. int pos;
  4279. Sheet * sheet;
  4280. SetWordSpellingWorker( TQStringList & _list,Sheet * s )
  4281. : Sheet::CellWorker( false, false, true ), list( _list ), pos( 0 ), sheet( s ) { }
  4282. class UndoAction* createUndoAction( Doc* doc, Sheet* sheet, const KSpread::Region& region ) {
  4283. return new UndoChangeAreaTextCell( doc, sheet, region );
  4284. }
  4285. bool testCondition( Cell* ) {
  4286. return true;
  4287. }
  4288. void doWork( Cell* c, bool cellRegion, int, int )
  4289. {
  4290. if ( !c->isObscured() || cellRegion /* ### ??? */ ) {
  4291. if ( !c->isFormula() && !c->value().isNumber() && !c->value().asString().isEmpty() && !c->isTime()
  4292. && !c->isDate()
  4293. && !c->text().isEmpty())
  4294. {
  4295. c->setCellText( list[pos] );
  4296. pos++;
  4297. }
  4298. }
  4299. }
  4300. };
  4301. void Sheet::setWordSpelling(Selection* selectionInfo,
  4302. const TQString _listWord )
  4303. {
  4304. TQStringList list = TQStringList::split ( '\n', _listWord );
  4305. SetWordSpellingWorker w( list, this );
  4306. workOnCells( selectionInfo, w );
  4307. }
  4308. static TQString cellAsText( Cell* cell, unsigned int max )
  4309. {
  4310. TQString result;
  4311. if( !cell->isDefault() )
  4312. {
  4313. int l = max - cell->strOutText().length();
  4314. if (cell->defineAlignX() == Format::Right )
  4315. {
  4316. for ( int i = 0; i < l; ++i )
  4317. result += " ";
  4318. result += cell->strOutText();
  4319. }
  4320. else if (cell->defineAlignX() == Format::Left )
  4321. {
  4322. result += " ";
  4323. result += cell->strOutText();
  4324. // start with "1" because we already set one space
  4325. for ( int i = 1; i < l; ++i )
  4326. result += " ";
  4327. }
  4328. else // centered
  4329. {
  4330. int i;
  4331. int s = (int) l / 2;
  4332. for ( i = 0; i < s; ++i )
  4333. result += " ";
  4334. result += cell->strOutText();
  4335. for ( i = s; i < l; ++i )
  4336. result += " ";
  4337. }
  4338. }
  4339. else
  4340. {
  4341. for ( unsigned int i = 0; i < max; ++i )
  4342. result += " ";
  4343. }
  4344. return result;
  4345. }
  4346. TQString Sheet::copyAsText( Selection* selectionInfo )
  4347. {
  4348. // Only one cell selected? => copy active cell
  4349. if ( selectionInfo->isSingular() )
  4350. {
  4351. Cell * cell = cellAt( selectionInfo->marker() );
  4352. if( !cell->isDefault() )
  4353. return cell->strOutText();
  4354. return "";
  4355. }
  4356. TQRect selection(selectionInfo->selection());
  4357. // Find area
  4358. unsigned top = selection.bottom();
  4359. unsigned bottom = selection.top();
  4360. unsigned left = selection.right();
  4361. unsigned right = selection.left();
  4362. unsigned max = 1;
  4363. for( Cell *c = d->cells.firstCell();c; c = c->nextCell() )
  4364. {
  4365. if ( !c->isDefault() )
  4366. {
  4367. TQPoint p( c->column(), c->row() );
  4368. if ( selection.contains( p ) )
  4369. {
  4370. top = TQMIN( top, (unsigned) c->row() );
  4371. left = TQMIN( left, (unsigned) c->column() );
  4372. bottom = TQMAX( bottom, (unsigned) c->row() );
  4373. right = TQMAX( right, (unsigned) c->column() );
  4374. if ( c->strOutText().length() > max )
  4375. max = c->strOutText().length();
  4376. }
  4377. }
  4378. }
  4379. ++max;
  4380. TQString result;
  4381. for ( unsigned y = top; y <= bottom; ++y)
  4382. {
  4383. for ( unsigned x = left; x <= right; ++x)
  4384. {
  4385. Cell *cell = cellAt( x, y );
  4386. result += cellAsText( cell, max );
  4387. }
  4388. result += "\n";
  4389. }
  4390. return result;
  4391. }
  4392. void Sheet::copySelection( Selection* selectionInfo )
  4393. {
  4394. TQDomDocument doc = saveCellRegion( *selectionInfo, true );
  4395. // Save to buffer
  4396. TQBuffer buffer;
  4397. buffer.open( IO_WriteOnly );
  4398. TQTextStream str( &buffer );
  4399. str.setEncoding( TQTextStream::UnicodeUTF8 );
  4400. str << doc;
  4401. buffer.close();
  4402. TextDrag * kd = new TextDrag( 0L );
  4403. kd->setPlain( copyAsText(selectionInfo) );
  4404. kd->setKSpread( buffer.buffer() );
  4405. TQApplication::clipboard()->setData( kd );
  4406. }
  4407. void Sheet::cutSelection( Selection* selectionInfo )
  4408. {
  4409. TQDomDocument doc = saveCellRegion(*selectionInfo, true, true);
  4410. // Save to buffer
  4411. TQBuffer buffer;
  4412. buffer.open( IO_WriteOnly );
  4413. TQTextStream str( &buffer );
  4414. str.setEncoding( TQTextStream::UnicodeUTF8 );
  4415. str << doc;
  4416. buffer.close();
  4417. TextDrag * kd = new TextDrag( 0L );
  4418. kd->setPlain( copyAsText(selectionInfo) );
  4419. kd->setKSpread( buffer.buffer() );
  4420. TQApplication::clipboard()->setData( kd );
  4421. deleteSelection( selectionInfo, true );
  4422. }
  4423. void Sheet::paste( const TQRect& pasteArea, bool makeUndo,
  4424. Paste::Mode mode, Paste::Operation operation,
  4425. bool insert, int insertTo, bool pasteFC,
  4426. TQClipboard::Mode clipboardMode )
  4427. {
  4428. TQMimeSource * mime = TQApplication::clipboard()->data( clipboardMode );
  4429. if ( !mime )
  4430. return;
  4431. TQByteArray b;
  4432. if ( mime->provides( TextDrag::selectionMimeType() ) )
  4433. {
  4434. b = mime->encodedData( TextDrag::selectionMimeType() );
  4435. }
  4436. else if( mime->provides( "text/plain" ) )
  4437. {
  4438. // Note: TQClipboard::text() seems to do a better job than encodedData( "text/plain" )
  4439. // In particular it handles charsets (in the mimetype). Copied from KPresenter ;-)
  4440. TQString _text = TQApplication::clipboard()->text( clipboardMode );
  4441. doc()->emitBeginOperation();
  4442. pasteTextPlain( _text, pasteArea );
  4443. emit sig_updateView( this );
  4444. // doc()->emitEndOperation();
  4445. return;
  4446. }
  4447. else
  4448. return;
  4449. // Do the actual pasting.
  4450. doc()->emitBeginOperation();
  4451. paste( b, pasteArea, makeUndo, mode, operation, insert, insertTo, pasteFC );
  4452. emit sig_updateView( this );
  4453. // doc()->emitEndOperation();
  4454. }
  4455. void Sheet::pasteTextPlain( TQString &_text, TQRect pasteArea)
  4456. {
  4457. // TQString tmp;
  4458. // tmp= TQString::fromLocal8Bit(_mime->encodedData( "text/plain" ));
  4459. if( _text.isEmpty() )
  4460. return;
  4461. TQString tmp = _text;
  4462. int i;
  4463. int mx = pasteArea.left();
  4464. int my = pasteArea.top();
  4465. int rows = 1;
  4466. int len = tmp.length();
  4467. //count the numbers of lines in text
  4468. for ( i = 0; i < len; ++i )
  4469. {
  4470. if ( tmp[i] == '\n' )
  4471. ++rows;
  4472. }
  4473. Cell * cell = nonDefaultCell( mx, my );
  4474. if ( rows == 1 )
  4475. {
  4476. if ( !doc()->undoLocked() )
  4477. {
  4478. UndoSetText * undo = new UndoSetText( doc(), this , cell->text(), mx, my, cell->formatType() );
  4479. doc()->addCommand( undo );
  4480. }
  4481. }
  4482. else
  4483. {
  4484. TQRect rect(mx, my, mx, my + rows - 1);
  4485. UndoChangeAreaTextCell * undo = new UndoChangeAreaTextCell( doc(), this , rect );
  4486. doc()->addCommand( undo );
  4487. }
  4488. i = 0;
  4489. TQString rowtext;
  4490. while ( i < rows )
  4491. {
  4492. int p = 0;
  4493. p = tmp.find('\n');
  4494. if (p < 0)
  4495. p = tmp.length();
  4496. rowtext = tmp.left(p);
  4497. if ( !isProtected() || cell->format()->notProtected( mx, my + i ) )
  4498. {
  4499. cell->setCellText( rowtext );
  4500. cell->updateChart();
  4501. }
  4502. // next cell
  4503. ++i;
  4504. cell = nonDefaultCell( mx, my + i );
  4505. if (!cell || p == (int) tmp.length())
  4506. break;
  4507. // exclude the left part and '\n'
  4508. tmp = tmp.right(tmp.length() - p - 1);
  4509. }
  4510. if (!isLoading())
  4511. refreshMergedCell();
  4512. emit sig_updateView( this );
  4513. emit sig_updateHBorder( this );
  4514. emit sig_updateVBorder( this );
  4515. }
  4516. void Sheet::paste( const TQByteArray& b, const TQRect& pasteArea, bool makeUndo,
  4517. Paste::Mode mode, Paste::Operation operation,
  4518. bool insert, int insertTo, bool pasteFC )
  4519. {
  4520. kdDebug(36001) << "Parsing " << b.size() << " bytes" << endl;
  4521. TQBuffer buffer( b );
  4522. buffer.open( IO_ReadOnly );
  4523. TQDomDocument doc;
  4524. doc.setContent( &buffer );
  4525. buffer.close();
  4526. // ##### TODO: Test for parsing errors
  4527. int mx = pasteArea.left();
  4528. int my = pasteArea.top();
  4529. loadSelection( doc, pasteArea, mx - 1, my - 1, makeUndo,
  4530. mode, operation, insert, insertTo, pasteFC );
  4531. }
  4532. bool Sheet::loadSelection(const TQDomDocument& doc, const TQRect& pasteArea,
  4533. int _xshift, int _yshift, bool makeUndo,
  4534. Paste::Mode mode, Paste::Operation operation, bool insert,
  4535. int insertTo, bool pasteFC)
  4536. {
  4537. //kdDebug(36001) << "loadSelection called. pasteArea=" << pasteArea << endl;
  4538. if (!isLoading() && makeUndo)
  4539. {
  4540. loadSelectionUndo( doc, pasteArea, _xshift, _yshift, insert, insertTo );
  4541. }
  4542. TQDomElement root = doc.documentElement(); // "spreadsheet-snippet"
  4543. int rowsInClpbrd = root.attribute( "rows" ).toInt();
  4544. int columnsInClpbrd = root.attribute( "columns" ).toInt();
  4545. // find size of rectangle that we want to paste to (either clipboard size or current selection)
  4546. const int pasteWidth = ( pasteArea.width() >= columnsInClpbrd
  4547. && util_isRowSelected(pasteArea) == false
  4548. && root.namedItem( "rows" ).toElement().isNull() )
  4549. ? pasteArea.width() : columnsInClpbrd;
  4550. const int pasteHeight = ( pasteArea.height() >= rowsInClpbrd
  4551. && util_isColumnSelected(pasteArea) == false
  4552. && root.namedItem( "columns" ).toElement().isNull())
  4553. ? pasteArea.height() : rowsInClpbrd;
  4554. // kdDebug() << "loadSelection: paste area has size "
  4555. // << pasteHeight << " rows * "
  4556. // << pasteWidth << " columns " << endl;
  4557. // kdDebug() << "loadSelection: " << rowsInClpbrd << " rows and "
  4558. // << columnsInClpbrd << " columns in clipboard." << endl;
  4559. // kdDebug() << "xshift: " << _xshift << " _yshift: " << _yshift << endl;
  4560. TQDomElement e = root.firstChild().toElement(); // "columns", "rows" or "cell"
  4561. for (; !e.isNull(); e = e.nextSibling().toElement())
  4562. {
  4563. // entire columns given
  4564. if (e.tagName() == "columns" && !isProtected())
  4565. {
  4566. _yshift = 0;
  4567. // Clear the existing columns
  4568. int col = e.attribute("column").toInt();
  4569. int width = e.attribute("count").toInt();
  4570. if (!insert)
  4571. {
  4572. for ( int i = col; i < col + width; ++i )
  4573. {
  4574. d->cells.clearColumn( _xshift + i );
  4575. d->columns.removeElement( _xshift + i );
  4576. }
  4577. }
  4578. // Insert column formats
  4579. TQDomElement c = e.firstChild().toElement();
  4580. for ( ; !c.isNull(); c = c.nextSibling().toElement() )
  4581. {
  4582. if ( c.tagName() == "column" )
  4583. {
  4584. ColumnFormat *cl = new ColumnFormat( this, 0 );
  4585. if ( cl->load( c, _xshift, mode, pasteFC ) )
  4586. insertColumnFormat( cl );
  4587. else
  4588. delete cl;
  4589. }
  4590. }
  4591. }
  4592. // entire rows given
  4593. if (e.tagName() == "rows" && !isProtected())
  4594. {
  4595. _xshift = 0;
  4596. // Clear the existing rows
  4597. int row = e.attribute("row").toInt();
  4598. int height = e.attribute("count").toInt();
  4599. if ( !insert )
  4600. {
  4601. for( int i = row; i < row + height; ++i )
  4602. {
  4603. d->cells.clearRow( _yshift + i );
  4604. d->rows.removeElement( _yshift + i );
  4605. }
  4606. }
  4607. // Insert row formats
  4608. TQDomElement c = e.firstChild().toElement();
  4609. for( ; !c.isNull(); c = c.nextSibling().toElement() )
  4610. {
  4611. if ( c.tagName() == "row" )
  4612. {
  4613. RowFormat *cl = new RowFormat( this, 0 );
  4614. if ( cl->load( c, _yshift, mode, pasteFC ) )
  4615. insertRowFormat( cl );
  4616. else
  4617. delete cl;
  4618. }
  4619. }
  4620. }
  4621. Cell* refreshCell = 0;
  4622. Cell *cell;
  4623. Cell *cellBackup = NULL;
  4624. if (e.tagName() == "cell")
  4625. {
  4626. int row = e.attribute( "row" ).toInt() + _yshift;
  4627. int col = e.attribute( "column" ).toInt() + _xshift;
  4628. // tile the selection with the clipboard contents
  4629. for (int roff = 0; row + roff - _yshift <= pasteHeight; roff += rowsInClpbrd)
  4630. {
  4631. for (int coff = 0; col + coff - _xshift <= pasteWidth; coff += columnsInClpbrd)
  4632. {
  4633. // kdDebug() << "loadSelection: cell at " << (col+coff) << "," << (row+roff)
  4634. // << " with roff,coff= " << roff << "," << coff
  4635. // << ", _xshift: " << _xshift << ", _yshift: " << _yshift << endl;
  4636. cell = nonDefaultCell( col + coff, row + roff );
  4637. if (isProtected() && !cell->format()->notProtected(col + coff, row + roff))
  4638. {
  4639. continue;
  4640. }
  4641. cellBackup = new Cell(this, cell->column(), cell->row());
  4642. cellBackup->copyAll(cell);
  4643. if (!cell->load(e, _xshift + coff, _yshift + roff, mode, operation, pasteFC))
  4644. {
  4645. cell->copyAll(cellBackup);
  4646. }
  4647. else
  4648. {
  4649. if (cell->isFormula())
  4650. {
  4651. cell->setCalcDirtyFlag();
  4652. }
  4653. }
  4654. delete cellBackup;
  4655. cell = cellAt( col + coff, row + roff );
  4656. if( !refreshCell && cell->updateChart( false ) )
  4657. {
  4658. refreshCell = cell;
  4659. }
  4660. }
  4661. }
  4662. }
  4663. //refresh chart after that you paste all cells
  4664. /* I don't think this is gonna work....doesn't this only update
  4665. one chart -- the one which had a dependant cell update first? - John
  4666. I don't have time to check on this now....
  4667. */
  4668. if ( refreshCell )
  4669. refreshCell->updateChart();
  4670. }
  4671. this->doc()->setModified( true );
  4672. if (!isLoading())
  4673. refreshMergedCell();
  4674. emit sig_updateView( this );
  4675. emit sig_updateHBorder( this );
  4676. emit sig_updateVBorder( this );
  4677. return true;
  4678. }
  4679. void Sheet::loadSelectionUndo(const TQDomDocument& d, const TQRect& loadArea,
  4680. int _xshift, int _yshift,
  4681. bool insert, int insertTo)
  4682. {
  4683. TQDomElement root = d.documentElement(); // "spreadsheet-snippet"
  4684. int rowsInClpbrd = root.attribute( "rows" ).toInt();
  4685. int columnsInClpbrd = root.attribute( "columns" ).toInt();
  4686. // find rect that we paste to
  4687. const int pasteWidth = (loadArea.width() >= columnsInClpbrd &&
  4688. util_isRowSelected(loadArea) == false &&
  4689. root.namedItem( "rows" ).toElement().isNull())
  4690. ? loadArea.width() : columnsInClpbrd;
  4691. const int pasteHeight = (loadArea.height() >= rowsInClpbrd &&
  4692. util_isColumnSelected(loadArea) == false &&
  4693. root.namedItem( "columns" ).toElement().isNull())
  4694. ? loadArea.height() : rowsInClpbrd;
  4695. uint numCols = 0;
  4696. uint numRows = 0;
  4697. Region region;
  4698. for (TQDomNode n = root.firstChild(); !n.isNull(); n = n.nextSibling())
  4699. {
  4700. TQDomElement e = n.toElement(); // "columns", "rows" or "cell"
  4701. if (e.tagName() == "columns")
  4702. {
  4703. _yshift = 0;
  4704. int col = e.attribute("column").toInt();
  4705. int width = e.attribute("count").toInt();
  4706. for (int coff = 0; col + coff <= pasteWidth; coff += columnsInClpbrd)
  4707. {
  4708. uint overlap = TQMAX(0, (col - 1 + coff + width) - pasteWidth);
  4709. uint effWidth = width - overlap;
  4710. region.add(TQRect(_xshift + col + coff, 1, effWidth, KS_rowMax));
  4711. numCols += effWidth;
  4712. }
  4713. }
  4714. else if (e.tagName() == "rows")
  4715. {
  4716. _xshift = 0;
  4717. int row = e.attribute("row").toInt();
  4718. int height = e.attribute("count").toInt();
  4719. for (int roff = 0; row + roff <= pasteHeight; roff += rowsInClpbrd)
  4720. {
  4721. uint overlap = TQMAX(0, (row - 1 + roff + height) - pasteHeight);
  4722. uint effHeight = height - overlap;
  4723. region.add(TQRect(1, _yshift + row + roff, KS_colMax, effHeight));
  4724. numRows += effHeight;
  4725. }
  4726. }
  4727. else if (!e.isNull())
  4728. {
  4729. // store the cols/rows for the insertion
  4730. int col = e.attribute("column").toInt();
  4731. int row = e.attribute("row").toInt();
  4732. for (int coff = 0; col + coff <= pasteWidth; coff += columnsInClpbrd)
  4733. {
  4734. for (int roff = 0; row + roff <= pasteHeight; roff += rowsInClpbrd)
  4735. {
  4736. region.add(TQPoint(_xshift + col + coff, _yshift + row + roff));
  4737. }
  4738. }
  4739. }
  4740. }
  4741. if (!doc()->undoLocked())
  4742. {
  4743. UndoCellPaste *undo = new UndoCellPaste( doc(), this, _xshift, _yshift, region, insert, insertTo );
  4744. doc()->addCommand( undo );
  4745. }
  4746. if (insert)
  4747. {
  4748. TQRect rect = region.boundingRect();
  4749. // shift cells to the right
  4750. if (insertTo == -1 && numCols == 0 && numRows == 0)
  4751. {
  4752. rect.setWidth(rect.width());
  4753. shiftRow(rect, false);
  4754. }
  4755. // shift cells to the bottom
  4756. else if (insertTo == 1 && numCols == 0 && numRows == 0)
  4757. {
  4758. rect.setHeight(rect.height());
  4759. shiftColumn( rect, false );
  4760. }
  4761. // insert columns
  4762. else if (insertTo == 0 && numCols == 0 && numRows > 0)
  4763. {
  4764. insertRow(rect.top(), rect.height() - 1, false);
  4765. }
  4766. // insert rows
  4767. else if (insertTo == 0 && numCols > 0 && numRows == 0)
  4768. {
  4769. insertColumn(rect.left(), rect.width() - 1, false);
  4770. }
  4771. }
  4772. }
  4773. bool Sheet::testAreaPasteInsert()const
  4774. {
  4775. TQMimeSource* mime = TQApplication::clipboard()->data( TQClipboard::Clipboard );
  4776. if ( !mime )
  4777. return false;
  4778. TQByteArray b;
  4779. if ( mime->provides( "application/x-kspread-snippet" ) )
  4780. b = mime->encodedData( "application/x-kspread-snippet" );
  4781. else
  4782. return false;
  4783. TQBuffer buffer( b );
  4784. buffer.open( IO_ReadOnly );
  4785. TQDomDocument d;
  4786. d.setContent( &buffer );
  4787. buffer.close();
  4788. TQDomElement e = d.documentElement();
  4789. if ( !e.namedItem( "columns" ).toElement().isNull() )
  4790. return false;
  4791. if ( !e.namedItem( "rows" ).toElement().isNull() )
  4792. return false;
  4793. TQDomElement c = e.firstChild().toElement();
  4794. for( ; !c.isNull(); c = c.nextSibling().toElement() )
  4795. {
  4796. if ( c.tagName() == "cell" )
  4797. return true;
  4798. }
  4799. return false;
  4800. }
  4801. void Sheet::deleteCells(const Region& region)
  4802. {
  4803. // A list of all cells we want to delete.
  4804. TQPtrStack<Cell> cellStack;
  4805. Region::ConstIterator endOfList = region.constEnd();
  4806. for (Region::ConstIterator it = region.constBegin(); it != endOfList; ++it)
  4807. {
  4808. TQRect range = (*it)->rect().normalize();
  4809. int right = range.right();
  4810. int left = range.left();
  4811. int bottom = range.bottom();
  4812. int col;
  4813. for ( int row = range.top(); row <= bottom; ++row )
  4814. {
  4815. Cell * c = getFirstCellRow( row );
  4816. while ( c )
  4817. {
  4818. col = c->column();
  4819. if ( col < left )
  4820. {
  4821. c = getNextCellRight( left - 1, row );
  4822. continue;
  4823. }
  4824. if ( col > right )
  4825. break;
  4826. if ( !c->isDefault() )
  4827. cellStack.push( c );
  4828. c = getNextCellRight( col, row );
  4829. }
  4830. }
  4831. }
  4832. d->cells.setAutoDelete( false );
  4833. // Remove the cells from the sheet
  4834. while ( !cellStack.isEmpty() )
  4835. {
  4836. Cell * cell = cellStack.pop();
  4837. d->cells.remove( cell->column(), cell->row() );
  4838. cell->setCalcDirtyFlag();
  4839. setRegionPaintDirty(cell->cellRect());
  4840. delete cell;
  4841. }
  4842. d->cells.setAutoDelete( true );
  4843. setLayoutDirtyFlag();
  4844. // TODO: don't go through all cells here!
  4845. // Since obscured cells might have been deleted we
  4846. // have to reenforce it.
  4847. Cell * c = d->cells.firstCell();
  4848. for( ;c; c = c->nextCell() )
  4849. {
  4850. if ( c->doesMergeCells() && !c->isDefault() )
  4851. c->mergeCells( c->column(), c->row(),
  4852. c->extraXCells(), c->extraYCells() );
  4853. }
  4854. doc()->setModified( true );
  4855. }
  4856. void Sheet::deleteSelection( Selection* selectionInfo, bool undo )
  4857. {
  4858. if ( undo && !doc()->undoLocked() )
  4859. {
  4860. UndoDelete *undo = new UndoDelete( doc(), this, *selectionInfo );
  4861. doc()->addCommand( undo );
  4862. }
  4863. Region::ConstIterator endOfList = selectionInfo->constEnd();
  4864. for (Region::ConstIterator it = selectionInfo->constBegin(); it != endOfList; ++it)
  4865. {
  4866. TQRect range = (*it)->rect().normalize();
  4867. // Entire rows selected ?
  4868. if ( util_isRowSelected(range) )
  4869. {
  4870. for( int i = range.top(); i <= range.bottom(); ++i )
  4871. {
  4872. d->cells.clearRow( i );
  4873. d->rows.removeElement( i );
  4874. }
  4875. emit sig_updateVBorder( this );
  4876. }
  4877. // Entire columns selected ?
  4878. else if ( util_isColumnSelected(range) )
  4879. {
  4880. for( int i = range.left(); i <= range.right(); ++i )
  4881. {
  4882. d->cells.clearColumn( i );
  4883. d->columns.removeElement( i );
  4884. }
  4885. emit sig_updateHBorder( this );
  4886. }
  4887. else
  4888. {
  4889. setRegionPaintDirty( range );
  4890. deleteCells( range );
  4891. }
  4892. }
  4893. refreshMergedCell();
  4894. emit sig_updateView( this );
  4895. }
  4896. void Sheet::updateView()
  4897. {
  4898. emit sig_updateView( this );
  4899. }
  4900. void Sheet::updateView( TQRect const & rect )
  4901. {
  4902. emit sig_updateView( this, rect );
  4903. }
  4904. void Sheet::updateView(Region* region)
  4905. {
  4906. emit sig_updateView( this, *region );
  4907. }
  4908. void Sheet::refreshView( const Region& region )
  4909. {
  4910. Region tmpRegion;
  4911. Region::ConstIterator endOfList = region.constEnd();
  4912. for (Region::ConstIterator it = region.constBegin(); it != endOfList; ++it)
  4913. {
  4914. TQRect range = (*it)->rect().normalize();
  4915. // TODO: don't go through all cells when refreshing!
  4916. TQRect tmp(range);
  4917. Cell * c = d->cells.firstCell();
  4918. for( ;c; c = c->nextCell() )
  4919. {
  4920. if ( !c->isDefault() &&
  4921. c->row() >= range.top() && c->row() <= range.bottom() &&
  4922. c->column() >= range.left() && c->column() <= range.right() )
  4923. {
  4924. if (c->doesMergeCells())
  4925. {
  4926. int right=TQMAX(tmp.right(),c->column()+c->extraXCells());
  4927. int bottom=TQMAX(tmp.bottom(),c->row()+c->extraYCells());
  4928. tmp.setRight(right);
  4929. tmp.setBottom(bottom);
  4930. }
  4931. }
  4932. }
  4933. deleteCells( range );
  4934. tmpRegion.add(tmp);
  4935. }
  4936. emit sig_updateView( this, tmpRegion );
  4937. }
  4938. void Sheet::mergeCells(const Region& region, bool hor, bool ver)
  4939. {
  4940. // sanity check
  4941. if( isProtected() )
  4942. return;
  4943. if( workbook()->isProtected() )
  4944. return;
  4945. MergeManipulator* manipulator = new MergeManipulator();
  4946. manipulator->setSheet(this);
  4947. manipulator->setHorizontalMerge(hor);
  4948. manipulator->setVerticalMerge(ver);
  4949. manipulator->add(region);
  4950. manipulator->execute();
  4951. }
  4952. void Sheet::dissociateCells(const Region& region)
  4953. {
  4954. // sanity check
  4955. if( isProtected() )
  4956. return;
  4957. if( workbook()->isProtected() )
  4958. return;
  4959. Manipulator* manipulator = new MergeManipulator();
  4960. manipulator->setSheet(this);
  4961. manipulator->setReverse(true);
  4962. manipulator->add(region);
  4963. manipulator->execute();
  4964. }
  4965. bool Sheet::testListChoose(Selection* selectionInfo)
  4966. {
  4967. TQRect selection( selectionInfo->selection() );
  4968. TQPoint marker( selectionInfo->marker() );
  4969. Cell *cell = cellAt( marker.x(), marker.y() );
  4970. TQString tmp=cell->text();
  4971. Cell* c = firstCell();
  4972. bool different=false;
  4973. int col;
  4974. for( ;c; c = c->nextCell() )
  4975. {
  4976. col = c->column();
  4977. if ( selection.left() <= col && selection.right() >= col &&
  4978. !c->isPartOfMerged() &&
  4979. !(col==marker.x() && c->row()==marker.y()))
  4980. {
  4981. if(!c->isFormula() && !c->value().isNumber() && !c->value().asString().isEmpty()
  4982. && !c->isTime() &&!c->isDate() )
  4983. {
  4984. if(c->text()!=tmp)
  4985. different=true;
  4986. }
  4987. }
  4988. }
  4989. return different;
  4990. }
  4991. TQDomDocument Sheet::saveCellRegion(const Region& region, bool copy, bool era)
  4992. {
  4993. TQDomDocument dd( "spreadsheet-snippet" );
  4994. dd.appendChild( dd.createProcessingInstruction( "xml", "version=\"1.0\" encoding=\"UTF-8\"" ) );
  4995. TQDomElement root = dd.createElement( "spreadsheet-snippet" );
  4996. dd.appendChild(root);
  4997. // find the upper left corner of the selection
  4998. TQRect boundingRect = region.boundingRect();
  4999. int left = boundingRect.left();
  5000. int top = boundingRect.top();
  5001. // for tiling the clipboard content in the selection
  5002. root.setAttribute( "rows", boundingRect.height() );
  5003. root.setAttribute( "columns", boundingRect.width() );
  5004. Region::ConstIterator endOfList = region.constEnd();
  5005. for (Region::ConstIterator it = region.constBegin(); it != endOfList; ++it)
  5006. {
  5007. TQRect range = (*it)->rect().normalize();
  5008. //
  5009. // Entire rows selected?
  5010. //
  5011. if ((*it)->isRow())
  5012. {
  5013. TQDomElement rows = dd.createElement("rows");
  5014. rows.setAttribute( "count", range.height() );
  5015. rows.setAttribute( "row", range.top() - top + 1 );
  5016. root.appendChild( rows );
  5017. // Save all cells.
  5018. for (Cell* cell = d->cells.firstCell(); cell; cell = cell->nextCell())
  5019. {
  5020. if (!cell->isDefault() && !cell->isPartOfMerged())
  5021. {
  5022. TQPoint point(cell->column(), cell->row());
  5023. if (range.contains(point))
  5024. {
  5025. root.appendChild(cell->save( dd, 0, top - 1, copy, copy, era));
  5026. }
  5027. }
  5028. }
  5029. // ##### Inefficient
  5030. // Save the row formats if there are any
  5031. RowFormat* format;
  5032. for (int row = range.top(); row <= range.bottom(); ++row)
  5033. {
  5034. format = rowFormat( row );
  5035. if (format && !format->isDefault())
  5036. {
  5037. TQDomElement e = format->save(dd, top - 1, copy);
  5038. if (!e.isNull())
  5039. {
  5040. rows.appendChild( e );
  5041. }
  5042. }
  5043. }
  5044. continue;
  5045. }
  5046. //
  5047. // Entire columns selected?
  5048. //
  5049. if ((*it)->isColumn())
  5050. {
  5051. TQDomElement columns = dd.createElement("columns");
  5052. columns.setAttribute( "count", range.width() );
  5053. columns.setAttribute( "column", range.left() - left + 1 );
  5054. root.appendChild( columns );
  5055. // Save all cells.
  5056. for (Cell* cell = d->cells.firstCell();cell; cell = cell->nextCell())
  5057. {
  5058. if (!cell->isDefault() && !cell->isPartOfMerged())
  5059. {
  5060. TQPoint point(cell->column(), cell->row());
  5061. if (range.contains(point))
  5062. {
  5063. root.appendChild(cell->save( dd, left - 1, 0, copy, copy, era));
  5064. }
  5065. }
  5066. }
  5067. // ##### Inefficient
  5068. // Save the column formats if there are any
  5069. ColumnFormat* format;
  5070. for (int col = range.left(); col <= range.right(); ++col)
  5071. {
  5072. format = columnFormat(col);
  5073. if (format && !format->isDefault())
  5074. {
  5075. TQDomElement e = format->save(dd, left - 1, copy);
  5076. if (!e.isNull())
  5077. {
  5078. columns.appendChild(e);
  5079. }
  5080. }
  5081. }
  5082. continue;
  5083. }
  5084. // Save all cells.
  5085. //store all cell
  5086. //when they don't exist we created them
  5087. //because it's necessary when there is a format on a column/row
  5088. //but I remove cell which is inserted.
  5089. Cell* cell;
  5090. bool insert;
  5091. enableScrollBarUpdates(false);
  5092. for (int col = range.left(); col <= range.right(); ++col)
  5093. {
  5094. for (int row = range.top(); row <= range.bottom(); ++row)
  5095. {
  5096. insert = false;
  5097. cell = cellAt(col, row);
  5098. if (cell == d->defaultCell)
  5099. {
  5100. cell = new Cell(this, col, row);
  5101. insertCell(cell);
  5102. insert = true;
  5103. }
  5104. root.appendChild(cell->save(dd, left - 1, top - 1, true, copy, era));
  5105. if (insert)
  5106. {
  5107. d->cells.remove(col, row);
  5108. }
  5109. }
  5110. }
  5111. enableScrollBarUpdates(true);
  5112. }
  5113. return dd;
  5114. }
  5115. TQDomElement Sheet::saveXML( TQDomDocument& dd )
  5116. {
  5117. TQDomElement sheet = dd.createElement( "table" );
  5118. sheet.setAttribute( "name", d->name );
  5119. //Laurent: for oasis format I think that we must use style:direction...
  5120. sheet.setAttribute( "layoutDirection", (d->layoutDirection == RightToLeft) ? "rtl" : "ltr" );
  5121. sheet.setAttribute( "columnnumber", (int)d->showColumnNumber);
  5122. sheet.setAttribute( "borders", (int)d->showPageBorders);
  5123. sheet.setAttribute( "hide", (int)d->hide);
  5124. sheet.setAttribute( "hidezero", (int)d->hideZero);
  5125. sheet.setAttribute( "firstletterupper", (int)d->firstLetterUpper);
  5126. sheet.setAttribute( "grid", (int)d->showGrid );
  5127. sheet.setAttribute( "printGrid", (int)d->print->printGrid() );
  5128. sheet.setAttribute( "printCommentIndicator", (int)d->print->printCommentIndicator() );
  5129. sheet.setAttribute( "printFormulaIndicator", (int)d->print->printFormulaIndicator() );
  5130. sheet.setAttribute( "showFormula", (int)d->showFormula);
  5131. sheet.setAttribute( "showFormulaIndicator", (int)d->showFormulaIndicator);
  5132. sheet.setAttribute( "showCommentIndicator", (int)d->showCommentIndicator);
  5133. sheet.setAttribute( "lcmode", (int)d->lcMode);
  5134. sheet.setAttribute( "autoCalc", (int)d->autoCalc);
  5135. sheet.setAttribute( "borders1.2", 1);
  5136. if ( !d->password.isNull() )
  5137. {
  5138. if ( d->password.size() > 0 )
  5139. {
  5140. TQCString str = KCodecs::base64Encode( d->password );
  5141. sheet.setAttribute( "protected", TQString( str.data() ) );
  5142. }
  5143. else
  5144. sheet.setAttribute( "protected", "" );
  5145. }
  5146. // paper parameters
  5147. TQDomElement paper = dd.createElement( "paper" );
  5148. paper.setAttribute( "format", d->print->paperFormatString() );
  5149. paper.setAttribute( "orientation", d->print->orientationString() );
  5150. sheet.appendChild( paper );
  5151. TQDomElement borders = dd.createElement( "borders" );
  5152. borders.setAttribute( "left", d->print->leftBorder() );
  5153. borders.setAttribute( "top", d->print->topBorder() );
  5154. borders.setAttribute( "right", d->print->rightBorder() );
  5155. borders.setAttribute( "bottom", d->print->bottomBorder() );
  5156. paper.appendChild( borders );
  5157. TQDomElement head = dd.createElement( "head" );
  5158. paper.appendChild( head );
  5159. if ( !d->print->headLeft().isEmpty() )
  5160. {
  5161. TQDomElement left = dd.createElement( "left" );
  5162. head.appendChild( left );
  5163. left.appendChild( dd.createTextNode( d->print->headLeft() ) );
  5164. }
  5165. if ( !d->print->headMid().isEmpty() )
  5166. {
  5167. TQDomElement center = dd.createElement( "center" );
  5168. head.appendChild( center );
  5169. center.appendChild( dd.createTextNode( d->print->headMid() ) );
  5170. }
  5171. if ( !d->print->headRight().isEmpty() )
  5172. {
  5173. TQDomElement right = dd.createElement( "right" );
  5174. head.appendChild( right );
  5175. right.appendChild( dd.createTextNode( d->print->headRight() ) );
  5176. }
  5177. TQDomElement foot = dd.createElement( "foot" );
  5178. paper.appendChild( foot );
  5179. if ( !d->print->footLeft().isEmpty() )
  5180. {
  5181. TQDomElement left = dd.createElement( "left" );
  5182. foot.appendChild( left );
  5183. left.appendChild( dd.createTextNode( d->print->footLeft() ) );
  5184. }
  5185. if ( !d->print->footMid().isEmpty() )
  5186. {
  5187. TQDomElement center = dd.createElement( "center" );
  5188. foot.appendChild( center );
  5189. center.appendChild( dd.createTextNode( d->print->footMid() ) );
  5190. }
  5191. if ( !d->print->footRight().isEmpty() )
  5192. {
  5193. TQDomElement right = dd.createElement( "right" );
  5194. foot.appendChild( right );
  5195. right.appendChild( dd.createTextNode( d->print->footRight() ) );
  5196. }
  5197. // print range
  5198. TQDomElement printrange = dd.createElement( "printrange-rect" );
  5199. TQRect _printRange = d->print->printRange();
  5200. int left = _printRange.left();
  5201. int right = _printRange.right();
  5202. int top = _printRange.top();
  5203. int bottom = _printRange.bottom();
  5204. //If whole rows are selected, then we store zeros, as KS_colMax may change in future
  5205. if ( left == 1 && right == KS_colMax )
  5206. {
  5207. left = 0;
  5208. right = 0;
  5209. }
  5210. //If whole columns are selected, then we store zeros, as KS_rowMax may change in future
  5211. if ( top == 1 && bottom == KS_rowMax )
  5212. {
  5213. top = 0;
  5214. bottom = 0;
  5215. }
  5216. printrange.setAttribute( "left-rect", left );
  5217. printrange.setAttribute( "right-rect", right );
  5218. printrange.setAttribute( "bottom-rect", bottom );
  5219. printrange.setAttribute( "top-rect", top );
  5220. sheet.appendChild( printrange );
  5221. // Print repeat columns
  5222. TQDomElement printRepeatColumns = dd.createElement( "printrepeatcolumns" );
  5223. printRepeatColumns.setAttribute( "left", d->print->printRepeatColumns().first );
  5224. printRepeatColumns.setAttribute( "right", d->print->printRepeatColumns().second );
  5225. sheet.appendChild( printRepeatColumns );
  5226. // Print repeat rows
  5227. TQDomElement printRepeatRows = dd.createElement( "printrepeatrows" );
  5228. printRepeatRows.setAttribute( "top", d->print->printRepeatRows().first );
  5229. printRepeatRows.setAttribute( "bottom", d->print->printRepeatRows().second );
  5230. sheet.appendChild( printRepeatRows );
  5231. //Save print zoom
  5232. sheet.setAttribute( "printZoom", d->print->zoom() );
  5233. //Save page limits
  5234. sheet.setAttribute( "printPageLimitX", d->print->pageLimitX() );
  5235. sheet.setAttribute( "printPageLimitY", d->print->pageLimitY() );
  5236. // Save all cells.
  5237. Cell* c = d->cells.firstCell();
  5238. for( ;c; c = c->nextCell() )
  5239. {
  5240. if ( !c->isDefault() )
  5241. {
  5242. TQDomElement e = c->save( dd );
  5243. if ( !e.isNull() )
  5244. sheet.appendChild( e );
  5245. }
  5246. }
  5247. // Save all RowFormat objects.
  5248. RowFormat* rl = d->rows.first();
  5249. for( ; rl; rl = rl->next() )
  5250. {
  5251. if ( !rl->isDefault() )
  5252. {
  5253. TQDomElement e = rl->save( dd );
  5254. if ( e.isNull() )
  5255. return TQDomElement();
  5256. sheet.appendChild( e );
  5257. }
  5258. }
  5259. // Save all ColumnFormat objects.
  5260. ColumnFormat* cl = d->columns.first();
  5261. for( ; cl; cl = cl->next() )
  5262. {
  5263. if ( !cl->isDefault() )
  5264. {
  5265. TQDomElement e = cl->save( dd );
  5266. if ( e.isNull() )
  5267. return TQDomElement();
  5268. sheet.appendChild( e );
  5269. }
  5270. }
  5271. TQPtrListIterator<EmbeddedObject> chl = doc()->embeddedObjects();
  5272. for( ; chl.current(); ++chl )
  5273. {
  5274. if ( chl.current()->sheet() == this )
  5275. {
  5276. TQDomElement e = chl.current()->save( dd );
  5277. if ( e.isNull() )
  5278. return TQDomElement();
  5279. sheet.appendChild( e );
  5280. }
  5281. }
  5282. return sheet;
  5283. }
  5284. bool Sheet::isLoading()
  5285. {
  5286. return doc()->isLoading();
  5287. }
  5288. TQPtrList<EmbeddedObject> Sheet::getSelectedObjects()
  5289. {
  5290. TQPtrList<EmbeddedObject> objects;
  5291. TQPtrListIterator<EmbeddedObject> it = doc()->embeddedObjects();
  5292. for ( ; it.current() ; ++it )
  5293. {
  5294. if( it.current()->isSelected()
  5295. && it.current()->sheet() == this )
  5296. {
  5297. objects.append( it.current() );
  5298. }
  5299. }
  5300. return objects;
  5301. }
  5302. KoRect Sheet::getRealRect( bool all )
  5303. {
  5304. KoRect rect;
  5305. TQPtrListIterator<EmbeddedObject> it( doc()->embeddedObjects() );
  5306. for ( ; it.current() ; ++it )
  5307. {
  5308. if ( all || ( it.current()->isSelected() && ! it.current()->isProtect() ) )
  5309. rect |= it.current()->geometry();
  5310. }
  5311. return rect;
  5312. }
  5313. // move object for releasemouseevent
  5314. KCommand *Sheet::moveObject(View *_view, double diffx, double diffy)
  5315. {
  5316. bool createCommand=false;
  5317. MoveObjectByCmd *moveByCmd=0L;
  5318. Canvas * canvas = _view->canvasWidget();
  5319. TQPtrList<EmbeddedObject> _objects;
  5320. _objects.setAutoDelete( false );
  5321. TQPtrListIterator<EmbeddedObject> it( doc()->embeddedObjects()/*m_objectList*/ );
  5322. for ( ; it.current() ; ++it )
  5323. {
  5324. if ( it.current()->isSelected() && !it.current()->isProtect())
  5325. {
  5326. _objects.append( it.current() );
  5327. KoRect geometry = it.current()->geometry();
  5328. geometry.moveBy( -canvas->xOffset(), -canvas->yOffset() );
  5329. TQRect br = doc()->zoomRect( geometry/*it.current()->geometry()*/ );
  5330. br.moveBy( doc()->zoomItX( diffx ), doc()->zoomItY( diffy ) );
  5331. br.moveBy( doc()->zoomItX( -canvas->xOffset() ), doc()->zoomItY( -canvas->yOffset() ) );
  5332. canvas->repaint( br ); // Previous position
  5333. canvas->repaintObject( it.current() ); // New position
  5334. createCommand=true;
  5335. }
  5336. }
  5337. if(createCommand) {
  5338. moveByCmd = new MoveObjectByCmd( i18n( "Move Objects" ), KoPoint( diffx, diffy ),
  5339. _objects, doc(), this );
  5340. // m_doc->updateSideBarItem( this );
  5341. }
  5342. return moveByCmd;
  5343. }
  5344. KCommand *Sheet::moveObject(View *_view,const KoPoint &_move,bool key)
  5345. {
  5346. TQPtrList<EmbeddedObject> _objects;
  5347. _objects.setAutoDelete( false );
  5348. MoveObjectByCmd *moveByCmd=0L;
  5349. Canvas * canvas = _view->canvasWidget();
  5350. TQPtrListIterator<EmbeddedObject> it( doc()->embeddedObjects()/*m_objectList*/ );
  5351. for ( ; it.current() ; ++it )
  5352. {
  5353. if ( it.current()->isSelected() && !it.current()->isProtect()) {
  5354. KoRect geometry = it.current()->geometry();
  5355. geometry.moveBy( -canvas->xOffset(), -canvas->yOffset() );
  5356. TQRect oldBoundingRect = doc()->zoomRect( geometry );
  5357. KoRect r = it.current()->geometry();
  5358. r.moveBy( _move.x(), _move.y() );
  5359. it.current()->setGeometry( r );
  5360. _objects.append( it.current() );
  5361. canvas->repaint( oldBoundingRect );
  5362. canvas->repaintObject( it.current() );
  5363. }
  5364. }
  5365. if ( key && !_objects.isEmpty())
  5366. moveByCmd = new MoveObjectByCmd( i18n( "Move Objects" ),
  5367. KoPoint( _move ),
  5368. _objects, doc() ,this );
  5369. return moveByCmd;
  5370. }
  5371. /*
  5372. * Check if object name already exists.
  5373. */
  5374. bool Sheet::objectNameExists( EmbeddedObject *object, TQPtrList<EmbeddedObject> &list ) {
  5375. TQPtrListIterator<EmbeddedObject> it( list );
  5376. for ( it.toFirst(); it.current(); ++it ) {
  5377. // object name can exist in current object.
  5378. if ( it.current()->getObjectName() == object->getObjectName() &&
  5379. it.current() != object ) {
  5380. return true;
  5381. }
  5382. }
  5383. return false;
  5384. }
  5385. void Sheet::unifyObjectName( EmbeddedObject *object ) {
  5386. if ( object->getObjectName().isEmpty() ) {
  5387. object->setObjectName( object->getTypeString() );
  5388. }
  5389. TQString objectName( object->getObjectName() );
  5390. TQPtrList<EmbeddedObject> list( doc()->embeddedObjects() );
  5391. int count = 1;
  5392. while ( objectNameExists( object, list ) ) {
  5393. count++;
  5394. TQRegExp rx( " \\(\\d{1,3}\\)$" );
  5395. if ( rx.search( objectName ) != -1 ) {
  5396. objectName.remove( rx );
  5397. }
  5398. objectName += TQString(" (%1)").arg( count );
  5399. object->setObjectName( objectName );
  5400. }
  5401. }
  5402. void Sheet::checkContentDirection( TQString const & name )
  5403. {
  5404. /* set sheet's direction to RTL if sheet name is an RTL string */
  5405. if ( (name.isRightToLeft()) )
  5406. setLayoutDirection( RightToLeft );
  5407. else
  5408. setLayoutDirection( LeftToRight );
  5409. emit sig_refreshView();
  5410. }
  5411. bool Sheet::loadSheetStyleFormat( TQDomElement *style )
  5412. {
  5413. TQString hleft, hmiddle, hright;
  5414. TQString fleft, fmiddle, fright;
  5415. TQDomNode header = KoDom::namedItemNS( *style, KoXmlNS::style, "header" );
  5416. if ( !header.isNull() )
  5417. {
  5418. kdDebug() << "Header exists" << endl;
  5419. TQDomNode part = KoDom::namedItemNS( header, KoXmlNS::style, "region-left" );
  5420. if ( !part.isNull() )
  5421. {
  5422. hleft = getPart( part );
  5423. kdDebug() << "Header left: " << hleft << endl;
  5424. }
  5425. else
  5426. kdDebug() << "Style:region:left doesn't exist!" << endl;
  5427. part = KoDom::namedItemNS( header, KoXmlNS::style, "region-center" );
  5428. if ( !part.isNull() )
  5429. {
  5430. hmiddle = getPart( part );
  5431. kdDebug() << "Header middle: " << hmiddle << endl;
  5432. }
  5433. part = KoDom::namedItemNS( header, KoXmlNS::style, "region-right" );
  5434. if ( !part.isNull() )
  5435. {
  5436. hright = getPart( part );
  5437. kdDebug() << "Header right: " << hright << endl;
  5438. }
  5439. }
  5440. //TODO implement it under kspread
  5441. TQDomNode headerleft = KoDom::namedItemNS( *style, KoXmlNS::style, "header-left" );
  5442. if ( !headerleft.isNull() )
  5443. {
  5444. TQDomElement e = headerleft.toElement();
  5445. if ( e.hasAttributeNS( KoXmlNS::style, "display" ) )
  5446. kdDebug()<<"header.hasAttribute( style:display ) :"<<e.hasAttributeNS( KoXmlNS::style, "display" )<<endl;
  5447. else
  5448. kdDebug()<<"header left doesn't has attribute style:display \n";
  5449. }
  5450. //TODO implement it under kspread
  5451. TQDomNode footerleft = KoDom::namedItemNS( *style, KoXmlNS::style, "footer-left" );
  5452. if ( !footerleft.isNull() )
  5453. {
  5454. TQDomElement e = footerleft.toElement();
  5455. if ( e.hasAttributeNS( KoXmlNS::style, "display" ) )
  5456. kdDebug()<<"footer.hasAttribute( style:display ) :"<<e.hasAttributeNS( KoXmlNS::style, "display" )<<endl;
  5457. else
  5458. kdDebug()<<"footer left doesn't has attribute style:display \n";
  5459. }
  5460. TQDomNode footer = KoDom::namedItemNS( *style, KoXmlNS::style, "footer" );
  5461. if ( !footer.isNull() )
  5462. {
  5463. TQDomNode part = KoDom::namedItemNS( footer, KoXmlNS::style, "region-left" );
  5464. if ( !part.isNull() )
  5465. {
  5466. fleft = getPart( part );
  5467. kdDebug() << "Footer left: " << fleft << endl;
  5468. }
  5469. part = KoDom::namedItemNS( footer, KoXmlNS::style, "region-center" );
  5470. if ( !part.isNull() )
  5471. {
  5472. fmiddle = getPart( part );
  5473. kdDebug() << "Footer middle: " << fmiddle << endl;
  5474. }
  5475. part = KoDom::namedItemNS( footer, KoXmlNS::style, "region-right" );
  5476. if ( !part.isNull() )
  5477. {
  5478. fright = getPart( part );
  5479. kdDebug() << "Footer right: " << fright << endl;
  5480. }
  5481. }
  5482. print()->setHeadFootLine( hleft, hmiddle, hright,
  5483. fleft, fmiddle, fright );
  5484. return true;
  5485. }
  5486. void Sheet::replaceMacro( TQString & text, const TQString & old, const TQString & newS )
  5487. {
  5488. int n = text.find( old );
  5489. if ( n != -1 )
  5490. text = text.replace( n, old.length(), newS );
  5491. }
  5492. TQString Sheet::getPart( const TQDomNode & part )
  5493. {
  5494. TQString result;
  5495. TQDomElement e = KoDom::namedItemNS( part, KoXmlNS::text, "p" );
  5496. while ( !e.isNull() )
  5497. {
  5498. TQString text = e.text();
  5499. kdDebug() << "PART: " << text << endl;
  5500. TQDomElement macro = KoDom::namedItemNS( e, KoXmlNS::text, "time" );
  5501. if ( !macro.isNull() )
  5502. replaceMacro( text, macro.text(), "<time>" );
  5503. macro = KoDom::namedItemNS( e, KoXmlNS::text, "date" );
  5504. if ( !macro.isNull() )
  5505. replaceMacro( text, macro.text(), "<date>" );
  5506. macro = KoDom::namedItemNS( e, KoXmlNS::text, "page-number" );
  5507. if ( !macro.isNull() )
  5508. replaceMacro( text, macro.text(), "<page>" );
  5509. macro = KoDom::namedItemNS( e, KoXmlNS::text, "page-count" );
  5510. if ( !macro.isNull() )
  5511. replaceMacro( text, macro.text(), "<pages>" );
  5512. macro = KoDom::namedItemNS( e, KoXmlNS::text, "sheet-name" );
  5513. if ( !macro.isNull() )
  5514. replaceMacro( text, macro.text(), "<sheet>" );
  5515. macro = KoDom::namedItemNS( e, KoXmlNS::text, "title" );
  5516. if ( !macro.isNull() )
  5517. replaceMacro( text, macro.text(), "<name>" );
  5518. macro = KoDom::namedItemNS( e, KoXmlNS::text, "file-name" );
  5519. if ( !macro.isNull() )
  5520. replaceMacro( text, macro.text(), "<file>" );
  5521. //add support for multi line into kspread
  5522. if ( !result.isEmpty() )
  5523. result += '\n';
  5524. result += text;
  5525. e = e.nextSibling().toElement();
  5526. }
  5527. return result;
  5528. }
  5529. bool Sheet::loadOasis( const TQDomElement& sheetElement, KoOasisLoadingContext& oasisContext, TQDict<Style>& styleMap )
  5530. {
  5531. d->layoutDirection = LeftToRight;
  5532. if ( sheetElement.hasAttributeNS( KoXmlNS::table, "style-name" ) )
  5533. {
  5534. TQString stylename = sheetElement.attributeNS( KoXmlNS::table, "style-name", TQString() );
  5535. //kdDebug()<<" style of table :"<<stylename<<endl;
  5536. const TQDomElement *style = oasisContext.oasisStyles().findStyle( stylename, "table" );
  5537. Q_ASSERT( style );
  5538. //kdDebug()<<" style :"<<style<<endl;
  5539. if ( style )
  5540. {
  5541. TQDomElement properties( KoDom::namedItemNS( *style, KoXmlNS::style, "table-properties" ) );
  5542. if ( !properties.isNull() )
  5543. {
  5544. if ( properties.hasAttributeNS( KoXmlNS::table, "display" ) )
  5545. {
  5546. bool visible = (properties.attributeNS( KoXmlNS::table, "display", TQString() ) == "true" ? true : false );
  5547. d->hide = !visible;
  5548. }
  5549. }
  5550. if ( style->hasAttributeNS( KoXmlNS::style, "master-page-name" ) )
  5551. {
  5552. TQString masterPageStyleName = style->attributeNS( KoXmlNS::style, "master-page-name", TQString() );
  5553. //kdDebug()<<"style->attribute( style:master-page-name ) :"<<masterPageStyleName <<endl;
  5554. TQDomElement *masterStyle = oasisContext.oasisStyles().masterPages()[masterPageStyleName];
  5555. //kdDebug()<<"oasisStyles.styles()[masterPageStyleName] :"<<masterStyle<<endl;
  5556. if ( masterStyle )
  5557. {
  5558. loadSheetStyleFormat( masterStyle );
  5559. if ( masterStyle->hasAttributeNS( KoXmlNS::style, "page-layout-name" ) )
  5560. {
  5561. TQString masterPageLayoutStyleName = masterStyle->attributeNS( KoXmlNS::style, "page-layout-name", TQString() );
  5562. //kdDebug()<<"masterPageLayoutStyleName :"<<masterPageLayoutStyleName<<endl;
  5563. const TQDomElement *masterLayoutStyle = oasisContext.oasisStyles().findStyle( masterPageLayoutStyleName );
  5564. if ( masterLayoutStyle )
  5565. {
  5566. //kdDebug()<<"masterLayoutStyle :"<<masterLayoutStyle<<endl;
  5567. KoStyleStack styleStack;
  5568. styleStack.setTypeProperties( "page-layout" );
  5569. styleStack.push( *masterLayoutStyle );
  5570. loadOasisMasterLayoutPage( styleStack );
  5571. }
  5572. }
  5573. }
  5574. }
  5575. }
  5576. }
  5577. //Maps from a column index to the name of the default cell style for that column
  5578. TQMap<int,TQString> defaultColumnCellStyles;
  5579. int rowIndex = 1;
  5580. int indexCol = 1;
  5581. TQDomNode rowNode = sheetElement.firstChild();
  5582. // Some spreadsheet programs may support more rows than
  5583. // KSpread so limit the number of repeated rows.
  5584. // FIXME POSSIBLE DATA LOSS!
  5585. while( !rowNode.isNull() && rowIndex <= KS_rowMax )
  5586. {
  5587. kdDebug()<<" rowIndex :"<<rowIndex<<" indexCol :"<<indexCol<<endl;
  5588. TQDomElement rowElement = rowNode.toElement();
  5589. if( !rowElement.isNull() )
  5590. {
  5591. kdDebug()<<" Sheet::loadOasis rowElement.tagName() :"<<rowElement.localName()<<endl;
  5592. if ( rowElement.namespaceURI() == KoXmlNS::table )
  5593. {
  5594. if ( rowElement.localName()=="table-column" && indexCol <= KS_colMax )
  5595. {
  5596. kdDebug ()<<" table-column found : index column before "<< indexCol<<endl;
  5597. loadColumnFormat( rowElement, oasisContext.oasisStyles(), indexCol , styleMap);
  5598. kdDebug ()<<" table-column found : index column after "<< indexCol<<endl;
  5599. }
  5600. else if ( rowElement.localName() == "table-header-rows" )
  5601. {
  5602. TQDomNode headerRowNode = rowElement.firstChild();
  5603. while ( !headerRowNode.isNull() )
  5604. {
  5605. // NOTE Handle header rows as ordinary ones
  5606. // as long as they're not supported.
  5607. loadRowFormat( headerRowNode.toElement(), rowIndex,
  5608. oasisContext, /*rowNode.isNull() ,*/ styleMap );
  5609. headerRowNode = headerRowNode.nextSibling();
  5610. }
  5611. }
  5612. else if( rowElement.localName() == "table-row" )
  5613. {
  5614. kdDebug()<<" table-row found :index row before "<<rowIndex<<endl;
  5615. loadRowFormat( rowElement, rowIndex, oasisContext, /*rowNode.isNull() ,*/ styleMap );
  5616. kdDebug()<<" table-row found :index row after "<<rowIndex<<endl;
  5617. }
  5618. else if ( rowElement.localName() == "shapes" )
  5619. loadOasisObjects( rowElement, oasisContext );
  5620. }
  5621. }
  5622. rowNode = rowNode.nextSibling();
  5623. }
  5624. if ( sheetElement.hasAttributeNS( KoXmlNS::table, "print-ranges" ) )
  5625. {
  5626. // e.g.: Sheet4.A1:Sheet4.E28
  5627. TQString range = sheetElement.attributeNS( KoXmlNS::table, "print-ranges", TQString() );
  5628. range = Oasis::decodeFormula( range );
  5629. Range p( range );
  5630. if ( sheetName() == p.sheetName() )
  5631. d->print->setPrintRange( p.range() );
  5632. }
  5633. if ( sheetElement.attributeNS( KoXmlNS::table, "protected", TQString() ) == "true" )
  5634. {
  5635. TQCString passwd( "" );
  5636. if ( sheetElement.hasAttributeNS( KoXmlNS::table, "protection-key" ) )
  5637. {
  5638. TQString p = sheetElement.attributeNS( KoXmlNS::table, "protection-key", TQString() );
  5639. TQCString str( p.latin1() );
  5640. kdDebug(30518) << "Decoding password: " << str << endl;
  5641. passwd = KCodecs::base64Decode( str );
  5642. }
  5643. kdDebug(30518) << "Password hash: '" << passwd << "'" << endl;
  5644. d->password = passwd;
  5645. }
  5646. return true;
  5647. }
  5648. void Sheet::loadOasisObjects( const TQDomElement &parent, KoOasisLoadingContext& oasisContext )
  5649. {
  5650. TQDomElement e;
  5651. TQDomNode n = parent.firstChild();
  5652. while( !n.isNull() )
  5653. {
  5654. e = n.toElement();
  5655. if ( e.localName() == "frame" && e.namespaceURI() == KoXmlNS::draw )
  5656. {
  5657. EmbeddedObject *obj = 0;
  5658. TQDomNode object = KoDom::namedItemNS( e, KoXmlNS::draw, "object" );
  5659. if ( !object.isNull() )
  5660. {
  5661. if ( !object.toElement().attributeNS( KoXmlNS::draw, "notify-on-update-of-ranges", TQString()).isNull() )
  5662. obj = new EmbeddedChart( doc(), this );
  5663. else
  5664. obj = new EmbeddedKOfficeObject( doc(), this );
  5665. }
  5666. else
  5667. {
  5668. TQDomNode image = KoDom::namedItemNS( e, KoXmlNS::draw, "image" );
  5669. if ( !image.isNull() )
  5670. obj = new EmbeddedPictureObject( this, doc()->pictureCollection() );
  5671. else
  5672. kdDebug() << "Object type wasn't loaded!" << endl;
  5673. }
  5674. if ( obj )
  5675. {
  5676. obj->loadOasis( e, oasisContext );
  5677. insertObject( obj );
  5678. }
  5679. }
  5680. n = n.nextSibling();
  5681. }
  5682. }
  5683. void Sheet::loadOasisMasterLayoutPage( KoStyleStack &styleStack )
  5684. {
  5685. // use A4 as default page size
  5686. float left = 20.0;
  5687. float right = 20.0;
  5688. float top = 20.0;
  5689. float bottom = 20.0;
  5690. float width = 210.0;
  5691. float height = 297.0;
  5692. TQString orientation = "Portrait";
  5693. TQString format;
  5694. // Laurent : Why we stored layout information as Millimeter ?!!!!!
  5695. // kspread used point for all other attribute
  5696. // I don't understand :(
  5697. if ( styleStack.hasAttributeNS( KoXmlNS::fo, "page-width" ) )
  5698. {
  5699. width = KoUnit::toMM(KoUnit::parseValue( styleStack.attributeNS( KoXmlNS::fo, "page-width" ) ) );
  5700. }
  5701. if ( styleStack.hasAttributeNS( KoXmlNS::fo, "page-height" ) )
  5702. {
  5703. height = KoUnit::toMM( KoUnit::parseValue( styleStack.attributeNS( KoXmlNS::fo, "page-height" ) ) );
  5704. }
  5705. if ( styleStack.hasAttributeNS( KoXmlNS::fo, "margin-top" ) )
  5706. {
  5707. top = KoUnit::toMM(KoUnit::parseValue( styleStack.attributeNS( KoXmlNS::fo, "margin-top" ) ) );
  5708. }
  5709. if ( styleStack.hasAttributeNS( KoXmlNS::fo, "margin-bottom" ) )
  5710. {
  5711. bottom = KoUnit::toMM(KoUnit::parseValue( styleStack.attributeNS( KoXmlNS::fo, "margin-bottom" ) ) );
  5712. }
  5713. if ( styleStack.hasAttributeNS( KoXmlNS::fo, "margin-left" ) )
  5714. {
  5715. left = KoUnit::toMM(KoUnit::parseValue( styleStack.attributeNS( KoXmlNS::fo, "margin-left" ) ) );
  5716. }
  5717. if ( styleStack.hasAttributeNS( KoXmlNS::fo, "margin-right" ) )
  5718. {
  5719. right = KoUnit::toMM(KoUnit::parseValue( styleStack.attributeNS( KoXmlNS::fo, "margin-right" ) ) );
  5720. }
  5721. if ( styleStack.hasAttributeNS( KoXmlNS::style, "writing-mode" ) )
  5722. {
  5723. kdDebug()<<"styleStack.hasAttribute( style:writing-mode ) :"<<styleStack.hasAttributeNS( KoXmlNS::style, "writing-mode" )<<endl;
  5724. d->layoutDirection = ( styleStack.attributeNS( KoXmlNS::style, "writing-mode" )=="lr-tb" ) ? LeftToRight : RightToLeft;
  5725. //TODO
  5726. //<value>lr-tb</value>
  5727. //<value>rl-tb</value>
  5728. //<value>tb-rl</value>
  5729. //<value>tb-lr</value>
  5730. //<value>lr</value>
  5731. //<value>rl</value>
  5732. //<value>tb</value>
  5733. //<value>page</value>
  5734. }
  5735. if ( styleStack.hasAttributeNS( KoXmlNS::style, "print-orientation" ) )
  5736. {
  5737. orientation = ( styleStack.attributeNS( KoXmlNS::style, "print-orientation" )=="landscape" ) ? "Landscape" : "Portrait" ;
  5738. }
  5739. if ( styleStack.hasAttributeNS( KoXmlNS::style, "num-format" ) )
  5740. {
  5741. //not implemented into kspread
  5742. //These attributes specify the numbering style to use.
  5743. //If a numbering style is not specified, the numbering style is inherited from
  5744. //the page style. See section 6.7.8 for information on these attributes
  5745. kdDebug()<<" num-format :"<<styleStack.attributeNS( KoXmlNS::style, "num-format" )<<endl;
  5746. }
  5747. if ( styleStack.hasAttributeNS( KoXmlNS::fo, "background-color" ) )
  5748. {
  5749. //TODO
  5750. kdDebug()<<" fo:background-color :"<<styleStack.attributeNS( KoXmlNS::fo, "background-color" )<<endl;
  5751. }
  5752. if ( styleStack.hasAttributeNS( KoXmlNS::style, "print" ) )
  5753. {
  5754. //todo parsing
  5755. TQString str = styleStack.attributeNS( KoXmlNS::style, "print" );
  5756. kdDebug()<<" style:print :"<<str<<endl;
  5757. if (str.contains( "headers" ) )
  5758. {
  5759. //TODO implement it into kspread
  5760. }
  5761. if ( str.contains( "grid" ) )
  5762. {
  5763. d->print->setPrintGrid( true );
  5764. }
  5765. if ( str.contains( "annotations" ) )
  5766. {
  5767. //TODO it's not implemented
  5768. }
  5769. if ( str.contains( "objects" ) )
  5770. {
  5771. //TODO it's not implemented
  5772. }
  5773. if ( str.contains( "charts" ) )
  5774. {
  5775. //TODO it's not implemented
  5776. }
  5777. if ( str.contains( "drawings" ) )
  5778. {
  5779. //TODO it's not implemented
  5780. }
  5781. if ( str.contains( "formulas" ) )
  5782. {
  5783. d->showFormula = true;
  5784. }
  5785. if ( str.contains( "zero-values" ) )
  5786. {
  5787. //TODO it's not implemented
  5788. }
  5789. }
  5790. if ( styleStack.hasAttributeNS( KoXmlNS::style, "table-centering" ) )
  5791. {
  5792. TQString str = styleStack.attributeNS( KoXmlNS::style, "table-centering" );
  5793. //TODO not implemented into kspread
  5794. kdDebug()<<" styleStack.attribute( style:table-centering ) :"<<str<<endl;
  5795. #if 0
  5796. if ( str == "horizontal" )
  5797. {
  5798. }
  5799. else if ( str == "vertical" )
  5800. {
  5801. }
  5802. else if ( str == "both" )
  5803. {
  5804. }
  5805. else if ( str == "none" )
  5806. {
  5807. }
  5808. else
  5809. kdDebug()<<" table-centering unknown :"<<str<<endl;
  5810. #endif
  5811. }
  5812. format = TQString( "%1x%2" ).arg( width ).arg( height );
  5813. kdDebug()<<" format : "<<format<<endl;
  5814. d->print->setPaperLayout( left, top, right, bottom, format, orientation );
  5815. kdDebug()<<" left margin :"<<left<<" right :"<<right<<" top :"<<top<<" bottom :"<<bottom<<endl;
  5816. //<style:properties fo:page-width="21.8cm" fo:page-height="28.801cm" fo:margin-top="2cm" fo:margin-bottom="2.799cm" fo:margin-left="1.3cm" fo:margin-right="1.3cm" style:writing-mode="lr-tb"/>
  5817. // TQString format = paper.attribute( "format" );
  5818. // TQString orientation = paper.attribute( "orientation" );
  5819. // d->print->setPaperLayout( left, top, right, bottom, format, orientation );
  5820. // }
  5821. }
  5822. bool Sheet::loadColumnFormat(const TQDomElement& column, const KoOasisStyles& oasisStyles, int & indexCol, const TQDict<Style>& styleMap)
  5823. {
  5824. kdDebug()<<"bool Sheet::loadColumnFormat(const TQDomElement& column, const KoOasisStyles& oasisStyles, unsigned int & indexCol ) index Col :"<<indexCol<<endl;
  5825. bool isNonDefaultColumn = false;
  5826. int number = 1;
  5827. if ( column.hasAttributeNS( KoXmlNS::table, "number-columns-repeated" ) )
  5828. {
  5829. bool ok = true;
  5830. int n = column.attributeNS( KoXmlNS::table, "number-columns-repeated", TQString() ).toInt( &ok );
  5831. if ( ok )
  5832. // Some spreadsheet programs may support more rows than KSpread so
  5833. // limit the number of repeated rows.
  5834. // FIXME POSSIBLE DATA LOSS!
  5835. number = TQMIN( n, KS_colMax - indexCol + 1 );
  5836. kdDebug() << "Repeated: " << number << endl;
  5837. }
  5838. Format layout( this , doc()->styleManager()->defaultStyle() );
  5839. if ( column.hasAttributeNS( KoXmlNS::table, "default-cell-style-name" ) )
  5840. {
  5841. const TQString styleName = column.attributeNS( KoXmlNS::table, "default-cell-style-name", TQString() );
  5842. if ( !styleName.isEmpty() )
  5843. {
  5844. Style* const style = styleMap[ styleName ];
  5845. if ( style )
  5846. {
  5847. layout.setStyle( style );
  5848. isNonDefaultColumn = true;
  5849. }
  5850. }
  5851. }
  5852. bool collapsed = false;
  5853. if ( column.hasAttributeNS( KoXmlNS::table, "visibility" ) )
  5854. {
  5855. const TQString visibility = column.attributeNS( KoXmlNS::table, "visibility", TQString() );
  5856. if ( visibility == "visible" )
  5857. collapsed = false;
  5858. else if ( visibility == "collapse" )
  5859. collapsed = true;
  5860. else if ( visibility == "filter" )
  5861. collapsed = false; // FIXME Stefan: Set to true, if filters are supported.
  5862. isNonDefaultColumn = true;
  5863. }
  5864. KoStyleStack styleStack;
  5865. if ( column.hasAttributeNS( KoXmlNS::table, "style-name" ) )
  5866. {
  5867. TQString str = column.attributeNS( KoXmlNS::table, "style-name", TQString() );
  5868. const TQDomElement *style = oasisStyles.findStyle( str, "table-column" );
  5869. if ( style )
  5870. {
  5871. styleStack.push( *style );
  5872. isNonDefaultColumn = true;
  5873. }
  5874. }
  5875. styleStack.setTypeProperties("table-column"); //style for column
  5876. double width = -1.0;
  5877. if ( styleStack.hasAttributeNS( KoXmlNS::style, "column-width" ) )
  5878. {
  5879. width = KoUnit::parseValue( styleStack.attributeNS( KoXmlNS::style, "column-width" ) , -1.0 );
  5880. kdDebug()<<" style:column-width : width :"<<width<<endl;
  5881. isNonDefaultColumn = true;
  5882. }
  5883. bool insertPageBreak = false;
  5884. if ( styleStack.hasAttributeNS( KoXmlNS::fo, "break-before" ) )
  5885. {
  5886. TQString str = styleStack.attributeNS( KoXmlNS::fo, "break-before" );
  5887. if ( str == "page" )
  5888. {
  5889. insertPageBreak = true;
  5890. }
  5891. else
  5892. kdDebug()<<" str :"<<str<<endl;
  5893. isNonDefaultColumn = true;
  5894. }
  5895. for ( int i = 0; i < number; ++i )
  5896. {
  5897. // kdDebug()<<" insert new column: pos :"<<indexCol<<" width :"<<width<<" hidden ? "<<collapsed<<endl;
  5898. ColumnFormat* columnFormat;
  5899. if ( isNonDefaultColumn )
  5900. {
  5901. columnFormat = nonDefaultColumnFormat( indexCol );
  5902. if ( width != -1.0 ) //safe
  5903. columnFormat->setWidth( (int) width );
  5904. // if ( insertPageBreak )
  5905. // columnFormat->setPageBreak( true )
  5906. if ( collapsed )
  5907. columnFormat->setHide( true );
  5908. }
  5909. else
  5910. {
  5911. columnFormat = this->columnFormat( indexCol );
  5912. }
  5913. columnFormat->copy( layout );
  5914. ++indexCol;
  5915. }
  5916. // kdDebug()<<" after index column !!!!!!!!!!!!!!!!!! :"<<indexCol<<endl;
  5917. return true;
  5918. }
  5919. bool Sheet::loadRowFormat( const TQDomElement& row, int &rowIndex, KoOasisLoadingContext& oasisContext, TQDict<Style>& styleMap )
  5920. {
  5921. // kdDebug()<<"Sheet::loadRowFormat( const TQDomElement& row, int &rowIndex,const KoOasisStyles& oasisStyles, bool isLast )***********\n";
  5922. int backupRow = rowIndex;
  5923. bool isNonDefaultRow = false;
  5924. KoStyleStack styleStack;
  5925. if ( row.hasAttributeNS( KoXmlNS::table, "style-name" ) )
  5926. {
  5927. TQString str = row.attributeNS( KoXmlNS::table, "style-name", TQString() );
  5928. const TQDomElement *style = oasisContext.oasisStyles().findStyle( str, "table-row" );
  5929. if ( style )
  5930. {
  5931. styleStack.push( *style );
  5932. isNonDefaultRow = true;
  5933. }
  5934. }
  5935. styleStack.setTypeProperties( "table-row" );
  5936. Format layout( this , doc()->styleManager()->defaultStyle() );
  5937. if ( row.hasAttributeNS( KoXmlNS::table,"default-cell-style-name" ) )
  5938. {
  5939. const TQString styleName = row.attributeNS( KoXmlNS::table, "default-cell-style-name", TQString() );
  5940. if ( !styleName.isEmpty() )
  5941. {
  5942. Style* const style = styleMap[ styleName ];
  5943. if ( style )
  5944. {
  5945. layout.setStyle( style );
  5946. isNonDefaultRow = true;
  5947. }
  5948. }
  5949. }
  5950. double height = -1.0;
  5951. if ( styleStack.hasAttributeNS( KoXmlNS::style, "row-height" ) )
  5952. {
  5953. height = KoUnit::parseValue( styleStack.attributeNS( KoXmlNS::style, "row-height" ) , -1.0 );
  5954. // kdDebug()<<" properties style:row-height : height :"<<height<<endl;
  5955. isNonDefaultRow = true;
  5956. }
  5957. int number = 1;
  5958. if ( row.hasAttributeNS( KoXmlNS::table, "number-rows-repeated" ) )
  5959. {
  5960. bool ok = true;
  5961. int n = row.attributeNS( KoXmlNS::table, "number-rows-repeated", TQString() ).toInt( &ok );
  5962. if ( ok )
  5963. // Some spreadsheet programs may support more rows than KSpread so
  5964. // limit the number of repeated rows.
  5965. // FIXME POSSIBLE DATA LOSS!
  5966. number = TQMIN( n, KS_rowMax - rowIndex + 1 );
  5967. }
  5968. bool collapse = false;
  5969. if ( row.hasAttributeNS( KoXmlNS::table, "visibility" ) )
  5970. {
  5971. const TQString visibility = row.attributeNS( KoXmlNS::table, "visibility", TQString() );
  5972. if ( visibility == "visible" )
  5973. collapse = false;
  5974. else if ( visibility == "collapse" )
  5975. collapse = true;
  5976. else if ( visibility == "filter" )
  5977. collapse = false; // FIXME Stefan: Set to true, if filters are supported.
  5978. isNonDefaultRow = true;
  5979. }
  5980. bool insertPageBreak = false;
  5981. if ( styleStack.hasAttributeNS( KoXmlNS::fo, "break-before" ) )
  5982. {
  5983. TQString str = styleStack.attributeNS( KoXmlNS::fo, "break-before" );
  5984. if ( str == "page" )
  5985. {
  5986. insertPageBreak = true;
  5987. }
  5988. // else
  5989. // kdDebug()<<" str :"<<str<<endl;
  5990. isNonDefaultRow = true;
  5991. }
  5992. //number == number of row to be copy. But we must copy cell too.
  5993. for ( int i = 0; i < number; ++i )
  5994. {
  5995. // kdDebug()<<" create non defaultrow format :"<<rowIndex<<" repeate : "<<number<<" height :"<<height<<endl;
  5996. RowFormat* rowFormat;
  5997. if ( isNonDefaultRow )
  5998. {
  5999. rowFormat = nonDefaultRowFormat( rowIndex );
  6000. if ( height != -1.0 )
  6001. rowFormat->setHeight( (int) height );
  6002. if ( collapse )
  6003. rowFormat->setHide( true );
  6004. }
  6005. else
  6006. {
  6007. rowFormat = this->rowFormat( rowIndex );
  6008. }
  6009. rowFormat->copy( layout );
  6010. ++rowIndex;
  6011. }
  6012. int columnIndex = 0;
  6013. TQDomNode cellNode = row.firstChild();
  6014. int endRow = min(backupRow+number,KS_rowMax);
  6015. while ( !cellNode.isNull() )
  6016. {
  6017. TQDomElement cellElement = cellNode.toElement();
  6018. if ( !cellElement.isNull() )
  6019. {
  6020. columnIndex++;
  6021. TQString localName = cellElement.localName();
  6022. if ( ((localName == "table-cell") || (localName == "covered-table-cell")) && cellElement.namespaceURI() == KoXmlNS::table)
  6023. {
  6024. //kdDebug() << "Loading cell #" << cellCount << endl;
  6025. Style* style = 0;
  6026. const bool cellHasStyle = cellElement.hasAttributeNS( KoXmlNS::table, "style-name" );
  6027. if ( cellHasStyle )
  6028. {
  6029. style = styleMap[ cellElement.attributeNS( KoXmlNS::table , "style-name" , TQString() ) ];
  6030. }
  6031. Cell* const cell = nonDefaultCell( columnIndex, backupRow ); // FIXME Stefan: if empty, delete afterwards
  6032. cell->loadOasis( cellElement, oasisContext, style );
  6033. int cols = 1;
  6034. // Copy this cell across & down, if it has repeated rows or columns, but only
  6035. // if the cell has some content or a style associated with it.
  6036. if ( (number > 1) || cellElement.hasAttributeNS( KoXmlNS::table, "number-columns-repeated" ) )
  6037. {
  6038. bool ok = false;
  6039. int n = cellElement.attributeNS( KoXmlNS::table, "number-columns-repeated", TQString() ).toInt( &ok );
  6040. if (ok)
  6041. // Some spreadsheet programs may support more columns than
  6042. // KSpread so limit the number of repeated columns.
  6043. // FIXME POSSIBLE DATA LOSS!
  6044. cols = TQMIN( n, KS_colMax - columnIndex + 1 );
  6045. if ( !cellHasStyle && ( cell->isEmpty() && cell->format()->comment( columnIndex, backupRow ).isEmpty() ) )
  6046. {
  6047. // just increment it
  6048. columnIndex += cols - 1;
  6049. }
  6050. else
  6051. {
  6052. for ( int k = cols ; k ; --k )
  6053. {
  6054. if ( k != cols )
  6055. columnIndex++;
  6056. for ( int newRow = backupRow; newRow < endRow; ++newRow )
  6057. {
  6058. Cell* target = nonDefaultCell( columnIndex, newRow );
  6059. if (cell != target)
  6060. target->copyAll( cell );
  6061. }
  6062. }
  6063. }
  6064. }
  6065. }
  6066. }
  6067. cellNode = cellNode.nextSibling();
  6068. }
  6069. return true;
  6070. }
  6071. void Sheet::maxRowCols( int & maxCols, int & maxRows )
  6072. {
  6073. const Cell * cell = firstCell();
  6074. while ( cell )
  6075. {
  6076. if ( cell->column() > maxCols )
  6077. maxCols = cell->column();
  6078. if ( cell->row() > maxRows )
  6079. maxRows = cell->row();
  6080. cell = cell->nextCell();
  6081. }
  6082. const RowFormat * row = firstRow();
  6083. while ( row )
  6084. {
  6085. if ( row->row() > maxRows )
  6086. maxRows = row->row();
  6087. row = row->next();
  6088. }
  6089. const ColumnFormat* col = firstCol();
  6090. while ( col )
  6091. {
  6092. if ( col->column() > maxCols )
  6093. maxCols = col->column();
  6094. col = col->next();
  6095. }
  6096. }
  6097. bool Sheet::compareRows( int row1, int row2, int& maxCols ) const
  6098. {
  6099. if ( *rowFormat( row1 ) != *rowFormat( row2 ) )
  6100. {
  6101. // kdDebug() << "\t Formats of " << row1 << " and " << row2 << " are different" << endl;
  6102. return false;
  6103. }
  6104. // FIXME Stefan: Make use of the cluster functionality.
  6105. for ( int col = 1; col <= maxCols; ++col )
  6106. {
  6107. if ( *cellAt( col, row1 ) != *cellAt( col, row2 ) )
  6108. {
  6109. // kdDebug() << "\t Cell at column " << col << " in row " << row2 << " differs from the one in row " << row1 << endl;
  6110. return false;
  6111. }
  6112. }
  6113. return true;
  6114. }
  6115. void Sheet::saveOasisHeaderFooter( KoXmlWriter &xmlWriter ) const
  6116. {
  6117. TQString headerLeft = print()->headLeft();
  6118. TQString headerCenter= print()->headMid();
  6119. TQString headerRight = print()->headRight();
  6120. TQString footerLeft = print()->footLeft();
  6121. TQString footerCenter= print()->footMid();
  6122. TQString footerRight = print()->footRight();
  6123. xmlWriter.startElement( "style:header");
  6124. if ( ( !headerLeft.isEmpty() )
  6125. || ( !headerCenter.isEmpty() )
  6126. || ( !headerRight.isEmpty() ) )
  6127. {
  6128. xmlWriter.startElement( "style:region-left" );
  6129. xmlWriter.startElement( "text:p" );
  6130. convertPart( headerLeft, xmlWriter );
  6131. xmlWriter.endElement();
  6132. xmlWriter.endElement();
  6133. xmlWriter.startElement( "style:region-center" );
  6134. xmlWriter.startElement( "text:p" );
  6135. convertPart( headerCenter, xmlWriter );
  6136. xmlWriter.endElement();
  6137. xmlWriter.endElement();
  6138. xmlWriter.startElement( "style:region-right" );
  6139. xmlWriter.startElement( "text:p" );
  6140. convertPart( headerRight, xmlWriter );
  6141. xmlWriter.endElement();
  6142. xmlWriter.endElement();
  6143. }
  6144. else
  6145. {
  6146. xmlWriter.startElement( "text:p" );
  6147. xmlWriter.startElement( "text:sheet-name" );
  6148. xmlWriter.addTextNode( "???" );
  6149. xmlWriter.endElement();
  6150. xmlWriter.endElement();
  6151. }
  6152. xmlWriter.endElement();
  6153. xmlWriter.startElement( "style:footer");
  6154. if ( ( !footerLeft.isEmpty() )
  6155. || ( !footerCenter.isEmpty() )
  6156. || ( !footerRight.isEmpty() ) )
  6157. {
  6158. xmlWriter.startElement( "style:region-left" );
  6159. xmlWriter.startElement( "text:p" );
  6160. convertPart( footerLeft, xmlWriter );
  6161. xmlWriter.endElement();
  6162. xmlWriter.endElement(); //style:region-left
  6163. xmlWriter.startElement( "style:region-center" );
  6164. xmlWriter.startElement( "text:p" );
  6165. convertPart( footerCenter, xmlWriter );
  6166. xmlWriter.endElement();
  6167. xmlWriter.endElement();
  6168. xmlWriter.startElement( "style:region-right" );
  6169. xmlWriter.startElement( "text:p" );
  6170. convertPart( footerRight, xmlWriter );
  6171. xmlWriter.endElement();
  6172. xmlWriter.endElement();
  6173. }
  6174. else
  6175. {
  6176. xmlWriter.startElement( "text:p" );
  6177. xmlWriter.startElement( "text:sheet-name" );
  6178. xmlWriter.addTextNode( "Page " ); // ???
  6179. xmlWriter.endElement();
  6180. xmlWriter.startElement( "text:page-number" );
  6181. xmlWriter.addTextNode( "1" ); // ???
  6182. xmlWriter.endElement();
  6183. xmlWriter.endElement();
  6184. }
  6185. xmlWriter.endElement();
  6186. }
  6187. void Sheet::addText( const TQString & text, KoXmlWriter & writer ) const
  6188. {
  6189. if ( !text.isEmpty() )
  6190. writer.addTextNode( text );
  6191. }
  6192. void Sheet::convertPart( const TQString & part, KoXmlWriter & xmlWriter ) const
  6193. {
  6194. TQString text;
  6195. TQString var;
  6196. bool inVar = false;
  6197. uint i = 0;
  6198. uint l = part.length();
  6199. while ( i < l )
  6200. {
  6201. if ( inVar || part[i] == '<' )
  6202. {
  6203. inVar = true;
  6204. var += part[i];
  6205. if ( part[i] == '>' )
  6206. {
  6207. inVar = false;
  6208. if ( var == "<page>" )
  6209. {
  6210. addText( text, xmlWriter );
  6211. xmlWriter.startElement( "text:page-number" );
  6212. xmlWriter.addTextNode( "1" );
  6213. xmlWriter.endElement();
  6214. }
  6215. else if ( var == "<pages>" )
  6216. {
  6217. addText( text, xmlWriter );
  6218. xmlWriter.startElement( "text:page-count" );
  6219. xmlWriter.addTextNode( "99" ); //TODO I think that it can be different from 99
  6220. xmlWriter.endElement();
  6221. }
  6222. else if ( var == "<date>" )
  6223. {
  6224. addText( text, xmlWriter );
  6225. //text:p><text:date style:data-style-name="N2" text:date-value="2005-10-02">02/10/2005</text:date>, <text:time>10:20:12</text:time></text:p> "add style" => create new style
  6226. #if 0 //FIXME
  6227. TQDomElement t = dd.createElement( "text:date" );
  6228. t.setAttribute( "text:date-value", "0-00-00" );
  6229. // todo: "style:data-style-name", "N2"
  6230. t.appendChild( dd.createTextNode( TQDate::currentDate().toString() ) );
  6231. parent.appendChild( t );
  6232. #endif
  6233. }
  6234. else if ( var == "<time>" )
  6235. {
  6236. addText( text, xmlWriter );
  6237. xmlWriter.startElement( "text:time" );
  6238. xmlWriter.addTextNode( TQTime::currentTime().toString() );
  6239. xmlWriter.endElement();
  6240. }
  6241. else if ( var == "<file>" ) // filepath + name
  6242. {
  6243. addText( text, xmlWriter );
  6244. xmlWriter.startElement( "text:file-name" );
  6245. xmlWriter.addAttribute( "text:display", "full" );
  6246. xmlWriter.addTextNode( "???" );
  6247. xmlWriter.endElement();
  6248. }
  6249. else if ( var == "<name>" ) // filename
  6250. {
  6251. addText( text, xmlWriter );
  6252. xmlWriter.startElement( "text:title" );
  6253. xmlWriter.addTextNode( "???" );
  6254. xmlWriter.endElement();
  6255. }
  6256. else if ( var == "<author>" )
  6257. {
  6258. Doc* sdoc = d->workbook->doc();
  6259. KoDocumentInfo * docInfo = sdoc->documentInfo();
  6260. KoDocumentInfoAuthor * authorPage = static_cast<KoDocumentInfoAuthor*>( docInfo->page( "author" ) );
  6261. text += authorPage->fullName();
  6262. addText( text, xmlWriter );
  6263. }
  6264. else if ( var == "<email>" )
  6265. {
  6266. Doc* sdoc = d->workbook->doc();
  6267. KoDocumentInfo * docInfo = sdoc->documentInfo();
  6268. KoDocumentInfoAuthor * authorPage = static_cast<KoDocumentInfoAuthor*>( docInfo->page( "author" ) );
  6269. text += authorPage->email();
  6270. addText( text, xmlWriter );
  6271. }
  6272. else if ( var == "<org>" )
  6273. {
  6274. Doc* sdoc = d->workbook->doc();
  6275. KoDocumentInfo * docInfo = sdoc->documentInfo();
  6276. KoDocumentInfoAuthor * authorPage = static_cast<KoDocumentInfoAuthor*>( docInfo->page( "author" ) );
  6277. text += authorPage->company();
  6278. addText( text, xmlWriter );
  6279. }
  6280. else if ( var == "<sheet>" )
  6281. {
  6282. addText( text, xmlWriter );
  6283. xmlWriter.startElement( "text:sheet-name" );
  6284. xmlWriter.addTextNode( "???" );
  6285. xmlWriter.endElement();
  6286. }
  6287. else
  6288. {
  6289. // no known variable:
  6290. text += var;
  6291. addText( text, xmlWriter );
  6292. }
  6293. text = "";
  6294. var = "";
  6295. }
  6296. }
  6297. else
  6298. {
  6299. text += part[i];
  6300. }
  6301. ++i;
  6302. }
  6303. if ( !text.isEmpty() || !var.isEmpty() )
  6304. {
  6305. //we don't have var at the end =>store it
  6306. addText( text+var, xmlWriter );
  6307. }
  6308. kdDebug()<<" text end :"<<text<<" var :"<<var<<endl;
  6309. }
  6310. void Sheet::loadOasisSettings( const KoOasisSettings::NamedMap &settings )
  6311. {
  6312. // Find the entry in the map that applies to this sheet (by name)
  6313. KoOasisSettings::Items items = settings.entry( d->name );
  6314. if ( items.isNull() )
  6315. return;
  6316. d->hideZero = items.parseConfigItemBool( "ShowZeroValues" );
  6317. d->showGrid = items.parseConfigItemBool( "ShowGrid" );
  6318. d->firstLetterUpper = items.parseConfigItemBool( "FirstLetterUpper" );
  6319. int cursorX = items.parseConfigItemInt( "CursorPositionX" );
  6320. int cursorY = items.parseConfigItemInt( "CursorPositionY" );
  6321. doc()->loadingInfo()->setCursorPosition( this, TQPoint( cursorX, cursorY ) );
  6322. double offsetX = items.parseConfigItemDouble( "xOffset" );
  6323. double offsetY = items.parseConfigItemDouble( "yOffset" );
  6324. doc()->loadingInfo()->setScrollingOffset( this, KoPoint( offsetX, offsetY ) );
  6325. d->showFormulaIndicator = items.parseConfigItemBool( "ShowFormulaIndicator" );
  6326. d->showCommentIndicator = items.parseConfigItemBool( "ShowCommentIndicator" );
  6327. d->showPageBorders = items.parseConfigItemBool( "ShowPageBorders" );
  6328. d->lcMode = items.parseConfigItemBool( "lcmode" );
  6329. d->autoCalc = items.parseConfigItemBool( "autoCalc" );
  6330. d->showColumnNumber = items.parseConfigItemBool( "ShowColumnNumber" );
  6331. }
  6332. void Sheet::saveOasisSettings( KoXmlWriter &settingsWriter ) const
  6333. {
  6334. //not into each page into oo spec
  6335. settingsWriter.addConfigItem( "ShowZeroValues", d->hideZero );
  6336. settingsWriter.addConfigItem( "ShowGrid", d->showGrid );
  6337. //not define into oo spec
  6338. settingsWriter.addConfigItem( "FirstLetterUpper", d->firstLetterUpper);
  6339. settingsWriter.addConfigItem( "ShowFormulaIndicator", d->showFormulaIndicator );
  6340. settingsWriter.addConfigItem( "ShowCommentIndicator", d->showCommentIndicator );
  6341. settingsWriter.addConfigItem( "ShowPageBorders",d->showPageBorders );
  6342. settingsWriter.addConfigItem( "lcmode", d->lcMode );
  6343. settingsWriter.addConfigItem( "autoCalc", d->autoCalc );
  6344. settingsWriter.addConfigItem( "ShowColumnNumber", d->showColumnNumber );
  6345. }
  6346. bool Sheet::saveOasis( KoXmlWriter & xmlWriter, KoGenStyles &mainStyles, GenValidationStyles &valStyle, KoStore *store, KoXmlWriter* /*manifestWriter*/, int &indexObj, int &partIndexObj )
  6347. {
  6348. int maxCols= 1;
  6349. int maxRows= 1;
  6350. xmlWriter.startElement( "table:table" );
  6351. xmlWriter.addAttribute( "table:name", d->name );
  6352. xmlWriter.addAttribute( "table:style-name", saveOasisSheetStyleName(mainStyles ) );
  6353. if ( !d->password.isEmpty() )
  6354. {
  6355. xmlWriter.addAttribute("table:protected", "true" );
  6356. TQCString str = KCodecs::base64Encode( d->password );
  6357. xmlWriter.addAttribute("table:protection-key", TQString( str.data() ) );/* FIXME !!!!*/
  6358. }
  6359. TQRect _printRange = d->print->printRange();
  6360. if ( _printRange != ( TQRect( TQPoint( 1, 1 ), TQPoint( KS_colMax, KS_rowMax ) ) ) )
  6361. {
  6362. TQString range= convertRangeToRef( d->name, _printRange );
  6363. kdDebug()<<" range : "<<range<<endl;
  6364. xmlWriter.addAttribute( "table:print-ranges", range );
  6365. }
  6366. saveOasisObjects( store, xmlWriter, mainStyles, indexObj, partIndexObj );
  6367. maxRowCols( maxCols, maxRows );
  6368. saveOasisColRowCell( xmlWriter, mainStyles, maxCols, maxRows, valStyle );
  6369. xmlWriter.endElement();
  6370. return true;
  6371. }
  6372. void Sheet::saveOasisPrintStyleLayout( KoGenStyle &style ) const
  6373. {
  6374. TQString printParameter;
  6375. if ( d->print->printGrid() )
  6376. printParameter="grid ";
  6377. if ( d->print->printObjects() )
  6378. printParameter+="objects ";
  6379. if ( d->print->printCharts() )
  6380. printParameter+="charts ";
  6381. if ( d->showFormula )
  6382. printParameter+="formulas ";
  6383. if ( !printParameter.isEmpty() )
  6384. {
  6385. printParameter+="drawings zero-values"; //default print style attributes in OO
  6386. style.addProperty( "style:print", printParameter );
  6387. }
  6388. }
  6389. TQString Sheet::saveOasisSheetStyleName( KoGenStyles &mainStyles )
  6390. {
  6391. KoGenStyle pageStyle( Doc::STYLE_PAGE, "table"/*FIXME I don't know if name is sheet*/ );
  6392. KoGenStyle pageMaster( Doc::STYLE_PAGEMASTER );
  6393. pageMaster.addAttribute( "style:page-layout-name", d->print->saveOasisSheetStyleLayout( mainStyles ) );
  6394. TQBuffer buffer;
  6395. buffer.open( IO_WriteOnly );
  6396. KoXmlWriter elementWriter( TQT_TQIODEVICE(&buffer) ); // TODO pass indentation level
  6397. saveOasisHeaderFooter(elementWriter);
  6398. TQString elementContents = TQString::fromUtf8( buffer.buffer(), buffer.buffer().size() );
  6399. pageMaster.addChildElement( "headerfooter", elementContents );
  6400. pageStyle.addAttribute( "style:master-page-name", mainStyles.lookup( pageMaster, "Standard" ) );
  6401. pageStyle.addProperty( "table:display", !d->hide );
  6402. return mainStyles.lookup( pageStyle, "ta" );
  6403. }
  6404. void Sheet::saveOasisColRowCell( KoXmlWriter& xmlWriter, KoGenStyles &mainStyles,
  6405. int maxCols, int maxRows, GenValidationStyles &valStyle )
  6406. {
  6407. kdDebug() << "Sheet::saveOasisColRowCell: " << d->name << endl;
  6408. kdDebug() << "\t Sheet dimension: " << maxCols << " x " << maxRows << endl;
  6409. // saving the columns
  6410. //
  6411. int i = 1;
  6412. while ( i <= maxCols )
  6413. {
  6414. // kdDebug() << "Sheet::saveOasisColRowCell: first col loop:"
  6415. // << " i: " << i
  6416. // << " column: " << column->column() << endl;
  6417. ColumnFormat* column = columnFormat( i );
  6418. KoGenStyle currentColumnStyle( Doc::STYLE_COLUMN_AUTO, "table-column" );
  6419. currentColumnStyle.addPropertyPt( "style:column-width", column->dblWidth() );
  6420. currentColumnStyle.addProperty( "fo:break-before", "auto" );/*FIXME auto or not ?*/
  6421. //style default layout for column
  6422. KoGenStyle currentDefaultCellStyle; // the type is determined in saveOasisCellStyle
  6423. TQString currentDefaultCellStyleName = column->saveOasisCellStyle( currentDefaultCellStyle, mainStyles );
  6424. bool hide = column->isHide();
  6425. bool refColumnIsDefault = column->isDefault();
  6426. int j = i;
  6427. int repeated = 1;
  6428. while ( j <= maxCols )
  6429. {
  6430. // kdDebug() << "Sheet::saveOasisColRowCell: second col loop:"
  6431. // << " j: " << j
  6432. // << " column: " << nextColumn->column() << endl;
  6433. ColumnFormat* nextColumn = d->columns.next( j++ );
  6434. // no next or not the adjacent column?
  6435. if ( !nextColumn || nextColumn->column() != j )
  6436. {
  6437. if ( refColumnIsDefault )
  6438. {
  6439. // if the origin column was a default column,
  6440. // we count the default columns
  6441. if ( !nextColumn )
  6442. {
  6443. repeated = maxCols - i + 1;
  6444. }
  6445. else
  6446. {
  6447. repeated = nextColumn->column() - j + 1;
  6448. }
  6449. }
  6450. // otherwise we just stop here to process the adjacent
  6451. // column in the next iteration of the outer loop
  6452. break;
  6453. }
  6454. #if 0
  6455. KoGenStyle nextColumnStyle( Doc::STYLE_COLUMN_AUTO, "table-column" );
  6456. nextColumnStyle.addPropertyPt( "style:column-width", nextColumn->dblWidth() );/*FIXME pt and not mm */
  6457. nextColumnStyle.addProperty( "fo:break-before", "auto" );/*FIXME auto or not ?*/
  6458. KoGenStyle nextDefaultCellStyle; // the type is determined in saveOasisCellStyle
  6459. TQString nextDefaultCellStyleName = nextColumn->saveOasisCellStyle( nextDefaultCellStyle, mainStyles );
  6460. if ( hide != nextColumn->isHide() ||
  6461. nextDefaultCellStyleName != currentDefaultCellStyleName ||
  6462. !( nextColumnStyle == currentColumnStyle ) )
  6463. {
  6464. break;
  6465. }
  6466. #endif
  6467. if ( *column != *nextColumn )
  6468. {
  6469. break;
  6470. }
  6471. ++repeated;
  6472. }
  6473. xmlWriter.startElement( "table:table-column" );
  6474. if ( !column->isDefault() )
  6475. {
  6476. xmlWriter.addAttribute( "table:style-name", mainStyles.lookup( currentColumnStyle, "co" ) );
  6477. if ( !currentDefaultCellStyle.isDefaultStyle() )
  6478. xmlWriter.addAttribute( "table:default-cell-style-name", currentDefaultCellStyleName );
  6479. if ( hide )
  6480. xmlWriter.addAttribute( "table:visibility", "collapse" );
  6481. }
  6482. if ( repeated > 1 )
  6483. xmlWriter.addAttribute( "table:number-columns-repeated", repeated );
  6484. xmlWriter.endElement();
  6485. kdDebug() << "Sheet::saveOasisColRowCell: column " << i << " "
  6486. << "repeated " << repeated << " time(s)" << endl;
  6487. i += repeated;
  6488. }
  6489. // saving the rows and the cells
  6490. // we have to loop through all rows of the used area
  6491. for ( i = 1; i <= maxRows; ++i )
  6492. {
  6493. RowFormat* const row = rowFormat( i );
  6494. KoGenStyle currentRowStyle( Doc::STYLE_ROW_AUTO, "table-row" );
  6495. currentRowStyle.addPropertyPt( "style:row-height", row->dblHeight() );
  6496. currentRowStyle.addProperty( "fo:break-before", "auto" );/*FIXME auto or not ?*/
  6497. // default cell style for row
  6498. KoGenStyle currentDefaultCellStyle; // the type is determined in saveOasisCellStyle
  6499. TQString currentDefaultCellStyleName = row->saveOasisCellStyle( currentDefaultCellStyle, mainStyles );
  6500. xmlWriter.startElement( "table:table-row" );
  6501. if ( !row->isDefault() )
  6502. {
  6503. xmlWriter.addAttribute( "table:style-name", mainStyles.lookup( currentRowStyle, "ro" ) );
  6504. }
  6505. int repeated = 1;
  6506. // empty row?
  6507. if ( !getFirstCellRow( i ) )
  6508. {
  6509. // kDebug() << "Sheet::saveOasisColRowCell: first row loop:"
  6510. // << " i: " << i
  6511. // << " row: " << row->row() << endl;
  6512. //bool isHidden = row->isHide();
  6513. bool isDefault = row->isDefault();
  6514. int j = i + 1;
  6515. // search for
  6516. // next non-empty row
  6517. // or
  6518. // next row with different Format
  6519. while ( j <= maxRows && !getFirstCellRow( j ) )
  6520. {
  6521. RowFormat* const nextRow = rowFormat( j );
  6522. // kDebug() << "Sheet::saveOasisColRowCell: second row loop:"
  6523. // << " j: " << j
  6524. // << " row: " << nextRow->row() << endl;
  6525. // if the reference row has the default row format
  6526. if ( isDefault )
  6527. {
  6528. // if the next is not default, stop here
  6529. if ( !nextRow->isDefault() )
  6530. break;
  6531. // otherwise, jump to the next
  6532. ++j;
  6533. continue;
  6534. }
  6535. #if 0
  6536. // create the Oasis representation of the format for the comparison
  6537. KoGenStyle nextRowStyle( Doc::STYLE_ROW_AUTO, "table-row" );
  6538. nextRowStyle.addPropertyPt( "style:row-height", nextRow->dblHeight() );
  6539. nextRowStyle.addProperty( "fo:break-before", "auto" );/*FIXME auto or not ?*/
  6540. // default cell style name for next row
  6541. KoGenStyle nextDefaultCellStyle; // the type is determined in saveOasisCellStyle
  6542. TQString nextDefaultCellStyleName = nextRow->saveOasisCellStyle( nextDefaultCellStyle, mainStyles );
  6543. // if the formats differ, stop here
  6544. if ( isHidden != nextRow->isHide() ||
  6545. nextDefaultCellStyleName != currentDefaultCellStyleName ||
  6546. !(nextRowStyle == currentRowStyle) )
  6547. {
  6548. break;
  6549. }
  6550. #endif
  6551. if ( *row != *nextRow )
  6552. {
  6553. break;
  6554. }
  6555. // otherwise, process the next
  6556. ++j;
  6557. }
  6558. repeated = j - i;
  6559. if ( repeated > 1 )
  6560. xmlWriter.addAttribute( "table:number-rows-repeated", repeated );
  6561. if ( !currentDefaultCellStyle.isDefaultStyle() )
  6562. xmlWriter.addAttribute( "table:default-cell-style-name", currentDefaultCellStyleName );
  6563. if ( row->isHide() ) // never true for the default row
  6564. xmlWriter.addAttribute( "table:visibility", "collapse" );
  6565. // NOTE Stefan: Even if paragraph 8.1 states, that rows may be empty, the
  6566. // RelaxNG schema does not allow that.
  6567. xmlWriter.startElement( "table:table-cell" );
  6568. xmlWriter.endElement();
  6569. kdDebug() << "Sheet::saveOasisColRowCell: empty row " << i << ' '
  6570. << "repeated " << repeated << " time(s)" << endl;
  6571. // copy the index for the next row to process
  6572. i = j - 1; /*it's already incremented in the for loop*/
  6573. }
  6574. else // row is not empty
  6575. {
  6576. if ( !currentDefaultCellStyle.isDefaultStyle() )
  6577. xmlWriter.addAttribute( "table:default-cell-style-name", currentDefaultCellStyleName );
  6578. if ( row->isHide() ) // never true for the default row
  6579. xmlWriter.addAttribute( "table:visibility", "collapse" );
  6580. int j = i + 1;
  6581. while ( compareRows( i, j, maxCols ) && j <= maxRows )
  6582. {
  6583. j++;
  6584. repeated++;
  6585. }
  6586. if ( repeated > 1 )
  6587. {
  6588. kdDebug() << "Sheet::saveOasisColRowCell: NON-empty row " << i << ' '
  6589. << "repeated " << repeated << " times" << endl;
  6590. xmlWriter.addAttribute( "table:number-rows-repeated", repeated );
  6591. }
  6592. saveOasisCells( xmlWriter, mainStyles, i, maxCols, valStyle );
  6593. // copy the index for the next row to process
  6594. i = j - 1; /*it's already incremented in the for loop*/
  6595. }
  6596. xmlWriter.endElement();
  6597. }
  6598. }
  6599. void Sheet::saveOasisCells( KoXmlWriter& xmlWriter, KoGenStyles &mainStyles, int row, int maxCols, GenValidationStyles &valStyle )
  6600. {
  6601. int i = 1;
  6602. Cell* cell = cellAt( i, row );
  6603. Cell* nextCell = getNextCellRight( i, row );
  6604. // while
  6605. // the current cell is not a default one
  6606. // or
  6607. // we have a further cell in this row
  6608. while ( !cell->isDefault() || nextCell )
  6609. {
  6610. kdDebug() << "Sheet::saveOasisCells:"
  6611. << " i: " << i
  6612. << " column: " << (cell->isDefault() ? 0 : cell->column()) << endl;
  6613. int repeated = 1;
  6614. cell->saveOasis( xmlWriter, mainStyles, row, i, repeated, valStyle );
  6615. i += repeated;
  6616. // stop if we reached the end column
  6617. if ( i > maxCols )
  6618. break;
  6619. cell = cellAt( i, row );
  6620. nextCell = getNextCellRight( i, row );
  6621. }
  6622. }
  6623. bool Sheet::loadXML( const TQDomElement& sheet )
  6624. {
  6625. bool ok = false;
  6626. if ( !doc()->loadingInfo() || !doc()->loadingInfo()->loadTemplate() )
  6627. {
  6628. d->name = sheet.attribute( "name" );
  6629. if ( d->name.isEmpty() )
  6630. {
  6631. doc()->setErrorMessage( i18n("Invalid document. Sheet name is empty.") );
  6632. return false;
  6633. }
  6634. }
  6635. bool detectDirection = true;
  6636. d->layoutDirection = LeftToRight;
  6637. TQString layoutDir = sheet.attribute( "layoutDirection" );
  6638. if( !layoutDir.isEmpty() )
  6639. {
  6640. if( layoutDir == "rtl" )
  6641. {
  6642. detectDirection = false;
  6643. d->layoutDirection = RightToLeft;
  6644. }
  6645. else if( layoutDir == "ltr" )
  6646. {
  6647. detectDirection = false;
  6648. d->layoutDirection = LeftToRight;
  6649. }
  6650. else
  6651. kdDebug()<<" Direction not implemented : "<<layoutDir<<endl;
  6652. }
  6653. if( detectDirection )
  6654. checkContentDirection( d->name );
  6655. /* older versions of KSpread allowed all sorts of characters that
  6656. the parser won't actually understand. Replace these with '_'
  6657. Also, the initial character cannot be a space.
  6658. */
  6659. if (d->name[0] == ' ')
  6660. {
  6661. d->name.remove(0,1);
  6662. }
  6663. for (unsigned int i=0; i < d->name.length(); i++)
  6664. {
  6665. if ( !(d->name[i].isLetterOrNumber() ||
  6666. d->name[i] == ' ' || d->name[i] == '.' ||
  6667. d->name[i] == '_'))
  6668. {
  6669. d->name[i] = '_';
  6670. }
  6671. }
  6672. /* make sure there are no name collisions with the altered name */
  6673. TQString testName;
  6674. TQString baseName;
  6675. int nameSuffix = 0;
  6676. testName = d->name;
  6677. baseName = d->name;
  6678. /* so we don't panic over finding ourself in the follwing test*/
  6679. d->name = "";
  6680. while (workbook()->findSheet(testName) != NULL)
  6681. {
  6682. nameSuffix++;
  6683. testName = baseName + '_' + TQString::number(nameSuffix);
  6684. }
  6685. d->name = testName;
  6686. kdDebug(36001)<<"Sheet::loadXML: table name="<<d->name<<endl;
  6687. setName(d->name.utf8());
  6688. (dynamic_cast<SheetIface*>(dcopObject()))->sheetNameHasChanged();
  6689. if( sheet.hasAttribute( "grid" ) )
  6690. {
  6691. d->showGrid = (int)sheet.attribute("grid").toInt( &ok );
  6692. // we just ignore 'ok' - if it didn't work, go on
  6693. }
  6694. if( sheet.hasAttribute( "printGrid" ) )
  6695. {
  6696. d->print->setPrintGrid( (bool)sheet.attribute("printGrid").toInt( &ok ) );
  6697. // we just ignore 'ok' - if it didn't work, go on
  6698. }
  6699. if( sheet.hasAttribute( "printCommentIndicator" ) )
  6700. {
  6701. d->print->setPrintCommentIndicator( (bool)sheet.attribute("printCommentIndicator").toInt( &ok ) );
  6702. // we just ignore 'ok' - if it didn't work, go on
  6703. }
  6704. if( sheet.hasAttribute( "printFormulaIndicator" ) )
  6705. {
  6706. d->print->setPrintFormulaIndicator( (bool)sheet.attribute("printFormulaIndicator").toInt( &ok ) );
  6707. // we just ignore 'ok' - if it didn't work, go on
  6708. }
  6709. if( sheet.hasAttribute( "hide" ) )
  6710. {
  6711. d->hide = (bool)sheet.attribute("hide").toInt( &ok );
  6712. // we just ignore 'ok' - if it didn't work, go on
  6713. }
  6714. if( sheet.hasAttribute( "showFormula" ) )
  6715. {
  6716. d->showFormula = (bool)sheet.attribute("showFormula").toInt( &ok );
  6717. // we just ignore 'ok' - if it didn't work, go on
  6718. }
  6719. //Compatibility with KSpread 1.1.x
  6720. if( sheet.hasAttribute( "formular" ) )
  6721. {
  6722. d->showFormula = (bool)sheet.attribute("formular").toInt( &ok );
  6723. // we just ignore 'ok' - if it didn't work, go on
  6724. }
  6725. if( sheet.hasAttribute( "showFormulaIndicator" ) )
  6726. {
  6727. d->showFormulaIndicator = (bool)sheet.attribute("showFormulaIndicator").toInt( &ok );
  6728. // we just ignore 'ok' - if it didn't work, go on
  6729. }
  6730. if( sheet.hasAttribute( "showCommentIndicator" ) )
  6731. {
  6732. d->showCommentIndicator = (bool)sheet.attribute("showCommentIndicator").toInt( &ok );
  6733. // we just ignore 'ok' - if it didn't work, go on
  6734. }
  6735. if( sheet.hasAttribute( "borders" ) )
  6736. {
  6737. d->showPageBorders = (bool)sheet.attribute("borders").toInt( &ok );
  6738. // we just ignore 'ok' - if it didn't work, go on
  6739. }
  6740. if( sheet.hasAttribute( "lcmode" ) )
  6741. {
  6742. d->lcMode = (bool)sheet.attribute("lcmode").toInt( &ok );
  6743. // we just ignore 'ok' - if it didn't work, go on
  6744. }
  6745. if ( sheet.hasAttribute( "autoCalc" ) )
  6746. {
  6747. d->autoCalc = ( bool )sheet.attribute( "autoCalc" ).toInt( &ok );
  6748. // we just ignore 'ok' - if it didn't work, go on
  6749. }
  6750. if( sheet.hasAttribute( "columnnumber" ) )
  6751. {
  6752. d->showColumnNumber = (bool)sheet.attribute("columnnumber").toInt( &ok );
  6753. // we just ignore 'ok' - if it didn't work, go on
  6754. }
  6755. if( sheet.hasAttribute( "hidezero" ) )
  6756. {
  6757. d->hideZero = (bool)sheet.attribute("hidezero").toInt( &ok );
  6758. // we just ignore 'ok' - if it didn't work, go on
  6759. }
  6760. if( sheet.hasAttribute( "firstletterupper" ) )
  6761. {
  6762. d->firstLetterUpper = (bool)sheet.attribute("firstletterupper").toInt( &ok );
  6763. // we just ignore 'ok' - if it didn't work, go on
  6764. }
  6765. // Load the paper layout
  6766. TQDomElement paper = sheet.namedItem( "paper" ).toElement();
  6767. if ( !paper.isNull() )
  6768. {
  6769. TQString format = paper.attribute( "format" );
  6770. TQString orientation = paper.attribute( "orientation" );
  6771. // <borders>
  6772. TQDomElement borders = paper.namedItem( "borders" ).toElement();
  6773. if ( !borders.isNull() )
  6774. {
  6775. float left = borders.attribute( "left" ).toFloat();
  6776. float right = borders.attribute( "right" ).toFloat();
  6777. float top = borders.attribute( "top" ).toFloat();
  6778. float bottom = borders.attribute( "bottom" ).toFloat();
  6779. d->print->setPaperLayout( left, top, right, bottom, format, orientation );
  6780. }
  6781. TQString hleft, hright, hcenter;
  6782. TQString fleft, fright, fcenter;
  6783. // <head>
  6784. TQDomElement head = paper.namedItem( "head" ).toElement();
  6785. if ( !head.isNull() )
  6786. {
  6787. TQDomElement left = head.namedItem( "left" ).toElement();
  6788. if ( !left.isNull() )
  6789. hleft = left.text();
  6790. TQDomElement center = head.namedItem( "center" ).toElement();
  6791. if ( !center.isNull() )
  6792. hcenter = center.text();
  6793. TQDomElement right = head.namedItem( "right" ).toElement();
  6794. if ( !right.isNull() )
  6795. hright = right.text();
  6796. }
  6797. // <foot>
  6798. TQDomElement foot = paper.namedItem( "foot" ).toElement();
  6799. if ( !foot.isNull() )
  6800. {
  6801. TQDomElement left = foot.namedItem( "left" ).toElement();
  6802. if ( !left.isNull() )
  6803. fleft = left.text();
  6804. TQDomElement center = foot.namedItem( "center" ).toElement();
  6805. if ( !center.isNull() )
  6806. fcenter = center.text();
  6807. TQDomElement right = foot.namedItem( "right" ).toElement();
  6808. if ( !right.isNull() )
  6809. fright = right.text();
  6810. }
  6811. d->print->setHeadFootLine( hleft, hcenter, hright, fleft, fcenter, fright);
  6812. }
  6813. // load print range
  6814. TQDomElement printrange = sheet.namedItem( "printrange-rect" ).toElement();
  6815. if ( !printrange.isNull() )
  6816. {
  6817. int left = printrange.attribute( "left-rect" ).toInt();
  6818. int right = printrange.attribute( "right-rect" ).toInt();
  6819. int bottom = printrange.attribute( "bottom-rect" ).toInt();
  6820. int top = printrange.attribute( "top-rect" ).toInt();
  6821. if ( left == 0 ) //whole row(s) selected
  6822. {
  6823. left = 1;
  6824. right = KS_colMax;
  6825. }
  6826. if ( top == 0 ) //whole column(s) selected
  6827. {
  6828. top = 1;
  6829. bottom = KS_rowMax;
  6830. }
  6831. d->print->setPrintRange( TQRect( TQPoint( left, top ), TQPoint( right, bottom ) ) );
  6832. }
  6833. // load print zoom
  6834. if( sheet.hasAttribute( "printZoom" ) )
  6835. {
  6836. double zoom = sheet.attribute( "printZoom" ).toDouble( &ok );
  6837. if ( ok )
  6838. {
  6839. d->print->setZoom( zoom );
  6840. }
  6841. }
  6842. // load page limits
  6843. if( sheet.hasAttribute( "printPageLimitX" ) )
  6844. {
  6845. int pageLimit = sheet.attribute( "printPageLimitX" ).toInt( &ok );
  6846. if ( ok )
  6847. {
  6848. d->print->setPageLimitX( pageLimit );
  6849. }
  6850. }
  6851. // load page limits
  6852. if( sheet.hasAttribute( "printPageLimitY" ) )
  6853. {
  6854. int pageLimit = sheet.attribute( "printPageLimitY" ).toInt( &ok );
  6855. if ( ok )
  6856. {
  6857. d->print->setPageLimitY( pageLimit );
  6858. }
  6859. }
  6860. // Load the cells
  6861. TQDomNode n = sheet.firstChild();
  6862. while( !n.isNull() )
  6863. {
  6864. TQDomElement e = n.toElement();
  6865. if ( !e.isNull() )
  6866. {
  6867. TQString tagName=e.tagName();
  6868. if ( tagName == "cell" )
  6869. {
  6870. Cell *cell = new Cell( this, 0, 0 );
  6871. if ( cell->load( e, 0, 0 ) )
  6872. insertCell( cell );
  6873. else
  6874. delete cell; // Allow error handling: just skip invalid cells
  6875. }
  6876. else if ( tagName == "row" )
  6877. {
  6878. RowFormat *rl = new RowFormat( this, 0 );
  6879. if ( rl->load( e ) )
  6880. insertRowFormat( rl );
  6881. else
  6882. delete rl;
  6883. }
  6884. else if ( tagName == "column" )
  6885. {
  6886. ColumnFormat *cl = new ColumnFormat( this, 0 );
  6887. if ( cl->load( e ) )
  6888. insertColumnFormat( cl );
  6889. else
  6890. delete cl;
  6891. }
  6892. else if ( tagName == "object" )
  6893. {
  6894. EmbeddedKOfficeObject *ch = new EmbeddedKOfficeObject( doc(), this );
  6895. if ( ch->load( e ) )
  6896. insertObject( ch );
  6897. else
  6898. {
  6899. ch->embeddedObject()->setDeleted(true);
  6900. delete ch;
  6901. }
  6902. }
  6903. else if ( tagName == "chart" )
  6904. {
  6905. EmbeddedChart *ch = new EmbeddedChart( doc(), this );
  6906. if ( ch->load( e ) )
  6907. insertObject( ch );
  6908. else
  6909. {
  6910. ch->embeddedObject()->setDeleted(true);
  6911. delete ch;
  6912. }
  6913. }
  6914. }
  6915. n = n.nextSibling();
  6916. }
  6917. // load print repeat columns
  6918. TQDomElement printrepeatcolumns = sheet.namedItem( "printrepeatcolumns" ).toElement();
  6919. if ( !printrepeatcolumns.isNull() )
  6920. {
  6921. int left = printrepeatcolumns.attribute( "left" ).toInt();
  6922. int right = printrepeatcolumns.attribute( "right" ).toInt();
  6923. d->print->setPrintRepeatColumns( tqMakePair( left, right ) );
  6924. }
  6925. // load print repeat rows
  6926. TQDomElement printrepeatrows = sheet.namedItem( "printrepeatrows" ).toElement();
  6927. if ( !printrepeatrows.isNull() )
  6928. {
  6929. int top = printrepeatrows.attribute( "top" ).toInt();
  6930. int bottom = printrepeatrows.attribute( "bottom" ).toInt();
  6931. d->print->setPrintRepeatRows( tqMakePair( top, bottom ) );
  6932. }
  6933. if( !sheet.hasAttribute( "borders1.2" ) )
  6934. {
  6935. convertObscuringBorders();
  6936. }
  6937. if ( sheet.hasAttribute( "protected" ) )
  6938. {
  6939. TQString passwd = sheet.attribute( "protected" );
  6940. if ( passwd.length() > 0 )
  6941. {
  6942. TQCString str( passwd.latin1() );
  6943. d->password = KCodecs::base64Decode( str );
  6944. }
  6945. else
  6946. d->password = TQCString( "" );
  6947. }
  6948. return true;
  6949. }
  6950. bool Sheet::loadChildren( KoStore* _store )
  6951. {
  6952. TQPtrListIterator<EmbeddedObject> it( doc()->embeddedObjects() );
  6953. for( ; it.current(); ++it )
  6954. {
  6955. if ( it.current()->sheet() == this && ( it.current()->getType() == OBJECT_KOFFICE_PART || it.current()->getType() == OBJECT_CHART ) )
  6956. {
  6957. kdDebug() << "KSpreadSheet::loadChildren" << endl;
  6958. if ( !dynamic_cast<EmbeddedKOfficeObject*>( it.current() )->embeddedObject()->loadDocument( _store ) )
  6959. return false;
  6960. }
  6961. }
  6962. return true;
  6963. }
  6964. void Sheet::setShowPageBorders( bool b )
  6965. {
  6966. if ( b == d->showPageBorders )
  6967. return;
  6968. d->showPageBorders = b;
  6969. emit sig_updateView( this );
  6970. }
  6971. void Sheet::addCellBinding( CellBinding *_bind )
  6972. {
  6973. d->cellBindings.append( _bind );
  6974. doc()->setModified( true );
  6975. }
  6976. void Sheet::removeCellBinding( CellBinding *_bind )
  6977. {
  6978. d->cellBindings.removeRef( _bind );
  6979. doc()->setModified( true );
  6980. }
  6981. Sheet* Sheet::findSheet( const TQString & _name )
  6982. {
  6983. if ( !workbook() )
  6984. return 0L;
  6985. return workbook()->findSheet( _name );
  6986. }
  6987. // ###### Torben: Use this one instead of d->cells.insert()
  6988. void Sheet::insertCell( Cell *_cell )
  6989. {
  6990. d->cells.insert( _cell, _cell->column(), _cell->row() );
  6991. // Adjust the scrollbar range, if the max. dimension has changed.
  6992. if ( d->scrollBarUpdates )
  6993. {
  6994. checkRangeHBorder ( _cell->column() );
  6995. checkRangeVBorder ( _cell->row() );
  6996. }
  6997. }
  6998. void Sheet::insertColumnFormat( ColumnFormat *l )
  6999. {
  7000. d->columns.insertElement( l, l->column() );
  7001. }
  7002. void Sheet::insertRowFormat( RowFormat *l )
  7003. {
  7004. d->rows.insertElement( l, l->row() );
  7005. }
  7006. void Sheet::update()
  7007. {
  7008. Cell* c = d->cells.firstCell();
  7009. for( ;c; c = c->nextCell() )
  7010. {
  7011. updateCell(c, c->column(), c->row());
  7012. }
  7013. }
  7014. void Sheet::updateCellArea(const Region& cellArea)
  7015. {
  7016. if ( doc()->isLoading() || doc()->delayCalculation() || (!getAutoCalc()))
  7017. return;
  7018. setRegionPaintDirty( cellArea );
  7019. }
  7020. void Sheet::updateCell( Cell */*cell*/, int _column, int _row )
  7021. {
  7022. TQRect cellArea(TQPoint(_column, _row), TQPoint(_column, _row));
  7023. updateCellArea(cellArea);
  7024. }
  7025. void Sheet::emit_updateRow( RowFormat *_format, int _row, bool repaint )
  7026. {
  7027. if ( doc()->isLoading() )
  7028. return;
  7029. Cell* c = d->cells.firstCell();
  7030. for( ;c; c = c->nextCell() )
  7031. if ( c->row() == _row )
  7032. c->setLayoutDirtyFlag( true );
  7033. if ( repaint )
  7034. {
  7035. //All the cells in this row, or below this row will need to be repainted
  7036. //So add that region of the sheet to the paint dirty list.
  7037. setRegionPaintDirty( TQRect( 0 , _row , KS_colMax , KS_rowMax) );
  7038. emit sig_updateVBorder( this );
  7039. emit sig_updateView( this );
  7040. }
  7041. emit sig_maxRow(maxRow());
  7042. _format->clearDisplayDirtyFlag();
  7043. }
  7044. void Sheet::emit_updateColumn( ColumnFormat *_format, int _column )
  7045. {
  7046. if ( doc()->isLoading() )
  7047. return;
  7048. Cell* c = d->cells.firstCell();
  7049. for( ;c; c = c->nextCell() )
  7050. if ( c->column() == _column )
  7051. c->setLayoutDirtyFlag( true );
  7052. //All the cells in this column or to the right of it will need to be repainted if the column
  7053. //has been resized or hidden, so add that region of the sheet to the paint dirty list.
  7054. setRegionPaintDirty( TQRect( _column , 0 , KS_colMax , KS_rowMax) );
  7055. emit sig_updateHBorder( this );
  7056. emit sig_updateView( this );
  7057. emit sig_maxColumn( maxColumn() );
  7058. _format->clearDisplayDirtyFlag();
  7059. }
  7060. bool Sheet::insertChart( const KoRect& _rect, KoDocumentEntry& _e, const TQRect& _data )
  7061. {
  7062. kdDebug(36001) << "Creating document" << endl;
  7063. KoDocument* dd = _e.createDoc();
  7064. kdDebug(36001) << "Created" << endl;
  7065. if ( !dd )
  7066. // Error message is already displayed, so just return
  7067. return false;
  7068. kdDebug(36001) << "NOW FETCHING INTERFACE" << endl;
  7069. if ( !dd->initDoc(KoDocument::InitDocEmbedded) )
  7070. return false;
  7071. EmbeddedChart * ch = new EmbeddedChart( doc(), this, dd, _rect );
  7072. ch->setDataArea( _data );
  7073. ch->update();
  7074. ch->chart()->setCanChangeValue( false );
  7075. KoChart::WizardExtension * wiz = ch->chart()->wizardExtension();
  7076. Range dataRange;
  7077. dataRange.setRange( _data );
  7078. dataRange.setSheet( this );
  7079. TQString rangeString=dataRange.toString();
  7080. if ( wiz )
  7081. wiz->show( rangeString );
  7082. insertObject( ch );
  7083. return true;
  7084. }
  7085. bool Sheet::insertChild( const KoRect& _rect, KoDocumentEntry& _e )
  7086. {
  7087. KoDocument* d = _e.createDoc( doc() );
  7088. if ( !d )
  7089. {
  7090. kdDebug() << "Error inserting child!" << endl;
  7091. return false;
  7092. }
  7093. if ( !d->initDoc(KoDocument::InitDocEmbedded) )
  7094. return false;
  7095. EmbeddedKOfficeObject* ch = new EmbeddedKOfficeObject( doc(), this, d, _rect );
  7096. insertObject( ch );
  7097. return true;
  7098. }
  7099. bool Sheet::insertPicture( const KoPoint& point , const KURL& url )
  7100. {
  7101. KoPicture picture = doc()->pictureCollection()->downloadPicture( url , 0 );
  7102. return insertPicture(point,picture);
  7103. }
  7104. bool Sheet::insertPicture( const KoPoint& point , KoPicture& picture )
  7105. {
  7106. if (picture.isNull())
  7107. return false;
  7108. KoPictureKey key = picture.getKey();
  7109. KoRect destinationRect;
  7110. destinationRect.setLeft( point.x() );
  7111. destinationRect.setTop( point.y() );
  7112. //Generate correct pixel size - this is a bit tricky.
  7113. //This ensures that when we load the image it appears
  7114. //the same size on screen on a 100%-zoom KSpread spreadsheet as it would in an
  7115. //image viewer or another spreadsheet program such as OpenOffice.
  7116. //
  7117. //KoUnit assumes 72DPI, whereas the user's display resolution will probably be
  7118. //different (eg. 96*96). So, we convert the actual size in pixels into inches
  7119. //using the screen display resolution and then use KoUnit to convert back into
  7120. //the appropriate pixel size KSpread.
  7121. KoSize destinationSize;
  7122. double inchWidth = (double)picture.getOriginalSize().width() / KoGlobal::dpiX();
  7123. double inchHeight = (double)picture.getOriginalSize().height() / KoGlobal::dpiY();
  7124. destinationSize.setWidth( KoUnit::fromUserValue(inchWidth,KoUnit::U_INCH) );
  7125. destinationSize.setHeight( KoUnit::fromUserValue(inchHeight,KoUnit::U_INCH) );
  7126. destinationRect.setSize( destinationSize);
  7127. EmbeddedPictureObject* object = new EmbeddedPictureObject( this, destinationRect, doc()->pictureCollection(),key);
  7128. // ch->setPicture(key);
  7129. insertObject( object );
  7130. return true;
  7131. }
  7132. bool Sheet::insertPicture( const KoPoint& point, const TQPixmap& pixmap )
  7133. {
  7134. TQByteArray data;
  7135. TQBuffer buffer(data);
  7136. buffer.open( IO_ReadWrite );
  7137. pixmap.save( TQT_TQIODEVICE(&buffer) , "PNG" );
  7138. //Reset the buffer so that KoPicture reads the whole file from the beginning
  7139. //(at the moment the read/write position is at the end)
  7140. buffer.reset();
  7141. KoPicture picture;
  7142. picture.load( TQT_TQIODEVICE(&buffer) , "PNG" );
  7143. doc()->pictureCollection()->insertPicture(picture);
  7144. return insertPicture( point , picture );
  7145. }
  7146. void Sheet::insertObject( EmbeddedObject *_obj )
  7147. {
  7148. doc()->insertObject( _obj );
  7149. emit sig_updateView( _obj );
  7150. }
  7151. void Sheet::changeChildGeometry( EmbeddedKOfficeObject *_child, const KoRect& _rect )
  7152. {
  7153. _child->setGeometry( _rect );
  7154. emit sig_updateChildGeometry( _child );
  7155. }
  7156. bool Sheet::saveChildren( KoStore* _store, const TQString &_path )
  7157. {
  7158. int i = 0;
  7159. TQPtrListIterator<EmbeddedObject> it( doc()->embeddedObjects() );
  7160. for( ; it.current(); ++it )
  7161. {
  7162. if ( it.current()->sheet() == this && ( it.current()->getType() == OBJECT_KOFFICE_PART || it.current()->getType() == OBJECT_CHART ) )
  7163. {
  7164. TQString path = TQString( "%1/%2" ).arg( _path ).arg( i++ );
  7165. if ( !dynamic_cast<EmbeddedKOfficeObject*>( it.current() )->embeddedObject()->document()->saveToStore( _store, path ) )
  7166. return false;
  7167. }
  7168. }
  7169. return true;
  7170. }
  7171. bool Sheet::saveOasisObjects( KoStore */*store*/, KoXmlWriter &xmlWriter, KoGenStyles& mainStyles, int & indexObj, int &partIndexObj )
  7172. {
  7173. //int i = 0;
  7174. if ( doc()->embeddedObjects().isEmpty() )
  7175. return true;
  7176. bool objectFound = false; // object on this sheet?
  7177. EmbeddedObject::KSpreadOasisSaveContext sc( xmlWriter, mainStyles, indexObj, partIndexObj );
  7178. TQPtrListIterator<EmbeddedObject> it( doc()->embeddedObjects() );
  7179. for( ; it.current(); ++it )
  7180. {
  7181. if ( it.current()->sheet() == this && ( doc()->savingWholeDocument() || it.current()->isSelected() ) )
  7182. {
  7183. if ( !objectFound )
  7184. {
  7185. xmlWriter.startElement( "table:shapes" );
  7186. objectFound = true;
  7187. }
  7188. if ( !it.current()->saveOasisObject(sc) )
  7189. {
  7190. xmlWriter.endElement();
  7191. return false;
  7192. }
  7193. ++indexObj;
  7194. }
  7195. }
  7196. if ( objectFound )
  7197. {
  7198. xmlWriter.endElement();
  7199. }
  7200. return true;
  7201. }
  7202. Sheet::~Sheet()
  7203. {
  7204. //Disable automatic recalculation of dependancies on this sheet to prevent crashes
  7205. //in certain situations:
  7206. //
  7207. //For example, suppose a cell in SheetB depends upon a cell in SheetA. If the cell in SheetB is emptied
  7208. //after SheetA has already been deleted, the program would try to remove dependancies from the cell in SheetA
  7209. //causing a crash.
  7210. setAutoCalc(false);
  7211. s_mapSheets->remove( d->id );
  7212. //when you remove all sheet (close file)
  7213. //you must reinit s_id otherwise there is not
  7214. //the good name between map and sheet
  7215. if( s_mapSheets->count()==0)
  7216. s_id=0L;
  7217. Cell* c = d->cells.firstCell();
  7218. for( ; c; c = c->nextCell() )
  7219. c->sheetDies();
  7220. d->cells.clear(); // cells destructor needs sheet to still exist
  7221. d->painter->end();
  7222. delete d->painter;
  7223. delete d->widget;
  7224. delete d->defaultFormat;
  7225. delete d->defaultCell;
  7226. delete d->defaultRowFormat;
  7227. delete d->defaultColumnFormat;
  7228. delete d->print;
  7229. delete d->dcop;
  7230. delete d->dependencies;
  7231. delete d;
  7232. //this is for debugging a crash
  7233. d=0;
  7234. }
  7235. void Sheet::checkRangeHBorder ( int _column )
  7236. {
  7237. if ( d->scrollBarUpdates && _column > d->maxColumn )
  7238. {
  7239. d->maxColumn = _column;
  7240. emit sig_maxColumn( _column );
  7241. }
  7242. }
  7243. void Sheet::checkRangeVBorder ( int _row )
  7244. {
  7245. if ( d->scrollBarUpdates && _row > d->maxRow )
  7246. {
  7247. d->maxRow = _row;
  7248. emit sig_maxRow( _row );
  7249. }
  7250. }
  7251. void Sheet::enableScrollBarUpdates( bool _enable )
  7252. {
  7253. d->scrollBarUpdates = _enable;
  7254. }
  7255. DCOPObject* Sheet::dcopObject()
  7256. {
  7257. if ( !d->dcop )
  7258. d->dcop = new SheetIface( this );
  7259. return d->dcop;
  7260. }
  7261. void Sheet::hideSheet(bool _hide)
  7262. {
  7263. setHidden(_hide);
  7264. if(_hide)
  7265. emit sig_SheetHidden(this);
  7266. else
  7267. emit sig_SheetShown(this);
  7268. }
  7269. void Sheet::removeSheet()
  7270. {
  7271. emit sig_SheetRemoved(this);
  7272. }
  7273. bool Sheet::setSheetName( const TQString& name, bool init, bool /*makeUndo*/ )
  7274. {
  7275. if ( workbook()->findSheet( name ) )
  7276. return false;
  7277. if ( isProtected() )
  7278. return false;
  7279. if ( d->name == name )
  7280. return true;
  7281. TQString old_name = d->name;
  7282. d->name = name;
  7283. if ( init )
  7284. return true;
  7285. TQPtrListIterator<Sheet> it( workbook()->sheetList() );
  7286. for ( ; it.current(); ++it )
  7287. it.current()->changeCellTabName( old_name, name );
  7288. doc()->changeAreaSheetName( old_name, name );
  7289. emit sig_nameChanged( this, old_name );
  7290. setName(name.utf8());
  7291. (dynamic_cast<SheetIface*>(dcopObject()))->sheetNameHasChanged();
  7292. return true;
  7293. }
  7294. void Sheet::updateLocale()
  7295. {
  7296. doc()->emitBeginOperation(true);
  7297. setRegionPaintDirty(TQRect(TQPoint(1,1), TQPoint(KS_colMax, KS_rowMax)));
  7298. Cell* c = d->cells.firstCell();
  7299. for( ;c; c = c->nextCell() )
  7300. {
  7301. TQString _text = c->text();
  7302. c->setCellText( _text );
  7303. }
  7304. emit sig_updateView( this );
  7305. // doc()->emitEndOperation();
  7306. }
  7307. Cell* Sheet::getFirstCellColumn(int col) const
  7308. { return d->cells.getFirstCellColumn(col); }
  7309. Cell* Sheet::getLastCellColumn(int col) const
  7310. { return d->cells.getLastCellColumn(col); }
  7311. Cell* Sheet::getFirstCellRow(int row) const
  7312. { return d->cells.getFirstCellRow(row); }
  7313. Cell* Sheet::getLastCellRow(int row) const
  7314. { return d->cells.getLastCellRow(row); }
  7315. Cell* Sheet::getNextCellUp(int col, int row) const
  7316. { return d->cells.getNextCellUp(col, row); }
  7317. Cell* Sheet::getNextCellDown(int col, int row) const
  7318. { return d->cells.getNextCellDown(col, row); }
  7319. Cell* Sheet::getNextCellLeft(int col, int row) const
  7320. { return d->cells.getNextCellLeft(col, row); }
  7321. Cell* Sheet::getNextCellRight(int col, int row) const
  7322. { return d->cells.getNextCellRight(col, row); }
  7323. void Sheet::convertObscuringBorders()
  7324. {
  7325. /* a word of explanation here:
  7326. beginning with KSpread 1.2 (actually, cvs of Mar 28, 2002), border information
  7327. is stored differently. Previously, for a cell obscuring a region, the entire
  7328. region's border's data would be stored in the obscuring cell. This caused
  7329. some data loss in certain situations. After that date, each cell stores
  7330. its own border data, and prints it even if it is an obscured cell (as long
  7331. as that border isn't across an obscuring border).
  7332. Anyway, this function is used when loading a file that was stored with the
  7333. old way of borders. All new files have the sheet attribute "borders1.2" so
  7334. if that isn't in the file, all the border data will be converted here.
  7335. It's a bit of a hack but I can't think of a better way and it's not *that*
  7336. bad of a hack.:-)
  7337. */
  7338. Cell* c = d->cells.firstCell();
  7339. TQPen topPen, bottomPen, leftPen, rightPen;
  7340. for( ;c; c = c->nextCell() )
  7341. {
  7342. if (c->extraXCells() > 0 || c->extraYCells() > 0)
  7343. {
  7344. topPen = c->topBorderPen(c->column(), c->row());
  7345. leftPen = c->leftBorderPen(c->column(), c->row());
  7346. rightPen = c->rightBorderPen(c->column(), c->row());
  7347. bottomPen = c->bottomBorderPen(c->column(), c->row());
  7348. c->format()->setTopBorderStyle(Qt::NoPen);
  7349. c->format()->setLeftBorderStyle(Qt::NoPen);
  7350. c->format()->setRightBorderStyle(Qt::NoPen);
  7351. c->format()->setBottomBorderStyle(Qt::NoPen);
  7352. for (int x = c->column(); x < c->column() + c->extraXCells(); x++)
  7353. {
  7354. nonDefaultCell( x, c->row() )->setTopBorderPen(topPen);
  7355. nonDefaultCell( x, c->row() + c->extraYCells() )->
  7356. setBottomBorderPen(bottomPen);
  7357. }
  7358. for (int y = c->row(); y < c->row() + c->extraYCells(); y++)
  7359. {
  7360. nonDefaultCell( c->column(), y )->setLeftBorderPen(leftPen);
  7361. nonDefaultCell( c->column() + c->extraXCells(), y )->
  7362. setRightBorderPen(rightPen);
  7363. }
  7364. }
  7365. }
  7366. }
  7367. /**********************
  7368. * Printout Functions *
  7369. **********************/
  7370. // TODO Stefan: these belong to View, even better Canvas
  7371. void Sheet::setRegionPaintDirty( Region const & region )
  7372. {
  7373. DilationManipulator manipulator;
  7374. manipulator.setSheet(this);
  7375. manipulator.add(region);
  7376. manipulator.execute();
  7377. // don't put it in the undo list! ;-)
  7378. d->paintDirtyList.add(manipulator);
  7379. //kdDebug() << "setRegionPaintDirty "<< static_cast<Region*>(&manipulator)->name(this) << endl;
  7380. }
  7381. void Sheet::setRegionPaintDirty( TQRect const & range )
  7382. {
  7383. DilationManipulator manipulator;
  7384. manipulator.setSheet(this);
  7385. manipulator.add(range);
  7386. manipulator.execute();
  7387. // don't put it in the undo list! ;-)
  7388. d->paintDirtyList.add(manipulator);
  7389. //kdDebug() << "setRegionPaintDirty "<< static_cast<Region*>(&manipulator)->name(this) << endl;
  7390. }
  7391. void Sheet::clearPaintDirtyData()
  7392. {
  7393. d->paintDirtyList.clear();
  7394. }
  7395. bool Sheet::cellIsPaintDirty( TQPoint const & cell ) const
  7396. {
  7397. return d->paintDirtyList.contains(cell);
  7398. }
  7399. #ifndef NDEBUG
  7400. void Sheet::printDebug()
  7401. {
  7402. int iMaxColumn = maxColumn();
  7403. int iMaxRow = maxRow();
  7404. kdDebug(36001) << "Cell | Content | DataT | Text" << endl;
  7405. Cell *cell;
  7406. for ( int currentrow = 1 ; currentrow < iMaxRow ; ++currentrow )
  7407. {
  7408. for ( int currentcolumn = 1 ; currentcolumn < iMaxColumn ; currentcolumn++ )
  7409. {
  7410. cell = cellAt( currentcolumn, currentrow );
  7411. if ( !cell->isDefault() && !cell->isEmpty() )
  7412. {
  7413. TQString cellDescr = Cell::name( currentcolumn, currentrow );
  7414. cellDescr = cellDescr.rightJustify( 4,' ' );
  7415. //TQString cellDescr = "Cell ";
  7416. //cellDescr += TQString::number(currentrow).rightJustify(3,'0') + ',';
  7417. //cellDescr += TQString::number(currentcolumn).rightJustify(3,'0') + ' ';
  7418. cellDescr += " | ";
  7419. cellDescr += cell->value().type();
  7420. cellDescr += " | ";
  7421. cellDescr += cell->text();
  7422. if ( cell->isFormula() )
  7423. cellDescr += TQString(" [result: %1]").arg( cell->value().asString() );
  7424. kdDebug(36001) << cellDescr << endl;
  7425. }
  7426. }
  7427. }
  7428. }
  7429. #endif
  7430. } // namespace KSpread