summaryrefslogtreecommitdiffstats
path: root/kspread/kspread_util.cc
diff options
context:
space:
mode:
Diffstat (limited to 'kspread/kspread_util.cc')
-rw-r--r--kspread/kspread_util.cc1218
1 files changed, 1218 insertions, 0 deletions
diff --git a/kspread/kspread_util.cc b/kspread/kspread_util.cc
new file mode 100644
index 000000000..47d1a2154
--- /dev/null
+++ b/kspread/kspread_util.cc
@@ -0,0 +1,1218 @@
+/* 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);
+}*/