summaryrefslogtreecommitdiffstats
path: root/kspread/kspread_sheet.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'kspread/kspread_sheet.cpp')
-rw-r--r--kspread/kspread_sheet.cpp8577
1 files changed, 8577 insertions, 0 deletions
diff --git a/kspread/kspread_sheet.cpp b/kspread/kspread_sheet.cpp
new file mode 100644
index 000000000..a8965b9e7
--- /dev/null
+++ b/kspread/kspread_sheet.cpp
@@ -0,0 +1,8577 @@
+/* This file is part of the KDE project
+ Copyright 1998, 1999 Torben Weis <weis@kde.org>
+ Copyright 1999- 2006 The KSpread Team
+ www.koffice.org/kspread
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+*/
+
+#include <assert.h>
+#include <ctype.h>
+#include <float.h>
+#include <math.h>
+#include <pwd.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <tqapplication.h>
+#include <tqcheckbox.h>
+#include <tqclipboard.h>
+#include <tqlabel.h>
+#include <tqlayout.h>
+#include <tqlineedit.h>
+#include <tqpicture.h>
+#include <tqregexp.h>
+#include <tqvbox.h>
+#include <tqmap.h>
+
+#include <kdebug.h>
+#include <kmdcodec.h>
+#include <kfind.h>
+#include <kfinddialog.h>
+#include <tdemessagebox.h>
+#include <kreplace.h>
+#include <kreplacedialog.h>
+#include <kprinter.h>
+#include <kurl.h>
+
+#include <koChart.h>
+#include <KoDom.h>
+#include <KoDocumentInfo.h>
+#include <KoOasisLoadingContext.h>
+#include <KoOasisSettings.h>
+#include <KoOasisStyles.h>
+#include <KoQueryTrader.h>
+#include <KoStyleStack.h>
+#include <KoUnit.h>
+#include <KoXmlNS.h>
+#include <KoXmlWriter.h>
+
+#include "commands.h"
+#include "dependencies.h"
+#include "selection.h"
+#include "ksploadinginfo.h"
+#include "ksprsavinginfo.h"
+#include "kspread_canvas.h"
+#include "kspread_cluster.h"
+#include "kspread_condition.h"
+#include "kspread_doc.h"
+#include "kspread_global.h"
+#include "kspread_locale.h"
+#include "kspread_map.h"
+#include "kspread_object.h"
+#include "kspread_sheetprint.h"
+#include "kspread_style.h"
+#include "kspread_style_manager.h"
+#include "kspread_undo.h"
+#include "kspread_util.h"
+#include "kspread_view.h"
+#include "manipulator.h"
+#include "manipulator_data.h"
+#include "KSpreadTableIface.h"
+
+#include "kspread_sheet.h"
+#include "kspread_sheet.moc"
+
+#define NO_MODIFICATION_POSSIBLE \
+do { \
+ KMessageBox::error( 0, i18n ( "You cannot change a protected sheet" ) ); return; \
+} while(0)
+
+namespace KSpread {
+
+/*****************************************************************************
+ *
+ * CellBinding
+ *
+ *****************************************************************************/
+
+CellBinding::CellBinding( Sheet *_sheet, const TQRect& _area )
+{
+ m_rctDataArea = _area;
+
+ m_pSheet = _sheet;
+ m_pSheet->addCellBinding( this );
+
+ m_bIgnoreChanges = false;
+}
+
+CellBinding::~CellBinding()
+{
+ m_pSheet->removeCellBinding( this );
+}
+
+void CellBinding::cellChanged( Cell *_cell )
+{
+ if ( m_bIgnoreChanges )
+ return;
+
+ emit changed( _cell );
+}
+
+bool CellBinding::contains( int _x, int _y )
+{
+ return m_rctDataArea.contains( TQPoint( _x, _y ) );
+}
+
+/*****************************************************************************
+ *
+ * ChartBinding
+ *
+ *****************************************************************************/
+
+ChartBinding::ChartBinding( Sheet *_sheet, const TQRect& _area, EmbeddedChart *_child )
+ : CellBinding( _sheet, _area )
+{
+ m_child = _child;
+}
+
+ChartBinding::~ChartBinding()
+{
+}
+
+void ChartBinding::cellChanged( Cell* /*changedCell*/ )
+{
+ if ( m_bIgnoreChanges )
+ return;
+
+ //Ensure display gets updated by marking all cells underneath the chart as
+ //dirty
+
+ const TQRect chartGeometry = m_child->geometry().toTQRect();
+
+ double tmp;
+ int left = sheet()->leftColumn( chartGeometry.left() , tmp );
+ int top = sheet()->topRow( chartGeometry.top() , tmp );
+ int right = sheet()->rightColumn( chartGeometry.right() );
+ int bottom = sheet()->bottomRow( chartGeometry.bottom() );
+
+ sheet()->setRegionPaintDirty( TQRect(left,top,right-left,bottom-top) );
+
+ //kdDebug(36001) << m_rctDataArea << endl;
+
+ // Get the chart and resize its data if necessary.
+ //
+ // FIXME: Only do this if he data actually changed size.
+ KoChart::Part *chart = m_child->chart();
+ chart->resizeData( m_rctDataArea.height(), m_rctDataArea.width() );
+
+ // Reset all the data, i.e. retransfer them to the chart.
+ // This is definitely not the most efficient way to do this.
+ //
+ // FIXME: Find a way to do it with just the data that changed.
+ Cell* cell;
+ for ( int row = 0; row < m_rctDataArea.height(); row++ ) {
+ for ( int col = 0; col < m_rctDataArea.width(); col++ ) {
+ cell = m_pSheet->cellAt( m_rctDataArea.left() + col,
+ m_rctDataArea.top() + row );
+ if ( cell && cell->value().isNumber() )
+ chart->setCellData( row, col, cell->value().asFloat() );
+ else if ( cell )
+ chart->setCellData( row, col, cell->value().asString() );
+ else
+ chart->setCellData( row, col, KoChart::Value() );
+ }
+ }
+ chart->analyzeHeaders( );
+
+ // ######### Kalle may be interested in that, too
+#if 0
+ Chart::Range range;
+ range.top = m_rctDataArea.top();
+ range.left = m_rctDataArea.left();
+ range.right = m_rctDataArea.right();
+ range.bottom = m_rctDataArea.bottom();
+ range.sheet = m_pSheet->name(); */
+
+ //m_child->chart()->setData( matrix );
+
+ // Force a redraw of the chart on all views
+
+ /** TODO - replace the call below with something that will repaint this chart */
+#endif
+ // sheet()->emit_polygonInvalidated( m_child->framePointArray() );
+}
+
+
+/******************************************************************/
+/* Class: TextDrag */
+/******************************************************************/
+
+
+TextDrag::TextDrag( TQWidget * dragSource, const char * name )
+ : TQTextDrag( dragSource, name )
+{
+}
+
+TextDrag::~TextDrag()
+{
+}
+
+
+TQByteArray TextDrag::encodedData( const char * mime ) const
+{
+ if ( strcmp( selectionMimeType(), mime ) == 0)
+ return m_kspread;
+ else
+ return TQTextDrag::encodedData( mime );
+}
+
+bool TextDrag::canDecode( TQMimeSource* e )
+{
+ if ( e->provides( selectionMimeType() ) )
+ return true;
+ return TQTextDrag::canDecode(e);
+}
+
+const char * TextDrag::format( int i ) const
+{
+ if ( i < 4 ) // HACK, but how to do otherwise ??
+ return TQTextDrag::format(i);
+ else if ( i == 4 )
+ return selectionMimeType();
+ else return 0;
+}
+
+const char * TextDrag::selectionMimeType()
+{
+ return "application/x-kspread-snippet";
+}
+
+/*****************************************************************************
+ *
+ * Sheet
+ *
+ *****************************************************************************/
+
+class Sheet::Private
+{
+public:
+
+ Map* workbook;
+
+ DCOPObject* dcop;
+
+ TQString name;
+ int id;
+
+ Sheet::LayoutDirection layoutDirection;
+
+ // true if sheet is hidden
+ bool hide;
+
+ // password of protected sheet
+ TQCString password;
+
+
+ bool showGrid;
+ bool showFormula;
+ bool showFormulaIndicator;
+ bool showCommentIndicator;
+ bool autoCalc;
+ bool lcMode;
+ bool showColumnNumber;
+ bool hideZero;
+ bool firstLetterUpper;
+
+ // clusters to hold objects
+ Cluster cells;
+ RowCluster rows;
+ ColumnCluster columns;
+
+ // default objects
+ Cell* defaultCell;
+ Format* defaultFormat;
+ RowFormat* defaultRowFormat;
+ ColumnFormat* defaultColumnFormat;
+
+ // hold the print object
+ SheetPrint* print;
+
+ // cells that need painting
+ Region paintDirtyList;
+
+ // to get font metrics
+ TQPainter *painter;
+ TQWidget *widget;
+
+ // List of all cell bindings. For example charts use bindings to get
+ // informed about changing cell contents.
+ TQPtrList<CellBinding> cellBindings;
+
+ // Indicates whether the sheet should paint the page breaks.
+ // Doing so costs some time, so by default it should be turned off.
+ bool showPageBorders;
+
+ // List of all embedded objects. FIXME unused ??
+ // TQPtrList<Child> m_lstChildren;
+
+ // The highest row and column ever accessed by the user.
+ int maxRow;
+ int maxColumn;
+
+ // Max range of canvas in x and ye direction.
+ // Depends on KS_colMax/KS_rowMax and the width/height of all columns/rows
+ double sizeMaxX;
+ double sizeMaxY;
+
+
+ bool scrollBarUpdates;
+
+ TQPen emptyPen;
+ TQBrush emptyBrush;
+ TQColor emptyColor;
+
+ int scrollPosX;
+ int scrollPosY;
+
+ KSpread::DependencyManager *dependencies;
+};
+
+int Sheet::s_id = 0L;
+TQIntDict<Sheet>* Sheet::s_mapSheets;
+
+Sheet* Sheet::find( int _id )
+{
+ if ( !s_mapSheets )
+ return 0L;
+
+ return (*s_mapSheets)[ _id ];
+}
+
+Sheet::Sheet (Map* map,
+ const TQString &sheetName, const char *_name )
+ : TQObject( map, _name )
+{
+ if ( s_mapSheets == 0L )
+ s_mapSheets = new TQIntDict<Sheet>;
+ d = new Private;
+
+ d->workbook = map;
+
+ d->id = s_id++;
+ s_mapSheets->insert( d->id, this );
+
+ d->layoutDirection = LeftToRight;
+
+ d->defaultFormat = new Format (this, d->workbook->doc()->styleManager()->defaultStyle());
+ d->emptyPen.setStyle( Qt::NoPen );
+ d->dcop = 0;
+ d->name = sheetName;
+
+ dcopObject();
+ d->cellBindings.setAutoDelete( false );
+
+ // m_lstChildren.setAutoDelete( true );
+
+ d->cells.setAutoDelete( true );
+ d->rows.setAutoDelete( true );
+ d->columns.setAutoDelete( true );
+
+ d->defaultCell = new Cell( this, d->workbook->doc()->styleManager()->defaultStyle(), 0, 0);
+ d->defaultRowFormat = new RowFormat( this, 0 );
+ d->defaultRowFormat->setDefault();
+ d->defaultColumnFormat = new ColumnFormat( this, 0 );
+ d->defaultColumnFormat->setDefault();
+
+ d->widget = new TQWidget();
+ d->painter = new TQPainter;
+ d->painter->begin( d->widget );
+
+ d->maxColumn = 256;
+ d->maxRow = 256;
+ d->sizeMaxX = KS_colMax * d->defaultColumnFormat->dblWidth(); // default is max cols * default width
+ d->sizeMaxY = KS_rowMax * d->defaultRowFormat->dblHeight(); // default is max rows * default height
+
+ d->scrollBarUpdates = true;
+
+ setHidden( false );
+ d->showGrid=true;
+ d->showFormula=false;
+ d->showFormulaIndicator=true;
+ d->showCommentIndicator=true;
+ d->showPageBorders = false;
+
+ d->lcMode=false;
+ d->showColumnNumber=false;
+ d->hideZero=false;
+ d->firstLetterUpper=false;
+ d->autoCalc=true;
+ // Get a unique name so that we can offer scripting
+ if ( !_name )
+ {
+ TQCString s;
+ s.sprintf("Sheet%i", s_id );
+ TQObject::setName( s.data() );
+ }
+ d->print = new SheetPrint( this );
+
+ // initialize dependencies
+ d->dependencies = new KSpread::DependencyManager (this);
+
+ // connect to named area slots
+ TQObject::connect( doc(), TQT_SIGNAL( sig_addAreaName( const TQString & ) ),
+ this, TQT_SLOT( slotAreaModified( const TQString & ) ) );
+
+ TQObject::connect( doc(), TQT_SIGNAL( sig_removeAreaName( const TQString & ) ),
+ this, TQT_SLOT( slotAreaModified( const TQString & ) ) );
+
+
+}
+
+TQString Sheet::sheetName() const
+{
+ return d->name;
+}
+
+Map* Sheet::workbook() const
+{
+ return d->workbook;
+}
+
+Doc* Sheet::doc() const
+{
+ return d->workbook->doc();
+}
+
+int Sheet::id() const
+{
+ return d->id;
+}
+
+Sheet::LayoutDirection Sheet::layoutDirection() const
+{
+ return d->layoutDirection;
+}
+
+void Sheet::setLayoutDirection( LayoutDirection dir )
+{
+ d->layoutDirection = dir;
+}
+
+bool Sheet::isRightToLeft() const
+{
+ return d->layoutDirection == RightToLeft;
+}
+
+bool Sheet::isHidden() const
+{
+ return d->hide;
+}
+
+void Sheet::setHidden( bool hidden )
+{
+ d->hide = hidden;
+}
+
+bool Sheet::getShowGrid() const
+{
+ return d->showGrid;
+}
+
+void Sheet::setShowGrid( bool _showGrid )
+{
+ d->showGrid=_showGrid;
+}
+
+bool Sheet::getShowFormula() const
+{
+ return d->showFormula;
+}
+
+void Sheet::setShowFormula( bool _showFormula )
+{
+ d->showFormula=_showFormula;
+}
+
+bool Sheet::getShowFormulaIndicator() const
+{
+ return d->showFormulaIndicator;
+}
+
+void Sheet::setShowFormulaIndicator( bool _showFormulaIndicator )
+{
+ d->showFormulaIndicator=_showFormulaIndicator;
+}
+
+bool Sheet::getShowCommentIndicator() const
+{
+ return d->showCommentIndicator;
+}
+
+void Sheet::setShowCommentIndicator(bool _indic)
+{
+ d->showCommentIndicator=_indic;
+}
+
+bool Sheet::getLcMode() const
+{
+ return d->lcMode;
+}
+
+void Sheet::setLcMode( bool _lcMode )
+{
+ d->lcMode=_lcMode;
+}
+
+bool Sheet::getAutoCalc() const
+{
+ return d->autoCalc;
+}
+
+void Sheet::setAutoCalc( bool _AutoCalc )
+{
+ //Avoid possible recalculation of dependancies if the auto calc setting hasn't changed
+ if (d->autoCalc == _AutoCalc)
+ return;
+
+ //If enabling automatic calculation, make sure that the dependencies are up-to-date
+ if (_AutoCalc == true)
+ {
+ updateAllDependencies();
+ recalc();
+ }
+
+ d->autoCalc=_AutoCalc;
+
+
+}
+
+bool Sheet::getShowColumnNumber() const
+{
+ return d->showColumnNumber;
+}
+
+void Sheet::setShowColumnNumber( bool _showColumnNumber )
+{
+ d->showColumnNumber=_showColumnNumber;
+}
+
+bool Sheet::getHideZero() const
+{
+ return d->hideZero;
+}
+
+void Sheet::setHideZero( bool _hideZero )
+{
+ d->hideZero=_hideZero;
+}
+
+bool Sheet::getFirstLetterUpper() const
+{
+ return d->firstLetterUpper;
+}
+
+void Sheet::setFirstLetterUpper( bool _firstUpper )
+{
+ d->firstLetterUpper=_firstUpper;
+}
+
+bool Sheet::isShowPageBorders() const
+{
+ return d->showPageBorders;
+}
+
+bool Sheet::isEmpty( unsigned long int x, unsigned long int y ) const
+{
+ const Cell* c = cellAt( x, y );
+ if ( !c || c->isEmpty() )
+ return true;
+
+ return false;
+}
+
+Cell* Sheet::defaultCell() const
+{
+ return d->defaultCell;
+}
+
+Format* Sheet::defaultFormat()
+{
+ return d->defaultFormat;
+}
+
+const Format* Sheet::defaultFormat() const
+{
+ return d->defaultFormat;
+}
+
+const ColumnFormat* Sheet::columnFormat( int _column ) const
+{
+ const ColumnFormat *p = d->columns.lookup( _column );
+ if ( p != 0L )
+ return p;
+
+ return d->defaultColumnFormat;
+}
+
+ColumnFormat* Sheet::columnFormat( int _column )
+{
+ ColumnFormat *p = d->columns.lookup( _column );
+ if ( p != 0L )
+ return p;
+
+ return d->defaultColumnFormat;
+}
+
+const RowFormat* Sheet::rowFormat( int _row ) const
+{
+ const RowFormat *p = d->rows.lookup( _row );
+ if ( p != 0L )
+ return p;
+
+ return d->defaultRowFormat;
+}
+
+RowFormat* Sheet::rowFormat( int _row )
+{
+ RowFormat *p = d->rows.lookup( _row );
+ if ( p != 0L )
+ return p;
+
+ return d->defaultRowFormat;
+}
+
+Value Sheet::value (int col, int row) const
+{
+ Cell *cell = d->cells.lookup (col, row);
+ if (cell)
+ return cell->value ();
+ Value empty;
+ return empty;
+}
+
+Value Sheet::valueRange (int col1, int row1,
+ int col2, int row2) const
+{
+ return d->cells.valueRange (col1, row1, col2, row2);
+}
+
+void Sheet::password( TQCString & passwd ) const
+{
+ passwd = d->password;
+}
+
+bool Sheet::isProtected() const
+{
+ return !d->password.isNull();
+}
+
+void Sheet::setProtected( TQCString const & passwd )
+{
+ d->password = passwd;
+}
+
+bool Sheet::checkPassword( TQCString const & passwd ) const
+{
+ return ( passwd == d->password );
+}
+
+SheetPrint* Sheet::print() const
+{
+ return d->print;
+}
+
+TQPainter& Sheet::painter()
+{
+ return *d->painter;
+}
+
+TQWidget* Sheet::widget()const
+{
+ return d->widget;
+}
+
+CellBinding* Sheet::firstCellBinding()
+{
+ return d->cellBindings.first();
+}
+
+CellBinding* Sheet::nextCellBinding()
+{
+ return d->cellBindings.next();
+}
+
+void Sheet::setDefaultHeight( double height )
+{
+ if ( isProtected() )
+ NO_MODIFICATION_POSSIBLE;
+
+ d->defaultRowFormat->setDblHeight( height );
+}
+
+void Sheet::setDefaultWidth( double width )
+{
+ if ( isProtected() )
+ NO_MODIFICATION_POSSIBLE;
+
+ d->defaultColumnFormat->setDblWidth( width );
+}
+
+double Sheet::sizeMaxX() const
+{
+ return d->sizeMaxX;
+}
+
+double Sheet::sizeMaxY() const
+{
+ return d->sizeMaxY;
+}
+
+int Sheet::maxColumn() const
+{
+ return d->maxColumn;
+}
+
+int Sheet::maxRow() const
+{
+ return d->maxRow;
+}
+
+const TQPen& Sheet::emptyPen() const
+{
+ return d->emptyPen;
+}
+
+const TQBrush& Sheet::emptyBrush() const
+{
+ return d->emptyBrush;
+}
+
+const TQColor& Sheet::emptyColor() const
+{
+ return d->emptyColor;
+}
+
+KSpread::DependencyManager *Sheet::dependencies ()
+{
+ return d->dependencies;
+}
+
+int Sheet::numSelected() const
+{
+ int num = 0;
+
+ TQPtrListIterator<EmbeddedObject> it( d->workbook->doc()->embeddedObjects() );
+ for ( ; it.current() ; ++it )
+ {
+ if( it.current()->sheet() == this && it.current()->isSelected() )
+ num++;
+ }
+
+ return num;
+}
+
+int Sheet::leftColumn( double _xpos, double &_left,
+ const Canvas *_canvas ) const
+{
+ if ( _canvas )
+ {
+ _xpos += _canvas->xOffset();
+ _left = -_canvas->xOffset();
+ }
+ else
+ _left = 0.0;
+
+ int col = 1;
+ double x = columnFormat( col )->dblWidth( _canvas );
+ while ( x < _xpos )
+ {
+ // Should never happen
+ if ( col >= KS_colMax )
+ {
+ kdDebug(36001) << "Sheet:leftColumn: invalid column (col: " << col + 1 << ")" << endl;
+ return KS_colMax + 1; //Return out of range value, so other code can react on this
+ }
+ _left += columnFormat( col )->dblWidth( _canvas );
+ col++;
+ x += columnFormat( col )->dblWidth( _canvas );
+ }
+
+ return col;
+}
+
+int Sheet::rightColumn( double _xpos, const Canvas *_canvas ) const
+{
+ if ( _canvas )
+ _xpos += _canvas->xOffset();
+
+ int col = 1;
+ double x = 0.0;
+ while ( x < _xpos )
+ {
+ // Should never happen
+ if ( col > KS_colMax )
+ {
+ kdDebug(36001) << "Sheet:rightColumn: invalid column (col: " << col << ")" << endl;
+ return KS_colMax + 1; //Return out of range value, so other code can react on this
+ }
+ x += columnFormat( col )->dblWidth( _canvas );
+ col++;
+ }
+
+ return col - 1;
+}
+
+TQRect Sheet::visibleRect( Canvas const * const _canvas ) const
+{
+ int top = 0;
+ int left = 0;
+
+ double x = 0;
+ double y = 0;
+ double width = 0;
+ double height = 0;
+
+ if ( _canvas )
+ {
+ y += _canvas->yOffset() * _canvas->zoom();
+ x += _canvas->xOffset() * _canvas->zoom();
+ width = _canvas->width();
+ height = _canvas->height();
+ }
+
+ double yn = rowFormat( top )->dblHeight( _canvas );
+ while ( yn < y )
+ {
+ if ( top >= KS_rowMax ) // Should never happen
+ break;
+
+ ++top;
+ yn += rowFormat( top )->dblHeight( _canvas );
+ }
+
+ int bottom = top + 1;
+
+ y += height;
+ while ( yn < y )
+ {
+ if ( bottom > KS_rowMax ) // Should never happen
+ break;
+
+ ++bottom;
+ yn += rowFormat( bottom )->dblHeight( _canvas );
+ }
+
+ double xn = columnFormat( left )->dblWidth( _canvas );
+ while ( xn < x )
+ {
+ if ( left >= KS_colMax ) // Should never happen
+ break;
+
+ ++left;
+ xn += columnFormat( left )->dblWidth( _canvas );
+ }
+ x += width;
+
+ int right = left + 1;
+
+ while ( xn < x )
+ {
+ if ( right > KS_colMax ) // Should never happen
+ break;
+
+ ++right;
+ xn += columnFormat( right )->dblWidth( _canvas );
+ }
+ x += width;
+
+ return TQRect( left, top, right - left + 1, bottom - top + 1 );
+}
+
+int Sheet::topRow( double _ypos, double & _top,
+ const Canvas *_canvas ) const
+{
+ if ( _canvas )
+ {
+ _ypos += _canvas->yOffset();
+ _top = -_canvas->yOffset();
+ }
+ else
+ _top = 0.0;
+
+ int row = 1;
+ double y = rowFormat( row )->dblHeight( _canvas );
+ while ( y < _ypos )
+ {
+ // Should never happen
+ if ( row >= KS_rowMax )
+ {
+ kdDebug(36001) << "Sheet:topRow: invalid row (row: " << row + 1 << ")" << endl;
+ return KS_rowMax + 1; //Return out of range value, so other code can react on this
+ }
+ _top += rowFormat( row )->dblHeight( _canvas );
+ row++;
+ y += rowFormat( row )->dblHeight( _canvas );
+ }
+
+ return row;
+}
+
+int Sheet::bottomRow( double _ypos, const Canvas *_canvas ) const
+{
+ if ( _canvas )
+ _ypos += _canvas->yOffset();
+
+ int row = 1;
+ double y = 0.0;
+ while ( y < _ypos )
+ {
+ // Should never happen
+ if ( row > KS_rowMax )
+ {
+ kdDebug(36001) << "Sheet:bottomRow: invalid row (row: " << row << ")" << endl;
+ return KS_rowMax + 1; //Return out of range value, so other code can react on this
+ }
+ y += rowFormat( row )->dblHeight( _canvas );
+ row++;
+ }
+
+ return row - 1;
+}
+
+double Sheet::dblColumnPos( int _col, const Canvas *_canvas ) const
+{
+ double x = 0.0;
+ if ( _canvas )
+ x -= _canvas->xOffset();
+ for ( int col = 1; col < _col; col++ )
+ {
+ // Should never happen
+ if ( col > KS_colMax )
+ {
+ kdDebug(36001) << "Sheet:columnPos: invalid column (col: " << col << ")" << endl;
+ return x;
+ }
+
+ x += columnFormat( col )->dblWidth( _canvas );
+ }
+
+ return x;
+}
+
+int Sheet::columnPos( int _col, const Canvas *_canvas ) const
+{
+ return (int)dblColumnPos( _col, _canvas );
+}
+
+
+double Sheet::dblRowPos( int _row, const Canvas *_canvas ) const
+{
+ double y = 0.0;
+ if ( _canvas )
+ y -= _canvas->yOffset();
+
+ for ( int row = 1 ; row < _row ; row++ )
+ {
+ // Should never happen
+ if ( row > KS_rowMax )
+ {
+ kdDebug(36001) << "Sheet:rowPos: invalid row (row: " << row << ")" << endl;
+ return y;
+ }
+
+ y += rowFormat( row )->dblHeight( _canvas );
+ }
+
+ return y;
+}
+
+int Sheet::rowPos( int _row, const Canvas *_canvas ) const
+{
+ return (int)dblRowPos( _row, _canvas );
+}
+
+
+void Sheet::adjustSizeMaxX ( double _x )
+{
+ d->sizeMaxX += _x;
+}
+
+void Sheet::adjustSizeMaxY ( double _y )
+{
+ d->sizeMaxY += _y;
+}
+
+Cell* Sheet::visibleCellAt( int _column, int _row, bool _scrollbar_update )
+{
+ Cell* cell = cellAt( _column, _row, _scrollbar_update );
+ if ( cell->obscuringCells().isEmpty() )
+ return cell;
+ else
+ return cell->obscuringCells().last();
+}
+
+Cell* Sheet::firstCell() const
+{
+ return d->cells.firstCell();
+}
+
+RowFormat* Sheet::firstRow() const
+{
+ return d->rows.first();
+}
+
+ColumnFormat* Sheet::firstCol() const
+{
+ return d->columns.first();
+}
+
+Cell* Sheet::cellAt( int _column, int _row ) const
+{
+ Cell *p = d->cells.lookup( _column, _row );
+ if ( p != 0L )
+ return p;
+
+ return d->defaultCell;
+}
+
+Cell* Sheet::cellAt( int _column, int _row, bool _scrollbar_update )
+{
+ if ( _scrollbar_update && d->scrollBarUpdates )
+ {
+ checkRangeHBorder( _column );
+ checkRangeVBorder( _row );
+ }
+
+ Cell *p = d->cells.lookup( _column, _row );
+ if ( p != 0L )
+ return p;
+
+ return d->defaultCell;
+}
+
+ColumnFormat* Sheet::nonDefaultColumnFormat( int _column, bool force_creation )
+{
+ ColumnFormat *p = d->columns.lookup( _column );
+ if ( p != 0L || !force_creation )
+ return p;
+
+ p = new ColumnFormat( this, _column );
+ // TODO: copy the default ColumnFormat here!!
+ p->setDblWidth( d->defaultColumnFormat->dblWidth() );
+
+ d->columns.insertElement( p, _column );
+
+ return p;
+}
+
+RowFormat* Sheet::nonDefaultRowFormat( int _row, bool force_creation )
+{
+ RowFormat *p = d->rows.lookup( _row );
+ if ( p != 0L || !force_creation )
+ return p;
+
+ p = new RowFormat( this, _row );
+ // TODO: copy the default RowLFormat here!!
+ p->setDblHeight( d->defaultRowFormat->dblHeight() );
+
+ d->rows.insertElement( p, _row );
+
+ return p;
+}
+
+Cell* Sheet::nonDefaultCell( int _column, int _row,
+ bool _scrollbar_update, Style * _style )
+{
+ // NOTE Stefan: _scrollbar_update defaults to false and this function
+ // is never called with it being true. So, this here is
+ // actually never processed. I'll leave this in here for the
+ // case I'm mistaken, but will remove it for 2.0.
+ if ( _scrollbar_update && d->scrollBarUpdates )
+ {
+ checkRangeHBorder( _column );
+ checkRangeVBorder( _row );
+ }
+
+ Cell * p = d->cells.lookup( _column, _row );
+ if ( p != 0L )
+ return p;
+
+ Cell * cell = 0;
+
+ if ( _style )
+ cell = new Cell( this, _style, _column, _row );
+ else
+ cell = new Cell( this, _column, _row );
+
+ insertCell( cell );
+
+ return cell;
+}
+
+void Sheet::setText( int _row, int _column, const TQString& _text, bool asString )
+{
+ ProtectedCheck prot;
+ prot.setSheet (this);
+ prot.add (TQPoint (_column, _row));
+ if (prot.check())
+ NO_MODIFICATION_POSSIBLE;
+
+ DataManipulator *dm = new DataManipulator ();
+ dm->setSheet (this);
+ dm->setValue (_text);
+ dm->setParsing (!asString);
+ dm->add (TQPoint (_column, _row));
+ dm->execute ();
+
+ /* PRE-MANIPULATOR CODE looked like this:
+ TODO remove this after the new code works
+ if ( !doc()->undoLocked() )
+ {
+ UndoSetText *undo = new UndoSetText( doc(), this, cell->text(), _column, _row,cell->formatType() );
+ doc()->addCommand( undo );
+ }
+
+ // The cell will force a display refresh itself, so we dont have to care here.
+ cell->setCellText( _text, asString );
+ */
+
+ //refresh anchor
+ if(_text.at(0)=='!')
+ emit sig_updateView( this, Region(_column,_row,_column,_row) );
+}
+
+void Sheet::setArrayFormula (Selection *selectionInfo, const TQString &_text)
+{
+ // check protection
+ ProtectedCheck prot;
+ prot.setSheet (this);
+ prot.add (*selectionInfo);
+ if (prot.check())
+ NO_MODIFICATION_POSSIBLE;
+
+ // create and call the manipulator
+ ArrayFormulaManipulator *afm = new ArrayFormulaManipulator;
+ afm->setSheet (this);
+ afm->setText (_text);
+ afm->add (*selectionInfo);
+ afm->execute ();
+
+ /* PRE-MANIPULATOR CODE LOOKED LIKE THIS
+ TODO remove this when the above code works
+ // add undo
+ if ( !doc()->undoLocked() )
+ {
+ UndoChangeAreaTextCell *undo =
+ new UndoChangeAreaTextCell (doc(), this,
+ TQRect (_column, _row, cols, rows));
+ doc()->addCommand( undo );
+ }
+
+ // fill in the cells ... top-left one gets the formula, the rest gets =INDEX
+ // TODO: also fill in information about cells being a part of a range
+ Cell *cell = nonDefaultCell (_column, _row);
+ cell->setCellText (_text, false);
+ TQString cellRef = cell->name();
+ for (int row = 0; row < rows; ++row)
+ for (int col = 0; col < cols; col++)
+ if (col || row)
+ {
+ Cell *cell = nonDefaultCell (_column + col, _row + row);
+ cell->setCellText ("=INDEX(" + cellRef + ";" + TQString::number (row+1)
+ + ";" + TQString::number (col+1) + ")", false);
+ }
+ */
+}
+
+void Sheet::setLayoutDirtyFlag()
+{
+ Cell * c = d->cells.firstCell();
+ for( ; c; c = c->nextCell() )
+ c->setLayoutDirtyFlag();
+}
+
+void Sheet::setCalcDirtyFlag()
+{
+ Cell* c = d->cells.firstCell();
+ for( ; c; c = c->nextCell() )
+ {
+ if ( !(c->isObscured() && c->isPartOfMerged()) )
+ c->setCalcDirtyFlag();
+ }
+}
+
+void Sheet::updateAllDependencies()
+{
+ for (Cell* cell = d->cells.firstCell() ; cell ; cell = cell->nextCell())
+ {
+ Point cellLocation;
+ cellLocation.setSheet(cell->sheet());
+ cellLocation.setRow(cell->row());
+ cellLocation.setColumn(cell->column());
+ d->dependencies->cellChanged(cellLocation);
+ }
+}
+
+void Sheet::recalc()
+{
+ recalc(false);
+}
+
+void Sheet::recalc( bool force )
+{
+ ElapsedTime et( "Recalculating " + d->name, ElapsedTime::PrintOnlyTime );
+ // emitBeginOperation(true);
+ // setRegionPaintDirty(TQRect(TQPoint(1,1), TQPoint(KS_colMax, KS_rowMax)));
+ setCalcDirtyFlag();
+
+ //If automatic calculation is disabled, don't recalculate unless the force flag has been
+ //set.
+ if ( !getAutoCalc() && !force )
+ return;
+
+ //If automatic calculation is disabled, the dependencies won't be up to date, so they need
+ //to be recalculated.
+ //FIXME: Tomas, is there a more efficient way to do this?
+ if ( !getAutoCalc() )
+ updateAllDependencies();
+
+
+ // (Tomas): actually recalc each cell
+ // this is FAR from being perfect, dependencies will cause some to be
+ // recalculated a LOT, but it's still better than otherwise, where
+ // we get no recalc if the result stored in a file differs from the
+ // current one - then we only obtain the correct result AFTER we scroll
+ // to the cell ... recalc should actually ... recalc :)
+ Cell* c;
+
+ int count = 0;
+ c = d->cells.firstCell();
+ for( ; c; c = c->nextCell() )
+ ++count;
+
+ int cur = 0;
+ int percent = -1;
+ c = d->cells.firstCell();
+ for( ; c; c = c->nextCell() )
+ {
+ c->calc (false);
+ cur++;
+ // some debug output to get some idea how damn slow this is ...
+ if (cur*100/count != percent) {
+ percent = cur*100/count;
+// kdDebug() << "Recalc: " << percent << "%" << endl;
+ }
+ }
+
+ // emitEndOperation();
+ emit sig_updateView( this );
+}
+
+void Sheet::valueChanged (Cell *cell)
+{
+
+ //TODO: call cell updating, when cell damaging implemented
+
+ //prepare the Point structure
+ Point c;
+ c.setRow (cell->row());
+ c.setColumn (cell->column());
+ c.setSheet( this );
+
+ //update dependencies
+ if ( getAutoCalc() )
+ d->dependencies->cellChanged (c);
+
+ //REMOVED - modification change - this was causing modified flag to be set inappropriately.
+ //nobody else seems to be setting the modified flag, so we do it here
+// doc()->setModified (true);
+}
+
+/*
+ Methods working on selections:
+
+ TYPE A:
+ { columns selected:
+ for all rows with properties X,X':
+ if default-cell create new cell
+ }
+ post undo object (always a UndoCellLayout; difference in title only)
+ { rows selected:
+ if condition Y clear properties X,X' of cells;
+ set properties X,X' of rowformats
+ emit complete update;
+ }
+ { columns selected:
+ if condition Y clear properties X,X' of cells;
+ set properties X,X' of columnformats;
+ for all rows with properties X,X':
+ create cells if necessary and set properties X,X'
+ emit complete update;
+ }
+ { cells selected:
+ for all cells with condition Y:
+ create if necessary and set properties X,X' and do Z;
+ emit update on selected region;
+ }
+
+ USED in:
+ setSelectionFont
+ setSelectionSize
+ setSelectionAngle
+ setSelectionTextColor
+ setSelectionBgColor
+ setSelectionPercent
+ borderAll
+ borderRemove (exceptions: ### creates cells (why?), ### changes default cell if cell-regions selected?)
+ setSelectionAlign
+ setSelectionAlignY
+ setSelectionMoneyFormat
+ increaseIndent
+ decreaseIndent
+
+ TYPE B:
+ post undo object
+ { rows selected:
+ if condition Y do X with cells;
+ emit update on selection;
+ }
+ { columns selected:
+ if condition Y do X with cells;
+ emit update on selection;
+ }
+ { cells selected:
+ if condition Y do X with cells; create cell if non-default;
+ emit update on selection;
+ }
+
+ USED in:
+ setSelectionUpperLower (exceptions: no undo; no create-if-default; ### modifies default-cell?)
+ setSelectionFirstLetterUpper (exceptions: no undo; no create-if-default; ### modifies default-cell?)
+ setSelectionVerticalText
+ setSelectionComment
+ setSelectionRemoveComment (exeception: no create-if-default and work only on non-default-cells for cell regions)
+ setSelectionBorderColor (exeception: no create-if-default and work only on non-default-cells for cell regions)
+ setSelectionMultiRow
+ setSelectionPrecision
+ clearTextSelection (exception: all only if !areaIsEmpty())
+ clearValiditySelection (exception: all only if !areaIsEmpty())
+ clearConditionalSelection (exception: all only if !areaIsEmpty())
+ setConditional (exception: conditional after create-if-default for cell regions)
+ setValidity (exception: conditional after create-if-default for cell regions)
+
+ OTHERS:
+ borderBottom
+ borderRight
+ borderLeft
+ borderTop
+ borderOutline
+ => these work only on some cells (at the border); undo only if cells affected; rest is similar to type A
+ --> better not use CellWorker/workOnCells()
+
+ defaultSelection
+ => similar to TYPE B, but works on columns/rows if complete columns/rows selected
+ --> use emit_signal=false and return value of workOnCells to finish
+
+ getWordSpelling
+ => returns text, no signal emitted, no cell-create, similar to TYPE B
+ --> use emit_signal=false, create_if_default=false and type B
+
+ setWordSpelling
+ => no signal emitted, no cell-create, similar to type B
+ --> use emit_signal=false, create_if_default=false and type B
+ */
+
+class UndoAction* Sheet::CellWorkerTypeA::createUndoAction( Doc* doc, Sheet* sheet, const KSpread::Region& region )
+{
+ TQString title = getUndoTitle();
+ return new UndoCellFormat( doc, sheet, region, title );
+}
+
+/*
+Sheet::SelectionType Sheet::workOnCells( const TQPoint& _marker, CellWorker& worker )
+{
+ // see what is selected; if nothing, take marker position
+ bool selected = ( m_rctSelection.left() != 0 );
+ TQRect r( m_rctSelection );
+ if ( !selected )
+ r.setCoords( _marker.x(), _marker.y(), _marker.x(), _marker.y() );
+
+ // create cells in rows if complete columns selected
+ Cell *cell;
+ if ( !worker.type_B && selected && isColumnSelected() )
+ {
+ for ( RowFormat* rw =d->rows.first(); rw; rw = rw->next() )
+ {
+ if ( !rw->isDefault() && worker.testCondition( rw ) )
+ {
+ for ( int i=m_rctSelection.left(); i<=m_rctSelection.right(); i++ )
+ {
+ cell = cellAt( i, rw->row() );
+ if ( cell == d->defaultCell )
+ // '&& worker.create_if_default' unnecessary as never used in type A
+ {
+ cell = new Cell( this, i, rw->row() );
+ insertCell( cell );
+ }
+ }
+ }
+ }
+ }
+
+ // create an undo action
+ if ( !doc()->undoLocked() )
+ {
+ UndoAction *undo = worker.createUndoAction( doc(), this, r );
+ // test if the worker has an undo action
+ if ( undo != 0L )
+ doc()->addCommand( undo );
+ }
+
+ // complete rows selected ?
+ if ( selected && isRowSelected() )
+ {
+ int row;
+ for ( Cell* cell = d->cells.firstCell(); cell; cell = cell->nextCell() )
+ {
+ row = cell->row();
+ if ( m_rctSelection.top() <= row && m_rctSelection.bottom() >= row
+ && worker.testCondition( cell ) )
+ if ( worker.type_B )
+ worker.doWork( cell, false, cell->column(), row );
+ else
+ worker.prepareCell( cell );
+ }
+
+ if ( worker.type_B ) {
+ // for type B there's nothing left to do
+ if ( worker.emit_signal )
+ emit sig_updateView( this, r );
+ } else {
+ // for type A now work on row formats
+ for ( int i=m_rctSelection.top(); i<=m_rctSelection.bottom(); i++ )
+ {
+ RowFormat *rw=nonDefaultRowFormat(i);
+ worker.doWork( rw );
+ }
+ if ( worker.emit_signal )
+ emit sig_updateView( this );
+ }
+ return CompleteRows;
+ }
+ // complete columns selected ?
+ else if ( selected && isColumnSelected() )
+ {
+ int col;
+ for ( Cell* cell = d->cells.firstCell(); cell; cell = cell->nextCell() )
+ {
+ col = cell->column();
+ if ( m_rctSelection.left() <= col && m_rctSelection.right() >= col
+ && worker.testCondition( cell ) )
+ if ( worker.type_B )
+ worker.doWork( cell, false, col, cell->row() );
+ else
+ worker.prepareCell( cell );
+ }
+
+ if ( worker.type_B ) {
+ if ( worker.emit_signal )
+ emit sig_updateView( this, r );
+ } else {
+ // for type A now work on column formats
+ for ( int i=m_rctSelection.left(); i<=m_rctSelection.right(); i++ )
+ {
+ ColumnFormat *cl=nonDefaultColumnFormat(i);
+ worker.doWork( cl );
+ }
+ Cell *cell;
+ for ( RowFormat* rw =d->rows.first(); rw; rw = rw->next() )
+ {
+ if ( !rw->isDefault() && worker.testCondition( rw ) )
+ {
+ for ( int i=m_rctSelection.left(); i<=m_rctSelection.right(); i++ )
+ {
+ cell = cellAt( i, rw->row() );
+ // ### this if should be not necessary; cells are created
+ // before the undo object is created, aren't they?
+ if ( cell == d->defaultCell )
+ {
+ cell = new Cell( this, i, rw->row() );
+ insertCell( cell );
+ }
+ worker.doWork( cell, false, i, rw->row() );
+ }
+ }
+ }
+ if ( worker.emit_signal )
+ emit sig_updateView( this );
+ }
+ return CompleteColumns;
+ }
+ // cell region selected
+ else
+ {
+ Cell *cell;
+ for ( int x = r.left(); x <= r.right(); x++ )
+ for ( int y = r.top(); y <= r.bottom(); y++ )
+ {
+ cell = cellAt( x, y );
+ if ( worker.testCondition( cell ) )
+ {
+ if ( worker.create_if_default && cell == d->defaultCell )
+ {
+ cell = new Cell( this, x, y );
+ insertCell( cell );
+ }
+ if ( cell != d->defaultCell )
+ worker.doWork( cell, true, x, y );
+ }
+ }
+ if ( worker.emit_signal )
+ emit sig_updateView( this, r );
+ return CellRegion;
+ }
+}
+
+*/
+
+Sheet::SelectionType Sheet::workOnCells( Selection* selectionInfo, CellWorker & worker )
+{
+ Sheet::SelectionType result;
+
+ doc()->emitBeginOperation();
+
+ // see what is selected; if nothing, take marker position
+ bool selected = !(selectionInfo->isSingular());
+
+ // create an undo action
+ if ( !doc()->undoLocked() )
+ {
+ UndoAction* undo = worker.createUndoAction(doc(), this, *selectionInfo);
+ // test if the worker has an undo action
+ if ( undo != 0 )
+ {
+ doc()->addCommand( undo );
+ }
+ }
+
+ Region::ConstIterator endOfList(selectionInfo->constEnd());
+ for (Region::ConstIterator it = selectionInfo->constBegin(); it != endOfList; ++it)
+ {
+ // see what is selected; if nothing, take marker position
+ TQRect range = (*it)->rect().normalize();
+
+ int top = range.top();
+ int left = range.left();
+ int bottom = range.bottom();
+ int right = range.right();
+
+ // create cells in rows if complete columns selected
+ Cell * cell;
+ Style * s = doc()->styleManager()->defaultStyle();
+
+ if ( !worker.type_B && selected && util_isColumnSelected(range) )
+ {
+ for ( RowFormat * rw = d->rows.first(); rw; rw = rw->next() )
+ {
+ if ( worker.testCondition( rw ) )
+ {
+ for ( int col = left; col <= right; ++col )
+ {
+ cell = nonDefaultCell( col, rw->row(), false, s );
+ }
+ }
+ }
+ }
+
+ // complete rows selected ?
+ if ( selected && util_isRowSelected(range) )
+ {
+ for ( int row = top; row <= bottom; ++row )
+ {
+ cell = getFirstCellRow( row );
+ while ( cell )
+ {
+ if ( worker.testCondition( cell ) )
+ {
+ if ( worker.type_B )
+ worker.doWork( cell, false, cell->column(), row );
+ else
+ worker.prepareCell( cell );
+ }
+ cell = getNextCellRight( cell->column(), row );
+ }
+ }
+
+ if ( worker.type_B )
+ {
+ // for type B there's nothing left to do
+ ;
+ }
+ else
+ {
+ // for type A now work on row formats
+ for ( int i = top; i <= bottom; ++i )
+ {
+ RowFormat * rw = nonDefaultRowFormat(i);
+ worker.doWork( rw );
+ }
+
+ for ( int row = top; row <= bottom; ++row )
+ {
+ cell = getFirstCellRow( row );
+ while ( cell )
+ {
+ if ( worker.testCondition( cell ) )
+ {
+ worker.doWork( cell, false, cell->column(), row );
+ }
+ cell = getNextCellRight( cell->column(), row );
+ }
+ }
+
+ }
+ result = CompleteRows;
+ }
+ // complete columns selected ?
+ else if ( selected && util_isColumnSelected(range) )
+ {
+ for ( int col = range.left(); col <= right; ++col )
+ {
+ cell = getFirstCellColumn( col );
+ while ( cell )
+ {
+ if ( worker.testCondition( cell ) )
+ {
+ if ( worker.type_B )
+ worker.doWork( cell, false, col, cell->row() );
+ else
+ worker.prepareCell( cell );
+ }
+
+ cell = getNextCellDown( col, cell->row() );
+ }
+ }
+
+ if ( worker.type_B )
+ {
+ ;
+ }
+ else
+ {
+ // for type A now work on column formats
+ for ( int i = left; i <= right; ++i )
+ {
+ ColumnFormat * cl = nonDefaultColumnFormat( i );
+ worker.doWork( cl );
+ }
+
+ for ( RowFormat * rw = d->rows.first(); rw; rw = rw->next() )
+ {
+ if ( worker.testCondition( rw ) )
+ {
+ for ( int i = left; i <= right; ++i )
+ {
+ cell = nonDefaultCell( i, rw->row(), false, s );
+ worker.doWork( cell, false, i, rw->row() );
+ }
+ }
+ }
+ }
+ result = CompleteColumns;
+ }
+ // cell region selected
+ else
+ {
+ for ( int x = left; x <= right; ++x )
+ {
+ enableScrollBarUpdates(false);
+ for ( int y = top; y <= bottom; ++y )
+ {
+ cell = cellAt( x, y );
+ if ( worker.testCondition( cell ) )
+ {
+ if ( cell == d->defaultCell && worker.create_if_default )
+ {
+ cell = new Cell( this, s, x, y );
+ insertCell( cell );
+ }
+ if ( cell != d->defaultCell )
+ {
+ // kdDebug() << "not default" << endl;
+ worker.doWork( cell, true, x, y );
+ }
+ }
+ }
+ enableScrollBarUpdates(true);
+ checkRangeVBorder(bottom);
+ }
+ checkRangeHBorder(right);
+ result = CellRegion;
+ }
+
+ } // for Region::Elements
+
+ // emitEndOperation();
+ emit sig_updateView( this );
+
+ if (worker.emit_signal)
+ {
+ emit sig_updateView( this, *selectionInfo );
+ }
+
+ return result;
+}
+
+void Sheet::setSelectionFont( Selection* selectionInfo,
+ const char *_font, int _size,
+ signed char _bold, signed char _italic,
+ signed char _underline, signed char _strike)
+{
+ FontManipulator* manipulator = new FontManipulator();
+ manipulator->setSheet(this);
+ manipulator->setProperty(Format::PFont);
+ manipulator->setFontFamily(_font);
+ manipulator->setFontSize(_size);
+ manipulator->setFontBold(_bold);
+ manipulator->setFontItalic(_italic);
+ manipulator->setFontStrike(_strike);
+ manipulator->setFontUnderline(_underline);
+ manipulator->add(*selectionInfo);
+ manipulator->execute();
+}
+
+void Sheet::setSelectionSize(Selection* selectionInfo,
+ int _size)
+{
+ // TODO Stefan: Increase/Decrease font size still used?
+ int size;
+ Cell* c;
+ TQPoint marker(selectionInfo->marker());
+ c = cellAt(marker);
+ size = c->format()->textFontSize(marker.x(), marker.y());
+
+ FontManipulator* manipulator = new FontManipulator();
+ manipulator->setSheet(this);
+ manipulator->setProperty(Format::PFont);
+ manipulator->setFontSize(_size+size);
+ manipulator->add(*selectionInfo);
+ manipulator->execute();
+}
+
+
+struct SetSelectionUpperLowerWorker : public Sheet::CellWorker {
+ int _type;
+ Sheet * _s;
+ SetSelectionUpperLowerWorker( int type, Sheet * s )
+ : Sheet::CellWorker( false ), _type( type ), _s( s ) { }
+
+ class UndoAction* createUndoAction( Doc* doc, Sheet* sheet, const KSpread::Region& region )
+ {
+ return new UndoChangeAreaTextCell( doc, sheet, region );
+ }
+ bool testCondition( Cell* c ) {
+ return ( !c->value().isNumber() && !c->value().isBoolean() &&!c->isFormula() && !c->isDefault()
+ && !c->text().isEmpty() && c->text()[0] != '*' && c->text()[0] != '!'
+ && !c->isPartOfMerged() );
+ }
+ void doWork( Cell* cell, bool, int, int )
+ {
+ cell->setDisplayDirtyFlag();
+ if ( _type == -1 )
+ cell->setCellText( (cell->text().lower()));
+ else if ( _type == 1 )
+ cell->setCellText( (cell->text().upper()));
+ cell->clearDisplayDirtyFlag();
+ }
+};
+
+void Sheet::setSelectionUpperLower( Selection* selectionInfo,
+ int _type )
+{
+ SetSelectionUpperLowerWorker w( _type, this );
+ workOnCells( selectionInfo, w );
+}
+
+
+struct SetSelectionFirstLetterUpperWorker : public Sheet::CellWorker
+{
+ Changes * _c;
+ Sheet * _s;
+ SetSelectionFirstLetterUpperWorker( Sheet * s )
+ : Sheet::CellWorker( false ), _s( s ) { }
+
+ class UndoAction* createUndoAction( Doc* doc, Sheet* sheet, const KSpread::Region& region ) {
+ return new UndoChangeAreaTextCell( doc, sheet, region );
+ }
+ bool testCondition( Cell* c ) {
+ return ( !c->value().isNumber() && !c->value().isBoolean() &&!c->isFormula() && !c->isDefault()
+ && !c->text().isEmpty() && c->text()[0] != '*' && c->text()[0] != '!'
+ && !c->isPartOfMerged() );
+ }
+ void doWork( Cell* cell, bool, int, int )
+ {
+
+ cell->setDisplayDirtyFlag();
+ TQString tmp = cell->text();
+ int len = tmp.length();
+ cell->setCellText( (tmp.at(0).upper()+tmp.right(len-1)) );
+ cell->clearDisplayDirtyFlag();
+ }
+};
+
+void Sheet::setSelectionfirstLetterUpper( Selection* selectionInfo)
+{
+ SetSelectionFirstLetterUpperWorker w( this );
+ workOnCells( selectionInfo, w );
+}
+
+
+struct SetSelectionVerticalTextWorker : public Sheet::CellWorker {
+ bool _b;
+ SetSelectionVerticalTextWorker( bool b ) : Sheet::CellWorker( ), _b( b ) { }
+
+ class UndoAction* createUndoAction( Doc* doc, Sheet* sheet, const KSpread::Region& region ) {
+ TQString title=i18n("Vertical Text");
+ return new UndoCellFormat( doc, sheet, region, title );
+ }
+ bool testCondition( Cell* cell ) {
+ return ( !cell->isPartOfMerged() );
+ }
+ void doWork( Cell* cell, bool, int, int ) {
+ cell->setDisplayDirtyFlag();
+ cell->format()->setVerticalText( _b );
+ cell->format()->setMultiRow( false );
+ cell->format()->setAngle( 0 );
+ cell->clearDisplayDirtyFlag();
+ }
+};
+
+void Sheet::setSelectionVerticalText( Selection* selectionInfo,
+ bool _b )
+{
+ SetSelectionVerticalTextWorker w( _b );
+ workOnCells( selectionInfo, w );
+}
+
+
+struct SetSelectionCommentWorker : public Sheet::CellWorker {
+ TQString _comment;
+ SetSelectionCommentWorker( TQString comment ) : Sheet::CellWorker( ), _comment( comment ) { }
+
+ class UndoAction* createUndoAction( Doc* doc, Sheet* sheet, const KSpread::Region& region ) {
+ TQString title=i18n("Add Comment");
+ return new UndoCellFormat( doc, sheet, region, title );
+ }
+ bool testCondition( Cell* cell ) {
+ return ( !cell->isPartOfMerged() );
+ }
+ void doWork( Cell* cell, bool, int, int ) {
+ cell->setDisplayDirtyFlag();
+ cell->format()->setComment( _comment );
+ cell->clearDisplayDirtyFlag();
+ }
+};
+
+void Sheet::setSelectionComment( Selection* selectionInfo,
+ const TQString &_comment)
+{
+ SetSelectionCommentWorker w( _comment );
+ workOnCells( selectionInfo, w );
+}
+
+
+void Sheet::setSelectionAngle( Selection* selectionInfo,
+ int _value )
+{
+ AngleManipulator* manipulator = new AngleManipulator();
+ manipulator->setSheet(this);
+ manipulator->setProperty(Format::PAngle);
+ manipulator->setAngle(_value);
+ manipulator->add(*selectionInfo);
+ manipulator->execute();
+}
+
+struct SetSelectionRemoveCommentWorker : public Sheet::CellWorker {
+ SetSelectionRemoveCommentWorker( ) : Sheet::CellWorker( false ) { }
+
+ class UndoAction* createUndoAction( Doc* doc, Sheet* sheet, const KSpread::Region& region ) {
+ TQString title=i18n("Remove Comment");
+ return new UndoCellFormat( doc, sheet, region, title );
+ }
+ bool testCondition( Cell* cell ) {
+ return ( !cell->isPartOfMerged() );
+ }
+ void doWork( Cell* cell, bool, int, int ) {
+ cell->setDisplayDirtyFlag();
+ cell->format()->setComment( "" );
+ cell->clearDisplayDirtyFlag();
+ }
+};
+
+void Sheet::setSelectionRemoveComment( Selection* selectionInfo )
+{
+ if (areaIsEmpty(*selectionInfo, Comment))
+ return;
+
+ SetSelectionRemoveCommentWorker w;
+ workOnCells( selectionInfo, w );
+}
+
+
+void Sheet::setSelectionTextColor( Selection* selectionInfo,
+ const TQColor &tb_Color )
+{
+ FontColorManipulator* manipulator = new FontColorManipulator();
+ manipulator->setSheet(this);
+ manipulator->setProperty(Format::PTextPen);
+ manipulator->setTextColor(tb_Color);
+ manipulator->add(*selectionInfo);
+ manipulator->execute();
+}
+
+void Sheet::setSelectionbgColor( Selection* selectionInfo,
+ const TQColor &bg_Color )
+{
+ BackgroundColorManipulator* manipulator = new BackgroundColorManipulator();
+ manipulator->setSheet(this);
+ manipulator->setProperty(Format::PBackgroundColor);
+ manipulator->setBackgroundColor(bg_Color);
+ manipulator->add(*selectionInfo);
+ manipulator->execute();
+}
+
+
+struct SetSelectionBorderColorWorker : public Sheet::CellWorker {
+ const TQColor& bd_Color;
+ SetSelectionBorderColorWorker( const TQColor& _bd_Color ) : Sheet::CellWorker( false ), bd_Color( _bd_Color ) { }
+
+ class UndoAction* createUndoAction( Doc* doc, Sheet* sheet, const KSpread::Region& region ) {
+ TQString title=i18n("Change Border Color");
+ return new UndoCellFormat( doc, sheet, region, title );
+ }
+ bool testCondition( Cell* cell ) {
+ return ( !cell->isPartOfMerged() );
+ }
+ void doWork( Cell* cell, bool, int, int ) {
+ cell->setDisplayDirtyFlag();
+ int it_Row = cell->row();
+ int it_Col = cell->column();
+ if ( cell->format()->topBorderStyle( it_Row, it_Col )!=TQt::NoPen )
+ cell->format()->setTopBorderColor( bd_Color );
+ if ( cell->format()->leftBorderStyle( it_Row, it_Col )!=TQt::NoPen )
+ cell->format()->setLeftBorderColor( bd_Color );
+ if ( cell->format()->fallDiagonalStyle( it_Row, it_Col )!=TQt::NoPen )
+ cell->format()->setFallDiagonalColor( bd_Color );
+ if ( cell->format()->goUpDiagonalStyle( it_Row, it_Col )!=TQt::NoPen )
+ cell->format()->setGoUpDiagonalColor( bd_Color );
+ if ( cell->format()->bottomBorderStyle( it_Row, it_Col )!=TQt::NoPen )
+ cell->format()->setBottomBorderColor( bd_Color );
+ if ( cell->format()->rightBorderStyle( it_Row, it_Col )!=TQt::NoPen )
+ cell->format()->setRightBorderColor( bd_Color );
+ cell->clearDisplayDirtyFlag();
+ }
+};
+
+void Sheet::setSelectionBorderColor( Selection* selectionInfo,
+ const TQColor &bd_Color )
+{
+ SetSelectionBorderColorWorker w( bd_Color );
+ workOnCells( selectionInfo, w );
+}
+
+
+void Sheet::setSeries( const TQPoint &_marker, double start, double end, double step, Series mode, Series type)
+{
+ doc()->emitBeginOperation();
+
+ TQString cellText;
+
+ int x,y; /* just some loop counters */
+
+ /* the actual number of columns or rows that the series will span.
+ i.e. this will count 3 cells for a single cell that spans three rows
+ */
+ int numberOfCells;
+ if (end > start)
+ numberOfCells = (int) ((end - start) / step + 1); /*initialize for linear*/
+ else if ( end <start )
+ numberOfCells = (int) ((start - end) / step + 1); /*initialize for linear*/
+ else //equal ! => one cell fix infini loop
+ numberOfCells = 1;
+ if (type == Geometric)
+ {
+ /* basically, A(n) = start ^ n
+ * so when does end = start ^ n ??
+ * when n = ln(end) / ln(start)
+ */
+ numberOfCells = (int)( (log((double)end) / log((double)start)) +
+ DBL_EPSILON) + 1;
+ }
+
+ Cell * cell = NULL;
+
+ /* markers for the top-left corner of the undo region. It'll probably
+ * be the top left corner of where the series is, but if something in front
+ * is obscuring the cell, then it needs to be part of the undo region */
+ TQRect undoRegion;
+
+ undoRegion.setLeft(_marker.x());
+ undoRegion.setTop(_marker.y());
+
+ /* this whole block is used to find the correct size for the undo region.
+ We're checking for two different things (in these examples,
+ mode==column):
+
+ 1. cells are vertically merged. This means that one value in the
+ series will span multiple cells.
+
+ 2. a cell in the column is merged to a cell to its left. In this case
+ the cell value will be stored in the left most cell so we need to
+ extend the undo range to include that column.
+ */
+ if ( mode == Column )
+ {
+ for ( y = _marker.y(); y <= (_marker.y() + numberOfCells - 1) && y <= KS_rowMax; y++ )
+ {
+ cell = cellAt( _marker.x(), y );
+
+ if ( cell->isPartOfMerged() )
+ {
+ /* case 2. */
+ cell = cell->obscuringCells().first();
+ undoRegion.setLeft(TQMIN(undoRegion.left(), cell->column()));
+ }
+ /* case 1. Add the extra space to numberOfCells and then skip
+ over the region. Note that because of the above if block 'cell'
+ points to the correct cell in the case where both case 1 and 2
+ are true
+ */
+ numberOfCells += cell->extraYCells();
+ y += cell->extraYCells();
+ }
+ undoRegion.setRight( _marker.x() );
+ undoRegion.setBottom( y - 1 );
+
+ checkRangeVBorder( undoRegion.bottom() );
+ }
+ else if(mode == Row)
+ {
+ for ( x = _marker.x(); x <=(_marker.x() + numberOfCells - 1) && x <= KS_colMax; x++ )
+ {
+ /* see the code above for a column series for a description of
+ what is going on here. */
+ cell = cellAt( x,_marker.y(), false );
+
+ if ( cell->isPartOfMerged() )
+ {
+ cell = cell->obscuringCells().first();
+ undoRegion.setTop(TQMIN(undoRegion.top(), cell->row()));
+ }
+ numberOfCells += cell->extraXCells();
+ x += cell->extraXCells();
+ }
+ undoRegion.setBottom( _marker.y() );
+ undoRegion.setRight( x - 1 );
+
+ checkRangeHBorder( undoRegion.right() );
+ }
+
+ kdDebug() << "Saving undo information" << endl;
+
+ if ( !doc()->undoLocked() )
+ {
+ UndoChangeAreaTextCell *undo = new
+ UndoChangeAreaTextCell( doc(), this, undoRegion );
+ doc()->addCommand( undo );
+ }
+
+ kdDebug() << "Saving undo information done" << endl;
+
+ setRegionPaintDirty( undoRegion );
+
+ x = _marker.x();
+ y = _marker.y();
+
+ /* now we're going to actually loop through and set the values */
+ double incr;
+ Style * s = doc()->styleManager()->defaultStyle();
+ if (step >= 0 && start < end)
+ {
+ for ( incr = start; incr <= end; )
+ {
+ cell = nonDefaultCell( x, y, false, s );
+
+ if ( cell->isPartOfMerged() )
+ {
+ cell = cell->obscuringCells().first();
+ }
+
+ // cell->setCellText(cellText.setNum( incr ));
+
+ cell->setNumber( incr );
+ if (mode == Column)
+ {
+ ++y;
+ if (cell->doesMergeCells())
+ {
+ y += cell->extraYCells();
+ }
+ if ( y > KS_rowMax )
+ {
+ break;
+ }
+ }
+ else if (mode == Row)
+ {
+ ++x;
+ if (cell->doesMergeCells())
+ {
+ x += cell->extraXCells();
+ }
+ if ( x > KS_colMax )
+ {
+ break;
+ }
+ }
+ else
+ {
+ kdDebug(36001) << "Error in Series::mode" << endl;
+ return;
+ }
+
+ if (type == Linear)
+ incr = incr + step;
+ else if (type == Geometric)
+ incr = incr * step;
+ else
+ {
+ kdDebug(36001) << "Error in Series::type" << endl;
+ return;
+ }
+ }
+ }
+ else
+ if (step >= 0 && start > end)
+ {
+ for ( incr = start; incr >= end; )
+ {
+ cell = nonDefaultCell( x, y, false, s );
+
+ if (cell->isPartOfMerged())
+ {
+ cell = cell->obscuringCells().first();
+ }
+
+ // cell->setCellText(cellText.setNum( incr ));
+ cell->setNumber( incr );
+ if (mode == Column)
+ {
+ ++y;
+ if (cell->doesMergeCells())
+ {
+ y += cell->extraYCells();
+ }
+ if ( y > KS_rowMax )
+ {
+ break;
+ }
+ }
+ else if (mode == Row)
+ {
+ ++x;
+ if (cell->doesMergeCells())
+ {
+ x += cell->extraXCells();
+ }
+ if ( x > KS_colMax )
+ {
+ break;
+ }
+ }
+ else
+ {
+ kdDebug(36001) << "Error in Series::mode" << endl;
+ return;
+ }
+
+ if (type == Linear)
+ incr = incr + step;
+ else if (type == Geometric)
+ incr = incr * step;
+ else
+ {
+ kdDebug(36001) << "Error in Series::type" << endl;
+ return;
+ }
+ }
+ }
+ else
+ {
+ for ( incr = start; incr <= end; )
+ {
+ cell = nonDefaultCell( x, y, false, s );
+
+ if (cell->isPartOfMerged())
+ {
+ cell = cell->obscuringCells().first();
+ }
+
+ //cell->setCellText(cellText.setNum( incr ));
+ cell->setNumber( incr );
+ if (mode == Column)
+ {
+ ++y;
+ if (cell->doesMergeCells())
+ {
+ y += cell->extraYCells();
+ }
+ if ( y > KS_rowMax )
+ {
+ break;
+ }
+ }
+ else if (mode == Row)
+ {
+ ++x;
+ if (cell->doesMergeCells())
+ {
+ x += cell->extraXCells();
+ }
+ if ( x > KS_colMax )
+ {
+ break;
+ }
+ }
+ else
+ {
+ kdDebug(36001) << "Error in Series::mode" << endl;
+ return;
+ }
+
+ if (type == Linear)
+ incr = incr + step;
+ else if (type == Geometric)
+ {
+
+ incr = incr * step;
+ //a step = 1 into geometric serie is not good
+ //we don't increase value => infini loop
+ if (step == 1)
+ return;
+ }
+ else
+ {
+ kdDebug(36001) << "Error in Series::type" << endl;
+ return;
+ }
+ }
+ }
+
+
+ // doc()->emitEndOperation();
+ emit sig_updateView( this );
+}
+
+
+struct SetSelectionPercentWorker : public Sheet::CellWorkerTypeA
+{
+ bool b;
+ SetSelectionPercentWorker( bool _b ) : b( _b ) { }
+
+ TQString getUndoTitle() { return i18n("Format Percent"); }
+ bool testCondition( RowFormat* ) {
+ //TODO: no idea what to put here, now that factor's gone :(
+ return ( true );
+ }
+ void doWork( RowFormat* rw ) {
+ //rw->setPrecision( 0 );
+ rw->setFormatType( b ? Percentage_format : Generic_format);
+ }
+ void doWork( ColumnFormat* cl ) {
+ cl->setFormatType( b ? Percentage_format : Generic_format);
+ }
+ void prepareCell( Cell* cell ) {
+ cell->format()->clearProperty(Format::PFormatType);
+ cell->format()->clearNoFallBackProperties( Format::PFormatType );
+ }
+ bool testCondition( Cell* cell ) {
+ return ( !cell->isPartOfMerged() );
+ }
+ void doWork( Cell* cell, bool cellRegion, int, int ) {
+ if ( cellRegion )
+ cell->setDisplayDirtyFlag();
+ cell->format()->setFormatType( b ? Percentage_format : Generic_format);
+ if ( cellRegion )
+ cell->clearDisplayDirtyFlag();
+ }
+};
+
+void Sheet::setSelectionPercent( Selection* selectionInfo, bool b )
+{
+ SetSelectionPercentWorker w( b );
+ workOnCells( selectionInfo, w );
+}
+
+void Sheet::slotAreaModified (const TQString &name)
+{
+ d->dependencies->areaModified (name);
+}
+
+
+void Sheet::refreshRemoveAreaName(const TQString & _areaName)
+{
+ Cell * c = d->cells.firstCell();
+ TQString tmp = "'" + _areaName + "'";
+ for( ;c ; c = c->nextCell() )
+ {
+ if ( c->isFormula() )
+ {
+ if (c->text().find(tmp) != -1)
+ {
+ if ( !c->makeFormula() )
+ kdError(36001) << "ERROR: Syntax ERROR" << endl;
+ }
+ }
+ }
+}
+
+void Sheet::refreshChangeAreaName(const TQString & _areaName)
+{
+ Cell * c = d->cells.firstCell();
+ TQString tmp = "'" + _areaName + "'";
+ for( ;c ; c = c->nextCell() )
+ {
+ if ( c->isFormula() )
+ {
+ if (c->text().find(tmp) != -1)
+ {
+ if ( !c->makeFormula() )
+ kdError(36001) << "ERROR: Syntax ERROR" << endl;
+ else
+ {
+ /* setting a cell calc dirty also sets it paint dirty */
+ c->setCalcDirtyFlag();
+ }
+ }
+ }
+ }
+}
+
+void Sheet::changeCellTabName( TQString const & old_name, TQString const & new_name )
+{
+ Cell* c = d->cells.firstCell();
+ for( ;c; c = c->nextCell() )
+ {
+ if( c->isFormula() )
+ {
+ if(c->text().find(old_name)!=-1)
+ {
+ int nb = c->text().contains(old_name+"!");
+ TQString tmp=old_name+"!";
+ int len = tmp.length();
+ tmp=c->text();
+
+ for( int i=0; i<nb; i++ )
+ {
+ int pos = tmp.find( old_name+"!" );
+ tmp.replace( pos, len, new_name+"!" );
+ }
+ c->setCellText(tmp);
+ }
+ }
+ }
+}
+
+bool Sheet::shiftRow( const TQRect &rect,bool makeUndo )
+{
+ UndoInsertCellRow * undo = 0;
+ if ( !doc()->undoLocked() &&makeUndo)
+ {
+ undo = new UndoInsertCellRow( doc(), this, rect );
+ doc()->addCommand( undo );
+ }
+
+ bool res=true;
+ bool result;
+ for( int i=rect.top(); i<=rect.bottom(); i++ )
+ {
+ for( int j=0; j<=(rect.right()-rect.left()); j++ )
+ {
+ result = d->cells.shiftRow( TQPoint(rect.left(),i) );
+ if( !result )
+ res=false;
+ }
+ }
+ TQPtrListIterator<Sheet> it( workbook()->sheetList() );
+ for( ; it.current(); ++it )
+ {
+ for(int i = rect.top(); i <= rect.bottom(); i++ )
+ it.current()->changeNameCellRef( TQPoint( rect.left(), i ), false,
+ Sheet::ColumnInsert, name(),
+ ( rect.right() - rect.left() + 1),
+ undo);
+ }
+ refreshChart(TQPoint(rect.left(),rect.top()), false, Sheet::ColumnInsert);
+ refreshMergedCell();
+ recalc();
+ emit sig_updateView( this );
+
+ return res;
+}
+
+bool Sheet::shiftColumn( const TQRect& rect,bool makeUndo )
+{
+ UndoInsertCellCol * undo = 0;
+ if ( !doc()->undoLocked() &&makeUndo)
+ {
+ undo = new UndoInsertCellCol( doc(), this,rect);
+ doc()->addCommand( undo );
+ }
+
+ bool res=true;
+ bool result;
+ for( int i =rect.left(); i<=rect.right(); i++ )
+ {
+ for( int j=0; j<=(rect.bottom()-rect.top()); j++ )
+ {
+ result = d->cells.shiftColumn( TQPoint(i,rect.top()) );
+ if(!result)
+ res=false;
+ }
+ }
+
+ TQPtrListIterator<Sheet> it( workbook()->sheetList() );
+ for( ; it.current(); ++it )
+ {
+ for(int i=rect.left();i<=rect.right();i++)
+ it.current()->changeNameCellRef( TQPoint( i, rect.top() ), false,
+ Sheet::RowInsert, name(),
+ ( rect.bottom() - rect.top() + 1 ),
+ undo );
+ }
+ refreshChart(/*marker*/TQPoint(rect.left(),rect.top()), false, Sheet::RowInsert);
+ refreshMergedCell();
+ recalc();
+ emit sig_updateView( this );
+
+ return res;
+}
+
+void Sheet::unshiftColumn( const TQRect & rect,bool makeUndo )
+{
+ UndoRemoveCellCol * undo = 0;
+ if ( !doc()->undoLocked() && makeUndo )
+ {
+ undo = new UndoRemoveCellCol( doc(), this, rect );
+ doc()->addCommand( undo );
+ }
+
+ for(int i =rect.top();i<=rect.bottom();i++)
+ for(int j=rect.left();j<=rect.right();j++)
+ d->cells.remove(j,i);
+
+ for(int i =rect.left();i<=rect.right();i++)
+ for(int j=0;j<=(rect.bottom()-rect.top());j++)
+ d->cells.unshiftColumn( TQPoint(i,rect.top()) );
+
+ TQPtrListIterator<Sheet> it( workbook()->sheetList() );
+ for( ; it.current(); ++it )
+ for(int i=rect.left();i<=rect.right();i++)
+ it.current()->changeNameCellRef( TQPoint( i, rect.top() ), false,
+ Sheet::RowRemove, name(),
+ ( rect.bottom() - rect.top() + 1 ),
+ undo );
+
+ refreshChart( TQPoint(rect.left(),rect.top()), false, Sheet::RowRemove );
+ refreshMergedCell();
+ recalc();
+ emit sig_updateView( this );
+}
+
+void Sheet::unshiftRow( const TQRect & rect,bool makeUndo )
+{
+ UndoRemoveCellRow * undo = 0;
+ if ( !doc()->undoLocked() && makeUndo )
+ {
+ undo = new UndoRemoveCellRow( doc(), this, rect );
+ doc()->addCommand( undo );
+ }
+ for(int i =rect.top();i<=rect.bottom();i++)
+ for(int j=rect.left();j<=rect.right();j++)
+ d->cells.remove(j,i);
+
+ for(int i =rect.top();i<=rect.bottom();i++)
+ for(int j=0;j<=(rect.right()-rect.left());j++)
+ d->cells.unshiftRow( TQPoint(rect.left(),i) );
+
+ TQPtrListIterator<Sheet> it( workbook()->sheetList() );
+ for( ; it.current(); ++it )
+ for(int i=rect.top();i<=rect.bottom();i++)
+ it.current()->changeNameCellRef( TQPoint( rect.left(), i ), false,
+ Sheet::ColumnRemove, name(),
+ ( rect.right() - rect.left() + 1 ),
+ undo);
+
+ refreshChart(TQPoint(rect.left(),rect.top()), false, Sheet::ColumnRemove );
+ refreshMergedCell();
+ recalc();
+ emit sig_updateView( this );
+}
+
+bool Sheet::insertColumn( int col, int nbCol, bool makeUndo )
+{
+ UndoInsertColumn * undo = 0;
+ if ( !doc()->undoLocked() && makeUndo)
+ {
+ undo = new UndoInsertColumn( doc(), this, col, nbCol );
+ doc()->addCommand( undo );
+ }
+
+ bool res=true;
+ bool result;
+ for( int i=0; i<=nbCol; i++ )
+ {
+ // Recalculate range max (minus size of last column)
+ d->sizeMaxX -= columnFormat( KS_colMax )->dblWidth();
+
+ result = d->cells.insertColumn( col );
+ d->columns.insertColumn( col );
+ if(!result)
+ res = false;
+
+ //Recalculate range max (plus size of new column)
+ d->sizeMaxX += columnFormat( col+i )->dblWidth();
+ }
+
+ TQPtrListIterator<Sheet> it( workbook()->sheetList() );
+ for( ; it.current(); ++it )
+ it.current()->changeNameCellRef( TQPoint( col, 1 ), true,
+ Sheet::ColumnInsert, name(),
+ nbCol + 1, undo );
+
+ //update print settings
+ d->print->insertColumn( col, nbCol );
+
+ refreshChart( TQPoint( col, 1 ), true, Sheet::ColumnInsert );
+ refreshMergedCell();
+ recalc();
+ emit sig_updateHBorder( this );
+ emit sig_updateView( this );
+
+ return res;
+}
+
+bool Sheet::insertRow( int row, int nbRow, bool makeUndo )
+{
+ UndoInsertRow *undo = 0;
+ if ( !doc()->undoLocked() && makeUndo)
+ {
+ undo = new UndoInsertRow( doc(), this, row, nbRow );
+ doc()->addCommand( undo );
+ }
+
+ bool res=true;
+ bool result;
+ for( int i=0; i<=nbRow; i++ )
+ {
+ // Recalculate range max (minus size of last row)
+ d->sizeMaxY -= rowFormat( KS_rowMax )->dblHeight();
+
+ result = d->cells.insertRow( row );
+ d->rows.insertRow( row );
+ if( !result )
+ res = false;
+
+ //Recalculate range max (plus size of new row)
+ d->sizeMaxY += rowFormat( row )->dblHeight();
+ }
+
+ TQPtrListIterator<Sheet> it( workbook()->sheetList() );
+ for( ; it.current(); ++it )
+ it.current()->changeNameCellRef( TQPoint( 1, row ), true,
+ Sheet::RowInsert, name(),
+ nbRow + 1, undo );
+
+ //update print settings
+ d->print->insertRow( row, nbRow );
+
+ refreshChart( TQPoint( 1, row ), true, Sheet::RowInsert );
+ refreshMergedCell();
+ recalc();
+ emit sig_updateVBorder( this );
+ emit sig_updateView( this );
+
+ return res;
+}
+
+void Sheet::removeColumn( int col, int nbCol, bool makeUndo )
+{
+ UndoRemoveColumn *undo = 0;
+ if ( !doc()->undoLocked() && makeUndo)
+ {
+ undo = new UndoRemoveColumn( doc(), this, col, nbCol );
+ doc()->addCommand( undo );
+ }
+
+ for ( int i = 0; i <= nbCol; ++i )
+ {
+ // Recalculate range max (minus size of removed column)
+ d->sizeMaxX -= columnFormat( col )->dblWidth();
+
+ d->cells.removeColumn( col );
+ d->columns.removeColumn( col );
+
+ //Recalculate range max (plus size of new column)
+ d->sizeMaxX += columnFormat( KS_colMax )->dblWidth();
+ }
+
+ TQPtrListIterator<Sheet> it( workbook()->sheetList() );
+ for( ; it.current(); ++it )
+ it.current()->changeNameCellRef( TQPoint( col, 1 ), true,
+ Sheet::ColumnRemove, name(),
+ nbCol + 1, undo );
+
+ //update print settings
+ d->print->removeColumn( col, nbCol );
+
+ refreshChart( TQPoint( col, 1 ), true, Sheet::ColumnRemove );
+ refreshMergedCell();
+ recalc();
+ emit sig_updateHBorder( this );
+ emit sig_updateView( this );
+}
+
+void Sheet::removeRow( int row, int nbRow, bool makeUndo )
+{
+ UndoRemoveRow *undo = 0;
+ if ( !doc()->undoLocked() && makeUndo )
+ {
+ undo = new UndoRemoveRow( doc(), this, row, nbRow );
+ doc()->addCommand( undo );
+ }
+
+ for( int i=0; i<=nbRow; i++ )
+ {
+ // Recalculate range max (minus size of removed row)
+ d->sizeMaxY -= rowFormat( row )->dblHeight();
+
+ d->cells.removeRow( row );
+ d->rows.removeRow( row );
+
+ //Recalculate range max (plus size of new row)
+ d->sizeMaxY += rowFormat( KS_rowMax )->dblHeight();
+ }
+
+ TQPtrListIterator<Sheet> it( workbook()->sheetList() );
+ for( ; it.current(); ++it )
+ it.current()->changeNameCellRef( TQPoint( 1, row ), true,
+ Sheet::RowRemove, name(),
+ nbRow + 1, undo );
+
+ //update print settings
+ d->print->removeRow( row, nbRow );
+
+ refreshChart( TQPoint( 1, row ), true, Sheet::RowRemove );
+ refreshMergedCell();
+ recalc();
+ emit sig_updateVBorder( this );
+ emit sig_updateView( this );
+}
+
+void Sheet::hideRow(const Region& region)
+{
+ HideShowManipulator* manipulator = new HideShowManipulator();
+ manipulator->setSheet(this);
+ manipulator->setManipulateRows(true);
+ manipulator->add(region);
+ manipulator->execute();
+}
+
+void Sheet::emitHideRow()
+{
+ emit sig_updateVBorder( this );
+ emit sig_updateView( this );
+}
+
+void Sheet::showRow(const Region& region)
+{
+ HideShowManipulator* manipulator = new HideShowManipulator();
+ manipulator->setSheet(this);
+ manipulator->setManipulateRows(true);
+ manipulator->setReverse(true);
+ manipulator->add(region);
+ manipulator->execute();
+}
+
+
+void Sheet::hideColumn(const Region& region)
+{
+ HideShowManipulator* manipulator = new HideShowManipulator();
+ manipulator->setSheet(this);
+ manipulator->setManipulateColumns(true);
+ manipulator->add(region);
+ manipulator->execute();
+}
+
+void Sheet::emitHideColumn()
+{
+ emit sig_updateHBorder( this );
+ emit sig_updateView( this );
+}
+
+void Sheet::showColumn(const Region& region)
+{
+ HideShowManipulator* manipulator = new HideShowManipulator();
+ manipulator->setSheet(this);
+ manipulator->setManipulateColumns(true);
+ manipulator->setReverse(true);
+ manipulator->add(region);
+ manipulator->execute();
+}
+
+
+void Sheet::refreshChart(const TQPoint & pos, bool fullRowOrColumn, ChangeRef ref)
+{
+ Cell * c = d->cells.firstCell();
+ for( ;c; c = c->nextCell() )
+ {
+ if ( (ref == ColumnInsert || ref == ColumnRemove) && fullRowOrColumn
+ && c->column() >= (pos.x() - 1))
+ {
+ if (c->updateChart())
+ return;
+ }
+ else if ( (ref == ColumnInsert || ref == ColumnRemove )&& !fullRowOrColumn
+ && c->column() >= (pos.x() - 1) && c->row() == pos.y() )
+ {
+ if (c->updateChart())
+ return;
+ }
+ else if ((ref == RowInsert || ref == RowRemove) && fullRowOrColumn
+ && c->row() >= (pos.y() - 1))
+ {
+ if (c->updateChart())
+ return;
+ }
+ else if ( (ref == RowInsert || ref == RowRemove) && !fullRowOrColumn
+ && c->column() == pos.x() && c->row() >= (pos.y() - 1) )
+ {
+ if (c->updateChart())
+ return;
+ }
+ }
+
+ //refresh chart when there is a chart and you remove
+ //all cells
+ if (c == 0L)
+ {
+ CellBinding * bind;
+ for ( bind = firstCellBinding(); bind != 0L; bind = nextCellBinding() )
+ {
+ bind->cellChanged( 0 );
+ }
+ // CellBinding * bind = firstCellBinding();
+ // if ( bind != 0L )
+ // bind->cellChanged( 0 );
+ }
+
+}
+
+void Sheet::refreshMergedCell()
+{
+ Cell* c = d->cells.firstCell();
+ for( ;c; c = c->nextCell() )
+ {
+ if(c->doesMergeCells())
+ c->mergeCells( c->column(), c->row(), c->extraXCells(), c->extraYCells() );
+ }
+}
+
+
+void Sheet::changeNameCellRef( const TQPoint & pos, bool fullRowOrColumn,
+ ChangeRef ref, TQString tabname, int nbCol,
+ UndoInsertRemoveAction * undo )
+{
+ bool correctDefaultSheetName = (tabname == name()); // for cells without sheet ref (eg "A1")
+ Cell* c = d->cells.firstCell();
+ for( ;c; c = c->nextCell() )
+ {
+ if( c->isFormula() )
+ {
+ TQString origText = c->text();
+ unsigned int i = 0;
+ bool error = false;
+ TQString newText;
+
+ bool correctSheetName = correctDefaultSheetName;
+ //bool previousCorrectSheetName = false;
+ TQChar origCh;
+ for ( ; i < origText.length(); ++i )
+ {
+ origCh = origText[i];
+ if ( origCh != ':' && origCh != '$' && !origCh.isLetter() )
+ {
+ newText += origCh;
+ // Reset the "correct table indicator"
+ correctSheetName = correctDefaultSheetName;
+ }
+ else // Letter or dollar : maybe start of cell name/range
+ // (or even ':', like in a range - note that correctSheet is kept in this case)
+ {
+ // Collect everything that forms a name (cell name or sheet name)
+ TQString str;
+ bool sheetNameFound = false; //Sheet names need spaces
+ for( ; ( i < origText.length() ) && // until the end
+ ( ( origText[i].isLetter() || origText[i].isDigit() || origText[i] == '$' ) || // all text and numbers are welcome
+ ( sheetNameFound && origText[i].isSpace() ) ) //in case of a sheet name, we include spaces too
+ ; ++i )
+ {
+ str += origText[i];
+ if ( origText[i] == '!' )
+ sheetNameFound = true;
+ }
+ // Was it a sheet name ?
+ if ( origText[i] == '!' )
+ {
+ newText += str + '!'; // Copy it (and the '!')
+ // Look for the sheet name right before that '!'
+ correctSheetName = ( newText.right( tabname.length()+1 ) == tabname+"!" );
+ }
+ else // It must be a cell identifier
+ {
+ // Parse it
+ Point point( str );
+ if ( point.isValid() )
+ {
+ int col = point.pos().x();
+ int row = point.pos().y();
+ TQString newPoint;
+
+ // Update column
+ if ( point.columnFixed() )
+ newPoint = '$';
+
+ if( ref == ColumnInsert
+ && correctSheetName
+ && col + nbCol <= KS_colMax
+ && col >= pos.x() // Column after the new one : +1
+ && ( fullRowOrColumn || row == pos.y() ) ) // All rows or just one
+ {
+ newPoint += Cell::columnName( col + nbCol );
+ }
+ else if( ref == ColumnRemove
+ && correctSheetName
+ && col > pos.x() // Column after the deleted one : -1
+ && ( fullRowOrColumn || row == pos.y() ) ) // All rows or just one
+ {
+ newPoint += Cell::columnName( col - nbCol );
+ }
+ else
+ newPoint += Cell::columnName( col );
+
+ // Update row
+ if ( point.rowFixed() )
+ newPoint += '$';
+
+ if( ref == RowInsert
+ && correctSheetName
+ && row + nbCol <= KS_rowMax
+ && row >= pos.y() // Row after the new one : +1
+ && ( fullRowOrColumn || col == pos.x() ) ) // All columns or just one
+ {
+ newPoint += TQString::number( row + nbCol );
+ }
+ else if( ref == RowRemove
+ && correctSheetName
+ && row > pos.y() // Row after the deleted one : -1
+ && ( fullRowOrColumn || col == pos.x() ) ) // All columns or just one
+ {
+ newPoint += TQString::number( row - nbCol );
+ }
+ else
+ newPoint += TQString::number( row );
+
+ if( correctSheetName &&
+ ( ( ref == ColumnRemove
+ && col == pos.x() // Column is the deleted one : error
+ && ( fullRowOrColumn || row == pos.y() ) ) ||
+ ( ref == RowRemove
+ && row == pos.y() // Row is the deleted one : error
+ && ( fullRowOrColumn || col == pos.x() ) ) ||
+ ( ref == ColumnInsert
+ && col + nbCol > KS_colMax
+ && col >= pos.x() // Column after the new one : +1
+ && ( fullRowOrColumn || row == pos.y() ) ) ||
+ ( ref == RowInsert
+ && row + nbCol > KS_rowMax
+ && row >= pos.y() // Row after the new one : +1
+ && ( fullRowOrColumn || col == pos.x() ) ) ) )
+ {
+ newPoint = "#" + i18n("Dependency") + "!";
+ error = true;
+ }
+
+ newText += newPoint;
+ }
+ else // Not a cell ref
+ {
+ kdDebug(36001) << "Copying (unchanged) : '" << str << "'" << endl;
+ newText += str;
+ }
+ // Copy the char that got us to stop
+ if ( i < origText.length() ) {
+ newText += origText[i];
+ if( origText[i] != ':' )
+ correctSheetName = correctDefaultSheetName;
+ }
+ }
+ }
+ }
+
+ if ( error && undo != 0 ) //Save the original formula, as we cannot calculate the undo of broken formulas
+ {
+ TQString formulaText = c->text();
+ int origCol = c->column();
+ int origRow = c->row();
+
+ if ( ref == ColumnInsert && origCol >= pos.x() )
+ origCol -= nbCol;
+ if ( ref == RowInsert && origRow >= pos.y() )
+ origRow -= nbCol;
+
+ if ( ref == ColumnRemove && origCol >= pos.x() )
+ origCol += nbCol;
+ if ( ref == RowRemove && origRow >= pos.y() )
+ origRow += nbCol;
+
+ undo->saveFormulaReference( this, origCol, origRow, formulaText );
+ }
+
+ c->setCellText( newText );
+ }
+ }
+}
+
+#if 0
+void Sheet::replace( const TQString &_find, const TQString &_replace, long options,
+ Canvas *canvas )
+{
+ Selection* selectionInfo = canvas->view()->selectionInfo();
+
+ // Identify the region of interest.
+ TQRect region( selectionInfo->selection() );
+ TQPoint marker( selectionInfo->marker() );
+
+ if (options & KReplaceDialog::SelectedText)
+ {
+
+ // Complete rows selected ?
+ if ( util_isRowSelected(region) )
+ {
+ }
+ // Complete columns selected ?
+ else if ( util_isColumnSelected(region) )
+ {
+ }
+ }
+ else
+ {
+ // All cells.
+ region.setCoords( 1, 1, d->maxRow, d->maxColumn );
+ }
+
+ // Create the class that handles all the actual replace stuff, and connect it to its
+ // local slots.
+ KReplace dialog( _find, _replace, options );
+ TQObject::connect(
+ &dialog, TQT_SIGNAL( highlight( const TQString &, int, int, const TQRect & ) ),
+ canvas, TQT_SLOT( highlight( const TQString &, int, int, const TQRect & ) ) );
+ TQObject::connect(
+ &dialog, TQT_SIGNAL( replace( const TQString &, int, int,int, const TQRect & ) ),
+ canvas, TQT_SLOT( replace( const TQString &, int, int,int, const TQRect & ) ) );
+
+ // Now do the replacing...
+ if ( !doc()->undoLocked() )
+ {
+ UndoChangeAreaTextCell *undo = new UndoChangeAreaTextCell( doc(), this, region );
+ doc()->addCommand( undo );
+ }
+
+ TQRect cellRegion( 0, 0, 0, 0 );
+ bool bck = options & KFindDialog::FindBackwards;
+
+ int colStart = !bck ? region.left() : region.right();
+ int colEnd = !bck ? region.right() : region.left();
+ int rowStart = !bck ? region.top() :region.bottom();
+ int rowEnd = !bck ? region.bottom() : region.top();
+ if ( options & KFindDialog::FromCursor ) {
+ colStart = marker.x();
+ rowStart = marker.y();
+ }
+ Cell *cell;
+ for (int row = rowStart ; !bck ? row < rowEnd : row > rowEnd ; !bck ? ++row : --row )
+ {
+ for(int col = colStart ; !bck ? col < colEnd : col > colEnd ; !bck ? ++col : --col )
+ {
+ cell = cellAt( col, row );
+ if ( !cell->isDefault() && !cell->isObscured() && !cell->isFormula() )
+ {
+ TQString text = cell->text();
+ cellRegion.setTop( row );
+ cellRegion.setLeft( col );
+ if (!dialog.replace( text, cellRegion ))
+ return;
+ }
+ }
+ }
+}
+#endif
+
+void Sheet::borderBottom( Selection* selectionInfo, const TQColor &_color )
+{
+ BorderManipulator* manipulator = new BorderManipulator();
+ manipulator->setSheet(this);
+ manipulator->setBottomBorderPen(TQPen(_color, 1, TQt::SolidLine));
+ manipulator->add(*selectionInfo);
+ manipulator->execute();
+}
+
+void Sheet::borderRight( Selection* selectionInfo, const TQColor &_color )
+{
+ BorderManipulator* manipulator = new BorderManipulator();
+ manipulator->setSheet(this);
+ manipulator->setRightBorderPen(TQPen(_color, 1, TQt::SolidLine));
+ manipulator->add(*selectionInfo);
+ manipulator->execute();
+}
+
+void Sheet::borderLeft( Selection* selectionInfo, const TQColor &_color )
+{
+ BorderManipulator* manipulator = new BorderManipulator();
+ manipulator->setSheet(this);
+ manipulator->setLeftBorderPen(TQPen(_color, 1, TQt::SolidLine));
+ manipulator->add(*selectionInfo);
+ manipulator->execute();
+}
+
+void Sheet::borderTop( Selection* selectionInfo, const TQColor &_color )
+{
+ BorderManipulator* manipulator = new BorderManipulator();
+ manipulator->setSheet(this);
+ manipulator->setTopBorderPen(TQPen(_color, 1, TQt::SolidLine));
+ manipulator->add(*selectionInfo);
+ manipulator->execute();
+}
+
+void Sheet::borderOutline( Selection* selectionInfo, const TQColor &_color )
+{
+ BorderManipulator* manipulator = new BorderManipulator();
+ manipulator->setSheet(this);
+ manipulator->setTopBorderPen(TQPen(_color, 1, TQt::SolidLine));
+ manipulator->setBottomBorderPen(TQPen(_color, 1, TQt::SolidLine));
+ manipulator->setLeftBorderPen(TQPen(_color, 1, TQt::SolidLine));
+ manipulator->setRightBorderPen(TQPen(_color, 1, TQt::SolidLine));
+ manipulator->add(*selectionInfo);
+ manipulator->execute();
+}
+
+void Sheet::borderAll( Selection * selectionInfo,
+ const TQColor & _color )
+{
+ BorderManipulator* manipulator = new BorderManipulator();
+ manipulator->setSheet(this);
+ manipulator->setTopBorderPen(TQPen(_color, 1, TQt::SolidLine));
+ manipulator->setBottomBorderPen(TQPen(_color, 1, TQt::SolidLine));
+ manipulator->setLeftBorderPen(TQPen(_color, 1, TQt::SolidLine));
+ manipulator->setRightBorderPen(TQPen(_color, 1, TQt::SolidLine));
+ manipulator->setHorizontalPen(TQPen(_color, 1, TQt::SolidLine));
+ manipulator->setVerticalPen(TQPen(_color, 1, TQt::SolidLine));
+ manipulator->add(*selectionInfo);
+ manipulator->execute();
+}
+
+void Sheet::borderRemove( Selection* selectionInfo )
+{
+ BorderManipulator* manipulator = new BorderManipulator();
+ manipulator->setSheet(this);
+ manipulator->setTopBorderPen(TQPen(TQt::NoPen));
+ manipulator->setBottomBorderPen(TQPen(TQt::NoPen));
+ manipulator->setLeftBorderPen(TQPen(TQt::NoPen));
+ manipulator->setRightBorderPen(TQPen(TQt::NoPen));
+ manipulator->setHorizontalPen(TQPen(TQt::NoPen));
+ manipulator->setVerticalPen(TQPen(TQt::NoPen));
+ manipulator->add(*selectionInfo);
+ manipulator->execute();
+}
+
+
+void Sheet::sortByRow( const TQRect &area, int ref_row, SortingOrder mode )
+{
+ Point point;
+ point.setSheet(this);
+ point.setSheetName (d->name);
+ point.setPos(area.topLeft());
+ point.setColumnFixed(false);
+ point.setRowFixed(false);
+
+ sortByRow( area, ref_row, 0, 0, mode, mode, mode, 0, false, false, point,true );
+}
+
+void Sheet::sortByColumn( const TQRect &area, int ref_column, SortingOrder mode )
+{
+ Point point;
+ point.setSheet(this);
+ point.setSheetName(d->name);
+ point.setPos(area.topLeft());
+ point.setColumnFixed(false);
+ point.setRowFixed(false);
+
+ sortByColumn( area, ref_column, 0, 0, mode, mode, mode, 0, false, false,
+ point,true );
+}
+
+void Sheet::checkCellContent(Cell * cell1, Cell * cell2, int & ret)
+{
+ if ( cell1->isEmpty() )
+ {
+ ret = 1;
+ return;
+ }
+ else if ( cell1->isObscured() && cell1->isPartOfMerged() )
+ {
+ ret = 1;
+ return;
+ }
+ else if ( cell2->isEmpty() )
+ {
+ ret = 2;
+ return;
+ }
+ ret = 0;
+}
+
+void Sheet::sortByRow( const TQRect &area, int key1, int key2, int key3,
+ SortingOrder order1, SortingOrder order2,
+ SortingOrder order3,
+ TQStringList const * firstKey, bool copyFormat,
+ bool headerRow, Point const & outputPoint, bool respectCase )
+{
+ TQRect r( area );
+ Map::respectCase = respectCase;
+ Q_ASSERT( order1 == Increase || order1 == Decrease );
+
+ // It may not happen that entire columns are selected.
+ Q_ASSERT( util_isColumnSelected(r) == false );
+
+ // Are entire rows selected ?
+ if ( util_isRowSelected(r) )
+ {
+ r.setLeft( KS_colMax );
+ r.setRight( 0 );
+
+ // Determine a correct left and right.
+ // Iterate over all cells to find out which cells are
+ // located in the selected rows.
+ for ( int row = r.top(); row <= r.bottom(); ++row )
+ {
+ Cell * c = getFirstCellRow( row );
+ int col;
+ while ( c )
+ {
+ col = c->column();
+ if ( !c->isEmpty() )
+ {
+ if ( col > r.right() )
+ r.rRight() = col;
+ if ( col < r.left() )
+ r.rLeft() = col;
+ }
+ c = getNextCellRight( col, row );
+ }
+ }
+
+ // Any cells to sort here ?
+ if ( r.right() < r.left() )
+ {
+ Map::respectCase = true;
+ return;
+ }
+ }
+
+ TQRect target( outputPoint.pos().x(), outputPoint.pos().y(), r.width(), r.height() );
+
+ doc()->emitBeginOperation();
+
+ if ( !doc()->undoLocked() )
+ {
+ UndoSort *undo = new UndoSort( doc(), this, target );
+ doc()->addCommand( undo );
+ }
+
+ if (target.topLeft() != r.topLeft())
+ {
+ int targetLeft = target.left();
+ int targetTop = target.top();
+ int sourceTop = r.top();
+ int sourceLeft = r.left();
+
+ key1 = key1 - sourceTop + targetTop;
+ key2 = key2 - sourceTop + targetTop;
+ key3 = key3 - sourceTop + targetTop;
+
+ for ( int x = 0; x < r.width(); ++x)
+ {
+ for ( int y = 0; y < r.height(); ++y )
+ {
+ // from - to
+ copyCells( sourceLeft + x, sourceTop + y,
+ targetLeft + x, targetTop + y, copyFormat );
+ }
+ }
+ }
+
+ // Sorting algorithm: David's :). Well, I guess it's called minmax or so.
+ // For each column, we look for all cells right hand of it and we find the one to swap with it.
+ // Much faster than the awful bubbleSort...
+ Cell * cell;
+ Cell * cell1;
+ Cell * cell2;
+ Cell * bestCell;
+ int status = 0;
+
+ for ( int d = target.left(); d <= target.right(); ++d )
+ {
+ cell1 = cellAt( d, key1 );
+ if ( cell1->isObscured() && cell1->isPartOfMerged() )
+ {
+ Cell* obscuring = cell1->obscuringCells().first();
+ cell = cellAt( obscuring->column(), key1 );
+ cell1 = cellAt( obscuring->column() + cell->extraXCells() + 1,
+ obscuring->column());
+ d = obscuring->column() + cell->extraXCells() + 1;
+ }
+
+ // Look for which column we want to swap with the one number d
+ bestCell = cell1;
+ int bestX = d;
+ for ( int x = d + 1 ; x <= target.right(); x++ )
+ {
+ cell2 = cellAt( x, key1 );
+
+ checkCellContent(cell2, bestCell, status);
+ if (status == 1)
+ continue;
+ else if (status == 2)
+ {
+ // empty cells are always shifted to the end
+ bestCell = cell2;
+ bestX = x;
+ continue;
+ }
+
+ if ( firstKey )
+ {
+ int i1 = firstKey->findIndex( cell2->text() );
+ int i2 = firstKey->findIndex( bestCell->text() );
+
+ if ( i1 != -1 && i2 != -1 )
+ {
+ if ( (order1 == Increase && i1 < i2 )
+ || (order1 == Decrease && i1 > i2) )
+ {
+ bestCell = cell2;
+ bestX = x;
+ continue;
+ }
+
+ if ( i1 == i2 )
+ {
+ // check 2nd key
+ if (key2 <= 0)
+ continue;
+
+ Cell * cell22 = cellAt( x, key2 );
+ Cell * bestCell2 = cellAt( bestX, key2 );
+
+ if ( cell22->isEmpty() )
+ {
+ /* No need to swap */
+ continue;
+ }
+ else if ( cell22->isObscured() && cell22->isPartOfMerged() )
+ {
+ /* No need to swap */
+ continue;
+ }
+ else if ( bestCell2->isEmpty() )
+ {
+ // empty cells are always shifted to the end
+ bestCell = cell2;
+ bestX = x;
+ continue;
+ }
+
+ if ( (order2 == Increase && *cell22 < *bestCell2)
+ || (order2 == Decrease && *cell22 > *bestCell2) )
+ {
+ bestCell = cell2;
+ bestX = x;
+ continue;
+ }
+ else if ( (order2 == Increase && *cell22 > *bestCell2)
+ || (order2 == Decrease && *cell22 < *bestCell2) )
+ {
+ // already in right order
+ continue;
+ }
+ else
+ {
+ // they are equal, check 3rd key
+ if (key3 <= 0)
+ continue;
+
+ Cell * cell23 = cellAt( x, key3 );
+ Cell * bestCell3 = cellAt( bestX, key3 );
+
+ if ( cell23->isEmpty() )
+ {
+ /* No need to swap */
+ continue;
+ }
+ else if ( cell23->isObscured() && cell23->isPartOfMerged() )
+ {
+ /* No need to swap */
+ continue;
+ }
+ else if ( bestCell3->isEmpty() )
+ {
+ // empty cells are always shifted to the end
+ bestCell = cell2;
+ bestX = x;
+ continue;
+ }
+ if ( (order3 == Increase && *cell23 < *bestCell3)
+ || (order3 == Decrease && *cell23 > *bestCell3) )
+ {
+ // they are really equal or in the right order
+ // no swap necessary
+ continue;
+ }
+ else
+ {
+ bestCell = cell2;
+ bestX = x;
+ continue;
+ }
+ }
+ }
+ continue;
+ }
+ else if ( i1 != -1 && i2 == -1 )
+ {
+ // if not in the key list, the cell is shifted to the end - always
+ bestCell = cell2;
+ bestX = x;
+ continue;
+ }
+ else if ( i2 != -1 && i1 == -1 )
+ {
+ // only text of cell2 is in the list so it is smaller than bestCell
+ /* No need to swap */
+ continue;
+ }
+
+ // if i1 and i2 are equals -1 go on:
+ } // end if (firstKey)
+
+ // Here we use the operators < and > for cells, which do it all.
+ if ( (order1 == Increase && *cell2 < *bestCell)
+ || (order1 == Decrease && *cell2 > *bestCell) )
+ {
+ bestCell = cell2;
+ bestX = x;
+ continue;
+ }
+ else if ( (order1 == Increase && *cell2 > *bestCell)
+ || (order1 == Decrease && *cell2 < *bestCell) )
+ {
+ // no change necessary
+ continue;
+ }
+ else
+ {
+ // *cell2 equals *bestCell
+ // check 2nd key
+ if (key2 <= 0)
+ continue;
+ Cell * cell22 = cellAt( d, key2 );
+ Cell * bestCell2 = cellAt( x, key2 );
+
+ checkCellContent(cell2, bestCell, status);
+ if (status == 1)
+ continue;
+ else if (status == 2)
+ {
+ // empty cells are always shifted to the end
+ bestCell = cell2;
+ bestX = x;
+ continue;
+ }
+
+ if ( (order2 == Increase && *cell22 > *bestCell2)
+ || (order2 == Decrease && *cell22 < *bestCell2) )
+ {
+ bestCell = cell2;
+ bestX = x;
+ continue;
+ }
+ else
+ if ( (order2 == Increase && *cell22 > *bestCell2)
+ || (order2 == Decrease && *cell22 < *bestCell2) )
+ {
+ // already in right order
+ continue;
+ }
+ else
+ {
+ // they are equal, check 3rd key
+ if (key3 == 0)
+ continue;
+ Cell * cell23 = cellAt( d, key3 );
+ Cell * bestCell3 = cellAt( x, key3 );
+
+ checkCellContent(cell2, bestCell, status);
+ if (status == 1)
+ continue;
+ else if (status == 2)
+ {
+ // empty cells are always shifted to the end
+ bestCell = cell2;
+ bestX = x;
+ continue;
+ }
+ if ( (order3 == Increase && *cell23 > *bestCell3)
+ || (order3 == Decrease && *cell23 < *bestCell3) )
+ {
+ bestCell = cell2;
+ bestX = x;
+ continue;
+ }
+ else
+ {
+ // they are really equal
+ // no swap necessary
+ continue;
+ }
+ }
+ }
+ }
+
+ // Swap columns cell1 and bestCell (i.e. d and bestX)
+ if ( d != bestX )
+ {
+ int top = target.top();
+ if (headerRow)
+ ++top;
+
+ for( int y = target.bottom(); y >= top; --y )
+ {
+ if ( y != key1 && y != key2 && y != key3 )
+ swapCells( d, y, bestX, y, copyFormat );
+ }
+ if (key3 > 0)
+ swapCells( d, key3, bestX, key3, copyFormat );
+ if (key2 > 0)
+ swapCells( d, key2, bestX, key2, copyFormat );
+ swapCells( d, key1, bestX, key1, copyFormat );
+ }
+ } // for (d = ...; ...; ++d)
+ Map::respectCase = true;
+ // doc()->emitEndOperation();
+ emit sig_updateView( this );
+}
+
+void Sheet::sortByColumn( const TQRect &area, int key1, int key2, int key3,
+ SortingOrder order1, SortingOrder order2,
+ SortingOrder order3,
+ TQStringList const * firstKey, bool copyFormat,
+ bool headerRow,
+ Point const & outputPoint, bool respectCase )
+{
+ TQRect r( area );
+ Map::respectCase = respectCase;
+
+ Q_ASSERT( order1 == Increase || order1 == Decrease );
+
+ // It may not happen that entire rows are selected.
+ Q_ASSERT( util_isRowSelected(r) == false );
+
+ // Are entire columns selected ?
+ if ( util_isColumnSelected(r) )
+ {
+ r.setTop( KS_rowMax );
+ r.setBottom( 0 );
+
+ // Determine a correct top and bottom.
+ // Iterate over all cells to find out which cells are
+ // located in the selected columns.
+ for ( int col = r.left(); col <= r.right(); ++col )
+ {
+ Cell * c = getFirstCellColumn( col );
+ int row;
+ while ( c )
+ {
+ row = c->row();
+ if ( !c->isEmpty() )
+ {
+ if ( row > r.bottom() )
+ r.rBottom() = row;
+ if ( row < r.top() )
+ r.rTop() = row;
+ }
+ c = getNextCellDown( col, row );
+ }
+ }
+
+ // Any cells to sort here ?
+ if ( r.bottom() < r.top() )
+ {
+ Map::respectCase = true;
+ return;
+ }
+ }
+ TQRect target( outputPoint.pos().x(), outputPoint.pos().y(), r.width(), r.height() );
+
+ if ( !doc()->undoLocked() )
+ {
+ UndoSort *undo = new UndoSort( doc(), this, target );
+ doc()->addCommand( undo );
+ }
+
+ doc()->emitBeginOperation();
+
+ if (target.topLeft() != r.topLeft())
+ {
+ int targetLeft = target.left();
+ int targetTop = target.top();
+ int sourceTop = r.top();
+ int sourceLeft = r.left();
+
+ key1 = key1 - sourceLeft + targetLeft;
+ key2 = key2 - sourceLeft + targetLeft;
+ key3 = key3 - sourceLeft + targetLeft;
+
+ for ( int x = 0; x < r.width(); ++x)
+ {
+ for ( int y = 0; y < r.height(); ++y )
+ {
+ // from - to
+ copyCells( sourceLeft + x, sourceTop + y,
+ targetLeft + x, targetTop + y, copyFormat );
+ }
+ }
+ }
+
+ // Sorting algorithm: David's :). Well, I guess it's called minmax or so.
+ // For each row, we look for all rows under it and we find the one to swap with it.
+ // Much faster than the awful bubbleSort...
+ // Torben: Asymptotically it is alltogether O(n^2) :-)
+
+ Cell * cell;
+ Cell * cell1;
+ Cell * cell2;
+ Cell * bestCell;
+ int status = 0;
+
+ int d = target.top();
+
+ if (headerRow)
+ ++d;
+
+ for ( ; d <= target.bottom(); ++d )
+ {
+ // Look for which row we want to swap with the one number d
+ cell1 = cellAt( key1, d );
+ if ( cell1->isObscured() && cell1->isPartOfMerged() )
+ {
+ Cell* obscuring = cell1->obscuringCells().first();
+ cell = cellAt( key1, obscuring->row() );
+ cell1 = cellAt( key1, obscuring->row() + cell->extraYCells() + 1 );
+ d = obscuring->row() + cell->extraYCells() + 1;
+ }
+
+ bestCell = cell1;
+ int bestY = d;
+
+ for ( int y = d + 1 ; y <= target.bottom(); ++y )
+ {
+ cell2 = cellAt( key1, y );
+
+ if ( cell2->isEmpty() )
+ {
+ /* No need to swap */
+ continue;
+ }
+ else if ( cell2->isObscured() && cell2->isPartOfMerged() )
+ {
+ /* No need to swap */
+ continue;
+ }
+ else if ( bestCell->isEmpty() )
+ {
+ // empty cells are always shifted to the end
+ bestCell = cell2;
+ bestY = y;
+ continue;
+ }
+
+ if ( firstKey )
+ {
+ int i1 = firstKey->findIndex( cell2->text() );
+ int i2 = firstKey->findIndex( bestCell->text() );
+
+ if ( i1 != -1 && i2 != -1 )
+ {
+ if ( (order1 == Increase && i1 < i2 )
+ || (order1 == Decrease && i1 > i2) )
+ {
+ bestCell = cell2;
+ bestY = y;
+ continue;
+ }
+
+ if ( i1 == i2 )
+ {
+ // check 2nd key
+ if (key2 <= 0)
+ continue;
+ Cell * cell22 = cellAt( key2, d );
+ Cell * bestCell2 = cellAt( key2, y );
+
+ if ( cell22->isEmpty() )
+ {
+ /* No need to swap */
+ continue;
+ }
+ else if ( cell22->isObscured() && cell22->isPartOfMerged() )
+ {
+ /* No need to swap */
+ continue;
+ }
+ else if ( bestCell2->isEmpty() )
+ {
+ // empty cells are always shifted to the end
+ bestCell = cell2;
+ bestY = y;
+ continue;
+ }
+
+ if ( (order2 == Increase && *cell22 > *bestCell2)
+ || (order2 == Decrease && *cell22 < *bestCell2) )
+ {
+ bestCell = cell2;
+ bestY = y;
+ continue;
+ }
+ else if ( (order2 == Increase && *cell22 < *bestCell2)
+ || (order2 == Decrease && *cell22 > *bestCell2) )
+ {
+ // already in right order
+ continue;
+ }
+ else
+ {
+ // they are equal, check 3rd key
+ if (key3 <= 0)
+ continue;
+ Cell * cell23 = cellAt( key3, d );
+ Cell * bestCell3 = cellAt( key3, y );
+
+ checkCellContent(cell2, bestCell, status);
+ if (status == 1)
+ continue;
+ else if (status == 2)
+ {
+ // empty cells are always shifted to the end
+ bestCell = cell2;
+ bestY = y;
+ continue;
+ }
+
+ if ( (order3 == Increase && *cell23 < *bestCell3)
+ || (order3 == Decrease && *cell23 > *bestCell3) )
+ {
+ bestCell = cell2;
+ bestY = y;
+ continue;
+ }
+ else
+ {
+ // they are really equal or in the correct order
+ // no swap necessary
+ continue;
+ }
+ }
+ }
+ continue;
+ }
+ else if ( i1 != -1 && i2 == -1 )
+ {
+ // if not in the key list, the cell is shifted to the end - always
+ bestCell = cell2;
+ bestY = y;
+ continue;
+ }
+ else if ( i2 != -1 && i1 == -1 )
+ {
+ // only text of cell2 is in the list so it is smaller than bestCell
+ /* No need to swap */
+ continue;
+ }
+
+ // if i1 and i2 are equals -1 go on:
+ } // if (firstKey)
+
+
+ // Here we use the operators < and > for cells, which do it all.
+ if ( (order1 == Increase && *cell2 < *bestCell)
+ || (order1 == Decrease && *cell2 > *bestCell) )
+ {
+ bestCell = cell2;
+ bestY = y;
+ }
+ else if ( (order1 == Increase && *cell2 > *bestCell)
+ || (order1 == Decrease && *cell2 < *bestCell) )
+ {
+ // no change necessary
+ continue;
+ }
+ else
+ {
+ // *cell2 equals *bestCell
+ // check 2nd key
+ if (key2 == 0)
+ continue;
+ Cell * cell22 = cellAt( key2, y );
+ Cell * bestCell2 = cellAt( key2, bestY );
+
+ if ( cell22->isEmpty() )
+ {
+ /* No need to swap */
+ continue;
+ }
+ else if ( cell22->isObscured() && cell22->isPartOfMerged() )
+ {
+ /* No need to swap */
+ continue;
+ }
+ else if ( bestCell2->isEmpty() )
+ {
+ // empty cells are always shifted to the end
+ bestCell = cell2;
+ bestY = y;
+ continue;
+ }
+
+ if ( (order2 == Increase && *cell22 < *bestCell2)
+ || (order2 == Decrease && *cell22 > *bestCell2) )
+ {
+ bestCell = cell2;
+ bestY = y;
+ continue;
+ }
+ else if ( (order2 == Increase && *cell22 > *bestCell2)
+ || (order2 == Decrease && *cell22 < *bestCell2) )
+ {
+ continue;
+ }
+ else
+ {
+ // they are equal, check 3rd key
+ if (key3 == 0)
+ continue;
+ Cell * cell23 = cellAt( key3, y );
+ Cell * bestCell3 = cellAt( key3, bestY );
+
+ if ( cell23->isEmpty() )
+ {
+ /* No need to swap */
+ continue;
+ }
+ else if ( cell23->isObscured() && cell23->isPartOfMerged() )
+ {
+ /* No need to swap */
+ continue;
+ }
+ else if ( bestCell3->isEmpty() )
+ {
+ // empty cells are always shifted to the end
+ bestCell = cell2;
+ bestY = y;
+ continue;
+ }
+
+ if ( (order3 == Increase && *cell23 < *bestCell3)
+ || (order3 == Decrease && *cell23 > *bestCell3) )
+ {
+ bestCell = cell2;
+ bestY = y;
+ continue;
+ }
+ else
+ {
+ // they are really equal or already in the correct order
+ // no swap necessary
+ continue;
+ }
+ }
+ }
+ }
+
+ // Swap rows cell1 and bestCell (i.e. d and bestY)
+ if ( d != bestY )
+ {
+ for (int x = target.left(); x <= target.right(); ++x)
+ {
+ if ( x != key1 && x != key2 && x != key3)
+ swapCells( x, d, x, bestY, copyFormat );
+ }
+ if (key3 > 0)
+ swapCells( key3, d, key3, bestY, copyFormat );
+ if (key2 > 0)
+ swapCells( key2, d, key2, bestY, copyFormat );
+ swapCells( key1, d, key1, bestY, copyFormat );
+ }
+ } // for (d = ...; ...; ++d)
+ // doc()->emitEndOperation();
+ Map::respectCase = true;
+ emit sig_updateView( this );
+}
+
+// from - to - copyFormat
+void Sheet::copyCells( int x1, int y1, int x2, int y2, bool cpFormat )
+{
+ Cell * sourceCell = cellAt( x1, y1 );
+ Cell * targetCell = cellAt( x2, y2 );
+
+ if ( sourceCell->isDefault() && targetCell->isDefault())
+ {
+ // if the source and target is default there is nothing to copy
+ return;
+ }
+
+ targetCell = nonDefaultCell(x2, y2);
+
+ // TODO: check if this enough
+ targetCell->copyContent( sourceCell );
+
+ /*
+ if ( !sourceCell->isFormula() )
+ {
+ targetCell->copyContent( sourceCell );
+ }
+ else
+ {
+ targetCell->setCellText( targetCell->decodeFormula( sourceCell->encodeFormula() ) );
+ targetCell->setCalcDirtyFlag();
+ targetCell->calc(false);
+ }
+ */
+
+ if (cpFormat)
+ {
+ targetCell->copyFormat( sourceCell );
+ /*
+ targetCell->setAlign( sourceCell->format()->align( x1, y1 ) );
+ targetCell->setAlignY( sourceCell->format()->alignY( x1, y1 ) );
+ targetCell->setTextFont( sourceCell->format()->textFont( x1, y1 ) );
+ targetCell->setTextColor( sourceCell->textColor( x1, y1 ) );
+ targetCell->setBgColor( sourceCell->bgColor( x1, y1 ) );
+ targetCell->setLeftBorderPen( sourceCell->leftBorderPen( x1, y1 ) );
+ targetCell->setTopBorderPen( sourceCell->topBorderPen( x1, y1 ) );
+ targetCell->setBottomBorderPen( sourceCell->bottomBorderPen( x1, y1 ) );
+ targetCell->setRightBorderPen( sourceCell->rightBorderPen( x1, y1 ) );
+ targetCell->setFallDiagonalPen( sourceCell->fallDiagonalPen( x1, y1 ) );
+ targetCell->setGoUpDiagonalPen( sourceCell->goUpDiagonalPen( x1, y1 ) );
+ targetCell->setBackGroundBrush( sourceCell->backGroundBrush( x1, y1 ) );
+ targetCell->setPrecision( sourceCell->precision( x1, y1 ) );
+ targetCell->format()->setPrefix( sourceCell->prefix( x1, y1 ) );
+ targetCell->format()->setPostfix( sourceCell->postfix( x1, y1 ) );
+ targetCell->setFloatFormat( sourceCell->floatFormat( x1, y1 ) );
+ targetCell->setFloatColor( sourceCell->floatColor( x1, y1 ) );
+ targetCell->setMultiRow( sourceCell->multiRow( x1, y1 ) );
+ targetCell->setVerticalText( sourceCell->verticalText( x1, y1 ) );
+ targetCell->setStyle( sourceCell->style() );
+ targetCell->setDontPrintText( sourceCell->getDontprintText( x1, y1 ) );
+ targetCell->setIndent( sourceCell->getIndent( x1, y1 ) );
+ targetCell->SetConditionList(sourceCell->GetConditionList());
+ targetCell->setComment( sourceCell->comment( x1, y1 ) );
+ targetCell->setAngle( sourceCell->getAngle( x1, y1 ) );
+ targetCell->setFormatType( sourceCell->getFormatType( x1, y1 ) );
+ */
+ }
+}
+
+void Sheet::swapCells( int x1, int y1, int x2, int y2, bool cpFormat )
+{
+ Cell * ref1 = cellAt( x1, y1 );
+ Cell * ref2 = cellAt( x2, y2 );
+
+ if ( ref1->isDefault() )
+ {
+ if ( !ref2->isDefault() )
+ {
+ ref1 = nonDefaultCell( x1, y1 );
+ // TODO : make ref2 default instead of copying a default cell into it
+ }
+ else
+ return; // nothing to do
+ }
+ else
+ if ( ref2->isDefault() )
+ {
+ ref2 = nonDefaultCell( x2, y2 );
+ // TODO : make ref1 default instead of copying a default cell into it
+ }
+
+ // Dummy cell used for swapping cells.
+ // In fact we copy only content and no layout
+ // information. Imagine sorting in a sheet. Swapping
+ // the format while sorting is not what you would expect
+ // as a user.
+ if (!ref1->isFormula() && !ref2->isFormula())
+ {
+ Cell *tmp = new Cell( this, -1, -1 );
+
+ tmp->copyContent( ref1 );
+ ref1->copyContent( ref2 );
+ ref2->copyContent( tmp );
+
+ delete tmp;
+ }
+ else
+ if ( ref1->isFormula() && ref2->isFormula() )
+ {
+ TQString d = ref1->encodeFormula();
+ ref1->setCellText( ref1->decodeFormula( ref2->encodeFormula( ) ) );
+ ref1->setCalcDirtyFlag();
+ ref1->calc(false);
+ ref2->setCellText( ref2->decodeFormula( d ) );
+ ref2->setCalcDirtyFlag();
+ ref2->calc(false);
+ }
+ else
+ if (ref1->isFormula() && !ref2->isFormula() )
+ {
+ TQString d = ref1->encodeFormula();
+ ref1->setCellText(ref2->text());
+ ref2->setCellText(ref2->decodeFormula(d));
+ ref2->setCalcDirtyFlag();
+ ref2->calc(false);
+ }
+ else
+ if (!ref1->isFormula() && ref2->isFormula() )
+ {
+ TQString d = ref2->encodeFormula();
+ ref2->setCellText(ref1->text());
+ ref1->setCellText(ref1->decodeFormula(d));
+ ref1->setCalcDirtyFlag();
+ ref1->calc(false);
+ }
+
+ if (cpFormat)
+ {
+ Format::Align a = ref1->format()->align( ref1->column(), ref1->row() );
+ ref1->format()->setAlign( ref2->format()->align( ref2->column(), ref2->row() ) );
+ ref2->format()->setAlign(a);
+
+ Format::AlignY ay = ref1->format()->alignY( ref1->column(), ref1->row() );
+ ref1->format()->setAlignY( ref2->format()->alignY( ref2->column(), ref2->row() ) );
+ ref2->format()->setAlignY(ay);
+
+ TQFont textFont = ref1->format()->textFont( ref1->column(), ref1->row() );
+ ref1->format()->setTextFont( ref2->format()->textFont( ref2->column(), ref2->row() ) );
+ ref2->format()->setTextFont(textFont);
+
+ TQColor textColor = ref1->format()->textColor( ref1->column(), ref1->row() );
+ ref1->format()->setTextColor( ref2->format()->textColor( ref2->column(), ref2->row() ) );
+ ref2->format()->setTextColor(textColor);
+
+ TQColor bgColor = ref1->bgColor( ref1->column(), ref1->row() );
+ ref1->format()->setBgColor( ref2->bgColor( ref2->column(), ref2->row() ) );
+ ref2->format()->setBgColor(bgColor);
+
+ TQPen lbp = ref1->leftBorderPen( ref1->column(), ref1->row() );
+ ref1->setLeftBorderPen( ref2->leftBorderPen( ref2->column(), ref2->row() ) );
+ ref2->setLeftBorderPen(lbp);
+
+ TQPen tbp = ref1->topBorderPen( ref1->column(), ref1->row() );
+ ref1->setTopBorderPen( ref2->topBorderPen( ref2->column(), ref2->row() ) );
+ ref2->setTopBorderPen(tbp);
+
+ TQPen bbp = ref1->bottomBorderPen( ref1->column(), ref1->row() );
+ ref1->setBottomBorderPen( ref2->bottomBorderPen( ref2->column(), ref2->row() ) );
+ ref2->setBottomBorderPen(bbp);
+
+ TQPen rbp = ref1->rightBorderPen( ref1->column(), ref1->row() );
+ ref1->setRightBorderPen( ref2->rightBorderPen( ref2->column(), ref2->row() ) );
+ ref2->setRightBorderPen(rbp);
+
+ TQPen fdp = ref1->format()->fallDiagonalPen( ref1->column(), ref1->row() );
+ ref1->format()->setFallDiagonalPen( ref2->format()->fallDiagonalPen( ref2->column(), ref2->row() ) );
+ ref2->format()->setFallDiagonalPen(fdp);
+
+ TQPen udp = ref1->format()->goUpDiagonalPen( ref1->column(), ref1->row() );
+ ref1->format()->setGoUpDiagonalPen( ref2->format()->goUpDiagonalPen( ref2->column(), ref2->row() ) );
+ ref2->format()->setGoUpDiagonalPen(udp);
+
+ TQBrush bgBrush = ref1->backGroundBrush( ref1->column(), ref1->row() );
+ ref1->format()->setBackGroundBrush( ref2->backGroundBrush( ref2->column(), ref2->row() ) );
+ ref2->format()->setBackGroundBrush(bgBrush);
+
+ int pre = ref1->format()->precision( ref1->column(), ref1->row() );
+ ref1->format()->setPrecision( ref2->format()->precision( ref2->column(), ref2->row() ) );
+ ref2->format()->setPrecision(pre);
+
+ TQString prefix = ref1->format()->prefix( ref1->column(), ref1->row() );
+ ref1->format()->setPrefix( ref2->format()->prefix( ref2->column(), ref2->row() ) );
+ ref2->format()->setPrefix(prefix);
+
+ TQString postfix = ref1->format()->postfix( ref1->column(), ref1->row() );
+ ref1->format()->setPostfix( ref2->format()->postfix( ref2->column(), ref2->row() ) );
+ ref2->format()->setPostfix(postfix);
+
+ Format::FloatFormat f = ref1->format()->floatFormat( ref1->column(), ref1->row() );
+ ref1->format()->setFloatFormat( ref2->format()->floatFormat( ref2->column(), ref2->row() ) );
+ ref2->format()->setFloatFormat(f);
+
+ Format::FloatColor c = ref1->format()->floatColor( ref1->column(), ref1->row() );
+ ref1->format()->setFloatColor( ref2->format()->floatColor( ref2->column(), ref2->row() ) );
+ ref2->format()->setFloatColor(c);
+
+ bool multi = ref1->format()->multiRow( ref1->column(), ref1->row() );
+ ref1->format()->setMultiRow( ref2->format()->multiRow( ref2->column(), ref2->row() ) );
+ ref2->format()->setMultiRow(multi);
+
+ bool vert = ref1->format()->verticalText( ref1->column(), ref1->row() );
+ ref1->format()->setVerticalText( ref2->format()->verticalText( ref2->column(), ref2->row() ) );
+ ref2->format()->setVerticalText(vert);
+
+ bool print = ref1->format()->getDontprintText( ref1->column(), ref1->row() );
+ ref1->format()->setDontPrintText( ref2->format()->getDontprintText( ref2->column(), ref2->row() ) );
+ ref2->format()->setDontPrintText(print);
+
+ double ind = ref1->format()->getIndent( ref1->column(), ref1->row() );
+ ref1->format()->setIndent( ref2->format()->getIndent( ref2->column(), ref2->row() ) );
+ ref2->format()->setIndent( ind );
+
+ TQValueList<Conditional> conditionList = ref1->conditionList();
+ ref1->setConditionList(ref2->conditionList());
+ ref2->setConditionList(conditionList);
+
+ TQString com = ref1->format()->comment( ref1->column(), ref1->row() );
+ ref1->format()->setComment( ref2->format()->comment( ref2->column(), ref2->row() ) );
+ ref2->format()->setComment(com);
+
+ int angle = ref1->format()->getAngle( ref1->column(), ref1->row() );
+ ref1->format()->setAngle( ref2->format()->getAngle( ref2->column(), ref2->row() ) );
+ ref2->format()->setAngle(angle);
+
+ FormatType form = ref1->format()->getFormatType( ref1->column(), ref1->row() );
+ ref1->format()->setFormatType( ref2->format()->getFormatType( ref2->column(), ref2->row() ) );
+ ref2->format()->setFormatType(form);
+ }
+}
+
+void Sheet::refreshPreference()
+{
+ if ( getAutoCalc() )
+ recalc();
+
+ emit sig_updateHBorder( this );
+ emit sig_updateView( this );
+}
+
+
+bool Sheet::areaIsEmpty(const Region& region, TestType _type)
+{
+ Region::ConstIterator endOfList = region.constEnd();
+ for (Region::ConstIterator it = region.constBegin(); it != endOfList; ++it)
+ {
+ TQRect range = (*it)->rect().normalize();
+ // Complete rows selected ?
+ if ((*it)->isRow())
+ {
+ for ( int row = range.top(); row <= range.bottom(); ++row )
+ {
+ Cell * c = getFirstCellRow( row );
+ while ( c )
+ {
+ if ( !c->isPartOfMerged())
+ {
+ switch( _type )
+ {
+ case Text :
+ if ( !c->text().isEmpty())
+ return false;
+ break;
+ case Validity:
+ if ( c->getValidity(0))
+ return false;
+ break;
+ case Comment:
+ if ( !c->format()->comment(c->column(), row).isEmpty())
+ return false;
+ break;
+ case ConditionalCellAttribute:
+ if ( c->conditionList().count()> 0)
+ return false;
+ break;
+ }
+ }
+
+ c = getNextCellRight( c->column(), row );
+ }
+ }
+ }
+ // Complete columns selected ?
+ else if ((*it)->isColumn())
+ {
+ for ( int col = range.left(); col <= range.right(); ++col )
+ {
+ Cell * c = getFirstCellColumn( col );
+ while ( c )
+ {
+ if ( !c->isPartOfMerged() )
+ {
+ switch( _type )
+ {
+ case Text :
+ if ( !c->text().isEmpty())
+ return false;
+ break;
+ case Validity:
+ if ( c->getValidity(0))
+ return false;
+ break;
+ case Comment:
+ if ( !c->format()->comment(col, c->row()).isEmpty())
+ return false;
+ break;
+ case ConditionalCellAttribute:
+ if ( c->conditionList().count()> 0)
+ return false;
+ break;
+ }
+ }
+
+ c = getNextCellDown( col, c->row() );
+ }
+ }
+ }
+ else
+ {
+ Cell * cell;
+
+ int right = range.right();
+ int bottom = range.bottom();
+ for ( int x = range.left(); x <= right; ++x )
+ for ( int y = range.top(); y <= bottom; ++y )
+ {
+ cell = cellAt( x, y );
+ if (!cell->isPartOfMerged() )
+ {
+ switch( _type )
+ {
+ case Text :
+ if ( !cell->text().isEmpty())
+ return false;
+ break;
+ case Validity:
+ if ( cell->getValidity(0))
+ return false;
+ break;
+ case Comment:
+ if ( !cell->format()->comment(x, y).isEmpty())
+ return false;
+ break;
+ case ConditionalCellAttribute:
+ if ( cell->conditionList().count()> 0)
+ return false;
+ break;
+ }
+ }
+ }
+ }
+ }
+ return true;
+}
+
+struct SetSelectionMultiRowWorker : public Sheet::CellWorker
+{
+ bool enable;
+ SetSelectionMultiRowWorker( bool _enable )
+ : Sheet::CellWorker( ), enable( _enable ) { }
+
+ class UndoAction* createUndoAction( Doc * doc, Sheet * sheet, const KSpread::Region& region )
+ {
+ TQString title = i18n("Multirow");
+ return new UndoCellFormat( doc, sheet, region, title );
+ }
+
+ bool testCondition( Cell * cell )
+ {
+ return ( !cell->isPartOfMerged() );
+ }
+
+ void doWork( Cell * cell, bool, int, int )
+ {
+ cell->setDisplayDirtyFlag();
+ cell->format()->setMultiRow( enable );
+ cell->format()->setVerticalText( false );
+ cell->format()->setAngle( 0 );
+ cell->clearDisplayDirtyFlag();
+ }
+};
+
+void Sheet::setSelectionMultiRow( Selection* selectionInfo,
+ bool enable )
+{
+ SetSelectionMultiRowWorker w( enable );
+ workOnCells( selectionInfo, w );
+}
+
+TQString Sheet::guessColumnTitle(TQRect& area, int col)
+{
+ //Verify range
+ Range rg;
+ rg.setRange(area);
+ rg.setSheet(this);
+
+ if ( (!rg.isValid()) || (col < area.left()) || (col > area.right()))
+ return TQString();
+
+ //The current guess logic is fairly simple - if the top row of the given area
+ //appears to contain headers (ie. there is text in each column) the text in the column at
+ //the top row of the area is returned.
+
+/* for (int i=area.left();i<=area.right();i++)
+ {
+ Value cellValue=value(i,area.top());
+
+ if (!cellValue.isString())
+ return TQString();
+ }*/
+
+ Value cellValue=value(col,area.top());
+ return cellValue.asString();
+}
+
+TQString Sheet::guessRowTitle(TQRect& area, int row)
+{
+ //Verify range
+ Range rg;
+ rg.setRange(area);
+ rg.setSheet(this);
+
+ if ( (!rg.isValid()) || (row < area.top()) || (row > area.bottom()) )
+ return TQString();
+
+ //The current guess logic is fairly simple - if the leftmost column of the given area
+ //appears to contain headers (ie. there is text in each row) the text in the row at
+ //the leftmost column of the area is returned.
+ /*for (int i=area.top();i<=area.bottom();i++)
+ {
+ Value cellValue=value(area.left(),i);
+
+ if (!cellValue.isString())
+ return TQString();
+ }*/
+
+ Value cellValue=value(area.left(),row);
+ return cellValue.asString();
+}
+
+void Sheet::setSelectionAlign( Selection* selectionInfo,
+ Format::Align _align )
+{
+ HorAlignManipulator* manipulator = new HorAlignManipulator();
+ manipulator->setSheet(this);
+ manipulator->setProperty(Format::PAlign);
+ manipulator->setHorizontalAlignment(_align);
+ manipulator->add(*selectionInfo);
+ manipulator->execute();
+}
+
+void Sheet::setSelectionAlignY( Selection* selectionInfo,
+ Format::AlignY _alignY )
+{
+ VerAlignManipulator* manipulator = new VerAlignManipulator();
+ manipulator->setSheet(this);
+ manipulator->setProperty(Format::PAlignY);
+ manipulator->setVerticalAlignment(_alignY);
+ manipulator->add(*selectionInfo);
+ manipulator->execute();
+}
+
+
+struct SetSelectionPrecisionWorker : public Sheet::CellWorker {
+ int _delta;
+ SetSelectionPrecisionWorker( int delta ) : Sheet::CellWorker( ), _delta( delta ) { }
+
+ class UndoAction* createUndoAction( Doc* doc, Sheet* sheet, const KSpread::Region& region ) {
+ TQString title=i18n("Change Precision");
+ return new UndoCellFormat( doc, sheet, region, title );
+ }
+ bool testCondition( Cell* cell ) {
+ return ( !cell->isPartOfMerged() );
+ }
+ void doWork( Cell* cell, bool, int, int ) {
+ cell->setDisplayDirtyFlag();
+ if ( _delta == 1 )
+ cell->incPrecision();
+ else
+ cell->decPrecision();
+ cell->clearDisplayDirtyFlag();
+ }
+};
+
+void Sheet::setSelectionPrecision( Selection* selectionInfo,
+ int _delta )
+{
+ SetSelectionPrecisionWorker w( _delta );
+ workOnCells( selectionInfo, w );
+}
+
+struct SetSelectionStyleWorker : public Sheet::CellWorkerTypeA
+{
+ Style * m_style;
+ SetSelectionStyleWorker( Style * style )
+ : m_style( style )
+ {
+ }
+
+ TQString getUndoTitle()
+ {
+ return i18n("Apply Style");
+ }
+
+ void doWork( RowFormat* rw )
+ {
+ rw->setStyle( m_style );
+ }
+
+ void doWork( ColumnFormat* cl )
+ {
+ cl->setStyle( m_style );
+ }
+
+ bool testCondition( Cell* cell )
+ {
+ return ( !cell->isPartOfMerged() && cell->format()->style() != m_style );
+ }
+
+ void doWork( Cell* cell, bool cellRegion, int, int )
+ {
+ if ( cellRegion )
+ cell->setDisplayDirtyFlag();
+
+ cell->format()->setStyle( m_style );
+
+ if ( cellRegion )
+ cell->clearDisplayDirtyFlag();
+ }
+};
+
+
+void Sheet::setSelectionStyle( Selection * selectionInfo, Style * style )
+{
+ SetSelectionStyleWorker w( style );
+ workOnCells( selectionInfo, w );
+}
+
+struct SetSelectionMoneyFormatWorker : public Sheet::CellWorkerTypeA
+{
+ bool b;
+ Doc *m_pDoc;
+ SetSelectionMoneyFormatWorker( bool _b,Doc* _doc ) : b( _b ), m_pDoc(_doc) { }
+ TQString getUndoTitle() { return i18n("Format Money"); }
+ bool testCondition( RowFormat* rw ) {
+ return ( rw->hasProperty( Format::PFormatType )
+ || rw->hasProperty( Format::PPrecision ) );
+ }
+ void doWork( RowFormat* rw ) {
+ rw->setFormatType( b ? Money_format : Generic_format );
+ rw->setPrecision( b ? m_pDoc->locale()->fracDigits() : 0 );
+ }
+ void doWork( ColumnFormat* cl ) {
+ cl->setFormatType( b ? Money_format : Generic_format );
+ cl->setPrecision( b ? m_pDoc->locale()->fracDigits() : 0 );
+ }
+ void prepareCell( Cell* c ) {
+ c->format()->clearProperty( Format::PPrecision );
+ c->format()->clearNoFallBackProperties( Format::PPrecision );
+ c->format()->clearProperty( Format::PFormatType );
+ c->format()->clearNoFallBackProperties( Format::PFormatType );
+ }
+ bool testCondition( Cell* cell ) {
+ return ( !cell->isPartOfMerged() );
+ }
+ void doWork( Cell* cell, bool cellRegion, int, int ) {
+ if ( cellRegion )
+ cell->setDisplayDirtyFlag();
+ cell->format()->setFormatType( b ? Money_format : Generic_format );
+ cell->format()->setPrecision( b ? m_pDoc->locale()->fracDigits() : 0 );
+ if ( cellRegion )
+ cell->clearDisplayDirtyFlag();
+ }
+};
+
+
+void Sheet::setSelectionMoneyFormat( Selection* selectionInfo,
+ bool b )
+{
+ SetSelectionMoneyFormatWorker w( b,doc() );
+ workOnCells( selectionInfo, w );
+}
+
+
+struct IncreaseIndentWorker : public Sheet::CellWorkerTypeA {
+ double tmpIndent;
+ double valIndent;
+
+ IncreaseIndentWorker( double _tmpIndent, double _valIndent )
+ : tmpIndent( _tmpIndent ), valIndent( _valIndent ) { }
+
+ TQString getUndoTitle() { return i18n("Increase Indent"); }
+ bool testCondition( RowFormat* rw ) {
+ return ( rw->hasProperty( Format::PIndent ) );
+ }
+
+ void doWork( RowFormat* rw ) {
+ rw->setIndent( tmpIndent+valIndent );
+ //rw->setAlign( Format::Left );
+ }
+ void doWork( ColumnFormat* cl ) {
+ cl->setIndent( tmpIndent+valIndent );
+ //cl->setAlign( Format::Left );
+ }
+ void prepareCell( Cell* c ) {
+ c->format()->clearProperty( Format::PIndent );
+ c->format()->clearNoFallBackProperties( Format::PIndent );
+ //c->format()->clearProperty( Format::PAlign );
+ //c->format()->clearNoFallBackProperties( Format::PAlign );
+ }
+ bool testCondition( Cell* cell ) {
+ return ( !cell->isPartOfMerged() );
+ }
+ void doWork( Cell* cell, bool cellRegion, int x, int y ) {
+ if ( cellRegion ) {
+ if(cell->format()->align(x,y)!=Format::Left)
+ {
+ //cell->setAlign(Format::Left);
+ //cell->format()->setIndent( 0.0 );
+ }
+ cell->setDisplayDirtyFlag();
+ cell->format()->setIndent( /* ### ??? --> */ cell->format()->getIndent(x,y) /* <-- */ +valIndent );
+ cell->clearDisplayDirtyFlag();
+ } else {
+ cell->format()->setIndent( tmpIndent+valIndent);
+ //cell->setAlign( Format::Left);
+ }
+ }
+};
+
+
+void Sheet::increaseIndent(Selection* selectionInfo)
+{
+ TQPoint marker(selectionInfo->marker());
+ double valIndent = doc()->getIndentValue();
+ Cell *c = cellAt( marker );
+ double tmpIndent = c->format()->getIndent( marker.x(), marker.y() );
+
+ IncreaseIndentWorker w( tmpIndent, valIndent );
+ workOnCells( selectionInfo, w );
+}
+
+
+struct DecreaseIndentWorker : public Sheet::CellWorkerTypeA {
+ double tmpIndent, valIndent;
+ DecreaseIndentWorker( double _tmpIndent, double _valIndent ) : tmpIndent( _tmpIndent ), valIndent( _valIndent ) { }
+ TQString getUndoTitle() { return i18n("Decrease Indent"); }
+ bool testCondition( RowFormat* rw ) {
+ return ( rw->hasProperty( Format::PIndent ) );
+ }
+ void doWork( RowFormat* rw ) {
+ rw->setIndent( TQMAX( 0.0, tmpIndent - valIndent ) );
+ }
+ void doWork( ColumnFormat* cl ) {
+ cl->setIndent( TQMAX( 0.0, tmpIndent - valIndent ) );
+ }
+ void prepareCell( Cell* c ) {
+ c->format()->clearProperty( Format::PIndent );
+ c->format()->clearNoFallBackProperties( Format::PIndent );
+ }
+ bool testCondition( Cell* cell ) {
+ return ( !cell->isPartOfMerged() );
+ }
+ void doWork( Cell* cell, bool cellRegion, int x, int y ) {
+ if ( cellRegion ) {
+ cell->setDisplayDirtyFlag();
+ cell->format()->setIndent( TQMAX( 0.0, cell->format()->getIndent( x, y ) - valIndent ) );
+ cell->clearDisplayDirtyFlag();
+ } else {
+ cell->format()->setIndent( TQMAX( 0.0, tmpIndent - valIndent ) );
+ }
+ }
+};
+
+
+void Sheet::decreaseIndent( Selection* selectionInfo )
+{
+ double valIndent = doc()->getIndentValue();
+ TQPoint marker(selectionInfo->marker());
+ Cell* c = cellAt( marker );
+ double tmpIndent = c->format()->getIndent( marker.x(), marker.y() );
+
+ DecreaseIndentWorker w( tmpIndent, valIndent );
+ workOnCells( selectionInfo, w );
+}
+
+
+int Sheet::adjustColumnHelper( Cell * c, int _col, int _row )
+{
+ double long_max = 0.0;
+ c->calculateTextParameters( painter(), _col, _row );
+ if ( c->textWidth() > long_max )
+ {
+ double indent = 0.0;
+ int a = c->format()->align( c->column(), c->row() );
+ if ( a == Format::Undefined )
+ {
+ if ( c->value().isNumber() || c->isDate() || c->isTime())
+ a = Format::Right;
+ else
+ a = Format::Left;
+ }
+
+ if ( a == Format::Left )
+ indent = c->format()->getIndent( c->column(), c->row() );
+ long_max = indent + c->textWidth()
+ + c->format()->leftBorderWidth( c->column(), c->row() )
+ + c->format()->rightBorderWidth( c->column(), c->row() );
+ }
+ return (int)long_max;
+}
+
+void Sheet::adjustArea(const Region& region)
+{
+ AdjustColumnRowManipulator* manipulator = new AdjustColumnRowManipulator();
+ manipulator->setSheet(this);
+ manipulator->setAdjustColumn(true);
+ manipulator->setAdjustRow(true);
+ manipulator->add(region);
+ manipulator->execute();
+}
+
+void Sheet::adjustColumn(const Region& region)
+{
+ AdjustColumnRowManipulator* manipulator = new AdjustColumnRowManipulator();
+ manipulator->setSheet(this);
+ manipulator->setAdjustColumn(true);
+ manipulator->add(region);
+ manipulator->execute();
+}
+
+void Sheet::adjustRow(const Region& region)
+{
+ AdjustColumnRowManipulator* manipulator = new AdjustColumnRowManipulator();
+ manipulator->setSheet(this);
+ manipulator->setAdjustRow(true);
+ manipulator->add(region);
+ manipulator->execute();
+}
+
+struct ClearTextSelectionWorker : public Sheet::CellWorker {
+ Sheet * _s;
+
+ ClearTextSelectionWorker( Sheet * s )
+ : Sheet::CellWorker( ), _s( s ) { }
+
+ class UndoAction* createUndoAction( Doc* doc, Sheet* sheet, const KSpread::Region& region ) {
+ return new UndoChangeAreaTextCell( doc, sheet, region );
+ }
+ bool testCondition( Cell* cell ) {
+ return ( !cell->isObscured() );
+ }
+ void doWork( Cell* cell, bool, int, int )
+ {
+ cell->setCellText( "" );
+ }
+};
+
+void Sheet::clearTextSelection( Selection* selectionInfo )
+{
+ if (areaIsEmpty(*selectionInfo))
+ return;
+
+ ClearTextSelectionWorker w( this );
+ workOnCells( selectionInfo, w );
+}
+
+
+struct ClearValiditySelectionWorker : public Sheet::CellWorker {
+ ClearValiditySelectionWorker( ) : Sheet::CellWorker( ) { }
+
+ class UndoAction* createUndoAction( Doc* doc, Sheet* sheet, const KSpread::Region& region ) {
+ return new UndoConditional( doc, sheet, region );
+ }
+ bool testCondition( Cell* cell ) {
+ return ( !cell->isObscured() );
+ }
+ void doWork( Cell* cell, bool, int, int ) {
+ cell->removeValidity();
+ }
+};
+
+void Sheet::clearValiditySelection( Selection* selectionInfo )
+{
+ if (areaIsEmpty(*selectionInfo, Validity))
+ return;
+
+ ClearValiditySelectionWorker w;
+ workOnCells( selectionInfo, w );
+}
+
+
+struct ClearConditionalSelectionWorker : public Sheet::CellWorker
+{
+ ClearConditionalSelectionWorker( ) : Sheet::CellWorker( ) { }
+
+ class UndoAction* createUndoAction( Doc* doc,
+ Sheet* sheet,
+ const KSpread::Region& region )
+ {
+ return new UndoConditional( doc, sheet, region );
+ }
+ bool testCondition( Cell* cell )
+ {
+ return ( !cell->isObscured() );
+ }
+ void doWork( Cell* cell, bool, int, int )
+ {
+ TQValueList<Conditional> emptyList;
+ cell->setConditionList(emptyList);
+ }
+};
+
+void Sheet::clearConditionalSelection( Selection* selectionInfo )
+{
+ ClearConditionalSelectionWorker w;
+ workOnCells( selectionInfo, w );
+}
+
+void Sheet::fillSelection( Selection * selectionInfo, int direction )
+{
+ TQRect rct( selectionInfo->selection() );
+ int right = rct.right();
+ int bottom = rct.bottom();
+ int left = rct.left();
+ int top = rct.top();
+ int width = rct.width();
+ int height = rct.height();
+
+ TQDomDocument undoDoc = saveCellRegion( rct );
+ loadSelectionUndo( undoDoc, rct, left - 1, top - 1, false, 0 );
+
+ TQDomDocument doc;
+
+ switch( direction )
+ {
+ case Right:
+ doc = saveCellRegion( TQRect( left, top, 1, height ) );
+ break;
+
+ case Up:
+ doc = saveCellRegion( TQRect( left, bottom, width, 1 ) );
+ break;
+
+ case Left:
+ doc = saveCellRegion( TQRect( right, top, 1, height ) );
+ break;
+
+ case Down:
+ doc = saveCellRegion( TQRect( left, top, width, 1 ) );
+ break;
+ };
+
+ // Save to buffer
+ TQBuffer buffer;
+ buffer.open( IO_WriteOnly );
+ TQTextStream str( &buffer );
+ str.setEncoding( TQTextStream::UnicodeUTF8 );
+ str << doc;
+ buffer.close();
+
+ int i;
+ switch( direction )
+ {
+ case Right:
+ for ( i = left + 1; i <= right; ++i )
+ {
+ paste( buffer.buffer(), TQRect( i, top, 1, 1 ), false );
+ }
+ break;
+
+ case Up:
+ for ( i = bottom + 1; i >= top; --i )
+ {
+ paste( buffer.buffer(), TQRect( left, i, 1, 1 ), false );
+ }
+ break;
+
+ case Left:
+ for ( i = right - 1; i >= left; --i )
+ {
+ paste( buffer.buffer(), TQRect( i, top, 1, 1 ), false );
+ }
+ break;
+
+ case Down:
+ for ( i = top + 1; i <= bottom; ++i )
+ {
+ paste( buffer.buffer(), TQRect( left, i, 1, 1 ), false );
+ }
+ break;
+ }
+
+ this->doc()->setModified( true );
+}
+
+
+struct DefaultSelectionWorker : public Sheet::CellWorker {
+ DefaultSelectionWorker( ) : Sheet::CellWorker( true, false, true ) { }
+
+ class UndoAction* createUndoAction( Doc* doc, Sheet* sheet, const KSpread::Region& region ) {
+ TQString title=i18n("Default Parameters");
+ return new UndoCellFormat( doc, sheet, region, title );
+ }
+ bool testCondition( Cell* ) {
+ return true;
+ }
+ void doWork( Cell* cell, bool, int, int ) {
+ cell->defaultStyle();
+ }
+};
+
+void Sheet::defaultSelection( Selection* selectionInfo )
+{
+ TQRect selection(selectionInfo->selection());
+ DefaultSelectionWorker w;
+ SelectionType st = workOnCells( selectionInfo, w );
+ switch ( st ) {
+ case CompleteRows:
+ RowFormat *rw;
+ for ( int i = selection.top(); i <= selection.bottom(); i++ ) {
+ rw = nonDefaultRowFormat( i );
+ rw->defaultStyleFormat();
+ }
+ emit sig_updateView( this, *selectionInfo );
+ return;
+ case CompleteColumns:
+ ColumnFormat *cl;
+ for ( int i = selection.left(); i <= selection.right(); i++ ) {
+ cl=nonDefaultColumnFormat( i );
+ cl->defaultStyleFormat();
+ }
+ emit sig_updateView( this, *selectionInfo );
+ return;
+ case CellRegion:
+ emit sig_updateView( this, *selectionInfo );
+ return;
+ }
+}
+
+
+struct SetConditionalWorker : public Sheet::CellWorker
+{
+ TQValueList<Conditional> conditionList;
+ SetConditionalWorker( TQValueList<Conditional> _tmp ) :
+ Sheet::CellWorker( ), conditionList( _tmp ) { }
+
+ class UndoAction* createUndoAction( Doc* doc,
+ Sheet* sheet, const KSpread::Region& region )
+ {
+ return new UndoConditional( doc, sheet, region );
+ }
+
+ bool testCondition( Cell* )
+ {
+ return true;
+ }
+
+ void doWork( Cell* cell, bool, int, int )
+ {
+ if ( !cell->isObscured() ) // TODO: isPartOfMerged()???
+ {
+ cell->setConditionList(conditionList);
+ cell->setDisplayDirtyFlag();
+ }
+ }
+};
+
+void Sheet::setConditional( Selection* selectionInfo,
+ TQValueList<Conditional> const & newConditions)
+{
+ if ( !doc()->undoLocked() )
+ {
+ UndoConditional * undo = new UndoConditional(doc(), this, *selectionInfo);
+ doc()->addCommand( undo );
+ }
+
+ Region::ConstIterator endOfList = selectionInfo->constEnd();
+ for (Region::ConstIterator it = selectionInfo->constBegin(); it != endOfList; ++it)
+ {
+ TQRect range = (*it)->rect().normalize();
+
+ int l = range.left();
+ int r = range.right();
+ int t = range.top();
+ int b = range.bottom();
+
+ Cell * cell;
+ Style * s = doc()->styleManager()->defaultStyle();
+ for (int x = l; x <= r; ++x)
+ {
+ for (int y = t; y <= b; ++y)
+ {
+ cell = nonDefaultCell( x, y, false, s );
+ cell->setConditionList( newConditions );
+ cell->setDisplayDirtyFlag();
+ }
+ }
+ }
+
+ emit sig_updateView( this, *selectionInfo );
+}
+
+
+struct SetValidityWorker : public Sheet::CellWorker {
+ Validity tmp;
+ SetValidityWorker( Validity _tmp ) : Sheet::CellWorker( ), tmp( _tmp ) { }
+
+ class UndoAction* createUndoAction( Doc* doc, Sheet* sheet, const KSpread::Region& region ) {
+ return new UndoConditional( doc, sheet, region );
+ }
+ bool testCondition( Cell* ) {
+ return true;
+ }
+ void doWork( Cell* cell, bool, int, int ) {
+ if ( !cell->isObscured() ) {
+ cell->setDisplayDirtyFlag();
+ if ( tmp.m_restriction==Restriction::None )
+ cell->removeValidity();
+ else
+ {
+ Validity *tmpValidity = cell->getValidity();
+ tmpValidity->message=tmp.message;
+ tmpValidity->title=tmp.title;
+ tmpValidity->valMin=tmp.valMin;
+ tmpValidity->valMax=tmp.valMax;
+ tmpValidity->m_cond=tmp.m_cond;
+ tmpValidity->m_action=tmp.m_action;
+ tmpValidity->m_restriction=tmp.m_restriction;
+ tmpValidity->timeMin=tmp.timeMin;
+ tmpValidity->timeMax=tmp.timeMax;
+ tmpValidity->dateMin=tmp.dateMin;
+ tmpValidity->dateMax=tmp.dateMax;
+ tmpValidity->displayMessage=tmp.displayMessage;
+ tmpValidity->allowEmptyCell=tmp.allowEmptyCell;
+ tmpValidity->displayValidationInformation=tmp.displayValidationInformation;
+ tmpValidity->titleInfo=tmp.titleInfo;
+ tmpValidity->messageInfo=tmp.messageInfo;
+ tmpValidity->listValidity=tmp.listValidity;
+ }
+ cell->clearDisplayDirtyFlag();
+ }
+ }
+};
+
+void Sheet::setValidity(Selection* selectionInfo,
+ KSpread::Validity tmp )
+{
+ SetValidityWorker w( tmp );
+ workOnCells( selectionInfo, w );
+}
+
+
+struct GetWordSpellingWorker : public Sheet::CellWorker {
+ TQString& listWord;
+ GetWordSpellingWorker( TQString& _listWord ) : Sheet::CellWorker( false, false, true ), listWord( _listWord ) { }
+
+ class UndoAction* createUndoAction( Doc*, Sheet*, const KSpread::Region& ) {
+ return 0;
+ }
+ bool testCondition( Cell* ) {
+ return true;
+ }
+ void doWork( Cell* c, bool cellRegion, int, int ) {
+ if ( !c->isObscured() || cellRegion /* ### ??? */ ) {
+ if ( !c->isFormula() && !c->value().isNumber() && !c->value().asString().isEmpty() && !c->isTime()
+ && !c->isDate()
+ && !c->text().isEmpty())
+ {
+ listWord+=c->text()+'\n';
+ }
+ }
+ }
+};
+
+TQString Sheet::getWordSpelling(Selection* selectionInfo )
+{
+ TQString listWord;
+ GetWordSpellingWorker w( listWord );
+ workOnCells( selectionInfo, w );
+ return listWord;
+}
+
+
+struct SetWordSpellingWorker : public Sheet::CellWorker {
+ TQStringList& list;
+ int pos;
+ Sheet * sheet;
+ SetWordSpellingWorker( TQStringList & _list,Sheet * s )
+ : Sheet::CellWorker( false, false, true ), list( _list ), pos( 0 ), sheet( s ) { }
+
+ class UndoAction* createUndoAction( Doc* doc, Sheet* sheet, const KSpread::Region& region ) {
+ return new UndoChangeAreaTextCell( doc, sheet, region );
+ }
+ bool testCondition( Cell* ) {
+ return true;
+ }
+ void doWork( Cell* c, bool cellRegion, int, int )
+ {
+ if ( !c->isObscured() || cellRegion /* ### ??? */ ) {
+ if ( !c->isFormula() && !c->value().isNumber() && !c->value().asString().isEmpty() && !c->isTime()
+ && !c->isDate()
+ && !c->text().isEmpty())
+ {
+
+
+ c->setCellText( list[pos] );
+ pos++;
+ }
+ }
+ }
+};
+
+void Sheet::setWordSpelling(Selection* selectionInfo,
+ const TQString _listWord )
+{
+ TQStringList list = TQStringList::split ( '\n', _listWord );
+ SetWordSpellingWorker w( list, this );
+ workOnCells( selectionInfo, w );
+}
+
+static TQString cellAsText( Cell* cell, unsigned int max )
+{
+ TQString result;
+ if( !cell->isDefault() )
+ {
+ int l = max - cell->strOutText().length();
+ if (cell->defineAlignX() == Format::Right )
+ {
+ for ( int i = 0; i < l; ++i )
+ result += " ";
+ result += cell->strOutText();
+ }
+ else if (cell->defineAlignX() == Format::Left )
+ {
+ result += " ";
+ result += cell->strOutText();
+ // start with "1" because we already set one space
+ for ( int i = 1; i < l; ++i )
+ result += " ";
+ }
+ else // centered
+ {
+ int i;
+ int s = (int) l / 2;
+ for ( i = 0; i < s; ++i )
+ result += " ";
+ result += cell->strOutText();
+ for ( i = s; i < l; ++i )
+ result += " ";
+ }
+ }
+ else
+ {
+ for ( unsigned int i = 0; i < max; ++i )
+ result += " ";
+ }
+
+ return result;
+}
+
+TQString Sheet::copyAsText( Selection* selectionInfo )
+{
+ // Only one cell selected? => copy active cell
+ if ( selectionInfo->isSingular() )
+ {
+ Cell * cell = cellAt( selectionInfo->marker() );
+ if( !cell->isDefault() )
+ return cell->strOutText();
+ return "";
+ }
+
+ TQRect selection(selectionInfo->selection());
+
+ // Find area
+ unsigned top = selection.bottom();
+ unsigned bottom = selection.top();
+ unsigned left = selection.right();
+ unsigned right = selection.left();
+
+ unsigned max = 1;
+ for( Cell *c = d->cells.firstCell();c; c = c->nextCell() )
+ {
+ if ( !c->isDefault() )
+ {
+ TQPoint p( c->column(), c->row() );
+ if ( selection.contains( p ) )
+ {
+ top = TQMIN( top, (unsigned) c->row() );
+ left = TQMIN( left, (unsigned) c->column() );
+ bottom = TQMAX( bottom, (unsigned) c->row() );
+ right = TQMAX( right, (unsigned) c->column() );
+
+ if ( c->strOutText().length() > max )
+ max = c->strOutText().length();
+ }
+ }
+ }
+
+ ++max;
+
+ TQString result;
+ for ( unsigned y = top; y <= bottom; ++y)
+ {
+ for ( unsigned x = left; x <= right; ++x)
+ {
+ Cell *cell = cellAt( x, y );
+ result += cellAsText( cell, max );
+ }
+ result += "\n";
+ }
+
+ return result;
+}
+
+void Sheet::copySelection( Selection* selectionInfo )
+{
+ TQDomDocument doc = saveCellRegion( *selectionInfo, true );
+
+ // Save to buffer
+ TQBuffer buffer;
+ buffer.open( IO_WriteOnly );
+ TQTextStream str( &buffer );
+ str.setEncoding( TQTextStream::UnicodeUTF8 );
+ str << doc;
+ buffer.close();
+
+ TextDrag * kd = new TextDrag( 0L );
+ kd->setPlain( copyAsText(selectionInfo) );
+ kd->setKSpread( buffer.buffer() );
+
+ TQApplication::clipboard()->setData( kd );
+}
+
+void Sheet::cutSelection( Selection* selectionInfo )
+{
+ TQDomDocument doc = saveCellRegion(*selectionInfo, true, true);
+
+ // Save to buffer
+ TQBuffer buffer;
+ buffer.open( IO_WriteOnly );
+ TQTextStream str( &buffer );
+ str.setEncoding( TQTextStream::UnicodeUTF8 );
+ str << doc;
+ buffer.close();
+
+ TextDrag * kd = new TextDrag( 0L );
+ kd->setPlain( copyAsText(selectionInfo) );
+ kd->setKSpread( buffer.buffer() );
+
+ TQApplication::clipboard()->setData( kd );
+
+ deleteSelection( selectionInfo, true );
+}
+
+void Sheet::paste( const TQRect& pasteArea, bool makeUndo,
+ Paste::Mode mode, Paste::Operation operation,
+ bool insert, int insertTo, bool pasteFC,
+ TQClipboard::Mode clipboardMode )
+{
+ TQMimeSource * mime = TQApplication::clipboard()->data( clipboardMode );
+ if ( !mime )
+ return;
+
+ TQByteArray b;
+
+ if ( mime->provides( TextDrag::selectionMimeType() ) )
+ {
+ b = mime->encodedData( TextDrag::selectionMimeType() );
+ }
+ else if( mime->provides( "text/plain" ) )
+ {
+ // Note: TQClipboard::text() seems to do a better job than encodedData( "text/plain" )
+ // In particular it handles charsets (in the mimetype). Copied from KPresenter ;-)
+ TQString _text = TQApplication::clipboard()->text( clipboardMode );
+ doc()->emitBeginOperation();
+ pasteTextPlain( _text, pasteArea );
+ emit sig_updateView( this );
+ // doc()->emitEndOperation();
+ return;
+ }
+ else
+ return;
+
+ // Do the actual pasting.
+ doc()->emitBeginOperation();
+ paste( b, pasteArea, makeUndo, mode, operation, insert, insertTo, pasteFC );
+ emit sig_updateView( this );
+ // doc()->emitEndOperation();
+}
+
+
+void Sheet::pasteTextPlain( TQString &_text, TQRect pasteArea)
+{
+// TQString tmp;
+// tmp= TQString::fromLocal8Bit(_mime->encodedData( "text/plain" ));
+ if( _text.isEmpty() )
+ return;
+
+ TQString tmp = _text;
+ int i;
+ int mx = pasteArea.left();
+ int my = pasteArea.top();
+ int rows = 1;
+ int len = tmp.length();
+
+ //count the numbers of lines in text
+ for ( i = 0; i < len; ++i )
+ {
+ if ( tmp[i] == '\n' )
+ ++rows;
+ }
+
+ Cell * cell = nonDefaultCell( mx, my );
+ if ( rows == 1 )
+ {
+ if ( !doc()->undoLocked() )
+ {
+ UndoSetText * undo = new UndoSetText( doc(), this , cell->text(), mx, my, cell->formatType() );
+ doc()->addCommand( undo );
+ }
+ }
+ else
+ {
+ TQRect rect(mx, my, mx, my + rows - 1);
+ UndoChangeAreaTextCell * undo = new UndoChangeAreaTextCell( doc(), this , rect );
+ doc()->addCommand( undo );
+ }
+
+ i = 0;
+ TQString rowtext;
+
+ while ( i < rows )
+ {
+ int p = 0;
+
+ p = tmp.find('\n');
+
+ if (p < 0)
+ p = tmp.length();
+
+ rowtext = tmp.left(p);
+
+ if ( !isProtected() || cell->format()->notProtected( mx, my + i ) )
+ {
+ cell->setCellText( rowtext );
+ cell->updateChart();
+ }
+
+ // next cell
+ ++i;
+ cell = nonDefaultCell( mx, my + i );
+
+ if (!cell || p == (int) tmp.length())
+ break;
+
+ // exclude the left part and '\n'
+ tmp = tmp.right(tmp.length() - p - 1);
+ }
+
+ if (!isLoading())
+ refreshMergedCell();
+
+ emit sig_updateView( this );
+ emit sig_updateHBorder( this );
+ emit sig_updateVBorder( this );
+}
+
+void Sheet::paste( const TQByteArray& b, const TQRect& pasteArea, bool makeUndo,
+ Paste::Mode mode, Paste::Operation operation,
+ bool insert, int insertTo, bool pasteFC )
+{
+ kdDebug(36001) << "Parsing " << b.size() << " bytes" << endl;
+
+ TQBuffer buffer( b );
+ buffer.open( IO_ReadOnly );
+ TQDomDocument doc;
+ doc.setContent( &buffer );
+ buffer.close();
+
+ // ##### TODO: Test for parsing errors
+
+ int mx = pasteArea.left();
+ int my = pasteArea.top();
+
+ loadSelection( doc, pasteArea, mx - 1, my - 1, makeUndo,
+ mode, operation, insert, insertTo, pasteFC );
+}
+
+bool Sheet::loadSelection(const TQDomDocument& doc, const TQRect& pasteArea,
+ int _xshift, int _yshift, bool makeUndo,
+ Paste::Mode mode, Paste::Operation operation, bool insert,
+ int insertTo, bool pasteFC)
+{
+ //kdDebug(36001) << "loadSelection called. pasteArea=" << pasteArea << endl;
+
+ if (!isLoading() && makeUndo)
+ {
+ loadSelectionUndo( doc, pasteArea, _xshift, _yshift, insert, insertTo );
+ }
+
+ TQDomElement root = doc.documentElement(); // "spreadsheet-snippet"
+
+ int rowsInClpbrd = root.attribute( "rows" ).toInt();
+ int columnsInClpbrd = root.attribute( "columns" ).toInt();
+
+ // find size of rectangle that we want to paste to (either clipboard size or current selection)
+ const int pasteWidth = ( pasteArea.width() >= columnsInClpbrd
+ && util_isRowSelected(pasteArea) == false
+ && root.namedItem( "rows" ).toElement().isNull() )
+ ? pasteArea.width() : columnsInClpbrd;
+ const int pasteHeight = ( pasteArea.height() >= rowsInClpbrd
+ && util_isColumnSelected(pasteArea) == false
+ && root.namedItem( "columns" ).toElement().isNull())
+ ? pasteArea.height() : rowsInClpbrd;
+
+// kdDebug() << "loadSelection: paste area has size "
+// << pasteHeight << " rows * "
+// << pasteWidth << " columns " << endl;
+// kdDebug() << "loadSelection: " << rowsInClpbrd << " rows and "
+// << columnsInClpbrd << " columns in clipboard." << endl;
+// kdDebug() << "xshift: " << _xshift << " _yshift: " << _yshift << endl;
+
+ TQDomElement e = root.firstChild().toElement(); // "columns", "rows" or "cell"
+ for (; !e.isNull(); e = e.nextSibling().toElement())
+ {
+ // entire columns given
+ if (e.tagName() == "columns" && !isProtected())
+ {
+ _yshift = 0;
+
+ // Clear the existing columns
+ int col = e.attribute("column").toInt();
+ int width = e.attribute("count").toInt();
+ if (!insert)
+ {
+ for ( int i = col; i < col + width; ++i )
+ {
+ d->cells.clearColumn( _xshift + i );
+ d->columns.removeElement( _xshift + i );
+ }
+ }
+
+ // Insert column formats
+ TQDomElement c = e.firstChild().toElement();
+ for ( ; !c.isNull(); c = c.nextSibling().toElement() )
+ {
+ if ( c.tagName() == "column" )
+ {
+ ColumnFormat *cl = new ColumnFormat( this, 0 );
+ if ( cl->load( c, _xshift, mode, pasteFC ) )
+ insertColumnFormat( cl );
+ else
+ delete cl;
+ }
+ }
+ }
+
+ // entire rows given
+ if (e.tagName() == "rows" && !isProtected())
+ {
+ _xshift = 0;
+
+ // Clear the existing rows
+ int row = e.attribute("row").toInt();
+ int height = e.attribute("count").toInt();
+ if ( !insert )
+ {
+ for( int i = row; i < row + height; ++i )
+ {
+ d->cells.clearRow( _yshift + i );
+ d->rows.removeElement( _yshift + i );
+ }
+ }
+
+ // Insert row formats
+ TQDomElement c = e.firstChild().toElement();
+ for( ; !c.isNull(); c = c.nextSibling().toElement() )
+ {
+ if ( c.tagName() == "row" )
+ {
+ RowFormat *cl = new RowFormat( this, 0 );
+ if ( cl->load( c, _yshift, mode, pasteFC ) )
+ insertRowFormat( cl );
+ else
+ delete cl;
+ }
+ }
+ }
+
+ Cell* refreshCell = 0;
+ Cell *cell;
+ Cell *cellBackup = NULL;
+ if (e.tagName() == "cell")
+ {
+ int row = e.attribute( "row" ).toInt() + _yshift;
+ int col = e.attribute( "column" ).toInt() + _xshift;
+
+ // tile the selection with the clipboard contents
+ for (int roff = 0; row + roff - _yshift <= pasteHeight; roff += rowsInClpbrd)
+ {
+ for (int coff = 0; col + coff - _xshift <= pasteWidth; coff += columnsInClpbrd)
+ {
+// kdDebug() << "loadSelection: cell at " << (col+coff) << "," << (row+roff)
+// << " with roff,coff= " << roff << "," << coff
+// << ", _xshift: " << _xshift << ", _yshift: " << _yshift << endl;
+
+ cell = nonDefaultCell( col + coff, row + roff );
+ if (isProtected() && !cell->format()->notProtected(col + coff, row + roff))
+ {
+ continue;
+ }
+
+ cellBackup = new Cell(this, cell->column(), cell->row());
+ cellBackup->copyAll(cell);
+
+ if (!cell->load(e, _xshift + coff, _yshift + roff, mode, operation, pasteFC))
+ {
+ cell->copyAll(cellBackup);
+ }
+ else
+ {
+ if (cell->isFormula())
+ {
+ cell->setCalcDirtyFlag();
+ }
+ }
+
+ delete cellBackup;
+
+
+
+ cell = cellAt( col + coff, row + roff );
+ if( !refreshCell && cell->updateChart( false ) )
+ {
+ refreshCell = cell;
+ }
+ }
+ }
+ }
+
+ //refresh chart after that you paste all cells
+
+ /* I don't think this is gonna work....doesn't this only update
+ one chart -- the one which had a dependant cell update first? - John
+
+ I don't have time to check on this now....
+ */
+ if ( refreshCell )
+ refreshCell->updateChart();
+ }
+ this->doc()->setModified( true );
+
+ if (!isLoading())
+ refreshMergedCell();
+
+ emit sig_updateView( this );
+ emit sig_updateHBorder( this );
+ emit sig_updateVBorder( this );
+
+ return true;
+}
+
+void Sheet::loadSelectionUndo(const TQDomDocument& d, const TQRect& loadArea,
+ int _xshift, int _yshift,
+ bool insert, int insertTo)
+{
+ TQDomElement root = d.documentElement(); // "spreadsheet-snippet"
+
+ int rowsInClpbrd = root.attribute( "rows" ).toInt();
+ int columnsInClpbrd = root.attribute( "columns" ).toInt();
+
+ // find rect that we paste to
+ const int pasteWidth = (loadArea.width() >= columnsInClpbrd &&
+ util_isRowSelected(loadArea) == false &&
+ root.namedItem( "rows" ).toElement().isNull())
+ ? loadArea.width() : columnsInClpbrd;
+ const int pasteHeight = (loadArea.height() >= rowsInClpbrd &&
+ util_isColumnSelected(loadArea) == false &&
+ root.namedItem( "columns" ).toElement().isNull())
+ ? loadArea.height() : rowsInClpbrd;
+
+ uint numCols = 0;
+ uint numRows = 0;
+
+ Region region;
+ for (TQDomNode n = root.firstChild(); !n.isNull(); n = n.nextSibling())
+ {
+ TQDomElement e = n.toElement(); // "columns", "rows" or "cell"
+ if (e.tagName() == "columns")
+ {
+ _yshift = 0;
+ int col = e.attribute("column").toInt();
+ int width = e.attribute("count").toInt();
+ for (int coff = 0; col + coff <= pasteWidth; coff += columnsInClpbrd)
+ {
+ uint overlap = TQMAX(0, (col - 1 + coff + width) - pasteWidth);
+ uint effWidth = width - overlap;
+ region.add(TQRect(_xshift + col + coff, 1, effWidth, KS_rowMax));
+ numCols += effWidth;
+ }
+ }
+ else if (e.tagName() == "rows")
+ {
+ _xshift = 0;
+ int row = e.attribute("row").toInt();
+ int height = e.attribute("count").toInt();
+ for (int roff = 0; row + roff <= pasteHeight; roff += rowsInClpbrd)
+ {
+ uint overlap = TQMAX(0, (row - 1 + roff + height) - pasteHeight);
+ uint effHeight = height - overlap;
+ region.add(TQRect(1, _yshift + row + roff, KS_colMax, effHeight));
+ numRows += effHeight;
+ }
+ }
+ else if (!e.isNull())
+ {
+ // store the cols/rows for the insertion
+ int col = e.attribute("column").toInt();
+ int row = e.attribute("row").toInt();
+ for (int coff = 0; col + coff <= pasteWidth; coff += columnsInClpbrd)
+ {
+ for (int roff = 0; row + roff <= pasteHeight; roff += rowsInClpbrd)
+ {
+ region.add(TQPoint(_xshift + col + coff, _yshift + row + roff));
+ }
+ }
+ }
+ }
+
+ if (!doc()->undoLocked())
+ {
+ UndoCellPaste *undo = new UndoCellPaste( doc(), this, _xshift, _yshift, region, insert, insertTo );
+ doc()->addCommand( undo );
+ }
+
+ if (insert)
+ {
+ TQRect rect = region.boundingRect();
+ // shift cells to the right
+ if (insertTo == -1 && numCols == 0 && numRows == 0)
+ {
+ rect.setWidth(rect.width());
+ shiftRow(rect, false);
+ }
+ // shift cells to the bottom
+ else if (insertTo == 1 && numCols == 0 && numRows == 0)
+ {
+ rect.setHeight(rect.height());
+ shiftColumn( rect, false );
+ }
+ // insert columns
+ else if (insertTo == 0 && numCols == 0 && numRows > 0)
+ {
+ insertRow(rect.top(), rect.height() - 1, false);
+ }
+ // insert rows
+ else if (insertTo == 0 && numCols > 0 && numRows == 0)
+ {
+ insertColumn(rect.left(), rect.width() - 1, false);
+ }
+ }
+}
+
+bool Sheet::testAreaPasteInsert()const
+{
+ TQMimeSource* mime = TQApplication::clipboard()->data( TQClipboard::Clipboard );
+ if ( !mime )
+ return false;
+
+ TQByteArray b;
+
+ if ( mime->provides( "application/x-kspread-snippet" ) )
+ b = mime->encodedData( "application/x-kspread-snippet" );
+ else
+ return false;
+
+ TQBuffer buffer( b );
+ buffer.open( IO_ReadOnly );
+ TQDomDocument d;
+ d.setContent( &buffer );
+ buffer.close();
+
+ TQDomElement e = d.documentElement();
+ if ( !e.namedItem( "columns" ).toElement().isNull() )
+ return false;
+
+ if ( !e.namedItem( "rows" ).toElement().isNull() )
+ return false;
+
+ TQDomElement c = e.firstChild().toElement();
+ for( ; !c.isNull(); c = c.nextSibling().toElement() )
+ {
+ if ( c.tagName() == "cell" )
+ return true;
+ }
+ return false;
+}
+
+void Sheet::deleteCells(const Region& region)
+{
+ // A list of all cells we want to delete.
+ TQPtrStack<Cell> cellStack;
+
+ Region::ConstIterator endOfList = region.constEnd();
+ for (Region::ConstIterator it = region.constBegin(); it != endOfList; ++it)
+ {
+ TQRect range = (*it)->rect().normalize();
+
+ int right = range.right();
+ int left = range.left();
+ int bottom = range.bottom();
+ int col;
+ for ( int row = range.top(); row <= bottom; ++row )
+ {
+ Cell * c = getFirstCellRow( row );
+ while ( c )
+ {
+ col = c->column();
+ if ( col < left )
+ {
+ c = getNextCellRight( left - 1, row );
+ continue;
+ }
+ if ( col > right )
+ break;
+
+ if ( !c->isDefault() )
+ cellStack.push( c );
+
+ c = getNextCellRight( col, row );
+ }
+ }
+ }
+
+ d->cells.setAutoDelete( false );
+
+ // Remove the cells from the sheet
+ while ( !cellStack.isEmpty() )
+ {
+ Cell * cell = cellStack.pop();
+
+ d->cells.remove( cell->column(), cell->row() );
+ cell->setCalcDirtyFlag();
+ setRegionPaintDirty(cell->cellRect());
+
+ delete cell;
+ }
+
+ d->cells.setAutoDelete( true );
+
+ setLayoutDirtyFlag();
+
+ // TODO: don't go through all cells here!
+ // Since obscured cells might have been deleted we
+ // have to reenforce it.
+ Cell * c = d->cells.firstCell();
+ for( ;c; c = c->nextCell() )
+ {
+ if ( c->doesMergeCells() && !c->isDefault() )
+ c->mergeCells( c->column(), c->row(),
+ c->extraXCells(), c->extraYCells() );
+ }
+ doc()->setModified( true );
+}
+
+void Sheet::deleteSelection( Selection* selectionInfo, bool undo )
+{
+ if ( undo && !doc()->undoLocked() )
+ {
+ UndoDelete *undo = new UndoDelete( doc(), this, *selectionInfo );
+ doc()->addCommand( undo );
+ }
+
+ Region::ConstIterator endOfList = selectionInfo->constEnd();
+ for (Region::ConstIterator it = selectionInfo->constBegin(); it != endOfList; ++it)
+ {
+ TQRect range = (*it)->rect().normalize();
+
+ // Entire rows selected ?
+ if ( util_isRowSelected(range) )
+ {
+ for( int i = range.top(); i <= range.bottom(); ++i )
+ {
+ d->cells.clearRow( i );
+ d->rows.removeElement( i );
+ }
+
+ emit sig_updateVBorder( this );
+ }
+ // Entire columns selected ?
+ else if ( util_isColumnSelected(range) )
+ {
+ for( int i = range.left(); i <= range.right(); ++i )
+ {
+ d->cells.clearColumn( i );
+ d->columns.removeElement( i );
+ }
+
+ emit sig_updateHBorder( this );
+ }
+ else
+ {
+ setRegionPaintDirty( range );
+ deleteCells( range );
+ }
+ }
+ refreshMergedCell();
+ emit sig_updateView( this );
+}
+
+void Sheet::updateView()
+{
+ emit sig_updateView( this );
+}
+
+void Sheet::updateView( TQRect const & rect )
+{
+ emit sig_updateView( this, rect );
+}
+
+void Sheet::updateView(Region* region)
+{
+ emit sig_updateView( this, *region );
+}
+
+void Sheet::refreshView( const Region& region )
+{
+ Region tmpRegion;
+ Region::ConstIterator endOfList = region.constEnd();
+ for (Region::ConstIterator it = region.constBegin(); it != endOfList; ++it)
+ {
+ TQRect range = (*it)->rect().normalize();
+ // TODO: don't go through all cells when refreshing!
+ TQRect tmp(range);
+ Cell * c = d->cells.firstCell();
+ for( ;c; c = c->nextCell() )
+ {
+ if ( !c->isDefault() &&
+ c->row() >= range.top() && c->row() <= range.bottom() &&
+ c->column() >= range.left() && c->column() <= range.right() )
+ {
+ if (c->doesMergeCells())
+ {
+ int right=TQMAX(tmp.right(),c->column()+c->extraXCells());
+ int bottom=TQMAX(tmp.bottom(),c->row()+c->extraYCells());
+
+ tmp.setRight(right);
+ tmp.setBottom(bottom);
+ }
+ }
+ }
+ deleteCells( range );
+ tmpRegion.add(tmp);
+ }
+ emit sig_updateView( this, tmpRegion );
+}
+
+
+void Sheet::mergeCells(const Region& region, bool hor, bool ver)
+{
+ // sanity check
+ if( isProtected() )
+ return;
+ if( workbook()->isProtected() )
+ return;
+
+ MergeManipulator* manipulator = new MergeManipulator();
+ manipulator->setSheet(this);
+ manipulator->setHorizontalMerge(hor);
+ manipulator->setVerticalMerge(ver);
+ manipulator->add(region);
+ manipulator->execute();
+}
+
+void Sheet::dissociateCells(const Region& region)
+{
+ // sanity check
+ if( isProtected() )
+ return;
+ if( workbook()->isProtected() )
+ return;
+
+ Manipulator* manipulator = new MergeManipulator();
+ manipulator->setSheet(this);
+ manipulator->setReverse(true);
+ manipulator->add(region);
+ manipulator->execute();
+}
+
+bool Sheet::testListChoose(Selection* selectionInfo)
+{
+ TQRect selection( selectionInfo->selection() );
+ TQPoint marker( selectionInfo->marker() );
+
+ Cell *cell = cellAt( marker.x(), marker.y() );
+ TQString tmp=cell->text();
+
+ Cell* c = firstCell();
+ bool different=false;
+ int col;
+ for( ;c; c = c->nextCell() )
+ {
+ col = c->column();
+ if ( selection.left() <= col && selection.right() >= col &&
+ !c->isPartOfMerged() &&
+ !(col==marker.x() && c->row()==marker.y()))
+ {
+ if(!c->isFormula() && !c->value().isNumber() && !c->value().asString().isEmpty()
+ && !c->isTime() &&!c->isDate() )
+ {
+ if(c->text()!=tmp)
+ different=true;
+ }
+
+ }
+ }
+ return different;
+}
+
+
+
+TQDomDocument Sheet::saveCellRegion(const Region& region, bool copy, bool era)
+{
+ TQDomDocument dd( "spreadsheet-snippet" );
+ dd.appendChild( dd.createProcessingInstruction( "xml", "version=\"1.0\" encoding=\"UTF-8\"" ) );
+ TQDomElement root = dd.createElement( "spreadsheet-snippet" );
+ dd.appendChild(root);
+
+ // find the upper left corner of the selection
+ TQRect boundingRect = region.boundingRect();
+ int left = boundingRect.left();
+ int top = boundingRect.top();
+
+ // for tiling the clipboard content in the selection
+ root.setAttribute( "rows", boundingRect.height() );
+ root.setAttribute( "columns", boundingRect.width() );
+
+ Region::ConstIterator endOfList = region.constEnd();
+ for (Region::ConstIterator it = region.constBegin(); it != endOfList; ++it)
+ {
+ TQRect range = (*it)->rect().normalize();
+
+ //
+ // Entire rows selected?
+ //
+ if ((*it)->isRow())
+ {
+ TQDomElement rows = dd.createElement("rows");
+ rows.setAttribute( "count", range.height() );
+ rows.setAttribute( "row", range.top() - top + 1 );
+ root.appendChild( rows );
+
+ // Save all cells.
+ for (Cell* cell = d->cells.firstCell(); cell; cell = cell->nextCell())
+ {
+ if (!cell->isDefault() && !cell->isPartOfMerged())
+ {
+ TQPoint point(cell->column(), cell->row());
+ if (range.contains(point))
+ {
+ root.appendChild(cell->save( dd, 0, top - 1, copy, copy, era));
+ }
+ }
+ }
+
+ // ##### Inefficient
+ // Save the row formats if there are any
+ RowFormat* format;
+ for (int row = range.top(); row <= range.bottom(); ++row)
+ {
+ format = rowFormat( row );
+ if (format && !format->isDefault())
+ {
+ TQDomElement e = format->save(dd, top - 1, copy);
+ if (!e.isNull())
+ {
+ rows.appendChild( e );
+ }
+ }
+ }
+ continue;
+ }
+
+ //
+ // Entire columns selected?
+ //
+ if ((*it)->isColumn())
+ {
+ TQDomElement columns = dd.createElement("columns");
+ columns.setAttribute( "count", range.width() );
+ columns.setAttribute( "column", range.left() - left + 1 );
+ root.appendChild( columns );
+
+ // Save all cells.
+ for (Cell* cell = d->cells.firstCell();cell; cell = cell->nextCell())
+ {
+ if (!cell->isDefault() && !cell->isPartOfMerged())
+ {
+ TQPoint point(cell->column(), cell->row());
+ if (range.contains(point))
+ {
+ root.appendChild(cell->save( dd, left - 1, 0, copy, copy, era));
+ }
+ }
+ }
+
+ // ##### Inefficient
+ // Save the column formats if there are any
+ ColumnFormat* format;
+ for (int col = range.left(); col <= range.right(); ++col)
+ {
+ format = columnFormat(col);
+ if (format && !format->isDefault())
+ {
+ TQDomElement e = format->save(dd, left - 1, copy);
+ if (!e.isNull())
+ {
+ columns.appendChild(e);
+ }
+ }
+ }
+ continue;
+ }
+
+ // Save all cells.
+ //store all cell
+ //when they don't exist we created them
+ //because it's necessary when there is a format on a column/row
+ //but I remove cell which is inserted.
+ Cell* cell;
+ bool insert;
+ enableScrollBarUpdates(false);
+ for (int col = range.left(); col <= range.right(); ++col)
+ {
+ for (int row = range.top(); row <= range.bottom(); ++row)
+ {
+ insert = false;
+ cell = cellAt(col, row);
+ if (cell == d->defaultCell)
+ {
+ cell = new Cell(this, col, row);
+ insertCell(cell);
+ insert = true;
+ }
+ root.appendChild(cell->save(dd, left - 1, top - 1, true, copy, era));
+ if (insert)
+ {
+ d->cells.remove(col, row);
+ }
+ }
+ }
+ enableScrollBarUpdates(true);
+ }
+ return dd;
+}
+
+TQDomElement Sheet::saveXML( TQDomDocument& dd )
+{
+ TQDomElement sheet = dd.createElement( "table" );
+ sheet.setAttribute( "name", d->name );
+
+
+ //Laurent: for oasis format I think that we must use style:direction...
+ sheet.setAttribute( "layoutDirection", (d->layoutDirection == RightToLeft) ? "rtl" : "ltr" );
+ sheet.setAttribute( "columnnumber", (int)d->showColumnNumber);
+ sheet.setAttribute( "borders", (int)d->showPageBorders);
+ sheet.setAttribute( "hide", (int)d->hide);
+ sheet.setAttribute( "hidezero", (int)d->hideZero);
+ sheet.setAttribute( "firstletterupper", (int)d->firstLetterUpper);
+ sheet.setAttribute( "grid", (int)d->showGrid );
+ sheet.setAttribute( "printGrid", (int)d->print->printGrid() );
+ sheet.setAttribute( "printCommentIndicator", (int)d->print->printCommentIndicator() );
+ sheet.setAttribute( "printFormulaIndicator", (int)d->print->printFormulaIndicator() );
+ sheet.setAttribute( "showFormula", (int)d->showFormula);
+ sheet.setAttribute( "showFormulaIndicator", (int)d->showFormulaIndicator);
+ sheet.setAttribute( "showCommentIndicator", (int)d->showCommentIndicator);
+ sheet.setAttribute( "lcmode", (int)d->lcMode);
+ sheet.setAttribute( "autoCalc", (int)d->autoCalc);
+ sheet.setAttribute( "borders1.2", 1);
+ if ( !d->password.isNull() )
+ {
+ if ( d->password.size() > 0 )
+ {
+ TQCString str = KCodecs::base64Encode( d->password );
+ sheet.setAttribute( "protected", TQString( str.data() ) );
+ }
+ else
+ sheet.setAttribute( "protected", "" );
+ }
+
+ // paper parameters
+ TQDomElement paper = dd.createElement( "paper" );
+ paper.setAttribute( "format", d->print->paperFormatString() );
+ paper.setAttribute( "orientation", d->print->orientationString() );
+ sheet.appendChild( paper );
+
+ TQDomElement borders = dd.createElement( "borders" );
+ borders.setAttribute( "left", d->print->leftBorder() );
+ borders.setAttribute( "top", d->print->topBorder() );
+ borders.setAttribute( "right", d->print->rightBorder() );
+ borders.setAttribute( "bottom", d->print->bottomBorder() );
+ paper.appendChild( borders );
+
+ TQDomElement head = dd.createElement( "head" );
+ paper.appendChild( head );
+ if ( !d->print->headLeft().isEmpty() )
+ {
+ TQDomElement left = dd.createElement( "left" );
+ head.appendChild( left );
+ left.appendChild( dd.createTextNode( d->print->headLeft() ) );
+ }
+ if ( !d->print->headMid().isEmpty() )
+ {
+ TQDomElement center = dd.createElement( "center" );
+ head.appendChild( center );
+ center.appendChild( dd.createTextNode( d->print->headMid() ) );
+ }
+ if ( !d->print->headRight().isEmpty() )
+ {
+ TQDomElement right = dd.createElement( "right" );
+ head.appendChild( right );
+ right.appendChild( dd.createTextNode( d->print->headRight() ) );
+ }
+ TQDomElement foot = dd.createElement( "foot" );
+ paper.appendChild( foot );
+ if ( !d->print->footLeft().isEmpty() )
+ {
+ TQDomElement left = dd.createElement( "left" );
+ foot.appendChild( left );
+ left.appendChild( dd.createTextNode( d->print->footLeft() ) );
+ }
+ if ( !d->print->footMid().isEmpty() )
+ {
+ TQDomElement center = dd.createElement( "center" );
+ foot.appendChild( center );
+ center.appendChild( dd.createTextNode( d->print->footMid() ) );
+ }
+ if ( !d->print->footRight().isEmpty() )
+ {
+ TQDomElement right = dd.createElement( "right" );
+ foot.appendChild( right );
+ right.appendChild( dd.createTextNode( d->print->footRight() ) );
+ }
+
+ // print range
+ TQDomElement printrange = dd.createElement( "printrange-rect" );
+ TQRect _printRange = d->print->printRange();
+ int left = _printRange.left();
+ int right = _printRange.right();
+ int top = _printRange.top();
+ int bottom = _printRange.bottom();
+ //If whole rows are selected, then we store zeros, as KS_colMax may change in future
+ if ( left == 1 && right == KS_colMax )
+ {
+ left = 0;
+ right = 0;
+ }
+ //If whole columns are selected, then we store zeros, as KS_rowMax may change in future
+ if ( top == 1 && bottom == KS_rowMax )
+ {
+ top = 0;
+ bottom = 0;
+ }
+ printrange.setAttribute( "left-rect", left );
+ printrange.setAttribute( "right-rect", right );
+ printrange.setAttribute( "bottom-rect", bottom );
+ printrange.setAttribute( "top-rect", top );
+ sheet.appendChild( printrange );
+
+ // Print repeat columns
+ TQDomElement printRepeatColumns = dd.createElement( "printrepeatcolumns" );
+ printRepeatColumns.setAttribute( "left", d->print->printRepeatColumns().first );
+ printRepeatColumns.setAttribute( "right", d->print->printRepeatColumns().second );
+ sheet.appendChild( printRepeatColumns );
+
+ // Print repeat rows
+ TQDomElement printRepeatRows = dd.createElement( "printrepeatrows" );
+ printRepeatRows.setAttribute( "top", d->print->printRepeatRows().first );
+ printRepeatRows.setAttribute( "bottom", d->print->printRepeatRows().second );
+ sheet.appendChild( printRepeatRows );
+
+ //Save print zoom
+ sheet.setAttribute( "printZoom", d->print->zoom() );
+
+ //Save page limits
+ sheet.setAttribute( "printPageLimitX", d->print->pageLimitX() );
+ sheet.setAttribute( "printPageLimitY", d->print->pageLimitY() );
+
+ // Save all cells.
+ Cell* c = d->cells.firstCell();
+ for( ;c; c = c->nextCell() )
+ {
+ if ( !c->isDefault() )
+ {
+ TQDomElement e = c->save( dd );
+ if ( !e.isNull() )
+ sheet.appendChild( e );
+ }
+ }
+
+ // Save all RowFormat objects.
+ RowFormat* rl = d->rows.first();
+ for( ; rl; rl = rl->next() )
+ {
+ if ( !rl->isDefault() )
+ {
+ TQDomElement e = rl->save( dd );
+ if ( e.isNull() )
+ return TQDomElement();
+ sheet.appendChild( e );
+ }
+ }
+
+ // Save all ColumnFormat objects.
+ ColumnFormat* cl = d->columns.first();
+ for( ; cl; cl = cl->next() )
+ {
+ if ( !cl->isDefault() )
+ {
+ TQDomElement e = cl->save( dd );
+ if ( e.isNull() )
+ return TQDomElement();
+ sheet.appendChild( e );
+ }
+ }
+
+ TQPtrListIterator<EmbeddedObject> chl = doc()->embeddedObjects();
+ for( ; chl.current(); ++chl )
+ {
+ if ( chl.current()->sheet() == this )
+ {
+ TQDomElement e = chl.current()->save( dd );
+
+ if ( e.isNull() )
+ return TQDomElement();
+ sheet.appendChild( e );
+ }
+ }
+ return sheet;
+}
+
+bool Sheet::isLoading()
+{
+ return doc()->isLoading();
+}
+
+
+TQPtrList<EmbeddedObject> Sheet::getSelectedObjects()
+{
+ TQPtrList<EmbeddedObject> objects;
+ TQPtrListIterator<EmbeddedObject> it = doc()->embeddedObjects();
+ for ( ; it.current() ; ++it )
+ {
+ if( it.current()->isSelected()
+ && it.current()->sheet() == this )
+ {
+ objects.append( it.current() );
+ }
+ }
+ return objects;
+}
+
+KoRect Sheet::getRealRect( bool all )
+{
+ KoRect rect;
+
+ TQPtrListIterator<EmbeddedObject> it( doc()->embeddedObjects() );
+ for ( ; it.current() ; ++it )
+ {
+
+ if ( all || ( it.current()->isSelected() && ! it.current()->isProtect() ) )
+ rect |= it.current()->geometry();
+ }
+
+ return rect;
+}
+
+// move object for releasemouseevent
+KCommand *Sheet::moveObject(View *_view, double diffx, double diffy)
+{
+ bool createCommand=false;
+ MoveObjectByCmd *moveByCmd=0L;
+ Canvas * canvas = _view->canvasWidget();
+ TQPtrList<EmbeddedObject> _objects;
+ _objects.setAutoDelete( false );
+ TQPtrListIterator<EmbeddedObject> it( doc()->embeddedObjects()/*m_objectList*/ );
+ for ( ; it.current() ; ++it )
+ {
+ if ( it.current()->isSelected() && !it.current()->isProtect())
+ {
+ _objects.append( it.current() );
+ KoRect geometry = it.current()->geometry();
+ geometry.moveBy( -canvas->xOffset(), -canvas->yOffset() );
+ TQRect br = doc()->zoomRect( geometry/*it.current()->geometry()*/ );
+ br.moveBy( doc()->zoomItX( diffx ), doc()->zoomItY( diffy ) );
+ br.moveBy( doc()->zoomItX( -canvas->xOffset() ), doc()->zoomItY( -canvas->yOffset() ) );
+ canvas->repaint( br ); // Previous position
+ canvas->repaintObject( it.current() ); // New position
+ createCommand=true;
+ }
+ }
+ if(createCommand) {
+ moveByCmd = new MoveObjectByCmd( i18n( "Move Objects" ), KoPoint( diffx, diffy ),
+ _objects, doc(), this );
+
+// m_doc->updateSideBarItem( this );
+ }
+ return moveByCmd;
+}
+
+KCommand *Sheet::moveObject(View *_view,const KoPoint &_move,bool key)
+{
+ TQPtrList<EmbeddedObject> _objects;
+ _objects.setAutoDelete( false );
+ MoveObjectByCmd *moveByCmd=0L;
+ Canvas * canvas = _view->canvasWidget();
+ TQPtrListIterator<EmbeddedObject> it( doc()->embeddedObjects()/*m_objectList*/ );
+ for ( ; it.current() ; ++it )
+ {
+ if ( it.current()->isSelected() && !it.current()->isProtect()) {
+
+ KoRect geometry = it.current()->geometry();
+ geometry.moveBy( -canvas->xOffset(), -canvas->yOffset() );
+ TQRect oldBoundingRect = doc()->zoomRect( geometry );
+
+
+ KoRect r = it.current()->geometry();
+ r.moveBy( _move.x(), _move.y() );
+
+ it.current()->setGeometry( r );
+ _objects.append( it.current() );
+
+ canvas->repaint( oldBoundingRect );
+ canvas->repaintObject( it.current() );
+ }
+ }
+
+ if ( key && !_objects.isEmpty())
+ moveByCmd = new MoveObjectByCmd( i18n( "Move Objects" ),
+ KoPoint( _move ),
+ _objects, doc() ,this );
+
+ return moveByCmd;
+}
+
+/*
+ * Check if object name already exists.
+ */
+bool Sheet::objectNameExists( EmbeddedObject *object, TQPtrList<EmbeddedObject> &list ) {
+ TQPtrListIterator<EmbeddedObject> it( list );
+
+ for ( it.toFirst(); it.current(); ++it ) {
+ // object name can exist in current object.
+ if ( it.current()->getObjectName() == object->getObjectName() &&
+ it.current() != object ) {
+ return true;
+ }
+ }
+ return false;
+}
+
+void Sheet::unifyObjectName( EmbeddedObject *object ) {
+ if ( object->getObjectName().isEmpty() ) {
+ object->setObjectName( object->getTypeString() );
+ }
+ TQString objectName( object->getObjectName() );
+
+ TQPtrList<EmbeddedObject> list( doc()->embeddedObjects() );
+
+ int count = 1;
+
+ while ( objectNameExists( object, list ) ) {
+ count++;
+ TQRegExp rx( " \\(\\d{1,3}\\)$" );
+ if ( rx.search( objectName ) != -1 ) {
+ objectName.remove( rx );
+ }
+ objectName += TQString(" (%1)").arg( count );
+ object->setObjectName( objectName );
+ }
+}
+
+
+void Sheet::checkContentDirection( TQString const & name )
+{
+ /* set sheet's direction to RTL if sheet name is an RTL string */
+ if ( (name.isRightToLeft()) )
+ setLayoutDirection( RightToLeft );
+ else
+ setLayoutDirection( LeftToRight );
+
+ emit sig_refreshView();
+}
+
+bool Sheet::loadSheetStyleFormat( TQDomElement *style )
+{
+ TQString hleft, hmiddle, hright;
+ TQString fleft, fmiddle, fright;
+ TQDomNode header = KoDom::namedItemNS( *style, KoXmlNS::style, "header" );
+
+ if ( !header.isNull() )
+ {
+ kdDebug() << "Header exists" << endl;
+ TQDomNode part = KoDom::namedItemNS( header, KoXmlNS::style, "region-left" );
+ if ( !part.isNull() )
+ {
+ hleft = getPart( part );
+ kdDebug() << "Header left: " << hleft << endl;
+ }
+ else
+ kdDebug() << "Style:region:left doesn't exist!" << endl;
+ part = KoDom::namedItemNS( header, KoXmlNS::style, "region-center" );
+ if ( !part.isNull() )
+ {
+ hmiddle = getPart( part );
+ kdDebug() << "Header middle: " << hmiddle << endl;
+ }
+ part = KoDom::namedItemNS( header, KoXmlNS::style, "region-right" );
+ if ( !part.isNull() )
+ {
+ hright = getPart( part );
+ kdDebug() << "Header right: " << hright << endl;
+ }
+ }
+ //TODO implement it under kspread
+ TQDomNode headerleft = KoDom::namedItemNS( *style, KoXmlNS::style, "header-left" );
+ if ( !headerleft.isNull() )
+ {
+ TQDomElement e = headerleft.toElement();
+ if ( e.hasAttributeNS( KoXmlNS::style, "display" ) )
+ kdDebug()<<"header.hasAttribute( style:display ) :"<<e.hasAttributeNS( KoXmlNS::style, "display" )<<endl;
+ else
+ kdDebug()<<"header left doesn't has attribute style:display \n";
+ }
+ //TODO implement it under kspread
+ TQDomNode footerleft = KoDom::namedItemNS( *style, KoXmlNS::style, "footer-left" );
+ if ( !footerleft.isNull() )
+ {
+ TQDomElement e = footerleft.toElement();
+ if ( e.hasAttributeNS( KoXmlNS::style, "display" ) )
+ kdDebug()<<"footer.hasAttribute( style:display ) :"<<e.hasAttributeNS( KoXmlNS::style, "display" )<<endl;
+ else
+ kdDebug()<<"footer left doesn't has attribute style:display \n";
+ }
+
+ TQDomNode footer = KoDom::namedItemNS( *style, KoXmlNS::style, "footer" );
+
+ if ( !footer.isNull() )
+ {
+ TQDomNode part = KoDom::namedItemNS( footer, KoXmlNS::style, "region-left" );
+ if ( !part.isNull() )
+ {
+ fleft = getPart( part );
+ kdDebug() << "Footer left: " << fleft << endl;
+ }
+ part = KoDom::namedItemNS( footer, KoXmlNS::style, "region-center" );
+ if ( !part.isNull() )
+ {
+ fmiddle = getPart( part );
+ kdDebug() << "Footer middle: " << fmiddle << endl;
+ }
+ part = KoDom::namedItemNS( footer, KoXmlNS::style, "region-right" );
+ if ( !part.isNull() )
+ {
+ fright = getPart( part );
+ kdDebug() << "Footer right: " << fright << endl;
+ }
+ }
+
+ print()->setHeadFootLine( hleft, hmiddle, hright,
+ fleft, fmiddle, fright );
+ return true;
+}
+
+void Sheet::replaceMacro( TQString & text, const TQString & old, const TQString & newS )
+{
+ int n = text.find( old );
+ if ( n != -1 )
+ text = text.replace( n, old.length(), newS );
+}
+
+
+TQString Sheet::getPart( const TQDomNode & part )
+{
+ TQString result;
+ TQDomElement e = KoDom::namedItemNS( part, KoXmlNS::text, "p" );
+ while ( !e.isNull() )
+ {
+ TQString text = e.text();
+ kdDebug() << "PART: " << text << endl;
+
+ TQDomElement macro = KoDom::namedItemNS( e, KoXmlNS::text, "time" );
+ if ( !macro.isNull() )
+ replaceMacro( text, macro.text(), "<time>" );
+
+ macro = KoDom::namedItemNS( e, KoXmlNS::text, "date" );
+ if ( !macro.isNull() )
+ replaceMacro( text, macro.text(), "<date>" );
+
+ macro = KoDom::namedItemNS( e, KoXmlNS::text, "page-number" );
+ if ( !macro.isNull() )
+ replaceMacro( text, macro.text(), "<page>" );
+
+ macro = KoDom::namedItemNS( e, KoXmlNS::text, "page-count" );
+ if ( !macro.isNull() )
+ replaceMacro( text, macro.text(), "<pages>" );
+
+ macro = KoDom::namedItemNS( e, KoXmlNS::text, "sheet-name" );
+ if ( !macro.isNull() )
+ replaceMacro( text, macro.text(), "<sheet>" );
+
+ macro = KoDom::namedItemNS( e, KoXmlNS::text, "title" );
+ if ( !macro.isNull() )
+ replaceMacro( text, macro.text(), "<name>" );
+
+ macro = KoDom::namedItemNS( e, KoXmlNS::text, "file-name" );
+ if ( !macro.isNull() )
+ replaceMacro( text, macro.text(), "<file>" );
+
+ //add support for multi line into kspread
+ if ( !result.isEmpty() )
+ result += '\n';
+ result += text;
+ e = e.nextSibling().toElement();
+ }
+
+ return result;
+}
+
+
+bool Sheet::loadOasis( const TQDomElement& sheetElement, KoOasisLoadingContext& oasisContext, TQDict<Style>& styleMap )
+{
+ d->layoutDirection = LeftToRight;
+ if ( sheetElement.hasAttributeNS( KoXmlNS::table, "style-name" ) )
+ {
+ TQString stylename = sheetElement.attributeNS( KoXmlNS::table, "style-name", TQString() );
+ //kdDebug()<<" style of table :"<<stylename<<endl;
+ const TQDomElement *style = oasisContext.oasisStyles().findStyle( stylename, "table" );
+ Q_ASSERT( style );
+ //kdDebug()<<" style :"<<style<<endl;
+ if ( style )
+ {
+ TQDomElement properties( KoDom::namedItemNS( *style, KoXmlNS::style, "table-properties" ) );
+ if ( !properties.isNull() )
+ {
+ if ( properties.hasAttributeNS( KoXmlNS::table, "display" ) )
+ {
+ bool visible = (properties.attributeNS( KoXmlNS::table, "display", TQString() ) == "true" ? true : false );
+ d->hide = !visible;
+ }
+ }
+ if ( style->hasAttributeNS( KoXmlNS::style, "master-page-name" ) )
+ {
+ TQString masterPageStyleName = style->attributeNS( KoXmlNS::style, "master-page-name", TQString() );
+ //kdDebug()<<"style->attribute( style:master-page-name ) :"<<masterPageStyleName <<endl;
+ TQDomElement *masterStyle = oasisContext.oasisStyles().masterPages()[masterPageStyleName];
+ //kdDebug()<<"oasisStyles.styles()[masterPageStyleName] :"<<masterStyle<<endl;
+ if ( masterStyle )
+ {
+ loadSheetStyleFormat( masterStyle );
+ if ( masterStyle->hasAttributeNS( KoXmlNS::style, "page-layout-name" ) )
+ {
+ TQString masterPageLayoutStyleName = masterStyle->attributeNS( KoXmlNS::style, "page-layout-name", TQString() );
+ //kdDebug()<<"masterPageLayoutStyleName :"<<masterPageLayoutStyleName<<endl;
+ const TQDomElement *masterLayoutStyle = oasisContext.oasisStyles().findStyle( masterPageLayoutStyleName );
+ if ( masterLayoutStyle )
+ {
+ //kdDebug()<<"masterLayoutStyle :"<<masterLayoutStyle<<endl;
+ KoStyleStack styleStack;
+ styleStack.setTypeProperties( "page-layout" );
+ styleStack.push( *masterLayoutStyle );
+ loadOasisMasterLayoutPage( styleStack );
+ }
+ }
+ }
+ }
+ }
+ }
+
+ //Maps from a column index to the name of the default cell style for that column
+ TQMap<int,TQString> defaultColumnCellStyles;
+
+ int rowIndex = 1;
+ int indexCol = 1;
+ TQDomNode rowNode = sheetElement.firstChild();
+ // Some spreadsheet programs may support more rows than
+ // KSpread so limit the number of repeated rows.
+ // FIXME POSSIBLE DATA LOSS!
+ while( !rowNode.isNull() && rowIndex <= KS_rowMax )
+ {
+ kdDebug()<<" rowIndex :"<<rowIndex<<" indexCol :"<<indexCol<<endl;
+ TQDomElement rowElement = rowNode.toElement();
+ if( !rowElement.isNull() )
+ {
+ kdDebug()<<" Sheet::loadOasis rowElement.tagName() :"<<rowElement.localName()<<endl;
+ if ( rowElement.namespaceURI() == KoXmlNS::table )
+ {
+ if ( rowElement.localName()=="table-column" && indexCol <= KS_colMax )
+ {
+ kdDebug ()<<" table-column found : index column before "<< indexCol<<endl;
+ loadColumnFormat( rowElement, oasisContext.oasisStyles(), indexCol , styleMap);
+ kdDebug ()<<" table-column found : index column after "<< indexCol<<endl;
+ }
+ else if ( rowElement.localName() == "table-header-rows" )
+ {
+ TQDomNode headerRowNode = rowElement.firstChild();
+ while ( !headerRowNode.isNull() )
+ {
+ // NOTE Handle header rows as ordinary ones
+ // as long as they're not supported.
+ loadRowFormat( headerRowNode.toElement(), rowIndex,
+ oasisContext, /*rowNode.isNull() ,*/ styleMap );
+ headerRowNode = headerRowNode.nextSibling();
+ }
+ }
+ else if( rowElement.localName() == "table-row" )
+ {
+ kdDebug()<<" table-row found :index row before "<<rowIndex<<endl;
+ loadRowFormat( rowElement, rowIndex, oasisContext, /*rowNode.isNull() ,*/ styleMap );
+ kdDebug()<<" table-row found :index row after "<<rowIndex<<endl;
+ }
+ else if ( rowElement.localName() == "shapes" )
+ loadOasisObjects( rowElement, oasisContext );
+ }
+ }
+ rowNode = rowNode.nextSibling();
+ }
+
+ if ( sheetElement.hasAttributeNS( KoXmlNS::table, "print-ranges" ) )
+ {
+ // e.g.: Sheet4.A1:Sheet4.E28
+ TQString range = sheetElement.attributeNS( KoXmlNS::table, "print-ranges", TQString() );
+ range = Oasis::decodeFormula( range );
+ Range p( range );
+ if ( sheetName() == p.sheetName() )
+ d->print->setPrintRange( p.range() );
+ }
+
+
+ if ( sheetElement.attributeNS( KoXmlNS::table, "protected", TQString() ) == "true" )
+ {
+ TQCString passwd( "" );
+ if ( sheetElement.hasAttributeNS( KoXmlNS::table, "protection-key" ) )
+ {
+ TQString p = sheetElement.attributeNS( KoXmlNS::table, "protection-key", TQString() );
+ TQCString str( p.latin1() );
+ kdDebug(30518) << "Decoding password: " << str << endl;
+ passwd = KCodecs::base64Decode( str );
+ }
+ kdDebug(30518) << "Password hash: '" << passwd << "'" << endl;
+ d->password = passwd;
+ }
+ return true;
+}
+
+
+void Sheet::loadOasisObjects( const TQDomElement &parent, KoOasisLoadingContext& oasisContext )
+{
+ TQDomElement e;
+ TQDomNode n = parent.firstChild();
+ while( !n.isNull() )
+ {
+ e = n.toElement();
+ if ( e.localName() == "frame" && e.namespaceURI() == KoXmlNS::draw )
+ {
+ EmbeddedObject *obj = 0;
+ TQDomNode object = KoDom::namedItemNS( e, KoXmlNS::draw, "object" );
+ if ( !object.isNull() )
+ {
+ if ( !object.toElement().attributeNS( KoXmlNS::draw, "notify-on-update-of-ranges", TQString()).isNull() )
+ obj = new EmbeddedChart( doc(), this );
+ else
+ obj = new EmbeddedKOfficeObject( doc(), this );
+ }
+ else
+ {
+ TQDomNode image = KoDom::namedItemNS( e, KoXmlNS::draw, "image" );
+ if ( !image.isNull() )
+ obj = new EmbeddedPictureObject( this, doc()->pictureCollection() );
+ else
+ kdDebug() << "Object type wasn't loaded!" << endl;
+ }
+
+ if ( obj )
+ {
+ obj->loadOasis( e, oasisContext );
+ insertObject( obj );
+ }
+ }
+ n = n.nextSibling();
+ }
+}
+
+
+void Sheet::loadOasisMasterLayoutPage( KoStyleStack &styleStack )
+{
+ // use A4 as default page size
+ float left = 20.0;
+ float right = 20.0;
+ float top = 20.0;
+ float bottom = 20.0;
+ float width = 210.0;
+ float height = 297.0;
+ TQString orientation = "Portrait";
+ TQString format;
+
+ // Laurent : Why we stored layout information as Millimeter ?!!!!!
+ // kspread used point for all other attribute
+ // I don't understand :(
+ if ( styleStack.hasAttributeNS( KoXmlNS::fo, "page-width" ) )
+ {
+ width = KoUnit::toMM(KoUnit::parseValue( styleStack.attributeNS( KoXmlNS::fo, "page-width" ) ) );
+ }
+ if ( styleStack.hasAttributeNS( KoXmlNS::fo, "page-height" ) )
+ {
+ height = KoUnit::toMM( KoUnit::parseValue( styleStack.attributeNS( KoXmlNS::fo, "page-height" ) ) );
+ }
+ if ( styleStack.hasAttributeNS( KoXmlNS::fo, "margin-top" ) )
+ {
+ top = KoUnit::toMM(KoUnit::parseValue( styleStack.attributeNS( KoXmlNS::fo, "margin-top" ) ) );
+ }
+ if ( styleStack.hasAttributeNS( KoXmlNS::fo, "margin-bottom" ) )
+ {
+ bottom = KoUnit::toMM(KoUnit::parseValue( styleStack.attributeNS( KoXmlNS::fo, "margin-bottom" ) ) );
+ }
+ if ( styleStack.hasAttributeNS( KoXmlNS::fo, "margin-left" ) )
+ {
+ left = KoUnit::toMM(KoUnit::parseValue( styleStack.attributeNS( KoXmlNS::fo, "margin-left" ) ) );
+ }
+ if ( styleStack.hasAttributeNS( KoXmlNS::fo, "margin-right" ) )
+ {
+ right = KoUnit::toMM(KoUnit::parseValue( styleStack.attributeNS( KoXmlNS::fo, "margin-right" ) ) );
+ }
+ if ( styleStack.hasAttributeNS( KoXmlNS::style, "writing-mode" ) )
+ {
+ kdDebug()<<"styleStack.hasAttribute( style:writing-mode ) :"<<styleStack.hasAttributeNS( KoXmlNS::style, "writing-mode" )<<endl;
+ d->layoutDirection = ( styleStack.attributeNS( KoXmlNS::style, "writing-mode" )=="lr-tb" ) ? LeftToRight : RightToLeft;
+ //TODO
+ //<value>lr-tb</value>
+ //<value>rl-tb</value>
+ //<value>tb-rl</value>
+ //<value>tb-lr</value>
+ //<value>lr</value>
+ //<value>rl</value>
+ //<value>tb</value>
+ //<value>page</value>
+
+ }
+ if ( styleStack.hasAttributeNS( KoXmlNS::style, "print-orientation" ) )
+ {
+ orientation = ( styleStack.attributeNS( KoXmlNS::style, "print-orientation" )=="landscape" ) ? "Landscape" : "Portrait" ;
+ }
+ if ( styleStack.hasAttributeNS( KoXmlNS::style, "num-format" ) )
+ {
+ //not implemented into kspread
+ //These attributes specify the numbering style to use.
+ //If a numbering style is not specified, the numbering style is inherited from
+ //the page style. See section 6.7.8 for information on these attributes
+ kdDebug()<<" num-format :"<<styleStack.attributeNS( KoXmlNS::style, "num-format" )<<endl;
+
+ }
+ if ( styleStack.hasAttributeNS( KoXmlNS::fo, "background-color" ) )
+ {
+ //TODO
+ kdDebug()<<" fo:background-color :"<<styleStack.attributeNS( KoXmlNS::fo, "background-color" )<<endl;
+ }
+ if ( styleStack.hasAttributeNS( KoXmlNS::style, "print" ) )
+ {
+ //todo parsing
+ TQString str = styleStack.attributeNS( KoXmlNS::style, "print" );
+ kdDebug()<<" style:print :"<<str<<endl;
+
+ if (str.contains( "headers" ) )
+ {
+ //TODO implement it into kspread
+ }
+ if ( str.contains( "grid" ) )
+ {
+ d->print->setPrintGrid( true );
+ }
+ if ( str.contains( "annotations" ) )
+ {
+ //TODO it's not implemented
+ }
+ if ( str.contains( "objects" ) )
+ {
+ //TODO it's not implemented
+ }
+ if ( str.contains( "charts" ) )
+ {
+ //TODO it's not implemented
+ }
+ if ( str.contains( "drawings" ) )
+ {
+ //TODO it's not implemented
+ }
+ if ( str.contains( "formulas" ) )
+ {
+ d->showFormula = true;
+ }
+ if ( str.contains( "zero-values" ) )
+ {
+ //TODO it's not implemented
+ }
+ }
+ if ( styleStack.hasAttributeNS( KoXmlNS::style, "table-centering" ) )
+ {
+ TQString str = styleStack.attributeNS( KoXmlNS::style, "table-centering" );
+ //TODO not implemented into kspread
+ kdDebug()<<" styleStack.attribute( style:table-centering ) :"<<str<<endl;
+#if 0
+ if ( str == "horizontal" )
+ {
+ }
+ else if ( str == "vertical" )
+ {
+ }
+ else if ( str == "both" )
+ {
+ }
+ else if ( str == "none" )
+ {
+ }
+ else
+ kdDebug()<<" table-centering unknown :"<<str<<endl;
+#endif
+ }
+ format = TQString( "%1x%2" ).arg( width ).arg( height );
+ kdDebug()<<" format : "<<format<<endl;
+ d->print->setPaperLayout( left, top, right, bottom, format, orientation );
+
+ kdDebug()<<" left margin :"<<left<<" right :"<<right<<" top :"<<top<<" bottom :"<<bottom<<endl;
+//<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"/>
+// TQString format = paper.attribute( "format" );
+// TQString orientation = paper.attribute( "orientation" );
+// d->print->setPaperLayout( left, top, right, bottom, format, orientation );
+// }
+}
+
+
+bool Sheet::loadColumnFormat(const TQDomElement& column, const KoOasisStyles& oasisStyles, int & indexCol, const TQDict<Style>& styleMap)
+{
+ kdDebug()<<"bool Sheet::loadColumnFormat(const TQDomElement& column, const KoOasisStyles& oasisStyles, unsigned int & indexCol ) index Col :"<<indexCol<<endl;
+
+ bool isNonDefaultColumn = false;
+
+ int number = 1;
+ if ( column.hasAttributeNS( KoXmlNS::table, "number-columns-repeated" ) )
+ {
+ bool ok = true;
+ int n = column.attributeNS( KoXmlNS::table, "number-columns-repeated", TQString() ).toInt( &ok );
+ if ( ok )
+ // Some spreadsheet programs may support more rows than KSpread so
+ // limit the number of repeated rows.
+ // FIXME POSSIBLE DATA LOSS!
+ number = TQMIN( n, KS_colMax - indexCol + 1 );
+ kdDebug() << "Repeated: " << number << endl;
+ }
+
+ Format layout( this , doc()->styleManager()->defaultStyle() );
+ if ( column.hasAttributeNS( KoXmlNS::table, "default-cell-style-name" ) )
+ {
+ const TQString styleName = column.attributeNS( KoXmlNS::table, "default-cell-style-name", TQString() );
+ if ( !styleName.isEmpty() )
+ {
+ Style* const style = styleMap[ styleName ];
+ if ( style )
+ {
+ layout.setStyle( style );
+ isNonDefaultColumn = true;
+ }
+ }
+ }
+
+ bool collapsed = false;
+ if ( column.hasAttributeNS( KoXmlNS::table, "visibility" ) )
+ {
+ const TQString visibility = column.attributeNS( KoXmlNS::table, "visibility", TQString() );
+ if ( visibility == "visible" )
+ collapsed = false;
+ else if ( visibility == "collapse" )
+ collapsed = true;
+ else if ( visibility == "filter" )
+ collapsed = false; // FIXME Stefan: Set to true, if filters are supported.
+ isNonDefaultColumn = true;
+ }
+
+ KoStyleStack styleStack;
+ if ( column.hasAttributeNS( KoXmlNS::table, "style-name" ) )
+ {
+ TQString str = column.attributeNS( KoXmlNS::table, "style-name", TQString() );
+ const TQDomElement *style = oasisStyles.findStyle( str, "table-column" );
+ if ( style )
+ {
+ styleStack.push( *style );
+ isNonDefaultColumn = true;
+ }
+ }
+ styleStack.setTypeProperties("table-column"); //style for column
+
+ double width = -1.0;
+ if ( styleStack.hasAttributeNS( KoXmlNS::style, "column-width" ) )
+ {
+ width = KoUnit::parseValue( styleStack.attributeNS( KoXmlNS::style, "column-width" ) , -1.0 );
+ kdDebug()<<" style:column-width : width :"<<width<<endl;
+ isNonDefaultColumn = true;
+ }
+
+ bool insertPageBreak = false;
+ if ( styleStack.hasAttributeNS( KoXmlNS::fo, "break-before" ) )
+ {
+ TQString str = styleStack.attributeNS( KoXmlNS::fo, "break-before" );
+ if ( str == "page" )
+ {
+ insertPageBreak = true;
+ }
+ else
+ kdDebug()<<" str :"<<str<<endl;
+ isNonDefaultColumn = true;
+ }
+
+ for ( int i = 0; i < number; ++i )
+ {
+// kdDebug()<<" insert new column: pos :"<<indexCol<<" width :"<<width<<" hidden ? "<<collapsed<<endl;
+
+ ColumnFormat* columnFormat;
+ if ( isNonDefaultColumn )
+ {
+ columnFormat = nonDefaultColumnFormat( indexCol );
+
+ if ( width != -1.0 ) //safe
+ columnFormat->setWidth( (int) width );
+ // if ( insertPageBreak )
+ // columnFormat->setPageBreak( true )
+ if ( collapsed )
+ columnFormat->setHide( true );
+ }
+ else
+ {
+ columnFormat = this->columnFormat( indexCol );
+ }
+ columnFormat->copy( layout );
+
+ ++indexCol;
+ }
+// kdDebug()<<" after index column !!!!!!!!!!!!!!!!!! :"<<indexCol<<endl;
+ return true;
+}
+
+
+bool Sheet::loadRowFormat( const TQDomElement& row, int &rowIndex, KoOasisLoadingContext& oasisContext, TQDict<Style>& styleMap )
+{
+// kdDebug()<<"Sheet::loadRowFormat( const TQDomElement& row, int &rowIndex,const KoOasisStyles& oasisStyles, bool isLast )***********\n";
+
+ int backupRow = rowIndex;
+ bool isNonDefaultRow = false;
+
+ KoStyleStack styleStack;
+ if ( row.hasAttributeNS( KoXmlNS::table, "style-name" ) )
+ {
+ TQString str = row.attributeNS( KoXmlNS::table, "style-name", TQString() );
+ const TQDomElement *style = oasisContext.oasisStyles().findStyle( str, "table-row" );
+ if ( style )
+ {
+ styleStack.push( *style );
+ isNonDefaultRow = true;
+ }
+ }
+ styleStack.setTypeProperties( "table-row" );
+
+ Format layout( this , doc()->styleManager()->defaultStyle() );
+ if ( row.hasAttributeNS( KoXmlNS::table,"default-cell-style-name" ) )
+ {
+ const TQString styleName = row.attributeNS( KoXmlNS::table, "default-cell-style-name", TQString() );
+ if ( !styleName.isEmpty() )
+ {
+ Style* const style = styleMap[ styleName ];
+ if ( style )
+ {
+ layout.setStyle( style );
+ isNonDefaultRow = true;
+ }
+ }
+ }
+
+ double height = -1.0;
+ if ( styleStack.hasAttributeNS( KoXmlNS::style, "row-height" ) )
+ {
+ height = KoUnit::parseValue( styleStack.attributeNS( KoXmlNS::style, "row-height" ) , -1.0 );
+ // kdDebug()<<" properties style:row-height : height :"<<height<<endl;
+ isNonDefaultRow = true;
+ }
+
+ int number = 1;
+ if ( row.hasAttributeNS( KoXmlNS::table, "number-rows-repeated" ) )
+ {
+ bool ok = true;
+ int n = row.attributeNS( KoXmlNS::table, "number-rows-repeated", TQString() ).toInt( &ok );
+ if ( ok )
+ // Some spreadsheet programs may support more rows than KSpread so
+ // limit the number of repeated rows.
+ // FIXME POSSIBLE DATA LOSS!
+ number = TQMIN( n, KS_rowMax - rowIndex + 1 );
+ }
+
+ bool collapse = false;
+ if ( row.hasAttributeNS( KoXmlNS::table, "visibility" ) )
+ {
+ const TQString visibility = row.attributeNS( KoXmlNS::table, "visibility", TQString() );
+ if ( visibility == "visible" )
+ collapse = false;
+ else if ( visibility == "collapse" )
+ collapse = true;
+ else if ( visibility == "filter" )
+ collapse = false; // FIXME Stefan: Set to true, if filters are supported.
+ isNonDefaultRow = true;
+ }
+
+ bool insertPageBreak = false;
+ if ( styleStack.hasAttributeNS( KoXmlNS::fo, "break-before" ) )
+ {
+ TQString str = styleStack.attributeNS( KoXmlNS::fo, "break-before" );
+ if ( str == "page" )
+ {
+ insertPageBreak = true;
+ }
+ // else
+ // kdDebug()<<" str :"<<str<<endl;
+ isNonDefaultRow = true;
+ }
+
+ //number == number of row to be copy. But we must copy cell too.
+ for ( int i = 0; i < number; ++i )
+ {
+ // kdDebug()<<" create non defaultrow format :"<<rowIndex<<" repeate : "<<number<<" height :"<<height<<endl;
+
+ RowFormat* rowFormat;
+ if ( isNonDefaultRow )
+ {
+ rowFormat = nonDefaultRowFormat( rowIndex );
+
+ if ( height != -1.0 )
+ rowFormat->setHeight( (int) height );
+ if ( collapse )
+ rowFormat->setHide( true );
+ }
+ else
+ {
+ rowFormat = this->rowFormat( rowIndex );
+ }
+ rowFormat->copy( layout );
+
+ ++rowIndex;
+ }
+
+ int columnIndex = 0;
+ TQDomNode cellNode = row.firstChild();
+ int endRow = min(backupRow+number,KS_rowMax);
+
+
+ while ( !cellNode.isNull() )
+ {
+ TQDomElement cellElement = cellNode.toElement();
+ if ( !cellElement.isNull() )
+ {
+ columnIndex++;
+ TQString localName = cellElement.localName();
+
+ if ( ((localName == "table-cell") || (localName == "covered-table-cell")) && cellElement.namespaceURI() == KoXmlNS::table)
+ {
+ //kdDebug() << "Loading cell #" << cellCount << endl;
+
+ Style* style = 0;
+ const bool cellHasStyle = cellElement.hasAttributeNS( KoXmlNS::table, "style-name" );
+ if ( cellHasStyle )
+ {
+ style = styleMap[ cellElement.attributeNS( KoXmlNS::table , "style-name" , TQString() ) ];
+ }
+
+ Cell* const cell = nonDefaultCell( columnIndex, backupRow ); // FIXME Stefan: if empty, delete afterwards
+ cell->loadOasis( cellElement, oasisContext, style );
+
+ int cols = 1;
+
+ // Copy this cell across & down, if it has repeated rows or columns, but only
+ // if the cell has some content or a style associated with it.
+ if ( (number > 1) || cellElement.hasAttributeNS( KoXmlNS::table, "number-columns-repeated" ) )
+ {
+ bool ok = false;
+ int n = cellElement.attributeNS( KoXmlNS::table, "number-columns-repeated", TQString() ).toInt( &ok );
+
+ if (ok)
+ // Some spreadsheet programs may support more columns than
+ // KSpread so limit the number of repeated columns.
+ // FIXME POSSIBLE DATA LOSS!
+ cols = TQMIN( n, KS_colMax - columnIndex + 1 );
+
+ if ( !cellHasStyle && ( cell->isEmpty() && cell->format()->comment( columnIndex, backupRow ).isEmpty() ) )
+ {
+ // just increment it
+ columnIndex += cols - 1;
+ }
+ else
+ {
+ for ( int k = cols ; k ; --k )
+ {
+ if ( k != cols )
+ columnIndex++;
+
+ for ( int newRow = backupRow; newRow < endRow; ++newRow )
+ {
+ Cell* target = nonDefaultCell( columnIndex, newRow );
+
+ if (cell != target)
+ target->copyAll( cell );
+ }
+ }
+ }
+ }
+ }
+ }
+ cellNode = cellNode.nextSibling();
+ }
+
+ return true;
+}
+
+void Sheet::maxRowCols( int & maxCols, int & maxRows )
+{
+ const Cell * cell = firstCell();
+ while ( cell )
+ {
+ if ( cell->column() > maxCols )
+ maxCols = cell->column();
+
+ if ( cell->row() > maxRows )
+ maxRows = cell->row();
+
+ cell = cell->nextCell();
+ }
+
+ const RowFormat * row = firstRow();
+ while ( row )
+ {
+ if ( row->row() > maxRows )
+ maxRows = row->row();
+
+ row = row->next();
+ }
+ const ColumnFormat* col = firstCol();
+ while ( col )
+ {
+ if ( col->column() > maxCols )
+ maxCols = col->column();
+
+ col = col->next();
+ }
+}
+
+
+bool Sheet::compareRows( int row1, int row2, int& maxCols ) const
+{
+ if ( *rowFormat( row1 ) != *rowFormat( row2 ) )
+ {
+// kdDebug() << "\t Formats of " << row1 << " and " << row2 << " are different" << endl;
+ return false;
+ }
+ // FIXME Stefan: Make use of the cluster functionality.
+ for ( int col = 1; col <= maxCols; ++col )
+ {
+ if ( *cellAt( col, row1 ) != *cellAt( col, row2 ) )
+ {
+// kdDebug() << "\t Cell at column " << col << " in row " << row2 << " differs from the one in row " << row1 << endl;
+ return false;
+ }
+ }
+ return true;
+}
+
+
+void Sheet::saveOasisHeaderFooter( KoXmlWriter &xmlWriter ) const
+{
+ TQString headerLeft = print()->headLeft();
+ TQString headerCenter= print()->headMid();
+ TQString headerRight = print()->headRight();
+
+ TQString footerLeft = print()->footLeft();
+ TQString footerCenter= print()->footMid();
+ TQString footerRight = print()->footRight();
+
+ xmlWriter.startElement( "style:header");
+ if ( ( !headerLeft.isEmpty() )
+ || ( !headerCenter.isEmpty() )
+ || ( !headerRight.isEmpty() ) )
+ {
+ xmlWriter.startElement( "style:region-left" );
+ xmlWriter.startElement( "text:p" );
+ convertPart( headerLeft, xmlWriter );
+ xmlWriter.endElement();
+ xmlWriter.endElement();
+
+ xmlWriter.startElement( "style:region-center" );
+ xmlWriter.startElement( "text:p" );
+ convertPart( headerCenter, xmlWriter );
+ xmlWriter.endElement();
+ xmlWriter.endElement();
+
+ xmlWriter.startElement( "style:region-right" );
+ xmlWriter.startElement( "text:p" );
+ convertPart( headerRight, xmlWriter );
+ xmlWriter.endElement();
+ xmlWriter.endElement();
+ }
+ else
+ {
+ xmlWriter.startElement( "text:p" );
+
+ xmlWriter.startElement( "text:sheet-name" );
+ xmlWriter.addTextNode( "???" );
+ xmlWriter.endElement();
+
+ xmlWriter.endElement();
+ }
+ xmlWriter.endElement();
+
+
+ xmlWriter.startElement( "style:footer");
+ if ( ( !footerLeft.isEmpty() )
+ || ( !footerCenter.isEmpty() )
+ || ( !footerRight.isEmpty() ) )
+ {
+ xmlWriter.startElement( "style:region-left" );
+ xmlWriter.startElement( "text:p" );
+ convertPart( footerLeft, xmlWriter );
+ xmlWriter.endElement();
+ xmlWriter.endElement(); //style:region-left
+
+ xmlWriter.startElement( "style:region-center" );
+ xmlWriter.startElement( "text:p" );
+ convertPart( footerCenter, xmlWriter );
+ xmlWriter.endElement();
+ xmlWriter.endElement();
+
+ xmlWriter.startElement( "style:region-right" );
+ xmlWriter.startElement( "text:p" );
+ convertPart( footerRight, xmlWriter );
+ xmlWriter.endElement();
+ xmlWriter.endElement();
+ }
+ else
+ {
+ xmlWriter.startElement( "text:p" );
+
+ xmlWriter.startElement( "text:sheet-name" );
+ xmlWriter.addTextNode( "Page " ); // ???
+ xmlWriter.endElement();
+
+ xmlWriter.startElement( "text:page-number" );
+ xmlWriter.addTextNode( "1" ); // ???
+ xmlWriter.endElement();
+
+ xmlWriter.endElement();
+ }
+ xmlWriter.endElement();
+
+
+}
+
+void Sheet::addText( const TQString & text, KoXmlWriter & writer ) const
+{
+ if ( !text.isEmpty() )
+ writer.addTextNode( text );
+}
+
+void Sheet::convertPart( const TQString & part, KoXmlWriter & xmlWriter ) const
+{
+ TQString text;
+ TQString var;
+
+ bool inVar = false;
+ uint i = 0;
+ uint l = part.length();
+ while ( i < l )
+ {
+ if ( inVar || part[i] == '<' )
+ {
+ inVar = true;
+ var += part[i];
+ if ( part[i] == '>' )
+ {
+ inVar = false;
+ if ( var == "<page>" )
+ {
+ addText( text, xmlWriter );
+ xmlWriter.startElement( "text:page-number" );
+ xmlWriter.addTextNode( "1" );
+ xmlWriter.endElement();
+ }
+ else if ( var == "<pages>" )
+ {
+ addText( text, xmlWriter );
+ xmlWriter.startElement( "text:page-count" );
+ xmlWriter.addTextNode( "99" ); //TODO I think that it can be different from 99
+ xmlWriter.endElement();
+ }
+ else if ( var == "<date>" )
+ {
+ addText( text, xmlWriter );
+ //text:p><text:date style:data-style-name="N2" text:date-value="2005-10-02">02/10/2005</text:date>, <text:time>10:20:12</text:time></text:p> "add style" => create new style
+#if 0 //FIXME
+ TQDomElement t = dd.createElement( "text:date" );
+ t.setAttribute( "text:date-value", "0-00-00" );
+ // todo: "style:data-style-name", "N2"
+ t.appendChild( dd.createTextNode( TQDate::currentDate().toString() ) );
+ parent.appendChild( t );
+#endif
+ }
+ else if ( var == "<time>" )
+ {
+ addText( text, xmlWriter );
+
+ xmlWriter.startElement( "text:time" );
+ xmlWriter.addTextNode( TQTime::currentTime().toString() );
+ xmlWriter.endElement();
+ }
+ else if ( var == "<file>" ) // filepath + name
+ {
+ addText( text, xmlWriter );
+ xmlWriter.startElement( "text:file-name" );
+ xmlWriter.addAttribute( "text:display", "full" );
+ xmlWriter.addTextNode( "???" );
+ xmlWriter.endElement();
+ }
+ else if ( var == "<name>" ) // filename
+ {
+ addText( text, xmlWriter );
+
+ xmlWriter.startElement( "text:title" );
+ xmlWriter.addTextNode( "???" );
+ xmlWriter.endElement();
+ }
+ else if ( var == "<author>" )
+ {
+ Doc* sdoc = d->workbook->doc();
+ KoDocumentInfo * docInfo = sdoc->documentInfo();
+ KoDocumentInfoAuthor * authorPage = static_cast<KoDocumentInfoAuthor*>( docInfo->page( "author" ) );
+
+ text += authorPage->fullName();
+
+ addText( text, xmlWriter );
+ }
+ else if ( var == "<email>" )
+ {
+ Doc* sdoc = d->workbook->doc();
+ KoDocumentInfo * docInfo = sdoc->documentInfo();
+ KoDocumentInfoAuthor * authorPage = static_cast<KoDocumentInfoAuthor*>( docInfo->page( "author" ) );
+
+ text += authorPage->email();
+ addText( text, xmlWriter );
+
+ }
+ else if ( var == "<org>" )
+ {
+ Doc* sdoc = d->workbook->doc();
+ KoDocumentInfo * docInfo = sdoc->documentInfo();
+ KoDocumentInfoAuthor * authorPage = static_cast<KoDocumentInfoAuthor*>( docInfo->page( "author" ) );
+
+ text += authorPage->company();
+ addText( text, xmlWriter );
+
+ }
+ else if ( var == "<sheet>" )
+ {
+ addText( text, xmlWriter );
+
+ xmlWriter.startElement( "text:sheet-name" );
+ xmlWriter.addTextNode( "???" );
+ xmlWriter.endElement();
+ }
+ else
+ {
+ // no known variable:
+ text += var;
+ addText( text, xmlWriter );
+ }
+
+ text = "";
+ var = "";
+ }
+ }
+ else
+ {
+ text += part[i];
+ }
+ ++i;
+ }
+ if ( !text.isEmpty() || !var.isEmpty() )
+ {
+ //we don't have var at the end =>store it
+ addText( text+var, xmlWriter );
+ }
+ kdDebug()<<" text end :"<<text<<" var :"<<var<<endl;
+}
+
+
+void Sheet::loadOasisSettings( const KoOasisSettings::NamedMap &settings )
+{
+ // Find the entry in the map that applies to this sheet (by name)
+ KoOasisSettings::Items items = settings.entry( d->name );
+ if ( items.isNull() )
+ return;
+ d->hideZero = items.parseConfigItemBool( "ShowZeroValues" );
+ d->showGrid = items.parseConfigItemBool( "ShowGrid" );
+ d->firstLetterUpper = items.parseConfigItemBool( "FirstLetterUpper" );
+
+ int cursorX = items.parseConfigItemInt( "CursorPositionX" );
+ int cursorY = items.parseConfigItemInt( "CursorPositionY" );
+ doc()->loadingInfo()->setCursorPosition( this, TQPoint( cursorX, cursorY ) );
+
+ double offsetX = items.parseConfigItemDouble( "xOffset" );
+ double offsetY = items.parseConfigItemDouble( "yOffset" );
+ doc()->loadingInfo()->setScrollingOffset( this, KoPoint( offsetX, offsetY ) );
+
+ d->showFormulaIndicator = items.parseConfigItemBool( "ShowFormulaIndicator" );
+ d->showCommentIndicator = items.parseConfigItemBool( "ShowCommentIndicator" );
+ d->showPageBorders = items.parseConfigItemBool( "ShowPageBorders" );
+ d->lcMode = items.parseConfigItemBool( "lcmode" );
+ d->autoCalc = items.parseConfigItemBool( "autoCalc" );
+ d->showColumnNumber = items.parseConfigItemBool( "ShowColumnNumber" );
+}
+
+void Sheet::saveOasisSettings( KoXmlWriter &settingsWriter ) const
+{
+ //not into each page into oo spec
+ settingsWriter.addConfigItem( "ShowZeroValues", d->hideZero );
+ settingsWriter.addConfigItem( "ShowGrid", d->showGrid );
+ //not define into oo spec
+ settingsWriter.addConfigItem( "FirstLetterUpper", d->firstLetterUpper);
+ settingsWriter.addConfigItem( "ShowFormulaIndicator", d->showFormulaIndicator );
+ settingsWriter.addConfigItem( "ShowCommentIndicator", d->showCommentIndicator );
+ settingsWriter.addConfigItem( "ShowPageBorders",d->showPageBorders );
+ settingsWriter.addConfigItem( "lcmode", d->lcMode );
+ settingsWriter.addConfigItem( "autoCalc", d->autoCalc );
+ settingsWriter.addConfigItem( "ShowColumnNumber", d->showColumnNumber );
+}
+
+bool Sheet::saveOasis( KoXmlWriter & xmlWriter, KoGenStyles &mainStyles, GenValidationStyles &valStyle, KoStore *store, KoXmlWriter* /*manifestWriter*/, int &indexObj, int &partIndexObj )
+{
+ int maxCols= 1;
+ int maxRows= 1;
+ xmlWriter.startElement( "table:table" );
+ xmlWriter.addAttribute( "table:name", d->name );
+ xmlWriter.addAttribute( "table:style-name", saveOasisSheetStyleName(mainStyles ) );
+ if ( !d->password.isEmpty() )
+ {
+ xmlWriter.addAttribute("table:protected", "true" );
+ TQCString str = KCodecs::base64Encode( d->password );
+ xmlWriter.addAttribute("table:protection-key", TQString( str.data() ) );/* FIXME !!!!*/
+ }
+ TQRect _printRange = d->print->printRange();
+ if ( _printRange != ( TQRect( TQPoint( 1, 1 ), TQPoint( KS_colMax, KS_rowMax ) ) ) )
+ {
+ TQString range= convertRangeToRef( d->name, _printRange );
+ kdDebug()<<" range : "<<range<<endl;
+ xmlWriter.addAttribute( "table:print-ranges", range );
+ }
+
+ saveOasisObjects( store, xmlWriter, mainStyles, indexObj, partIndexObj );
+ maxRowCols( maxCols, maxRows );
+ saveOasisColRowCell( xmlWriter, mainStyles, maxCols, maxRows, valStyle );
+ xmlWriter.endElement();
+ return true;
+}
+
+void Sheet::saveOasisPrintStyleLayout( KoGenStyle &style ) const
+{
+ TQString printParameter;
+ if ( d->print->printGrid() )
+ printParameter="grid ";
+ if ( d->print->printObjects() )
+ printParameter+="objects ";
+ if ( d->print->printCharts() )
+ printParameter+="charts ";
+ if ( d->showFormula )
+ printParameter+="formulas ";
+ if ( !printParameter.isEmpty() )
+ {
+ printParameter+="drawings zero-values"; //default print style attributes in OO
+ style.addProperty( "style:print", printParameter );
+ }
+}
+
+TQString Sheet::saveOasisSheetStyleName( KoGenStyles &mainStyles )
+{
+ KoGenStyle pageStyle( Doc::STYLE_PAGE, "table"/*FIXME I don't know if name is sheet*/ );
+
+ KoGenStyle pageMaster( Doc::STYLE_PAGEMASTER );
+ pageMaster.addAttribute( "style:page-layout-name", d->print->saveOasisSheetStyleLayout( mainStyles ) );
+
+ TQBuffer buffer;
+ buffer.open( IO_WriteOnly );
+ KoXmlWriter elementWriter( TQT_TQIODEVICE(&buffer) ); // TODO pass indentation level
+ saveOasisHeaderFooter(elementWriter);
+
+ TQString elementContents = TQString::fromUtf8( buffer.buffer(), buffer.buffer().size() );
+ pageMaster.addChildElement( "headerfooter", elementContents );
+ pageStyle.addAttribute( "style:master-page-name", mainStyles.lookup( pageMaster, "Standard" ) );
+
+ pageStyle.addProperty( "table:display", !d->hide );
+ return mainStyles.lookup( pageStyle, "ta" );
+}
+
+
+void Sheet::saveOasisColRowCell( KoXmlWriter& xmlWriter, KoGenStyles &mainStyles,
+ int maxCols, int maxRows, GenValidationStyles &valStyle )
+{
+ kdDebug() << "Sheet::saveOasisColRowCell: " << d->name << endl;
+ kdDebug() << "\t Sheet dimension: " << maxCols << " x " << maxRows << endl;
+
+ // saving the columns
+ //
+ int i = 1;
+ while ( i <= maxCols )
+ {
+// kdDebug() << "Sheet::saveOasisColRowCell: first col loop:"
+// << " i: " << i
+// << " column: " << column->column() << endl;
+ ColumnFormat* column = columnFormat( i );
+
+ KoGenStyle currentColumnStyle( Doc::STYLE_COLUMN_AUTO, "table-column" );
+ currentColumnStyle.addPropertyPt( "style:column-width", column->dblWidth() );
+ currentColumnStyle.addProperty( "fo:break-before", "auto" );/*FIXME auto or not ?*/
+
+ //style default layout for column
+ KoGenStyle currentDefaultCellStyle; // the type is determined in saveOasisCellStyle
+ TQString currentDefaultCellStyleName = column->saveOasisCellStyle( currentDefaultCellStyle, mainStyles );
+
+
+ bool hide = column->isHide();
+ bool refColumnIsDefault = column->isDefault();
+ int j = i;
+ int repeated = 1;
+
+ while ( j <= maxCols )
+ {
+// kdDebug() << "Sheet::saveOasisColRowCell: second col loop:"
+// << " j: " << j
+// << " column: " << nextColumn->column() << endl;
+ ColumnFormat* nextColumn = d->columns.next( j++ );
+
+ // no next or not the adjacent column?
+ if ( !nextColumn || nextColumn->column() != j )
+ {
+ if ( refColumnIsDefault )
+ {
+ // if the origin column was a default column,
+ // we count the default columns
+ if ( !nextColumn )
+ {
+ repeated = maxCols - i + 1;
+ }
+ else
+ {
+ repeated = nextColumn->column() - j + 1;
+ }
+ }
+ // otherwise we just stop here to process the adjacent
+ // column in the next iteration of the outer loop
+ break;
+ }
+#if 0
+ KoGenStyle nextColumnStyle( Doc::STYLE_COLUMN_AUTO, "table-column" );
+ nextColumnStyle.addPropertyPt( "style:column-width", nextColumn->dblWidth() );/*FIXME pt and not mm */
+ nextColumnStyle.addProperty( "fo:break-before", "auto" );/*FIXME auto or not ?*/
+
+ KoGenStyle nextDefaultCellStyle; // the type is determined in saveOasisCellStyle
+ TQString nextDefaultCellStyleName = nextColumn->saveOasisCellStyle( nextDefaultCellStyle, mainStyles );
+
+ if ( hide != nextColumn->isHide() ||
+ nextDefaultCellStyleName != currentDefaultCellStyleName ||
+ !( nextColumnStyle == currentColumnStyle ) )
+ {
+ break;
+ }
+#endif
+ if ( *column != *nextColumn )
+ {
+ break;
+ }
+ ++repeated;
+ }
+ xmlWriter.startElement( "table:table-column" );
+ if ( !column->isDefault() )
+ {
+ xmlWriter.addAttribute( "table:style-name", mainStyles.lookup( currentColumnStyle, "co" ) );
+
+ if ( !currentDefaultCellStyle.isDefaultStyle() )
+ xmlWriter.addAttribute( "table:default-cell-style-name", currentDefaultCellStyleName );
+
+ if ( hide )
+ xmlWriter.addAttribute( "table:visibility", "collapse" );
+ }
+
+ if ( repeated > 1 )
+ xmlWriter.addAttribute( "table:number-columns-repeated", repeated );
+
+ xmlWriter.endElement();
+
+ kdDebug() << "Sheet::saveOasisColRowCell: column " << i << " "
+ << "repeated " << repeated << " time(s)" << endl;
+ i += repeated;
+ }
+
+
+ // saving the rows and the cells
+ // we have to loop through all rows of the used area
+ for ( i = 1; i <= maxRows; ++i )
+ {
+ RowFormat* const row = rowFormat( i );
+
+ KoGenStyle currentRowStyle( Doc::STYLE_ROW_AUTO, "table-row" );
+ currentRowStyle.addPropertyPt( "style:row-height", row->dblHeight() );
+ currentRowStyle.addProperty( "fo:break-before", "auto" );/*FIXME auto or not ?*/
+
+ // default cell style for row
+ KoGenStyle currentDefaultCellStyle; // the type is determined in saveOasisCellStyle
+ TQString currentDefaultCellStyleName = row->saveOasisCellStyle( currentDefaultCellStyle, mainStyles );
+
+ xmlWriter.startElement( "table:table-row" );
+
+ if ( !row->isDefault() )
+ {
+ xmlWriter.addAttribute( "table:style-name", mainStyles.lookup( currentRowStyle, "ro" ) );
+ }
+ int repeated = 1;
+ // empty row?
+ if ( !getFirstCellRow( i ) )
+ {
+// kDebug() << "Sheet::saveOasisColRowCell: first row loop:"
+// << " i: " << i
+// << " row: " << row->row() << endl;
+ //bool isHidden = row->isHide();
+ bool isDefault = row->isDefault();
+ int j = i + 1;
+
+ // search for
+ // next non-empty row
+ // or
+ // next row with different Format
+ while ( j <= maxRows && !getFirstCellRow( j ) )
+ {
+ RowFormat* const nextRow = rowFormat( j );
+// kDebug() << "Sheet::saveOasisColRowCell: second row loop:"
+// << " j: " << j
+// << " row: " << nextRow->row() << endl;
+
+ // if the reference row has the default row format
+ if ( isDefault )
+ {
+ // if the next is not default, stop here
+ if ( !nextRow->isDefault() )
+ break;
+ // otherwise, jump to the next
+ ++j;
+ continue;
+ }
+#if 0
+ // create the Oasis representation of the format for the comparison
+ KoGenStyle nextRowStyle( Doc::STYLE_ROW_AUTO, "table-row" );
+ nextRowStyle.addPropertyPt( "style:row-height", nextRow->dblHeight() );
+ nextRowStyle.addProperty( "fo:break-before", "auto" );/*FIXME auto or not ?*/
+
+ // default cell style name for next row
+ KoGenStyle nextDefaultCellStyle; // the type is determined in saveOasisCellStyle
+ TQString nextDefaultCellStyleName = nextRow->saveOasisCellStyle( nextDefaultCellStyle, mainStyles );
+
+ // if the formats differ, stop here
+ if ( isHidden != nextRow->isHide() ||
+ nextDefaultCellStyleName != currentDefaultCellStyleName ||
+ !(nextRowStyle == currentRowStyle) )
+ {
+ break;
+ }
+#endif
+ if ( *row != *nextRow )
+ {
+ break;
+ }
+ // otherwise, process the next
+ ++j;
+ }
+ repeated = j - i;
+
+ if ( repeated > 1 )
+ xmlWriter.addAttribute( "table:number-rows-repeated", repeated );
+ if ( !currentDefaultCellStyle.isDefaultStyle() )
+ xmlWriter.addAttribute( "table:default-cell-style-name", currentDefaultCellStyleName );
+ if ( row->isHide() ) // never true for the default row
+ xmlWriter.addAttribute( "table:visibility", "collapse" );
+
+ // NOTE Stefan: Even if paragraph 8.1 states, that rows may be empty, the
+ // RelaxNG schema does not allow that.
+ xmlWriter.startElement( "table:table-cell" );
+ xmlWriter.endElement();
+
+ kdDebug() << "Sheet::saveOasisColRowCell: empty row " << i << ' '
+ << "repeated " << repeated << " time(s)" << endl;
+
+ // copy the index for the next row to process
+ i = j - 1; /*it's already incremented in the for loop*/
+ }
+ else // row is not empty
+ {
+ if ( !currentDefaultCellStyle.isDefaultStyle() )
+ xmlWriter.addAttribute( "table:default-cell-style-name", currentDefaultCellStyleName );
+ if ( row->isHide() ) // never true for the default row
+ xmlWriter.addAttribute( "table:visibility", "collapse" );
+
+ int j = i + 1;
+ while ( compareRows( i, j, maxCols ) && j <= maxRows )
+ {
+ j++;
+ repeated++;
+ }
+ if ( repeated > 1 )
+ {
+ kdDebug() << "Sheet::saveOasisColRowCell: NON-empty row " << i << ' '
+ << "repeated " << repeated << " times" << endl;
+
+ xmlWriter.addAttribute( "table:number-rows-repeated", repeated );
+ }
+
+ saveOasisCells( xmlWriter, mainStyles, i, maxCols, valStyle );
+
+ // copy the index for the next row to process
+ i = j - 1; /*it's already incremented in the for loop*/
+ }
+ xmlWriter.endElement();
+ }
+}
+
+void Sheet::saveOasisCells( KoXmlWriter& xmlWriter, KoGenStyles &mainStyles, int row, int maxCols, GenValidationStyles &valStyle )
+{
+ int i = 1;
+ Cell* cell = cellAt( i, row );
+ Cell* nextCell = getNextCellRight( i, row );
+ // while
+ // the current cell is not a default one
+ // or
+ // we have a further cell in this row
+ while ( !cell->isDefault() || nextCell )
+ {
+ kdDebug() << "Sheet::saveOasisCells:"
+ << " i: " << i
+ << " column: " << (cell->isDefault() ? 0 : cell->column()) << endl;
+ int repeated = 1;
+ cell->saveOasis( xmlWriter, mainStyles, row, i, repeated, valStyle );
+ i += repeated;
+ // stop if we reached the end column
+ if ( i > maxCols )
+ break;
+ cell = cellAt( i, row );
+ nextCell = getNextCellRight( i, row );
+ }
+}
+
+bool Sheet::loadXML( const TQDomElement& sheet )
+{
+ bool ok = false;
+ if ( !doc()->loadingInfo() || !doc()->loadingInfo()->loadTemplate() )
+ {
+ d->name = sheet.attribute( "name" );
+ if ( d->name.isEmpty() )
+ {
+ doc()->setErrorMessage( i18n("Invalid document. Sheet name is empty.") );
+ return false;
+ }
+ }
+
+ bool detectDirection = true;
+ d->layoutDirection = LeftToRight;
+ TQString layoutDir = sheet.attribute( "layoutDirection" );
+ if( !layoutDir.isEmpty() )
+ {
+ if( layoutDir == "rtl" )
+ {
+ detectDirection = false;
+ d->layoutDirection = RightToLeft;
+ }
+ else if( layoutDir == "ltr" )
+ {
+ detectDirection = false;
+ d->layoutDirection = LeftToRight;
+ }
+ else
+ kdDebug()<<" Direction not implemented : "<<layoutDir<<endl;
+ }
+ if( detectDirection )
+ checkContentDirection( d->name );
+
+ /* older versions of KSpread allowed all sorts of characters that
+ the parser won't actually understand. Replace these with '_'
+ Also, the initial character cannot be a space.
+ */
+ if (d->name[0] == ' ')
+ {
+ d->name.remove(0,1);
+ }
+ for (unsigned int i=0; i < d->name.length(); i++)
+ {
+ if ( !(d->name[i].isLetterOrNumber() ||
+ d->name[i] == ' ' || d->name[i] == '.' ||
+ d->name[i] == '_'))
+ {
+ d->name[i] = '_';
+ }
+ }
+
+ /* make sure there are no name collisions with the altered name */
+ TQString testName;
+ TQString baseName;
+ int nameSuffix = 0;
+
+ testName = d->name;
+ baseName = d->name;
+
+ /* so we don't panic over finding ourself in the follwing test*/
+ d->name = "";
+ while (workbook()->findSheet(testName) != NULL)
+ {
+ nameSuffix++;
+ testName = baseName + '_' + TQString::number(nameSuffix);
+ }
+ d->name = testName;
+
+ kdDebug(36001)<<"Sheet::loadXML: table name="<<d->name<<endl;
+ setName(d->name.utf8());
+ (dynamic_cast<SheetIface*>(dcopObject()))->sheetNameHasChanged();
+
+ if( sheet.hasAttribute( "grid" ) )
+ {
+ d->showGrid = (int)sheet.attribute("grid").toInt( &ok );
+ // we just ignore 'ok' - if it didn't work, go on
+ }
+ if( sheet.hasAttribute( "printGrid" ) )
+ {
+ d->print->setPrintGrid( (bool)sheet.attribute("printGrid").toInt( &ok ) );
+ // we just ignore 'ok' - if it didn't work, go on
+ }
+ if( sheet.hasAttribute( "printCommentIndicator" ) )
+ {
+ d->print->setPrintCommentIndicator( (bool)sheet.attribute("printCommentIndicator").toInt( &ok ) );
+ // we just ignore 'ok' - if it didn't work, go on
+ }
+ if( sheet.hasAttribute( "printFormulaIndicator" ) )
+ {
+ d->print->setPrintFormulaIndicator( (bool)sheet.attribute("printFormulaIndicator").toInt( &ok ) );
+ // we just ignore 'ok' - if it didn't work, go on
+ }
+ if( sheet.hasAttribute( "hide" ) )
+ {
+ d->hide = (bool)sheet.attribute("hide").toInt( &ok );
+ // we just ignore 'ok' - if it didn't work, go on
+ }
+ if( sheet.hasAttribute( "showFormula" ) )
+ {
+ d->showFormula = (bool)sheet.attribute("showFormula").toInt( &ok );
+ // we just ignore 'ok' - if it didn't work, go on
+ }
+ //Compatibility with KSpread 1.1.x
+ if( sheet.hasAttribute( "formular" ) )
+ {
+ d->showFormula = (bool)sheet.attribute("formular").toInt( &ok );
+ // we just ignore 'ok' - if it didn't work, go on
+ }
+ if( sheet.hasAttribute( "showFormulaIndicator" ) )
+ {
+ d->showFormulaIndicator = (bool)sheet.attribute("showFormulaIndicator").toInt( &ok );
+ // we just ignore 'ok' - if it didn't work, go on
+ }
+ if( sheet.hasAttribute( "showCommentIndicator" ) )
+ {
+ d->showCommentIndicator = (bool)sheet.attribute("showCommentIndicator").toInt( &ok );
+ // we just ignore 'ok' - if it didn't work, go on
+ }
+ if( sheet.hasAttribute( "borders" ) )
+ {
+ d->showPageBorders = (bool)sheet.attribute("borders").toInt( &ok );
+ // we just ignore 'ok' - if it didn't work, go on
+ }
+ if( sheet.hasAttribute( "lcmode" ) )
+ {
+ d->lcMode = (bool)sheet.attribute("lcmode").toInt( &ok );
+ // we just ignore 'ok' - if it didn't work, go on
+ }
+ if ( sheet.hasAttribute( "autoCalc" ) )
+ {
+ d->autoCalc = ( bool )sheet.attribute( "autoCalc" ).toInt( &ok );
+ // we just ignore 'ok' - if it didn't work, go on
+ }
+ if( sheet.hasAttribute( "columnnumber" ) )
+ {
+ d->showColumnNumber = (bool)sheet.attribute("columnnumber").toInt( &ok );
+ // we just ignore 'ok' - if it didn't work, go on
+ }
+ if( sheet.hasAttribute( "hidezero" ) )
+ {
+ d->hideZero = (bool)sheet.attribute("hidezero").toInt( &ok );
+ // we just ignore 'ok' - if it didn't work, go on
+ }
+ if( sheet.hasAttribute( "firstletterupper" ) )
+ {
+ d->firstLetterUpper = (bool)sheet.attribute("firstletterupper").toInt( &ok );
+ // we just ignore 'ok' - if it didn't work, go on
+ }
+
+ // Load the paper layout
+ TQDomElement paper = sheet.namedItem( "paper" ).toElement();
+ if ( !paper.isNull() )
+ {
+ TQString format = paper.attribute( "format" );
+ TQString orientation = paper.attribute( "orientation" );
+
+ // <borders>
+ TQDomElement borders = paper.namedItem( "borders" ).toElement();
+ if ( !borders.isNull() )
+ {
+ float left = borders.attribute( "left" ).toFloat();
+ float right = borders.attribute( "right" ).toFloat();
+ float top = borders.attribute( "top" ).toFloat();
+ float bottom = borders.attribute( "bottom" ).toFloat();
+ d->print->setPaperLayout( left, top, right, bottom, format, orientation );
+ }
+ TQString hleft, hright, hcenter;
+ TQString fleft, fright, fcenter;
+ // <head>
+ TQDomElement head = paper.namedItem( "head" ).toElement();
+ if ( !head.isNull() )
+ {
+ TQDomElement left = head.namedItem( "left" ).toElement();
+ if ( !left.isNull() )
+ hleft = left.text();
+ TQDomElement center = head.namedItem( "center" ).toElement();
+ if ( !center.isNull() )
+ hcenter = center.text();
+ TQDomElement right = head.namedItem( "right" ).toElement();
+ if ( !right.isNull() )
+ hright = right.text();
+ }
+ // <foot>
+ TQDomElement foot = paper.namedItem( "foot" ).toElement();
+ if ( !foot.isNull() )
+ {
+ TQDomElement left = foot.namedItem( "left" ).toElement();
+ if ( !left.isNull() )
+ fleft = left.text();
+ TQDomElement center = foot.namedItem( "center" ).toElement();
+ if ( !center.isNull() )
+ fcenter = center.text();
+ TQDomElement right = foot.namedItem( "right" ).toElement();
+ if ( !right.isNull() )
+ fright = right.text();
+ }
+ d->print->setHeadFootLine( hleft, hcenter, hright, fleft, fcenter, fright);
+ }
+
+ // load print range
+ TQDomElement printrange = sheet.namedItem( "printrange-rect" ).toElement();
+ if ( !printrange.isNull() )
+ {
+ int left = printrange.attribute( "left-rect" ).toInt();
+ int right = printrange.attribute( "right-rect" ).toInt();
+ int bottom = printrange.attribute( "bottom-rect" ).toInt();
+ int top = printrange.attribute( "top-rect" ).toInt();
+ if ( left == 0 ) //whole row(s) selected
+ {
+ left = 1;
+ right = KS_colMax;
+ }
+ if ( top == 0 ) //whole column(s) selected
+ {
+ top = 1;
+ bottom = KS_rowMax;
+ }
+ d->print->setPrintRange( TQRect( TQPoint( left, top ), TQPoint( right, bottom ) ) );
+ }
+
+ // load print zoom
+ if( sheet.hasAttribute( "printZoom" ) )
+ {
+ double zoom = sheet.attribute( "printZoom" ).toDouble( &ok );
+ if ( ok )
+ {
+ d->print->setZoom( zoom );
+ }
+ }
+
+ // load page limits
+ if( sheet.hasAttribute( "printPageLimitX" ) )
+ {
+ int pageLimit = sheet.attribute( "printPageLimitX" ).toInt( &ok );
+ if ( ok )
+ {
+ d->print->setPageLimitX( pageLimit );
+ }
+ }
+
+ // load page limits
+ if( sheet.hasAttribute( "printPageLimitY" ) )
+ {
+ int pageLimit = sheet.attribute( "printPageLimitY" ).toInt( &ok );
+ if ( ok )
+ {
+ d->print->setPageLimitY( pageLimit );
+ }
+ }
+
+ // Load the cells
+ TQDomNode n = sheet.firstChild();
+ while( !n.isNull() )
+ {
+ TQDomElement e = n.toElement();
+ if ( !e.isNull() )
+ {
+ TQString tagName=e.tagName();
+ if ( tagName == "cell" )
+ {
+ Cell *cell = new Cell( this, 0, 0 );
+ if ( cell->load( e, 0, 0 ) )
+ insertCell( cell );
+ else
+ delete cell; // Allow error handling: just skip invalid cells
+ }
+ else if ( tagName == "row" )
+ {
+ RowFormat *rl = new RowFormat( this, 0 );
+ if ( rl->load( e ) )
+ insertRowFormat( rl );
+ else
+ delete rl;
+ }
+ else if ( tagName == "column" )
+ {
+ ColumnFormat *cl = new ColumnFormat( this, 0 );
+ if ( cl->load( e ) )
+ insertColumnFormat( cl );
+ else
+ delete cl;
+ }
+ else if ( tagName == "object" )
+ {
+ EmbeddedKOfficeObject *ch = new EmbeddedKOfficeObject( doc(), this );
+ if ( ch->load( e ) )
+ insertObject( ch );
+ else
+ {
+ ch->embeddedObject()->setDeleted(true);
+ delete ch;
+ }
+ }
+ else if ( tagName == "chart" )
+ {
+ EmbeddedChart *ch = new EmbeddedChart( doc(), this );
+ if ( ch->load( e ) )
+ insertObject( ch );
+ else
+ {
+ ch->embeddedObject()->setDeleted(true);
+ delete ch;
+ }
+ }
+ }
+
+ n = n.nextSibling();
+ }
+
+
+ // load print repeat columns
+ TQDomElement printrepeatcolumns = sheet.namedItem( "printrepeatcolumns" ).toElement();
+ if ( !printrepeatcolumns.isNull() )
+ {
+ int left = printrepeatcolumns.attribute( "left" ).toInt();
+ int right = printrepeatcolumns.attribute( "right" ).toInt();
+ d->print->setPrintRepeatColumns( tqMakePair( left, right ) );
+ }
+
+ // load print repeat rows
+ TQDomElement printrepeatrows = sheet.namedItem( "printrepeatrows" ).toElement();
+ if ( !printrepeatrows.isNull() )
+ {
+ int top = printrepeatrows.attribute( "top" ).toInt();
+ int bottom = printrepeatrows.attribute( "bottom" ).toInt();
+ d->print->setPrintRepeatRows( tqMakePair( top, bottom ) );
+ }
+
+ if( !sheet.hasAttribute( "borders1.2" ) )
+ {
+ convertObscuringBorders();
+ }
+
+ if ( sheet.hasAttribute( "protected" ) )
+ {
+ TQString passwd = sheet.attribute( "protected" );
+
+ if ( passwd.length() > 0 )
+ {
+ TQCString str( passwd.latin1() );
+ d->password = KCodecs::base64Decode( str );
+ }
+ else
+ d->password = TQCString( "" );
+ }
+
+ return true;
+}
+
+
+bool Sheet::loadChildren( KoStore* _store )
+{
+ TQPtrListIterator<EmbeddedObject> it( doc()->embeddedObjects() );
+ for( ; it.current(); ++it )
+ {
+ if ( it.current()->sheet() == this && ( it.current()->getType() == OBJECT_KOFFICE_PART || it.current()->getType() == OBJECT_CHART ) )
+ {
+ kdDebug() << "KSpreadSheet::loadChildren" << endl;
+ if ( !dynamic_cast<EmbeddedKOfficeObject*>( it.current() )->embeddedObject()->loadDocument( _store ) )
+ return false;
+ }
+ }
+
+ return true;
+}
+
+
+void Sheet::setShowPageBorders( bool b )
+{
+ if ( b == d->showPageBorders )
+ return;
+
+ d->showPageBorders = b;
+ emit sig_updateView( this );
+}
+
+void Sheet::addCellBinding( CellBinding *_bind )
+{
+ d->cellBindings.append( _bind );
+
+ doc()->setModified( true );
+}
+
+void Sheet::removeCellBinding( CellBinding *_bind )
+{
+ d->cellBindings.removeRef( _bind );
+
+ doc()->setModified( true );
+}
+
+Sheet* Sheet::findSheet( const TQString & _name )
+{
+ if ( !workbook() )
+ return 0L;
+
+ return workbook()->findSheet( _name );
+}
+
+// ###### Torben: Use this one instead of d->cells.insert()
+void Sheet::insertCell( Cell *_cell )
+{
+
+ d->cells.insert( _cell, _cell->column(), _cell->row() );
+
+ // Adjust the scrollbar range, if the max. dimension has changed.
+ if ( d->scrollBarUpdates )
+ {
+ checkRangeHBorder ( _cell->column() );
+ checkRangeVBorder ( _cell->row() );
+ }
+}
+
+void Sheet::insertColumnFormat( ColumnFormat *l )
+{
+ d->columns.insertElement( l, l->column() );
+}
+
+void Sheet::insertRowFormat( RowFormat *l )
+{
+ d->rows.insertElement( l, l->row() );
+}
+
+void Sheet::update()
+{
+ Cell* c = d->cells.firstCell();
+ for( ;c; c = c->nextCell() )
+ {
+ updateCell(c, c->column(), c->row());
+ }
+}
+
+void Sheet::updateCellArea(const Region& cellArea)
+{
+ if ( doc()->isLoading() || doc()->delayCalculation() || (!getAutoCalc()))
+ return;
+
+ setRegionPaintDirty( cellArea );
+}
+
+void Sheet::updateCell( Cell */*cell*/, int _column, int _row )
+{
+ TQRect cellArea(TQPoint(_column, _row), TQPoint(_column, _row));
+
+ updateCellArea(cellArea);
+}
+
+void Sheet::emit_updateRow( RowFormat *_format, int _row, bool repaint )
+{
+ if ( doc()->isLoading() )
+ return;
+
+ Cell* c = d->cells.firstCell();
+ for( ;c; c = c->nextCell() )
+ if ( c->row() == _row )
+ c->setLayoutDirtyFlag( true );
+
+ if ( repaint )
+ {
+ //All the cells in this row, or below this row will need to be repainted
+ //So add that region of the sheet to the paint dirty list.
+ setRegionPaintDirty( TQRect( 0 , _row , KS_colMax , KS_rowMax) );
+
+ emit sig_updateVBorder( this );
+ emit sig_updateView( this );
+ }
+ emit sig_maxRow(maxRow());
+ _format->clearDisplayDirtyFlag();
+}
+
+void Sheet::emit_updateColumn( ColumnFormat *_format, int _column )
+{
+ if ( doc()->isLoading() )
+ return;
+
+ Cell* c = d->cells.firstCell();
+ for( ;c; c = c->nextCell() )
+ if ( c->column() == _column )
+ c->setLayoutDirtyFlag( true );
+
+ //All the cells in this column or to the right of it will need to be repainted if the column
+ //has been resized or hidden, so add that region of the sheet to the paint dirty list.
+ setRegionPaintDirty( TQRect( _column , 0 , KS_colMax , KS_rowMax) );
+
+ emit sig_updateHBorder( this );
+ emit sig_updateView( this );
+ emit sig_maxColumn( maxColumn() );
+
+
+
+ _format->clearDisplayDirtyFlag();
+}
+
+bool Sheet::insertChart( const KoRect& _rect, KoDocumentEntry& _e, const TQRect& _data )
+{
+ kdDebug(36001) << "Creating document" << endl;
+ KoDocument* dd = _e.createDoc();
+ kdDebug(36001) << "Created" << endl;
+ if ( !dd )
+ // Error message is already displayed, so just return
+ return false;
+
+ kdDebug(36001) << "NOW FETCHING INTERFACE" << endl;
+
+ if ( !dd->initDoc(KoDocument::InitDocEmbedded) )
+ return false;
+
+ EmbeddedChart * ch = new EmbeddedChart( doc(), this, dd, _rect );
+ ch->setDataArea( _data );
+ ch->update();
+ ch->chart()->setCanChangeValue( false );
+
+ KoChart::WizardExtension * wiz = ch->chart()->wizardExtension();
+
+ Range dataRange;
+ dataRange.setRange( _data );
+ dataRange.setSheet( this );
+
+ TQString rangeString=dataRange.toString();
+
+ if ( wiz )
+ wiz->show( rangeString );
+
+ insertObject( ch );
+
+ return true;
+}
+
+bool Sheet::insertChild( const KoRect& _rect, KoDocumentEntry& _e )
+{
+ KoDocument* d = _e.createDoc( doc() );
+ if ( !d )
+ {
+ kdDebug() << "Error inserting child!" << endl;
+ return false;
+ }
+ if ( !d->initDoc(KoDocument::InitDocEmbedded) )
+ return false;
+
+ EmbeddedKOfficeObject* ch = new EmbeddedKOfficeObject( doc(), this, d, _rect );
+ insertObject( ch );
+ return true;
+}
+
+bool Sheet::insertPicture( const KoPoint& point , const KURL& url )
+{
+ KoPicture picture = doc()->pictureCollection()->downloadPicture( url , 0 );
+
+ return insertPicture(point,picture);
+}
+
+bool Sheet::insertPicture( const KoPoint& point , KoPicture& picture )
+{
+
+ if (picture.isNull())
+ return false;
+
+ KoPictureKey key = picture.getKey();
+
+ KoRect destinationRect;
+ destinationRect.setLeft( point.x() );
+ destinationRect.setTop( point.y() );
+
+ //Generate correct pixel size - this is a bit tricky.
+ //This ensures that when we load the image it appears
+ //the same size on screen on a 100%-zoom KSpread spreadsheet as it would in an
+ //image viewer or another spreadsheet program such as OpenOffice.
+ //
+ //KoUnit assumes 72DPI, whereas the user's display resolution will probably be
+ //different (eg. 96*96). So, we convert the actual size in pixels into inches
+ //using the screen display resolution and then use KoUnit to convert back into
+ //the appropriate pixel size KSpread.
+
+ KoSize destinationSize;
+
+ double inchWidth = (double)picture.getOriginalSize().width() / KoGlobal::dpiX();
+ double inchHeight = (double)picture.getOriginalSize().height() / KoGlobal::dpiY();
+
+ destinationSize.setWidth( KoUnit::fromUserValue(inchWidth,KoUnit::U_INCH) );
+ destinationSize.setHeight( KoUnit::fromUserValue(inchHeight,KoUnit::U_INCH) );
+
+ destinationRect.setSize( destinationSize);
+
+ EmbeddedPictureObject* object = new EmbeddedPictureObject( this, destinationRect, doc()->pictureCollection(),key);
+ // ch->setPicture(key);
+
+ insertObject( object );
+ return true;
+}
+
+bool Sheet::insertPicture( const KoPoint& point, const TQPixmap& pixmap )
+{
+ TQByteArray data;
+ TQBuffer buffer(data);
+
+ buffer.open( IO_ReadWrite );
+ pixmap.save( TQT_TQIODEVICE(&buffer) , "PNG" );
+
+ //Reset the buffer so that KoPicture reads the whole file from the beginning
+ //(at the moment the read/write position is at the end)
+ buffer.reset();
+
+ KoPicture picture;
+ picture.load( TQT_TQIODEVICE(&buffer) , "PNG" );
+
+ doc()->pictureCollection()->insertPicture(picture);
+
+ return insertPicture( point , picture );
+}
+
+void Sheet::insertObject( EmbeddedObject *_obj )
+{
+ doc()->insertObject( _obj );
+ emit sig_updateView( _obj );
+}
+
+void Sheet::changeChildGeometry( EmbeddedKOfficeObject *_child, const KoRect& _rect )
+{
+ _child->setGeometry( _rect );
+
+ emit sig_updateChildGeometry( _child );
+}
+
+bool Sheet::saveChildren( KoStore* _store, const TQString &_path )
+{
+ int i = 0;
+
+ TQPtrListIterator<EmbeddedObject> it( doc()->embeddedObjects() );
+ for( ; it.current(); ++it )
+ {
+ if ( it.current()->sheet() == this && ( it.current()->getType() == OBJECT_KOFFICE_PART || it.current()->getType() == OBJECT_CHART ) )
+ {
+ TQString path = TQString( "%1/%2" ).arg( _path ).arg( i++ );
+ if ( !dynamic_cast<EmbeddedKOfficeObject*>( it.current() )->embeddedObject()->document()->saveToStore( _store, path ) )
+ return false;
+ }
+ }
+ return true;
+}
+
+bool Sheet::saveOasisObjects( KoStore */*store*/, KoXmlWriter &xmlWriter, KoGenStyles& mainStyles, int & indexObj, int &partIndexObj )
+{
+ //int i = 0;
+ if ( doc()->embeddedObjects().isEmpty() )
+ return true;
+
+ bool objectFound = false; // object on this sheet?
+ EmbeddedObject::KSpreadOasisSaveContext sc( xmlWriter, mainStyles, indexObj, partIndexObj );
+ TQPtrListIterator<EmbeddedObject> it( doc()->embeddedObjects() );
+ for( ; it.current(); ++it )
+ {
+ if ( it.current()->sheet() == this && ( doc()->savingWholeDocument() || it.current()->isSelected() ) )
+ {
+ if ( !objectFound )
+ {
+ xmlWriter.startElement( "table:shapes" );
+ objectFound = true;
+ }
+ if ( !it.current()->saveOasisObject(sc) )
+ {
+ xmlWriter.endElement();
+ return false;
+ }
+ ++indexObj;
+ }
+ }
+ if ( objectFound )
+ {
+ xmlWriter.endElement();
+ }
+ return true;
+}
+
+Sheet::~Sheet()
+{
+ //Disable automatic recalculation of dependancies on this sheet to prevent crashes
+ //in certain situations:
+ //
+ //For example, suppose a cell in SheetB depends upon a cell in SheetA. If the cell in SheetB is emptied
+ //after SheetA has already been deleted, the program would try to remove dependancies from the cell in SheetA
+ //causing a crash.
+ setAutoCalc(false);
+
+ s_mapSheets->remove( d->id );
+
+ //when you remove all sheet (close file)
+ //you must reinit s_id otherwise there is not
+ //the good name between map and sheet
+ if( s_mapSheets->count()==0)
+ s_id=0L;
+
+ Cell* c = d->cells.firstCell();
+ for( ; c; c = c->nextCell() )
+ c->sheetDies();
+
+ d->cells.clear(); // cells destructor needs sheet to still exist
+
+ d->painter->end();
+ delete d->painter;
+ delete d->widget;
+
+ delete d->defaultFormat;
+ delete d->defaultCell;
+ delete d->defaultRowFormat;
+ delete d->defaultColumnFormat;
+ delete d->print;
+ delete d->dcop;
+
+ delete d->dependencies;
+
+ delete d;
+
+ //this is for debugging a crash
+ d=0;
+}
+
+void Sheet::checkRangeHBorder ( int _column )
+{
+ if ( d->scrollBarUpdates && _column > d->maxColumn )
+ {
+ d->maxColumn = _column;
+ emit sig_maxColumn( _column );
+ }
+}
+
+void Sheet::checkRangeVBorder ( int _row )
+{
+ if ( d->scrollBarUpdates && _row > d->maxRow )
+ {
+ d->maxRow = _row;
+ emit sig_maxRow( _row );
+ }
+}
+
+
+void Sheet::enableScrollBarUpdates( bool _enable )
+{
+ d->scrollBarUpdates = _enable;
+}
+
+DCOPObject* Sheet::dcopObject()
+{
+ if ( !d->dcop )
+ d->dcop = new SheetIface( this );
+
+ return d->dcop;
+}
+
+void Sheet::hideSheet(bool _hide)
+{
+ setHidden(_hide);
+ if(_hide)
+ emit sig_SheetHidden(this);
+ else
+ emit sig_SheetShown(this);
+}
+
+void Sheet::removeSheet()
+{
+ emit sig_SheetRemoved(this);
+}
+
+bool Sheet::setSheetName( const TQString& name, bool init, bool /*makeUndo*/ )
+{
+ if ( workbook()->findSheet( name ) )
+ return false;
+
+ if ( isProtected() )
+ return false;
+
+ if ( d->name == name )
+ return true;
+
+ TQString old_name = d->name;
+ d->name = name;
+
+ if ( init )
+ return true;
+
+ TQPtrListIterator<Sheet> it( workbook()->sheetList() );
+ for ( ; it.current(); ++it )
+ it.current()->changeCellTabName( old_name, name );
+
+ doc()->changeAreaSheetName( old_name, name );
+ emit sig_nameChanged( this, old_name );
+
+ setName(name.utf8());
+ (dynamic_cast<SheetIface*>(dcopObject()))->sheetNameHasChanged();
+
+ return true;
+}
+
+
+void Sheet::updateLocale()
+{
+ doc()->emitBeginOperation(true);
+ setRegionPaintDirty(TQRect(TQPoint(1,1), TQPoint(KS_colMax, KS_rowMax)));
+
+ Cell* c = d->cells.firstCell();
+ for( ;c; c = c->nextCell() )
+ {
+ TQString _text = c->text();
+ c->setCellText( _text );
+ }
+ emit sig_updateView( this );
+ // doc()->emitEndOperation();
+}
+
+Cell* Sheet::getFirstCellColumn(int col) const
+{ return d->cells.getFirstCellColumn(col); }
+
+Cell* Sheet::getLastCellColumn(int col) const
+{ return d->cells.getLastCellColumn(col); }
+
+Cell* Sheet::getFirstCellRow(int row) const
+{ return d->cells.getFirstCellRow(row); }
+
+Cell* Sheet::getLastCellRow(int row) const
+{ return d->cells.getLastCellRow(row); }
+
+Cell* Sheet::getNextCellUp(int col, int row) const
+{ return d->cells.getNextCellUp(col, row); }
+
+Cell* Sheet::getNextCellDown(int col, int row) const
+{ return d->cells.getNextCellDown(col, row); }
+
+Cell* Sheet::getNextCellLeft(int col, int row) const
+{ return d->cells.getNextCellLeft(col, row); }
+
+Cell* Sheet::getNextCellRight(int col, int row) const
+{ return d->cells.getNextCellRight(col, row); }
+
+void Sheet::convertObscuringBorders()
+{
+ /* a word of explanation here:
+ beginning with KSpread 1.2 (actually, cvs of Mar 28, 2002), border information
+ is stored differently. Previously, for a cell obscuring a region, the entire
+ region's border's data would be stored in the obscuring cell. This caused
+ some data loss in certain situations. After that date, each cell stores
+ its own border data, and prints it even if it is an obscured cell (as long
+ as that border isn't across an obscuring border).
+ Anyway, this function is used when loading a file that was stored with the
+ old way of borders. All new files have the sheet attribute "borders1.2" so
+ if that isn't in the file, all the border data will be converted here.
+ It's a bit of a hack but I can't think of a better way and it's not *that*
+ bad of a hack.:-)
+ */
+ Cell* c = d->cells.firstCell();
+ TQPen topPen, bottomPen, leftPen, rightPen;
+ for( ;c; c = c->nextCell() )
+ {
+ if (c->extraXCells() > 0 || c->extraYCells() > 0)
+ {
+ topPen = c->topBorderPen(c->column(), c->row());
+ leftPen = c->leftBorderPen(c->column(), c->row());
+ rightPen = c->rightBorderPen(c->column(), c->row());
+ bottomPen = c->bottomBorderPen(c->column(), c->row());
+
+ c->format()->setTopBorderStyle(Qt::NoPen);
+ c->format()->setLeftBorderStyle(Qt::NoPen);
+ c->format()->setRightBorderStyle(Qt::NoPen);
+ c->format()->setBottomBorderStyle(Qt::NoPen);
+
+ for (int x = c->column(); x < c->column() + c->extraXCells(); x++)
+ {
+ nonDefaultCell( x, c->row() )->setTopBorderPen(topPen);
+ nonDefaultCell( x, c->row() + c->extraYCells() )->
+ setBottomBorderPen(bottomPen);
+ }
+ for (int y = c->row(); y < c->row() + c->extraYCells(); y++)
+ {
+ nonDefaultCell( c->column(), y )->setLeftBorderPen(leftPen);
+ nonDefaultCell( c->column() + c->extraXCells(), y )->
+ setRightBorderPen(rightPen);
+ }
+ }
+ }
+}
+
+/**********************
+ * Printout Functions *
+ **********************/
+
+// TODO Stefan: these belong to View, even better Canvas
+void Sheet::setRegionPaintDirty( Region const & region )
+{
+ DilationManipulator manipulator;
+ manipulator.setSheet(this);
+ manipulator.add(region);
+ manipulator.execute();
+ // don't put it in the undo list! ;-)
+ d->paintDirtyList.add(manipulator);
+ //kdDebug() << "setRegionPaintDirty "<< static_cast<Region*>(&manipulator)->name(this) << endl;
+}
+
+void Sheet::setRegionPaintDirty( TQRect const & range )
+{
+ DilationManipulator manipulator;
+ manipulator.setSheet(this);
+ manipulator.add(range);
+ manipulator.execute();
+ // don't put it in the undo list! ;-)
+ d->paintDirtyList.add(manipulator);
+ //kdDebug() << "setRegionPaintDirty "<< static_cast<Region*>(&manipulator)->name(this) << endl;
+}
+
+void Sheet::clearPaintDirtyData()
+{
+ d->paintDirtyList.clear();
+}
+
+bool Sheet::cellIsPaintDirty( TQPoint const & cell ) const
+{
+ return d->paintDirtyList.contains(cell);
+}
+
+#ifndef NDEBUG
+void Sheet::printDebug()
+{
+ int iMaxColumn = maxColumn();
+ int iMaxRow = maxRow();
+
+ kdDebug(36001) << "Cell | Content | DataT | Text" << endl;
+ Cell *cell;
+ for ( int currentrow = 1 ; currentrow < iMaxRow ; ++currentrow )
+ {
+ for ( int currentcolumn = 1 ; currentcolumn < iMaxColumn ; currentcolumn++ )
+ {
+ cell = cellAt( currentcolumn, currentrow );
+ if ( !cell->isDefault() && !cell->isEmpty() )
+ {
+ TQString cellDescr = Cell::name( currentcolumn, currentrow );
+ cellDescr = cellDescr.rightJustify( 4,' ' );
+ //TQString cellDescr = "Cell ";
+ //cellDescr += TQString::number(currentrow).rightJustify(3,'0') + ',';
+ //cellDescr += TQString::number(currentcolumn).rightJustify(3,'0') + ' ';
+ cellDescr += " | ";
+ cellDescr += cell->value().type();
+ cellDescr += " | ";
+ cellDescr += cell->text();
+ if ( cell->isFormula() )
+ cellDescr += TQString(" [result: %1]").arg( cell->value().asString() );
+ kdDebug(36001) << cellDescr << endl;
+ }
+ }
+ }
+}
+#endif
+
+} // namespace KSpread
+