00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include "kspread_util.h"
00021 #include "kspread_map.h"
00022 #include "kspread_doc.h"
00023 #include "kspread_locale.h"
00024 #include <ctype.h>
00025
00026 #include <qregexp.h>
00027
00028 #include <kdebug.h>
00029
00030
00031 bool formatIsDate (FormatType fmt)
00032 {
00033 return ((fmt == ShortDate_format) || (fmt == TextDate_format) ||
00034 (((int) fmt >= 200) && ((int) fmt < 300)));
00035 }
00036
00037 bool formatIsTime (FormatType fmt)
00038 {
00039 return (((int) fmt >= 50) && ((int) fmt < 70));
00040 }
00041
00042 bool formatIsFraction (FormatType fmt)
00043 {
00044 return (((int) fmt >= 70) && ((int) fmt < 80));
00045 }
00046
00047
00048
00049
00050 int util_decodeColumnLabelText( const QString &_col )
00051 {
00052 int col = 0;
00053 int offset='a'-'A';
00054 int counterColumn = 0;
00055 for ( uint i=0; i < _col.length(); i++ )
00056 {
00057 counterColumn = (int) pow(26.0 , static_cast<int>(_col.length() - i - 1));
00058 if( _col[i] >= 'A' && _col[i] <= 'Z' )
00059 col += counterColumn * ( _col[i].latin1() - 'A' + 1);
00060 else if( _col[i] >= 'a' && _col[i] <= 'z' )
00061 col += counterColumn * ( _col[i].latin1() - 'A' - offset + 1 );
00062 else
00063 kdDebug(36001) << "util_decodeColumnLabelText: Wrong characters in label text for col:'" << _col << "'" << endl;
00064 }
00065 return col;
00066 }
00067
00068
00069 QString util_rangeColumnName( const QRect &_area)
00070 {
00071 return QString("%1:%2")
00072 .arg( KSpreadCell::columnName( _area.left()))
00073 .arg( KSpreadCell::columnName(_area.right()));
00074 }
00075
00076
00077 QString util_rangeRowName( const QRect &_area)
00078 {
00079 return QString("%1:%2")
00080 .arg( _area.top())
00081 .arg(_area.bottom());
00082 }
00083
00084
00085 QString util_rangeName(const QRect &_area)
00086 {
00087 return KSpreadCell::name( _area.left(), _area.top() ) + ":" +
00088 KSpreadCell::name( _area.right(), _area.bottom() );
00089 }
00090
00091 QString util_rangeName(KSpreadSheet * _sheet, const QRect &_area)
00092 {
00093 return _sheet->sheetName() + "!" + util_rangeName(_area);
00094 }
00095
00096 QDomElement util_createElement( const QString & tagName, const QFont & font, QDomDocument & doc )
00097 {
00098 QDomElement e( doc.createElement( tagName ) );
00099
00100 e.setAttribute( "family", font.family() );
00101 e.setAttribute( "size", font.pointSize() );
00102 e.setAttribute( "weight", font.weight() );
00103 if ( font.bold() )
00104 e.setAttribute( "bold", "yes" );
00105 if ( font.italic() )
00106 e.setAttribute( "italic", "yes" );
00107 if ( font.underline() )
00108 e.setAttribute( "underline", "yes" );
00109 if ( font.strikeOut() )
00110 e.setAttribute( "strikeout", "yes" );
00111
00112
00113 return e;
00114 }
00115
00116 QDomElement util_createElement( const QString & tagname, const QPen & pen, QDomDocument & doc )
00117 {
00118 QDomElement e( doc.createElement( tagname ) );
00119 e.setAttribute( "color", pen.color().name() );
00120 e.setAttribute( "style", (int)pen.style() );
00121 e.setAttribute( "width", (int)pen.width() );
00122 return e;
00123 }
00124
00125 QFont util_toFont( QDomElement & element )
00126 {
00127 QFont f;
00128 f.setFamily( element.attribute( "family" ) );
00129
00130 bool ok;
00131 f.setPointSize( element.attribute("size").toInt( &ok ) );
00132 if ( !ok )
00133 return QFont();
00134
00135 f.setWeight( element.attribute("weight").toInt( &ok ) );
00136 if ( !ok )
00137 return QFont();
00138
00139 if ( element.hasAttribute( "italic" ) && element.attribute("italic") == "yes" )
00140 f.setItalic( TRUE );
00141
00142 if ( element.hasAttribute( "bold" ) && element.attribute("bold") == "yes" )
00143 f.setBold( TRUE );
00144
00145 if ( element.hasAttribute( "underline" ) && element.attribute("underline") == "yes" )
00146 f.setUnderline( TRUE );
00147
00148 if ( element.hasAttribute( "strikeout" ) && element.attribute("strikeout") == "yes" )
00149 f.setStrikeOut( TRUE );
00150
00151
00152
00153
00154
00155
00156
00157
00158
00159
00160 return f;
00161 }
00162
00163 QPen util_toPen( QDomElement & element )
00164 {
00165 bool ok;
00166 QPen p;
00167
00168 p.setStyle( (Qt::PenStyle)element.attribute("style").toInt( &ok ) );
00169 if ( !ok )
00170 return QPen();
00171
00172 p.setWidth( element.attribute("width").toInt( &ok ) );
00173 if ( !ok )
00174 return QPen();
00175
00176 p.setColor( QColor( element.attribute("color") ) );
00177
00178 return p;
00179 }
00180
00181 KSpreadPoint::KSpreadPoint(const QString & _str)
00182 {
00183 sheet = 0;
00184 init(_str);
00185 }
00186
00187 void KSpreadPoint::init(const QString & _str)
00188 {
00189
00190
00191 pos.setX(-1);
00192
00193 uint len = _str.length();
00194 if ( !len )
00195 {
00196 kdDebug(36001) << "KSpreadPoint::init: len = 0" << endl;
00197 return;
00198 }
00199
00200 QString str( _str );
00201 int n = _str.find( '!' );
00202 if ( n != -1 )
00203 {
00204 sheetName = _str.left( n );
00205 str = _str.right( len - n - 1 );
00206 len = str.length();
00207 }
00208
00209 uint p = 0;
00210
00211
00212 if ( str[0] == '$' )
00213 {
00214 columnFixed = true;
00215 p++;
00216 }
00217 else
00218 columnFixed = false;
00219
00220
00221 if ( p == len )
00222 {
00223 kdDebug(36001) << "KSpreadPoint::init: no point after '$' (str: '" << str.mid( p ) << "'" << endl;
00224 return;
00225 }
00226 if ( str[p] < 'A' || str[p] > 'Z' )
00227 {
00228 if ( str[p] < 'a' || str[p] > 'z' )
00229 {
00230 kdDebug(36001) << "KSpreadPoint::init: wrong first character in point (str: '" << str.mid( p ) << "'" << endl;
00231 return;
00232 }
00233 }
00234
00235 int x = -1;
00236
00237 int result = str.find( QRegExp("[^A-Za-z]+"), p );
00238
00239
00240 if ( result != -1 )
00241 x = util_decodeColumnLabelText( str.mid( p, result - p ) );
00242 else
00243 {
00244 kdDebug(36001) << "KSpreadPoint::init: no number in string (str: '" << str.mid( p, result ) << "'" << endl;
00245 return;
00246 }
00247 p = result;
00248
00249
00250 if ( x > KS_colMax )
00251 {
00252 kdDebug(36001) << "KSpreadPoint::init: column value too high (col: " << x << ")" << endl;
00253 return;
00254 }
00255
00256
00257 if (p == len)
00258 {
00259 kdDebug(36001) << "KSpreadPoint::init: p==len after cols" << endl;
00260 return;
00261 }
00262
00263 if (str[p] == '$')
00264 {
00265 rowFixed = true;
00266 p++;
00267
00268 if ( p == len )
00269 {
00270 kdDebug(36001) << "KSpreadPoint::init: p==len after $ of row" << endl;
00271 return;
00272 }
00273 }
00274 else
00275 rowFixed = false;
00276
00277 uint p2 = p;
00278 while ( p < len )
00279 {
00280 if ( !isdigit( QChar(str[p++]) ) )
00281 {
00282 kdDebug(36001) << "KSpreadPoint::init: no number" << endl;
00283 return;
00284 }
00285 }
00286
00287 bool ok;
00288 int y = str.mid( p2, p-p2 ).toInt( &ok );
00289 if ( !ok )
00290 {
00291 kdDebug(36001) << "KSpreadPoint::init: Invalid number (str: '" << str.mid( p2, p-p2 ) << "'" << endl;
00292 return;
00293 }
00294 if ( y > KS_rowMax )
00295 {
00296 kdDebug(36001) << "KSpreadPoint::init: row value too high (row: " << y << ")" << endl;
00297 return;
00298 }
00299 if ( y <= 0 )
00300 {
00301 kdDebug(36001) << "KSpreadPoint::init: y <= 0" << endl;
00302 return;
00303 }
00304 pos = QPoint( x, y );
00305 }
00306
00307 KSpreadPoint::KSpreadPoint( const QString & _str, KSpreadMap * _map,
00308 KSpreadSheet * _sheet )
00309 {
00310 uint p = 0;
00311 int p2 = _str.find( '!' );
00312 if ( p2 != -1 )
00313 {
00314 sheetName = _str.left( p2++ );
00315 while ( true )
00316 {
00317 sheet = _map->findSheet( sheetName );
00318 if ( !sheet && sheetName[0] == ' ' )
00319 {
00320 sheetName = sheetName.right( sheetName.length() - 1 );
00321 continue;
00322 }
00323 break;
00324 }
00325 p = p2;
00326
00327
00328 if ( sheetName.isEmpty() )
00329 {
00330 kdDebug(36001) << "KSpreadPoint: tableName is unknown" << endl;
00331 sheetName = "unknown";
00332 }
00333 }
00334 else
00335 {
00336 if ( _sheet != 0 )
00337 {
00338 sheet = _sheet;
00339 sheetName = _sheet->sheetName();
00340 }
00341 else
00342 sheet = 0;
00343 }
00344
00345 init( _str.mid( p ) );
00346 }
00347
00348 KSpreadCell *KSpreadPoint::cell() const
00349 {
00350 return sheet->cellAt(pos);
00351 }
00352
00353 bool KSpreadPoint::operator== (const KSpreadPoint &cell) const
00354 {
00355
00356 return (pos == cell.pos);
00357 }
00358
00359 bool KSpreadPoint::operator< (const KSpreadPoint &cell) const
00360 {
00361
00362 return (pos.y() < cell.pos.y()) ? true :
00363 ((pos.y() == cell.pos.y()) && (pos.x() < cell.pos.x()));
00364 }
00365
00366 KSpreadRange::KSpreadRange(const QString & _str)
00367 {
00368 range.setLeft(-1);
00369 sheet = 0;
00370
00371 int p = _str.find(':');
00372 if (p == -1)
00373 return;
00374
00375 KSpreadPoint ul(_str.left(p));
00376 KSpreadPoint lr(_str.mid(p + 1));
00377 range = QRect(ul.pos, lr.pos);
00378 sheetName = ul.sheetName;
00379
00380 leftFixed = ul.columnFixed;
00381 rightFixed = lr.columnFixed;
00382 topFixed = ul.rowFixed;
00383 bottomFixed = lr.rowFixed;
00384 }
00385
00386 KSpreadRange::KSpreadRange(const QString & _str, KSpreadMap * _map,
00387 KSpreadSheet * _sheet)
00388 {
00389 range.setLeft(-1);
00390 sheet = 0;
00391
00392 if (_str.at(0) == "'" && _str.at(_str.length() - 1) == "'") {
00393 QString tmp = _str.right(_str.length() - 1);
00394 tmp = tmp.left(tmp.length() - 1);
00395 QValueList < Reference >::Iterator it;
00396 QValueList < Reference > area = _map->doc()->listArea();
00397 for (it = area.begin(); it != area.end(); ++it) {
00398 if ((*it).ref_name == tmp) {
00399 range = (*it).rect;
00400 sheet = _map->findSheet((*it).sheet_name);
00401 break;
00402 }
00403 }
00404 leftFixed = false;
00405 rightFixed = false;
00406 topFixed = false;
00407 bottomFixed = false;
00408 return;
00409 }
00410 range.setLeft(-1);
00411 sheet = 0;
00412
00413 int p = 0;
00414 int p2 = _str.find('!');
00415 if (p2 != -1)
00416 {
00417 sheetName = _str.left(p2++);
00418 while ( true )
00419 {
00420 sheet = _map->findSheet(sheetName);
00421 if ( !sheet && sheetName[0] == ' ' )
00422 {
00423 sheetName = sheetName.right( sheetName.length() - 1 );
00424 continue;
00425 }
00426 break;
00427 }
00428 p = p2;
00429 } else
00430 sheet = _sheet;
00431
00432
00433 int p3 = _str.find(':', p);
00434 if (p3 == -1)
00435 return;
00436
00437 KSpreadPoint ul(_str.mid(p, p3 - p));
00438 KSpreadPoint lr(_str.mid(p3 + 1));
00439 range = QRect(ul.pos, lr.pos);
00440
00441 leftFixed = ul.columnFixed;
00442 rightFixed = lr.columnFixed;
00443 topFixed = ul.rowFixed;
00444 bottomFixed = lr.rowFixed;
00445 }
00446
00447 bool KSpreadRange::contains (const KSpreadPoint &cell) const
00448 {
00449 return range.contains (cell.pos);
00450 }
00451
00452 bool KSpreadRange::intersects (const KSpreadRange &r) const
00453 {
00454 return range.intersects (r.range);
00455 }
00456
00457
00458 double util_fact( double val, double end )
00459 {
00460
00461 if(val<0.0 || end<0.0)
00462 return (-1);
00463 if(val==0.0)
00464 return (1);
00465 else if (val==end)
00466 return(1);
00467
00468 else
00469 return (val*util_fact((double)(val-1),end));
00470 }
00471
00472 bool util_isAllSelected(const QRect &selection)
00473 {
00474 return ( selection.top() == 1 && selection.bottom() == KS_rowMax
00475 && selection.left() == 1 && selection.right() == KS_colMax);
00476 }
00477
00478 bool util_isColumnSelected(const QRect &selection)
00479 {
00480 return ( (selection.top() == 1) && (selection.bottom() == KS_rowMax) );
00481 }
00482
00483 bool util_isRowSelected(const QRect &selection)
00484 {
00485 return ( (selection.left() == 1) && (selection.right() == KS_colMax) );
00486 }
00487
00488
00489 bool util_validateSheetName(const QString &name)
00490 {
00491 if (name[0] == ' ')
00492 {
00493 return false;
00494 }
00495 for (unsigned int i = 0; i < name.length(); i++)
00496 {
00497 if ( !(name[i].isLetterOrNumber() ||
00498 name[i] == ' ' || name[i] == '.' ||
00499 name[i] == '_'))
00500 {
00501 return false;
00502 }
00503 }
00504 return true;
00505 }
00506
00507
00508 KSpreadRangeIterator::KSpreadRangeIterator(QRect _range, KSpreadSheet* _sheet)
00509 {
00510 range = _range;
00511 sheet = _sheet;
00512 current = QPoint(0,0);
00513 }
00514
00515 KSpreadRangeIterator::~KSpreadRangeIterator()
00516 {
00517 }
00518
00519 KSpreadCell* KSpreadRangeIterator::first()
00520 {
00521 current.setY(range.top());
00522
00523
00524
00525 current.setX(range.left() - 1);
00526 return next();
00527 }
00528
00529 KSpreadCell* KSpreadRangeIterator::next()
00530 {
00531 if (current.x() == 0 && current.y() == 0)
00532 {
00533 return first();
00534 }
00535
00536 KSpreadCell* cell = NULL;
00537 bool done = false;
00538
00539 while (cell == NULL && !done)
00540 {
00541 cell = sheet->getNextCellRight(current.x(), current.y());
00542 if (cell != NULL && cell->column() > range.right())
00543 {
00544 cell = NULL;
00545 }
00546
00547 if (cell == NULL)
00548 {
00549 current.setX(range.left() - 1);
00550 current.setY(current.y() + 1);
00551 done = (current.y() > range.bottom());
00552 }
00553 }
00554 return cell;
00555 }
00556
00557
00558 int util_penCompare( QPen const & pen1, QPen const & pen2 )
00559 {
00560 if ( pen1.style() == Qt::NoPen && pen2.style() == Qt::NoPen )
00561 return 0;
00562
00563 if ( pen1.style() == Qt::NoPen )
00564 return -1;
00565
00566 if ( pen2.style() == Qt::NoPen )
00567 return 1;
00568
00569 if ( pen1.width() < pen2.width() )
00570 return -1;
00571
00572 if ( pen1.width() > pen2.width() )
00573 return 1;
00574
00575 if ( pen1.style() < pen2.style() )
00576 return -1;
00577
00578 if ( pen1.style() > pen2.style() )
00579 return 1;
00580
00581 if ( pen1.color().name() < pen2.color().name() )
00582 return -1;
00583
00584 if ( pen1.color().name() > pen2.color().name() )
00585 return 1;
00586
00587 return 0;
00588 }
00589
00590
00591 QString convertRefToBase( const QString & sheet, const QRect & rect )
00592 {
00593 QPoint bottomRight( rect.bottomRight() );
00594
00595 QString s( "$" );
00596 s += sheet;
00597 s += ".$";
00598 s += KSpreadCell::columnName( bottomRight.x() );
00599 s += '$';
00600 s += QString::number( bottomRight.y() );
00601
00602 return s;
00603 }
00604
00605 QString convertRefToRange( const QString & sheet, const QRect & rect )
00606 {
00607 QPoint topLeft( rect.topLeft() );
00608 QPoint bottomRight( rect.bottomRight() );
00609
00610 if ( topLeft == bottomRight )
00611 return convertRefToBase( sheet, rect );
00612
00613 QString s( "$" );
00614 s += sheet;
00615 s += ".$";
00616 s += KSpreadCell::columnName( topLeft.x() );
00617 s += '$';
00618 s += QString::number( topLeft.y() );
00619 s += ":.$";
00620 s += KSpreadCell::columnName( bottomRight.x() );
00621 s += '$';
00622 s += QString::number( bottomRight.y() );
00623
00624 return s;
00625 }
00626
00627
00628 void insertBracket( QString & s )
00629 {
00630 QChar c;
00631 int i = (int) s.length() - 1;
00632
00633 while ( i >= 0 )
00634 {
00635 c = s[i];
00636 if ( c == ' ' )
00637 s[i] = '_';
00638 if ( !(c.isLetterOrNumber() || c == ' ' || c == '.'
00639 || c == '_') )
00640 {
00641 s.insert( i + 1, '[' );
00642 return;
00643 }
00644 --i;
00645 }
00646 }
00647
00648
00649
00650 QString convertRangeToRef( const QString & sheetName, const QRect & _area )
00651 {
00652 return sheetName + "." + KSpreadCell::name( _area.left(), _area.top() ) + ":" + sheetName + "."+ KSpreadCell::name( _area.right(), _area.bottom() );
00653 }
00654
00655 QString convertOasisPenToString( const QPen & pen )
00656 {
00657 kdDebug()<<"convertOasisPenToString( const QPen & pen ) :"<<pen<<endl;
00658 QString s = QString( "%1pt " ).arg( pen.width() );
00659 switch( pen.style() )
00660 {
00661 case Qt::NoPen:
00662 return "none";
00663 case Qt::SolidLine:
00664 s+="solid";
00665 break;
00666 case Qt::DashLine:
00667 s+="dashed";
00668 break;
00669 case Qt::DotLine:
00670 s+="dotted";
00671 break;
00672 case Qt::DashDotLine:
00673 s+="dot-dash";
00674 break;
00675 case Qt::DashDotDotLine:
00676 s+="dot-dot-dash";
00677 break;
00678 }
00679 kdDebug()<<" convertOasisPenToString :"<<s<<endl;
00680 if ( pen.color().isValid() )
00681 {
00682 s+=' ';
00683 s+=pen.color().name();
00684 }
00685 return s;
00686 }
00687
00688 QPen convertOasisStringToPen( const QString &border )
00689 {
00690 QPen pen;
00691
00692 if (border.isEmpty() || border=="none" || border=="hidden")
00693 {
00694 pen.setStyle( Qt::NoPen );
00695 return pen;
00696 }
00697
00698
00699 QString _width = border.section(' ', 0, 0);
00700 QCString _style = border.section(' ', 1, 1).latin1();
00701 QString _color = border.section(' ', 2, 2);
00702
00703 pen.setWidth( ( int )( KoUnit::parseValue( _width, 1.0 ) ) );
00704
00705 if ( _style =="none" )
00706 pen.setStyle( Qt::NoPen );
00707 else if ( _style =="solid" )
00708 pen.setStyle( Qt::SolidLine );
00709 else if ( _style =="dashed" )
00710 pen.setStyle( Qt::DashLine );
00711 else if ( _style =="dotted" )
00712 pen.setStyle( Qt::DotLine );
00713 else if ( _style =="dot-dash" )
00714 pen.setStyle( Qt::DashDotLine );
00715 else if ( _style =="dot-dot-dash" )
00716 pen.setStyle( Qt::DashDotDotLine );
00717 else
00718 kdDebug()<<" style undefined : "<<_style<<endl;
00719
00720 if ( _color.isEmpty() )
00721 pen.setColor( QColor() );
00722 else
00723 pen.setColor( QColor( _color ) );
00724
00725 return pen;
00726 }
00727
00728
00729 bool localReferenceAnchor( const QString &_ref )
00730 {
00731 bool isLocalRef = (_ref.find("http://") != 0 &&
00732 _ref.find("mailto:") != 0 &&
00733 _ref.find("ftp://") != 0 &&
00734 _ref.find("file:") != 0 );
00735 return isLocalRef;
00736 }