You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
8578 lines
250 KiB
8578 lines
250 KiB
/* 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( TQt::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( &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( qMakePair( 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( qMakePair( 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( &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( &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(TQt::NoPen);
|
|
c->format()->setLeftBorderStyle(TQt::NoPen);
|
|
c->format()->setRightBorderStyle(TQt::NoPen);
|
|
c->format()->setBottomBorderStyle(TQt::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
|
|
|