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.
1219 lines
27 KiB
1219 lines
27 KiB
15 years ago
|
/* This file is part of the KDE project
|
||
|
Copyright (C) 2006 Stefan Nikolaus <stefan.nikolaus@kdemail.net>
|
||
|
Copyright (C) 1998, 1999 Torben Weis <weis@kde.org>
|
||
|
|
||
|
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 <ctype.h>
|
||
|
|
||
|
#include <qregexp.h>
|
||
|
|
||
|
#include <kdebug.h>
|
||
|
|
||
|
#include "formula.h"
|
||
|
#include "kspread_doc.h"
|
||
|
#include "kspread_locale.h"
|
||
|
#include "kspread_map.h"
|
||
|
#include "kspread_sheet.h"
|
||
|
#include "kspread_style.h"
|
||
|
#include "kspread_util.h"
|
||
|
|
||
|
using namespace KSpread;
|
||
|
|
||
|
//helper functions for the formatting
|
||
|
bool KSpread::formatIsDate (FormatType fmt)
|
||
|
{
|
||
|
return ((fmt == ShortDate_format) || (fmt == TextDate_format) ||
|
||
|
(((int) fmt >= 200) && ((int) fmt < 300)));
|
||
|
}
|
||
|
|
||
|
bool KSpread::formatIsTime (FormatType fmt)
|
||
|
{
|
||
|
return (((int) fmt >= 50) && ((int) fmt < 70));
|
||
|
}
|
||
|
|
||
|
bool KSpread::formatIsFraction (FormatType fmt)
|
||
|
{
|
||
|
return (((int) fmt >= 70) && ((int) fmt < 80));
|
||
|
}
|
||
|
|
||
|
|
||
|
//used in Point::init, Cell::encodeFormula and
|
||
|
// dialogs/kspread_dlg_paperlayout.cc
|
||
|
int KSpread::util_decodeColumnLabelText( const QString &_col )
|
||
|
{
|
||
|
int col = 0;
|
||
|
int offset='a'-'A';
|
||
|
int counterColumn = 0;
|
||
|
for ( uint i=0; i < _col.length(); i++ )
|
||
|
{
|
||
|
counterColumn = (int) pow(26.0 , static_cast<int>(_col.length() - i - 1));
|
||
|
if( _col[i] >= 'A' && _col[i] <= 'Z' )
|
||
|
col += counterColumn * ( _col[i].latin1() - 'A' + 1); // okay here (Werner)
|
||
|
else if( _col[i] >= 'a' && _col[i] <= 'z' )
|
||
|
col += counterColumn * ( _col[i].latin1() - 'A' - offset + 1 );
|
||
|
else
|
||
|
kdDebug(36001) << "util_decodeColumnLabelText: Wrong characters in label text for col:'" << _col << "'" << endl;
|
||
|
}
|
||
|
return col;
|
||
|
}
|
||
|
|
||
|
//used in dialogs/kspread_dlg_paperlayout.cc
|
||
|
QString KSpread::util_rangeColumnName( const QRect &_area)
|
||
|
{
|
||
|
return QString("%1:%2")
|
||
|
.arg( Cell::columnName( _area.left()))
|
||
|
.arg( Cell::columnName(_area.right()));
|
||
|
}
|
||
|
|
||
|
//used in dialogs/kspread_dlg_paperlayout.cc
|
||
|
QString KSpread::util_rangeRowName( const QRect &_area)
|
||
|
{
|
||
|
return QString("%1:%2")
|
||
|
.arg( _area.top())
|
||
|
.arg(_area.bottom());
|
||
|
}
|
||
|
|
||
|
QString KSpread::util_rangeName(const QRect &_area)
|
||
|
{
|
||
|
return Cell::name( _area.left(), _area.top() ) + ":" +
|
||
|
Cell::name( _area.right(), _area.bottom() );
|
||
|
}
|
||
|
|
||
|
QString KSpread::util_rangeName(Sheet * _sheet, const QRect &_area)
|
||
|
{
|
||
|
return _sheet->sheetName() + "!" + util_rangeName(_area);
|
||
|
}
|
||
|
|
||
|
QDomElement KSpread::util_createElement( const QString & tagName, const QFont & font, QDomDocument & doc )
|
||
|
{
|
||
|
QDomElement e( doc.createElement( tagName ) );
|
||
|
|
||
|
e.setAttribute( "family", font.family() );
|
||
|
e.setAttribute( "size", font.pointSize() );
|
||
|
e.setAttribute( "weight", font.weight() );
|
||
|
if ( font.bold() )
|
||
|
e.setAttribute( "bold", "yes" );
|
||
|
if ( font.italic() )
|
||
|
e.setAttribute( "italic", "yes" );
|
||
|
if ( font.underline() )
|
||
|
e.setAttribute( "underline", "yes" );
|
||
|
if ( font.strikeOut() )
|
||
|
e.setAttribute( "strikeout", "yes" );
|
||
|
//e.setAttribute( "charset", KGlobal::charsets()->name( font ) );
|
||
|
|
||
|
return e;
|
||
|
}
|
||
|
|
||
|
QDomElement KSpread::util_createElement( const QString & tagname, const QPen & pen, QDomDocument & doc )
|
||
|
{
|
||
|
QDomElement e( doc.createElement( tagname ) );
|
||
|
e.setAttribute( "color", pen.color().name() );
|
||
|
e.setAttribute( "style", (int)pen.style() );
|
||
|
e.setAttribute( "width", (int)pen.width() );
|
||
|
return e;
|
||
|
}
|
||
|
|
||
|
QFont KSpread::util_toFont( QDomElement & element )
|
||
|
{
|
||
|
QFont f;
|
||
|
f.setFamily( element.attribute( "family" ) );
|
||
|
|
||
|
bool ok;
|
||
|
f.setPointSize( element.attribute("size").toInt( &ok ) );
|
||
|
if ( !ok )
|
||
|
return QFont();
|
||
|
|
||
|
f.setWeight( element.attribute("weight").toInt( &ok ) );
|
||
|
if ( !ok )
|
||
|
return QFont();
|
||
|
|
||
|
if ( element.hasAttribute( "italic" ) && element.attribute("italic") == "yes" )
|
||
|
f.setItalic( true );
|
||
|
|
||
|
if ( element.hasAttribute( "bold" ) && element.attribute("bold") == "yes" )
|
||
|
f.setBold( true );
|
||
|
|
||
|
if ( element.hasAttribute( "underline" ) && element.attribute("underline") == "yes" )
|
||
|
f.setUnderline( true );
|
||
|
|
||
|
if ( element.hasAttribute( "strikeout" ) && element.attribute("strikeout") == "yes" )
|
||
|
f.setStrikeOut( true );
|
||
|
|
||
|
/* Uncomment when charset is added to kspread_dlg_layout
|
||
|
+ save a document-global charset
|
||
|
if ( element.hasAttribute( "charset" ) )
|
||
|
KGlobal::charsets()->setQFont( f, element.attribute("charset") );
|
||
|
else
|
||
|
*/
|
||
|
// ######## Not needed anymore in 3.0?
|
||
|
//KGlobal::charsets()->setQFont( f, KGlobal::locale()->charset() );
|
||
|
|
||
|
return f;
|
||
|
}
|
||
|
|
||
|
QPen KSpread::util_toPen( QDomElement & element )
|
||
|
{
|
||
|
bool ok;
|
||
|
QPen p;
|
||
|
|
||
|
p.setStyle( (Qt::PenStyle)element.attribute("style").toInt( &ok ) );
|
||
|
if ( !ok )
|
||
|
return QPen();
|
||
|
|
||
|
p.setWidth( element.attribute("width").toInt( &ok ) );
|
||
|
if ( !ok )
|
||
|
return QPen();
|
||
|
|
||
|
p.setColor( QColor( element.attribute("color") ) );
|
||
|
|
||
|
return p;
|
||
|
}
|
||
|
|
||
|
Point::Point(const QString & _str)
|
||
|
{
|
||
|
_sheet = 0;
|
||
|
init(_str);
|
||
|
}
|
||
|
|
||
|
void Point::setPos(QPoint pos)
|
||
|
{
|
||
|
_pos=pos;
|
||
|
}
|
||
|
QPoint Point::pos() const
|
||
|
{
|
||
|
return _pos;
|
||
|
}
|
||
|
void Point::setSheet(Sheet* sheet)
|
||
|
{
|
||
|
_sheet=sheet;
|
||
|
}
|
||
|
KSpread::Sheet* Point::sheet() const
|
||
|
{
|
||
|
return _sheet;
|
||
|
}
|
||
|
void Point::setSheetName(QString name)
|
||
|
{
|
||
|
_sheetName=name;
|
||
|
}
|
||
|
QString Point::sheetName() const
|
||
|
{
|
||
|
return _sheetName;
|
||
|
}
|
||
|
void Point::setColumnFixed(bool colFixed)
|
||
|
{
|
||
|
_columnFixed=colFixed;
|
||
|
}
|
||
|
bool Point::columnFixed() const
|
||
|
{
|
||
|
return _columnFixed;
|
||
|
}
|
||
|
void Point::setRowFixed(bool rowFixed)
|
||
|
{
|
||
|
_rowFixed=rowFixed;
|
||
|
}
|
||
|
bool Point::rowFixed() const
|
||
|
{
|
||
|
return _rowFixed;
|
||
|
}
|
||
|
|
||
|
|
||
|
void Point::init(const QString & _str)
|
||
|
{
|
||
|
_columnFixed=false;
|
||
|
_rowFixed=false;
|
||
|
|
||
|
// kdDebug(36001) <<"Point::init ("<<_str<<")"<<endl;
|
||
|
_pos.setX(-1);
|
||
|
|
||
|
uint len = _str.length();
|
||
|
if ( !len )
|
||
|
{
|
||
|
kdDebug(36001) << "Point::init: len = 0" << endl;
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
QString str( _str );
|
||
|
int n = _str.find( '!' );
|
||
|
if ( n != -1 )
|
||
|
{
|
||
|
_sheetName = _str.left( n );
|
||
|
str = _str.right( len - n - 1 ); // remove the '!'
|
||
|
len = str.length();
|
||
|
}
|
||
|
|
||
|
uint p = 0;
|
||
|
|
||
|
// Fixed ?
|
||
|
if ( str[0] == '$' )
|
||
|
{
|
||
|
_columnFixed = true;
|
||
|
p++;
|
||
|
}
|
||
|
else
|
||
|
_columnFixed = false;
|
||
|
|
||
|
// Malformed ?
|
||
|
if ( p == len )
|
||
|
{
|
||
|
kdDebug(36001) << "Point::init: no point after '$' (str: '" << str.mid( p ) << "'" << endl;
|
||
|
return;
|
||
|
}
|
||
|
if ( str[p] < 'A' || str[p] > 'Z' )
|
||
|
{
|
||
|
if ( str[p] < 'a' || str[p] > 'z' )
|
||
|
{
|
||
|
kdDebug(36001) << "Point::init: wrong first character in point (str: '" << str.mid( p ) << "'" << endl;
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
//default is error
|
||
|
int x = -1;
|
||
|
//search for the first character != text
|
||
|
int result = str.find( QRegExp("[^A-Za-z]+"), p );
|
||
|
|
||
|
//get the colomn number for the character between actual position and the first non text charakter
|
||
|
if ( result != -1 )
|
||
|
x = util_decodeColumnLabelText( str.mid( p, result - p ) ); // x is defined now
|
||
|
else // If there isn't any, then this is not a point -> return
|
||
|
{
|
||
|
kdDebug(36001) << "Point::init: no number in string (str: '" << str.mid( p, result ) << "'" << endl;
|
||
|
return;
|
||
|
}
|
||
|
p = result;
|
||
|
|
||
|
//limit is KS_colMax
|
||
|
if ( x > KS_colMax )
|
||
|
{
|
||
|
kdDebug(36001) << "Point::init: column value too high (col: " << x << ")" << endl;
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// Malformed ?
|
||
|
if (p == len)
|
||
|
{
|
||
|
kdDebug(36001) << "Point::init: p==len after cols" << endl;
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if (str[p] == '$')
|
||
|
{
|
||
|
_rowFixed = true;
|
||
|
p++;
|
||
|
// Malformed ?
|
||
|
if ( p == len )
|
||
|
{
|
||
|
kdDebug(36001) << "Point::init: p==len after $ of row" << endl;
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
_rowFixed = false;
|
||
|
|
||
|
uint p2 = p;
|
||
|
while ( p < len )
|
||
|
{
|
||
|
if ( !isdigit( QChar(str[p++]) ) )
|
||
|
{
|
||
|
kdDebug(36001) << "Point::init: no number" << endl;
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
bool ok;
|
||
|
int y = str.mid( p2, p-p2 ).toInt( &ok );
|
||
|
if ( !ok )
|
||
|
{
|
||
|
kdDebug(36001) << "Point::init: Invalid number (str: '" << str.mid( p2, p-p2 ) << "'" << endl;
|
||
|
return;
|
||
|
}
|
||
|
if ( y > KS_rowMax )
|
||
|
{
|
||
|
kdDebug(36001) << "Point::init: row value too high (row: " << y << ")" << endl;
|
||
|
return;
|
||
|
}
|
||
|
if ( y <= 0 )
|
||
|
{
|
||
|
kdDebug(36001) << "Point::init: y <= 0" << endl;
|
||
|
return;
|
||
|
}
|
||
|
_pos = QPoint( x, y );
|
||
|
}
|
||
|
|
||
|
bool util_isPointValid( QPoint point )
|
||
|
{
|
||
|
if ( point.x() >= 1
|
||
|
&& point.y() >= 1
|
||
|
&& point.x() <= KS_colMax
|
||
|
&& point.y() <= KS_rowMax
|
||
|
)
|
||
|
return true;
|
||
|
else
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
bool util_isRectValid( QRect rect )
|
||
|
{
|
||
|
if ( util_isPointValid( rect.topLeft() )
|
||
|
&& util_isPointValid( rect.bottomRight() )
|
||
|
)
|
||
|
return true;
|
||
|
else
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
Point::Point( const QString & str, Map * map,
|
||
|
Sheet * sheet )
|
||
|
{
|
||
|
|
||
|
uint p = 0;
|
||
|
int p2 = str.find( '!' );
|
||
|
if ( p2 != -1 )
|
||
|
{
|
||
|
_sheetName = str.left( p2++ );
|
||
|
while ( true )
|
||
|
{
|
||
|
_sheet = map->findSheet( _sheetName );
|
||
|
if ( !sheet && _sheetName[0] == ' ' )
|
||
|
{
|
||
|
_sheetName = _sheetName.right( _sheetName.length() - 1 );
|
||
|
continue;
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
p = p2;
|
||
|
|
||
|
//If the loop didn't return a sheet, better keep a string for isValid
|
||
|
if ( _sheetName.isEmpty() )
|
||
|
{
|
||
|
kdDebug(36001) << "Point: tableName is unknown" << endl;
|
||
|
_sheetName = "unknown";
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if ( sheet != 0 )
|
||
|
{
|
||
|
_sheet = sheet;
|
||
|
_sheetName = sheet->sheetName();
|
||
|
}
|
||
|
else
|
||
|
_sheet = 0;
|
||
|
}
|
||
|
|
||
|
init( str.mid( p ) );
|
||
|
}
|
||
|
|
||
|
Cell *Point::cell() const
|
||
|
{
|
||
|
return _sheet->cellAt(_pos);
|
||
|
}
|
||
|
|
||
|
bool Point::operator== (const Point &cell) const
|
||
|
{
|
||
|
//sheet info ignored
|
||
|
return (_pos == cell.pos());
|
||
|
}
|
||
|
|
||
|
bool Point::operator< (const Point &cell) const
|
||
|
{
|
||
|
//sheet info ignored
|
||
|
return (pos().y() < cell.pos().y()) ? true :
|
||
|
((pos().y() == cell.pos().y()) && (pos().x() < cell.pos().x()));
|
||
|
}
|
||
|
|
||
|
bool Range::operator ==(const Range& otherRange) const
|
||
|
{
|
||
|
if ( _range == otherRange._range
|
||
|
&& _leftFixed == otherRange._leftFixed
|
||
|
&& _rightFixed == otherRange._rightFixed
|
||
|
&& _bottomFixed == otherRange._bottomFixed
|
||
|
&& _topFixed == otherRange._topFixed
|
||
|
&& _sheet == otherRange._sheet )
|
||
|
return true;
|
||
|
else
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
Range::Range()
|
||
|
{
|
||
|
_sheet = 0;
|
||
|
_range.setLeft( -1 );
|
||
|
|
||
|
_leftFixed=false;
|
||
|
_rightFixed=false;
|
||
|
_topFixed=false;
|
||
|
_bottomFixed=false;
|
||
|
}
|
||
|
Range::Range(const QString & _str)
|
||
|
{
|
||
|
_range.setLeft(-1);
|
||
|
_sheet = 0;
|
||
|
|
||
|
int p = _str.find(':');
|
||
|
// if (p == -1)
|
||
|
// return;
|
||
|
|
||
|
Point ul;
|
||
|
Point lr; ;
|
||
|
|
||
|
if ( p != -1)
|
||
|
{
|
||
|
ul = Point(_str.left(p));
|
||
|
lr = Point(_str.mid(p + 1));
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
ul = Point(_str);
|
||
|
lr = ul;
|
||
|
}
|
||
|
|
||
|
_range = QRect(ul.pos(), lr.pos());
|
||
|
_sheetName = ul.sheetName();
|
||
|
|
||
|
_leftFixed = ul.columnFixed();
|
||
|
_rightFixed = lr.columnFixed();
|
||
|
_topFixed = ul.rowFixed();
|
||
|
_bottomFixed = lr.rowFixed();
|
||
|
}
|
||
|
|
||
|
Range::Range( const Range& r )
|
||
|
{
|
||
|
_sheet = r.sheet();
|
||
|
_sheetName = r.sheetName();
|
||
|
_range = r.range();
|
||
|
_namedArea = r.namedArea();
|
||
|
|
||
|
_leftFixed=r._leftFixed;
|
||
|
_rightFixed=r._rightFixed;
|
||
|
_topFixed=r._topFixed;
|
||
|
_bottomFixed=r._bottomFixed;
|
||
|
}
|
||
|
|
||
|
Range::Range( const Point& ul, const Point& lr )
|
||
|
{
|
||
|
_range = QRect( ul.pos(), lr.pos() );
|
||
|
if ( ul.sheetName() != lr.sheetName() )
|
||
|
{
|
||
|
_range.setLeft( -1 );
|
||
|
return;
|
||
|
}
|
||
|
_sheetName = ul.sheetName();
|
||
|
_sheet = ul.sheet();
|
||
|
_leftFixed = ul.columnFixed();
|
||
|
_rightFixed = lr.columnFixed();
|
||
|
_topFixed = ul.rowFixed();
|
||
|
_bottomFixed = lr.rowFixed();
|
||
|
}
|
||
|
|
||
|
Range::Range(const QString & str, Map * map,
|
||
|
Sheet * sheet)
|
||
|
{
|
||
|
_range.setLeft(-1);
|
||
|
_sheet = 0;
|
||
|
|
||
|
//try to parse as named area
|
||
|
bool gotNamed = false;
|
||
|
QString tmp = str.lower();
|
||
|
QValueList < Reference >::Iterator it;
|
||
|
QValueList < Reference > area = map->doc()->listArea();
|
||
|
for (it = area.begin(); it != area.end(); ++it) {
|
||
|
if ((*it).ref_name.lower() == tmp) {
|
||
|
// success - such named area exists
|
||
|
_range = (*it).rect;
|
||
|
_sheet = map->findSheet((*it).sheet_name);
|
||
|
gotNamed = true;
|
||
|
_namedArea = tmp;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
if (gotNamed) {
|
||
|
// we have a named area - no need to proceed further
|
||
|
_leftFixed = false;
|
||
|
_rightFixed = false;
|
||
|
_topFixed = false;
|
||
|
_bottomFixed = false;
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
_range.setLeft(-1);
|
||
|
_sheet = 0;
|
||
|
|
||
|
int p = 0;
|
||
|
int p2 = str.find('!');
|
||
|
if (p2 != -1)
|
||
|
{
|
||
|
_sheetName = str.left(p2++);
|
||
|
while ( true )
|
||
|
{
|
||
|
_sheet = map->findSheet(_sheetName);
|
||
|
|
||
|
if ( !_sheet && _sheetName[0] == ' ' )
|
||
|
{
|
||
|
_sheetName = _sheetName.right( _sheetName.length() - 1 );
|
||
|
continue;
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
p = p2;
|
||
|
} else
|
||
|
_sheet = sheet;
|
||
|
|
||
|
|
||
|
int p3 = str.find(':', p);
|
||
|
if (p3 == -1)
|
||
|
return;
|
||
|
|
||
|
Point ul(str.mid(p, p3 - p));
|
||
|
Point lr(str.mid(p3 + 1));
|
||
|
_range = QRect(ul.pos(), lr.pos());
|
||
|
|
||
|
_leftFixed = ul.columnFixed();
|
||
|
_rightFixed = lr.columnFixed();
|
||
|
_topFixed = ul.rowFixed();
|
||
|
_bottomFixed = lr.rowFixed();
|
||
|
}
|
||
|
|
||
|
QString Range::toString() const
|
||
|
{
|
||
|
QString result;
|
||
|
|
||
|
if (_sheet)
|
||
|
{
|
||
|
result=util_rangeName(_sheet,_range);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
result=util_rangeName(_range);
|
||
|
}
|
||
|
|
||
|
//Insert $ characters to show fixed parts of range
|
||
|
|
||
|
int pos=result.find("!")+1;
|
||
|
Q_ASSERT(pos != -1);
|
||
|
|
||
|
if (_leftFixed)
|
||
|
{
|
||
|
result.insert(pos,'$');
|
||
|
pos++; //Takes account of extra character added in
|
||
|
}
|
||
|
if (_topFixed)
|
||
|
{
|
||
|
result.insert(pos+Cell::columnName(_range.left()).length(),'$');
|
||
|
}
|
||
|
|
||
|
pos=result.find(":")+1;
|
||
|
Q_ASSERT(pos != -1);
|
||
|
|
||
|
if (_rightFixed)
|
||
|
{
|
||
|
result.insert(pos,'$');
|
||
|
pos++; //Takes account of extra character added in
|
||
|
}
|
||
|
if (_bottomFixed)
|
||
|
{
|
||
|
result.insert(pos+Cell::columnName(_range.right()).length(),'$');
|
||
|
}
|
||
|
|
||
|
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
void Range::getStartPoint(Point* pt)
|
||
|
{
|
||
|
if (!isValid()) return;
|
||
|
|
||
|
pt->setRow(startRow());
|
||
|
pt->setColumn(startCol());
|
||
|
pt->setColumnFixed(_leftFixed);
|
||
|
pt->setRowFixed(_topFixed);
|
||
|
pt->setSheet(_sheet);
|
||
|
pt->setSheetName(_sheetName);
|
||
|
}
|
||
|
|
||
|
void Range::getEndPoint(Point* pt)
|
||
|
{
|
||
|
if (!isValid()) return;
|
||
|
|
||
|
pt->setRow(endRow());
|
||
|
pt->setColumn(endCol());
|
||
|
pt->setColumnFixed(_rightFixed);
|
||
|
pt->setRowFixed(_bottomFixed);
|
||
|
pt->setSheet(_sheet);
|
||
|
pt->setSheetName(_sheetName);
|
||
|
}
|
||
|
|
||
|
bool Range::contains (const Point &cell) const
|
||
|
{
|
||
|
return _range.contains (cell.pos());
|
||
|
}
|
||
|
|
||
|
bool Range::intersects (const Range &r) const
|
||
|
{
|
||
|
return _range.intersects (r.range());
|
||
|
}
|
||
|
|
||
|
bool Range::isValid() const
|
||
|
{
|
||
|
return ( _range.left() >= 0 ) &&
|
||
|
( _range.right() >= 0 ) &&
|
||
|
( _sheet != 0 || _sheetName.isEmpty() ) &&
|
||
|
( _range.isValid() ) ;
|
||
|
}
|
||
|
|
||
|
QRect Range::range() const
|
||
|
{
|
||
|
return _range;
|
||
|
}
|
||
|
|
||
|
void Range::setLeftFixed(bool fixed)
|
||
|
{
|
||
|
_leftFixed=fixed;
|
||
|
}
|
||
|
bool Range::leftFixed() const
|
||
|
{
|
||
|
return _leftFixed;
|
||
|
}
|
||
|
void Range::setRightFixed(bool fixed)
|
||
|
{
|
||
|
_rightFixed=fixed;
|
||
|
}
|
||
|
bool Range::rightFixed() const
|
||
|
{
|
||
|
return _rightFixed;
|
||
|
}
|
||
|
void Range::setTopFixed(bool fixed)
|
||
|
{
|
||
|
_topFixed=fixed;
|
||
|
}
|
||
|
bool Range::topFixed() const
|
||
|
{
|
||
|
return _topFixed;
|
||
|
}
|
||
|
void Range::setBottomFixed(bool fixed)
|
||
|
{
|
||
|
_bottomFixed=fixed;
|
||
|
}
|
||
|
bool Range::bottomFixed() const
|
||
|
{
|
||
|
return _bottomFixed;
|
||
|
}
|
||
|
void Range::setSheet(Sheet* sheet)
|
||
|
{
|
||
|
_sheet=sheet;
|
||
|
}
|
||
|
KSpread::Sheet* Range::sheet() const
|
||
|
{
|
||
|
return _sheet;
|
||
|
}
|
||
|
void Range::setSheetName(QString sheetName)
|
||
|
{
|
||
|
_sheetName=sheetName;
|
||
|
}
|
||
|
QString Range::sheetName() const
|
||
|
{
|
||
|
return _sheetName;
|
||
|
}
|
||
|
QString Range::namedArea() const
|
||
|
{
|
||
|
return _namedArea;
|
||
|
}
|
||
|
|
||
|
|
||
|
bool KSpread::util_isAllSelected(const QRect &selection)
|
||
|
{
|
||
|
return ( selection.top() == 1 && selection.bottom() == KS_rowMax
|
||
|
&& selection.left() == 1 && selection.right() == KS_colMax);
|
||
|
}
|
||
|
|
||
|
bool KSpread::util_isColumnSelected(const QRect &selection)
|
||
|
{
|
||
|
return ( (selection.top() == 1) && (selection.bottom() == KS_rowMax) );
|
||
|
}
|
||
|
|
||
|
bool KSpread::util_isRowSelected(const QRect &selection)
|
||
|
{
|
||
|
return ( (selection.left() == 1) && (selection.right() == KS_colMax) );
|
||
|
}
|
||
|
|
||
|
bool KSpread::util_isRowOrColumnSelected(const QRect &selection)
|
||
|
{
|
||
|
return ( (selection.left() == 1) && (selection.right() == KS_colMax)
|
||
|
|| (selection.top() == 1) && (selection.bottom() == KS_rowMax) );
|
||
|
}
|
||
|
|
||
|
//used in View::slotRename
|
||
|
bool KSpread::util_validateSheetName(const QString &name)
|
||
|
{
|
||
|
if (name[0] == ' ')
|
||
|
{
|
||
|
return false;
|
||
|
}
|
||
|
for (unsigned int i = 0; i < name.length(); i++)
|
||
|
{
|
||
|
if ( !(name[i].isLetterOrNumber() ||
|
||
|
name[i] == ' ' || name[i] == '.' ||
|
||
|
name[i] == '_'))
|
||
|
{
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
|
||
|
RangeIterator::RangeIterator(QRect _range, Sheet* _sheet)
|
||
|
{
|
||
|
range = _range;
|
||
|
sheet = _sheet;
|
||
|
current = QPoint(0,0);
|
||
|
}
|
||
|
|
||
|
RangeIterator::~RangeIterator()
|
||
|
{
|
||
|
}
|
||
|
|
||
|
Cell* RangeIterator::first()
|
||
|
{
|
||
|
current.setY(range.top());
|
||
|
|
||
|
/* OK, because even if this equals zero, the 'getNextCellRight' won't
|
||
|
try to access it*/
|
||
|
current.setX(range.left() - 1);
|
||
|
return next();
|
||
|
}
|
||
|
|
||
|
Cell* RangeIterator::next()
|
||
|
{
|
||
|
if (current.x() == 0 && current.y() == 0)
|
||
|
{
|
||
|
return first();
|
||
|
}
|
||
|
|
||
|
Cell* cell = NULL;
|
||
|
bool done = false;
|
||
|
|
||
|
while (cell == NULL && !done)
|
||
|
{
|
||
|
cell = sheet->getNextCellRight(current.x(), current.y());
|
||
|
if (cell != NULL && cell->column() > range.right())
|
||
|
{
|
||
|
cell = NULL;
|
||
|
}
|
||
|
|
||
|
if (cell == NULL)
|
||
|
{
|
||
|
current.setX(range.left() - 1);
|
||
|
current.setY(current.y() + 1);
|
||
|
done = (current.y() > range.bottom());
|
||
|
}
|
||
|
}
|
||
|
return cell;
|
||
|
}
|
||
|
|
||
|
//not used anywhere
|
||
|
int KSpread::util_penCompare( QPen const & pen1, QPen const & pen2 )
|
||
|
{
|
||
|
if ( pen1.style() == Qt::NoPen && pen2.style() == Qt::NoPen )
|
||
|
return 0;
|
||
|
|
||
|
if ( pen1.style() == Qt::NoPen )
|
||
|
return -1;
|
||
|
|
||
|
if ( pen2.style() == Qt::NoPen )
|
||
|
return 1;
|
||
|
|
||
|
if ( pen1.width() < pen2.width() )
|
||
|
return -1;
|
||
|
|
||
|
if ( pen1.width() > pen2.width() )
|
||
|
return 1;
|
||
|
|
||
|
if ( pen1.style() < pen2.style() )
|
||
|
return -1;
|
||
|
|
||
|
if ( pen1.style() > pen2.style() )
|
||
|
return 1;
|
||
|
|
||
|
if ( pen1.color().name() < pen2.color().name() )
|
||
|
return -1;
|
||
|
|
||
|
if ( pen1.color().name() > pen2.color().name() )
|
||
|
return 1;
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
|
||
|
QString KSpread::convertRefToBase( const QString & sheet, const QRect & rect )
|
||
|
{
|
||
|
QPoint bottomRight( rect.bottomRight() );
|
||
|
|
||
|
QString s( "$" );
|
||
|
s += sheet;
|
||
|
s += ".$";
|
||
|
s += Cell::columnName( bottomRight.x() );
|
||
|
s += '$';
|
||
|
s += QString::number( bottomRight.y() );
|
||
|
|
||
|
return s;
|
||
|
}
|
||
|
|
||
|
QString KSpread::convertRefToRange( const QString & sheet, const QRect & rect )
|
||
|
{
|
||
|
QPoint topLeft( rect.topLeft() );
|
||
|
QPoint bottomRight( rect.bottomRight() );
|
||
|
|
||
|
if ( topLeft == bottomRight )
|
||
|
return convertRefToBase( sheet, rect );
|
||
|
|
||
|
QString s( "$" );
|
||
|
s += sheet;
|
||
|
s += ".$";
|
||
|
s += /*util_encodeColumnLabelText*/Cell::columnName( topLeft.x() );
|
||
|
s += '$';
|
||
|
s += QString::number( topLeft.y() );
|
||
|
s += ":.$";
|
||
|
s += /*util_encodeColumnLabelText*/Cell::columnName( bottomRight.x() );
|
||
|
s += '$';
|
||
|
s += QString::number( bottomRight.y() );
|
||
|
|
||
|
return s;
|
||
|
}
|
||
|
|
||
|
//used in Cell::convertFormulaToOasisFormat
|
||
|
void KSpread::insertBracket( QString & s )
|
||
|
{
|
||
|
QChar c;
|
||
|
int i = (int) s.length() - 1;
|
||
|
|
||
|
while ( i >= 0 )
|
||
|
{
|
||
|
c = s[i];
|
||
|
if ( c == ' ' )
|
||
|
s[i] = '_';
|
||
|
if ( !(c.isLetterOrNumber() || c == ' ' || c == '.'
|
||
|
|| c == '_') )
|
||
|
{
|
||
|
s.insert( i + 1, '[' );
|
||
|
return;
|
||
|
}
|
||
|
--i;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// e.g.: Sheet4.A1:Sheet4.E28
|
||
|
//used in Sheet::saveOasis
|
||
|
QString KSpread::convertRangeToRef( const QString & sheetName, const QRect & _area )
|
||
|
{
|
||
|
return sheetName + "." + Cell::name( _area.left(), _area.top() ) + ":" + sheetName + "."+ Cell::name( _area.right(), _area.bottom() );
|
||
|
}
|
||
|
|
||
|
QString KSpread::convertOasisPenToString( const QPen & pen )
|
||
|
{
|
||
|
// kdDebug()<<"convertOasisPenToString( const QPen & pen ) :"<<pen<<endl;
|
||
|
// NOTE Stefan: QPen api docs:
|
||
|
// For horizontal and vertical lines a line width of 0 is
|
||
|
// the same as a line width of 1.
|
||
|
// A line width of 0 will produce a 1 pixel wide line using
|
||
|
// a fast algorithm for diagonals. A line width of 1 will
|
||
|
// also produce a 1 pixel wide line, but uses a slower more
|
||
|
// accurate algorithm for diagonals.
|
||
|
QString s = QString( "%1pt " ).arg( (pen.width() == 0) ? 1 : pen.width() );
|
||
|
switch( pen.style() )
|
||
|
{
|
||
|
case Qt::NoPen:
|
||
|
return "none";
|
||
|
case Qt::SolidLine:
|
||
|
s+="solid";
|
||
|
break;
|
||
|
case Qt::DashLine:
|
||
|
s+="dashed";
|
||
|
break;
|
||
|
case Qt::DotLine:
|
||
|
s+="dotted";
|
||
|
break;
|
||
|
case Qt::DashDotLine:
|
||
|
s+="dot-dash";
|
||
|
break;
|
||
|
case Qt::DashDotDotLine:
|
||
|
s+="dot-dot-dash";
|
||
|
break;
|
||
|
default: break;
|
||
|
}
|
||
|
kdDebug()<<" convertOasisPenToString :"<<s<<endl;
|
||
|
if ( pen.color().isValid() )
|
||
|
{
|
||
|
s+=' ';
|
||
|
s+=Style::colorName(pen.color());
|
||
|
}
|
||
|
return s;
|
||
|
}
|
||
|
|
||
|
QPen KSpread::convertOasisStringToPen( const QString &border )
|
||
|
{
|
||
|
QPen pen;
|
||
|
//string like "0.088cm solid #800000"
|
||
|
if (border.isEmpty() || border=="none" || border=="hidden") // in fact no border
|
||
|
{
|
||
|
pen.setStyle( Qt::NoPen );
|
||
|
return pen;
|
||
|
}
|
||
|
//code from koborder, for the moment kspread doesn't use koborder
|
||
|
// ## isn't it faster to use QStringList::split than parse it 3 times?
|
||
|
QString _width = border.section(' ', 0, 0);
|
||
|
QCString _style = border.section(' ', 1, 1).latin1();
|
||
|
QString _color = border.section(' ', 2, 2);
|
||
|
|
||
|
pen.setWidth( ( int )( KoUnit::parseValue( _width, 1.0 ) ) );
|
||
|
|
||
|
if ( _style =="none" )
|
||
|
pen.setStyle( Qt::NoPen );
|
||
|
else if ( _style =="solid" )
|
||
|
pen.setStyle( Qt::SolidLine );
|
||
|
else if ( _style =="dashed" )
|
||
|
pen.setStyle( Qt::DashLine );
|
||
|
else if ( _style =="dotted" )
|
||
|
pen.setStyle( Qt::DotLine );
|
||
|
else if ( _style =="dot-dash" )
|
||
|
pen.setStyle( Qt::DashDotLine );
|
||
|
else if ( _style =="dot-dot-dash" )
|
||
|
pen.setStyle( Qt::DashDotDotLine );
|
||
|
else
|
||
|
kdDebug()<<" style undefined : "<<_style<<endl;
|
||
|
|
||
|
if ( _color.isEmpty() )
|
||
|
pen.setColor( QColor() );
|
||
|
else
|
||
|
pen.setColor( QColor( _color ) );
|
||
|
|
||
|
return pen;
|
||
|
}
|
||
|
|
||
|
//Return true when it's a reference to cell from sheet.
|
||
|
bool KSpread::localReferenceAnchor( const QString &_ref )
|
||
|
{
|
||
|
bool isLocalRef = (_ref.find("http://") != 0 &&
|
||
|
_ref.find("mailto:") != 0 &&
|
||
|
_ref.find("ftp://") != 0 &&
|
||
|
_ref.find("file:") != 0 );
|
||
|
return isLocalRef;
|
||
|
}
|
||
|
|
||
|
|
||
|
QString KSpread::Oasis::decodeFormula(const QString& expr, const KLocale* locale)
|
||
|
{
|
||
|
// parsing state
|
||
|
enum { Start, InNumber, InString, InIdentifier, InReference, InSheetName } state;
|
||
|
|
||
|
// use locale settings
|
||
|
QString decimal = locale ? locale->decimalSymbol() : ".";
|
||
|
|
||
|
// initialize variables
|
||
|
state = Start;
|
||
|
unsigned int i = 0;
|
||
|
const QString ex = expr;
|
||
|
QString result;
|
||
|
|
||
|
if (ex[0] == '=')
|
||
|
{
|
||
|
result="=";
|
||
|
++i;
|
||
|
}
|
||
|
|
||
|
// main loop
|
||
|
while( i < ex.length() )
|
||
|
{
|
||
|
QChar ch = ex[i];
|
||
|
|
||
|
switch( state )
|
||
|
{
|
||
|
case Start:
|
||
|
{
|
||
|
// check for number
|
||
|
if( ch.isDigit() )
|
||
|
{
|
||
|
state = InNumber;
|
||
|
}
|
||
|
|
||
|
// a string?
|
||
|
else if ( ch == '"' )
|
||
|
{
|
||
|
state = InString;
|
||
|
result.append( ex[i++] );
|
||
|
}
|
||
|
|
||
|
// beginning with alphanumeric ?
|
||
|
// could be identifier, cell, range, or function...
|
||
|
else if( isIdentifier( ch ) )
|
||
|
{
|
||
|
state = InIdentifier;
|
||
|
}
|
||
|
|
||
|
// [ marks sheet name for 3-d cell, e.g ['Sales Q3'.A4]
|
||
|
else if ( ch.unicode() == '[' )
|
||
|
{
|
||
|
++i;
|
||
|
state = InReference;
|
||
|
// NOTE Stefan: As long as KSpread does not support fixed sheets eat the dollar sign.
|
||
|
if ( ex[i] == '$' ) ++i;
|
||
|
}
|
||
|
|
||
|
// decimal dot ?
|
||
|
else if ( ch == '.' )
|
||
|
{
|
||
|
if ( ex[i+1].isDigit() )
|
||
|
state = InNumber;
|
||
|
else
|
||
|
state = InReference;
|
||
|
}
|
||
|
|
||
|
// look for operator match
|
||
|
else
|
||
|
{
|
||
|
int op;
|
||
|
QString s;
|
||
|
|
||
|
// check for two-chars operator, such as '<=', '>=', etc
|
||
|
s.append( ch ).append( ex[i+1] );
|
||
|
op = matchOperator( s );
|
||
|
|
||
|
// check for one-char operator, such as '+', ';', etc
|
||
|
if( op == Token::InvalidOp )
|
||
|
{
|
||
|
s = QString( ch );
|
||
|
op = matchOperator( s );
|
||
|
}
|
||
|
|
||
|
// any matched operator ?
|
||
|
if ( op == Token::Equal )
|
||
|
{
|
||
|
result.append( "==" );
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
result.append( s );
|
||
|
}
|
||
|
if( op != Token::InvalidOp )
|
||
|
{
|
||
|
int len = s.length();
|
||
|
i += len;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
++i;
|
||
|
state = Start;
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
case InReference:
|
||
|
{
|
||
|
// consume as long as alpha, dollar sign, underscore, or digit, or colon
|
||
|
if( isIdentifier( ch ) || ch.isDigit() || ch == ':' )
|
||
|
result.append( ex[i] );
|
||
|
else if ( ch == '.' && i > 0 && ex[i-1] != '[' && ex[i-1] != ':' )
|
||
|
result.append( '!' );
|
||
|
else if( ch == ']' )
|
||
|
state = Start;
|
||
|
else if ( ch == '\'' )
|
||
|
{
|
||
|
result.append( ex[i] );
|
||
|
state = InSheetName;
|
||
|
// NOTE Stefan: As long as KSpread does not support fixed sheets eat the dollar sign.
|
||
|
if ( ex[i] == '$' ) ++i;
|
||
|
}
|
||
|
else if ( ch != '.' )
|
||
|
{
|
||
|
state = Start;
|
||
|
break;
|
||
|
}
|
||
|
++i;
|
||
|
break;
|
||
|
}
|
||
|
case InSheetName:
|
||
|
{
|
||
|
if ( ch == '\'' )
|
||
|
state = InReference;
|
||
|
result.append( ex[i] );
|
||
|
++i;
|
||
|
break;
|
||
|
}
|
||
|
case InNumber:
|
||
|
{
|
||
|
// consume as long as it's digit
|
||
|
if( ch.isDigit() )
|
||
|
result.append( ex[i++] );
|
||
|
// convert '.' to decimal separator
|
||
|
else if ( ch == '.' )
|
||
|
{
|
||
|
result.append( decimal );
|
||
|
++i;
|
||
|
}
|
||
|
// exponent ?
|
||
|
else if( ch.upper() == 'E' )
|
||
|
{
|
||
|
result.append( 'E' );
|
||
|
++i;
|
||
|
}
|
||
|
// we're done with integer number
|
||
|
else
|
||
|
state = Start;
|
||
|
break;
|
||
|
}
|
||
|
case InString:
|
||
|
{
|
||
|
// consume until "
|
||
|
if( ch != '"' )
|
||
|
{
|
||
|
result.append( ex[i++] );
|
||
|
}
|
||
|
// we're done
|
||
|
else
|
||
|
{
|
||
|
result.append( ch );
|
||
|
++i;
|
||
|
state = Start;
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
case InIdentifier:
|
||
|
{
|
||
|
// consume as long as alpha, dollar sign, underscore, or digit
|
||
|
if( isIdentifier( ch ) || ch.isDigit() )
|
||
|
result.append( ex[i++] );
|
||
|
// we're done
|
||
|
else
|
||
|
state = Start;
|
||
|
break;
|
||
|
}
|
||
|
default:
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
/*QString KSpread::Oasis::encodeFormula(const QString& expr, const KLocale* locale)
|
||
|
{
|
||
|
// TODO move Cell::convertFormulaToOasisFormat to this point
|
||
|
//expr = "not here yet";
|
||
|
//Q_UNUSED(locale);
|
||
|
kdDebug() << k_funcinfo << " not implemented"
|
||
|
qFatal(0);
|
||
|
}*/
|