kspread Library API Documentation

kspread_sheet.cc

00001 /* This file is part of the KDE project
00002    Copyright (C) 1998,  1999 Torben Weis <weis@kde.org>
00003    Copyright (C) 1999 - 2005 The KSpread Team
00004                              www.koffice.org/kspread
00005 
00006    This library is free software; you can redistribute it and/or
00007    modify it under the terms of the GNU Library General Public
00008    License as published by the Free Software Foundation; either
00009    version 2 of the License, or (at your option) any later version.
00010 
00011    This library is distributed in the hope that it will be useful,
00012    but WITHOUT ANY WARRANTY; without even the implied warranty of
00013    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014    Library General Public License for more details.
00015 
00016    You should have received a copy of the GNU Library General Public License
00017    along with this library; see the file COPYING.LIB.  If not, write to
00018    the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
00019    Boston, MA 02111-1307, USA.
00020 */
00021 
00022 #include <stdlib.h>
00023 #include <ctype.h>
00024 #include <float.h>
00025 #include <math.h>
00026 #include <pwd.h>
00027 #include <unistd.h>
00028 
00029 #include <qapplication.h>
00030 #include <qclipboard.h>
00031 #include <qpicture.h>
00032 #include <qregexp.h>
00033 
00034 #include <qlayout.h>
00035 #include <qvbox.h>
00036 #include <qcheckbox.h>
00037 #include <qlabel.h>
00038 #include <qlineedit.h>
00039 #include <kmessagebox.h>
00040 
00041 #include <kfind.h>
00042 #include <kfinddialog.h>
00043 #include <kreplace.h>
00044 #include <kreplacedialog.h>
00045 #include <kprinter.h>
00046 #include <koDocumentInfo.h>
00047 #include <koOasisStyles.h>
00048 #include <koUnit.h>
00049 #include <koStyleStack.h>
00050 #include <koOasisSettings.h>
00051 #include <koxmlns.h>
00052 #include <kodom.h>
00053 
00054 #include "dependencies.h"
00055 
00056 #include "ksprsavinginfo.h"
00057 #include "kspread_cluster.h"
00058 #include "kspread_sheet.h"
00059 #include "kspread_sheetprint.h"
00060 #include "kspread_locale.h"
00061 #include "kspread_selection.h"
00062 #include "kspread_global.h"
00063 #include "kspread_undo.h"
00064 #include "kspread_map.h"
00065 #include "kspread_doc.h"
00066 #include "kspread_util.h"
00067 #include "kspread_canvas.h"
00068 #include "kspread_style.h"
00069 #include "kspread_style_manager.h"
00070 #include "ksploadinginfo.h"
00071 #include "KSpreadTableIface.h"
00072 
00073 #include <kdebug.h>
00074 #include <kmdcodec.h>
00075 #include <assert.h>
00076 
00077 #include <koChart.h>
00078 #include "kspread_sheet.moc"
00079 
00080 #define NO_MODIFICATION_POSSIBLE \
00081 do { \
00082   KMessageBox::error( 0, i18n ( "You cannot change a protected sheet" ) ); return; \
00083 } while(0)
00084 
00085 /*****************************************************************************
00086  *
00087  * CellBinding
00088  *
00089  *****************************************************************************/
00090 
00091 CellBinding::CellBinding( KSpreadSheet *_sheet, const QRect& _area )
00092 {
00093   m_rctDataArea = _area;
00094 
00095   m_pSheet = _sheet;
00096   m_pSheet->addCellBinding( this );
00097 
00098   m_bIgnoreChanges = false;
00099 }
00100 
00101 CellBinding::~CellBinding()
00102 {
00103   m_pSheet->removeCellBinding( this );
00104 }
00105 
00106 void CellBinding::cellChanged( KSpreadCell *_cell )
00107 {
00108   if ( m_bIgnoreChanges )
00109     return;
00110 
00111   emit changed( _cell );
00112 }
00113 
00114 bool CellBinding::contains( int _x, int _y )
00115 {
00116   return m_rctDataArea.contains( QPoint( _x, _y ) );
00117 }
00118 
00119 /*****************************************************************************
00120  *
00121  * ChartBinding
00122  *
00123  *****************************************************************************/
00124 
00125 ChartBinding::ChartBinding( KSpreadSheet *_sheet, const QRect& _area, ChartChild *_child )
00126     : CellBinding( _sheet, _area )
00127 {
00128   m_child = _child;
00129 }
00130 
00131 ChartBinding::~ChartBinding()
00132 {
00133 }
00134 
00135 void ChartBinding::cellChanged( KSpreadCell* )
00136 {
00137     kdDebug(36001) << "######### void ChartBinding::cellChanged( KSpreadCell* )" << endl;
00138 
00139     if ( m_bIgnoreChanges )
00140         return;
00141 
00142     kdDebug(36001) << "with=" << m_rctDataArea.width() << "  height=" << m_rctDataArea.height() << endl;
00143 
00144     KoChart::Data matrix( m_rctDataArea.height(), m_rctDataArea.width() );
00145 
00146     KSpreadCell* cell;
00147     for ( int y = 0; y < m_rctDataArea.height(); y++ )
00148         for ( int x = 0; x < m_rctDataArea.width(); x++ )
00149         {
00150             cell = m_pSheet->cellAt( m_rctDataArea.left() + x, m_rctDataArea.top() + y );
00151             if ( cell && cell->value().isNumber() )
00152                 matrix.cell( y, x ) = KoChart::Value( cell->value().asFloat() );
00153             else if ( cell )
00154                 matrix.cell( y, x ) = KoChart::Value( cell->value().asString() );
00155             else
00156                 matrix.cell( y, x ) = KoChart::Value();
00157         }
00158 
00159     // ######### Kalle may be interested in that, too
00160     /* Chart::Range range;
00161        range.top = m_rctDataArea.top();
00162        range.left = m_rctDataArea.left();
00163        range.right = m_rctDataArea.right();
00164        range.bottom = m_rctDataArea.bottom();
00165        range.sheet = m_pSheet->name(); */
00166 
00167     m_child->chart()->setData( matrix );
00168 
00169     // Force a redraw of the chart on all views
00170 
00172 //    sheet()->emit_polygonInvalidated( m_child->framePointArray() );
00173 }
00174 
00175 /******************************************************************/
00176 /* Class: KSpreadTextDrag                                               */
00177 /******************************************************************/
00178 
00179 KSpreadTextDrag::KSpreadTextDrag( QWidget * dragSource, const char * name )
00180     : QTextDrag( dragSource, name )
00181 {
00182 }
00183 
00184 KSpreadTextDrag::~KSpreadTextDrag()
00185 {
00186 }
00187 
00188 
00189 QByteArray KSpreadTextDrag::encodedData( const char * mime ) const
00190 {
00191   if ( strcmp( selectionMimeType(), mime ) == 0)
00192     return m_kspread;
00193   else
00194     return QTextDrag::encodedData( mime );
00195 }
00196 
00197 bool KSpreadTextDrag::canDecode( QMimeSource* e )
00198 {
00199   if ( e->provides( selectionMimeType() ) )
00200     return true;
00201   return QTextDrag::canDecode(e);
00202 }
00203 
00204 const char * KSpreadTextDrag::format( int i ) const
00205 {
00206   if ( i < 4 ) // HACK, but how to do otherwise ??
00207     return QTextDrag::format(i);
00208   else if ( i == 4 )
00209     return selectionMimeType();
00210   else return 0;
00211 }
00212 
00213 const char * KSpreadTextDrag::selectionMimeType()
00214 {
00215   return "application/x-kspread-snippet";
00216 }
00217 
00218 /*****************************************************************************
00219  *
00220  * KSpreadSheet
00221  *
00222  *****************************************************************************/
00223 
00224 class SheetPrivate
00225 {
00226 public:
00227 
00228   KSpreadMap* workbook;
00229 
00230   DCOPObject* dcop;
00231 
00232   QString name;
00233   int id;
00234 
00235   KSpreadSheet::LayoutDirection layoutDirection;
00236 
00237   // true if sheet is hidden
00238   bool hide;
00239 
00240   // password of protected sheet
00241   QCString password;
00242 
00243 
00244   bool showGrid;
00245   bool showFormula;
00246   bool showFormulaIndicator;
00247   bool autoCalc;
00248   bool lcMode;
00249   bool showColumnNumber;
00250   bool hideZero;
00251   bool firstLetterUpper;
00252 
00253   // clusters to hold objects
00254   KSpreadCluster cells;
00255   KSpreadRowCluster rows;
00256   KSpreadColumnCluster columns;
00257 
00258   // default objects
00259   KSpreadCell* defaultCell;
00260   KSpreadFormat* defaultFormat;
00261   RowFormat* defaultRowFormat;
00262   ColumnFormat* defaultColumnFormat;
00263 
00264   // hold the print object
00265   KSpreadSheetPrint* print;
00266 
00267   // cells that need painting
00268   QValueList<QRect> paintDirtyList;
00269 
00270   // to get font metrics
00271   QPainter *painter;
00272   QWidget *widget;
00273 
00274   // List of all cell bindings. For example charts use bindings to get
00275   // informed about changing cell contents.
00276   QPtrList<CellBinding> cellBindings;
00277 
00278   // Indicates whether the sheet should paint the page breaks.
00279   // Doing so costs some time, so by default it should be turned off.
00280   bool showPageBorders;
00281 
00282   // List of all embedded objects. FIXME unused ??
00283   // QPtrList<KSpreadChild> m_lstChildren;
00284 
00285   // The highest row and column ever accessed by the user.
00286   int maxRow;
00287   int maxColumn;
00288 
00289   // Max range of canvas in x and ye direction.
00290   //  Depends on KS_colMax/KS_rowMax and the width/height of all columns/rows
00291   double sizeMaxX;
00292   double sizeMaxY;
00293 
00294 
00295   bool scrollBarUpdates;
00296 
00297   QPen emptyPen;
00298   QBrush emptyBrush;
00299   QColor emptyColor;
00300 
00301   int scrollPosX;
00302   int scrollPosY;
00303 
00304   KSpread::DependencyManager *dependencies;
00305 };
00306 
00307 int KSpreadSheet::s_id = 0L;
00308 QIntDict<KSpreadSheet>* KSpreadSheet::s_mapSheets;
00309 
00310 KSpreadSheet* KSpreadSheet::find( int _id )
00311 {
00312   if ( !s_mapSheets )
00313     return 0L;
00314 
00315   return (*s_mapSheets)[ _id ];
00316 }
00317 
00318 KSpreadSheet::KSpreadSheet (KSpreadMap* map,
00319     const QString &sheetName, const char *_name )
00320   : QObject( map, _name )
00321 {
00322   if ( s_mapSheets == 0L )
00323     s_mapSheets = new QIntDict<KSpreadSheet>;
00324   d = new SheetPrivate;
00325 
00326   d->workbook = map;
00327 
00328   d->id = s_id++;
00329   s_mapSheets->insert( d->id, this );
00330 
00331   d->layoutDirection = LeftToRight;
00332 
00333   d->defaultFormat = new KSpreadFormat (this, d->workbook->doc()->styleManager()->defaultStyle());
00334   d->emptyPen.setStyle( Qt::NoPen );
00335   d->dcop = 0;
00336   d->name = sheetName;
00337 
00338   dcopObject();
00339   d->cellBindings.setAutoDelete( FALSE );
00340 
00341   // m_lstChildren.setAutoDelete( true );
00342 
00343   d->cells.setAutoDelete( true );
00344   d->rows.setAutoDelete( true );
00345   d->columns.setAutoDelete( true );
00346 
00347   d->defaultCell = new KSpreadCell( this, d->workbook->doc()->styleManager()->defaultStyle(), 0, 0);
00348   d->defaultRowFormat = new RowFormat( this, 0 );
00349   d->defaultRowFormat->setDefault();
00350   d->defaultColumnFormat = new ColumnFormat( this, 0 );
00351   d->defaultColumnFormat->setDefault();
00352 
00353   d->widget = new QWidget();
00354   d->painter = new QPainter;
00355   d->painter->begin( d->widget );
00356 
00357   d->maxColumn = 256;
00358   d->maxRow = 256;
00359   d->sizeMaxX = KS_colMax * d->defaultColumnFormat->dblWidth(); // default is max cols * default width
00360   d->sizeMaxY = KS_rowMax * d->defaultRowFormat->dblHeight(); // default is max rows * default height
00361 
00362   d->scrollBarUpdates = true;
00363 
00364   setHidden( false );
00365   d->showGrid=true;
00366   d->showFormula=false;
00367   d->showFormulaIndicator=true;
00368   d->showPageBorders = FALSE;
00369 
00370   d->lcMode=false;
00371   d->showColumnNumber=false;
00372   d->hideZero=false;
00373   d->firstLetterUpper=false;
00374   d->autoCalc=true;
00375   // Get a unique name so that we can offer scripting
00376   if ( !_name )
00377   {
00378       QCString s;
00379       s.sprintf("Sheet%i", s_id );
00380       QObject::setName( s.data() );
00381   }
00382   d->print = new KSpreadSheetPrint( this );
00383 
00384   //initialize dependencies
00385   d->dependencies = new KSpread::DependencyManager (this);
00386 }
00387 
00388 QString KSpreadSheet::sheetName() const
00389 {
00390   return d->name;
00391 }
00392 
00393 KSpreadMap* KSpreadSheet::workbook()
00394 {
00395   return d->workbook;
00396 }
00397 
00398 KSpreadDoc* KSpreadSheet::doc()
00399 {
00400   return d->workbook->doc();
00401 }
00402 
00403 int KSpreadSheet::id() const
00404 {
00405   return d->id;
00406 }
00407 
00408 KSpreadSheet::LayoutDirection KSpreadSheet::layoutDirection() const
00409 {
00410   return d->layoutDirection;
00411 }
00412 
00413 void KSpreadSheet::setLayoutDirection( LayoutDirection dir )
00414 {
00415   d->layoutDirection = dir;
00416 }
00417 
00418 bool KSpreadSheet::isRightToLeft() const
00419 {
00420   return d->layoutDirection == RightToLeft;
00421 }
00422 
00423 bool KSpreadSheet::isHidden() const
00424 {
00425   return d->hide;
00426 }
00427 
00428 void KSpreadSheet::setHidden( bool hidden )
00429 {
00430   d->hide = hidden;
00431 }
00432 
00433 bool KSpreadSheet::getShowGrid() const
00434 {
00435     return d->showGrid;
00436 }
00437 
00438 void KSpreadSheet::setShowGrid( bool _showGrid )
00439 {
00440     d->showGrid=_showGrid;
00441 }
00442 
00443 bool KSpreadSheet::getShowFormula() const
00444 {
00445     return d->showFormula;
00446 }
00447 
00448 void KSpreadSheet::setShowFormula( bool _showFormula )
00449 {
00450     d->showFormula=_showFormula;
00451 }
00452 
00453 bool KSpreadSheet::getShowFormulaIndicator() const
00454 {
00455     return d->showFormulaIndicator;
00456 }
00457 
00458 void KSpreadSheet::setShowFormulaIndicator( bool _showFormulaIndicator )
00459 {
00460     d->showFormulaIndicator=_showFormulaIndicator;
00461 }
00462 
00463 bool KSpreadSheet::getLcMode() const
00464 {
00465     return d->lcMode;
00466 }
00467 
00468 void KSpreadSheet::setLcMode( bool _lcMode )
00469 {
00470     d->lcMode=_lcMode;
00471 }
00472 
00473 bool KSpreadSheet::getAutoCalc() const
00474 {
00475     return d->autoCalc;
00476 }
00477 
00478 void KSpreadSheet::setAutoCalc( bool _AutoCalc )
00479 {
00480     d->autoCalc=_AutoCalc;
00481 }
00482 
00483 bool KSpreadSheet::getShowColumnNumber() const
00484 {
00485     return d->showColumnNumber;
00486 }
00487 
00488 void KSpreadSheet::setShowColumnNumber( bool _showColumnNumber )
00489 {
00490     d->showColumnNumber=_showColumnNumber;
00491 }
00492 
00493 bool KSpreadSheet::getHideZero() const
00494 {
00495     return d->hideZero;
00496 }
00497 
00498 void KSpreadSheet::setHideZero( bool _hideZero )
00499 {
00500     d->hideZero=_hideZero;
00501 }
00502 
00503 bool KSpreadSheet::getFirstLetterUpper() const
00504 {
00505     return d->firstLetterUpper;
00506 }
00507 
00508 void KSpreadSheet::setFirstLetterUpper( bool _firstUpper )
00509 {
00510     d->firstLetterUpper=_firstUpper;
00511 }
00512 
00513 bool KSpreadSheet::isShowPageBorders() const
00514 {
00515     return d->showPageBorders;
00516 }
00517 
00518 bool KSpreadSheet::isEmpty( unsigned long int x, unsigned long int y ) const
00519 {
00520   const KSpreadCell* c = cellAt( x, y );
00521   if ( !c || c->isEmpty() )
00522     return true;
00523 
00524   return false;
00525 }
00526 
00527 KSpreadCell* KSpreadSheet::defaultCell() const
00528 {
00529     return d->defaultCell;
00530 }
00531 
00532 KSpreadFormat* KSpreadSheet::defaultFormat()
00533 {
00534     return d->defaultFormat;
00535 }
00536 
00537 const KSpreadFormat* KSpreadSheet::defaultFormat() const
00538 {
00539     return d->defaultFormat;
00540 }
00541 
00542 const ColumnFormat* KSpreadSheet::columnFormat( int _column ) const
00543 {
00544     const ColumnFormat *p = d->columns.lookup( _column );
00545     if ( p != 0L )
00546         return p;
00547 
00548     return d->defaultColumnFormat;
00549 }
00550 
00551 ColumnFormat* KSpreadSheet::columnFormat( int _column )
00552 {
00553     ColumnFormat *p = d->columns.lookup( _column );
00554     if ( p != 0L )
00555         return p;
00556 
00557     return d->defaultColumnFormat;
00558 }
00559 
00560 const RowFormat* KSpreadSheet::rowFormat( int _row ) const
00561 {
00562     const RowFormat *p = d->rows.lookup( _row );
00563     if ( p != 0L )
00564         return p;
00565 
00566     return d->defaultRowFormat;
00567 }
00568 
00569 RowFormat* KSpreadSheet::rowFormat( int _row )
00570 {
00571     RowFormat *p = d->rows.lookup( _row );
00572     if ( p != 0L )
00573         return p;
00574 
00575     return d->defaultRowFormat;
00576 }
00577 
00578 KSpreadValue KSpreadSheet::value (int col, int row) const
00579 {
00580   KSpreadCell *cell = d->cells.lookup (col, row);
00581   if (cell)
00582     return cell->value ();
00583   KSpreadValue empty;
00584   return empty;
00585 }
00586 
00587 KSpreadValue KSpreadSheet::valueRange (int col1, int row1,
00588     int col2, int row2) const
00589 {
00590   return d->cells.valueRange (col1, row1, col2, row2);
00591 }
00592 
00593 void KSpreadSheet::password( QCString & passwd ) const
00594 {
00595     passwd = d->password;
00596 }
00597 
00598 bool KSpreadSheet::isProtected() const
00599 {
00600     return !d->password.isNull();
00601 }
00602 
00603 void KSpreadSheet::setProtected( QCString const & passwd )
00604 {
00605   d->password = passwd;
00606 }
00607 
00608 bool KSpreadSheet::checkPassword( QCString const & passwd ) const
00609 {
00610     return ( passwd == d->password );
00611 }
00612 
00613 KSpreadSheetPrint* KSpreadSheet::print() const
00614 {
00615     return d->print;
00616 }
00617 
00618 QPainter& KSpreadSheet::painter()
00619 {
00620     return *d->painter;
00621 }
00622 
00623 QWidget* KSpreadSheet::widget()const
00624 {
00625     return d->widget;
00626 }
00627 
00628 CellBinding* KSpreadSheet::firstCellBinding()
00629 {
00630     return d->cellBindings.first();
00631 }
00632 
00633 CellBinding* KSpreadSheet::nextCellBinding()
00634 {
00635     return d->cellBindings.next();
00636 }
00637 
00638 void KSpreadSheet::setDefaultHeight( double height )
00639 {
00640   if ( isProtected() )
00641     NO_MODIFICATION_POSSIBLE;
00642 
00643   d->defaultRowFormat->setDblHeight( height );
00644 }
00645 
00646 void KSpreadSheet::setDefaultWidth( double width )
00647 {
00648   if ( isProtected() )
00649     NO_MODIFICATION_POSSIBLE;
00650 
00651   d->defaultColumnFormat->setDblWidth( width );
00652 }
00653 
00654 double KSpreadSheet::sizeMaxX() const
00655 {
00656   return d->sizeMaxX;
00657 }
00658 
00659 double KSpreadSheet::sizeMaxY() const
00660 {
00661   return d->sizeMaxY;
00662 }
00663 
00664 int KSpreadSheet::maxColumn() const
00665 {
00666   return d->maxColumn;
00667 }
00668 
00669 int KSpreadSheet::maxRow() const
00670 {
00671   return d->maxRow;
00672 }
00673 
00674 const QPen& KSpreadSheet::emptyPen() const
00675 {
00676   return d->emptyPen;
00677 }
00678 
00679 const QBrush& KSpreadSheet::emptyBrush() const
00680 {
00681   return d->emptyBrush;
00682 }
00683 
00684 const QColor& KSpreadSheet::emptyColor() const
00685 {
00686   return d->emptyColor;
00687 }
00688 
00689 KSpread::DependencyManager *KSpreadSheet::dependencies ()
00690 {
00691   return d->dependencies;
00692 }
00693 
00694 int KSpreadSheet::leftColumn( double _xpos, double &_left,
00695                               const KSpreadCanvas *_canvas ) const
00696 {
00697     if ( _canvas )
00698     {
00699         _xpos += _canvas->xOffset();
00700         _left = -_canvas->xOffset();
00701     }
00702     else
00703         _left = 0.0;
00704 
00705     int col = 1;
00706     double x = columnFormat( col )->dblWidth( _canvas );
00707     while ( x < _xpos )
00708     {
00709         // Should never happen
00710         if ( col >= KS_colMax )
00711     {
00712         kdDebug(36001) << "KSpreadSheet:leftColumn: invalid column (col: " << col + 1 << ")" << endl;
00713         return KS_colMax + 1; //Return out of range value, so other code can react on this
00714     }
00715         _left += columnFormat( col )->dblWidth( _canvas );
00716         col++;
00717         x += columnFormat( col )->dblWidth( _canvas );
00718     }
00719 
00720     return col;
00721 }
00722 
00723 int KSpreadSheet::rightColumn( double _xpos, const KSpreadCanvas *_canvas ) const
00724 {
00725     if ( _canvas )
00726         _xpos += _canvas->xOffset();
00727 
00728     int col = 1;
00729     double x = 0.0;
00730     while ( x < _xpos )
00731     {
00732         // Should never happen
00733         if ( col > KS_colMax )
00734     {
00735         kdDebug(36001) << "KSpreadSheet:rightColumn: invalid column (col: " << col << ")" << endl;
00736             return KS_colMax + 1; //Return out of range value, so other code can react on this
00737     }
00738         x += columnFormat( col )->dblWidth( _canvas );
00739         col++;
00740     }
00741 
00742     return col - 1;
00743 }
00744 
00745 QRect KSpreadSheet::visibleRect( KSpreadCanvas const * const _canvas ) const
00746 {
00747   int top    = 0;
00748   int left   = 0;
00749 
00750   double x      = 0;
00751   double y      = 0;
00752   double width  = 0;
00753   double height = 0;
00754 
00755   if ( _canvas )
00756   {
00757     y     += _canvas->yOffset() * _canvas->zoom();
00758     x     += _canvas->xOffset() * _canvas->zoom();
00759     width  = _canvas->width();
00760     height = _canvas->height();
00761   }
00762 
00763   double yn = rowFormat( top )->dblHeight( _canvas );
00764   while ( yn < y )
00765   {
00766     if ( top >= KS_rowMax ) // Should never happen
00767       break;
00768 
00769     ++top;
00770     yn += rowFormat( top )->dblHeight( _canvas );
00771   }
00772 
00773   int bottom = top + 1;
00774 
00775   y += height;
00776   while ( yn < y )
00777   {
00778     if ( bottom > KS_rowMax ) // Should never happen
00779       break;
00780 
00781     ++bottom;
00782     yn += rowFormat( bottom )->dblHeight( _canvas );
00783   }
00784 
00785   double xn = columnFormat( left )->dblWidth( _canvas );
00786   while ( xn < x )
00787   {
00788     if ( left >= KS_colMax )    // Should never happen
00789       break;
00790 
00791     ++left;
00792     xn += columnFormat( left )->dblWidth( _canvas );
00793   }
00794   x += width;
00795 
00796   int right = left + 1;
00797 
00798   while ( xn < x )
00799   {
00800     if ( right > KS_colMax )    // Should never happen
00801       break;
00802 
00803     ++right;
00804     xn += columnFormat( right )->dblWidth( _canvas );
00805   }
00806   x += width;
00807 
00808   return QRect( left, top, right - left + 1, bottom - top + 1 );
00809 }
00810 
00811 int KSpreadSheet::topRow( double _ypos, double & _top,
00812                           const KSpreadCanvas *_canvas ) const
00813 {
00814     if ( _canvas )
00815     {
00816         _ypos += _canvas->yOffset();
00817         _top = -_canvas->yOffset();
00818     }
00819     else
00820         _top = 0.0;
00821 
00822     int row = 1;
00823     double y = rowFormat( row )->dblHeight( _canvas );
00824     while ( y < _ypos )
00825     {
00826         // Should never happen
00827         if ( row >= KS_rowMax )
00828         {
00829             kdDebug(36001) << "KSpreadSheet:topRow: invalid row (row: " << row + 1 << ")" << endl;
00830             return KS_rowMax + 1; //Return out of range value, so other code can react on this
00831         }
00832         _top += rowFormat( row )->dblHeight( _canvas );
00833         row++;
00834         y += rowFormat( row )->dblHeight( _canvas );
00835     }
00836 
00837     return row;
00838 }
00839 
00840 int KSpreadSheet::bottomRow( double _ypos, const KSpreadCanvas *_canvas ) const
00841 {
00842     if ( _canvas )
00843         _ypos += _canvas->yOffset();
00844 
00845     int row = 1;
00846     double y = 0.0;
00847     while ( y < _ypos )
00848     {
00849         // Should never happen
00850         if ( row > KS_rowMax )
00851     {
00852         kdDebug(36001) << "KSpreadSheet:bottomRow: invalid row (row: " << row << ")" << endl;
00853             return KS_rowMax + 1; //Return out of range value, so other code can react on this
00854     }
00855         y += rowFormat( row )->dblHeight( _canvas );
00856         row++;
00857     }
00858 
00859     return row - 1;
00860 }
00861 
00862 double KSpreadSheet::dblColumnPos( int _col, const KSpreadCanvas *_canvas ) const
00863 {
00864     double x = 0.0;
00865     if ( _canvas )
00866       x -= _canvas->xOffset();
00867     for ( int col = 1; col < _col; col++ )
00868     {
00869         // Should never happen
00870         if ( col > KS_colMax )
00871     {
00872         kdDebug(36001) << "KSpreadSheet:columnPos: invalid column (col: " << col << ")" << endl;
00873             return x;
00874     }
00875 
00876         x += columnFormat( col )->dblWidth( _canvas );
00877     }
00878 
00879     return x;
00880 }
00881 
00882 int KSpreadSheet::columnPos( int _col, const KSpreadCanvas *_canvas ) const
00883 {
00884     return (int)dblColumnPos( _col, _canvas );
00885 }
00886 
00887 
00888 double KSpreadSheet::dblRowPos( int _row, const KSpreadCanvas *_canvas ) const
00889 {
00890     double y = 0.0;
00891     if ( _canvas )
00892       y -= _canvas->yOffset();
00893 
00894     for ( int row = 1 ; row < _row ; row++ )
00895     {
00896         // Should never happen
00897         if ( row > KS_rowMax )
00898     {
00899         kdDebug(36001) << "KSpreadSheet:rowPos: invalid row (row: " << row << ")" << endl;
00900             return y;
00901     }
00902 
00903         y += rowFormat( row )->dblHeight( _canvas );
00904     }
00905 
00906     return y;
00907 }
00908 
00909 int KSpreadSheet::rowPos( int _row, const KSpreadCanvas *_canvas ) const
00910 {
00911     return (int)dblRowPos( _row, _canvas );
00912 }
00913 
00914 
00915 void KSpreadSheet::adjustSizeMaxX ( double _x )
00916 {
00917     d->sizeMaxX += _x;
00918 }
00919 
00920 void KSpreadSheet::adjustSizeMaxY ( double _y )
00921 {
00922     d->sizeMaxY += _y;
00923 }
00924 
00925 KSpreadCell* KSpreadSheet::visibleCellAt( int _column, int _row, bool _scrollbar_update )
00926 {
00927   KSpreadCell* cell = cellAt( _column, _row, _scrollbar_update );
00928   if ( cell->obscuringCells().isEmpty() )
00929       return cell;
00930   else
00931       return cell->obscuringCells().last();
00932 }
00933 
00934 KSpreadCell* KSpreadSheet::firstCell() const
00935 {
00936     return d->cells.firstCell();
00937 }
00938 
00939 RowFormat* KSpreadSheet::firstRow() const
00940 {
00941     return d->rows.first();
00942 }
00943 
00944 ColumnFormat* KSpreadSheet::firstCol() const
00945 {
00946     return d->columns.first();
00947 }
00948 
00949 KSpreadCell* KSpreadSheet::cellAt( int _column, int _row ) const
00950 {
00951     KSpreadCell *p = d->cells.lookup( _column, _row );
00952     if ( p != 0L )
00953         return p;
00954 
00955     return d->defaultCell;
00956 }
00957 
00958 KSpreadCell* KSpreadSheet::cellAt( int _column, int _row, bool _scrollbar_update )
00959 {
00960   if ( _column > KS_colMax ) {
00961     _column = KS_colMax;
00962     kdDebug (36001) << "KSpreadSheet::cellAt: column range: (col: " << _column << ")" << endl;
00963   }
00964   if ( _row > KS_rowMax) {
00965     kdDebug (36001) << "KSpreadSheet::cellAt: row out of range: (row: " << _row << ")" << endl;
00966     _row = KS_rowMax;
00967   }
00968 
00969   if ( _scrollbar_update && d->scrollBarUpdates )
00970   {
00971     checkRangeHBorder( _column );
00972     checkRangeVBorder( _row );
00973   }
00974 
00975   KSpreadCell *p = d->cells.lookup( _column, _row );
00976   if ( p != 0L )
00977     return p;
00978 
00979   return d->defaultCell;
00980 }
00981 
00982 ColumnFormat* KSpreadSheet::nonDefaultColumnFormat( int _column, bool force_creation )
00983 {
00984     ColumnFormat *p = d->columns.lookup( _column );
00985     if ( p != 0L || !force_creation )
00986         return p;
00987 
00988     p = new ColumnFormat( this, _column );
00989     // TODO: copy the default ColumnFormat here!!
00990     p->setDblWidth( d->defaultColumnFormat->dblWidth() );
00991 
00992     d->columns.insertElement( p, _column );
00993 
00994     return p;
00995 }
00996 
00997 RowFormat* KSpreadSheet::nonDefaultRowFormat( int _row, bool force_creation )
00998 {
00999     RowFormat *p = d->rows.lookup( _row );
01000     if ( p != 0L || !force_creation )
01001         return p;
01002 
01003     p = new RowFormat( this, _row );
01004     // TODO: copy the default RowLFormat here!!
01005     p->setDblHeight( d->defaultRowFormat->dblHeight() );
01006 
01007     d->rows.insertElement( p, _row );
01008 
01009     return p;
01010 }
01011 
01012 KSpreadCell* KSpreadSheet::nonDefaultCell( int _column, int _row,
01013                                            bool _scrollbar_update, KSpreadStyle * _style )
01014 {
01015   if ( _scrollbar_update && d->scrollBarUpdates )
01016   {
01017     checkRangeHBorder( _column );
01018     checkRangeVBorder( _row );
01019   }
01020 
01021   KSpreadCell * p = d->cells.lookup( _column, _row );
01022   if ( p != 0L )
01023     return p;
01024 
01025   KSpreadCell * cell = 0;
01026 
01027   if ( _style )
01028     cell = new KSpreadCell( this, _style, _column, _row );
01029   else
01030     cell = new KSpreadCell( this, _column, _row );
01031 
01032   insertCell( cell );
01033 
01034   return cell;
01035 }
01036 
01037 void KSpreadSheet::setText( int _row, int _column, const QString& _text, bool asString )
01038 {
01039     KSpreadCell * cell = nonDefaultCell( _column, _row );
01040 
01041     if ( isProtected() )
01042     {
01043       if ( !cell->notProtected( _column, _row ) )
01044         NO_MODIFICATION_POSSIBLE;
01045     }
01046 
01047     if ( !doc()->undoLocked() )
01048     {
01049         KSpreadUndoSetText *undo = new KSpreadUndoSetText( doc(), this, cell->text(), _column, _row,cell->formatType() );
01050         doc()->addCommand( undo );
01051     }
01052 
01053     // The cell will force a display refresh itself, so we dont have to care here.
01054     cell->setCellText( _text, asString );
01055     //refresh anchor
01056     if(_text.at(0)=='!')
01057       emit sig_updateView( this, QRect(_column,_row,_column,_row) );
01058 }
01059 
01060 void KSpreadSheet::setLayoutDirtyFlag()
01061 {
01062     KSpreadCell * c = d->cells.firstCell();
01063     for( ; c; c = c->nextCell() )
01064         c->setLayoutDirtyFlag();
01065 }
01066 
01067 void KSpreadSheet::setCalcDirtyFlag()
01068 {
01069     KSpreadCell* c = d->cells.firstCell();
01070     for( ; c; c = c->nextCell() )
01071     {
01072         if ( !(c->isObscured() && c->isObscuringForced()) )
01073             c->setCalcDirtyFlag();
01074     }
01075 }
01076 
01077 void KSpreadSheet::recalc()
01078 {
01079   //  emitBeginOperation(true);
01080   //  setRegionPaintDirty(QRect(QPoint(1,1), QPoint(KS_colMax, KS_rowMax)));
01081   setCalcDirtyFlag();
01082   //  emitEndOperation();
01083   emit sig_updateView( this );
01084 }
01085 
01086 void KSpreadSheet::valueChanged (KSpreadCell *cell)
01087 {
01088   //TODO: call cell updating, when cell damaging implemented
01089   //TODO: do nothing is updates are disabled
01090 
01091   //prepare the KSpreadPoint structure
01092   KSpreadPoint c;
01093   c.setRow (cell->row());
01094   c.setColumn (cell->column());
01095   c.sheet = this;
01096 
01097   //update dependencies
01098   d->dependencies->cellChanged (c);
01099 
01100   //nobody else seems to be setting the modified flag, so we do it here
01101   doc()->setModified (true);
01102 }
01103 
01104 /*
01105  Methods working on selections:
01106 
01107  TYPE A:
01108  { columns selected:
01109    for all rows with properties X,X':
01110      if default-cell create new cell
01111  }
01112  post undo object (always a KSpreadUndoCellLayout; difference in title only)
01113  { rows selected:
01114    if condition Y clear properties X,X' of cells;
01115    set properties X,X' of rowformats
01116    emit complete update;
01117  }
01118  { columns selected:
01119    if condition Y clear properties X,X' of cells;
01120    set properties X,X' of columnformats;
01121    for all rows with properties X,X':
01122      create cells if necessary and set properties X,X'
01123    emit complete update;
01124  }
01125  { cells selected:
01126    for all cells with condition Y:
01127      create if necessary and set properties X,X' and do Z;
01128    emit update on selected region;
01129  }
01130 
01131  USED in:
01132  setSelectionFont
01133  setSelectionSize
01134  setSelectionAngle
01135  setSelectionTextColor
01136  setSelectionBgColor
01137  setSelectionPercent
01138  borderAll
01139  borderRemove (exceptions: ### creates cells (why?), ### changes default cell if cell-regions selected?)
01140  setSelectionAlign
01141  setSelectionAlignY
01142  setSelectionMoneyFormat
01143  increaseIndent
01144  decreaseIndent
01145 
01146  TYPE B:
01147  post undo object
01148  { rows selected:
01149    if condition Y do X with cells;
01150    emit update on selection;
01151  }
01152  { columns selected:
01153    if condition Y do X with cells;
01154    emit update on selection;
01155  }
01156  { cells selected:
01157    if condition Y do X with cells; create cell if non-default;
01158    emit update on selection;
01159  }
01160 
01161  USED in:
01162  setSelectionUpperLower (exceptions: no undo; no create-if-default; ### modifies default-cell?)
01163  setSelectionFirstLetterUpper (exceptions: no undo; no create-if-default; ### modifies default-cell?)
01164  setSelectionVerticalText
01165  setSelectionComment
01166  setSelectionRemoveComment (exeception: no create-if-default and work only on non-default-cells for cell regions)
01167  setSelectionBorderColor (exeception: no create-if-default and work only on non-default-cells for cell regions)
01168  setSelectionMultiRow
01169  setSelectionPrecision
01170  clearTextSelection (exception: all only if !areaIsEmpty())
01171  clearValiditySelection (exception: all only if !areaIsEmpty())
01172  clearConditionalSelection (exception: all only if !areaIsEmpty())
01173  setConditional (exception: conditional after create-if-default for cell regions)
01174  setValidity (exception: conditional after create-if-default for cell regions)
01175 
01176  OTHERS:
01177  borderBottom
01178  borderRight
01179  borderLeft
01180  borderTop
01181  borderOutline
01182  => these work only on some cells (at the border); undo only if cells affected; rest is similar to type A
01183  --> better not use CellWorker/workOnCells()
01184 
01185  defaultSelection
01186  => similar to TYPE B, but works on columns/rows if complete columns/rows selected
01187  --> use emit_signal=false and return value of workOnCells to finish
01188 
01189  getWordSpelling
01190  => returns text, no signal emitted, no cell-create, similar to TYPE B
01191  --> use emit_signal=false, create_if_default=false and type B
01192 
01193  setWordSpelling
01194  => no signal emitted, no cell-create, similar to type B
01195  --> use emit_signal=false, create_if_default=false and type B
01196  */
01197 
01198 class KSpreadUndoAction* KSpreadSheet::CellWorkerTypeA::createUndoAction( KSpreadDoc* doc, KSpreadSheet* sheet, QRect& r )
01199 {
01200     QString title = getUndoTitle();
01201     return new KSpreadUndoCellFormat( doc, sheet, r, title );
01202 }
01203 
01204 /*
01205 KSpreadSheet::SelectionType KSpreadSheet::workOnCells( const QPoint& _marker, CellWorker& worker )
01206 {
01207     // see what is selected; if nothing, take marker position
01208     bool selected = ( m_rctSelection.left() != 0 );
01209     QRect r( m_rctSelection );
01210     if ( !selected )
01211     r.setCoords( _marker.x(), _marker.y(), _marker.x(), _marker.y() );
01212 
01213     // create cells in rows if complete columns selected
01214     KSpreadCell *cell;
01215     if ( !worker.type_B && selected && isColumnSelected() )
01216     {
01217     for ( RowFormat* rw =d->rows.first(); rw; rw = rw->next() )
01218     {
01219         if ( !rw->isDefault() && worker.testCondition( rw ) )
01220         {
01221         for ( int i=m_rctSelection.left(); i<=m_rctSelection.right(); i++ )
01222         {
01223             cell = cellAt( i, rw->row() );
01224             if ( cell == d->defaultCell )
01225             // '&& worker.create_if_default' unnecessary as never used in type A
01226             {
01227             cell = new KSpreadCell( this, i, rw->row() );
01228             insertCell( cell );
01229             }
01230         }
01231         }
01232     }
01233     }
01234 
01235     // create an undo action
01236     if ( !doc()->undoLocked() )
01237     {
01238     KSpreadUndoAction *undo = worker.createUndoAction( doc(), this, r );
01239         // test if the worker has an undo action
01240         if ( undo != 0L )
01241         doc()->addCommand( undo );
01242     }
01243 
01244     // complete rows selected ?
01245     if ( selected && isRowSelected() )
01246     {
01247     int row;
01248     for ( KSpreadCell* cell = d->cells.firstCell(); cell; cell = cell->nextCell() )
01249     {
01250         row = cell->row();
01251         if ( m_rctSelection.top() <= row && m_rctSelection.bottom() >= row
01252          && worker.testCondition( cell ) )
01253         if ( worker.type_B )
01254             worker.doWork( cell, false, cell->column(), row );
01255         else
01256             worker.prepareCell( cell );
01257     }
01258 
01259     if ( worker.type_B ) {
01260             // for type B there's nothing left to do
01261         if ( worker.emit_signal )
01262         emit sig_updateView( this, r );
01263     } else {
01264             // for type A now work on row formats
01265         for ( int i=m_rctSelection.top(); i<=m_rctSelection.bottom(); i++ )
01266         {
01267         RowFormat *rw=nonDefaultRowFormat(i);
01268         worker.doWork( rw );
01269         }
01270         if ( worker.emit_signal )
01271         emit sig_updateView( this );
01272     }
01273     return CompleteRows;
01274     }
01275     // complete columns selected ?
01276     else if ( selected && isColumnSelected() )
01277     {
01278     int col;
01279     for ( KSpreadCell* cell = d->cells.firstCell(); cell; cell = cell->nextCell() )
01280     {
01281         col = cell->column();
01282         if ( m_rctSelection.left() <= col && m_rctSelection.right() >= col
01283          && worker.testCondition( cell ) )
01284         if ( worker.type_B )
01285             worker.doWork( cell, false, col, cell->row() );
01286         else
01287             worker.prepareCell( cell );
01288     }
01289 
01290     if ( worker.type_B ) {
01291         if ( worker.emit_signal )
01292         emit sig_updateView( this, r );
01293     } else {
01294         // for type A now work on column formats
01295         for ( int i=m_rctSelection.left(); i<=m_rctSelection.right(); i++ )
01296         {
01297         ColumnFormat *cl=nonDefaultColumnFormat(i);
01298         worker.doWork( cl );
01299         }
01300         KSpreadCell *cell;
01301         for ( RowFormat* rw =d->rows.first(); rw; rw = rw->next() )
01302         {
01303         if ( !rw->isDefault() && worker.testCondition( rw ) )
01304         {
01305             for ( int i=m_rctSelection.left(); i<=m_rctSelection.right(); i++ )
01306             {
01307             cell = cellAt( i, rw->row() );
01308             // ### this if should be not necessary; cells are created
01309             //     before the undo object is created, aren't they?
01310             if ( cell == d->defaultCell )
01311             {
01312                 cell = new KSpreadCell( this, i, rw->row() );
01313                 insertCell( cell );
01314             }
01315             worker.doWork( cell, false, i, rw->row() );
01316             }
01317         }
01318         }
01319             if ( worker.emit_signal )
01320         emit sig_updateView( this );
01321     }
01322     return CompleteColumns;
01323     }
01324     // cell region selected
01325     else
01326     {
01327     KSpreadCell *cell;
01328     for ( int x = r.left(); x <= r.right(); x++ )
01329         for ( int y = r.top(); y <= r.bottom(); y++ )
01330         {
01331         cell = cellAt( x, y );
01332                 if ( worker.testCondition( cell ) )
01333         {
01334             if ( worker.create_if_default && cell == d->defaultCell )
01335             {
01336             cell = new KSpreadCell( this, x, y );
01337             insertCell( cell );
01338             }
01339                     if ( cell != d->defaultCell )
01340             worker.doWork( cell, true, x, y );
01341         }
01342         }
01343         if ( worker.emit_signal )
01344         emit sig_updateView( this, r );
01345         return CellRegion;
01346     }
01347 }
01348 
01349 */
01350 
01351 KSpreadSheet::SelectionType KSpreadSheet::workOnCells( KSpreadSelection* selectionInfo, CellWorker & worker )
01352 {
01353   // see what is selected; if nothing, take marker position
01354   QRect selection(selectionInfo->selection());
01355   bool selected = !(selectionInfo->singleCellSelection());
01356 
01357   int top = selection.top();
01358   int left = selection.left();
01359   int bottom = selection.bottom();
01360   int right  = selection.right();
01361 
01362   KSpreadSheet::SelectionType result;
01363 
01364   doc()->emitBeginOperation();
01365 
01366   // create cells in rows if complete columns selected
01367   KSpreadCell * cell;
01368   KSpreadStyle * s = doc()->styleManager()->defaultStyle();
01369 
01370   if ( !worker.type_B && selected && util_isColumnSelected(selection) )
01371   {
01372     for ( RowFormat * rw = d->rows.first(); rw; rw = rw->next() )
01373     {
01374       if ( worker.testCondition( rw ) )
01375       {
01376         for ( int col = left; col <= right; ++col )
01377         {
01378           cell = nonDefaultCell( col, rw->row(), false, s );
01379         }
01380       }
01381     }
01382   }
01383 
01384   // create an undo action
01385   if ( !doc()->undoLocked() )
01386   {
01387     KSpreadUndoAction * undo = worker.createUndoAction(doc(), this, selection);
01388     // test if the worker has an undo action
01389     if ( undo != 0L )
01390       doc()->addCommand( undo );
01391   }
01392 
01393   // complete rows selected ?
01394   if ( selected && util_isRowSelected(selection) )
01395   {
01396     for ( int row = top; row <= bottom; ++row )
01397     {
01398       cell = getFirstCellRow( row );
01399       while ( cell )
01400       {
01401         if ( worker.testCondition( cell ) )
01402         {
01403           if ( worker.type_B )
01404             worker.doWork( cell, false, cell->column(), row );
01405           else
01406             worker.prepareCell( cell );
01407         }
01408         cell = getNextCellRight( cell->column(), row );
01409       }
01410     }
01411 
01412     if ( worker.type_B )
01413     {
01414       // for type B there's nothing left to do
01415       ;
01416     }
01417     else
01418     {
01419       // for type A now work on row formats
01420       for ( int i = top; i <= bottom; ++i )
01421       {
01422         RowFormat * rw = nonDefaultRowFormat(i);
01423         worker.doWork( rw );
01424       }
01425 
01426       for ( int row = top; row <= bottom; ++row )
01427       {
01428         cell = getFirstCellRow( row );
01429         while ( cell )
01430         {
01431           if ( worker.testCondition( cell ) )
01432           {
01433             worker.doWork( cell, false, cell->column(), row );
01434           }
01435         cell = getNextCellRight( cell->column(), row );
01436         }
01437       }
01438 
01439     }
01440     result = CompleteRows;
01441   }
01442   // complete columns selected ?
01443   else if ( selected && util_isColumnSelected(selection) )
01444   {
01445     for ( int col = selection.left(); col <= right; ++col )
01446     {
01447       cell = getFirstCellColumn( col );
01448       while ( cell )
01449       {
01450     if ( worker.testCondition( cell ) )
01451         {
01452           if ( worker.type_B )
01453             worker.doWork( cell, false, col, cell->row() );
01454           else
01455             worker.prepareCell( cell );
01456         }
01457 
01458         cell = getNextCellDown( col, cell->row() );
01459       }
01460     }
01461 
01462     if ( worker.type_B )
01463     {
01464       ;
01465     }
01466     else
01467     {
01468       // for type A now work on column formats
01469       for ( int i = left; i <= right; ++i )
01470       {
01471         ColumnFormat * cl = nonDefaultColumnFormat( i );
01472         worker.doWork( cl );
01473       }
01474 
01475       for ( RowFormat * rw = d->rows.first(); rw; rw = rw->next() )
01476       {
01477         if ( worker.testCondition( rw ) )
01478         {
01479           for ( int i = left; i <= right; ++i )
01480           {
01481             cell = nonDefaultCell( i, rw->row(), false, s );
01482             worker.doWork( cell, false, i, rw->row() );
01483           }
01484         }
01485       }
01486     }
01487     result = CompleteColumns;
01488   }
01489   // cell region selected
01490   else
01491   {
01492     for ( int x = left; x <= right; ++x )
01493     {
01494       for ( int y = top; y <= bottom; ++y )
01495       {
01496         cell = cellAt( x, y );
01497         if ( worker.testCondition( cell ) )
01498         {
01499           if ( cell == d->defaultCell && worker.create_if_default )
01500           {
01501             cell = new KSpreadCell( this, s, x, y );
01502             insertCell( cell );
01503           }
01504           if ( cell != d->defaultCell )
01505           {
01506             // kdDebug() << "not default" << endl;
01507             worker.doWork( cell, true, x, y );
01508           }
01509         }
01510       }
01511     }
01512     result = CellRegion;
01513   }
01514 
01515   // emitEndOperation();
01516   emit sig_updateView( this );
01517 
01518   if (worker.emit_signal)
01519   {
01520     emit sig_updateView( this, selection );
01521   }
01522 
01523   return result;
01524 }
01525 
01526 struct SetSelectionFontWorker : public KSpreadSheet::CellWorkerTypeA
01527 {
01528     const char *_font;
01529     int _size;
01530     signed char _bold;
01531     signed char _italic;
01532     signed char _underline;
01533     signed char _strike;
01534     SetSelectionFontWorker( const char *font, int size, signed char bold, signed char italic,signed char underline, signed char strike )
01535     : _font( font ), _size( size ), _bold( bold ), _italic( italic ), _underline( underline ), _strike( strike ) { }
01536 
01537     QString getUndoTitle() { return i18n("Change Font"); }
01538     bool testCondition( RowFormat* rw ) {
01539         return ( rw->hasProperty( KSpreadCell::PFont ) );
01540     }
01541     void doWork( RowFormat* rw ) {
01542     if ( _font )
01543         rw->setTextFontFamily( _font );
01544     if ( _size > 0 )
01545         rw->setTextFontSize( _size );
01546     if ( _italic >= 0 )
01547         rw->setTextFontItalic( (bool)_italic );
01548     if ( _bold >= 0 )
01549         rw->setTextFontBold( (bool)_bold );
01550     if ( _underline >= 0 )
01551         rw->setTextFontUnderline( (bool)_underline );
01552     if ( _strike >= 0 )
01553         rw->setTextFontStrike( (bool)_strike );
01554     }
01555     void doWork( ColumnFormat* cl ) {
01556     if ( _font )
01557         cl->setTextFontFamily( _font );
01558     if ( _size > 0 )
01559         cl->setTextFontSize( _size );
01560     if ( _italic >= 0 )
01561         cl->setTextFontItalic( (bool)_italic );
01562     if ( _bold >= 0 )
01563         cl->setTextFontBold( (bool)_bold );
01564     if ( _underline >= 0 )
01565         cl->setTextFontUnderline( (bool)_underline );
01566     if ( _strike >= 0 )
01567         cl->setTextFontStrike( (bool)_strike );
01568     }
01569     void prepareCell( KSpreadCell* cell ) {
01570     cell->clearProperty( KSpreadCell::PFont );
01571     cell->clearNoFallBackProperties( KSpreadCell::PFont );
01572     }
01573     bool testCondition( KSpreadCell* cell ) {
01574     return ( !cell->isObscuringForced() );
01575     }
01576     void doWork( KSpreadCell* cell, bool cellRegion, int, int ) {
01577     if ( cellRegion )
01578         cell->setDisplayDirtyFlag();
01579     if ( _font )
01580         cell->setTextFontFamily( _font );
01581     if ( _size > 0 )
01582         cell->setTextFontSize( _size );
01583     if ( _italic >= 0 )
01584         cell->setTextFontItalic( (bool)_italic );
01585     if ( _bold >= 0 )
01586         cell->setTextFontBold( (bool)_bold );
01587     if ( _underline >= 0 )
01588         cell->setTextFontUnderline( (bool)_underline );
01589     if ( _strike >= 0 )
01590         cell->setTextFontStrike( (bool)_strike );
01591         if ( cellRegion )
01592         cell->clearDisplayDirtyFlag();
01593     }
01594 };
01595 
01596 void KSpreadSheet::setSelectionFont( KSpreadSelection* selectionInfo,
01597                                      const char *_font, int _size,
01598                                      signed char _bold, signed char _italic,
01599                                      signed char _underline, signed char _strike)
01600 {
01601     SetSelectionFontWorker w( _font, _size, _bold, _italic, _underline, _strike );
01602     workOnCells( selectionInfo, w );
01603 }
01604 
01605 struct SetSelectionSizeWorker : public KSpreadSheet::CellWorkerTypeA {
01606     int _size, size;
01607     SetSelectionSizeWorker( int __size, int size2 ) : _size( __size ), size( size2 ) { }
01608 
01609     QString getUndoTitle() { return i18n("Change Font"); }
01610     bool testCondition( RowFormat* rw ) {
01611         return ( rw->hasProperty( KSpreadCell::PFont ) );
01612     }
01613     void doWork( RowFormat* rw ) {
01614     rw->setTextFontSize( size + _size) ;
01615     }
01616     void doWork( ColumnFormat* cl ) {
01617     cl->setTextFontSize( size + _size );
01618     }
01619     void prepareCell( KSpreadCell* cell ) {
01620     cell->clearProperty( KSpreadCell::PFont );
01621     cell->clearNoFallBackProperties( KSpreadCell::PFont );
01622     }
01623     bool testCondition( KSpreadCell* cell ) {
01624     return ( !cell->isObscuringForced() );
01625     }
01626     void doWork( KSpreadCell* cell, bool cellRegion, int, int ) {
01627     if ( cellRegion )
01628         cell->setDisplayDirtyFlag();
01629     cell->setTextFontSize( size + _size );
01630         if ( cellRegion )
01631         cell->clearDisplayDirtyFlag();
01632     }
01633 };
01634 
01635 void KSpreadSheet::setSelectionSize( KSpreadSelection* selectionInfo, int _size )
01636 {
01637     int size;
01638     KSpreadCell* c;
01639     QPoint marker(selectionInfo->marker());
01640     c = cellAt(marker);
01641     size = c->textFontSize(marker.x(), marker.y());
01642 
01643     SetSelectionSizeWorker w( _size, size );
01644     workOnCells( selectionInfo, w );
01645 }
01646 
01647 
01648 struct SetSelectionUpperLowerWorker : public KSpreadSheet::CellWorker {
01649     int _type;
01650     KSpreadSheet   * _s;
01651     SetSelectionUpperLowerWorker( int type, KSpreadSheet * s )
01652       : KSpreadSheet::CellWorker( false ), _type( type ),  _s( s ) { }
01653 
01654     class KSpreadUndoAction* createUndoAction( KSpreadDoc* doc, KSpreadSheet* sheet, QRect& r ) {
01655     return new KSpreadUndoChangeAreaTextCell( doc, sheet, r );
01656     }
01657     bool testCondition( KSpreadCell* c ) {
01658     return ( !c->value().isNumber() && !c->value().isBoolean() &&!c->isFormula() && !c->isDefault()
01659          && !c->text().isEmpty() && c->text()[0] != '*' && c->text()[0] != '!'
01660          && !c->isObscuringForced() );
01661     }
01662     void doWork( KSpreadCell* cell, bool, int, int )
01663     {
01664     cell->setDisplayDirtyFlag();
01665     if ( _type == -1 )
01666         cell->setCellText( (cell->text().lower()));
01667     else if ( _type == 1 )
01668         cell->setCellText( (cell->text().upper()));
01669     cell->clearDisplayDirtyFlag();
01670     }
01671 };
01672 
01673 void KSpreadSheet::setSelectionUpperLower( KSpreadSelection* selectionInfo,
01674                                            int _type )
01675 {
01676   SetSelectionUpperLowerWorker w( _type, this );
01677   workOnCells( selectionInfo, w );
01678 }
01679 
01680 
01681 struct SetSelectionFirstLetterUpperWorker : public KSpreadSheet::CellWorker
01682 {
01683     KSpreadChanges * _c;
01684     KSpreadSheet   * _s;
01685     SetSelectionFirstLetterUpperWorker( KSpreadSheet * s )
01686       : KSpreadSheet::CellWorker( false ),  _s( s ) { }
01687 
01688     class KSpreadUndoAction* createUndoAction( KSpreadDoc* doc, KSpreadSheet* sheet, QRect& r ) {
01689     return   new KSpreadUndoChangeAreaTextCell( doc, sheet, r );
01690     }
01691     bool testCondition( KSpreadCell* c ) {
01692     return ( !c->value().isNumber() && !c->value().isBoolean() &&!c->isFormula() && !c->isDefault()
01693          && !c->text().isEmpty() && c->text()[0] != '*' && c->text()[0] != '!'
01694          && !c->isObscuringForced() );
01695     }
01696     void doWork( KSpreadCell* cell, bool, int, int )
01697     {
01698 
01699     cell->setDisplayDirtyFlag();
01700     QString tmp = cell->text();
01701     int len = tmp.length();
01702     cell->setCellText( (tmp.at(0).upper()+tmp.right(len-1)) );
01703     cell->clearDisplayDirtyFlag();
01704     }
01705 };
01706 
01707 void KSpreadSheet::setSelectionfirstLetterUpper( KSpreadSelection* selectionInfo)
01708 {
01709   SetSelectionFirstLetterUpperWorker w(  this );
01710   workOnCells( selectionInfo, w );
01711 }
01712 
01713 
01714 struct SetSelectionVerticalTextWorker : public KSpreadSheet::CellWorker {
01715     bool _b;
01716     SetSelectionVerticalTextWorker( bool b ) : KSpreadSheet::CellWorker( ), _b( b ) { }
01717 
01718     class KSpreadUndoAction* createUndoAction( KSpreadDoc* doc, KSpreadSheet* sheet, QRect& r ) {
01719         QString title=i18n("Vertical Text");
01720     return new KSpreadUndoCellFormat( doc, sheet, r, title );
01721     }
01722     bool testCondition( KSpreadCell* cell ) {
01723     return ( !cell->isObscuringForced() );
01724     }
01725     void doWork( KSpreadCell* cell, bool, int, int ) {
01726     cell->setDisplayDirtyFlag();
01727     cell->setVerticalText( _b );
01728     cell->setMultiRow( false );
01729     cell->setAngle( 0 );
01730     cell->clearDisplayDirtyFlag();
01731     }
01732 };
01733 
01734 void KSpreadSheet::setSelectionVerticalText( KSpreadSelection* selectionInfo,
01735                                              bool _b )
01736 {
01737     SetSelectionVerticalTextWorker w( _b );
01738     workOnCells( selectionInfo, w );
01739 }
01740 
01741 
01742 struct SetSelectionCommentWorker : public KSpreadSheet::CellWorker {
01743     QString _comment;
01744     SetSelectionCommentWorker( QString comment ) : KSpreadSheet::CellWorker( ), _comment( comment ) { }
01745 
01746     class KSpreadUndoAction* createUndoAction( KSpreadDoc* doc, KSpreadSheet* sheet, QRect& r ) {
01747         QString title=i18n("Add Comment");
01748     return new KSpreadUndoCellFormat( doc, sheet, r, title );
01749     }
01750     bool testCondition( KSpreadCell* cell ) {
01751     return ( !cell->isObscuringForced() );
01752     }
01753     void doWork( KSpreadCell* cell, bool, int, int ) {
01754     cell->setDisplayDirtyFlag();
01755     cell->setComment( _comment );
01756     cell->clearDisplayDirtyFlag();
01757     }
01758 };
01759 
01760 void KSpreadSheet::setSelectionComment( KSpreadSelection* selectionInfo,
01761                                         const QString &_comment)
01762 {
01763     SetSelectionCommentWorker w( _comment );
01764     workOnCells( selectionInfo, w );
01765 }
01766 
01767 
01768 struct SetSelectionAngleWorker : public KSpreadSheet::CellWorkerTypeA {
01769     int _value;
01770     SetSelectionAngleWorker( int value ) : _value( value ) { }
01771 
01772     QString getUndoTitle() { return i18n("Change Angle"); }
01773     KSpreadUndoAction* createUndoAction( KSpreadDoc* doc, KSpreadSheet* sheet, QRect& r ){
01774         return new KSpreadUndoChangeAngle( doc, sheet, r );
01775     }
01776 
01777     bool testCondition( RowFormat* rw ) {
01778         return ( rw->hasProperty( KSpreadCell::PAngle ) );
01779     }
01780     void doWork( RowFormat* rw ) {
01781     rw->setAngle( _value );
01782     }
01783     void doWork( ColumnFormat* cl ) {
01784     cl->setAngle( _value );
01785     }
01786     void prepareCell( KSpreadCell* cell ) {
01787     cell->clearProperty( KSpreadCell::PAngle );
01788     cell->clearNoFallBackProperties( KSpreadCell::PAngle );
01789     }
01790     bool testCondition( KSpreadCell* cell ) {
01791     return ( !cell->isObscuringForced() );
01792     }
01793     void doWork( KSpreadCell* cell, bool cellRegion, int, int ) {
01794     if ( cellRegion )
01795         cell->setDisplayDirtyFlag();
01796     cell->setAngle( _value );
01797     if ( cellRegion ) {
01798         cell->setVerticalText(false);
01799         cell->setMultiRow( false );
01800         cell->clearDisplayDirtyFlag();
01801     }
01802     }
01803 };
01804 
01805 void KSpreadSheet::setSelectionAngle( KSpreadSelection* selectionInfo,
01806                                       int _value )
01807 {
01808     SetSelectionAngleWorker w( _value );
01809     workOnCells( selectionInfo, w );
01810 }
01811 
01812 struct SetSelectionRemoveCommentWorker : public KSpreadSheet::CellWorker {
01813     SetSelectionRemoveCommentWorker( ) : KSpreadSheet::CellWorker( false ) { }
01814 
01815     class KSpreadUndoAction* createUndoAction( KSpreadDoc* doc, KSpreadSheet* sheet, QRect& r ) {
01816         QString title=i18n("Remove Comment");
01817     return new KSpreadUndoCellFormat( doc, sheet, r, title );
01818     }
01819     bool testCondition( KSpreadCell* cell ) {
01820     return ( !cell->isObscuringForced() );
01821     }
01822     void doWork( KSpreadCell* cell, bool, int, int ) {
01823     cell->setDisplayDirtyFlag();
01824     cell->setComment( "" );
01825     cell->clearDisplayDirtyFlag();
01826     }
01827 };
01828 
01829 void KSpreadSheet::setSelectionRemoveComment( KSpreadSelection* selectionInfo )
01830 {
01831     if(areaIsEmpty(selectionInfo->selection(), Comment))
01832         return;
01833     SetSelectionRemoveCommentWorker w;
01834     workOnCells( selectionInfo, w );
01835 }
01836 
01837 
01838 struct SetSelectionTextColorWorker : public KSpreadSheet::CellWorkerTypeA {
01839     const QColor& tb_Color;
01840     SetSelectionTextColorWorker( const QColor& _tb_Color ) : tb_Color( _tb_Color ) { }
01841 
01842     QString getUndoTitle() { return i18n("Change Text Color"); }
01843     bool testCondition( RowFormat* rw ) {
01844         return ( rw->hasProperty( KSpreadCell::PTextPen ) );
01845     }
01846     void doWork( RowFormat* rw ) {
01847     rw->setTextColor( tb_Color );
01848     }
01849     void doWork( ColumnFormat* cl ) {
01850     cl->setTextColor( tb_Color );
01851     }
01852     void prepareCell( KSpreadCell* cell ) {
01853     cell->clearProperty( KSpreadCell::PTextPen );
01854     cell->clearNoFallBackProperties( KSpreadCell::PTextPen );
01855     }
01856     bool testCondition( KSpreadCell* cell ) {
01857     return ( !cell->isObscuringForced() );
01858     }
01859     void doWork( KSpreadCell* cell, bool cellRegion, int, int ) {
01860     if ( cellRegion )
01861         cell->setDisplayDirtyFlag();
01862     cell->setTextColor( tb_Color );
01863     if ( cellRegion )
01864         cell->clearDisplayDirtyFlag();
01865     }
01866 };
01867 
01868 void KSpreadSheet::setSelectionTextColor( KSpreadSelection* selectionInfo,
01869                                           const QColor &tb_Color )
01870 {
01871     SetSelectionTextColorWorker w( tb_Color );
01872     workOnCells( selectionInfo, w );
01873 }
01874 
01875 
01876 struct SetSelectionBgColorWorker : public KSpreadSheet::CellWorkerTypeA {
01877     const QColor& bg_Color;
01878     SetSelectionBgColorWorker( const QColor& _bg_Color ) : bg_Color( _bg_Color ) { }
01879 
01880     QString getUndoTitle() { return i18n("Change Background Color"); }
01881     bool testCondition( RowFormat* rw ) {
01882         return ( rw->hasProperty( KSpreadCell::PBackgroundColor ) );
01883     }
01884     void doWork( RowFormat* rw ) {
01885     rw->setBgColor( bg_Color );
01886     }
01887     void doWork( ColumnFormat* cl ) {
01888     cl->setBgColor( bg_Color );
01889     }
01890     void prepareCell( KSpreadCell* cell ) {
01891     cell->clearProperty( KSpreadCell::PBackgroundColor );
01892     cell->clearNoFallBackProperties( KSpreadCell::PBackgroundColor );
01893     }
01894     bool testCondition( KSpreadCell* cell ) {
01895     return ( !cell->isObscuringForced() );
01896     }
01897     void doWork( KSpreadCell* cell, bool cellRegion, int, int ) {
01898     if ( cellRegion )
01899         cell->setDisplayDirtyFlag();
01900     cell->setBgColor( bg_Color );
01901     if ( cellRegion )
01902         cell->clearDisplayDirtyFlag();
01903     }
01904 };
01905 
01906 void KSpreadSheet::setSelectionbgColor( KSpreadSelection* selectionInfo,
01907                                         const QColor &bg_Color )
01908 {
01909     SetSelectionBgColorWorker w( bg_Color );
01910     workOnCells( selectionInfo, w );
01911 }
01912 
01913 
01914 struct SetSelectionBorderColorWorker : public KSpreadSheet::CellWorker {
01915     const QColor& bd_Color;
01916     SetSelectionBorderColorWorker( const QColor& _bd_Color ) : KSpreadSheet::CellWorker( false ), bd_Color( _bd_Color ) { }
01917 
01918     class KSpreadUndoAction* createUndoAction( KSpreadDoc* doc, KSpreadSheet* sheet, QRect& r ) {
01919         QString title=i18n("Change Border Color");
01920     return new KSpreadUndoCellFormat( doc, sheet, r, title );
01921     }
01922     bool testCondition( KSpreadCell* cell ) {
01923     return ( !cell->isObscuringForced() );
01924     }
01925     void doWork( KSpreadCell* cell, bool, int, int ) {
01926     cell->setDisplayDirtyFlag();
01927     int it_Row = cell->row();
01928     int it_Col = cell->column();
01929     if ( cell->topBorderStyle( it_Row, it_Col )!=Qt::NoPen )
01930         cell->setTopBorderColor( bd_Color );
01931     if ( cell->leftBorderStyle( it_Row, it_Col )!=Qt::NoPen )
01932         cell->setLeftBorderColor( bd_Color );
01933     if ( cell->fallDiagonalStyle( it_Row, it_Col )!=Qt::NoPen )
01934         cell->setFallDiagonalColor( bd_Color );
01935     if ( cell->goUpDiagonalStyle( it_Row, it_Col )!=Qt::NoPen )
01936         cell->setGoUpDiagonalColor( bd_Color );
01937     if ( cell->bottomBorderStyle( it_Row, it_Col )!=Qt::NoPen )
01938         cell->setBottomBorderColor( bd_Color );
01939     if ( cell->rightBorderStyle( it_Row, it_Col )!=Qt::NoPen )
01940         cell->setRightBorderColor( bd_Color );
01941     cell->clearDisplayDirtyFlag();
01942     }
01943 };
01944 
01945 void KSpreadSheet::setSelectionBorderColor( KSpreadSelection* selectionInfo,
01946                                             const QColor &bd_Color )
01947 {
01948     SetSelectionBorderColorWorker w( bd_Color );
01949     workOnCells( selectionInfo, w );
01950 }
01951 
01952 
01953 void KSpreadSheet::setSeries( const QPoint &_marker, double start, double end, double step, Series mode, Series type)
01954 {
01955   doc()->emitBeginOperation();
01956 
01957   QString cellText;
01958 
01959   int x,y; /* just some loop counters */
01960 
01961   /* the actual number of columns or rows that the series will span.
01962      i.e. this will count 3 cells for a single cell that spans three rows
01963   */
01964   int numberOfCells;
01965   if (end > start)
01966     numberOfCells = (int) ((end - start) / step + 1); /*initialize for linear*/
01967   else if ( end <start )
01968     numberOfCells = (int) ((start - end) / step + 1); /*initialize for linear*/
01969   else //equal ! => one cell fix infini loop
01970       numberOfCells = 1;
01971   if (type == Geometric)
01972   {
01973     /* basically, A(n) = start ^ n
01974      * so when does end = start ^ n ??
01975      * when n = ln(end) / ln(start)
01976      */
01977     numberOfCells = (int)( (log((double)end) / log((double)start)) +
01978                  DBL_EPSILON) + 1;
01979   }
01980 
01981   KSpreadCell * cell = NULL;
01982 
01983   /* markers for the top-left corner of the undo region.  It'll probably
01984    * be the top left corner of where the series is, but if something in front
01985    * is obscuring the cell, then it needs to be part of the undo region */
01986   QRect undoRegion;
01987 
01988   undoRegion.setLeft(_marker.x());
01989   undoRegion.setTop(_marker.y());
01990 
01991   /* this whole block is used to find the correct size for the undo region.
01992      We're checking for two different things (in these examples,
01993        mode==column):
01994 
01995        1.  cells are vertically merged.  This means that one value in the
01996        series will span multiple cells.
01997 
01998        2.  a cell in the column is merged to a cell to its left.  In this case
01999        the cell value will be stored in the left most cell so we need to
02000        extend the undo range to include that column.
02001   */
02002   if ( mode == Column )
02003   {
02004     for ( y = _marker.y(); y <= (_marker.y() + numberOfCells - 1); y++ )
02005     {
02006       cell = cellAt( _marker.x(), y );
02007 
02008       if ( cell->isObscuringForced() )
02009       {
02010         /* case 2. */
02011         cell = cell->obscuringCells().first();
02012         undoRegion.setLeft(QMIN(undoRegion.left(), cell->column()));
02013       }
02014       /* case 1.  Add the extra space to numberOfCells and then skip
02015          over the region.  Note that because of the above if block 'cell'
02016          points to the correct cell in the case where both case 1 and 2
02017          are true
02018       */
02019       numberOfCells += cell->extraYCells();
02020       y += cell->extraYCells();
02021     }
02022     undoRegion.setRight( _marker.x() );
02023     undoRegion.setBottom( y - 1 );
02024   }
02025   else if(mode == Row)
02026   {
02027     for ( x = _marker.x(); x <=(_marker.x() + numberOfCells - 1); x++ )
02028     {
02029       /* see the code above for a column series for a description of
02030          what is going on here. */
02031       cell = cellAt( x,_marker.y() );
02032 
02033       if ( cell->isObscuringForced() )
02034       {
02035         cell = cell->obscuringCells().first();
02036         undoRegion.setTop(QMIN(undoRegion.top(), cell->row()));
02037       }
02038       numberOfCells += cell->extraXCells();
02039       x += cell->extraXCells();
02040     }
02041     undoRegion.setBottom( _marker.y() );
02042     undoRegion.setRight( x - 1 );
02043   }
02044 
02045   kdDebug() << "Saving undo information" << endl;
02046 
02047   if ( !doc()->undoLocked() )
02048   {
02049     KSpreadUndoChangeAreaTextCell *undo = new
02050       KSpreadUndoChangeAreaTextCell( doc(), this, undoRegion );
02051     doc()->addCommand( undo );
02052   }
02053 
02054   kdDebug() << "Saving undo information done" << endl;
02055 
02056   x = _marker.x();
02057   y = _marker.y();
02058 
02059   /* now we're going to actually loop through and set the values */
02060   double incr;
02061   KSpreadStyle * s = doc()->styleManager()->defaultStyle();
02062   if (step >= 0 && start < end)
02063   {
02064     for ( incr = start; incr <= end; )
02065     {
02066       cell = nonDefaultCell( x, y, false, s );
02067 
02068       if ( cell->isObscuringForced() )
02069       {
02070         cell = cell->obscuringCells().first();
02071       }
02072 
02073       //      cell->setCellText(cellText.setNum( incr ));
02074 
02075       cell->setNumber( incr );
02076       if (mode == Column)
02077       {
02078         ++y;
02079         if (cell->isForceExtraCells())
02080         {
02081           y += cell->extraYCells();
02082         }
02083       }
02084       else if (mode == Row)
02085       {
02086         ++x;
02087         if (cell->isForceExtraCells())
02088         {
02089           x += cell->extraXCells();
02090         }
02091       }
02092       else
02093       {
02094         kdDebug(36001) << "Error in Series::mode" << endl;
02095         return;
02096       }
02097 
02098       if (type == Linear)
02099         incr = incr + step;
02100       else if (type == Geometric)
02101         incr = incr * step;
02102       else
02103       {
02104         kdDebug(36001) << "Error in Series::type" << endl;
02105         return;
02106       }
02107     }
02108   }
02109   else
02110   if (step >= 0 && start > end)
02111   {
02112     for ( incr = start; incr >= end; )
02113     {
02114       cell = nonDefaultCell( x, y, false, s );
02115 
02116       if (cell->isObscuringForced())
02117       {
02118         cell = cell->obscuringCells().first();
02119       }
02120 
02121       //      cell->setCellText(cellText.setNum( incr ));
02122       cell->setNumber( incr );
02123       if (mode == Column)
02124       {
02125         ++y;
02126         if (cell->isForceExtraCells())
02127         {
02128           y += cell->extraYCells();
02129         }
02130       }
02131       else if (mode == Row)
02132       {
02133         ++x;
02134         if (cell->isForceExtraCells())
02135         {
02136           x += cell->extraXCells();
02137         }
02138       }
02139       else
02140       {
02141         kdDebug(36001) << "Error in Series::mode" << endl;
02142         return;
02143       }
02144 
02145       if (type == Linear)
02146         incr = incr + step;
02147       else if (type == Geometric)
02148         incr = incr * step;
02149       else
02150       {
02151         kdDebug(36001) << "Error in Series::type" << endl;
02152         return;
02153       }
02154     }
02155   }
02156   else
02157   {
02158     for ( incr = start; incr <= end; )
02159     {
02160       cell = nonDefaultCell( x, y, false, s );
02161 
02162       if (cell->isObscuringForced())
02163       {
02164         cell = cell->obscuringCells().first();
02165       }
02166 
02167       //cell->setCellText(cellText.setNum( incr ));
02168       cell->setNumber( incr );
02169       if (mode == Column)
02170       {
02171         ++y;
02172         if (cell->isForceExtraCells())
02173         {
02174           y += cell->extraYCells();
02175         }
02176       }
02177       else if (mode == Row)
02178       {
02179         ++x;
02180         if (cell->isForceExtraCells())
02181         {
02182           x += cell->extraXCells();
02183         }
02184       }
02185       else
02186       {
02187         kdDebug(36001) << "Error in Series::mode" << endl;
02188         return;
02189       }
02190 
02191       if (type == Linear)
02192         incr = incr + step;
02193       else if (type == Geometric)
02194       {
02195 
02196         incr = incr * step;
02197         //a step = 1 into geometric serie is not good
02198         //we don't increase value => infini loop
02199         if (step == 1)
02200             return;
02201       }
02202       else
02203       {
02204         kdDebug(36001) << "Error in Series::type" << endl;
02205         return;
02206       }
02207     }
02208   }
02209   //  doc()->emitEndOperation();
02210   emit sig_updateView( this );
02211 }
02212 
02213 
02214 struct SetSelectionPercentWorker : public KSpreadSheet::CellWorkerTypeA
02215 {
02216     bool b;
02217     SetSelectionPercentWorker( bool _b ) : b( _b ) { }
02218 
02219     QString getUndoTitle() { return i18n("Format Percent"); }
02220     bool testCondition( RowFormat* rw ) {
02221         //TODO: no idea what to put here, now that factor's gone :(
02222         return ( true );
02223     }
02224     void doWork( RowFormat* rw ) {
02225     //rw->setPrecision( 0 );
02226     rw->setFormatType( b ? Percentage_format : Generic_format);
02227     }
02228     void doWork( ColumnFormat* cl ) {
02229     cl->setFormatType( b ? Percentage_format : Generic_format);
02230     }
02231     void prepareCell( KSpreadCell* cell ) {
02232     cell->clearProperty(KSpreadCell::PFormatType);
02233     cell->clearNoFallBackProperties( KSpreadCell::PFormatType );
02234     }
02235     bool testCondition( KSpreadCell* cell ) {
02236     return ( !cell->isObscuringForced() );
02237     }
02238     void doWork( KSpreadCell* cell, bool cellRegion, int, int ) {
02239     if ( cellRegion )
02240         cell->setDisplayDirtyFlag();
02241     cell->setFormatType( b ? Percentage_format : Generic_format);
02242     if ( cellRegion )
02243         cell->clearDisplayDirtyFlag();
02244     }
02245 };
02246 
02247 void KSpreadSheet::setSelectionPercent( KSpreadSelection* selectionInfo, bool b )
02248 {
02249     SetSelectionPercentWorker w( b );
02250     workOnCells( selectionInfo, w );
02251 }
02252 
02253 
02254 void KSpreadSheet::refreshRemoveAreaName(const QString & _areaName)
02255 {
02256   KSpreadCell * c = d->cells.firstCell();
02257   QString tmp = "'" + _areaName + "'";
02258   for( ;c ; c = c->nextCell() )
02259   {
02260     if ( c->isFormula() )
02261     {
02262       if (c->text().find(tmp) != -1)
02263       {
02264         if ( !c->makeFormula() )
02265           kdError(36001) << "ERROR: Syntax ERROR" << endl;
02266       }
02267     }
02268   }
02269 }
02270 
02271 void KSpreadSheet::refreshChangeAreaName(const QString & _areaName)
02272 {
02273   KSpreadCell * c = d->cells.firstCell();
02274   QString tmp = "'" + _areaName + "'";
02275   for( ;c ; c = c->nextCell() )
02276   {
02277     if ( c->isFormula() )
02278     {
02279       if (c->text().find(tmp) != -1)
02280       {
02281         if ( !c->makeFormula() )
02282           kdError(36001) << "ERROR: Syntax ERROR" << endl;
02283         else
02284         {
02285           /* setting a cell calc dirty also sets it paint dirty */
02286           c->setCalcDirtyFlag();
02287         }
02288       }
02289     }
02290   }
02291 }
02292 
02293 void KSpreadSheet::changeCellTabName( QString const & old_name, QString const & new_name )
02294 {
02295     KSpreadCell* c = d->cells.firstCell();
02296     for( ;c; c = c->nextCell() )
02297     {
02298         if( c->isFormula() )
02299         {
02300             if(c->text().find(old_name)!=-1)
02301             {
02302                 int nb = c->text().contains(old_name+"!");
02303                 QString tmp=old_name+"!";
02304                 int len = tmp.length();
02305                 tmp=c->text();
02306 
02307                 for( int i=0; i<nb; i++ )
02308                 {
02309                     int pos = tmp.find( old_name+"!" );
02310                     tmp.replace( pos, len, new_name+"!" );
02311                 }
02312                 c->setCellText(tmp);
02313             }
02314         }
02315     }
02316 }
02317 
02318 bool KSpreadSheet::shiftRow( const QRect &rect,bool makeUndo )
02319 {
02320     KSpreadUndoInsertCellRow * undo = 0;
02321     if ( !doc()->undoLocked()  &&makeUndo)
02322     {
02323         undo = new KSpreadUndoInsertCellRow( doc(), this, rect );
02324         doc()->addCommand( undo );
02325     }
02326 
02327     bool res=true;
02328     bool result;
02329     for( int i=rect.top(); i<=rect.bottom(); i++ )
02330     {
02331         for( int j=0; j<=(rect.right()-rect.left()); j++ )
02332         {
02333             result = d->cells.shiftRow( QPoint(rect.left(),i) );
02334             if( !result )
02335                 res=false;
02336         }
02337     }
02338     QPtrListIterator<KSpreadSheet> it( workbook()->sheetList() );
02339     for( ; it.current(); ++it )
02340     {
02341         for(int i = rect.top(); i <= rect.bottom(); i++ )
02342             it.current()->changeNameCellRef( QPoint( rect.left(), i ), false,
02343                                              KSpreadSheet::ColumnInsert, name(),
02344                                              ( rect.right() - rect.left() + 1),
02345                                              undo);
02346     }
02347     refreshChart(QPoint(rect.left(),rect.top()), false, KSpreadSheet::ColumnInsert);
02348     refreshMergedCell();
02349     recalc();
02350     emit sig_updateView( this );
02351 
02352     return res;
02353 }
02354 
02355 bool KSpreadSheet::shiftColumn( const QRect& rect,bool makeUndo )
02356 {
02357     KSpreadUndoInsertCellCol * undo = 0;
02358     if ( !doc()->undoLocked()  &&makeUndo)
02359     {
02360         undo = new KSpreadUndoInsertCellCol( doc(), this,rect);
02361         doc()->addCommand( undo );
02362     }
02363 
02364     bool res=true;
02365     bool result;
02366     for( int i =rect.left(); i<=rect.right(); i++ )
02367     {
02368         for( int j=0; j<=(rect.bottom()-rect.top()); j++ )
02369         {
02370             result = d->cells.shiftColumn( QPoint(i,rect.top()) );
02371             if(!result)
02372                 res=false;
02373         }
02374     }
02375 
02376     QPtrListIterator<KSpreadSheet> it( workbook()->sheetList() );
02377     for( ; it.current(); ++it )
02378     {
02379         for(int i=rect.left();i<=rect.right();i++)
02380             it.current()->changeNameCellRef( QPoint( i, rect.top() ), false,
02381                                              KSpreadSheet::RowInsert, name(),
02382                                              ( rect.bottom() - rect.top() + 1 ),
02383                                              undo );
02384     }
02385     refreshChart(/*marker*/QPoint(rect.left(),rect.top()), false, KSpreadSheet::RowInsert);
02386     refreshMergedCell();
02387     recalc();
02388     emit sig_updateView( this );
02389 
02390     return res;
02391 }
02392 
02393 void KSpreadSheet::unshiftColumn( const QRect & rect,bool makeUndo )
02394 {
02395     KSpreadUndoRemoveCellCol * undo = 0;
02396     if ( !doc()->undoLocked() && makeUndo )
02397     {
02398         undo = new KSpreadUndoRemoveCellCol( doc(), this, rect );
02399         doc()->addCommand( undo );
02400     }
02401 
02402     for(int i =rect.top();i<=rect.bottom();i++)
02403         for(int j=rect.left();j<=rect.right();j++)
02404                d->cells.remove(j,i);
02405 
02406     for(int i =rect.left();i<=rect.right();i++)
02407         for(int j=0;j<=(rect.bottom()-rect.top());j++)
02408                 d->cells.unshiftColumn( QPoint(i,rect.top()) );
02409 
02410     QPtrListIterator<KSpreadSheet> it( workbook()->sheetList() );
02411     for( ; it.current(); ++it )
02412         for(int i=rect.left();i<=rect.right();i++)
02413                 it.current()->changeNameCellRef( QPoint( i, rect.top() ), false,
02414                                                  KSpreadSheet::RowRemove, name(),
02415                                                  ( rect.bottom() - rect.top() + 1 ),
02416                                                  undo );
02417 
02418     refreshChart( QPoint(rect.left(),rect.top()), false, KSpreadSheet::RowRemove );
02419     refreshMergedCell();
02420     recalc();
02421     emit sig_updateView( this );
02422 }
02423 
02424 void KSpreadSheet::unshiftRow( const QRect & rect,bool makeUndo )
02425 {
02426     KSpreadUndoRemoveCellRow * undo = 0;
02427     if ( !doc()->undoLocked() && makeUndo )
02428     {
02429         undo = new KSpreadUndoRemoveCellRow( doc(), this, rect );
02430         doc()->addCommand( undo );
02431     }
02432     for(int i =rect.top();i<=rect.bottom();i++)
02433         for(int j=rect.left();j<=rect.right();j++)
02434                 d->cells.remove(j,i);
02435 
02436     for(int i =rect.top();i<=rect.bottom();i++)
02437         for(int j=0;j<=(rect.right()-rect.left());j++)
02438                 d->cells.unshiftRow( QPoint(rect.left(),i) );
02439 
02440     QPtrListIterator<KSpreadSheet> it( workbook()->sheetList() );
02441     for( ; it.current(); ++it )
02442         for(int i=rect.top();i<=rect.bottom();i++)
02443                 it.current()->changeNameCellRef( QPoint( rect.left(), i ), false,
02444                                                  KSpreadSheet::ColumnRemove, name(),
02445                                                  ( rect.right() - rect.left() + 1 ),
02446                                                  undo);
02447 
02448     refreshChart(QPoint(rect.left(),rect.top()), false, KSpreadSheet::ColumnRemove );
02449     refreshMergedCell();
02450     recalc();
02451     emit sig_updateView( this );
02452 }
02453 
02454 bool KSpreadSheet::insertColumn( int col, int nbCol, bool makeUndo )
02455 {
02456     KSpreadUndoInsertColumn * undo = 0;
02457     if ( !doc()->undoLocked() && makeUndo)
02458     {
02459         undo = new KSpreadUndoInsertColumn( doc(), this, col, nbCol );
02460         doc()->addCommand( undo );
02461     }
02462 
02463     bool res=true;
02464     bool result;
02465     for( int i=0; i<=nbCol; i++ )
02466     {
02467         // Recalculate range max (minus size of last column)
02468         d->sizeMaxX -= columnFormat( KS_colMax )->dblWidth();
02469 
02470         result = d->cells.insertColumn( col );
02471         d->columns.insertColumn( col );
02472         if(!result)
02473             res = false;
02474 
02475         //Recalculate range max (plus size of new column)
02476         d->sizeMaxX += columnFormat( col+i )->dblWidth();
02477     }
02478 
02479     QPtrListIterator<KSpreadSheet> it( workbook()->sheetList() );
02480     for( ; it.current(); ++it )
02481         it.current()->changeNameCellRef( QPoint( col, 1 ), true,
02482                                          KSpreadSheet::ColumnInsert, name(),
02483                                          nbCol + 1, undo );
02484 
02485     //update print settings
02486     d->print->insertColumn( col, nbCol );
02487 
02488     refreshChart( QPoint( col, 1 ), true, KSpreadSheet::ColumnInsert );
02489     refreshMergedCell();
02490     recalc();
02491     emit sig_updateHBorder( this );
02492     emit sig_updateView( this );
02493 
02494     return res;
02495 }
02496 
02497 bool KSpreadSheet::insertRow( int row, int nbRow, bool makeUndo )
02498 {
02499     KSpreadUndoInsertRow *undo = 0;
02500     if ( !doc()->undoLocked() && makeUndo)
02501     {
02502         undo = new KSpreadUndoInsertRow( doc(), this, row, nbRow );
02503         doc()->addCommand( undo );
02504     }
02505 
02506     bool res=true;
02507     bool result;
02508     for( int i=0; i<=nbRow; i++ )
02509     {
02510         // Recalculate range max (minus size of last row)
02511         d->sizeMaxY -= rowFormat( KS_rowMax )->dblHeight();
02512 
02513         result = d->cells.insertRow( row );
02514         d->rows.insertRow( row );
02515         if( !result )
02516             res = false;
02517 
02518         //Recalculate range max (plus size of new row)
02519         d->sizeMaxY += rowFormat( row )->dblHeight();
02520     }
02521 
02522     QPtrListIterator<KSpreadSheet> it( workbook()->sheetList() );
02523     for( ; it.current(); ++it )
02524         it.current()->changeNameCellRef( QPoint( 1, row ), true,
02525                                          KSpreadSheet::RowInsert, name(),
02526                                          nbRow + 1, undo );
02527 
02528     //update print settings
02529     d->print->insertRow( row, nbRow );
02530 
02531     refreshChart( QPoint( 1, row ), true, KSpreadSheet::RowInsert );
02532     refreshMergedCell();
02533     recalc();
02534     emit sig_updateVBorder( this );
02535     emit sig_updateView( this );
02536 
02537     return res;
02538 }
02539 
02540 void KSpreadSheet::removeColumn( int col, int nbCol, bool makeUndo )
02541 {
02542     KSpreadUndoRemoveColumn *undo = 0;
02543     if ( !doc()->undoLocked() && makeUndo)
02544     {
02545         undo = new KSpreadUndoRemoveColumn( doc(), this, col, nbCol );
02546         doc()->addCommand( undo );
02547     }
02548 
02549     for( int i = 0; i <= nbCol; ++i )
02550     {
02551         // Recalculate range max (minus size of removed column)
02552         d->sizeMaxX -= columnFormat( col )->dblWidth();
02553 
02554         d->cells.removeColumn( col );
02555         d->columns.removeColumn( col );
02556 
02557         //Recalculate range max (plus size of new column)
02558         d->sizeMaxX += columnFormat( KS_colMax )->dblWidth();
02559     }
02560 
02561     QPtrListIterator<KSpreadSheet> it( workbook()->sheetList() );
02562     for( ; it.current(); ++it )
02563         it.current()->changeNameCellRef( QPoint( col, 1 ), true,
02564                                          KSpreadSheet::ColumnRemove, name(),
02565                                          nbCol + 1, undo );
02566 
02567     //update print settings
02568     d->print->removeColumn( col, nbCol );
02569 
02570     refreshChart( QPoint( col, 1 ), true, KSpreadSheet::ColumnRemove );
02571     refreshMergedCell();
02572     recalc();
02573     emit sig_updateHBorder( this );
02574     emit sig_updateView( this );
02575 }
02576 
02577 void KSpreadSheet::removeRow( int row, int nbRow, bool makeUndo )
02578 {
02579     KSpreadUndoRemoveRow *undo = 0;
02580     if ( !doc()->undoLocked() && makeUndo )
02581     {
02582         undo = new KSpreadUndoRemoveRow( doc(), this, row, nbRow );
02583         doc()->addCommand( undo );
02584     }
02585 
02586     for( int i=0; i<=nbRow; i++ )
02587     {
02588         // Recalculate range max (minus size of removed row)
02589         d->sizeMaxY -= rowFormat( row )->dblHeight();
02590 
02591         d->cells.removeRow( row );
02592         d->rows.removeRow( row );
02593 
02594         //Recalculate range max (plus size of new row)
02595         d->sizeMaxY += rowFormat( KS_rowMax )->dblHeight();
02596     }
02597 
02598     QPtrListIterator<KSpreadSheet> it( workbook()->sheetList() );
02599     for( ; it.current(); ++it )
02600         it.current()->changeNameCellRef( QPoint( 1, row ), true,
02601                                          KSpreadSheet::RowRemove, name(),
02602                                          nbRow + 1, undo );
02603 
02604     //update print settings
02605     d->print->removeRow( row, nbRow );
02606 
02607     refreshChart( QPoint( 1, row ), true, KSpreadSheet::RowRemove );
02608     refreshMergedCell();
02609     recalc();
02610     emit sig_updateVBorder( this );
02611     emit sig_updateView( this );
02612 }
02613 
02614 void KSpreadSheet::hideRow( int _row, int nbRow, QValueList<int>_list )
02615 {
02616     if ( !doc()->undoLocked() )
02617     {
02618       KSpreadUndoHideRow *undo ;
02619       if( nbRow!=-1 )
02620     undo= new KSpreadUndoHideRow( doc(), this, _row, nbRow );
02621       else
02622     undo= new KSpreadUndoHideRow( doc(), this, _row, nbRow, _list );
02623       doc()->addCommand( undo  );
02624     }
02625 
02626     RowFormat *rl;
02627     if( nbRow!=-1 )
02628     {
02629     for( int i=0; i<=nbRow; i++ )
02630     {
02631         rl=nonDefaultRowFormat( _row+i );
02632         rl->setHide(true);
02633     }
02634     }
02635     else
02636     {
02637     QValueList<int>::Iterator it;
02638     for( it = _list.begin(); it != _list.end(); ++it )
02639     {
02640         rl=nonDefaultRowFormat( *it );
02641         rl->setHide(true);
02642     }
02643     }
02644     emitHideRow();
02645 }
02646 
02647 void KSpreadSheet::emitHideRow()
02648 {
02649     emit sig_updateVBorder( this );
02650     emit sig_updateView( this );
02651 }
02652 
02653 void KSpreadSheet::showRow( int _row, int nbRow, QValueList<int>_list )
02654 {
02655     if ( !doc()->undoLocked() )
02656     {
02657       KSpreadUndoShowRow *undo;
02658       if(nbRow!=-1)
02659         undo = new KSpreadUndoShowRow( doc(), this, _row,nbRow );
02660       else
02661     undo = new KSpreadUndoShowRow( doc(), this, _row,nbRow, _list );
02662       doc()->addCommand( undo );
02663     }
02664 
02665     RowFormat *rl;
02666     if( nbRow!=-1 )
02667       {
02668     for( int i=0; i<=nbRow; i++ )
02669       {
02670         rl=nonDefaultRowFormat( _row + i );
02671         rl->setHide( false );
02672       }
02673       }
02674     else
02675       {
02676     QValueList<int>::Iterator it;
02677     for( it = _list.begin(); it != _list.end(); ++it )
02678       {
02679         rl=nonDefaultRowFormat( *it );
02680         rl->setHide( false );
02681       }
02682       }
02683     emit sig_updateVBorder( this );
02684     emit sig_updateView( this );
02685 }
02686 
02687 
02688 void KSpreadSheet::hideColumn( int _col, int nbCol, QValueList<int>_list )
02689 {
02690     if ( !doc()->undoLocked() )
02691     {
02692         KSpreadUndoHideColumn *undo;
02693     if( nbCol!=-1 )
02694       undo= new KSpreadUndoHideColumn( doc(), this, _col, nbCol );
02695     else
02696       undo= new KSpreadUndoHideColumn( doc(), this, _col, nbCol, _list );
02697         doc()->addCommand( undo );
02698     }
02699 
02700     ColumnFormat *cl;
02701     if( nbCol != -1 )
02702     {
02703     for( int i=0; i<=nbCol; i++ )
02704     {
02705         cl=nonDefaultColumnFormat( _col + i );
02706         cl->setHide( true );
02707     }
02708     }
02709     else
02710     {
02711     QValueList<int>::Iterator it;
02712     for( it = _list.begin(); it != _list.end(); ++it )
02713     {
02714         cl=nonDefaultColumnFormat( *it );
02715         cl->setHide( true );
02716     }
02717     }
02718     emitHideColumn();
02719 }
02720 
02721 void KSpreadSheet::emitHideColumn()
02722 {
02723     emit sig_updateHBorder( this );
02724     emit sig_updateView( this );
02725 }
02726 
02727 
02728 void KSpreadSheet::showColumn( int _col, int nbCol, QValueList<int>_list )
02729 {
02730     if ( !doc()->undoLocked() )
02731     {
02732       KSpreadUndoShowColumn *undo;
02733       if( nbCol != -1 )
02734     undo = new KSpreadUndoShowColumn( doc(), this, _col, nbCol );
02735       else
02736     undo = new KSpreadUndoShowColumn( doc(), this, _col, nbCol, _list );
02737       doc()->addCommand( undo );
02738     }
02739 
02740     ColumnFormat *cl;
02741     if( nbCol != -1 )
02742     {
02743       for( int i=0; i<=nbCol; i++ )
02744       {
02745     cl=nonDefaultColumnFormat( _col + i );
02746     cl->setHide( false );
02747       }
02748     }
02749     else
02750     {
02751        QValueList<int>::Iterator it;
02752        for( it = _list.begin(); it != _list.end(); ++it )
02753        {
02754        cl=nonDefaultColumnFormat( *it );
02755        cl->setHide( false );
02756        }
02757     }
02758     emit sig_updateHBorder( this );
02759     emit sig_updateView( this );
02760 }
02761 
02762 
02763 void KSpreadSheet::refreshChart(const QPoint & pos, bool fullRowOrColumn, ChangeRef ref)
02764 {
02765   KSpreadCell * c = d->cells.firstCell();
02766   for( ;c; c = c->nextCell() )
02767   {
02768     if ( (ref == ColumnInsert || ref == ColumnRemove) && fullRowOrColumn
02769         && c->column() >= (pos.x() - 1))
02770     {
02771       if (c->updateChart())
02772         return;
02773     }
02774     else if ( (ref == ColumnInsert || ref == ColumnRemove )&& !fullRowOrColumn
02775               && c->column() >= (pos.x() - 1) && c->row() == pos.y() )
02776     {
02777       if (c->updateChart())
02778         return;
02779     }
02780     else if ((ref == RowInsert || ref == RowRemove) && fullRowOrColumn
02781              && c->row() >= (pos.y() - 1))
02782     {
02783       if (c->updateChart())
02784         return;
02785     }
02786     else if ( (ref == RowInsert || ref == RowRemove) && !fullRowOrColumn
02787         && c->column() == pos.x() && c->row() >= (pos.y() - 1) )
02788     {
02789       if (c->updateChart())
02790         return;
02791     }
02792   }
02793 
02794   //refresh chart when there is a chart and you remove
02795   //all cells
02796   if (c == 0L)
02797   {
02798      CellBinding * bind;
02799      for ( bind = firstCellBinding(); bind != 0L; bind = nextCellBinding() )
02800      {
02801        bind->cellChanged( 0 );
02802      }
02803      //    CellBinding * bind = firstCellBinding();
02804      //    if ( bind != 0L )
02805      //      bind->cellChanged( 0 );
02806   }
02807 
02808 }
02809 
02810 void KSpreadSheet::refreshMergedCell()
02811 {
02812   KSpreadCell* c = d->cells.firstCell();
02813   for( ;c; c = c->nextCell() )
02814   {
02815     if(c->isForceExtraCells())
02816       c->forceExtraCells( c->column(), c->row(), c->extraXCells(), c->extraYCells() );
02817   }
02818 }
02819 
02820 
02821 void KSpreadSheet::changeNameCellRef( const QPoint & pos, bool fullRowOrColumn,
02822                                       ChangeRef ref, QString tabname, int nbCol,
02823                                       KSpreadUndoInsertRemoveAction * undo )
02824 {
02825   bool correctDefaultSheetName = (tabname == name()); // for cells without sheet ref (eg "A1")
02826   KSpreadCell* c = d->cells.firstCell();
02827   for( ;c; c = c->nextCell() )
02828   {
02829     if( c->isFormula() )
02830     {
02831       QString origText = c->text();
02832       unsigned int i = 0;
02833       bool error = false;
02834       QString newText;
02835 
02836       bool correctSheetName = correctDefaultSheetName;
02837       //bool previousCorrectSheetName = false;
02838       QChar origCh;
02839       for ( ; i < origText.length(); ++i )
02840       {
02841         origCh = origText[i];
02842         if ( origCh != ':' && origCh != '$' && !origCh.isLetter() )
02843         {
02844           newText += origCh;
02845           // Reset the "correct table indicator"
02846           correctSheetName = correctDefaultSheetName;
02847         }
02848         else // Letter or dollar : maybe start of cell name/range
02849           // (or even ':', like in a range - note that correctSheet is kept in this case)
02850         {
02851           // Collect everything that forms a name (cell name or sheet name)
02852           QString str;
02853           bool sheetNameFound = false; //Sheet names need spaces
02854           for( ; ( i < origText.length() ) &&  // until the end
02855                  (  ( origText[i].isLetter() || origText[i].isDigit() || origText[i] == '$' ) ||  // all text and numbers are welcome
02856                     ( sheetNameFound && origText[i].isSpace() ) ) //in case of a sheet name, we include spaces too
02857                ; ++i )
02858           {
02859             str += origText[i];
02860             if ( origText[i] == '!' )
02861               sheetNameFound = true;
02862           }
02863           // Was it a sheet name ?
02864           if ( origText[i] == '!' )
02865           {
02866             newText += str + '!'; // Copy it (and the '!')
02867             // Look for the sheet name right before that '!'
02868             correctSheetName = ( newText.right( tabname.length()+1 ) == tabname+"!" );
02869           }
02870           else // It must be a cell identifier
02871           {
02872             // Parse it
02873             KSpreadPoint point( str );
02874             if ( point.isValid() )
02875             {
02876               int col = point.pos.x();
02877               int row = point.pos.y();
02878               QString newPoint;
02879 
02880               // Update column
02881               if ( point.columnFixed )
02882                 newPoint = '$';
02883 
02884               if( ref == ColumnInsert
02885                   && correctSheetName
02886                   && col + nbCol <= KS_colMax
02887                   && col >= pos.x()     // Column after the new one : +1
02888                   && ( fullRowOrColumn || row == pos.y() ) ) // All rows or just one
02889               {
02890                 newPoint += KSpreadCell::columnName( col + nbCol );
02891               }
02892               else if( ref == ColumnRemove
02893                        && correctSheetName
02894                        && col > pos.x() // Column after the deleted one : -1
02895                        && ( fullRowOrColumn || row == pos.y() ) ) // All rows or just one
02896               {
02897                 newPoint += KSpreadCell::columnName( col - nbCol );
02898               }
02899               else
02900                 newPoint += KSpreadCell::columnName( col );
02901 
02902               // Update row
02903               if ( point.rowFixed )
02904                 newPoint += '$';
02905 
02906               if( ref == RowInsert
02907                   && correctSheetName
02908                   && row + nbCol <= KS_rowMax
02909                   && row >= pos.y() // Row after the new one : +1
02910                   && ( fullRowOrColumn || col == pos.x() ) ) // All columns or just one
02911               {
02912                 newPoint += QString::number( row + nbCol );
02913               }
02914               else if( ref == RowRemove
02915                        && correctSheetName
02916                        && row > pos.y() // Row after the deleted one : -1
02917                        && ( fullRowOrColumn || col == pos.x() ) ) // All columns or just one
02918               {
02919                 newPoint += QString::number( row - nbCol );
02920               }
02921               else
02922                 newPoint += QString::number( row );
02923 
02924               if( correctSheetName &&
02925                   ( ( ref == ColumnRemove
02926                       && col == pos.x() // Column is the deleted one : error
02927                       && ( fullRowOrColumn || row == pos.y() ) ) ||
02928                     ( ref == RowRemove
02929                       && row == pos.y() // Row is the deleted one : error
02930                       && ( fullRowOrColumn || col == pos.x() ) ) ||
02931                     ( ref == ColumnInsert
02932                       && col + nbCol > KS_colMax
02933                       && col >= pos.x()     // Column after the new one : +1
02934                       && ( fullRowOrColumn || row == pos.y() ) ) ||
02935                     ( ref == RowInsert
02936                       && row + nbCol > KS_rowMax
02937                       && row >= pos.y() // Row after the new one : +1
02938                       && ( fullRowOrColumn || col == pos.x() ) ) ) )
02939               {
02940                 newPoint = "#" + i18n("Dependency") + "!";
02941                 error = true;
02942               }
02943 
02944               newText += newPoint;
02945             }
02946             else // Not a cell ref
02947             {
02948               kdDebug(36001) << "Copying (unchanged) : '" << str << "'" << endl;
02949               newText += str;
02950             }
02951             // Copy the char that got us to stop
02952             if ( i < origText.length() ) {
02953               newText += origText[i];
02954               if( origText[i] != ':' )
02955                 correctSheetName = correctDefaultSheetName;
02956             }
02957           }
02958         }
02959       }
02960 
02961       if ( error && undo != 0 ) //Save the original formula, as we cannot calculate the undo of broken formulas
02962       {
02963           QString formulaText = c->text();
02964           int origCol = c->column();
02965           int origRow = c->row();
02966 
02967           if ( ref == ColumnInsert && origCol >= pos.x() )
02968               origCol -= nbCol;
02969           if ( ref == RowInsert && origRow >= pos.y() )
02970               origRow -= nbCol;
02971 
02972           if ( ref == ColumnRemove && origCol >= pos.x() )
02973               origCol += nbCol;
02974           if ( ref == RowRemove && origRow >= pos.y() )
02975               origRow += nbCol;
02976 
02977           undo->saveFormulaReference( this, origCol, origRow, formulaText );
02978       }
02979 
02980       c->setCellText( newText );
02981     }
02982   }
02983 }
02984 
02985 #if 0
02986 void KSpreadSheet::replace( const QString &_find, const QString &_replace, long options,
02987                             KSpreadCanvas *canvas )
02988 {
02989   KSpreadSelection* selectionInfo = canvas->view()->selectionInfo();
02990 
02991     // Identify the region of interest.
02992     QRect region( selectionInfo->selection() );
02993     QPoint marker( selectionInfo->marker() );
02994 
02995     if (options & KReplaceDialog::SelectedText)
02996     {
02997 
02998         // Complete rows selected ?
02999         if ( util_isRowSelected(region) )
03000         {
03001         }
03002         // Complete columns selected ?
03003         else if ( util_isColumnSelected(region) )
03004         {
03005         }
03006     }
03007     else
03008     {
03009         // All cells.
03010         region.setCoords( 1, 1, d->maxRow, d->maxColumn );
03011     }
03012 
03013     // Create the class that handles all the actual replace stuff, and connect it to its
03014     // local slots.
03015     KReplace dialog( _find, _replace, options );
03016     QObject::connect(
03017         &dialog, SIGNAL( highlight( const QString &, int, int, const QRect & ) ),
03018         canvas, SLOT( highlight( const QString &, int, int, const QRect & ) ) );
03019     QObject::connect(
03020         &dialog, SIGNAL( replace( const QString &, int, int,int, const QRect & ) ),
03021         canvas, SLOT( replace( const QString &, int, int,int, const QRect & ) ) );
03022 
03023     // Now do the replacing...
03024     if ( !doc()->undoLocked() )
03025     {
03026         KSpreadUndoChangeAreaTextCell *undo = new KSpreadUndoChangeAreaTextCell( doc(), this, region );
03027         doc()->addCommand( undo );
03028     }
03029 
03030     QRect cellRegion( 0, 0, 0, 0 );
03031     bool bck = options & KFindDialog::FindBackwards;
03032 
03033     int colStart = !bck ? region.left() : region.right();
03034     int colEnd = !bck ? region.right() : region.left();
03035     int rowStart = !bck ? region.top() :region.bottom();
03036     int rowEnd = !bck ? region.bottom() : region.top();
03037     if ( options & KFindDialog::FromCursor ) {
03038         colStart = marker.x();
03039         rowStart =  marker.y();
03040     }
03041     KSpreadCell *cell;
03042     for (int row = rowStart ; !bck ? row < rowEnd : row > rowEnd ; !bck ? ++row : --row )
03043     {
03044         for(int col = colStart ; !bck ? col < colEnd : col > colEnd ; !bck ? ++col : --col )
03045         {
03046             cell = cellAt( col, row );
03047             if ( !cell->isDefault() && !cell->isObscured() && !cell->isFormula() )
03048             {
03049                 QString text = cell->text();
03050                 cellRegion.setTop( row );
03051                 cellRegion.setLeft( col );
03052                 if (!dialog.replace( text, cellRegion ))
03053                     return;
03054             }
03055         }
03056     }
03057 }
03058 #endif
03059 
03060 void KSpreadSheet::borderBottom( KSpreadSelection* selectionInfo,
03061                                  const QColor &_color )
03062 {
03063   QRect selection( selectionInfo->selection() );
03064 
03065   QPen pen( _color,1,SolidLine);
03066 
03067   // Complete rows selected ?
03068   if ( util_isRowSelected(selection) )
03069   {
03070     if ( !doc()->undoLocked() )
03071     {
03072       QString title = i18n("Change Border");
03073       KSpreadUndoCellFormat * undo =
03074         new KSpreadUndoCellFormat( doc(), this, selection, title );
03075       doc()->addCommand( undo );
03076     }
03077 
03078     int row = selection.bottom();
03079     KSpreadCell * c = getFirstCellRow( row );
03080     while ( c )
03081     {
03082       c->clearProperty( KSpreadCell::PBottomBorder );
03083       c->clearNoFallBackProperties( KSpreadCell::PBottomBorder );
03084 
03085       c = getNextCellRight( c->column(), row );
03086     }
03087 
03088     RowFormat * rw = nonDefaultRowFormat(selection.bottom());
03089     rw->setBottomBorderPen(pen);
03090 
03091     emit sig_updateView( this );
03092     return;
03093   }
03094   // Complete columns selected ?
03095   else if ( util_isColumnSelected(selection) )
03096   {
03097     //nothing
03098     return;
03099   }
03100   else
03101   {
03102     if ( !doc()->undoLocked() )
03103     {
03104       QString title=i18n("Change Border");
03105       KSpreadUndoCellFormat *undo =
03106         new KSpreadUndoCellFormat( doc(), this, selection,title );
03107       doc()->addCommand( undo );
03108     }
03109 
03110     KSpreadCell* cell;
03111     int y = selection.bottom();
03112     for ( int x = selection.left(); x <= selection.right(); ++x )
03113     {
03114       cell = nonDefaultCell( x, y );
03115       if ( cell->isObscuringForced() )
03116         cell = cell->obscuringCells().first();
03117       cell->setBottomBorderPen( pen );
03118     }
03119     emit sig_updateView( this, selection );
03120   }
03121 }
03122 
03123 void KSpreadSheet::borderRight( KSpreadSelection* selectionInfo,
03124                                 const QColor &_color )
03125 {
03126   QRect selection( selectionInfo->selection() );
03127 
03128   QPen pen( _color,1,SolidLine);
03129   // Complete rows selected ?
03130   if ( util_isRowSelected(selection) )
03131   {
03132     //nothing
03133     return;
03134   }
03135   // Complete columns selected ?
03136   else if ( util_isColumnSelected(selection) )
03137   {
03138 
03139     if ( !doc()->undoLocked() )
03140     {
03141       QString title = i18n("Change Border");
03142       KSpreadUndoCellFormat * undo =
03143         new KSpreadUndoCellFormat( doc(), this, selection, title );
03144       doc()->addCommand( undo );
03145     }
03146 
03147     int col = selection.right();
03148     KSpreadCell * c = getFirstCellColumn( col );
03149     while ( c )
03150     {
03151       if ( !c->isObscuringForced() )
03152       {
03153         c->clearProperty( KSpreadCell::PRightBorder );
03154         c->clearNoFallBackProperties( KSpreadCell::PRightBorder );
03155       }
03156       c = getNextCellDown( col, c->row() );
03157     }
03158 
03159     RowFormat * rw = d->rows.first();
03160 
03161     ColumnFormat * cl = nonDefaultColumnFormat(selection.right());
03162     cl->setRightBorderPen(pen);
03163 
03164     KSpreadCell * cell;
03165     rw = d->rows.first();
03166     for( ; rw; rw = rw->next() )
03167     {
03168       if ( !rw->isDefault() && (rw->hasProperty(KSpreadCell::PRightBorder)))
03169       {
03170         for(int i = selection.left(); i <= selection.right(); i++)
03171         {
03172           cell = nonDefaultCell( i, rw->row() );
03173           if ( cell->isObscuringForced() )
03174             cell = cell->obscuringCells().first();
03175           cell->setRightBorderPen(pen);
03176         }
03177       }
03178     }
03179 
03180     emit sig_updateView( this );
03181     return;
03182   }
03183   else
03184   {
03185     if ( !doc()->undoLocked() )
03186     {
03187       QString title=i18n("Change Border");
03188       KSpreadUndoCellFormat *undo =
03189         new KSpreadUndoCellFormat( doc(), this, selection, title );
03190       doc()->addCommand( undo );
03191     }
03192 
03193     KSpreadCell* cell;
03194     int x = selection.right();
03195     for ( int y = selection.top(); y <= selection.bottom(); y++ )
03196     {
03197       cell = nonDefaultCell( x, y );
03198       if ( cell->isObscuringForced() )
03199         cell = cell->obscuringCells().first();
03200       cell->setRightBorderPen(pen);
03201     }
03202     emit sig_updateView( this, selection );
03203   }
03204 }
03205 
03206 void KSpreadSheet::borderLeft( KSpreadSelection* selectionInfo,
03207                                const QColor &_color )
03208 {
03209   QString title = i18n("Change Border");
03210   QRect selection( selectionInfo->selection() );
03211 
03212   QPen pen( _color,1,SolidLine);
03213 
03214   // Complete columns selected ?
03215   if ( util_isColumnSelected(selection) )
03216   {
03217     RowFormat* rw =d->rows.first();
03218 
03219     if ( !doc()->undoLocked() )
03220     {
03221       KSpreadUndoCellFormat *undo =
03222         new KSpreadUndoCellFormat( doc(), this, selection, title );
03223       doc()->addCommand( undo );
03224     }
03225 
03226     int col = selection.left();
03227     KSpreadCell * c = getFirstCellColumn( col );
03228     while ( c )
03229     {
03230       c->clearProperty( KSpreadCell::PLeftBorder );
03231       c->clearNoFallBackProperties( KSpreadCell::PLeftBorder );
03232 
03233       c = getNextCellDown( col, c->row() );
03234     }
03235 
03236 
03237     ColumnFormat * cl = nonDefaultColumnFormat( col );
03238     cl->setLeftBorderPen(pen);
03239 
03240     KSpreadCell * cell;
03241     rw = d->rows.first();
03242     for( ; rw; rw = rw->next() )
03243     {
03244       if ( !rw->isDefault() && (rw->hasProperty(KSpreadCell::PLeftBorder)))
03245       {
03246         for(int i = selection.left(); i <= selection.right(); ++i)
03247         {
03248           cell = nonDefaultCell( i,  rw->row() );
03249           if ( cell->isObscuringForced() )
03250             continue;
03251           cell->setLeftBorderPen(pen);
03252         }
03253       }
03254     }
03255 
03256     emit sig_updateView( this );
03257     return;
03258   }
03259   else
03260   {
03261     if ( !doc()->undoLocked() )
03262     {
03263       KSpreadUndoCellFormat *undo = new KSpreadUndoCellFormat( doc(), this,
03264                                                                selection,title );
03265       doc()->addCommand( undo );
03266     }
03267 
03268     KSpreadCell* cell;
03269     int x = selection.left();
03270     for ( int y = selection.top(); y <= selection.bottom(); y++ )
03271     {
03272       cell = nonDefaultCell( x, y );
03273       if ( cell->isObscuringForced() )
03274         continue;
03275       cell->setLeftBorderPen(pen);
03276     }
03277     emit sig_updateView( this, selection );
03278   }
03279 }
03280 
03281 void KSpreadSheet::borderTop( KSpreadSelection* selectionInfo,
03282                               const QColor &_color )
03283 {
03284   /* duplicate code in kspread_dlg_layout.cc  That needs fixed at some point
03285      We need to save the code here and have the dialog code removed.
03286    */
03287   QRect selection( selectionInfo->selection() );
03288 
03289   QString title = i18n("Change Border");
03290   QPen pen( _color, 1, SolidLine);
03291   // Complete rows selected ?
03292   if ( util_isRowSelected(selection) )
03293   {
03294     if ( !doc()->undoLocked() )
03295     {
03296       KSpreadUndoCellFormat * undo =
03297         new KSpreadUndoCellFormat( doc(), this, selection, title );
03298       doc()->addCommand( undo );
03299     }
03300 
03301     int row = selection.top();
03302     KSpreadCell * c = getFirstCellRow( row );
03303     while ( c )
03304     {
03305       c->clearProperty( KSpreadCell::PTopBorder );
03306       c->clearNoFallBackProperties( KSpreadCell::PTopBorder );
03307 
03308       c = getNextCellRight( c->column(), row );
03309     }
03310 
03311     RowFormat * rw = nonDefaultRowFormat( row );
03312     rw->setTopBorderPen( pen );
03313 
03314     emit sig_updateView( this );
03315     return;
03316   }
03317   // Complete columns selected ? -- the top will just be row 1, then
03318   // so it's the same as in no rows/columns selected
03319   else
03320   {
03321     if ( !doc()->undoLocked() )
03322     {
03323       KSpreadUndoCellFormat *undo =
03324         new KSpreadUndoCellFormat( doc(), this, selection, title );
03325       doc()->addCommand( undo );
03326     }
03327 
03328     KSpreadCell* cell;
03329     int y = selection.top();
03330     for ( int x = selection.left(); x <= selection.right(); x++ )
03331     {
03332       cell = nonDefaultCell( x, y );
03333       if ( cell->isObscuringForced() )
03334         continue;
03335       cell->setTopBorderPen(pen);
03336     }
03337     emit sig_updateView( this, selection );
03338   }
03339 }
03340 
03341 void KSpreadSheet::borderOutline( KSpreadSelection* selectionInfo,
03342                                   const QColor &_color )
03343 {
03344   QRect selection( selectionInfo->selection() );
03345 
03346   if ( !doc()->undoLocked() )
03347   {
03348     QString title = i18n("Change Border");
03349     KSpreadUndoCellFormat *undo = new KSpreadUndoCellFormat( doc(), this,
03350                                                              selection, title );
03351     doc()->addCommand( undo );
03352   }
03353 
03354   QPen pen( _color, 1, SolidLine );
03355 
03356   // Complete rows selected ?
03357   if ( util_isRowSelected(selection) )
03358   {
03359     int row = selection.top();
03360     KSpreadCell * c = getFirstCellRow( row );
03361     while ( c )
03362     {
03363       c->clearProperty( KSpreadCell::PTopBorder );
03364       c->clearNoFallBackProperties( KSpreadCell::PTopBorder );
03365 
03366       c = getNextCellRight( c->column(), row );
03367     }
03368 
03369     row = selection.bottom();
03370     c = getFirstCellRow( row );
03371     while ( c )
03372     {
03373       c->clearProperty( KSpreadCell::PBottomBorder );
03374       c->clearNoFallBackProperties( KSpreadCell::PBottomBorder );
03375 
03376       c = getNextCellRight( c->column(), row );
03377     }
03378 
03379     RowFormat * rw = nonDefaultRowFormat( selection.top() );
03380     rw->setTopBorderPen(pen);
03381     rw=nonDefaultRowFormat(selection.bottom());
03382     rw->setBottomBorderPen(pen);
03383     KSpreadCell* cell;
03384     int bottom = selection.bottom();
03385     int left   = selection.left();
03386     for ( int y = selection.top(); y <= bottom; ++y )
03387     {
03388       cell = nonDefaultCell( left, y );
03389       if ( cell->isObscuringForced() )
03390         continue;
03391       cell->setLeftBorderPen( pen );
03392     }
03393     emit sig_updateView( this );
03394     return;
03395   }
03396   // Complete columns selected ?
03397   else if ( util_isColumnSelected(selection) )
03398   {
03399     int col = selection.left();
03400     KSpreadCell * c = getFirstCellColumn( col );
03401     while ( c )
03402     {
03403       c->clearProperty( KSpreadCell::PLeftBorder );
03404       c->clearNoFallBackProperties( KSpreadCell::PLeftBorder );
03405 
03406       c = getNextCellDown( col, c->row() );
03407     }
03408 
03409     col = selection.right();
03410     c = getFirstCellColumn( col );
03411     while ( c )
03412     {
03413       c->clearProperty( KSpreadCell::PRightBorder );
03414       c->clearNoFallBackProperties( KSpreadCell::PRightBorder );
03415 
03416       c = getNextCellDown( col, c->row() );
03417     }
03418 
03419     ColumnFormat *cl=nonDefaultColumnFormat(selection.left());
03420     cl->setLeftBorderPen(pen);
03421     cl=nonDefaultColumnFormat(selection.right());
03422     cl->setRightBorderPen(pen);
03423     KSpreadCell* cell;
03424     for ( int x = selection.left(); x <= selection.right(); x++ )
03425     {
03426       cell = nonDefaultCell( x, selection.top() );
03427       if ( cell->isObscuringForced() )
03428         continue;
03429       cell->setTopBorderPen( pen );
03430     }
03431     emit sig_updateView( this );
03432     return;
03433   }
03434   else
03435   {
03436     KSpreadCell* cell;
03437     for ( int x = selection.left(); x <= selection.right(); x++ )
03438     {
03439       cell = nonDefaultCell( x, selection.top() );
03440       if ( !cell->isObscuringForced() )
03441         cell->setTopBorderPen( pen );
03442 
03443       cell = nonDefaultCell( x, selection.bottom() );
03444       if ( cell->isObscuringForced() )
03445         cell = cell->obscuringCells().first();
03446       cell->setBottomBorderPen( pen );
03447     }
03448     for ( int y = selection.top(); y <= selection.bottom(); y++ )
03449     {
03450       cell = nonDefaultCell( selection.left(), y );
03451       if ( !cell->isObscuringForced() )
03452         cell->setLeftBorderPen( pen );
03453 
03454       cell = nonDefaultCell( selection.right(), y );
03455       if ( cell->isObscuringForced() )
03456         cell = cell->obscuringCells().first();
03457       cell->setRightBorderPen( pen );
03458     }
03459     emit sig_updateView( this, selection );
03460   }
03461 }
03462 
03463 struct SetSelectionBorderAllWorker : public KSpreadSheet::CellWorkerTypeA {
03464     QPen pen;
03465     SetSelectionBorderAllWorker( const QColor& color ) : pen( color, 1, QPen::SolidLine ) { }
03466 
03467     QString getUndoTitle() { return i18n("Change Border"); }
03468     bool testCondition( RowFormat* rw ) {
03469     return ( rw->hasProperty( KSpreadCell::PRightBorder )
03470          || rw->hasProperty( KSpreadCell::PLeftBorder )
03471          || rw->hasProperty( KSpreadCell::PTopBorder )
03472          || rw->hasProperty( KSpreadCell::PBottomBorder ) );
03473     }
03474     void doWork( RowFormat* rw ) {
03475     rw->setTopBorderPen( pen );
03476         rw->setRightBorderPen( pen );
03477         rw->setLeftBorderPen( pen );
03478         rw->setBottomBorderPen( pen );
03479     }
03480     void doWork( ColumnFormat* cl ) {
03481     cl->setTopBorderPen( pen );
03482         cl->setRightBorderPen( pen );
03483         cl->setLeftBorderPen( pen );
03484         cl->setBottomBorderPen( pen );
03485     }
03486     void prepareCell( KSpreadCell* c ) {
03487     c->clearProperty( KSpreadCell::PTopBorder );
03488     c->clearNoFallBackProperties( KSpreadCell::PTopBorder );
03489     c->clearProperty( KSpreadCell::PBottomBorder );
03490     c->clearNoFallBackProperties( KSpreadCell::PBottomBorder );
03491     c->clearProperty( KSpreadCell::PLeftBorder );
03492     c->clearNoFallBackProperties( KSpreadCell::PLeftBorder );
03493     c->clearProperty( KSpreadCell::PRightBorder );
03494     c->clearNoFallBackProperties( KSpreadCell::PRightBorder );
03495     }
03496 
03497   bool testCondition( KSpreadCell */* cell*/ ) { return true; }
03498 
03499     void doWork( KSpreadCell* cell, bool, int, int ) {
03500     //if ( cellRegion )
03501     //    cell->setDisplayDirtyFlag();
03502     cell->setTopBorderPen( pen );
03503         cell->setRightBorderPen( pen );
03504         cell->setLeftBorderPen( pen );
03505         cell->setBottomBorderPen( pen );
03506     //if ( cellRegion )
03507     //    cell->clearDisplayDirtyFlag();
03508     }
03509 };
03510 
03511 void KSpreadSheet::borderAll( KSpreadSelection * selectionInfo,
03512                               const QColor & _color )
03513 {
03514   if ( selectionInfo->singleCellSelection() )
03515   {
03516     borderOutline( selectionInfo, _color );
03517   }
03518   else
03519   {
03520     SetSelectionBorderAllWorker w( _color );
03521     workOnCells( selectionInfo, w );
03522   }
03523 }
03524 
03525 struct SetSelectionBorderRemoveWorker : public KSpreadSheet::CellWorkerTypeA {
03526     QPen pen;
03527     SetSelectionBorderRemoveWorker() : pen( Qt::black, 1, Qt::NoPen  ) { }
03528     QString getUndoTitle() { return i18n("Change Border"); }
03529     bool testCondition( RowFormat* rw ) {
03530     return ( rw->hasProperty( KSpreadCell::PRightBorder )
03531          || rw->hasProperty( KSpreadCell::PLeftBorder )
03532          || rw->hasProperty( KSpreadCell::PTopBorder )
03533          || rw->hasProperty( KSpreadCell::PBottomBorder )
03534          || rw->hasProperty( KSpreadCell::PFallDiagonal )
03535          || rw->hasProperty( KSpreadCell::PGoUpDiagonal ) );
03536     }
03537     void doWork( RowFormat* rw ) {
03538     rw->setTopBorderPen( pen );
03539         rw->setRightBorderPen( pen );
03540         rw->setLeftBorderPen( pen );
03541         rw->setBottomBorderPen( pen);
03542         rw->setFallDiagonalPen( pen );
03543         rw->setGoUpDiagonalPen (pen );
03544     }
03545     void doWork( ColumnFormat* cl ) {
03546     cl->setTopBorderPen( pen );
03547         cl->setRightBorderPen( pen );
03548         cl->setLeftBorderPen( pen );
03549         cl->setBottomBorderPen( pen);
03550         cl->setFallDiagonalPen( pen );
03551         cl->setGoUpDiagonalPen (pen );
03552     }
03553     void prepareCell( KSpreadCell* c ) {
03554     c->clearProperty( KSpreadCell::PTopBorder );
03555     c->clearNoFallBackProperties( KSpreadCell::PTopBorder );
03556     c->clearProperty( KSpreadCell::PLeftBorder );
03557     c->clearNoFallBackProperties( KSpreadCell::PLeftBorder );
03558     c->clearProperty( KSpreadCell::PRightBorder );
03559     c->clearNoFallBackProperties( KSpreadCell::PRightBorder );
03560     c->clearProperty( KSpreadCell::PBottomBorder );
03561     c->clearNoFallBackProperties( KSpreadCell::PBottomBorder );
03562     c->clearProperty( KSpreadCell::PFallDiagonal );
03563     c->clearNoFallBackProperties( KSpreadCell::PFallDiagonal );
03564     c->clearProperty( KSpreadCell::PGoUpDiagonal );
03565     c->clearNoFallBackProperties( KSpreadCell::PGoUpDiagonal );
03566     }
03567 
03568     bool testCondition(KSpreadCell* /*cell*/ ){ return true; }
03569 
03570     void doWork( KSpreadCell* cell, bool, int, int ) {
03571     //if ( cellRegion )
03572     //    cell->setDisplayDirtyFlag();
03573     cell->setTopBorderPen( pen );
03574         cell->setRightBorderPen( pen );
03575         cell->setLeftBorderPen( pen );
03576         cell->setBottomBorderPen( pen);
03577         cell->setFallDiagonalPen( pen );
03578         cell->setGoUpDiagonalPen (pen );
03579     //if ( cellRegion )
03580     //    cell->clearDisplayDirtyFlag();
03581     }
03582 };
03583 
03584 
03585 void KSpreadSheet::borderRemove( KSpreadSelection* selectionInfo )
03586 {
03587     SetSelectionBorderRemoveWorker w;
03588     workOnCells( selectionInfo, w );
03589 }
03590 
03591 
03592 void KSpreadSheet::sortByRow( const QRect &area, int ref_row, SortingOrder mode )
03593 {
03594   KSpreadPoint point;
03595   point.sheet = this;
03596   point.sheetName = d->name;
03597   point.pos = area.topLeft();
03598   point.columnFixed = false;
03599   point.rowFixed = false;
03600 
03601   sortByRow( area, ref_row, 0, 0, mode, mode, mode, 0, false, false, point,true );
03602 }
03603 
03604 void KSpreadSheet::sortByColumn( const QRect &area, int ref_column, SortingOrder mode )
03605 {
03606   KSpreadPoint point;
03607   point.sheet = this;
03608   point.sheetName = d->name;
03609   point.pos = area.topLeft();
03610   point.columnFixed = false;
03611   point.rowFixed = false;
03612 
03613   sortByColumn( area, ref_column, 0, 0, mode, mode, mode, 0, false, false,
03614                 point,true );
03615 }
03616 
03617 void KSpreadSheet::checkCellContent(KSpreadCell * cell1, KSpreadCell * cell2, int & ret)
03618 {
03619   if ( cell1->isEmpty() )
03620   {
03621     ret = 1;
03622     return;
03623   }
03624   else if ( cell1->isObscured() && cell1->isObscuringForced() )
03625   {
03626     ret = 1;
03627     return;
03628   }
03629   else if ( cell2->isEmpty() )
03630   {
03631     ret = 2;
03632     return;
03633   }
03634   ret = 0;
03635 }
03636 
03637 void KSpreadSheet::sortByRow( const QRect &area, int key1, int key2, int key3,
03638                               SortingOrder order1, SortingOrder order2,
03639                               SortingOrder order3,
03640                               QStringList const * firstKey, bool copyFormat,
03641                               bool headerRow, KSpreadPoint const & outputPoint, bool respectCase )
03642 {
03643   QRect r( area );
03644   KSpreadMap::respectCase = respectCase;
03645   Q_ASSERT( order1 == Increase || order1 == Decrease );
03646 
03647   // It may not happen that entire columns are selected.
03648   Q_ASSERT( util_isColumnSelected(r) == FALSE );
03649 
03650   // Are entire rows selected ?
03651   if ( util_isRowSelected(r) )
03652   {
03653     r.setLeft( KS_colMax );
03654     r.setRight( 0 );
03655 
03656     // Determine a correct left and right.
03657     // Iterate over all cells to find out which cells are
03658     // located in the selected rows.
03659     for ( int row = r.top(); row <= r.bottom(); ++row )
03660     {
03661       KSpreadCell * c = getFirstCellRow( row );
03662       int col;
03663       while ( c )
03664       {
03665         col = c->column();
03666         if ( !c->isEmpty() )
03667         {
03668           if ( col > r.right() )
03669             r.rRight() = col;
03670           if ( col < r.left() )
03671             r.rLeft() = col;
03672         }
03673         c = getNextCellRight( col, row );
03674       }
03675     }
03676 
03677     // Any cells to sort here ?
03678     if ( r.right() < r.left() )
03679     {
03680         KSpreadMap::respectCase = true;
03681         return;
03682     }
03683   }
03684 
03685   QRect target( outputPoint.pos.x(), outputPoint.pos.y(), r.width(), r.height() );
03686 
03687   doc()->emitBeginOperation();
03688 
03689   if ( !doc()->undoLocked() )
03690   {
03691     KSpreadUndoSort *undo = new KSpreadUndoSort( doc(), this, target );
03692     doc()->addCommand( undo );
03693   }
03694 
03695   if (target.topLeft() != r.topLeft())
03696   {
03697     int targetLeft = target.left();
03698     int targetTop  = target.top();
03699     int sourceTop  = r.top();
03700     int sourceLeft = r.left();
03701 
03702     key1 = key1 - sourceTop + targetTop;
03703     key2 = key2 - sourceTop + targetTop;
03704     key3 = key3 - sourceTop + targetTop;
03705 
03706     for ( int x = 0; x < r.width(); ++x)
03707     {
03708       for ( int y = 0; y < r.height(); ++y )
03709       {
03710         // from - to
03711         copyCells( sourceLeft + x, sourceTop + y,
03712                    targetLeft + x, targetTop + y, copyFormat );
03713       }
03714     }
03715   }
03716 
03717   // Sorting algorithm: David's :). Well, I guess it's called minmax or so.
03718   // For each column, we look for all cells right hand of it and we find the one to swap with it.
03719   // Much faster than the awful bubbleSort...
03720   KSpreadCell * cell;
03721   KSpreadCell * cell1;
03722   KSpreadCell * cell2;
03723   KSpreadCell * bestCell;
03724   int status = 0;
03725 
03726   for ( int d = target.left();  d <= target.right(); ++d )
03727   {
03728     cell1 = cellAt( d, key1 );
03729     if ( cell1->isObscured() && cell1->isObscuringForced() )
03730     {
03731       KSpreadCell* obscuring = cell1->obscuringCells().first();
03732       cell = cellAt( obscuring->column(), key1 );
03733       cell1 = cellAt( obscuring->column() + cell->extraXCells() + 1,
03734                       obscuring->column());
03735       d = obscuring->column() + cell->extraXCells() + 1;
03736     }
03737 
03738     // Look for which column we want to swap with the one number d
03739     bestCell = cell1;
03740     int bestX = d;
03741     for ( int x = d + 1 ; x <= target.right(); x++ )
03742     {
03743       cell2 = cellAt( x, key1 );
03744 
03745       checkCellContent(cell2, bestCell, status);
03746       if (status == 1)
03747         continue;
03748       else if (status == 2)
03749       {
03750         // empty cells are always shifted to the end
03751         bestCell = cell2;
03752         bestX = x;
03753         continue;
03754       }
03755 
03756       if ( firstKey )
03757       {
03758         int i1 = firstKey->findIndex( cell2->text() );
03759         int i2 = firstKey->findIndex( bestCell->text() );
03760 
03761         if ( i1 != -1 && i2 != -1 )
03762         {
03763           if ( (order1 == Increase && i1 < i2 )
03764                || (order1 == Decrease && i1 > i2) )
03765           {
03766             bestCell = cell2;
03767             bestX = x;
03768             continue;
03769           }
03770 
03771           if ( i1 == i2 )
03772           {
03773             // check 2nd key
03774             if (key2 <= 0)
03775               continue;
03776 
03777             KSpreadCell * cell22 = cellAt( x, key2 );
03778             KSpreadCell * bestCell2 = cellAt( bestX, key2 );
03779 
03780             if ( cell22->isEmpty() )
03781             {
03782               /* No need to swap */
03783               continue;
03784             }
03785             else if ( cell22->isObscured() && cell22->isObscuringForced() )
03786             {
03787               /* No need to swap */
03788               continue;
03789             }
03790             else if ( bestCell2->isEmpty() )
03791             {
03792               // empty cells are always shifted to the end
03793               bestCell = cell2;
03794               bestX = x;
03795               continue;
03796             }
03797 
03798             if ( (order2 == Increase && *cell22 < *bestCell2)
03799                  || (order2 == Decrease && *cell22 > *bestCell2) )
03800             {
03801               bestCell = cell2;
03802               bestX = x;
03803               continue;
03804             }
03805             else if ( (order2 == Increase && *cell22 > *bestCell2)
03806                       || (order2 == Decrease && *cell22 < *bestCell2) )
03807             {
03808               // already in right order
03809               continue;
03810             }
03811             else
03812             {
03813               // they are equal, check 3rd key
03814               if (key3 <= 0)
03815                 continue;
03816 
03817               KSpreadCell * cell23 = cellAt( x, key3 );
03818               KSpreadCell * bestCell3 = cellAt( bestX, key3 );
03819 
03820               if ( cell23->isEmpty() )
03821               {
03822                 /* No need to swap */
03823                 continue;
03824               }
03825               else if ( cell23->isObscured() && cell23->isObscuringForced() )
03826               {
03827                 /* No need to swap */
03828                 continue;
03829               }
03830               else if ( bestCell3->isEmpty() )
03831               {
03832                 // empty cells are always shifted to the end
03833                 bestCell = cell2;
03834                 bestX = x;
03835                 continue;
03836               }
03837               if ( (order3 == Increase && *cell23 < *bestCell3)
03838                    || (order3 == Decrease && *cell23 > *bestCell3) )
03839               {
03840                 // they are really equal or in the right order
03841                 // no swap necessary
03842                 continue;
03843               }
03844               else
03845               {
03846                 bestCell = cell2;
03847                 bestX = x;
03848                 continue;
03849               }
03850             }
03851           }
03852           continue;
03853         }
03854         else if ( i1 != -1 && i2 == -1 )
03855         {
03856           // if not in the key list, the cell is shifted to the end - always
03857           bestCell = cell2;
03858           bestX = x;
03859           continue;
03860        }
03861         else if ( i2 != -1 && i1 == -1 )
03862         {
03863           // only text of cell2 is in the list so it is smaller than bestCell
03864           /* No need to swap */
03865           continue;
03866         }
03867 
03868         // if i1 and i2 are equals -1 go on:
03869       } // end if (firstKey)
03870 
03871       // Here we use the operators < and > for cells, which do it all.
03872       if ( (order1 == Increase && *cell2 < *bestCell)
03873            || (order1 == Decrease && *cell2 > *bestCell) )
03874       {
03875         bestCell = cell2;
03876         bestX = x;
03877         continue;
03878       }
03879       else if ( (order1 == Increase && *cell2 > *bestCell)
03880                 || (order1 == Decrease && *cell2 < *bestCell) )
03881       {
03882         // no change necessary
03883         continue;
03884       }
03885       else
03886       {
03887         // *cell2 equals *bestCell
03888         // check 2nd key
03889         if (key2 <= 0)
03890           continue;
03891         KSpreadCell * cell22 = cellAt( d, key2 );
03892         KSpreadCell * bestCell2 = cellAt( x, key2 );
03893 
03894         checkCellContent(cell2, bestCell, status);
03895         if (status == 1)
03896           continue;
03897         else if (status == 2)
03898         {
03899           // empty cells are always shifted to the end
03900           bestCell = cell2;
03901           bestX = x;
03902           continue;
03903         }
03904 
03905         if ( (order2 == Increase && *cell22 > *bestCell2)
03906              || (order2 == Decrease && *cell22 < *bestCell2) )
03907         {
03908           bestCell = cell2;
03909           bestX = x;
03910           continue;
03911         }
03912         else
03913         if ( (order2 == Increase && *cell22 > *bestCell2)
03914              || (order2 == Decrease && *cell22 < *bestCell2) )
03915         {
03916           // already in right order
03917           continue;
03918         }
03919         else
03920         {
03921           // they are equal, check 3rd key
03922           if (key3 == 0)
03923             continue;
03924           KSpreadCell * cell23 = cellAt( d, key3 );
03925           KSpreadCell * bestCell3 = cellAt( x, key3 );
03926 
03927           checkCellContent(cell2, bestCell, status);
03928           if (status == 1)
03929             continue;
03930           else if (status == 2)
03931           {
03932             // empty cells are always shifted to the end
03933             bestCell = cell2;
03934             bestX = x;
03935             continue;
03936           }
03937           if ( (order3 == Increase && *cell23 > *bestCell3)
03938                || (order3 == Decrease && *cell23 < *bestCell3) )
03939           {
03940             bestCell = cell2;
03941             bestX = x;
03942             continue;
03943           }
03944           else
03945           {
03946             // they are really equal
03947             // no swap necessary
03948             continue;
03949           }
03950         }
03951       }
03952     }
03953 
03954     // Swap columns cell1 and bestCell (i.e. d and bestX)
03955     if ( d != bestX )
03956     {
03957       int top = target.top();
03958       if (headerRow)
03959         ++top;
03960 
03961       for( int y = target.bottom(); y >= top; --y )
03962       {
03963         if ( y != key1 && y != key2 && y != key3 )
03964           swapCells( d, y, bestX, y, copyFormat );
03965       }
03966       if (key3 > 0)
03967         swapCells( d, key3, bestX, key3, copyFormat );
03968       if (key2 > 0)
03969         swapCells( d, key2, bestX, key2, copyFormat );
03970       swapCells( d, key1, bestX, key1, copyFormat );
03971     }
03972   } // for (d = ...; ...; ++d)
03973   KSpreadMap::respectCase = true;
03974   //  doc()->emitEndOperation();
03975   emit sig_updateView( this );
03976 }
03977 
03978 void KSpreadSheet::sortByColumn( const QRect &area, int key1, int key2, int key3,
03979                                  SortingOrder order1, SortingOrder order2,
03980                                  SortingOrder order3,
03981                                  QStringList const * firstKey, bool copyFormat,
03982                                  bool headerRow,
03983                                  KSpreadPoint const & outputPoint, bool respectCase )
03984 {
03985   QRect r( area );
03986   KSpreadMap::respectCase = respectCase;
03987 
03988   Q_ASSERT( order1 == Increase || order1 == Decrease );
03989 
03990   // It may not happen that entire rows are selected.
03991   Q_ASSERT( util_isRowSelected(r) == FALSE );
03992 
03993   // Are entire columns selected ?
03994   if ( util_isColumnSelected(r) )
03995   {
03996     r.setTop( KS_rowMax );
03997     r.setBottom( 0 );
03998 
03999     // Determine a correct top and bottom.
04000     // Iterate over all cells to find out which cells are
04001     // located in the selected columns.
04002     for ( int col = r.left(); col <= r.right(); ++col )
04003     {
04004       KSpreadCell * c = getFirstCellColumn( col );
04005       int row;
04006       while ( c )
04007       {
04008         row = c->row();
04009         if ( !c->isEmpty() )
04010         {
04011           if ( row > r.bottom() )
04012             r.rBottom() = row;
04013           if ( row < r.top() )
04014             r.rTop() = row;
04015         }
04016         c = getNextCellDown( col, row );
04017       }
04018     }
04019 
04020     // Any cells to sort here ?
04021     if ( r.bottom() < r.top() )
04022     {
04023         KSpreadMap::respectCase = true;
04024       return;
04025     }
04026   }
04027   QRect target( outputPoint.pos.x(), outputPoint.pos.y(), r.width(), r.height() );
04028 
04029   if ( !doc()->undoLocked() )
04030   {
04031     KSpreadUndoSort *undo = new KSpreadUndoSort( doc(), this, target );
04032     doc()->addCommand( undo );
04033   }
04034 
04035   doc()->emitBeginOperation();
04036 
04037   if (target.topLeft() != r.topLeft())
04038   {
04039     int targetLeft = target.left();
04040     int targetTop  = target.top();
04041     int sourceTop  = r.top();
04042     int sourceLeft = r.left();
04043 
04044     key1 = key1 - sourceLeft + targetLeft;
04045     key2 = key2 - sourceLeft + targetLeft;
04046     key3 = key3 - sourceLeft + targetLeft;
04047 
04048     for ( int x = 0; x < r.width(); ++x)
04049     {
04050       for ( int y = 0; y < r.height(); ++y )
04051       {
04052         // from - to
04053         copyCells( sourceLeft + x, sourceTop + y,
04054                    targetLeft + x, targetTop + y, copyFormat );
04055       }
04056     }
04057   }
04058 
04059   // Sorting algorithm: David's :). Well, I guess it's called minmax or so.
04060   // For each row, we look for all rows under it and we find the one to swap with it.
04061   // Much faster than the awful bubbleSort...
04062   // Torben: Asymptotically it is alltogether O(n^2) :-)
04063 
04064   KSpreadCell * cell;
04065   KSpreadCell * cell1;
04066   KSpreadCell * cell2;
04067   KSpreadCell * bestCell;
04068   int status = 0;
04069 
04070   int d = target.top();
04071 
04072   if (headerRow)
04073     ++d;
04074 
04075   for ( ; d <= target.bottom(); ++d )
04076   {
04077     // Look for which row we want to swap with the one number d
04078     cell1 = cellAt( key1, d );
04079     if ( cell1->isObscured() && cell1->isObscuringForced() )
04080     {
04081       KSpreadCell* obscuring = cell1->obscuringCells().first();
04082       cell  = cellAt( key1, obscuring->row() );
04083       cell1 = cellAt( key1, obscuring->row() + cell->extraYCells() + 1 );
04084       d     = obscuring->row() + cell->extraYCells() + 1;
04085     }
04086 
04087     bestCell  = cell1;
04088     int bestY = d;
04089 
04090     for ( int y = d + 1 ; y <= target.bottom(); ++y )
04091     {
04092       cell2 = cellAt( key1, y );
04093 
04094       if ( cell2->isEmpty() )
04095       {
04096         /* No need to swap */
04097         continue;
04098       }
04099       else if ( cell2->isObscured() && cell2->isObscuringForced() )
04100       {
04101         /* No need to swap */
04102         continue;
04103       }
04104       else if ( bestCell->isEmpty() )
04105       {
04106         // empty cells are always shifted to the end
04107         bestCell = cell2;
04108         bestY = y;
04109         continue;
04110       }
04111 
04112       if ( firstKey )
04113       {
04114         int i1 = firstKey->findIndex( cell2->text() );
04115         int i2 = firstKey->findIndex( bestCell->text() );
04116 
04117         if ( i1 != -1 && i2 != -1 )
04118         {
04119           if ( (order1 == Increase && i1 < i2 )
04120                || (order1 == Decrease && i1 > i2) )
04121           {
04122             bestCell = cell2;
04123             bestY = y;
04124             continue;
04125           }
04126 
04127           if ( i1 == i2 )
04128           {
04129             // check 2nd key
04130             if (key2 <= 0)
04131               continue;
04132             KSpreadCell * cell22 = cellAt( key2, d );
04133             KSpreadCell * bestCell2 = cellAt( key2, y );
04134 
04135             if ( cell22->isEmpty() )
04136             {
04137               /* No need to swap */
04138               continue;
04139             }
04140             else if ( cell22->isObscured() && cell22->isObscuringForced() )
04141             {
04142               /* No need to swap */
04143               continue;
04144             }
04145             else if ( bestCell2->isEmpty() )
04146             {
04147               // empty cells are always shifted to the end
04148               bestCell = cell2;
04149               bestY = y;
04150               continue;
04151             }
04152 
04153             if ( (order2 == Increase && *cell22 > *bestCell2)
04154                  || (order2 == Decrease && *cell22 < *bestCell2) )
04155             {
04156               bestCell = cell2;
04157               bestY = y;
04158               continue;
04159             }
04160             else if ( (order2 == Increase && *cell22 < *bestCell2)
04161                       || (order2 == Decrease && *cell22 > *bestCell2) )
04162             {
04163               // already in right order
04164               continue;
04165             }
04166             else
04167             {
04168               // they are equal, check 3rd key
04169               if (key3 <= 0)
04170                 continue;
04171               KSpreadCell * cell23 = cellAt( key3, d );
04172               KSpreadCell * bestCell3 = cellAt( key3, y );
04173 
04174               checkCellContent(cell2, bestCell, status);
04175               if (status == 1)
04176                 continue;
04177               else if (status == 2)
04178               {
04179                 // empty cells are always shifted to the end
04180                 bestCell = cell2;
04181                 bestY = y;
04182                 continue;
04183               }
04184 
04185               if ( (order3 == Increase && *cell23 < *bestCell3)
04186                    || (order3 == Decrease && *cell23 > *bestCell3) )
04187               {
04188                 bestCell = cell2;
04189                 bestY = y;
04190                 continue;
04191               }
04192               else
04193               {
04194                 // they are really equal or in the correct order
04195                 // no swap necessary
04196                 continue;
04197               }
04198             }
04199           }
04200           continue;
04201         }
04202         else if ( i1 != -1 && i2 == -1 )
04203         {
04204           // if not in the key list, the cell is shifted to the end - always
04205           bestCell = cell2;
04206           bestY = y;
04207           continue;
04208         }
04209         else if ( i2 != -1 && i1 == -1 )
04210         {
04211           // only text of cell2 is in the list so it is smaller than bestCell
04212           /* No need to swap */
04213           continue;
04214         }
04215 
04216         // if i1 and i2 are equals -1 go on:
04217       } // if (firstKey)
04218 
04219 
04220         // Here we use the operators < and > for cells, which do it all.
04221       if ( (order1 == Increase && *cell2 < *bestCell)
04222            || (order1 == Decrease && *cell2 > *bestCell) )
04223       {
04224         bestCell = cell2;
04225         bestY = y;
04226       }
04227       else if ( (order1 == Increase && *cell2 > *bestCell)
04228                 || (order1 == Decrease && *cell2 < *bestCell) )
04229       {
04230         // no change necessary
04231         continue;
04232       }
04233       else
04234       {
04235         // *cell2 equals *bestCell
04236         // check 2nd key
04237         if (key2 == 0)
04238           continue;
04239         KSpreadCell * cell22 = cellAt( key2, y );
04240         KSpreadCell * bestCell2 = cellAt( key2, bestY );
04241 
04242         if ( cell22->isEmpty() )
04243         {
04244           /* No need to swap */
04245           continue;
04246         }
04247         else if ( cell22->isObscured() && cell22->isObscuringForced() )
04248         {
04249           /* No need to swap */
04250           continue;
04251         }
04252         else if ( bestCell2->isEmpty() )
04253         {
04254           // empty cells are always shifted to the end
04255           bestCell = cell2;
04256           bestY = y;
04257           continue;
04258         }
04259 
04260         if ( (order2 == Increase && *cell22 < *bestCell2)
04261              || (order2 == Decrease && *cell22 > *bestCell2) )
04262         {
04263           bestCell = cell2;
04264           bestY = y;
04265           continue;
04266         }
04267         else if ( (order2 == Increase && *cell22 > *bestCell2)
04268                   || (order2 == Decrease && *cell22 < *bestCell2) )
04269         {
04270           continue;
04271         }
04272         else
04273         {
04274           // they are equal, check 3rd key
04275           if (key3 == 0)
04276             continue;
04277           KSpreadCell * cell23 = cellAt( key3, y );
04278           KSpreadCell * bestCell3 = cellAt( key3, bestY );
04279 
04280           if ( cell23->isEmpty() )
04281           {
04282             /* No need to swap */
04283             continue;
04284           }
04285           else if ( cell23->isObscured() && cell23->isObscuringForced() )
04286           {
04287             /* No need to swap */
04288             continue;
04289           }
04290           else if ( bestCell3->isEmpty() )
04291           {
04292             // empty cells are always shifted to the end
04293             bestCell = cell2;
04294             bestY = y;
04295             continue;
04296           }
04297 
04298           if ( (order3 == Increase && *cell23 < *bestCell3)
04299                || (order3 == Decrease && *cell23 > *bestCell3) )
04300           {
04301             bestCell = cell2;
04302             bestY = y;
04303             continue;
04304           }
04305           else
04306           {
04307             // they are really equal or already in the correct order
04308             // no swap necessary
04309             continue;
04310           }
04311         }
04312       }
04313     }
04314 
04315     // Swap rows cell1 and bestCell (i.e. d and bestY)
04316     if ( d != bestY )
04317     {
04318       for (int x = target.left(); x <= target.right(); ++x)
04319       {
04320         if ( x != key1 && x != key2 && x != key3)
04321           swapCells( x, d, x, bestY, copyFormat );
04322       }
04323       if (key3 > 0)
04324         swapCells( key3, d, key3, bestY, copyFormat );
04325       if (key2 > 0)
04326         swapCells( key2, d, key2, bestY, copyFormat );
04327       swapCells( key1, d, key1, bestY, copyFormat );
04328     }
04329   } // for (d = ...; ...; ++d)
04330   // doc()->emitEndOperation();
04331   KSpreadMap::respectCase = true;
04332   emit sig_updateView( this );
04333 }
04334 
04335 // from - to - copyFormat
04336 void KSpreadSheet::copyCells( int x1, int y1, int x2, int y2, bool cpFormat )
04337 {
04338   KSpreadCell * sourceCell = cellAt( x1, y1 );
04339   KSpreadCell * targetCell = cellAt( x2, y2 );
04340 
04341   if ( sourceCell->isDefault() && targetCell->isDefault())
04342   {
04343     // if the source and target is default there is nothing to copy
04344     return;
04345   }
04346 
04347   targetCell = nonDefaultCell(x2, y2);
04348 
04349   // TODO: check if this enough
04350   targetCell->copyContent( sourceCell );
04351 
04352   /*
04353     if ( !sourceCell->isFormula() )
04354     {
04355     targetCell->copyContent( sourceCell );
04356     }
04357     else
04358     {
04359     targetCell->setCellText( targetCell->decodeFormula( sourceCell->encodeFormula() ) );
04360     targetCell->setCalcDirtyFlag();
04361     targetCell->calc(false);
04362   }
04363   */
04364 
04365   if (cpFormat)
04366   {
04367     targetCell->copyFormat( sourceCell );
04368     /*
04369     targetCell->setAlign( sourceCell->align( x1, y1 ) );
04370     targetCell->setAlignY( sourceCell->alignY( x1, y1 ) );
04371     targetCell->setTextFont( sourceCell->textFont( x1, y1 ) );
04372     targetCell->setTextColor( sourceCell->textColor( x1, y1 ) );
04373     targetCell->setBgColor( sourceCell->bgColor( x1, y1 ) );
04374     targetCell->setLeftBorderPen( sourceCell->leftBorderPen( x1, y1 ) );
04375     targetCell->setTopBorderPen( sourceCell->topBorderPen( x1, y1 ) );
04376     targetCell->setBottomBorderPen( sourceCell->bottomBorderPen( x1, y1 ) );
04377     targetCell->setRightBorderPen( sourceCell->rightBorderPen( x1, y1 ) );
04378     targetCell->setFallDiagonalPen( sourceCell->fallDiagonalPen( x1, y1 ) );
04379     targetCell->setGoUpDiagonalPen( sourceCell->goUpDiagonalPen( x1, y1 ) );
04380     targetCell->setBackGroundBrush( sourceCell->backGroundBrush( x1, y1 ) );
04381     targetCell->setPrecision( sourceCell->precision( x1, y1 ) );
04382     targetCell->setPrefix( sourceCell->prefix( x1, y1 ) );
04383     targetCell->setPostfix( sourceCell->postfix( x1, y1 ) );
04384     targetCell->setFloatFormat( sourceCell->floatFormat( x1, y1 ) );
04385     targetCell->setFloatColor( sourceCell->floatColor( x1, y1 ) );
04386     targetCell->setMultiRow( sourceCell->multiRow( x1, y1 ) );
04387     targetCell->setVerticalText( sourceCell->verticalText( x1, y1 ) );
04388     targetCell->setStyle( sourceCell->style() );
04389     targetCell->setDontPrintText( sourceCell->getDontprintText( x1, y1 ) );
04390     targetCell->setIndent( sourceCell->getIndent( x1, y1 ) );
04391     targetCell->SetConditionList(sourceCell->GetConditionList());
04392     targetCell->setComment( sourceCell->comment( x1, y1 ) );
04393     targetCell->setAngle( sourceCell->getAngle( x1, y1 ) );
04394     targetCell->setFormatType( sourceCell->getFormatType( x1, y1 ) );
04395     */
04396   }
04397 }
04398 
04399 void KSpreadSheet::swapCells( int x1, int y1, int x2, int y2, bool cpFormat )
04400 {
04401   KSpreadCell * ref1 = cellAt( x1, y1 );
04402   KSpreadCell * ref2 = cellAt( x2, y2 );
04403 
04404   if ( ref1->isDefault() )
04405   {
04406     if ( !ref2->isDefault() )
04407     {
04408       ref1 = nonDefaultCell( x1, y1 );
04409       // TODO : make ref2 default instead of copying a default cell into it
04410     }
04411     else
04412       return; // nothing to do
04413   }
04414   else
04415     if ( ref2->isDefault() )
04416     {
04417       ref2 = nonDefaultCell( x2, y2 );
04418       // TODO : make ref1 default instead of copying a default cell into it
04419     }
04420 
04421   // Dummy cell used for swapping cells.
04422   // In fact we copy only content and no layout
04423   // information. Imagine sorting in a sheet. Swapping
04424   // the format while sorting is not what you would expect
04425   // as a user.
04426   if (!ref1->isFormula() && !ref2->isFormula())
04427   {
04428     KSpreadCell *tmp = new KSpreadCell( this, -1, -1 );
04429 
04430     tmp->copyContent( ref1 );
04431     ref1->copyContent( ref2 );
04432     ref2->copyContent( tmp );
04433 
04434     delete tmp;
04435   }
04436   else
04437     if ( ref1->isFormula() && ref2->isFormula() )
04438     {
04439       QString d = ref1->encodeFormula();
04440       ref1->setCellText( ref1->decodeFormula( ref2->encodeFormula( ) ) );
04441       ref1->setCalcDirtyFlag();
04442       ref1->calc(false);
04443       ref2->setCellText( ref2->decodeFormula( d ) );
04444       ref2->setCalcDirtyFlag();
04445       ref2->calc(false);
04446     }
04447     else
04448       if (ref1->isFormula() && !ref2->isFormula() )
04449       {
04450         QString d = ref1->encodeFormula();
04451         ref1->setCellText(ref2->text());
04452         ref2->setCellText(ref2->decodeFormula(d));
04453         ref2->setCalcDirtyFlag();
04454         ref2->calc(false);
04455       }
04456       else
04457         if (!ref1->isFormula() && ref2->isFormula() )
04458         {
04459           QString d = ref2->encodeFormula();
04460           ref2->setCellText(ref1->text());
04461           ref1->setCellText(ref1->decodeFormula(d));
04462           ref1->setCalcDirtyFlag();
04463           ref1->calc(false);
04464         }
04465 
04466   if (cpFormat)
04467   {
04468     KSpreadFormat::Align a = ref1->align( ref1->column(), ref1->row() );
04469     ref1->setAlign( ref2->align( ref2->column(), ref2->row() ) );
04470     ref2->setAlign(a);
04471 
04472     KSpreadFormat::AlignY ay = ref1->alignY( ref1->column(), ref1->row() );
04473     ref1->setAlignY( ref2->alignY( ref2->column(), ref2->row() ) );
04474     ref2->setAlignY(ay);
04475 
04476     QFont textFont = ref1->textFont( ref1->column(), ref1->row() );
04477     ref1->setTextFont( ref2->textFont( ref2->column(), ref2->row() ) );
04478     ref2->setTextFont(textFont);
04479 
04480     QColor textColor = ref1->textColor( ref1->column(), ref1->row() );
04481     ref1->setTextColor( ref2->textColor( ref2->column(), ref2->row() ) );
04482     ref2->setTextColor(textColor);
04483 
04484     QColor bgColor = ref1->bgColor( ref1->column(), ref1->row() );
04485     ref1->setBgColor( ref2->bgColor( ref2->column(), ref2->row() ) );
04486     ref2->setBgColor(bgColor);
04487 
04488     QPen lbp = ref1->leftBorderPen( ref1->column(), ref1->row() );
04489     ref1->setLeftBorderPen( ref2->leftBorderPen( ref2->column(), ref2->row() ) );
04490     ref2->setLeftBorderPen(lbp);
04491 
04492     QPen tbp = ref1->topBorderPen( ref1->column(), ref1->row() );
04493     ref1->setTopBorderPen( ref2->topBorderPen( ref2->column(), ref2->row() ) );
04494     ref2->setTopBorderPen(tbp);
04495 
04496     QPen bbp = ref1->bottomBorderPen( ref1->column(), ref1->row() );
04497     ref1->setBottomBorderPen( ref2->bottomBorderPen( ref2->column(), ref2->row() ) );
04498     ref2->setBottomBorderPen(bbp);
04499 
04500     QPen rbp = ref1->rightBorderPen( ref1->column(), ref1->row() );
04501     ref1->setRightBorderPen( ref2->rightBorderPen( ref2->column(), ref2->row() ) );
04502     ref2->setRightBorderPen(rbp);
04503 
04504     QPen fdp = ref1->fallDiagonalPen( ref1->column(), ref1->row() );
04505     ref1->setFallDiagonalPen( ref2->fallDiagonalPen( ref2->column(), ref2->row() ) );
04506     ref2->setFallDiagonalPen(fdp);
04507 
04508     QPen udp = ref1->goUpDiagonalPen( ref1->column(), ref1->row() );
04509     ref1->setGoUpDiagonalPen( ref2->goUpDiagonalPen( ref2->column(), ref2->row() ) );
04510     ref2->setGoUpDiagonalPen(udp);
04511 
04512     QBrush bgBrush = ref1->backGroundBrush( ref1->column(), ref1->row() );
04513     ref1->setBackGroundBrush( ref2->backGroundBrush( ref2->column(), ref2->row() ) );
04514     ref2->setBackGroundBrush(bgBrush);
04515 
04516     int pre = ref1->precision( ref1->column(), ref1->row() );
04517     ref1->setPrecision( ref2->precision( ref2->column(), ref2->row() ) );
04518     ref2->setPrecision(pre);
04519 
04520     QString prefix = ref1->prefix( ref1->column(), ref1->row() );
04521     ref1->setPrefix( ref2->prefix( ref2->column(), ref2->row() ) );
04522     ref2->setPrefix(prefix);
04523 
04524     QString postfix = ref1->postfix( ref1->column(), ref1->row() );
04525     ref1->setPostfix( ref2->postfix( ref2->column(), ref2->row() ) );
04526     ref2->setPostfix(postfix);
04527 
04528     KSpreadFormat::FloatFormat f = ref1->floatFormat( ref1->column(), ref1->row() );
04529     ref1->setFloatFormat( ref2->floatFormat( ref2->column(), ref2->row() ) );
04530     ref2->setFloatFormat(f);
04531 
04532     KSpreadFormat::FloatColor c = ref1->floatColor( ref1->column(), ref1->row() );
04533     ref1->setFloatColor( ref2->floatColor( ref2->column(), ref2->row() ) );
04534     ref2->setFloatColor(c);
04535 
04536     bool multi = ref1->multiRow( ref1->column(), ref1->row() );
04537     ref1->setMultiRow( ref2->multiRow( ref2->column(), ref2->row() ) );
04538     ref2->setMultiRow(multi);
04539 
04540     bool vert = ref1->verticalText( ref1->column(), ref1->row() );
04541     ref1->setVerticalText( ref2->verticalText( ref2->column(), ref2->row() ) );
04542     ref2->setVerticalText(vert);
04543 
04544     bool print = ref1->getDontprintText( ref1->column(), ref1->row() );
04545     ref1->setDontPrintText( ref2->getDontprintText( ref2->column(), ref2->row() ) );
04546     ref2->setDontPrintText(print);
04547 
04548     double ind = ref1->getIndent( ref1->column(), ref1->row() );
04549     ref1->setIndent( ref2->getIndent( ref2->column(), ref2->row() ) );
04550     ref2->setIndent( ind );
04551 
04552     QValueList<KSpreadConditional> conditionList = ref1->conditionList();
04553     ref1->setConditionList(ref2->conditionList());
04554     ref2->setConditionList(conditionList);
04555 
04556     QString com = ref1->comment( ref1->column(), ref1->row() );
04557     ref1->setComment( ref2->comment( ref2->column(), ref2->row() ) );
04558     ref2->setComment(com);
04559 
04560     int angle = ref1->getAngle( ref1->column(), ref1->row() );
04561     ref1->setAngle( ref2->getAngle( ref2->column(), ref2->row() ) );
04562     ref2->setAngle(angle);
04563 
04564     FormatType form = ref1->getFormatType( ref1->column(), ref1->row() );
04565     ref1->setFormatType( ref2->getFormatType( ref2->column(), ref2->row() ) );
04566     ref2->setFormatType(form);
04567   }
04568 }
04569 
04570 void KSpreadSheet::refreshPreference()
04571 {
04572   if ( getAutoCalc() )
04573     recalc();
04574 
04575   emit sig_updateHBorder( this );
04576   emit sig_updateView( this );
04577 }
04578 
04579 
04580 bool KSpreadSheet::areaIsEmpty(const QRect &area, TestType _type)
04581 {
04582     // Complete rows selected ?
04583     if ( util_isRowSelected(area) )
04584     {
04585         for ( int row = area.top(); row <= area.bottom(); ++row )
04586         {
04587             KSpreadCell * c = getFirstCellRow( row );
04588             while ( c )
04589             {
04590                 if ( !c->isObscuringForced())
04591                 {
04592                     switch( _type )
04593                     {
04594                     case Text :
04595                         if ( !c->text().isEmpty())
04596                             return false;
04597                         break;
04598                     case Validity:
04599                         if ( c->getValidity(0))
04600                             return false;
04601                         break;
04602                     case Comment:
04603                         if ( !c->comment(c->column(), row).isEmpty())
04604                             return false;
04605                         break;
04606                     case ConditionalCellAttribute:
04607                         if ( c->conditionList().count()> 0)
04608                             return false;
04609                         break;
04610                     }
04611                 }
04612 
04613                 c = getNextCellRight( c->column(), row );
04614             }
04615         }
04616     }
04617     // Complete columns selected ?
04618     else if ( util_isColumnSelected(area) )
04619     {
04620         for ( int col = area.left(); col <= area.right(); ++col )
04621         {
04622             KSpreadCell * c = getFirstCellColumn( col );
04623             while ( c )
04624             {
04625                 if ( !c->isObscuringForced() )
04626                 {
04627                     switch( _type )
04628                     {
04629                     case Text :
04630                         if ( !c->text().isEmpty())
04631                             return false;
04632                         break;
04633                     case Validity:
04634                         if ( c->getValidity(0))
04635                             return false;
04636                         break;
04637                     case Comment:
04638                         if ( !c->comment(col, c->row()).isEmpty())
04639                             return false;
04640                         break;
04641                     case ConditionalCellAttribute:
04642                         if ( c->conditionList().count()> 0)
04643                             return false;
04644                         break;
04645                     }
04646                 }
04647 
04648                 c = getNextCellDown( col, c->row() );
04649             }
04650         }
04651     }
04652     else
04653     {
04654         KSpreadCell * cell;
04655 
04656         int right  = area.right();
04657         int bottom = area.bottom();
04658         for ( int x = area.left(); x <= right; ++x )
04659             for ( int y = area.top(); y <= bottom; ++y )
04660             {
04661                 cell = cellAt( x, y );
04662                 if (!cell->isObscuringForced() )
04663                 {
04664                     switch( _type )
04665                     {
04666                     case Text :
04667                         if ( !cell->text().isEmpty())
04668                             return false;
04669                         break;
04670                     case Validity:
04671                         if ( cell->getValidity(0))
04672                             return false;
04673                         break;
04674                     case Comment:
04675                         if ( !cell->comment(x, y).isEmpty())
04676                             return false;
04677                         break;
04678                     case ConditionalCellAttribute:
04679                         if ( cell->conditionList().count()> 0)
04680                             return false;
04681                         break;
04682                     }
04683                 }
04684             }
04685     }
04686     return true;
04687 }
04688 
04689 struct SetSelectionMultiRowWorker : public KSpreadSheet::CellWorker
04690 {
04691   bool enable;
04692   SetSelectionMultiRowWorker( bool _enable )
04693     : KSpreadSheet::CellWorker( ), enable( _enable ) { }
04694 
04695   class KSpreadUndoAction* createUndoAction( KSpreadDoc * doc, KSpreadSheet * sheet, QRect & r )
04696   {
04697     QString title = i18n("Multirow");
04698     return new KSpreadUndoCellFormat( doc, sheet, r, title );
04699   }
04700 
04701   bool testCondition( KSpreadCell * cell )
04702   {
04703     return ( !cell->isObscuringForced() );
04704   }
04705 
04706   void doWork( KSpreadCell * cell, bool, int, int )
04707   {
04708     cell->setDisplayDirtyFlag();
04709     cell->setMultiRow( enable );
04710     cell->setVerticalText( false );
04711     cell->setAngle( 0 );
04712     cell->clearDisplayDirtyFlag();
04713   }
04714 };
04715 
04716 void KSpreadSheet::setSelectionMultiRow( KSpreadSelection* selectionInfo,
04717                                          bool enable )
04718 {
04719     SetSelectionMultiRowWorker w( enable );
04720     workOnCells( selectionInfo, w );
04721 }
04722 
04723 
04724 struct SetSelectionAlignWorker
04725   : public KSpreadSheet::CellWorkerTypeA
04726 {
04727     KSpreadFormat::Align _align;
04728     SetSelectionAlignWorker( KSpreadFormat::Align align ) : _align( align ) {}
04729     QString getUndoTitle() { return i18n("Change Horizontal Alignment"); }
04730     bool testCondition( RowFormat* rw ) {
04731     return ( rw->hasProperty( KSpreadCell::PAlign ) );
04732     }
04733     void doWork( RowFormat* rw ) {
04734     rw->setAlign( _align );
04735     }
04736     void doWork( ColumnFormat* cl ) {
04737     cl->setAlign( _align );
04738     }
04739     void prepareCell( KSpreadCell* c ) {
04740     c->clearProperty( KSpreadCell::PAlign );
04741     c->clearNoFallBackProperties( KSpreadCell::PAlign );
04742     }
04743     bool testCondition( KSpreadCell* cell ) {
04744     return ( !cell->isObscuringForced() );
04745     }
04746     void doWork( KSpreadCell* cell, bool cellRegion, int, int ) {
04747     if ( cellRegion )
04748         cell->setDisplayDirtyFlag();
04749     cell->setAlign( _align );
04750     if ( cellRegion )
04751         cell->clearDisplayDirtyFlag();
04752     }
04753 };
04754 
04755 
04756 void KSpreadSheet::setSelectionAlign( KSpreadSelection* selectionInfo,
04757                                       KSpreadFormat::Align _align )
04758 {
04759     SetSelectionAlignWorker w( _align );
04760     workOnCells( selectionInfo, w );
04761 }
04762 
04763 
04764 struct SetSelectionAlignYWorker : public KSpreadSheet::CellWorkerTypeA {
04765     KSpreadFormat::AlignY _alignY;
04766     SetSelectionAlignYWorker( KSpreadFormat::AlignY alignY )
04767       : _alignY( alignY )
04768     {
04769       kdDebug() << "AlignY: " << _alignY << endl;
04770     }
04771     QString getUndoTitle() { return i18n("Change Vertical Alignment"); }
04772     bool testCondition( RowFormat* rw ) {
04773     return ( rw->hasProperty( KSpreadCell::PAlignY ) );
04774     }
04775     void doWork( RowFormat* rw ) {
04776     rw->setAlignY( _alignY );
04777     }
04778     void doWork( ColumnFormat* cl ) {
04779     cl->setAlignY( _alignY );
04780     }
04781     void prepareCell( KSpreadCell* c ) {
04782     c->clearProperty( KSpreadCell::PAlignY );
04783     c->clearNoFallBackProperties( KSpreadCell::PAlignY );
04784     }
04785     bool testCondition( KSpreadCell* cell ) {
04786         kdDebug() << "testCondition" << endl;
04787     return ( !cell->isObscuringForced() );
04788     }
04789     void doWork( KSpreadCell* cell, bool cellRegion, int, int ) {
04790     if ( cellRegion )
04791         cell->setDisplayDirtyFlag();
04792         kdDebug() << "cell->setAlignY: " << _alignY << endl;
04793     cell->setAlignY( _alignY );
04794     if ( cellRegion )
04795         cell->clearDisplayDirtyFlag();
04796     }
04797 };
04798 
04799 
04800 void KSpreadSheet::setSelectionAlignY( KSpreadSelection* selectionInfo,
04801                                        KSpreadFormat::AlignY _alignY )
04802 {
04803   kdDebug() << "setSelectionAlignY: " << _alignY << endl;
04804     SetSelectionAlignYWorker w( _alignY );
04805     workOnCells( selectionInfo, w );
04806 }
04807 
04808 
04809 struct SetSelectionPrecisionWorker : public KSpreadSheet::CellWorker {
04810     int _delta;
04811     SetSelectionPrecisionWorker( int delta ) : KSpreadSheet::CellWorker( ), _delta( delta ) { }
04812 
04813     class KSpreadUndoAction* createUndoAction( KSpreadDoc* doc, KSpreadSheet* sheet, QRect& r ) {
04814         QString title=i18n("Change Precision");
04815     return new KSpreadUndoCellFormat( doc, sheet, r, title );
04816     }
04817     bool testCondition( KSpreadCell* cell ) {
04818     return ( !cell->isObscuringForced() );
04819     }
04820     void doWork( KSpreadCell* cell, bool, int, int ) {
04821     cell->setDisplayDirtyFlag();
04822     if ( _delta == 1 )
04823         cell->incPrecision();
04824     else
04825         cell->decPrecision();
04826     cell->clearDisplayDirtyFlag();
04827     }
04828 };
04829 
04830 void KSpreadSheet::setSelectionPrecision( KSpreadSelection* selectionInfo,
04831                                           int _delta )
04832 {
04833     SetSelectionPrecisionWorker w( _delta );
04834     workOnCells( selectionInfo, w );
04835 }
04836 
04837 struct SetSelectionStyleWorker : public KSpreadSheet::CellWorkerTypeA
04838 {
04839   KSpreadStyle * m_style;
04840   SetSelectionStyleWorker( KSpreadStyle * style )
04841     : m_style( style )
04842   {
04843   }
04844 
04845   QString getUndoTitle()
04846   {
04847     return i18n("Apply Style");
04848   }
04849 
04850   void doWork( RowFormat* rw )
04851   {
04852     rw->setKSpreadStyle( m_style );
04853   }
04854 
04855   void doWork( ColumnFormat* cl )
04856   {
04857     cl->setKSpreadStyle( m_style );
04858   }
04859 
04860   bool testCondition( KSpreadCell* cell )
04861   {
04862     return ( !cell->isObscuringForced() && cell->kspreadStyle() != m_style );
04863   }
04864 
04865   void doWork( KSpreadCell* cell, bool cellRegion, int, int )
04866   {
04867     if ( cellRegion )
04868       cell->setDisplayDirtyFlag();
04869 
04870     cell->setKSpreadStyle( m_style );
04871 
04872     if ( cellRegion )
04873       cell->clearDisplayDirtyFlag();
04874   }
04875 };
04876 
04877 
04878 void KSpreadSheet::setSelectionStyle( KSpreadSelection * selectionInfo, KSpreadStyle * style )
04879 {
04880     SetSelectionStyleWorker w( style );
04881     workOnCells( selectionInfo, w );
04882 }
04883 
04884 struct SetSelectionMoneyFormatWorker : public KSpreadSheet::CellWorkerTypeA
04885 {
04886     bool b;
04887     KSpreadDoc *m_pDoc;
04888     SetSelectionMoneyFormatWorker( bool _b,KSpreadDoc* _doc ) : b( _b ), m_pDoc(_doc) { }
04889     QString getUndoTitle() { return i18n("Format Money"); }
04890     bool testCondition( RowFormat* rw ) {
04891     return ( rw->hasProperty( KSpreadCell::PFormatType )
04892          || rw->hasProperty( KSpreadCell::PPrecision ) );
04893     }
04894     void doWork( RowFormat* rw ) {
04895     rw->setFormatType( b ? Money_format : Generic_format );
04896     rw->setPrecision( b ? m_pDoc->locale()->fracDigits() : 0 );
04897     }
04898     void doWork( ColumnFormat* cl ) {
04899     cl->setFormatType( b ? Money_format : Generic_format );
04900     cl->setPrecision( b ? m_pDoc->locale()->fracDigits() : 0 );
04901     }
04902     void prepareCell( KSpreadCell* c ) {
04903     c->clearProperty( KSpreadCell::PPrecision );
04904     c->clearNoFallBackProperties( KSpreadCell::PPrecision );
04905     c->clearProperty( KSpreadCell::PFormatType );
04906     c->clearNoFallBackProperties( KSpreadCell::PFormatType );
04907     }
04908     bool testCondition( KSpreadCell* cell ) {
04909     return ( !cell->isObscuringForced() );
04910     }
04911     void doWork( KSpreadCell* cell, bool cellRegion, int, int ) {
04912     if ( cellRegion )
04913         cell->setDisplayDirtyFlag();
04914     cell->setFormatType( b ? Money_format : Generic_format );
04915     cell->setPrecision( b ?  m_pDoc->locale()->fracDigits() : 0 );
04916     if ( cellRegion )
04917         cell->clearDisplayDirtyFlag();
04918     }
04919 };
04920 
04921 
04922 void KSpreadSheet::setSelectionMoneyFormat( KSpreadSelection* selectionInfo,
04923                                             bool b )
04924 {
04925     SetSelectionMoneyFormatWorker w( b,doc() );
04926     workOnCells( selectionInfo, w );
04927 }
04928 
04929 
04930 struct IncreaseIndentWorker : public KSpreadSheet::CellWorkerTypeA {
04931     double tmpIndent, valIndent;
04932     IncreaseIndentWorker( double _tmpIndent, double _valIndent ) : tmpIndent( _tmpIndent ), valIndent( _valIndent ) { }
04933     QString getUndoTitle() { return i18n("Increase Indent"); }
04934     bool testCondition( RowFormat* rw ) {
04935     return ( rw->hasProperty( KSpreadCell::PIndent ) );
04936     }
04937     void doWork( RowFormat* rw ) {
04938     rw->setIndent( tmpIndent+valIndent );
04939     rw->setAlign( KSpreadCell::Left );
04940     }
04941     void doWork( ColumnFormat* cl ) {
04942     cl->setIndent( tmpIndent+valIndent );
04943     cl->setAlign( KSpreadCell::Left );
04944     }
04945     void prepareCell( KSpreadCell* c ) {
04946     c->clearProperty( KSpreadCell::PIndent );
04947     c->clearNoFallBackProperties( KSpreadCell::PIndent );
04948     c->clearProperty( KSpreadCell::PAlign );
04949     c->clearNoFallBackProperties( KSpreadCell::PAlign );
04950     }
04951     bool testCondition( KSpreadCell* cell ) {
04952     return ( !cell->isObscuringForced() );
04953     }
04954     void doWork( KSpreadCell* cell, bool cellRegion, int x, int y ) {
04955     if ( cellRegion ) {
04956         if(cell->align(x,y)!=KSpreadCell::Left)
04957         {
04958         cell->setAlign(KSpreadCell::Left);
04959         cell->setIndent( 0.0 );
04960         }
04961         cell->setDisplayDirtyFlag();
04962         cell->setIndent( /* ### ??? --> */ cell->getIndent(x,y) /* <-- */ +valIndent );
04963         cell->clearDisplayDirtyFlag();
04964     } else {
04965         cell->setIndent( tmpIndent+valIndent);
04966         cell->setAlign( KSpreadCell::Left);
04967     }
04968     }
04969 };
04970 
04971 
04972 void KSpreadSheet::increaseIndent(KSpreadSelection* selectionInfo)
04973 {
04974     double valIndent = doc()->getIndentValue();
04975     QPoint marker(selectionInfo->marker());
04976     KSpreadCell* c = cellAt( marker );
04977     double tmpIndent = c->getIndent( marker.x(), marker.y() );
04978 
04979     IncreaseIndentWorker w( tmpIndent, valIndent );
04980     workOnCells( selectionInfo, w );
04981 }
04982 
04983 
04984 struct DecreaseIndentWorker : public KSpreadSheet::CellWorkerTypeA {
04985     double tmpIndent, valIndent;
04986     DecreaseIndentWorker( double _tmpIndent, double _valIndent ) : tmpIndent( _tmpIndent ), valIndent( _valIndent ) { }
04987     QString getUndoTitle() { return i18n("Decrease Indent"); }
04988     bool testCondition( RowFormat* rw ) {
04989     return ( rw->hasProperty( KSpreadCell::PIndent ) );
04990     }
04991     void doWork( RowFormat* rw ) {
04992         rw->setIndent( QMAX( 0.0, tmpIndent - valIndent ) );
04993     }
04994     void doWork( ColumnFormat* cl ) {
04995         cl->setIndent( QMAX( 0.0, tmpIndent - valIndent ) );
04996     }
04997     void prepareCell( KSpreadCell* c ) {
04998     c->clearProperty( KSpreadCell::PIndent );
04999     c->clearNoFallBackProperties( KSpreadCell::PIndent );
05000     }
05001     bool testCondition( KSpreadCell* cell ) {
05002     return ( !cell->isObscuringForced() );
05003     }
05004     void doWork( KSpreadCell* cell, bool cellRegion, int x, int y ) {
05005     if ( cellRegion ) {
05006         cell->setDisplayDirtyFlag();
05007         cell->setIndent( QMAX( 0.0, cell->getIndent( x, y ) - valIndent ) );
05008         cell->clearDisplayDirtyFlag();
05009     } else {
05010         cell->setIndent( QMAX( 0.0, tmpIndent - valIndent ) );
05011     }
05012     }
05013 };
05014 
05015 
05016 void KSpreadSheet::decreaseIndent( KSpreadSelection* selectionInfo )
05017 {
05018     double valIndent = doc()->getIndentValue();
05019     QPoint marker(selectionInfo->marker());
05020     KSpreadCell* c = cellAt( marker );
05021     double tmpIndent = c->getIndent( marker.x(), marker.y() );
05022 
05023     DecreaseIndentWorker w( tmpIndent, valIndent );
05024     workOnCells( selectionInfo, w );
05025 }
05026 
05027 
05028 int KSpreadSheet::adjustColumnHelper( KSpreadCell * c, int _col, int _row )
05029 {
05030     double long_max = 0.0;
05031     c->calculateTextParameters( painter(), _col, _row );
05032     if ( c->textWidth() > long_max )
05033     {
05034         double indent = 0.0;
05035         int a = c->align( c->column(), c->row() );
05036         if ( a == KSpreadCell::Undefined )
05037         {
05038             if ( c->value().isNumber() || c->isDate() || c->isTime())
05039                 a = KSpreadCell::Right;
05040             else
05041                 a = KSpreadCell::Left;
05042         }
05043 
05044         if ( a == KSpreadCell::Left )
05045             indent = c->getIndent( c->column(), c->row() );
05046         long_max = indent + c->textWidth()
05047                    + c->leftBorderWidth( c->column(), c->row() )
05048                    + c->rightBorderWidth( c->column(), c->row() );
05049     }
05050     return (int)long_max;
05051 }
05052 
05053 int KSpreadSheet::adjustColumn( KSpreadSelection* selectionInfo, int _col )
05054 {
05055   QRect selection(selectionInfo->selection());
05056   double long_max = 0.0;
05057   if ( _col == -1 )
05058   {
05059     if ( util_isColumnSelected(selection) )
05060     {
05061       for ( int col = selection.left(); col <= selection.right(); ++col )
05062       {
05063         KSpreadCell * c = getFirstCellColumn( col );
05064         while ( c )
05065         {
05066           if ( !c->isEmpty() && !c->isObscured() )
05067           {
05068               long_max = QMAX( adjustColumnHelper( c, col, c->row() ), long_max );
05069           } // if !isEmpty...
05070           c = getNextCellDown( col, c->row() );
05071         }
05072       }
05073     }
05074   }
05075   else
05076   {
05077     if ( util_isColumnSelected(selection) )
05078     {
05079       for ( int col = selection.left(); col <= selection.right(); ++col )
05080       {
05081         KSpreadCell * c = getFirstCellColumn( col );
05082         while ( c )
05083         {
05084           if ( !c->isEmpty() && !c->isObscured())
05085           {
05086               long_max = QMAX( adjustColumnHelper( c, col, c->row() ), long_max );
05087           }
05088           c = getNextCellDown( col, c->row() );
05089         } // end while
05090       }
05091     }
05092     else
05093     {
05094       int x = _col;
05095       KSpreadCell * cell;
05096       for ( int y = selection.top(); y <= selection.bottom(); ++y )
05097       {
05098         cell = cellAt( x, y );
05099         if ( cell != d->defaultCell && !cell->isEmpty()
05100              && !cell->isObscured() )
05101         {
05102             long_max = QMAX( adjustColumnHelper( cell, x, y ), long_max );
05103         }
05104       } // for top...bottom
05105     } // not column selected
05106   }
05107 
05108   //add 4 because long_max is the long of the text
05109   //but column has borders
05110   if( long_max == 0 )
05111     return -1;
05112   else
05113     return ( (int)long_max + 4 );
05114 }
05115 
05116 int KSpreadSheet::adjustRow( KSpreadSelection* selectionInfo, int _row )
05117 {
05118   QRect selection(selectionInfo->selection());
05119   double long_max = 0.0;
05120   if( _row == -1 ) //No special row is defined, so use selected rows
05121   {
05122     if ( util_isRowSelected(selection) )
05123     {
05124       for ( int row = selection.top(); row <= selection.bottom(); ++row )
05125       {
05126         KSpreadCell * c = getFirstCellRow( row );
05127         while ( c )
05128         {
05129           if ( !c->isEmpty() && !c->isObscured() )
05130           {
05131             c->calculateTextParameters( painter(), c->column(), row );
05132             if( c->textHeight() > long_max )
05133               long_max = c->textHeight()
05134                 + c->topBorderWidth( c->column(), c->row() )
05135                 + c->bottomBorderWidth( c->column(), c->row() );
05136           }
05137           c = getNextCellRight( c->column(), row );
05138         }
05139       }
05140     }
05141   }
05142   else
05143   {
05144     if ( util_isRowSelected(selection) )
05145     {
05146       for ( int row = selection.top(); row <= selection.bottom(); ++row )
05147       {
05148         KSpreadCell * c = getFirstCellRow( row );
05149         while ( c )
05150         {
05151           if ( !c->isEmpty() && !c->isObscured() )
05152           {
05153             c->calculateTextParameters( painter(), c->column(), row );
05154             if ( c->textHeight() > long_max )
05155               long_max = c->textHeight()
05156                 + c->topBorderWidth( c->column(), c->row() )
05157                 + c->bottomBorderWidth( c->column(), c->row() );
05158           }
05159           c = getNextCellRight( c->column(), row );
05160         }
05161       }
05162     }
05163     else // no row selected
05164     {
05165       int y = _row;
05166       KSpreadCell * cell;
05167       for ( int x = selection.left(); x <= selection.right(); ++x )
05168       {
05169         cell = cellAt( x, y );
05170         if ( cell != d->defaultCell && !cell->isEmpty()
05171             && !cell->isObscured() )
05172         {
05173           cell->calculateTextParameters( painter(), x, y );
05174           if ( cell->textHeight() > long_max )
05175             long_max = cell->textHeight()
05176               + cell->topBorderWidth( cell->column(), cell->row() )
05177               + cell->bottomBorderWidth( cell->column(), cell->row() );
05178         }
05179       }
05180     }
05181   }
05182   //add 4 because long_max is the long of the text
05183   //but row has borders
05184   if( long_max == 0.0 )
05185     return -1;
05186   else
05187     return ( (int)long_max + 4 );
05188 }
05189 
05190 struct ClearTextSelectionWorker : public KSpreadSheet::CellWorker {
05191     KSpreadSheet   * _s;
05192 
05193     ClearTextSelectionWorker(  KSpreadSheet * s )
05194       : KSpreadSheet::CellWorker( ),  _s( s ) { }
05195 
05196     class KSpreadUndoAction* createUndoAction( KSpreadDoc* doc, KSpreadSheet* sheet, QRect& r ) {
05197     return new KSpreadUndoChangeAreaTextCell( doc, sheet, r );
05198     }
05199     bool testCondition( KSpreadCell* cell ) {
05200     return ( !cell->isObscured() );
05201     }
05202     void doWork( KSpreadCell* cell, bool, int, int )
05203     {
05204     cell->setCellText( "" );
05205     }
05206 };
05207 
05208 void KSpreadSheet::clearTextSelection( KSpreadSelection* selectionInfo )
05209 {
05210   if (areaIsEmpty(selectionInfo->selection()))
05211     return;
05212 
05213   ClearTextSelectionWorker w( this );
05214   workOnCells( selectionInfo, w );
05215 }
05216 
05217 
05218 struct ClearValiditySelectionWorker : public KSpreadSheet::CellWorker {
05219     ClearValiditySelectionWorker( ) : KSpreadSheet::CellWorker( ) { }
05220 
05221     class KSpreadUndoAction* createUndoAction( KSpreadDoc* doc, KSpreadSheet* sheet, QRect& r ) {
05222     return new KSpreadUndoConditional( doc, sheet, r );
05223     }
05224     bool testCondition( KSpreadCell* cell ) {
05225     return ( !cell->isObscured() );
05226     }
05227     void doWork( KSpreadCell* cell, bool, int, int ) {
05228     cell->removeValidity();
05229     }
05230 };
05231 
05232 void KSpreadSheet::clearValiditySelection( KSpreadSelection* selectionInfo )
05233 {
05234     if(areaIsEmpty(selectionInfo->selection(), Validity))
05235         return;
05236 
05237   ClearValiditySelectionWorker w;
05238   workOnCells( selectionInfo, w );
05239 }
05240 
05241 
05242 struct ClearConditionalSelectionWorker : public KSpreadSheet::CellWorker
05243 {
05244   ClearConditionalSelectionWorker( ) : KSpreadSheet::CellWorker( ) { }
05245 
05246   class KSpreadUndoAction* createUndoAction( KSpreadDoc* doc,
05247                          KSpreadSheet* sheet,
05248                          QRect& r )
05249   {
05250     return new KSpreadUndoConditional( doc, sheet, r );
05251   }
05252   bool testCondition( KSpreadCell* cell )
05253   {
05254     return ( !cell->isObscured() );
05255   }
05256   void doWork( KSpreadCell* cell, bool, int, int )
05257   {
05258     QValueList<KSpreadConditional> emptyList;
05259     cell->setConditionList(emptyList);
05260   }
05261 };
05262 
05263 void KSpreadSheet::clearConditionalSelection( KSpreadSelection* selectionInfo )
05264 {
05265   ClearConditionalSelectionWorker w;
05266   workOnCells( selectionInfo, w );
05267 }
05268 
05269 void KSpreadSheet::fillSelection( KSpreadSelection * selectionInfo, int direction )
05270 {
05271   QRect rct( selectionInfo->selection() );
05272   int right  = rct.right();
05273   int bottom = rct.bottom();
05274   int left   = rct.left();
05275   int top    = rct.top();
05276   int width  = rct.width();
05277   int height = rct.height();
05278 
05279   QDomDocument undoDoc = saveCellRect( rct );
05280   loadSelectionUndo( undoDoc, rct, left - 1, top - 1, false, 0 );
05281 
05282   QDomDocument doc;
05283 
05284   switch( direction )
05285   {
05286    case Right:
05287     doc = saveCellRect( QRect( left, top, 1, height ) );
05288     break;
05289 
05290    case Up:
05291     doc = saveCellRect( QRect( left, bottom, width, 1 ) );
05292     break;
05293 
05294    case Left:
05295     doc = saveCellRect( QRect( right, top, 1, height ) );
05296     break;
05297 
05298    case Down:
05299     doc = saveCellRect( QRect( left, top, width, 1 ) );
05300     break;
05301   };
05302 
05303   // Save to buffer
05304   QBuffer buffer;
05305   buffer.open( IO_WriteOnly );
05306   QTextStream str( &buffer );
05307   str.setEncoding( QTextStream::UnicodeUTF8 );
05308   str << doc;
05309   buffer.close();
05310 
05311   int i;
05312   switch( direction )
05313   {
05314    case Right:
05315     for ( i = left + 1; i <= right; ++i )
05316     {
05317       paste( buffer.buffer(), QRect( i, top, 1, 1 ), false );
05318     }
05319     break;
05320 
05321    case Up:
05322     for ( i = bottom + 1; i >= top; --i )
05323     {
05324       paste( buffer.buffer(), QRect( left, i, 1, 1 ), false );
05325     }
05326     break;
05327 
05328    case Left:
05329     for ( i = right - 1; i >= left; --i )
05330     {
05331       paste( buffer.buffer(), QRect( i, top, 1, 1 ), false );
05332     }
05333     break;
05334 
05335    case Down:
05336     for ( i = top + 1; i <= bottom; ++i )
05337     {
05338       paste( buffer.buffer(), QRect( left, i, 1, 1 ), false );
05339     }
05340     break;
05341   }
05342 
05343   this->doc()->setModified( true );
05344 }
05345 
05346 
05347 struct DefaultSelectionWorker : public KSpreadSheet::CellWorker {
05348     DefaultSelectionWorker( ) : KSpreadSheet::CellWorker( true, false, true ) { }
05349 
05350     class KSpreadUndoAction* createUndoAction( KSpreadDoc* doc, KSpreadSheet* sheet, QRect& r ) {
05351         QString title=i18n("Default Parameters");
05352     return new KSpreadUndoCellFormat( doc, sheet, r, title );
05353     }
05354     bool testCondition( KSpreadCell* ) {
05355     return true;
05356     }
05357     void doWork( KSpreadCell* cell, bool, int, int ) {
05358     cell->defaultStyle();
05359     }
05360 };
05361 
05362 void KSpreadSheet::defaultSelection( KSpreadSelection* selectionInfo )
05363 {
05364   QRect selection(selectionInfo->selection());
05365   DefaultSelectionWorker w;
05366   SelectionType st = workOnCells( selectionInfo, w );
05367   switch ( st ) {
05368   case CompleteRows:
05369     RowFormat *rw;
05370     for ( int i = selection.top(); i <= selection.bottom(); i++ ) {
05371       rw = nonDefaultRowFormat( i );
05372       rw->defaultStyleFormat();
05373     }
05374     emit sig_updateView( this, selection );
05375     return;
05376   case CompleteColumns:
05377     ColumnFormat *cl;
05378     for ( int i = selection.left(); i <= selection.right(); i++ ) {
05379       cl=nonDefaultColumnFormat( i );
05380       cl->defaultStyleFormat();
05381     }
05382     emit sig_updateView( this, selection );
05383     return;
05384   case CellRegion:
05385       emit sig_updateView( this, selection );
05386       return;
05387   }
05388 }
05389 
05390 
05391 struct SetConditionalWorker : public KSpreadSheet::CellWorker
05392 {
05393   QValueList<KSpreadConditional> conditionList;
05394   SetConditionalWorker( QValueList<KSpreadConditional> _tmp ) :
05395     KSpreadSheet::CellWorker( ), conditionList( _tmp ) { }
05396 
05397   class KSpreadUndoAction* createUndoAction( KSpreadDoc* doc,
05398                          KSpreadSheet* sheet, QRect& r )
05399   {
05400     return new KSpreadUndoConditional( doc, sheet, r );
05401   }
05402 
05403   bool testCondition( KSpreadCell* )
05404   {
05405     return true;
05406   }
05407 
05408   void doWork( KSpreadCell* cell, bool, int, int )
05409   {
05410     if ( !cell->isObscured() ) // TODO: isObscuringForced()???
05411     {
05412       cell->setConditionList(conditionList);
05413       cell->setDisplayDirtyFlag();
05414     }
05415   }
05416 };
05417 
05418 void KSpreadSheet::setConditional( KSpreadSelection* selectionInfo,
05419                                    QValueList<KSpreadConditional> const & newConditions)
05420 {
05421   QRect selection(selectionInfo->selection());
05422   if ( !doc()->undoLocked() )
05423   {
05424     KSpreadUndoConditional * undo = new KSpreadUndoConditional( doc(), this, selection );
05425     doc()->addCommand( undo );
05426   }
05427 
05428   int l = selection.left();
05429   int r = selection.right();
05430   int t = selection.top();
05431   int b = selection.bottom();
05432 
05433   KSpreadCell * cell;
05434   KSpreadStyle * s = doc()->styleManager()->defaultStyle();
05435   for (int x = l; x <= r; ++x)
05436   {
05437     for (int y = t; y <= b; ++y)
05438     {
05439       cell = nonDefaultCell( x, y, false, s );
05440       cell->setConditionList( newConditions );
05441       cell->setDisplayDirtyFlag();
05442     }
05443   }
05444 
05445   emit sig_updateView( this, selectionInfo->selection() );
05446 }
05447 
05448 
05449 struct SetValidityWorker : public KSpreadSheet::CellWorker {
05450     KSpreadValidity tmp;
05451     SetValidityWorker( KSpreadValidity _tmp ) : KSpreadSheet::CellWorker( ), tmp( _tmp ) { }
05452 
05453     class KSpreadUndoAction* createUndoAction( KSpreadDoc* doc, KSpreadSheet* sheet, QRect& r ) {
05454     return new KSpreadUndoConditional( doc, sheet, r );
05455     }
05456     bool testCondition( KSpreadCell* ) {
05457         return true;
05458     }
05459     void doWork( KSpreadCell* cell, bool, int, int ) {
05460     if ( !cell->isObscured() ) {
05461         cell->setDisplayDirtyFlag();
05462         if ( tmp.m_allow==Allow_All )
05463         cell->removeValidity();
05464         else
05465         {
05466         KSpreadValidity *tmpValidity = cell->getValidity();
05467         tmpValidity->message=tmp.message;
05468         tmpValidity->title=tmp.title;
05469         tmpValidity->valMin=tmp.valMin;
05470         tmpValidity->valMax=tmp.valMax;
05471         tmpValidity->m_cond=tmp.m_cond;
05472         tmpValidity->m_action=tmp.m_action;
05473         tmpValidity->m_allow=tmp.m_allow;
05474         tmpValidity->timeMin=tmp.timeMin;
05475         tmpValidity->timeMax=tmp.timeMax;
05476         tmpValidity->dateMin=tmp.dateMin;
05477         tmpValidity->dateMax=tmp.dateMax;
05478                 tmpValidity->displayMessage=tmp.displayMessage;
05479                 tmpValidity->allowEmptyCell=tmp.allowEmptyCell;
05480                 tmpValidity->displayValidationInformation=tmp.displayValidationInformation;
05481                 tmpValidity->titleInfo=tmp.titleInfo;
05482                 tmpValidity->messageInfo=tmp.messageInfo;
05483                 tmpValidity->listValidity=tmp.listValidity;
05484         }
05485         cell->clearDisplayDirtyFlag();
05486     }
05487     }
05488 };
05489 
05490 void KSpreadSheet::setValidity(KSpreadSelection* selectionInfo,
05491                                KSpreadValidity tmp )
05492 {
05493     SetValidityWorker w( tmp );
05494     workOnCells( selectionInfo, w );
05495 }
05496 
05497 
05498 struct GetWordSpellingWorker : public KSpreadSheet::CellWorker {
05499     QString& listWord;
05500     GetWordSpellingWorker( QString& _listWord ) : KSpreadSheet::CellWorker( false, false, true ), listWord( _listWord ) { }
05501 
05502     class KSpreadUndoAction* createUndoAction( KSpreadDoc*, KSpreadSheet*, QRect& ) {
05503     return 0L;
05504     }
05505     bool testCondition( KSpreadCell* ) {
05506         return true;
05507     }
05508     void doWork( KSpreadCell* c, bool cellRegion, int, int ) {
05509     if ( !c->isObscured() || cellRegion /* ### ??? */ ) {
05510         if ( !c->isFormula() && !c->value().isNumber() && !c->value().asString().isEmpty() && !c->isTime()
05511          && !c->isDate()
05512          && !c->text().isEmpty())
05513         {
05514         listWord+=c->text()+'\n';
05515         }
05516     }
05517     }
05518 };
05519 
05520 QString KSpreadSheet::getWordSpelling(KSpreadSelection* selectionInfo )
05521 {
05522     QString listWord;
05523     GetWordSpellingWorker w( listWord );
05524     workOnCells( selectionInfo, w );
05525     return listWord;
05526 }
05527 
05528 
05529 struct SetWordSpellingWorker : public KSpreadSheet::CellWorker {
05530     QStringList& list;
05531     int pos;
05532     KSpreadSheet   * sheet;
05533     SetWordSpellingWorker( QStringList & _list,KSpreadSheet * s )
05534       : KSpreadSheet::CellWorker( false, false, true ), list( _list ), pos( 0 ),  sheet( s ) { }
05535 
05536     class KSpreadUndoAction* createUndoAction( KSpreadDoc* doc, KSpreadSheet* sheet, QRect& r ) {
05537     return new KSpreadUndoChangeAreaTextCell( doc, sheet, r );
05538     }
05539     bool testCondition( KSpreadCell* ) {
05540         return true;
05541     }
05542     void doWork( KSpreadCell* c, bool cellRegion, int, int )
05543     {
05544     if ( !c->isObscured() || cellRegion /* ### ??? */ ) {
05545         if ( !c->isFormula() && !c->value().isNumber() && !c->value().asString().isEmpty() && !c->isTime()
05546          && !c->isDate()
05547          && !c->text().isEmpty())
05548         {
05549 
05550 
05551         c->setCellText( list[pos] );
05552         pos++;
05553         }
05554     }
05555     }
05556 };
05557 
05558 void KSpreadSheet::setWordSpelling(KSpreadSelection* selectionInfo,
05559                                    const QString _listWord )
05560 {
05561     QStringList list = QStringList::split ( '\n', _listWord );
05562     SetWordSpellingWorker w( list,  this );
05563     workOnCells( selectionInfo, w );
05564 }
05565 
05566 static QString cellAsText( KSpreadCell* cell, unsigned int max )
05567 {
05568   QString result;
05569   if( !cell->isDefault() )
05570   {
05571     int l = max - cell->strOutText().length();
05572     if (cell->defineAlignX() == KSpreadFormat::Right )
05573     {
05574         for ( int i = 0; i < l; ++i )
05575           result += " ";
05576         result += cell->strOutText();
05577     }
05578       else if (cell->defineAlignX() == KSpreadFormat::Left )
05579       {
05580           result += " ";
05581           result += cell->strOutText();
05582           // start with "1" because we already set one space
05583           for ( int i = 1; i < l; ++i )
05584             result += " ";
05585        }
05586          else // centered
05587          {
05588            int i;
05589            int s = (int) l / 2;
05590            for ( i = 0; i < s; ++i )
05591              result += " ";
05592            result += cell->strOutText();
05593            for ( i = s; i < l; ++i )
05594              result += " ";
05595           }
05596   }
05597   else
05598   {
05599     for ( unsigned int i = 0; i < max; ++i )
05600       result += " ";
05601   }
05602 
05603   return result;
05604 }
05605 
05606 QString KSpreadSheet::copyAsText( KSpreadSelection* selectionInfo )
05607 {
05608     // Only one cell selected? => copy active cell
05609     if ( selectionInfo->singleCellSelection() )
05610     {
05611         KSpreadCell * cell = cellAt( selectionInfo->marker() );
05612         if( !cell->isDefault() )
05613           return cell->strOutText();
05614         return "";
05615     }
05616 
05617     QRect selection(selectionInfo->selection());
05618 
05619     // Find area
05620     unsigned top = selection.bottom();
05621     unsigned bottom = selection.top();
05622     unsigned left = selection.right();
05623     unsigned right = selection.left();
05624 
05625     unsigned max = 1;
05626     for( KSpreadCell *c = d->cells.firstCell();c; c = c->nextCell() )
05627     {
05628       if ( !c->isDefault() )
05629       {
05630         QPoint p( c->column(), c->row() );
05631         if ( selection.contains( p ) )
05632         {
05633           top = QMIN( top, (unsigned) c->row() );
05634           left = QMIN( left, (unsigned) c->column() );
05635           bottom = QMAX( bottom, (unsigned) c->row() );
05636           right = QMAX( right, (unsigned) c->column() );
05637 
05638           if ( c->strOutText().length() > max )
05639                  max = c->strOutText().length();
05640         }
05641       }
05642     }
05643 
05644     ++max;
05645 
05646     QString result;
05647     for ( unsigned y = top; y <= bottom; ++y)
05648     {
05649       for ( unsigned x = left; x <= right; ++x)
05650       {
05651         KSpreadCell *cell = cellAt( x, y );
05652         result += cellAsText( cell, max );
05653       }
05654       result += "\n";
05655     }
05656 
05657     return result;
05658 }
05659 
05660 void KSpreadSheet::copySelection( KSpreadSelection* selectionInfo )
05661 {
05662     QRect rct;
05663 
05664     rct = selectionInfo->selection();
05665 
05666     QDomDocument doc = saveCellRect( rct, true );
05667 
05668     // Save to buffer
05669     QBuffer buffer;
05670     buffer.open( IO_WriteOnly );
05671     QTextStream str( &buffer );
05672     str.setEncoding( QTextStream::UnicodeUTF8 );
05673     str << doc;
05674     buffer.close();
05675 
05676     KSpreadTextDrag * kd = new KSpreadTextDrag( 0L );
05677     kd->setPlain( copyAsText(selectionInfo) );
05678     kd->setKSpread( buffer.buffer() );
05679 
05680     QApplication::clipboard()->setData( kd );
05681 }
05682 
05683 void KSpreadSheet::cutSelection( KSpreadSelection* selectionInfo )
05684 {
05685     QRect rct;
05686 
05687     rct = selectionInfo->selection();
05688 
05689     QDomDocument doc = saveCellRect( rct, true, true );
05690 
05691     // Save to buffer
05692     QBuffer buffer;
05693     buffer.open( IO_WriteOnly );
05694     QTextStream str( &buffer );
05695     str.setEncoding( QTextStream::UnicodeUTF8 );
05696     str << doc;
05697     buffer.close();
05698 
05699     KSpreadTextDrag * kd = new KSpreadTextDrag( 0L );
05700     kd->setPlain( copyAsText(selectionInfo) );
05701     kd->setKSpread( buffer.buffer() );
05702 
05703     QApplication::clipboard()->setData( kd );
05704 
05705     deleteSelection( selectionInfo, true );
05706 }
05707 
05708 void KSpreadSheet::paste( const QRect &pasteArea, bool makeUndo,
05709                           PasteMode sp, Operation op, bool insert, int insertTo, bool pasteFC )
05710 {
05711     QMimeSource * mime = QApplication::clipboard()->data();
05712     if ( !mime )
05713         return;
05714 
05715     QByteArray b;
05716 
05717     if ( mime->provides( KSpreadTextDrag::selectionMimeType() ) )
05718     {
05719         b = mime->encodedData( KSpreadTextDrag::selectionMimeType() );
05720     }
05721     else if( mime->provides( "text/plain" ) )
05722     {
05723         // Note: QClipboard::text() seems to do a better job than encodedData( "text/plain" )
05724         // In particular it handles charsets (in the mimetype). Copied from KPresenter ;-)
05725     QString _text = QApplication::clipboard()->text();
05726         doc()->emitBeginOperation();
05727     pasteTextPlain( _text, pasteArea);
05728         emit sig_updateView( this );
05729         // doc()->emitEndOperation();
05730     return;
05731     }
05732     else
05733         return;
05734 
05735     // Do the actual pasting.
05736     doc()->emitBeginOperation();
05737     paste( b, pasteArea, makeUndo, sp, op, insert, insertTo, pasteFC );
05738     emit sig_updateView( this );
05739     // doc()->emitEndOperation();
05740 }
05741 
05742 
05743 void KSpreadSheet::pasteTextPlain( QString &_text, QRect pasteArea)
05744 {
05745 //  QString tmp;
05746 //  tmp= QString::fromLocal8Bit(_mime->encodedData( "text/plain" ));
05747   if( _text.isEmpty() )
05748     return;
05749 
05750   QString tmp = _text;
05751   int i;
05752   int mx   = pasteArea.left();
05753   int my   = pasteArea.top();
05754   int rows = 1;
05755   int len  = tmp.length();
05756 
05757   //count the numbers of lines in text
05758   for ( i = 0; i < len; ++i )
05759   {
05760     if ( tmp[i] == '\n' )
05761       ++rows;
05762   }
05763 
05764   KSpreadCell * cell = nonDefaultCell( mx, my );
05765   if ( rows == 1 )
05766   {
05767     if ( !doc()->undoLocked() )
05768     {
05769       KSpreadUndoSetText * undo = new KSpreadUndoSetText( doc(), this , cell->text(), mx, my, cell->formatType() );
05770       doc()->addCommand( undo );
05771     }
05772   }
05773   else
05774   {
05775       QRect rect(mx, my, mx, my + rows - 1);
05776       KSpreadUndoChangeAreaTextCell * undo = new KSpreadUndoChangeAreaTextCell( doc(), this , rect );
05777       doc()->addCommand( undo );
05778   }
05779 
05780   i = 0;
05781   QString rowtext;
05782 
05783   while ( i < rows )
05784   {
05785     int p = 0;
05786 
05787     p = tmp.find('\n');
05788 
05789     if (p < 0)
05790       p = tmp.length();
05791 
05792     rowtext = tmp.left(p);
05793 
05794     if ( !isProtected() || cell->notProtected( mx, my + i ) )
05795     {
05796       cell->setCellText( rowtext );
05797       cell->updateChart();
05798     }
05799 
05800     // next cell
05801     ++i;
05802     cell = nonDefaultCell( mx, my + i );
05803 
05804     if (!cell || p == (int) tmp.length())
05805       break;
05806 
05807     // exclude the left part and '\n'
05808     tmp = tmp.right(tmp.length() - p - 1);
05809   }
05810 
05811   if (!isLoading())
05812     refreshMergedCell();
05813 
05814   emit sig_updateView( this );
05815   emit sig_updateHBorder( this );
05816   emit sig_updateVBorder( this );
05817 }
05818 
05819 void KSpreadSheet::paste( const QByteArray & b, const QRect & pasteArea, bool makeUndo,
05820                           PasteMode sp, Operation op, bool insert, int insertTo, bool pasteFC )
05821 {
05822     kdDebug(36001) << "Parsing " << b.size() << " bytes" << endl;
05823 
05824     QBuffer buffer( b );
05825     buffer.open( IO_ReadOnly );
05826     QDomDocument doc;
05827     doc.setContent( &buffer );
05828     buffer.close();
05829 
05830     // ##### TODO: Test for parsing errors
05831 
05832     int mx = pasteArea.left();
05833     int my = pasteArea.top();
05834 
05835     loadSelection( doc, pasteArea, mx - 1, my - 1, makeUndo, sp, op, insert,
05836                    insertTo, pasteFC );
05837 }
05838 
05839 bool KSpreadSheet::loadSelection( const QDomDocument& doc, const QRect &pasteArea,
05840                                   int _xshift, int _yshift, bool makeUndo,
05841                                   PasteMode sp, Operation op, bool insert,
05842                                   int insertTo, bool pasteFC )
05843 {
05844     QDomElement e = doc.documentElement();
05845 
05846     //kdDebug(36001) << "loadSelection called. pasteArea=" << pasteArea << endl;
05847 
05848     if (!isLoading() && makeUndo)
05849         loadSelectionUndo( doc, pasteArea, _xshift, _yshift, insert, insertTo );
05850 
05851     int rowsInClpbrd    =  e.attribute( "rows" ).toInt();
05852     int columnsInClpbrd =  e.attribute( "columns" ).toInt();
05853 
05854     // find size of rectangle that we want to paste to (either clipboard size or current selection)
05855     const int pasteWidth = ( pasteArea.width() >= columnsInClpbrd
05856                              && util_isRowSelected(pasteArea) == FALSE
05857                              && e.namedItem( "rows" ).toElement().isNull() )
05858       ? pasteArea.width() : columnsInClpbrd;
05859     const int pasteHeight = ( pasteArea.height() >= rowsInClpbrd
05860                               && util_isColumnSelected(pasteArea) == FALSE
05861                               && e.namedItem( "columns" ).toElement().isNull())
05862       ? pasteArea.height() : rowsInClpbrd;
05863 
05864     /*    kdDebug() << "loadSelection: paste area has size " << pasteHeight << " rows * "
05865           << pasteWidth << " columns " << endl;
05866           kdDebug() << "loadSelection: " << rowsInClpbrd << " rows and "
05867           << columnsInClpbrd << " columns in clipboard." << endl;
05868           kdDebug() << "xshift: " << _xshift << " _yshift: " << _yshift << endl;
05869     */
05870 
05871     if ( !e.namedItem( "columns" ).toElement().isNull() && !isProtected() )
05872     {
05873         _yshift = 0;
05874 
05875         // Clear the existing columns
05876         for( int i = 1; i <= pasteWidth; ++i )
05877         {
05878             if(!insert)
05879             {
05880                 d->cells.clearColumn( _xshift + i );
05881                 d->columns.removeElement( _xshift + i );
05882             }
05883         }
05884 
05885         // Insert column formats
05886         QDomElement c = e.firstChild().toElement();
05887         for( ; !c.isNull(); c = c.nextSibling().toElement() )
05888         {
05889             if ( c.tagName() == "column" )
05890             {
05891                 ColumnFormat *cl = new ColumnFormat( this, 0 );
05892                 if ( cl->load( c, _xshift, sp, pasteFC ) )
05893                     insertColumnFormat( cl );
05894                 else
05895                     delete cl;
05896             }
05897         }
05898 
05899     }
05900 
05901     if ( !e.namedItem( "rows" ).toElement().isNull() && !isProtected() )
05902     {
05903         _xshift = 0;
05904 
05905         // Clear the existing rows
05906         for( int i = 1; i <= pasteHeight; ++i )
05907         {
05908             d->cells.clearRow( _yshift + i );
05909             d->rows.removeElement( _yshift + i );
05910         }
05911 
05912         // Insert row formats
05913         QDomElement c = e.firstChild().toElement();
05914         for( ; !c.isNull(); c = c.nextSibling().toElement() )
05915         {
05916             if ( c.tagName() == "row" )
05917             {
05918                 RowFormat *cl = new RowFormat( this, 0 );
05919                 if ( cl->load( c, _yshift, sp, pasteFC ) )
05920                     insertRowFormat( cl );
05921                 else
05922                     delete cl;
05923             }
05924         }
05925     }
05926 
05927     KSpreadCell* refreshCell = 0;
05928     KSpreadCell *cell;
05929     KSpreadCell *cellBackup = NULL;
05930     QDomElement c = e.firstChild().toElement();
05931     for( ; !c.isNull(); c = c.nextSibling().toElement() )
05932     {
05933       if ( c.tagName() == "cell" )
05934       {
05935         int row = c.attribute( "row" ).toInt() + _yshift;
05936         int col = c.attribute( "column" ).toInt() + _xshift;
05937         // tile the selection with the clipboard contents
05938 
05939         for (int roff = 0; row + roff - _yshift <= pasteHeight; roff += rowsInClpbrd)
05940         {
05941           for (int coff = 0; col + coff - _xshift <= pasteWidth; coff += columnsInClpbrd)
05942           {
05943             //kdDebug() << "loadSelection: cell at " << (col+coff) << "," << (row+roff) << " with roff,coff= "
05944             //          << roff << "," << coff << ", _xshift: " << _xshift << ", _yshift: " << _yshift << endl;
05945 
05946             cell = nonDefaultCell( col + coff, row + roff );
05947             if ( isProtected() && !cell->notProtected( col + coff, row + roff ) )
05948               continue;
05949 
05950             cellBackup = new KSpreadCell(this, cell->column(), cell->row());
05951             cellBackup->copyAll(cell);
05952 
05953             if ( !cell->load( c, _xshift + coff, _yshift + roff, sp, op, pasteFC ) )
05954             {
05955               cell->copyAll(cellBackup);
05956             }
05957             else
05958             {
05959               if( cell->isFormula() )
05960               {
05961                   cell->setCalcDirtyFlag();
05962               }
05963             }
05964 
05965             delete cellBackup;
05966 
05967 
05968 
05969             cell = cellAt( col + coff, row + roff );
05970             if( !refreshCell && cell->updateChart( false ) )
05971             {
05972               refreshCell = cell;
05973             }
05974           }
05975         }
05976       }
05977     }
05978     //refresh chart after that you paste all cells
05979 
05980     /* I don't think this is gonna work....doesn't this only update
05981        one chart -- the one which had a dependant cell update first? - John
05982 
05983        I don't have time to check on this now....
05984     */
05985     if ( refreshCell )
05986         refreshCell->updateChart();
05987     this->doc()->setModified( true );
05988 
05989     if(!isLoading())
05990         refreshMergedCell();
05991 
05992     emit sig_updateView( this );
05993     emit sig_updateHBorder( this );
05994     emit sig_updateVBorder( this );
05995 
05996     return true;
05997 }
05998 
05999 void KSpreadSheet::loadSelectionUndo( const QDomDocument & d, const QRect &loadArea,
06000                                       int _xshift, int _yshift, bool insert,
06001                                       int insertTo)
06002 {
06003     QDomElement e = d.documentElement();
06004     QDomElement c = e.firstChild().toElement();
06005     int rowsInClpbrd =  e.attribute( "rows" ).toInt();
06006     int columnsInClpbrd =  e.attribute( "columns" ).toInt();
06007     // find rect that we paste to
06008     const int pasteWidth = ( loadArea.width() >= columnsInClpbrd &&
06009                              util_isRowSelected(loadArea) == FALSE &&
06010                              e.namedItem( "rows" ).toElement().isNull() )
06011         ? loadArea.width() : columnsInClpbrd;
06012     const int pasteHeight = ( loadArea.height() >= rowsInClpbrd &&
06013                               util_isColumnSelected(loadArea) == FALSE &&
06014                               e.namedItem( "columns" ).toElement().isNull() )
06015         ? loadArea.height() : rowsInClpbrd;
06016     QRect rect;
06017     if ( !e.namedItem( "columns" ).toElement().isNull() )
06018     {
06019         if ( !doc()->undoLocked() )
06020         {
06021                 KSpreadUndoCellPaste *undo = new KSpreadUndoCellPaste( doc(), this, pasteWidth, 0, _xshift,_yshift,rect,insert );
06022                 doc()->addCommand( undo );
06023         }
06024         if(insert)
06025                  insertColumn(  _xshift+1,pasteWidth-1,false);
06026     return;
06027     }
06028 
06029     if ( !e.namedItem( "rows" ).toElement().isNull() )
06030     {
06031         if ( !doc()->undoLocked() )
06032         {
06033                 KSpreadUndoCellPaste *undo = new KSpreadUndoCellPaste( doc(), this, 0,pasteHeight, _xshift,_yshift,rect,insert );
06034                 doc()->addCommand( undo );
06035         }
06036     if(insert)
06037         insertRow(  _yshift+1,pasteHeight-1,false);
06038     return;
06039     }
06040 
06041     rect.setRect( _xshift+1, _yshift+1, pasteWidth, pasteHeight );
06042 
06043     if(!c.isNull())
06044     {
06045         if ( !doc()->undoLocked() )
06046         {
06047                 KSpreadUndoCellPaste *undo = new KSpreadUndoCellPaste( doc(), this, 0,0,_xshift,_yshift,rect,insert,insertTo );
06048                 doc()->addCommand( undo );
06049         }
06050     if(insert)
06051         {
06052         if(insertTo==-1)
06053                 shiftRow(rect,false);
06054         else if(insertTo==1)
06055                 shiftColumn(rect,false);
06056         }
06057     }
06058 }
06059 
06060 bool KSpreadSheet::testAreaPasteInsert()const
06061 {
06062    QMimeSource* mime = QApplication::clipboard()->data();
06063     if ( !mime )
06064         return false;
06065 
06066     QByteArray b;
06067 
06068     if ( mime->provides( "application/x-kspread-snippet" ) )
06069         b = mime->encodedData( "application/x-kspread-snippet" );
06070     else
06071         return false;
06072 
06073     QBuffer buffer( b );
06074     buffer.open( IO_ReadOnly );
06075     QDomDocument d;
06076     d.setContent( &buffer );
06077     buffer.close();
06078 
06079     QDomElement e = d.documentElement();
06080     if ( !e.namedItem( "columns" ).toElement().isNull() )
06081         return false;
06082 
06083     if ( !e.namedItem( "rows" ).toElement().isNull() )
06084         return false;
06085 
06086     QDomElement c = e.firstChild().toElement();
06087     for( ; !c.isNull(); c = c.nextSibling().toElement() )
06088     {
06089         if ( c.tagName() == "cell" )
06090                 return true;
06091     }
06092     return false;
06093 }
06094 
06095 void KSpreadSheet::deleteCells( const QRect& rect )
06096 {
06097     // A list of all cells we want to delete.
06098     QPtrStack<KSpreadCell> cellStack;
06099 
06100     QRect tmpRect;
06101     bool extraCell = false;
06102     if (rect.width() == 1 && rect.height() == 1 )
06103     {
06104       KSpreadCell * cell = nonDefaultCell( rect.x(), rect.y() );
06105       if (cell->isForceExtraCells())
06106       {
06107         extraCell = true;
06108         tmpRect = rect;
06109       }
06110     }
06111 
06112     int right  = rect.right();
06113     int left   = rect.left();
06114     int bottom = rect.bottom();
06115     int col;
06116     for ( int row = rect.top(); row <= bottom; ++row )
06117     {
06118       KSpreadCell * c = getFirstCellRow( row );
06119       while ( c )
06120       {
06121         col = c->column();
06122         if ( col < left )
06123         {
06124           c = getNextCellRight( left - 1, row );
06125           continue;
06126         }
06127         if ( col > right )
06128           break;
06129 
06130         if ( !c->isDefault() )
06131           cellStack.push( c );
06132 
06133         c = getNextCellRight( col, row );
06134       }
06135     }
06136 
06137     d->cells.setAutoDelete( false );
06138 
06139     // Remove the cells from the sheet
06140     while ( !cellStack.isEmpty() )
06141     {
06142       KSpreadCell * cell = cellStack.pop();
06143 
06144       d->cells.remove( cell->column(), cell->row() );
06145       cell->setCalcDirtyFlag();
06146       setRegionPaintDirty(cell->cellRect());
06147 
06148       delete cell;
06149     }
06150 
06151     d->cells.setAutoDelete( true );
06152 
06153     setLayoutDirtyFlag();
06154 
06155     // TODO: don't go through all cells here!
06156     // Since obscured cells might have been deleted we
06157     // have to reenforce it.
06158     KSpreadCell * c = d->cells.firstCell();
06159     for( ;c; c = c->nextCell() )
06160     {
06161       if ( c->isForceExtraCells() && !c->isDefault() )
06162         c->forceExtraCells( c->column(), c->row(),
06163                             c->extraXCells(), c->extraYCells() );
06164     }
06165     doc()->setModified( true );
06166 }
06167 
06168 void KSpreadSheet::deleteSelection( KSpreadSelection* selectionInfo, bool undo )
06169 {
06170     QRect r( selectionInfo->selection() );
06171 
06172     if ( undo && !doc()->undoLocked() )
06173     {
06174         KSpreadUndoDelete *undo = new KSpreadUndoDelete( doc(), this, r );
06175         doc()->addCommand( undo );
06176     }
06177 
06178     // Entire rows selected ?
06179     if ( util_isRowSelected(r) )
06180     {
06181         for( int i = r.top(); i <= r.bottom(); ++i )
06182         {
06183             d->cells.clearRow( i );
06184             d->rows.removeElement( i );
06185         }
06186 
06187         emit sig_updateVBorder( this );
06188     }
06189     // Entire columns selected ?
06190     else if ( util_isColumnSelected(r) )
06191     {
06192         for( int i = r.left(); i <= r.right(); ++i )
06193         {
06194             d->cells.clearColumn( i );
06195             d->columns.removeElement( i );
06196         }
06197 
06198         emit sig_updateHBorder( this );
06199     }
06200     else
06201     {
06202 
06203         deleteCells( r );
06204     }
06205     refreshMergedCell();
06206     emit sig_updateView( this );
06207 }
06208 
06209 void KSpreadSheet::updateView()
06210 {
06211   emit sig_updateView( this );
06212 }
06213 
06214 void KSpreadSheet::updateView( QRect const & rect )
06215 {
06216   emit sig_updateView( this, rect );
06217 }
06218 
06219 void KSpreadSheet::refreshView( const QRect & rect )
06220 {
06221   // TODO: don't go through all cells when refreshing!
06222     QRect tmp(rect);
06223     KSpreadCell * c = d->cells.firstCell();
06224     for( ;c; c = c->nextCell() )
06225     {
06226         if ( !c->isDefault() && c->row() >= rect.top() &&
06227              c->row() <= rect.bottom() && c->column() >= rect.left() &&
06228              c->column() <= rect.right() )
06229           if(c->isForceExtraCells())
06230           {
06231                 int right=QMAX(tmp.right(),c->column()+c->extraXCells());
06232                 int bottom=QMAX(tmp.bottom(),c->row()+c->extraYCells());
06233 
06234                 tmp.setRight(right);
06235                 tmp.setBottom(bottom);
06236           }
06237     }
06238     deleteCells( rect );
06239     emit sig_updateView( this, tmp );
06240 }
06241 
06242 
06243 void KSpreadSheet::changeMergedCell( int m_iCol, int m_iRow, int m_iExtraX, int m_iExtraY)
06244 {
06245    if( m_iExtraX==0 && m_iExtraY==0)
06246    {
06247      dissociateCell( QPoint( m_iCol,m_iRow));
06248      return;
06249    }
06250 
06251    QRect rect;
06252    rect.setCoords(m_iCol,m_iRow,m_iCol+m_iExtraX,m_iRow+m_iExtraY);
06253 
06254    mergeCells(rect);
06255 }
06256 
06257 void KSpreadSheet::mergeCells( const QRect &area )
06258 {
06259   // sanity check
06260   if( isProtected() )
06261     return;
06262   if( workbook()->isProtected() )
06263     return;
06264 
06265   // no span ?
06266   if( area.width() == 1 && area.height() == 1)
06267     return;
06268 
06269   QPoint topLeft = area.topLeft();
06270 
06271   KSpreadCell *cell = nonDefaultCell( topLeft );
06272   cell->forceExtraCells( topLeft.x(), topLeft.y(),
06273                          area.width() - 1, area.height() - 1);
06274 
06275   if ( getAutoCalc() )
06276     recalc();
06277 
06278   emit sig_updateView( this, area );
06279 }
06280 
06281 void KSpreadSheet::dissociateCell( const QPoint &cellRef )
06282 {
06283   QPoint marker(cellRef);
06284   KSpreadCell *cell = nonDefaultCell( marker );
06285   if(!cell->isForceExtraCells())
06286     return;
06287 
06288   int x = cell->extraXCells() + 1;
06289   if( x == 0 )
06290     x = 1;
06291   int y = cell->extraYCells() + 1;
06292   if( y == 0 )
06293     y = 1;
06294 
06295   cell->forceExtraCells( marker.x() ,marker.y(), 0, 0 );
06296   QRect selection( marker.x() - 1, marker.y() - 1, x + 2, y + 2 );
06297   refreshMergedCell();
06298   emit sig_updateView( this, selection );
06299 }
06300 
06301 bool KSpreadSheet::testListChoose(KSpreadSelection* selectionInfo)
06302 {
06303    QRect selection( selectionInfo->selection() );
06304    QPoint marker( selectionInfo->marker() );
06305 
06306    KSpreadCell *cell = cellAt( marker.x(), marker.y() );
06307    QString tmp=cell->text();
06308 
06309    KSpreadCell* c = firstCell();
06310    bool different=false;
06311    int col;
06312    for( ;c; c = c->nextCell() )
06313      {
06314        col = c->column();
06315        if ( selection.left() <= col && selection.right() >= col &&
06316             !c->isObscuringForced() &&
06317             !(col==marker.x() && c->row()==marker.y()))
06318      {
06319        if(!c->isFormula() && !c->value().isNumber() && !c->value().asString().isEmpty()
06320           && !c->isTime() &&!c->isDate() )
06321          {
06322                  if(c->text()!=tmp)
06323                      different=true;
06324          }
06325 
06326      }
06327      }
06328    return different;
06329 }
06330 
06331 
06332 
06333 
06334 QDomDocument KSpreadSheet::saveCellRect( const QRect &_rect, bool copy, bool era )
06335 {
06336     QDomDocument dd( "spreadsheet-snippet" );
06337     dd.appendChild( dd.createProcessingInstruction( "xml", "version=\"1.0\" encoding=\"UTF-8\"" ) );
06338     QDomElement spread = dd.createElement( "spreadsheet-snippet" );
06339     spread.setAttribute( "rows", _rect.bottom() - _rect.top() + 1 );
06340     spread.setAttribute( "columns", _rect.right() - _rect.left() + 1 );
06341     dd.appendChild( spread );
06342 
06343     //
06344     // Entire rows selected ?
06345     //
06346     if ( util_isRowSelected( _rect ) )
06347     {
06348         QDomElement rows = dd.createElement("rows");
06349         rows.setAttribute( "count", _rect.bottom() - _rect.top() + 1 );
06350         spread.appendChild( rows );
06351 
06352         // Save all cells.
06353         KSpreadCell* c = d->cells.firstCell();
06354         for( ;c; c = c->nextCell() )
06355         {
06356             if ( !c->isDefault()&&!c->isObscuringForced() )
06357             {
06358                 QPoint p( c->column(), c->row() );
06359                 if ( _rect.contains( p ) )
06360                     spread.appendChild( c->save( dd, 0, _rect.top() - 1, copy, copy, era ) );
06361             }
06362         }
06363 
06364         // ##### Inefficient
06365         // Save the row formats if there are any
06366         RowFormat* lay;
06367         for( int y = _rect.top(); y <= _rect.bottom(); ++y )
06368         {
06369             lay = rowFormat( y );
06370             if ( lay && !lay->isDefault() )
06371             {
06372                 QDomElement e = lay->save( dd, _rect.top() - 1, copy );
06373                 if ( !e.isNull() )
06374                     spread.appendChild( e );
06375             }
06376         }
06377 
06378         return dd;
06379     }
06380 
06381     //
06382     // Entire columns selected ?
06383     //
06384     if ( util_isColumnSelected( _rect ) )
06385     {
06386         QDomElement columns = dd.createElement("columns");
06387         columns.setAttribute( "count", _rect.right() - _rect.left() + 1 );
06388         spread.appendChild( columns );
06389 
06390         // Save all cells.
06391         KSpreadCell* c = d->cells.firstCell();
06392         for( ;c; c = c->nextCell() )
06393         {
06394             if ( !c->isDefault()&&!c->isObscuringForced())
06395             {
06396                 QPoint p( c->column(), c->row() );
06397                 if ( _rect.contains( p ) )
06398                     spread.appendChild( c->save( dd, _rect.left() - 1, 0, copy, copy, era ) );
06399             }
06400         }
06401 
06402         // ##### Inefficient
06403         // Save the column formats if there are any
06404         ColumnFormat* lay;
06405         for( int x = _rect.left(); x <= _rect.right(); ++x )
06406         {
06407             lay = columnFormat( x );
06408             if ( lay && !lay->isDefault() )
06409             {
06410                 QDomElement e = lay->save( dd, _rect.left() - 1, copy );
06411                 if ( !e.isNull() )
06412                     spread.appendChild( e );
06413             }
06414         }
06415 
06416         return dd;
06417     }
06418 
06419     // Save all cells.
06420     //store all cell
06421     //when they don't exist we created them
06422     //because it's necessary when there is a  format on a column/row
06423     //but I remove cell which is inserted.
06424     KSpreadCell *cell;
06425     bool insert;
06426     for (int i=_rect.left();i<=_rect.right();i++)
06427     for(int j=_rect.top();j<=_rect.bottom();j++)
06428     {
06429         insert = false;
06430         cell = cellAt( i, j );
06431         if ( cell == d->defaultCell )
06432         {
06433         cell = new KSpreadCell( this, i, j );
06434         insertCell( cell );
06435         insert=true;
06436         }
06437         spread.appendChild( cell->save( dd, _rect.left() - 1, _rect.top() - 1, true, copy, era ) );
06438         if( insert )
06439             d->cells.remove(i,j);
06440     }
06441 
06442     return dd;
06443 }
06444 
06445 QDomElement KSpreadSheet::saveXML( QDomDocument& dd )
06446 {
06447     QDomElement sheet = dd.createElement( "table" );
06448     sheet.setAttribute( "name", d->name );
06449 
06450 
06451     //Laurent: for oasis format I think that we must use style:direction...
06452     sheet.setAttribute( "layoutDirection", (d->layoutDirection == RightToLeft) ? "rtl" : "ltr" );
06453     sheet.setAttribute( "columnnumber", (int)d->showColumnNumber);
06454     sheet.setAttribute( "borders", (int)d->showPageBorders);
06455     sheet.setAttribute( "hide", (int)d->hide);
06456     sheet.setAttribute( "hidezero", (int)d->hideZero);
06457     sheet.setAttribute( "firstletterupper", (int)d->firstLetterUpper);
06458     sheet.setAttribute( "grid", (int)d->showGrid );
06459     sheet.setAttribute( "printGrid", (int)d->print->printGrid() );
06460     sheet.setAttribute( "printCommentIndicator", (int)d->print->printCommentIndicator() );
06461     sheet.setAttribute( "printFormulaIndicator", (int)d->print->printFormulaIndicator() );
06462     if ( doc()->specialOutputFlag() == KoDocument::SaveAsKOffice1dot1 /* so it's KSpread < 1.2 */)
06463       sheet.setAttribute( "formular", (int)d->showFormula); //Was named different
06464     else
06465       sheet.setAttribute( "showFormula", (int)d->showFormula);
06466     sheet.setAttribute( "showFormulaIndicator", (int)d->showFormulaIndicator);
06467     sheet.setAttribute( "lcmode", (int)d->lcMode);
06468     sheet.setAttribute( "autoCalc", (int)d->autoCalc);
06469     sheet.setAttribute( "borders1.2", 1);
06470     if ( !d->password.isNull() )
06471     {
06472       if ( d->password.size() > 0 )
06473       {
06474         QCString str = KCodecs::base64Encode( d->password );
06475         sheet.setAttribute( "protected", QString( str.data() ) );
06476       }
06477       else
06478         sheet.setAttribute( "protected", "" );
06479     }
06480 
06481     // paper parameters
06482     QDomElement paper = dd.createElement( "paper" );
06483     paper.setAttribute( "format", d->print->paperFormatString() );
06484     paper.setAttribute( "orientation", d->print->orientationString() );
06485     sheet.appendChild( paper );
06486 
06487     QDomElement borders = dd.createElement( "borders" );
06488     borders.setAttribute( "left", d->print->leftBorder() );
06489     borders.setAttribute( "top", d->print->topBorder() );
06490     borders.setAttribute( "right", d->print->rightBorder() );
06491     borders.setAttribute( "bottom", d->print->bottomBorder() );
06492     paper.appendChild( borders );
06493 
06494     QDomElement head = dd.createElement( "head" );
06495     paper.appendChild( head );
06496     if ( !d->print->headLeft().isEmpty() )
06497     {
06498       QDomElement left = dd.createElement( "left" );
06499       head.appendChild( left );
06500       left.appendChild( dd.createTextNode( d->print->headLeft() ) );
06501     }
06502     if ( !d->print->headMid().isEmpty() )
06503     {
06504       QDomElement center = dd.createElement( "center" );
06505       head.appendChild( center );
06506       center.appendChild( dd.createTextNode( d->print->headMid() ) );
06507     }
06508     if ( !d->print->headRight().isEmpty() )
06509     {
06510       QDomElement right = dd.createElement( "right" );
06511       head.appendChild( right );
06512       right.appendChild( dd.createTextNode( d->print->headRight() ) );
06513     }
06514     QDomElement foot = dd.createElement( "foot" );
06515     paper.appendChild( foot );
06516     if ( !d->print->footLeft().isEmpty() )
06517     {
06518       QDomElement left = dd.createElement( "left" );
06519       foot.appendChild( left );
06520       left.appendChild( dd.createTextNode( d->print->footLeft() ) );
06521     }
06522     if ( !d->print->footMid().isEmpty() )
06523     {
06524       QDomElement center = dd.createElement( "center" );
06525       foot.appendChild( center );
06526       center.appendChild( dd.createTextNode( d->print->footMid() ) );
06527     }
06528     if ( !d->print->footRight().isEmpty() )
06529     {
06530       QDomElement right = dd.createElement( "right" );
06531       foot.appendChild( right );
06532       right.appendChild( dd.createTextNode( d->print->footRight() ) );
06533     }
06534 
06535     // print range
06536     QDomElement printrange = dd.createElement( "printrange-rect" );
06537     QRect _printRange = d->print->printRange();
06538     int left = _printRange.left();
06539     int right = _printRange.right();
06540     int top = _printRange.top();
06541     int bottom = _printRange.bottom();
06542     //If whole rows are selected, then we store zeros, as KS_colMax may change in future
06543     if ( left == 1 && right == KS_colMax )
06544     {
06545       left = 0;
06546       right = 0;
06547     }
06548     //If whole columns are selected, then we store zeros, as KS_rowMax may change in future
06549     if ( top == 1 && bottom == KS_rowMax )
06550     {
06551       top = 0;
06552       bottom = 0;
06553     }
06554     printrange.setAttribute( "left-rect", left );
06555     printrange.setAttribute( "right-rect", right );
06556     printrange.setAttribute( "bottom-rect", bottom );
06557     printrange.setAttribute( "top-rect", top );
06558     sheet.appendChild( printrange );
06559 
06560     // Print repeat columns
06561     QDomElement printRepeatColumns = dd.createElement( "printrepeatcolumns" );
06562     printRepeatColumns.setAttribute( "left", d->print->printRepeatColumns().first );
06563     printRepeatColumns.setAttribute( "right", d->print->printRepeatColumns().second );
06564     sheet.appendChild( printRepeatColumns );
06565 
06566     // Print repeat rows
06567     QDomElement printRepeatRows = dd.createElement( "printrepeatrows" );
06568     printRepeatRows.setAttribute( "top", d->print->printRepeatRows().first );
06569     printRepeatRows.setAttribute( "bottom", d->print->printRepeatRows().second );
06570     sheet.appendChild( printRepeatRows );
06571 
06572     //Save print zoom
06573     sheet.setAttribute( "printZoom", d->print->zoom() );
06574 
06575     //Save page limits
06576     sheet.setAttribute( "printPageLimitX", d->print->pageLimitX() );
06577     sheet.setAttribute( "printPageLimitY", d->print->pageLimitY() );
06578 
06579     // Save all cells.
06580     KSpreadCell* c = d->cells.firstCell();
06581     for( ;c; c = c->nextCell() )
06582     {
06583         if ( !c->isDefault() )
06584         {
06585             QDomElement e = c->save( dd );
06586             if ( !e.isNull() )
06587                 sheet.appendChild( e );
06588         }
06589     }
06590 
06591     // Save all RowFormat objects.
06592     RowFormat* rl = d->rows.first();
06593     for( ; rl; rl = rl->next() )
06594     {
06595         if ( !rl->isDefault() )
06596         {
06597             QDomElement e = rl->save( dd );
06598             if ( e.isNull() )
06599                 return QDomElement();
06600             sheet.appendChild( e );
06601         }
06602     }
06603 
06604     // Save all ColumnFormat objects.
06605     ColumnFormat* cl = d->columns.first();
06606     for( ; cl; cl = cl->next() )
06607     {
06608         if ( !cl->isDefault() )
06609         {
06610             QDomElement e = cl->save( dd );
06611             if ( e.isNull() )
06612                 return QDomElement();
06613             sheet.appendChild( e );
06614         }
06615     }
06616 
06617     QPtrListIterator<KoDocumentChild> chl( doc()->children() );
06618     for( ; chl.current(); ++chl )
06619     {
06620        if ( ((KSpreadChild*)chl.current())->sheet() == this )
06621         {
06622             QDomElement e;
06623             KSpreadChild * child = (KSpreadChild *) chl.current();
06624 
06625             // stupid hack :-( has anybody a better solution?
06626             if ( child->inherits("ChartChild") )
06627             {
06628                 e = ((ChartChild *) child)->save( dd );
06629             }
06630             else
06631                 e = chl.current()->save( dd );
06632 
06633             if ( e.isNull() )
06634                 return QDomElement();
06635             sheet.appendChild( e );
06636         }
06637     }
06638 
06639     return sheet;
06640 }
06641 
06642 bool KSpreadSheet::isLoading()
06643 {
06644     return doc()->isLoading();
06645 }
06646 
06647 void KSpreadSheet::checkContentDirection( QString const & name )
06648 {
06649   /* set sheet's direction to RTL if sheet name is an RTL string */
06650   if ( (name.isRightToLeft()) )
06651     setLayoutDirection( RightToLeft );
06652   else
06653     setLayoutDirection( LeftToRight );
06654 
06655   emit sig_refreshView();
06656 }
06657 
06658 bool KSpreadSheet::loadSheetStyleFormat( QDomElement *style )
06659 {
06660     QString hleft, hmiddle, hright;
06661     QString fleft, fmiddle, fright;
06662     QDomNode header = KoDom::namedItemNS( *style, KoXmlNS::style, "header" );
06663 
06664     if ( !header.isNull() )
06665     {
06666         kdDebug() << "Header exists" << endl;
06667         QDomNode part = KoDom::namedItemNS( header, KoXmlNS::style, "region-left" );
06668         if ( !part.isNull() )
06669         {
06670             hleft = getPart( part );
06671             kdDebug() << "Header left: " << hleft << endl;
06672         }
06673         else
06674             kdDebug() << "Style:region:left doesn't exist!" << endl;
06675         part = KoDom::namedItemNS( header, KoXmlNS::style, "region-center" );
06676         if ( !part.isNull() )
06677         {
06678             hmiddle = getPart( part );
06679             kdDebug() << "Header middle: " << hmiddle << endl;
06680         }
06681         part = KoDom::namedItemNS( header, KoXmlNS::style, "region-right" );
06682         if ( !part.isNull() )
06683         {
06684             hright = getPart( part );
06685             kdDebug() << "Header right: " << hright << endl;
06686         }
06687     }
06688     //TODO implement it under kspread
06689     QDomNode headerleft = KoDom::namedItemNS( *style, KoXmlNS::style, "header-left" );
06690     if ( !headerleft.isNull() )
06691     {
06692         QDomElement e = headerleft.toElement();
06693         if ( e.hasAttributeNS( KoXmlNS::style, "display" ) )
06694             kdDebug()<<"header.hasAttribute( style:display ) :"<<e.hasAttributeNS( KoXmlNS::style, "display" )<<endl;
06695         else
06696             kdDebug()<<"header left doesn't has attribute  style:display  \n";
06697     }
06698     //TODO implement it under kspread
06699     QDomNode footerleft = KoDom::namedItemNS( *style, KoXmlNS::style, "footer-left" );
06700     if ( !footerleft.isNull() )
06701     {
06702         QDomElement e = footerleft.toElement();
06703         if ( e.hasAttributeNS( KoXmlNS::style, "display" ) )
06704             kdDebug()<<"footer.hasAttribute( style:display ) :"<<e.hasAttributeNS( KoXmlNS::style, "display" )<<endl;
06705         else
06706             kdDebug()<<"footer left doesn't has attribute  style:display  \n";
06707     }
06708 
06709     QDomNode footer = KoDom::namedItemNS( *style, KoXmlNS::style, "footer" );
06710 
06711     if ( !footer.isNull() )
06712     {
06713         QDomNode part = KoDom::namedItemNS( footer, KoXmlNS::style, "region-left" );
06714         if ( !part.isNull() )
06715         {
06716             fleft = getPart( part );
06717             kdDebug() << "Footer left: " << fleft << endl;
06718         }
06719         part = KoDom::namedItemNS( footer, KoXmlNS::style, "region-center" );
06720         if ( !part.isNull() )
06721         {
06722             fmiddle = getPart( part );
06723             kdDebug() << "Footer middle: " << fmiddle << endl;
06724         }
06725         part = KoDom::namedItemNS( footer, KoXmlNS::style, "region-right" );
06726         if ( !part.isNull() )
06727         {
06728             fright = getPart( part );
06729             kdDebug() << "Footer right: " << fright << endl;
06730         }
06731     }
06732 
06733     print()->setHeadFootLine( hleft, hmiddle, hright,
06734                               fleft, fmiddle, fright );
06735     return true;
06736 }
06737 
06738 void KSpreadSheet::replaceMacro( QString & text, const QString & old, const QString & newS )
06739 {
06740   int n = text.find( old );
06741   if ( n != -1 )
06742     text = text.replace( n, old.length(), newS );
06743 }
06744 
06745 
06746 QString KSpreadSheet::getPart( const QDomNode & part )
06747 {
06748   QString result;
06749   QDomElement e = KoDom::namedItemNS( part, KoXmlNS::text, "p" );
06750   while ( !e.isNull() )
06751   {
06752     QString text = e.text();
06753     kdDebug() << "PART: " << text << endl;
06754 
06755     QDomElement macro = KoDom::namedItemNS( e, KoXmlNS::text, "time" );
06756     if ( !macro.isNull() )
06757       replaceMacro( text, macro.text(), "<time>" );
06758 
06759     macro = KoDom::namedItemNS( e, KoXmlNS::text, "date" );
06760     if ( !macro.isNull() )
06761       replaceMacro( text, macro.text(), "<date>" );
06762 
06763     macro = KoDom::namedItemNS( e, KoXmlNS::text, "page-number" );
06764     if ( !macro.isNull() )
06765       replaceMacro( text, macro.text(), "<page>" );
06766 
06767     macro = KoDom::namedItemNS( e, KoXmlNS::text, "page-count" );
06768     if ( !macro.isNull() )
06769       replaceMacro( text, macro.text(), "<pages>" );
06770 
06771     macro = KoDom::namedItemNS( e, KoXmlNS::text, "sheet-name" );
06772     if ( !macro.isNull() )
06773       replaceMacro( text, macro.text(), "<sheet>" );
06774 
06775     macro = KoDom::namedItemNS( e, KoXmlNS::text, "title" );
06776     if ( !macro.isNull() )
06777       replaceMacro( text, macro.text(), "<name>" );
06778 
06779     macro = KoDom::namedItemNS( e, KoXmlNS::text, "file-name" );
06780     if ( !macro.isNull() )
06781       replaceMacro( text, macro.text(), "<file>" );
06782 
06783     //add support for multi line into kspread
06784     if ( !result.isEmpty() )
06785       result += '\n';
06786     result += text;
06787     e = e.nextSibling().toElement();
06788   }
06789 
06790   return result;
06791 }
06792 
06793 
06794 bool KSpreadSheet::loadOasis( const QDomElement& sheetElement, const KoOasisStyles& oasisStyles )
06795 {
06796     d->layoutDirection = LeftToRight;
06797     if ( sheetElement.hasAttributeNS( KoXmlNS::table, "style-name" ) )
06798     {
06799         QString stylename = sheetElement.attributeNS( KoXmlNS::table, "style-name", QString::null );
06800         kdDebug()<<" style of table :"<<stylename<<endl;
06801         QDomElement *style = oasisStyles.styles()[stylename];
06802         Q_ASSERT( style );
06803         kdDebug()<<" style :"<<style<<endl;
06804         if ( style )
06805         {
06806             QDomElement properties( KoDom::namedItemNS( *style, KoXmlNS::style, "table-properties" ) );
06807             if ( !properties.isNull() )
06808             {
06809                 if ( properties.hasAttributeNS( KoXmlNS::table, "display" ) )
06810                 {
06811                     bool visible = (properties.attributeNS( KoXmlNS::table, "display", QString::null ) == "true" ? true : false );
06812                     d->hide = !visible;
06813                 }
06814             }
06815             if ( style->hasAttributeNS( KoXmlNS::style, "master-page-name" ) )
06816             {
06817                 QString masterPageStyleName = style->attributeNS( KoXmlNS::style, "master-page-name", QString::null );
06818                 kdDebug()<<"style->attribute( style:master-page-name ) :"<<masterPageStyleName <<endl;
06819                 QDomElement *masterStyle = oasisStyles.masterPages()[masterPageStyleName];
06820                 kdDebug()<<"oasisStyles.styles()[masterPageStyleName] :"<<masterStyle<<endl;
06821                 if ( masterStyle )
06822                 {
06823                     loadSheetStyleFormat( masterStyle );
06824                     if ( masterStyle->hasAttributeNS( KoXmlNS::style, "page-layout-name" ) )
06825                     {
06826                         QString masterPageLayoutStyleName=masterStyle->attributeNS( KoXmlNS::style, "page-layout-name", QString::null );
06827                         kdDebug()<<"masterPageLayoutStyleName :"<<masterPageLayoutStyleName<<endl;
06828                         QDomElement *masterLayoutStyle = oasisStyles.styles()[masterPageLayoutStyleName];
06829                         kdDebug()<<"masterLayoutStyle :"<<masterLayoutStyle<<endl;
06830                         KoStyleStack styleStack;
06831                         styleStack.setTypeProperties( "page-layout" );
06832                         styleStack.push( *masterLayoutStyle );
06833                         loadOasisMasterLayoutPage( styleStack );
06834                     }
06835                 }
06836             }
06837         }
06838     }
06839 
06840     int rowIndex = 1;
06841     int indexCol = 1;
06842     QDomNode rowNode = sheetElement.firstChild();
06843     while( !rowNode.isNull() )
06844     {
06845         kdDebug()<<" rowIndex :"<<rowIndex<<" indexCol :"<<indexCol<<endl;
06846         QDomElement rowElement = rowNode.toElement();
06847         if( !rowElement.isNull() )
06848         {
06849             kdDebug()<<" KSpreadSheet::loadOasis rowElement.tagName() :"<<rowElement.localName()<<endl;
06850             if ( rowElement.namespaceURI() == KoXmlNS::table )
06851             {
06852                 if ( rowElement.localName()=="table-column" )
06853                 {
06854                     kdDebug ()<<" table-column found : index column before "<< indexCol<<endl;
06855                     loadColumnFormat( rowElement, oasisStyles, indexCol );
06856                     kdDebug ()<<" table-column found : index column after "<< indexCol<<endl;
06857                 }
06858                 else if( rowElement.localName() == "table-row" )
06859                 {
06860                     kdDebug()<<" table-row found :index row before "<<rowIndex<<endl;
06861                     loadRowFormat( rowElement, rowIndex, oasisStyles, rowNode.isNull() );
06862                     kdDebug()<<" table-row found :index row after "<<rowIndex<<endl;
06863                 }
06864             }
06865         }
06866         rowNode = rowNode.nextSibling();
06867     }
06868 
06869     if ( sheetElement.hasAttributeNS( KoXmlNS::table, "print-ranges" ) )
06870     {
06871         // e.g.: Sheet4.A1:Sheet4.E28
06872         QString range = sheetElement.attributeNS( KoXmlNS::table, "print-ranges", QString::null );
06873         KSpreadRange p( translateOpenCalcPoint( range ) );
06874         if ( sheetName() == p.sheetName )
06875             d->print->setPrintRange( p.range );
06876     }
06877 
06878 
06879     if ( sheetElement.hasAttributeNS( KoXmlNS::table, "protected" ) )
06880     {
06881         QCString passwd( "" );
06882         if ( sheetElement.hasAttributeNS( KoXmlNS::table, "protection-key" ) )
06883         {
06884             QString p = sheetElement.attributeNS( KoXmlNS::table, "protection-key", QString::null );
06885             QCString str( p.latin1() );
06886             kdDebug(30518) << "Decoding password: " << str << endl;
06887             passwd = KCodecs::base64Decode( str );
06888         }
06889         kdDebug(30518) << "Password hash: '" << passwd << "'" << endl;
06890         d->password = passwd;
06891     }
06892     return true;
06893 }
06894 
06895 
06896 void KSpreadSheet::loadOasisMasterLayoutPage( KoStyleStack &styleStack )
06897 {
06898     float left = 0.0;
06899     float right = 0.0;
06900     float top = 0.0;
06901     float bottom = 0.0;
06902     float width = 0.0;
06903     float height = 0.0;
06904     QString orientation = "Portrait";
06905     QString format;
06906 
06907     // Laurent : Why we stored layout information as Millimeter ?!!!!!
06908     // kspread used point for all other attribute
06909     // I don't understand :(
06910     if ( styleStack.hasAttributeNS( KoXmlNS::fo, "page-width" ) )
06911     {
06912         width = KoUnit::toMM(KoUnit::parseValue( styleStack.attributeNS( KoXmlNS::fo, "page-width" ) ) );
06913     }
06914     if ( styleStack.hasAttributeNS( KoXmlNS::fo, "page-height" ) )
06915     {
06916         height = KoUnit::toMM( KoUnit::parseValue( styleStack.attributeNS( KoXmlNS::fo, "page-height" ) ) );
06917     }
06918     if ( styleStack.hasAttributeNS( KoXmlNS::fo, "margin-top" ) )
06919     {
06920         top = KoUnit::toMM(KoUnit::parseValue( styleStack.attributeNS( KoXmlNS::fo, "margin-top" ) ) );
06921     }
06922     if ( styleStack.hasAttributeNS( KoXmlNS::fo, "margin-bottom" ) )
06923     {
06924         bottom = KoUnit::toMM(KoUnit::parseValue( styleStack.attributeNS( KoXmlNS::fo, "margin-bottom" ) ) );
06925     }
06926     if ( styleStack.hasAttributeNS( KoXmlNS::fo, "margin-left" ) )
06927     {
06928         left = KoUnit::toMM(KoUnit::parseValue( styleStack.attributeNS( KoXmlNS::fo, "margin-left" ) ) );
06929     }
06930     if ( styleStack.hasAttributeNS( KoXmlNS::fo, "margin-right" ) )
06931     {
06932         right = KoUnit::toMM(KoUnit::parseValue( styleStack.attributeNS( KoXmlNS::fo, "margin-right" ) ) );
06933     }
06934     if ( styleStack.hasAttributeNS( KoXmlNS::style, "writing-mode" ) )
06935     {
06936         kdDebug()<<"styleStack.hasAttribute( style:writing-mode ) :"<<styleStack.hasAttributeNS( KoXmlNS::style, "writing-mode" )<<endl;
06937         d->layoutDirection = ( styleStack.attributeNS( KoXmlNS::style, "writing-mode" )=="lr-tb" ) ? LeftToRight : RightToLeft;
06938         //TODO
06939         //<value>lr-tb</value>
06940         //<value>rl-tb</value>
06941         //<value>tb-rl</value>
06942         //<value>tb-lr</value>
06943         //<value>lr</value>
06944         //<value>rl</value>
06945         //<value>tb</value>
06946         //<value>page</value>
06947 
06948     }
06949     if ( styleStack.hasAttributeNS( KoXmlNS::style, "print-orientation" ) )
06950     {
06951         orientation = ( styleStack.attributeNS( KoXmlNS::style, "print-orientation" )=="landscape" ) ? "Landscape" : "Portrait" ;
06952     }
06953     if ( styleStack.hasAttributeNS( KoXmlNS::style, "num-format" ) )
06954     {
06955         //not implemented into kspread
06956         //These attributes specify the numbering style to use.
06957         //If a numbering style is not specified, the numbering style is inherited from
06958         //the page style. See section 6.7.8 for information on these attributes
06959         kdDebug()<<" num-format :"<<styleStack.attributeNS( KoXmlNS::style, "num-format" )<<endl;
06960 
06961     }
06962     if ( styleStack.hasAttributeNS( KoXmlNS::fo, "background-color" ) )
06963     {
06964         //todo
06965         kdDebug()<<" fo:background-color :"<<styleStack.attributeNS( KoXmlNS::fo, "background-color" )<<endl;
06966     }
06967     if ( styleStack.hasAttributeNS( KoXmlNS::style, "print" ) )
06968     {
06969         //todo parsing
06970         QString str = styleStack.attributeNS( KoXmlNS::style, "print" );
06971         kdDebug()<<" style:print :"<<str<<endl;
06972 
06973         if (str.contains( "headers" ) )
06974         {
06975             //TODO implement it into kspread
06976         }
06977         if ( str.contains( "grid" ) )
06978         {
06979             d->print->setPrintGrid( true );
06980         }
06981         if ( str.contains( "annotations" ) )
06982         {
06983             //TODO it's not implemented
06984         }
06985         if ( str.contains( "objects" ) )
06986         {
06987             //TODO it's not implemented
06988         }
06989         if ( str.contains( "charts" ) )
06990         {
06991             //TODO it's not implemented
06992         }
06993         if ( str.contains( "drawings" ) )
06994         {
06995             //TODO it's not implemented
06996         }
06997         if ( str.contains( "formulas" ) )
06998         {
06999             d->showFormula = true;
07000         }
07001         if ( str.contains( "zero-values" ) )
07002         {
07003             //TODO it's not implemented
07004         }
07005     }
07006     if ( styleStack.hasAttributeNS( KoXmlNS::style, "table-centering" ) )
07007     {
07008         QString str = styleStack.attributeNS( KoXmlNS::style, "table-centering" );
07009         //TODO not implemented into kspread
07010         kdDebug()<<" styleStack.attribute( style:table-centering ) :"<<str<<endl;
07011 #if 0
07012         if ( str == "horizontal" )
07013         {
07014         }
07015         else if ( str == "vertical" )
07016         {
07017         }
07018         else if ( str == "both" )
07019         {
07020         }
07021         else if ( str == "none" )
07022         {
07023         }
07024         else
07025             kdDebug()<<" table-centering unknown :"<<str<<endl;
07026 #endif
07027     }
07028     format = QString( "%1x%2" ).arg( width ).arg( height );
07029     kdDebug()<<" format : "<<format<<endl;
07030     d->print->setPaperLayout( left, top, right, bottom, format, orientation );
07031 
07032     kdDebug()<<" left margin :"<<left<<" right :"<<right<<" top :"<<top<<" bottom :"<<bottom<<endl;
07033 //<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"/>
07034 //          QString format = paper.attribute( "format" );
07035 //      QString orientation = paper.attribute( "orientation" );
07036 //        d->print->setPaperLayout( left, top, right, bottom, format, orientation );
07037 //      }
07038 }
07039 
07040 
07041 bool KSpreadSheet::loadColumnFormat(const QDomElement& column, const KoOasisStyles& oasisStyles, int & indexCol )
07042 {
07043     kdDebug()<<"bool KSpreadSheet::loadColumnFormat(const QDomElement& column, const KoOasisStyles& oasisStyles, unsigned int & indexCol ) index Col :"<<indexCol<<endl;
07044 
07045     bool collapsed = ( column.attributeNS( KoXmlNS::table, "visibility", QString::null ) == "collapse" );
07046     KSpreadFormat layout( this , doc()->styleManager()->defaultStyle() );
07047     int number = 1;
07048     double width   = 10;//POINT_TO_MM( colWidth ); FIXME
07049     if ( column.hasAttributeNS( KoXmlNS::table, "number-columns-repeated" ) )
07050     {
07051         bool ok = true;
07052         number = column.attributeNS( KoXmlNS::table, "number-columns-repeated", QString::null ).toInt( &ok );
07053         if ( !ok )
07054             number = 1;
07055         kdDebug() << "Repeated: " << number << endl;
07056     }
07057 
07058     KoStyleStack styleStack;
07059     styleStack.setTypeProperties("table-column"); //style for column
07060     if ( column.hasAttributeNS( KoXmlNS::table, "default-cell-style-name" ) )
07061     {
07062         //todo load cell attribute default into this column
07063         QString str = column.attributeNS( KoXmlNS::table, "default-cell-style-name", QString::null );
07064         kdDebug()<<" default-cell-style-name :"<<str<<endl;
07065         QDomElement *style = oasisStyles.styles()[str];
07066         kdDebug()<<"default column style :"<<style<<endl;
07067         if ( style )
07068         {
07069             styleStack.push( *style );
07070             layout.loadOasisStyleProperties( styleStack, oasisStyles );
07071             styleStack.pop();
07072         }
07073     }
07074 
07075     styleStack.setTypeProperties("table-column");
07076     if ( column.hasAttributeNS( KoXmlNS::table, "style-name" ) )
07077     {
07078         QString str = column.attributeNS( KoXmlNS::table, "style-name", QString::null );
07079         QDomElement *style = oasisStyles.styles()[str];
07080         styleStack.push( *style );
07081         kdDebug()<<" style column:"<<style<<"style name : "<<str<<endl;
07082     }
07083 
07084     if ( styleStack.hasAttributeNS( KoXmlNS::style, "column-width" ) )
07085     {
07086         width = KoUnit::parseValue( styleStack.attributeNS( KoXmlNS::style, "column-width" ) , -1 );
07087         kdDebug()<<" style:column-width : width :"<<width<<endl;
07088     }
07089 
07090     bool insertPageBreak = false;
07091     if ( styleStack.hasAttributeNS( KoXmlNS::fo, "break-before" ) )
07092     {
07093         QString str = styleStack.attributeNS( KoXmlNS::fo, "break-before" );
07094         if ( str == "page" )
07095         {
07096             insertPageBreak = true;
07097         }
07098         else
07099             kdDebug()<<" str :"<<str<<endl;
07100     }
07101 
07102 
07103     if ( number>30 )
07104         number = 30; //todo fixme !
07105 
07106     for ( int i = 0; i < number; ++i )
07107     {
07108         kdDebug()<<"index col :"<<indexCol<<endl;
07109         ColumnFormat * col = new ColumnFormat( this, indexCol );
07110         col->copy( layout );
07111         col->setWidth( width );
07112 
07113         // if ( insertPageBreak )
07114         //   col->setPageBreak( true )
07115 
07116         if ( collapsed )
07117             col->setHide( true );
07118 
07119         insertColumnFormat( col );
07120         ++indexCol;
07121     }
07122     kdDebug()<<" after index column !!!!!!!!!!!!!!!!!! :"<<indexCol<<endl;
07123     return true;
07124 }
07125 
07126 
07127 bool KSpreadSheet::loadRowFormat( const QDomElement& row, int &rowIndex,const KoOasisStyles& oasisStyles, bool isLast )
07128 {
07129     kdDebug()<<"KSpreadSheet::loadRowFormat( const QDomElement& row, int &rowIndex,const KoOasisStyles& oasisStyles, bool isLast )***********\n";
07130     double height = -1.0;
07131     KSpreadFormat layout( this , doc()->styleManager()->defaultStyle() );
07132     KoStyleStack styleStack;
07133     styleStack.setTypeProperties( "table-row" );
07134     int backupRow = rowIndex;
07135     if ( row.hasAttributeNS( KoXmlNS::table, "style-name" ) )
07136     {
07137         QString str = row.attributeNS( KoXmlNS::table, "style-name", QString::null );
07138         QDomElement *style = oasisStyles.styles()[str];
07139         styleStack.push( *style );
07140         kdDebug()<<" style column:"<<style<<"style name : "<<str<<endl;
07141     }
07142     layout.loadOasisStyleProperties( styleStack, oasisStyles );
07143     styleStack.setTypeProperties( "table-row" );
07144     if ( styleStack.hasAttributeNS( KoXmlNS::style, "row-height" ) )
07145     {
07146         height = KoUnit::parseValue( styleStack.attributeNS( KoXmlNS::style, "row-height" ) , -1 );
07147         kdDebug()<<" properties style:row-height : height :"<<height<<endl;
07148     }
07149 
07150     int number = 1;
07151     if ( row.hasAttributeNS( KoXmlNS::table, "number-rows-repeated" ) )
07152     {
07153         bool ok = true;
07154         int n = row.attributeNS( KoXmlNS::table, "number-rows-repeated", QString::null ).toInt( &ok );
07155         if ( ok )
07156             number = n;
07157         kdDebug() << "Row repeated: " << number << endl;
07158     }
07159     bool collapse = false;
07160     if ( row.hasAttributeNS( KoXmlNS::table, "visibility" ) )
07161     {
07162         QString visible = row.attributeNS( KoXmlNS::table, "visibility", QString::null );
07163         kdDebug()<<" row.attribute( table:visibility ) "<<visible<<endl;
07164         if ( visible == "collapse" )
07165             collapse=true;
07166         else
07167             kdDebug()<<" visible row not implemented/supported : "<<visible<<endl;
07168 
07169     }
07170     kdDebug()<<" height !!!!!!!!!!!!!!!!!!!!!!! :"<<height<<endl;
07171     //code from opencalc filter, I don't know why it's necessary.
07172     if ( isLast )
07173     {
07174         if ( number > 30 )
07175             number = 30;
07176     }
07177     else
07178     {
07179         if ( number > 256 )
07180             number = 256;
07181     }
07182 
07183     bool insertPageBreak = false;
07184     if ( styleStack.hasAttributeNS( KoXmlNS::fo, "break-before" ) )
07185     {
07186         QString str = styleStack.attributeNS( KoXmlNS::fo, "break-before" );
07187         if ( str == "page" )
07188         {
07189             insertPageBreak = true;
07190         }
07191         else
07192             kdDebug()<<" str :"<<str<<endl;
07193     }
07194 
07195     //number == number of row to be copy. But we must copy cell too.
07196     for ( int i = 0; i < number; ++i )
07197     {
07198         kdDebug()<<" create non defaultrow format :"<<rowIndex<<endl;
07199         kdDebug()<<" number :"<<number<<endl;
07200         RowFormat * rowL = nonDefaultRowFormat( rowIndex );
07201         rowL->copy( layout );
07202         kdDebug()<<"height :"<<height<<endl;
07203         if ( height != -1 )
07204         {
07205             kdDebug() << "Setting row height to " << height << endl;
07206             rowL->setHeight( height );
07207             if ( collapse )
07208                 rowL->setHide( true );
07209         }
07210         ++rowIndex;
07211     }
07212 
07213     int columnIndex = 0;
07214     QDomNode cellNode = row.firstChild();
07215     while( !cellNode.isNull() )
07216     {
07217         QDomElement cellElement = cellNode.toElement();
07218         if( !cellElement.isNull() )
07219         {
07220             ++columnIndex;
07221             kdDebug()<<"bool KSpreadSheet::loadRowFormat( const QDomElement& row, int &rowIndex,const KoOasisStyles& oasisStyles, bool isLast ) cellElement.tagName() :"<<cellElement.tagName()<<endl;
07222             if( cellElement.localName() == "table-cell" && cellElement.namespaceURI() == KoXmlNS::table)
07223             {
07224                 kdDebug()<<" create cell at row index :"<<backupRow<<endl;
07225                 KSpreadCell* cell = nonDefaultCell( columnIndex, backupRow );
07226                 cell->loadOasis( cellElement, oasisStyles );
07227                 bool haveStyle = cellElement.hasAttributeNS( KoXmlNS::table, "style-name" );
07228                 int cols = 1;
07229                 if( cellElement.hasAttributeNS( KoXmlNS::table, "number-columns-repeated" ) )
07230                 {
07231                     bool ok = false;
07232                     cols = cellElement.attributeNS( KoXmlNS::table, "number-columns-repeated", QString::null ).toInt( &ok );
07233                    if ( !haveStyle && ( cell->isEmpty() && cell->comment( columnIndex, backupRow ).isEmpty() ) )
07234                     {
07235                         //just increment it
07236                         columnIndex +=cols - 1;
07237                     }
07238                     else
07239                     {
07240                         if( ok )
07241                         {
07242                             for( int i = 0; i < cols; i++ )
07243                             {
07244                                 if( i != 0 )
07245                                 {
07246                                     ++columnIndex;
07247                                     KSpreadCell* target = nonDefaultCell( columnIndex, backupRow );
07248                                     target->copyAll( cell );
07249                                 }
07250                                     //copy contains of cell of each col
07251                                 for ( int newRow = backupRow+1; newRow < backupRow + number;++newRow )
07252                                 {
07253                                         KSpreadCell* target = nonDefaultCell( columnIndex, newRow );
07254                                         target->copyAll( cell );
07255                                 }
07256                            }
07257                         }
07258                         else
07259                         {
07260                                 //just one cell
07261                                 for ( int newRow = backupRow+1; newRow < backupRow + number;++newRow )
07262                                 {
07263                                         KSpreadCell* target = nonDefaultCell( columnIndex, newRow );
07264                                         target->copyAll( cell );
07265                                 }
07266                         }
07267                     }    
07268                 }
07269                 else
07270                 {
07271                     if ( haveStyle )
07272                     {
07273                         for ( int newRow = backupRow+1; newRow < backupRow + number;++newRow )
07274                         {
07275                                 KSpreadCell* target = nonDefaultCell( columnIndex, newRow );
07276                                 target->copyAll( cell );
07277                         }
07278                     }
07279                 }   
07280             }
07281         }
07282         cellNode = cellNode.nextSibling();
07283     }
07284 
07285     return true;
07286 }
07287 
07288 QString KSpreadSheet::translateOpenCalcPoint( const QString & str )
07289 {
07290     bool inQuote = false;
07291 
07292     int l = str.length();
07293     int colonPos = -1;
07294     QString range;
07295     bool isRange = false;
07296     // replace '.' with '!'
07297     for ( int i = 0; i < l; ++i )
07298     {
07299         if ( str[i] == '$' )
07300             continue;
07301         if ( str[i] == '\'' )
07302         {
07303             inQuote = !inQuote;
07304         }
07305         else if ( str[i] == '.' )
07306         {
07307             if ( !inQuote )
07308             {
07309                 if ( i != 0 && i != (colonPos + 1) ) // no empty sheet names
07310                     range += '!';
07311             }
07312             else
07313                 range += '.';
07314         }
07315         else if ( str[i] == ':' )
07316         {
07317             if ( !inQuote )
07318             {
07319                 isRange  = true;
07320                 colonPos = i;
07321             }
07322             range += ':';
07323         }
07324         else
07325             range += str[i];
07326     }
07327     return range;
07328 }
07329 
07330 void KSpreadSheet::maxRowCols( int & maxCols, int & maxRows )
07331 {
07332   const KSpreadCell * cell = firstCell();
07333   while ( cell )
07334   {
07335     if ( cell->column() > maxCols )
07336       maxCols = cell->column();
07337 
07338     if ( cell->row() > maxRows )
07339       maxRows = cell->row();
07340 
07341     cell = cell->nextCell();
07342   }
07343 
07344   const RowFormat * row = firstRow();
07345   while ( row )
07346   {
07347     if ( row->row() > maxRows )
07348       maxRows = row->row();
07349 
07350     row = row->next();
07351   }
07352   const ColumnFormat* col = firstCol();
07353   while ( col )
07354   {
07355     if ( col->column() > maxCols )
07356       maxCols = col->column();
07357 
07358     col = col->next();
07359   }
07360 }
07361 
07362 
07363 void KSpreadSheet::saveOasisHeaderFooter( KoXmlWriter &xmlWriter ) const
07364 {
07365     QString headerLeft = print()->headLeft();
07366     QString headerCenter= print()->headMid();
07367     QString headerRight = print()->headRight();
07368 
07369     QString footerLeft = print()->footLeft();
07370     QString footerCenter= print()->footMid();
07371     QString footerRight = print()->footRight();
07372 
07373     xmlWriter.startElement( "style:header");
07374     if ( ( !headerLeft.isEmpty() )
07375          || ( !headerCenter.isEmpty() )
07376          || ( !headerRight.isEmpty() ) )
07377     {
07378         xmlWriter.startElement( "style:region-left" );
07379         xmlWriter.startElement( "text:p" );
07380         convertPart( headerLeft, xmlWriter );
07381         xmlWriter.endElement();
07382         xmlWriter.endElement();
07383 
07384         xmlWriter.startElement( "style:region-center" );
07385         xmlWriter.startElement( "text:p" );
07386         convertPart( headerCenter, xmlWriter );
07387         xmlWriter.endElement();
07388         xmlWriter.endElement();
07389 
07390         xmlWriter.startElement( "style:region-right" );
07391         xmlWriter.startElement( "text:p" );
07392         convertPart( headerRight, xmlWriter );
07393         xmlWriter.endElement();
07394         xmlWriter.endElement();
07395     }
07396     else
07397     {
07398        xmlWriter.startElement( "text:p" );
07399 
07400        xmlWriter.startElement( "text:sheet-name" );
07401        xmlWriter.addTextNode( "???" );
07402        xmlWriter.endElement();
07403 
07404        xmlWriter.endElement();
07405     }
07406     xmlWriter.endElement();
07407 
07408 
07409     xmlWriter.startElement( "style:footer");
07410     if ( ( !footerLeft.isEmpty() )
07411          || ( !footerCenter.isEmpty() )
07412          || ( !footerRight.isEmpty() ) )
07413     {
07414         xmlWriter.startElement( "style:region-left" );
07415         xmlWriter.startElement( "text:p" );
07416         convertPart( footerLeft, xmlWriter );
07417         xmlWriter.endElement();
07418         xmlWriter.endElement(); //style:region-left
07419 
07420         xmlWriter.startElement( "style:region-center" );
07421         xmlWriter.startElement( "text:p" );
07422         convertPart( footerCenter, xmlWriter );
07423         xmlWriter.endElement();
07424         xmlWriter.endElement();
07425 
07426         xmlWriter.startElement( "style:region-right" );
07427         xmlWriter.startElement( "text:p" );
07428         convertPart( footerRight, xmlWriter );
07429         xmlWriter.endElement();
07430         xmlWriter.endElement();
07431     }
07432     else
07433     {
07434 
07435        xmlWriter.startElement( "text:p" );
07436 
07437        xmlWriter.startElement( "text:sheet-name" );
07438        xmlWriter.addTextNode( "Page " ); // ???
07439 
07440        xmlWriter.startElement( "text:page-number" );
07441        xmlWriter.addTextNode( "1" ); // ???
07442        xmlWriter.endElement();
07443 
07444 
07445        xmlWriter.endElement();
07446 
07447        xmlWriter.endElement();
07448     }
07449     xmlWriter.endElement();
07450 
07451 
07452 }
07453 
07454 void KSpreadSheet::addText( const QString & text, KoXmlWriter & writer ) const
07455 {
07456     if ( !text.isEmpty() )
07457         writer.addTextNode( text );
07458 }
07459 
07460 void KSpreadSheet::convertPart( const QString & part, KoXmlWriter & xmlWriter ) const
07461 {
07462     QString text;
07463     QString var;
07464 
07465     bool inVar = false;
07466     uint i = 0;
07467     uint l = part.length();
07468     while ( i < l )
07469     {
07470         if ( inVar || part[i] == '<' )
07471         {
07472             inVar = true;
07473             var += part[i];
07474             if ( part[i] == '>' )
07475             {
07476                 inVar = false;
07477                 if ( var == "<page>" )
07478                 {
07479                     addText( text, xmlWriter );
07480                     xmlWriter.startElement( "text:page-number" );
07481                     xmlWriter.addTextNode( "1" );
07482                     xmlWriter.endElement();
07483                 }
07484                 else if ( var == "<pages>" )
07485                 {
07486                     addText( text, xmlWriter );
07487                     xmlWriter.startElement( "text:page-count" );
07488                     xmlWriter.addTextNode( "99" );
07489                     xmlWriter.endElement();
07490                 }
07491                 else if ( var == "<date>" )
07492                 {
07493                     addText( text, xmlWriter );
07494 #if 0 //FIXME
07495                     QDomElement t = dd.createElement( "text:date" );
07496                     t.setAttribute( "text:date-value", "0-00-00" );
07497                     // todo: "style:data-style-name", "N2"
07498                     t.appendChild( dd.createTextNode( QDate::currentDate().toString() ) );
07499                     parent.appendChild( t );
07500 #endif
07501                 }
07502                 else if ( var == "<time>" )
07503                 {
07504                     addText( text, xmlWriter );
07505 
07506                     xmlWriter.startElement( "text:time" );
07507                     xmlWriter.addTextNode( QTime::currentTime().toString() );
07508                     xmlWriter.endElement();
07509                 }
07510                 else if ( var == "<file>" ) // filepath + name
07511                 {
07512                     addText( text, xmlWriter );
07513                     xmlWriter.startElement( "text:file-name" );
07514                     xmlWriter.addAttribute( "text:display", "full" );
07515                     xmlWriter.addTextNode( "???" );
07516                     xmlWriter.endElement();
07517                 }
07518                 else if ( var == "<name>" ) // filename
07519                 {
07520                     addText( text, xmlWriter );
07521 
07522                     xmlWriter.startElement( "text:title" );
07523                     xmlWriter.addTextNode( "???" );
07524                     xmlWriter.endElement();
07525                 }
07526                 else if ( var == "<author>" )
07527                 {
07528                     KSpreadDoc* sdoc = d->workbook->doc();
07529                     KoDocumentInfo       * docInfo    = sdoc->documentInfo();
07530                     KoDocumentInfoAuthor * authorPage = static_cast<KoDocumentInfoAuthor*>( docInfo->page( "author" ) );
07531 
07532                     text += authorPage->fullName();
07533 
07534                     addText( text, xmlWriter );
07535                 }
07536                 else if ( var == "<email>" )
07537                 {
07538                     KSpreadDoc* sdoc = d->workbook->doc();
07539                     KoDocumentInfo       * docInfo    = sdoc->documentInfo();
07540                     KoDocumentInfoAuthor * authorPage = static_cast<KoDocumentInfoAuthor*>( docInfo->page( "author" ) );
07541 
07542                     text += authorPage->email();
07543                     addText( text, xmlWriter );
07544 
07545                 }
07546                 else if ( var == "<org>" )
07547                 {
07548                     KSpreadDoc* sdoc = d->workbook->doc();
07549                     KoDocumentInfo       * docInfo    = sdoc->documentInfo();
07550                     KoDocumentInfoAuthor * authorPage = static_cast<KoDocumentInfoAuthor*>( docInfo->page( "author" ) );
07551 
07552                     text += authorPage->company();
07553                     addText( text, xmlWriter );
07554 
07555                 }
07556                 else if ( var == "<sheet>" )
07557                 {
07558                     addText( text, xmlWriter );
07559 
07560                     xmlWriter.startElement( "text:sheet-name" );
07561                     xmlWriter.addTextNode( "???" );
07562                     xmlWriter.endElement();
07563                 }
07564                 else
07565                 {
07566                     // no known variable:
07567                     text += var;
07568                     addText( text, xmlWriter );
07569                 }
07570 
07571                 text = "";
07572                 var  = "";
07573             }
07574         }
07575         else
07576         {
07577             text += part[i];
07578         }
07579         ++i;
07580     }
07581     if ( !text.isEmpty() || !var.isEmpty() )
07582     {
07583         //we don't have var at the end =>store it
07584         addText( text+var, xmlWriter );
07585     }
07586     kdDebug()<<" text end :"<<text<<" var :"<<var<<endl;
07587 }
07588 
07589 
07590 void KSpreadSheet::loadOasisSettings( const KoOasisSettings::NamedMap &settings )
07591 {
07592     // Find the entry in the map that applies to this sheet (by name)
07593     KoOasisSettings::Items items = settings.entry( d->name );
07594     if ( items.isNull() )
07595         return;
07596     d->hideZero = items.parseConfigItemBool( "ShowZeroValues" );
07597     d->showGrid = items.parseConfigItemBool( "ShowGrid" );
07598     d->firstLetterUpper = items.parseConfigItemBool( "FirstLetterUpper" );
07599 
07600     int cursorX = items.parseConfigItemInt( "CursorPositionX" );
07601     int cursorY = items.parseConfigItemInt( "CursorPositionY" );
07602 
07603     doc()->loadingInfo()->addMarkerSelection( this, QPoint( cursorX, cursorY ) );
07604     kdDebug()<<"d->hideZero :"<<d->hideZero<<" d->showGrid :"<<d->showGrid<<" d->firstLetterUpper :"<<d->firstLetterUpper<<" cursorX :"<<cursorX<<" cursorY :"<<cursorY<< endl;
07605 
07606     d->showFormulaIndicator = items.parseConfigItemBool("ShowFormulaIndicator" );
07607     d->showPageBorders = items.parseConfigItemBool( "ShowPageBorders" );
07608     d->lcMode = items.parseConfigItemBool( "lcmode" );
07609     d->autoCalc = items.parseConfigItemBool( "autoCalc" );
07610     d->showColumnNumber = items.parseConfigItemBool( "ShowPageBorders" );
07611     d->firstLetterUpper = items.parseConfigItemBool( "FirstLetterUpper" );
07612 }
07613 
07614 void KSpreadSheet::saveOasisSettings( KoXmlWriter &settingsWriter, const QPoint& marker ) const
07615 {
07616     //not into each page into oo spec
07617     settingsWriter.addConfigItem( "ShowZeroValues", d->hideZero );
07618     settingsWriter.addConfigItem( "ShowGrid", d->showGrid );
07619     //not define into oo spec
07620 
07621     settingsWriter.addConfigItem( "FirstLetterUpper", d->firstLetterUpper);
07622 
07623     //<config:config-item config:name="CursorPositionX" config:type="int">3</config:config-item>
07624     //<config:config-item config:name="CursorPositionY" config:type="int">34</config:config-item>
07625     settingsWriter.addConfigItem( "CursorPositionX", marker.x() );
07626     settingsWriter.addConfigItem( "CursorPositionY", marker.y() );
07627 
07628     settingsWriter.addConfigItem( "ShowFormulaIndicator", d->showFormulaIndicator );
07629     settingsWriter.addConfigItem( "ShowPageBorders",d->showPageBorders );
07630     settingsWriter.addConfigItem( "lcmode", d->lcMode );
07631     settingsWriter.addConfigItem( "autoCalc", d->autoCalc );
07632     settingsWriter.addConfigItem( "ShowPageNumber", d->showColumnNumber );
07633     settingsWriter.addConfigItem( "FirstLetterUpper", d->firstLetterUpper );
07634 }
07635 
07636 
07637 bool KSpreadSheet::saveOasis( KoXmlWriter & xmlWriter, KoGenStyles &mainStyles, KSpreadGenValidationStyles &valStyle )
07638 {
07639     int maxCols= 1;
07640     int maxRows= 1;
07641     xmlWriter.startElement( "table:table" );
07642     xmlWriter.addAttribute( "table:name", d->name );
07643     xmlWriter.addAttribute( "table:style-name", saveOasisSheetStyleName(mainStyles )  );
07644     if ( !d->password.isEmpty() )
07645     {
07646         xmlWriter.addAttribute("table:protected", "true" );
07647         QCString str = KCodecs::base64Encode( d->password );
07648         xmlWriter.addAttribute("table:protection-key", QString( str.data() ) );/* FIXME !!!!*/
07649     }
07650     QRect _printRange = d->print->printRange();
07651     if ( _printRange != ( QRect( QPoint( 1, 1 ), QPoint( KS_colMax, KS_rowMax ) ) ) )
07652     {
07653         QString range= convertRangeToRef( d->name, _printRange );
07654         kdDebug()<<" range : "<<range<<endl;
07655         xmlWriter.addAttribute( "table:print-ranges", range );
07656     }
07657 
07658     maxRowCols( maxCols, maxRows );
07659     saveOasisColRowCell( xmlWriter, mainStyles, maxCols, maxRows, valStyle );
07660     xmlWriter.endElement();
07661     return true;
07662 }
07663 
07664 void KSpreadSheet::saveOasisPrintStyleLayout( KoGenStyle &style ) const
07665 {
07666     QString printParameter;
07667     if ( d->print->printGrid() )
07668         printParameter="grid ";
07669     if ( d->showFormula )
07670         printParameter="formulas ";
07671     if ( !printParameter.isEmpty() )
07672         style.addProperty( "style:print", printParameter );
07673 }
07674 
07675 QString KSpreadSheet::saveOasisSheetStyleName( KoGenStyles &mainStyles )
07676 {
07677     KoGenStyle pageStyle( KSpreadDoc::STYLE_PAGE, "table"/*FIXME I don't know if name is sheet*/ );
07678 
07679     KoGenStyle pageMaster( KSpreadDoc::STYLE_PAGEMASTER );
07680     pageMaster.addAttribute( "style:page-layout-name", d->print->saveOasisSheetStyleLayout( mainStyles ) );
07681 
07682     QBuffer buffer;
07683     buffer.open( IO_WriteOnly );
07684     KoXmlWriter elementWriter( &buffer );  // TODO pass indentation level
07685     saveOasisHeaderFooter(elementWriter);
07686 
07687     QString elementContents = QString::fromUtf8( buffer.buffer(), buffer.buffer().size() );
07688     pageMaster.addChildElement( "headerfooter", elementContents );
07689     pageStyle.addAttribute( "style:master-page-name", mainStyles.lookup( pageMaster, "Standard" ) );
07690 
07691     pageStyle.addProperty( "table:display", !d->hide );
07692     return mainStyles.lookup( pageStyle, "ta" );
07693 }
07694 
07695 
07696 void KSpreadSheet::saveOasisColRowCell( KoXmlWriter& xmlWriter, KoGenStyles &mainStyles, int maxCols, int maxRows, KSpreadGenValidationStyles &valStyle )
07697 {
07698     int i = 1;
07699     while ( i <= maxCols )
07700     {
07701         ColumnFormat * column = columnFormat( i );
07702         KoGenStyle styleCurrent( KSpreadDoc::STYLE_COLUMN, "table-column" );
07703         styleCurrent.addPropertyPt( "style:column-width", column->dblWidth() );/*FIXME pt and not mm */
07704         styleCurrent.addProperty( "fo:break-before", "auto" );/*FIXME auto or not ?*/
07705 
07706         bool hide = column->isHide();
07707         int j = i + 1;
07708         int repeated = 1;
07709         while ( j <= maxCols )
07710         {
07711             const ColumnFormat *nextColumn = columnFormat( j );
07712             KoGenStyle nextStyle( KSpreadDoc::STYLE_COLUMN, "table-column" );
07713             nextStyle.addPropertyPt( "style:column-width", nextColumn->dblWidth() );/*FIXME pt and not mm */
07714             nextStyle.addProperty( "fo:break-before", "auto" );/*FIXME auto or not ?*/
07715 
07716             //FIXME all the time repeate == 2
07717             if ( ( nextStyle==styleCurrent ) && ( hide == nextColumn->isHide() ) )
07718                 ++repeated;
07719             else
07720                 break;
07721             ++j;
07722         }
07723         xmlWriter.startElement( "table:table-column" );
07724         xmlWriter.addAttribute( "table:style-name", mainStyles.lookup( styleCurrent, "co" ) );
07725         KoGenStyle styleColCurrent( KSpreadDoc::STYLE_CELL, "table-cell" );
07726         column->saveOasisCellStyle(styleColCurrent,mainStyles );
07727         //FIXME doesn't create format if it's default format
07728         xmlWriter.addAttribute( "table:default-cell-style-name", mainStyles.lookup( styleColCurrent, "ce" ) );//TODO fixme create style from cell
07729         if ( hide )
07730             xmlWriter.addAttribute( "table:visibility", "collapse" );
07731 
07732         if ( repeated > 1 )
07733             xmlWriter.addAttribute( "table:number-columns-repeated", repeated  );
07734         xmlWriter.endElement();
07735         i += repeated;
07736     }
07737 
07738     for ( i = 1; i <= maxRows; ++i )
07739     {
07740         const RowFormat * row = rowFormat( i );
07741         KoGenStyle rowStyle( KSpreadDoc::STYLE_ROW, "table-row" );
07742         rowStyle.addPropertyPt( "style:row-height", row->dblHeight());/*FIXME pt and not mm */
07743         rowStyle.addProperty( "fo:break-before", "auto" );/*FIXME auto or not ?*/
07744 
07745         xmlWriter.startElement( "table:table-row" );
07746         xmlWriter.addAttribute( "table:style-name", mainStyles.lookup( rowStyle, "ro" ) );
07747 
07748         if ( row->isHide() )
07749             xmlWriter.addAttribute( "table:visibility", "collapse" );
07750 
07751         saveOasisCells(  xmlWriter, mainStyles, i, maxCols, valStyle );
07752 
07753         xmlWriter.endElement();
07754     }
07755 }
07756 
07757 void KSpreadSheet::saveOasisCells(  KoXmlWriter& xmlWriter, KoGenStyles &mainStyles, int row, int maxCols, KSpreadGenValidationStyles &valStyle )
07758 {
07759     int i = 1;
07760     while ( i <= maxCols )
07761     {
07762         int repeated = 1;
07763         KSpreadCell* cell = cellAt( i, row );
07764         cell->saveOasis( xmlWriter, mainStyles, row, i,  maxCols, repeated, valStyle );
07765         i += repeated;
07766     }
07767 }
07768 
07769 bool KSpreadSheet::loadXML( const QDomElement& sheet )
07770 {
07771     bool ok = false;
07772     if ( !doc()->loadingInfo() ||  !doc()->loadingInfo()->loadTemplate() )
07773     {
07774         d->name = sheet.attribute( "name" );
07775         if ( d->name.isEmpty() )
07776         {
07777             doc()->setErrorMessage( i18n("Invalid document. Sheet name is empty.") );
07778             return false;
07779         }
07780     }
07781 
07782     bool detectDirection = true;
07783     d->layoutDirection = LeftToRight;
07784     QString layoutDir = sheet.attribute( "layoutDirection" );
07785     if( !layoutDir.isEmpty() )
07786     {
07787         if( layoutDir == "rtl" )
07788         {
07789            detectDirection = false;
07790            d->layoutDirection = RightToLeft;
07791         }
07792         else if( layoutDir == "ltr" )
07793         {
07794            detectDirection = false;
07795            d->layoutDirection = LeftToRight;
07796         }
07797     }
07798     if( detectDirection )
07799        checkContentDirection( d->name );
07800 
07801     /* older versions of KSpread allowed all sorts of characters that
07802        the parser won't actually understand.  Replace these with '_'
07803        Also, the initial character cannot be a space.
07804     */
07805     if (d->name[0] == ' ')
07806     {
07807       d->name.remove(0,1);
07808     }
07809     for (unsigned int i=0; i < d->name.length(); i++)
07810     {
07811       if ( !(d->name[i].isLetterOrNumber() ||
07812              d->name[i] == ' ' || d->name[i] == '.' ||
07813              d->name[i] == '_'))
07814         {
07815         d->name[i] = '_';
07816       }
07817     }
07818 
07819     /* make sure there are no name collisions with the altered name */
07820     QString testName;
07821     QString baseName;
07822     int nameSuffix = 0;
07823 
07824     testName = d->name;
07825     baseName = d->name;
07826 
07827     /* so we don't panic over finding ourself in the follwing test*/
07828     d->name = "";
07829     while (workbook()->findSheet(testName) != NULL)
07830     {
07831       nameSuffix++;
07832       testName = baseName + '_' + QString::number(nameSuffix);
07833     }
07834     d->name = testName;
07835 
07836     kdDebug(36001)<<"KSpreadSheet::loadXML: table name="<<d->name<<endl;
07837     setName(d->name.utf8());
07838     (dynamic_cast<KSpreadSheetIface*>(dcopObject()))->sheetNameHasChanged();
07839 
07840     if( sheet.hasAttribute( "grid" ) )
07841     {
07842         d->showGrid = (int)sheet.attribute("grid").toInt( &ok );
07843         // we just ignore 'ok' - if it didn't work, go on
07844     }
07845     if( sheet.hasAttribute( "printGrid" ) )
07846     {
07847         d->print->setPrintGrid( (int)sheet.attribute("printGrid").toInt( &ok ) );
07848         // we just ignore 'ok' - if it didn't work, go on
07849     }
07850     if( sheet.hasAttribute( "printCommentIndicator" ) )
07851     {
07852         d->print->setPrintCommentIndicator( (int)sheet.attribute("printCommentIndicator").toInt( &ok ) );
07853         // we just ignore 'ok' - if it didn't work, go on
07854     }
07855     if( sheet.hasAttribute( "printFormulaIndicator" ) )
07856     {
07857         d->print->setPrintFormulaIndicator( (int)sheet.attribute("printFormulaIndicator").toInt( &ok ) );
07858         // we just ignore 'ok' - if it didn't work, go on
07859     }
07860     if( sheet.hasAttribute( "hide" ) )
07861     {
07862         d->hide = (int)sheet.attribute("hide").toInt( &ok );
07863         // we just ignore 'ok' - if it didn't work, go on
07864     }
07865     if( sheet.hasAttribute( "showFormula" ) )
07866     {
07867         d->showFormula = (int)sheet.attribute("showFormula").toInt( &ok );
07868         // we just ignore 'ok' - if it didn't work, go on
07869     }
07870     //Compatibility with KSpread 1.1.x
07871     if( sheet.hasAttribute( "formular" ) )
07872     {
07873         d->showFormula = (int)sheet.attribute("formular").toInt( &ok );
07874         // we just ignore 'ok' - if it didn't work, go on
07875     }
07876     if( sheet.hasAttribute( "showFormulaIndicator" ) )
07877     {
07878         d->showFormulaIndicator = (int)sheet.attribute("showFormulaIndicator").toInt( &ok );
07879         // we just ignore 'ok' - if it didn't work, go on
07880     }
07881     if( sheet.hasAttribute( "borders" ) )
07882     {
07883         d->showPageBorders = (int)sheet.attribute("borders").toInt( &ok );
07884         // we just ignore 'ok' - if it didn't work, go on
07885     }
07886     if( sheet.hasAttribute( "lcmode" ) )
07887     {
07888         d->lcMode = (int)sheet.attribute("lcmode").toInt( &ok );
07889         // we just ignore 'ok' - if it didn't work, go on
07890     }
07891     if ( sheet.hasAttribute( "autoCalc" ) )
07892     {
07893         d->autoCalc = ( int )sheet.attribute( "autoCalc" ).toInt( &ok );
07894         // we just ignore 'ok' - if it didn't work, go on
07895     }
07896     if( sheet.hasAttribute( "columnnumber" ) )
07897     {
07898         d->showColumnNumber = (int)sheet.attribute("columnnumber").toInt( &ok );
07899         // we just ignore 'ok' - if it didn't work, go on
07900     }
07901     if( sheet.hasAttribute( "hidezero" ) )
07902     {
07903         d->hideZero = (int)sheet.attribute("hidezero").toInt( &ok );
07904         // we just ignore 'ok' - if it didn't work, go on
07905     }
07906     if( sheet.hasAttribute( "firstletterupper" ) )
07907     {
07908         d->firstLetterUpper = (int)sheet.attribute("firstletterupper").toInt( &ok );
07909         // we just ignore 'ok' - if it didn't work, go on
07910     }
07911 
07912     // Load the paper layout
07913     QDomElement paper = sheet.namedItem( "paper" ).toElement();
07914     if ( !paper.isNull() )
07915     {
07916       QString format = paper.attribute( "format" );
07917       QString orientation = paper.attribute( "orientation" );
07918 
07919       // <borders>
07920       QDomElement borders = paper.namedItem( "borders" ).toElement();
07921       if ( !borders.isNull() )
07922       {
07923         float left = borders.attribute( "left" ).toFloat();
07924         float right = borders.attribute( "right" ).toFloat();
07925         float top = borders.attribute( "top" ).toFloat();
07926         float bottom = borders.attribute( "bottom" ).toFloat();
07927         d->print->setPaperLayout( left, top, right, bottom, format, orientation );
07928       }
07929       QString hleft, hright, hcenter;
07930       QString fleft, fright, fcenter;
07931       // <head>
07932       QDomElement head = paper.namedItem( "head" ).toElement();
07933       if ( !head.isNull() )
07934       {
07935         QDomElement left = head.namedItem( "left" ).toElement();
07936         if ( !left.isNull() )
07937           hleft = left.text();
07938         QDomElement center = head.namedItem( "center" ).toElement();
07939         if ( !center.isNull() )
07940         hcenter = center.text();
07941         QDomElement right = head.namedItem( "right" ).toElement();
07942         if ( !right.isNull() )
07943           hright = right.text();
07944       }
07945       // <foot>
07946       QDomElement foot = paper.namedItem( "foot" ).toElement();
07947       if ( !foot.isNull() )
07948       {
07949         QDomElement left = foot.namedItem( "left" ).toElement();
07950         if ( !left.isNull() )
07951           fleft = left.text();
07952         QDomElement center = foot.namedItem( "center" ).toElement();
07953         if ( !center.isNull() )
07954           fcenter = center.text();
07955         QDomElement right = foot.namedItem( "right" ).toElement();
07956         if ( !right.isNull() )
07957           fright = right.text();
07958       }
07959       d->print->setHeadFootLine( hleft, hcenter, hright, fleft, fcenter, fright);
07960     }
07961 
07962       // load print range
07963       QDomElement printrange = sheet.namedItem( "printrange-rect" ).toElement();
07964       if ( !printrange.isNull() )
07965       {
07966         int left = printrange.attribute( "left-rect" ).toInt();
07967         int right = printrange.attribute( "right-rect" ).toInt();
07968         int bottom = printrange.attribute( "bottom-rect" ).toInt();
07969         int top = printrange.attribute( "top-rect" ).toInt();
07970         if ( left == 0 ) //whole row(s) selected
07971         {
07972           left = 1;
07973           right = KS_colMax;
07974         }
07975         if ( top == 0 ) //whole column(s) selected
07976         {
07977           top = 1;
07978           bottom = KS_rowMax;
07979         }
07980         d->print->setPrintRange( QRect( QPoint( left, top ), QPoint( right, bottom ) ) );
07981       }
07982 
07983       // load print zoom
07984       if( sheet.hasAttribute( "printZoom" ) )
07985       {
07986         double zoom = sheet.attribute( "printZoom" ).toDouble( &ok );
07987         if ( ok )
07988         {
07989           d->print->setZoom( zoom );
07990         }
07991       }
07992 
07993       // load page limits
07994       if( sheet.hasAttribute( "printPageLimitX" ) )
07995       {
07996         int pageLimit = sheet.attribute( "printPageLimitX" ).toInt( &ok );
07997         if ( ok )
07998         {
07999           d->print->setPageLimitX( pageLimit );
08000         }
08001       }
08002 
08003       // load page limits
08004       if( sheet.hasAttribute( "printPageLimitY" ) )
08005       {
08006         int pageLimit = sheet.attribute( "printPageLimitY" ).toInt( &ok );
08007         if ( ok )
08008         {
08009           d->print->setPageLimitY( pageLimit );
08010         }
08011       }
08012 
08013     // Load the cells
08014     QDomNode n = sheet.firstChild();
08015     while( !n.isNull() )
08016     {
08017         QDomElement e = n.toElement();
08018         if ( !e.isNull() && e.tagName() == "cell" )
08019         {
08020             KSpreadCell *cell = new KSpreadCell( this, 0, 0 );
08021             if ( cell->load( e, 0, 0 ) )
08022                 insertCell( cell );
08023             else
08024                 delete cell; // Allow error handling: just skip invalid cells
08025         }
08026         else if ( !e.isNull() && e.tagName() == "row" )
08027         {
08028             RowFormat *rl = new RowFormat( this, 0 );
08029             if ( rl->load( e ) )
08030                 insertRowFormat( rl );
08031             else
08032                 delete rl;
08033         }
08034         else if ( !e.isNull() && e.tagName() == "column" )
08035         {
08036             ColumnFormat *cl = new ColumnFormat( this, 0 );
08037             if ( cl->load( e ) )
08038                 insertColumnFormat( cl );
08039             else
08040                 delete cl;
08041         }
08042         else if ( !e.isNull() && e.tagName() == "object" )
08043         {
08044             KSpreadChild *ch = new KSpreadChild( doc(), this );
08045             if ( ch->load( e ) )
08046                 insertChild( ch );
08047             else
08048                 delete ch;
08049         }
08050         else if ( !e.isNull() && e.tagName() == "chart" )
08051         {
08052             ChartChild *ch = new ChartChild( doc(), this );
08053             if ( ch->load( e ) )
08054                 insertChild( ch );
08055             else
08056                 delete ch;
08057         }
08058 
08059         n = n.nextSibling();
08060     }
08061 
08062     // load print repeat columns
08063     QDomElement printrepeatcolumns = sheet.namedItem( "printrepeatcolumns" ).toElement();
08064     if ( !printrepeatcolumns.isNull() )
08065     {
08066         int left = printrepeatcolumns.attribute( "left" ).toInt();
08067         int right = printrepeatcolumns.attribute( "right" ).toInt();
08068         d->print->setPrintRepeatColumns( qMakePair( left, right ) );
08069     }
08070 
08071     // load print repeat rows
08072     QDomElement printrepeatrows = sheet.namedItem( "printrepeatrows" ).toElement();
08073     if ( !printrepeatrows.isNull() )
08074     {
08075         int top = printrepeatrows.attribute( "top" ).toInt();
08076         int bottom = printrepeatrows.attribute( "bottom" ).toInt();
08077         d->print->setPrintRepeatRows( qMakePair( top, bottom ) );
08078     }
08079 
08080     if( !sheet.hasAttribute( "borders1.2" ) )
08081     {
08082       convertObscuringBorders();
08083     }
08084 
08085     if ( sheet.hasAttribute( "protected" ) )
08086     {
08087       QString passwd = sheet.attribute( "protected" );
08088 
08089       if ( passwd.length() > 0 )
08090       {
08091         QCString str( passwd.latin1() );
08092         d->password = KCodecs::base64Decode( str );
08093       }
08094       else
08095         d->password = QCString( "" );
08096     }
08097 
08098     return true;
08099 }
08100 
08101 
08102 bool KSpreadSheet::loadChildren( KoStore* _store )
08103 {
08104     QPtrListIterator<KoDocumentChild> it( doc()->children() );
08105     for( ; it.current(); ++it )
08106     {
08107         if ( ((KSpreadChild*)it.current())->sheet() == this )
08108         {
08109             if ( !it.current()->loadDocument( _store ) )
08110                 return false;
08111         }
08112     }
08113 
08114     return true;
08115 }
08116 
08117 void KSpreadSheet::setShowPageBorders( bool b )
08118 {
08119     if ( b == d->showPageBorders )
08120         return;
08121 
08122     d->showPageBorders = b;
08123     emit sig_updateView( this );
08124 }
08125 
08126 void KSpreadSheet::addCellBinding( CellBinding *_bind )
08127 {
08128   d->cellBindings.append( _bind );
08129 
08130   doc()->setModified( true );
08131 }
08132 
08133 void KSpreadSheet::removeCellBinding( CellBinding *_bind )
08134 {
08135   d->cellBindings.removeRef( _bind );
08136 
08137   doc()->setModified( true );
08138 }
08139 
08140 KSpreadSheet* KSpreadSheet::findSheet( const QString & _name )
08141 {
08142   if ( !workbook() )
08143     return 0L;
08144 
08145   return workbook()->findSheet( _name );
08146 }
08147 
08148 // ###### Torben: Use this one instead of d->cells.insert()
08149 void KSpreadSheet::insertCell( KSpreadCell *_cell )
08150 {
08151 
08152   d->cells.insert( _cell, _cell->column(), _cell->row() );
08153 
08154   if ( d->scrollBarUpdates )
08155   {
08156     checkRangeHBorder ( _cell->column() );
08157     checkRangeVBorder ( _cell->row() );
08158   }
08159 }
08160 
08161 void KSpreadSheet::insertColumnFormat( ColumnFormat *l )
08162 {
08163   d->columns.insertElement( l, l->column() );
08164 }
08165 
08166 void KSpreadSheet::insertRowFormat( RowFormat *l )
08167 {
08168   d->rows.insertElement( l, l->row() );
08169 }
08170 
08171 void KSpreadSheet::update()
08172 {
08173   KSpreadCell* c = d->cells.firstCell();
08174   for( ;c; c = c->nextCell() )
08175   {
08176     updateCell(c, c->column(), c->row());
08177   }
08178 }
08179 
08180 void KSpreadSheet::updateCellArea( const QRect &cellArea )
08181 {
08182   if ( doc()->isLoading() || doc()->delayCalculation() || (!getAutoCalc()))
08183     return;
08184 
08185   setRegionPaintDirty( cellArea );
08186 }
08187 
08188 void KSpreadSheet::updateCell( KSpreadCell */*cell*/, int _column, int _row )
08189 {
08190   QRect cellArea(QPoint(_column, _row), QPoint(_column, _row));
08191 
08192   updateCellArea(cellArea);
08193 }
08194 
08195 void KSpreadSheet::emit_updateRow( RowFormat *_format, int _row )
08196 {
08197     if ( doc()->isLoading() )
08198         return;
08199 
08200     KSpreadCell* c = d->cells.firstCell();
08201     for( ;c; c = c->nextCell() )
08202       if ( c->row() == _row )
08203           c->setLayoutDirtyFlag( true );
08204 
08205     emit sig_updateVBorder( this );
08206     emit sig_updateView( this );
08207     emit sig_maxRow(maxRow());
08208     _format->clearDisplayDirtyFlag();
08209 }
08210 
08211 void KSpreadSheet::emit_updateColumn( ColumnFormat *_format, int _column )
08212 {
08213     if ( doc()->isLoading() )
08214         return;
08215 
08216     KSpreadCell* c = d->cells.firstCell();
08217     for( ;c; c = c->nextCell() )
08218         if ( c->column() == _column )
08219             c->setLayoutDirtyFlag( true );
08220 
08221     emit sig_updateHBorder( this );
08222     emit sig_updateView( this );
08223     emit sig_maxColumn( maxColumn() );
08224     _format->clearDisplayDirtyFlag();
08225 }
08226 
08227 void KSpreadSheet::insertChart( const QRect& _rect, KoDocumentEntry& _e, const QRect& _data )
08228 {
08229     kdDebug(36001) << "Creating document" << endl;
08230     KoDocument* dd = _e.createDoc();
08231     kdDebug(36001) << "Created" << endl;
08232     if ( !dd )
08233         // Error message is already displayed, so just return
08234         return;
08235 
08236     kdDebug(36001) << "NOW FETCHING INTERFACE" << endl;
08237 
08238     if ( !dd->initDoc(KoDocument::InitDocEmbedded) )
08239         return;
08240 
08241     ChartChild * ch = new ChartChild( doc(), this, dd, _rect );
08242     ch->setDataArea( _data );
08243     ch->update();
08244     ch->chart()->setCanChangeValue( false  );
08245     // doc()->insertChild( ch );
08246     //insertChild( ch );
08247 
08248     KoChart::WizardExtension * wiz = ch->chart()->wizardExtension();
08249 
08250     if ( wiz && wiz->show())
08251         insertChild( ch );
08252     else
08253         delete ch;
08254 }
08255 
08256 void KSpreadSheet::insertChild( const QRect& _rect, KoDocumentEntry& _e )
08257 {
08258     KoDocument* d = _e.createDoc( doc() );
08259     if ( !d )
08260     {
08261         kdDebug() << "Error inserting child!" << endl;
08262         return;
08263     }
08264     if ( !d->initDoc(KoDocument::InitDocEmbedded) )
08265         return;
08266 
08267     KSpreadChild* ch = new KSpreadChild( doc(), this, d, _rect );
08268 
08269     insertChild( ch );
08270 }
08271 
08272 void KSpreadSheet::insertChild( KSpreadChild *_child )
08273 {
08274     // m_lstChildren.append( _child );
08275     doc()->insertChild( _child );
08276 
08277     updateView( _child->boundingRect() );
08278 
08279     /* TODO - handle this */
08280 //    emit sig_polygonInvalidated( _child->framePointArray() );
08281 }
08282 
08283 void KSpreadSheet::deleteChild( KSpreadChild* child )
08284 {
08285     QPointArray polygon = child->framePointArray();
08286 
08287     emit sig_removeChild( child );
08288 
08289     child->setDeleted(true);
08290     delete child;
08291 
08293 //    emit sig_polygonInvalidated( polygon );
08294 }
08295 
08296 void KSpreadSheet::changeChildGeometry( KSpreadChild *_child, const QRect& _rect )
08297 {
08298     _child->setGeometry( _rect );
08299 
08300     emit sig_updateChildGeometry( _child );
08301 }
08302 
08303 /*
08304 QPtrListIterator<KSpreadChild> KSpreadSheet::childIterator()
08305 {
08306   return QPtrListIterator<KSpreadChild> ( m_lstChildren );
08307 }
08308 */
08309 
08310 bool KSpreadSheet::saveChildren( KoStore* _store, const QString &_path )
08311 {
08312     int i = 0;
08313 
08314     QPtrListIterator<KoDocumentChild> it( doc()->children() );
08315     for( ; it.current(); ++it )
08316     {
08317         if ( ((KSpreadChild*)it.current())->sheet() == this )
08318         {
08319             QString path = QString( "%1/%2" ).arg( _path ).arg( i++ );
08320             if ( !it.current()->document()->saveToStore( _store, path ) )
08321                 return false;
08322         }
08323     }
08324     return true;
08325 }
08326 
08327 KSpreadSheet::~KSpreadSheet()
08328 {
08329     //kdDebug()<<" KSpreadSheet::~KSpreadSheet() :"<<this<<endl;
08330     s_mapSheets->remove( d->id );
08331 
08332     //when you remove all sheet (close file)
08333     //you must reinit s_id otherwise there is not
08334     //the good name between map and sheet
08335     if( s_mapSheets->count()==0)
08336       s_id=0L;
08337 
08338     KSpreadCell* c = d->cells.firstCell();
08339     for( ; c; c = c->nextCell() )
08340         c->sheetDies();
08341 
08342     d->cells.clear(); // cells destructor needs sheet to still exist
08343 
08344     d->painter->end();
08345     delete d->painter;
08346     delete d->widget;
08347 
08348     delete d->defaultFormat;
08349     delete d->defaultCell;
08350     delete d->defaultRowFormat;
08351     delete d->defaultColumnFormat;
08352     delete d->print;
08353     delete d->dcop;
08354 
08355     delete d->dependencies;
08356 
08357     delete d;
08358 }
08359 
08360 
08361 void KSpreadSheet::checkRangeHBorder ( int _column )
08362 {
08363     if ( d->scrollBarUpdates && _column > d->maxColumn )
08364     {
08365       d->maxColumn = _column;
08366       emit sig_maxColumn( _column );
08367     }
08368 }
08369 
08370 void KSpreadSheet::checkRangeVBorder ( int _row )
08371 {
08372     if ( d->scrollBarUpdates && _row > d->maxRow )
08373     {
08374       d->maxRow = _row;
08375       emit sig_maxRow( _row );
08376     }
08377 }
08378 
08379 
08380 void KSpreadSheet::enableScrollBarUpdates( bool _enable )
08381 {
08382   d->scrollBarUpdates = _enable;
08383 }
08384 
08385 DCOPObject* KSpreadSheet::dcopObject()
08386 {
08387     if ( !d->dcop )
08388         d->dcop = new KSpreadSheetIface( this );
08389 
08390     return d->dcop;
08391 }
08392 
08393 void KSpreadSheet::hideSheet(bool _hide)
08394 {
08395     setHidden(_hide);
08396     if(_hide)
08397         emit sig_SheetHidden(this);
08398     else
08399         emit sig_SheetShown(this);
08400 }
08401 
08402 void KSpreadSheet::removeSheet()
08403 {
08404     emit sig_SheetRemoved(this);
08405 }
08406 
08407 bool KSpreadSheet::setSheetName( const QString& name, bool init, bool /*makeUndo*/ )
08408 {
08409     if ( workbook()->findSheet( name ) )
08410         return FALSE;
08411 
08412     if ( isProtected() )
08413       return false;
08414 
08415     if ( d->name == name )
08416         return TRUE;
08417 
08418     QString old_name = d->name;
08419     d->name = name;
08420 
08421     if ( init )
08422         return TRUE;
08423 
08424     QPtrListIterator<KSpreadSheet> it( workbook()->sheetList() );
08425     for ( ; it.current(); ++it )
08426         it.current()->changeCellTabName( old_name, name );
08427 
08428     doc()->changeAreaSheetName( old_name, name );
08429     emit sig_nameChanged( this, old_name );
08430 
08431     setName(name.utf8());
08432     (dynamic_cast<KSpreadSheetIface*>(dcopObject()))->sheetNameHasChanged();
08433 
08434     return TRUE;
08435 }
08436 
08437 
08438 void KSpreadSheet::updateLocale()
08439 {
08440   doc()->emitBeginOperation(true);
08441   setRegionPaintDirty(QRect(QPoint(1,1), QPoint(KS_colMax, KS_rowMax)));
08442 
08443   KSpreadCell* c = d->cells.firstCell();
08444   for( ;c; c = c->nextCell() )
08445   {
08446       QString _text = c->text();
08447       c->setDisplayText( _text );
08448   }
08449   emit sig_updateView( this );
08450   //  doc()->emitEndOperation();
08451 }
08452 
08453 KSpreadCell* KSpreadSheet::getFirstCellColumn(int col) const
08454 { return d->cells.getFirstCellColumn(col); }
08455 
08456 KSpreadCell* KSpreadSheet::getLastCellColumn(int col) const
08457 { return d->cells.getLastCellColumn(col); }
08458 
08459 KSpreadCell* KSpreadSheet::getFirstCellRow(int row) const
08460 { return d->cells.getFirstCellRow(row); }
08461 
08462 KSpreadCell* KSpreadSheet::getLastCellRow(int row) const
08463 { return d->cells.getLastCellRow(row); }
08464 
08465 KSpreadCell* KSpreadSheet::getNextCellUp(int col, int row) const
08466 { return d->cells.getNextCellUp(col, row); }
08467 
08468 KSpreadCell* KSpreadSheet::getNextCellDown(int col, int row) const
08469 { return d->cells.getNextCellDown(col, row); }
08470 
08471 KSpreadCell* KSpreadSheet::getNextCellLeft(int col, int row) const
08472 { return d->cells.getNextCellLeft(col, row); }
08473 
08474 KSpreadCell* KSpreadSheet::getNextCellRight(int col, int row) const
08475 { return d->cells.getNextCellRight(col, row); }
08476 
08477 void KSpreadSheet::convertObscuringBorders()
08478 {
08479   /* a word of explanation here:
08480      beginning with KSpread 1.2 (actually, cvs of Mar 28, 2002), border information
08481      is stored differently.  Previously, for a cell obscuring a region, the entire
08482      region's border's data would be stored in the obscuring cell.  This caused
08483      some data loss in certain situations.  After that date, each cell stores
08484      its own border data, and prints it even if it is an obscured cell (as long
08485      as that border isn't across an obscuring border).
08486      Anyway, this function is used when loading a file that was stored with the
08487      old way of borders.  All new files have the sheet attribute "borders1.2" so
08488      if that isn't in the file, all the border data will be converted here.
08489      It's a bit of a hack but I can't think of a better way and it's not *that*
08490      bad of a hack.:-)
08491   */
08492   KSpreadCell* c = d->cells.firstCell();
08493   QPen topPen, bottomPen, leftPen, rightPen;
08494   for( ;c; c = c->nextCell() )
08495   {
08496     if (c->extraXCells() > 0 || c->extraYCells() > 0)
08497     {
08498       topPen = c->topBorderPen(c->column(), c->row());
08499       leftPen = c->leftBorderPen(c->column(), c->row());
08500       rightPen = c->rightBorderPen(c->column(), c->row());
08501       bottomPen = c->bottomBorderPen(c->column(), c->row());
08502 
08503       c->setTopBorderStyle(Qt::NoPen);
08504       c->setLeftBorderStyle(Qt::NoPen);
08505       c->setRightBorderStyle(Qt::NoPen);
08506       c->setBottomBorderStyle(Qt::NoPen);
08507 
08508       for (int x = c->column(); x < c->column() + c->extraXCells(); x++)
08509       {
08510         nonDefaultCell( x, c->row() )->setTopBorderPen(topPen);
08511         nonDefaultCell( x, c->row() + c->extraYCells() )->
08512           setBottomBorderPen(bottomPen);
08513       }
08514       for (int y = c->row(); y < c->row() + c->extraYCells(); y++)
08515       {
08516         nonDefaultCell( c->column(), y )->setLeftBorderPen(leftPen);
08517         nonDefaultCell( c->column() + c->extraXCells(), y )->
08518           setRightBorderPen(rightPen);
08519       }
08520     }
08521   }
08522 }
08523 
08524 /**********************
08525  * Printout Functions *
08526  **********************/
08527 
08528 void KSpreadSheet::setRegionPaintDirty( QRect const & region )
08529 {
08530   QValueList<QRect>::iterator it  = d->paintDirtyList.begin();
08531   QValueList<QRect>::iterator end = d->paintDirtyList.end();
08532 
08533   while ( it != end )
08534   {
08535     if ( (*it).contains( region ) )
08536       return;
08537 
08538     ++it;
08539   }
08540 
08541   d->paintDirtyList.append( region );
08542 }
08543 
08544 void KSpreadSheet::clearPaintDirtyData()
08545 {
08546   d->paintDirtyList.clear();
08547 }
08548 
08549 bool KSpreadSheet::cellIsPaintDirty( QPoint const & cell )
08550 {
08551   QValueList<QRect>::iterator it;
08552   QValueList<QRect>::iterator end = d->paintDirtyList.end();
08553   bool found = false;
08554 
08555   /* Yes, this seems an inefficient method....I just want to get it working
08556      now then worry about optimization later (hash sheet?).
08557      And it might not matter -- this is going to be cleared every repaint
08558      of the screen, so it will never grow large
08559   */
08560   for ( it = d->paintDirtyList.begin(); it != end && !found; ++it )
08561   {
08562     found = (*it).contains( cell );
08563   }
08564   return found;
08565 }
08566 
08567 #ifndef NDEBUG
08568 void KSpreadSheet::printDebug()
08569 {
08570     int iMaxColumn = maxColumn();
08571     int iMaxRow = maxRow();
08572 
08573     kdDebug(36001) << "Cell | Content  | DataT | Text" << endl;
08574     KSpreadCell *cell;
08575     for ( int currentrow = 1 ; currentrow < iMaxRow ; ++currentrow )
08576     {
08577         for ( int currentcolumn = 1 ; currentcolumn < iMaxColumn ; currentcolumn++ )
08578         {
08579             cell = cellAt( currentcolumn, currentrow );
08580             if ( !cell->isDefault() && !cell->isEmpty() )
08581             {
08582                 QString cellDescr = KSpreadCell::name( currentcolumn, currentrow );
08583                 cellDescr = cellDescr.rightJustify( 4,' ' );
08584                 //QString cellDescr = "Cell ";
08585                 //cellDescr += QString::number(currentrow).rightJustify(3,'0') + ',';
08586                 //cellDescr += QString::number(currentcolumn).rightJustify(3,'0') + ' ';
08587                 cellDescr += " | ";
08588                 cellDescr += cell->value().type();
08589                 cellDescr += " | ";
08590                 cellDescr += cell->text();
08591                 if ( cell->isFormula() )
08592                     cellDescr += QString("  [result: %1]").arg( cell->value().asString() );
08593                 kdDebug(36001) << cellDescr << endl;
08594             }
08595         }
08596     }
08597 }
08598 #endif
08599 
08600 /**********************************************************
08601  *
08602  * KSpreadChild
08603  *
08604  **********************************************************/
08605 
08606 KSpreadChild::KSpreadChild( KSpreadDoc *parent, KSpreadSheet *_sheet, KoDocument* doc, const QRect& geometry )
08607   : KoDocumentChild( parent, doc, geometry )
08608 {
08609   m_pSheet = _sheet;
08610 }
08611 
08612 KSpreadChild::KSpreadChild( KSpreadDoc *parent, KSpreadSheet *_sheet ) : KoDocumentChild( parent )
08613 {
08614   m_pSheet = _sheet;
08615 }
08616 
08617 
08618 KSpreadChild::~KSpreadChild()
08619 {
08620 }
08621 
08622 /**********************************************************
08623  *
08624  * ChartChild
08625  *
08626  **********************************************************/
08627 
08628 ChartChild::ChartChild( KSpreadDoc *_spread, KSpreadSheet *_sheet, KoDocument* doc, const QRect& geometry )
08629   : KSpreadChild( _spread, _sheet, doc, geometry )
08630 {
08631     m_pBinding = 0;
08632 }
08633 
08634 ChartChild::ChartChild( KSpreadDoc *_spread, KSpreadSheet *_sheet )
08635   : KSpreadChild( _spread, _sheet )
08636 {
08637     m_pBinding = 0;
08638 }
08639 
08640 ChartChild::~ChartChild()
08641 {
08642     if ( isDeleted() )
08643         delete m_pBinding;
08644 }
08645 
08646 void ChartChild::setDataArea( const QRect& _data )
08647 {
08648     if ( m_pBinding == 0L )
08649         m_pBinding = new ChartBinding( m_pSheet, _data, this );
08650     else
08651         m_pBinding->setDataArea( _data );
08652 }
08653 
08654 void ChartChild::update()
08655 {
08656     if ( m_pBinding )
08657         m_pBinding->cellChanged( 0 );
08658 }
08659 
08660 bool ChartChild::load( const QDomElement& element )
08661 {
08662     if ( !KSpreadChild::load( element ) )
08663         return false;
08664 
08665     if ( element.hasAttribute( "left-cell" ) &&
08666          element.hasAttribute( "top-cell" ) &&
08667          element.hasAttribute( "right-cell" ) &&
08668          element.hasAttribute( "bottom-cell" ) )
08669     {
08670         QRect r;
08671         r.setCoords( element.attribute( "left-cell" ).toInt(),
08672                      element.attribute( "top-cell" ).toInt(),
08673                      element.attribute( "right-cell" ).toInt(),
08674                      element.attribute( "bottom-cell" ).toInt() );
08675 
08676         setDataArea( r );
08677     }
08678 
08679     return true;
08680 }
08681 
08682 QDomElement ChartChild::save( QDomDocument& doc )
08683 {
08684     QDomElement element = KSpreadChild::save( doc );
08685     element.setTagName( "chart" );
08686 
08687     element.setAttribute( "left-cell", m_pBinding->dataArea().left() );
08688     element.setAttribute( "right-cell", m_pBinding->dataArea().right() );
08689     element.setAttribute( "top-cell", m_pBinding->dataArea().top() );
08690     element.setAttribute( "bottom-cell", m_pBinding->dataArea().bottom() );
08691 
08692     return element;
08693 }
08694 
08695 bool ChartChild::loadDocument( KoStore* _store )
08696 {
08697     bool res = KSpreadChild::loadDocument( _store );
08698     if ( !res )
08699         return res;
08700 
08701     // Did we see a cell rectangle ?
08702     if ( !m_pBinding )
08703         return true;
08704 
08705     update();
08706 
08707     chart()->setCanChangeValue( false  );
08708     return true;
08709 }
08710 
08711 KoChart::Part* ChartChild::chart()
08712 {
08713     assert( document()->inherits( "KoChart::Part" ) );
08714     return static_cast<KoChart::Part *>( document() );
08715 }
KDE Logo
This file is part of the documentation for kspread Library Version 1.4.2.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Mon Feb 13 09:43:23 2006 by doxygen 1.4.2 written by Dimitri van Heesch, © 1997-2003