KOffice – TDE office suite
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
27KB

  1. /* This file is part of the KDE project
  2. Copyright (C) 2006 Stefan Nikolaus <stefan.nikolaus@kdemail.net>
  3. Copyright (C) 1998, 1999 Torben Weis <weis@kde.org>
  4. This library is free software; you can redistribute it and/or
  5. modify it under the terms of the GNU Library General Public
  6. License as published by the Free Software Foundation; either
  7. version 2 of the License, or (at your option) any later version.
  8. This library is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  11. Library General Public License for more details.
  12. You should have received a copy of the GNU Library General Public License
  13. along with this library; see the file COPYING.LIB. If not, write to
  14. the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
  15. * Boston, MA 02110-1301, USA.
  16. */
  17. #include <ctype.h>
  18. #include <tqregexp.h>
  19. #include <kdebug.h>
  20. #include "formula.h"
  21. #include "kspread_doc.h"
  22. #include "kspread_locale.h"
  23. #include "kspread_map.h"
  24. #include "kspread_sheet.h"
  25. #include "kspread_style.h"
  26. #include "kspread_util.h"
  27. using namespace KSpread;
  28. //helper functions for the formatting
  29. bool KSpread::formatIsDate (FormatType fmt)
  30. {
  31. return ((fmt == ShortDate_format) || (fmt == TextDate_format) ||
  32. (((int) fmt >= 200) && ((int) fmt < 300)));
  33. }
  34. bool KSpread::formatIsTime (FormatType fmt)
  35. {
  36. return (((int) fmt >= 50) && ((int) fmt < 70));
  37. }
  38. bool KSpread::formatIsFraction (FormatType fmt)
  39. {
  40. return (((int) fmt >= 70) && ((int) fmt < 80));
  41. }
  42. //used in Point::init, Cell::encodeFormula and
  43. // dialogs/kspread_dlg_paperlayout.cc
  44. int KSpread::util_decodeColumnLabelText( const TQString &_col )
  45. {
  46. int col = 0;
  47. int offset='a'-'A';
  48. int counterColumn = 0;
  49. for ( uint i=0; i < _col.length(); i++ )
  50. {
  51. counterColumn = (int) pow(26.0 , static_cast<int>(_col.length() - i - 1));
  52. if( (int)(_col[i]) >= 'A' && (int)(_col[i]) <= 'Z' )
  53. col += counterColumn * ( _col[i].latin1() - 'A' + 1); // okay here (Werner)
  54. else if( (int)(_col[i]) >= 'a' && (int)(_col[i]) <= 'z' )
  55. col += counterColumn * ( _col[i].latin1() - 'A' - offset + 1 );
  56. else
  57. kdDebug(36001) << "util_decodeColumnLabelText: Wrong characters in label text for col:'" << _col << "'" << endl;
  58. }
  59. return col;
  60. }
  61. //used in dialogs/kspread_dlg_paperlayout.cc
  62. TQString KSpread::util_rangeColumnName( const TQRect &_area)
  63. {
  64. return TQString("%1:%2")
  65. .arg( Cell::columnName( _area.left()))
  66. .arg( Cell::columnName(_area.right()));
  67. }
  68. //used in dialogs/kspread_dlg_paperlayout.cc
  69. TQString KSpread::util_rangeRowName( const TQRect &_area)
  70. {
  71. return TQString("%1:%2")
  72. .arg( _area.top())
  73. .arg(_area.bottom());
  74. }
  75. TQString KSpread::util_rangeName(const TQRect &_area)
  76. {
  77. return Cell::name( _area.left(), _area.top() ) + ":" +
  78. Cell::name( _area.right(), _area.bottom() );
  79. }
  80. TQString KSpread::util_rangeName(Sheet * _sheet, const TQRect &_area)
  81. {
  82. return _sheet->sheetName() + "!" + util_rangeName(_area);
  83. }
  84. TQDomElement KSpread::util_createElement( const TQString & tagName, const TQFont & font, TQDomDocument & doc )
  85. {
  86. TQDomElement e( doc.createElement( tagName ) );
  87. e.setAttribute( "family", font.family() );
  88. e.setAttribute( "size", font.pointSize() );
  89. e.setAttribute( "weight", font.weight() );
  90. if ( font.bold() )
  91. e.setAttribute( "bold", "yes" );
  92. if ( font.italic() )
  93. e.setAttribute( "italic", "yes" );
  94. if ( font.underline() )
  95. e.setAttribute( "underline", "yes" );
  96. if ( font.strikeOut() )
  97. e.setAttribute( "strikeout", "yes" );
  98. //e.setAttribute( "charset", TDEGlobal::charsets()->name( font ) );
  99. return e;
  100. }
  101. TQDomElement KSpread::util_createElement( const TQString & tagname, const TQPen & pen, TQDomDocument & doc )
  102. {
  103. TQDomElement e( doc.createElement( tagname ) );
  104. e.setAttribute( "color", pen.color().name() );
  105. e.setAttribute( "style", (int)pen.style() );
  106. e.setAttribute( "width", (int)pen.width() );
  107. return e;
  108. }
  109. TQFont KSpread::util_toFont( TQDomElement & element )
  110. {
  111. TQFont f;
  112. f.setFamily( element.attribute( "family" ) );
  113. bool ok;
  114. f.setPointSize( element.attribute("size").toInt( &ok ) );
  115. if ( !ok )
  116. return TQFont();
  117. f.setWeight( element.attribute("weight").toInt( &ok ) );
  118. if ( !ok )
  119. return TQFont();
  120. if ( element.hasAttribute( "italic" ) && element.attribute("italic") == "yes" )
  121. f.setItalic( true );
  122. if ( element.hasAttribute( "bold" ) && element.attribute("bold") == "yes" )
  123. f.setBold( true );
  124. if ( element.hasAttribute( "underline" ) && element.attribute("underline") == "yes" )
  125. f.setUnderline( true );
  126. if ( element.hasAttribute( "strikeout" ) && element.attribute("strikeout") == "yes" )
  127. f.setStrikeOut( true );
  128. /* Uncomment when charset is added to kspread_dlg_layout
  129. + save a document-global charset
  130. if ( element.hasAttribute( "charset" ) )
  131. TDEGlobal::charsets()->setTQFont( f, element.attribute("charset") );
  132. else
  133. */
  134. // ######## Not needed anymore in 3.0?
  135. //TDEGlobal::charsets()->setTQFont( f, TDEGlobal::locale()->charset() );
  136. return f;
  137. }
  138. TQPen KSpread::util_toPen( TQDomElement & element )
  139. {
  140. bool ok;
  141. TQPen p;
  142. p.setStyle( (Qt::PenStyle)element.attribute("style").toInt( &ok ) );
  143. if ( !ok )
  144. return TQPen();
  145. p.setWidth( element.attribute("width").toInt( &ok ) );
  146. if ( !ok )
  147. return TQPen();
  148. p.setColor( TQColor( element.attribute("color") ) );
  149. return p;
  150. }
  151. Point::Point(const TQString & _str)
  152. {
  153. _sheet = 0;
  154. init(_str);
  155. }
  156. void Point::setPos(TQPoint pos)
  157. {
  158. _pos=pos;
  159. }
  160. TQPoint Point::pos() const
  161. {
  162. return _pos;
  163. }
  164. void Point::setSheet(Sheet* sheet)
  165. {
  166. _sheet=sheet;
  167. }
  168. KSpread::Sheet* Point::sheet() const
  169. {
  170. return _sheet;
  171. }
  172. void Point::setSheetName(TQString name)
  173. {
  174. _sheetName=name;
  175. }
  176. TQString Point::sheetName() const
  177. {
  178. return _sheetName;
  179. }
  180. void Point::setColumnFixed(bool colFixed)
  181. {
  182. _columnFixed=colFixed;
  183. }
  184. bool Point::columnFixed() const
  185. {
  186. return _columnFixed;
  187. }
  188. void Point::setRowFixed(bool rowFixed)
  189. {
  190. _rowFixed=rowFixed;
  191. }
  192. bool Point::rowFixed() const
  193. {
  194. return _rowFixed;
  195. }
  196. void Point::init(const TQString & _str)
  197. {
  198. _columnFixed=false;
  199. _rowFixed=false;
  200. // kdDebug(36001) <<"Point::init ("<<_str<<")"<<endl;
  201. _pos.setX(-1);
  202. uint len = _str.length();
  203. if ( !len )
  204. {
  205. kdDebug(36001) << "Point::init: len = 0" << endl;
  206. return;
  207. }
  208. TQString str( _str );
  209. int n = _str.find( '!' );
  210. if ( n != -1 )
  211. {
  212. _sheetName = _str.left( n );
  213. str = _str.right( len - n - 1 ); // remove the '!'
  214. len = str.length();
  215. }
  216. uint p = 0;
  217. // Fixed ?
  218. if ( str[0] == '$' )
  219. {
  220. _columnFixed = true;
  221. p++;
  222. }
  223. else
  224. _columnFixed = false;
  225. // Malformed ?
  226. if ( p == len )
  227. {
  228. kdDebug(36001) << "Point::init: no point after '$' (str: '" << str.mid( p ) << "'" << endl;
  229. return;
  230. }
  231. if ( str[p] < 'A' || str[p] > 'Z' )
  232. {
  233. if ( str[p] < 'a' || str[p] > 'z' )
  234. {
  235. kdDebug(36001) << "Point::init: wrong first character in point (str: '" << str.mid( p ) << "'" << endl;
  236. return;
  237. }
  238. }
  239. //default is error
  240. int x = -1;
  241. //search for the first character != text
  242. int result = str.find( TQRegExp("[^A-Za-z]+"), p );
  243. //get the colomn number for the character between actual position and the first non text charakter
  244. if ( result != -1 )
  245. x = util_decodeColumnLabelText( str.mid( p, result - p ) ); // x is defined now
  246. else // If there isn't any, then this is not a point -> return
  247. {
  248. kdDebug(36001) << "Point::init: no number in string (str: '" << str.mid( p, result ) << "'" << endl;
  249. return;
  250. }
  251. p = result;
  252. //limit is KS_colMax
  253. if ( x > KS_colMax )
  254. {
  255. kdDebug(36001) << "Point::init: column value too high (col: " << x << ")" << endl;
  256. return;
  257. }
  258. // Malformed ?
  259. if (p == len)
  260. {
  261. kdDebug(36001) << "Point::init: p==len after cols" << endl;
  262. return;
  263. }
  264. if (str[p] == '$')
  265. {
  266. _rowFixed = true;
  267. p++;
  268. // Malformed ?
  269. if ( p == len )
  270. {
  271. kdDebug(36001) << "Point::init: p==len after $ of row" << endl;
  272. return;
  273. }
  274. }
  275. else
  276. _rowFixed = false;
  277. uint p2 = p;
  278. while ( p < len )
  279. {
  280. if ( !isdigit( TQChar(str[p++]) ) )
  281. {
  282. kdDebug(36001) << "Point::init: no number" << endl;
  283. return;
  284. }
  285. }
  286. bool ok;
  287. int y = str.mid( p2, p-p2 ).toInt( &ok );
  288. if ( !ok )
  289. {
  290. kdDebug(36001) << "Point::init: Invalid number (str: '" << str.mid( p2, p-p2 ) << "'" << endl;
  291. return;
  292. }
  293. if ( y > KS_rowMax )
  294. {
  295. kdDebug(36001) << "Point::init: row value too high (row: " << y << ")" << endl;
  296. return;
  297. }
  298. if ( y <= 0 )
  299. {
  300. kdDebug(36001) << "Point::init: y <= 0" << endl;
  301. return;
  302. }
  303. _pos = TQPoint( x, y );
  304. }
  305. bool util_isPointValid( TQPoint point )
  306. {
  307. if ( point.x() >= 1
  308. && point.y() >= 1
  309. && point.x() <= KS_colMax
  310. && point.y() <= KS_rowMax
  311. )
  312. return true;
  313. else
  314. return false;
  315. }
  316. bool util_isRectValid( TQRect rect )
  317. {
  318. if ( util_isPointValid( rect.topLeft() )
  319. && util_isPointValid( rect.bottomRight() )
  320. )
  321. return true;
  322. else
  323. return false;
  324. }
  325. Point::Point( const TQString & str, Map * map,
  326. Sheet * sheet )
  327. {
  328. uint p = 0;
  329. int p2 = str.find( '!' );
  330. if ( p2 != -1 )
  331. {
  332. _sheetName = str.left( p2++ );
  333. while ( true )
  334. {
  335. _sheet = map->findSheet( _sheetName );
  336. if ( !sheet && _sheetName[0] == ' ' )
  337. {
  338. _sheetName = _sheetName.right( _sheetName.length() - 1 );
  339. continue;
  340. }
  341. break;
  342. }
  343. p = p2;
  344. //If the loop didn't return a sheet, better keep a string for isValid
  345. if ( _sheetName.isEmpty() )
  346. {
  347. kdDebug(36001) << "Point: tableName is unknown" << endl;
  348. _sheetName = "unknown";
  349. }
  350. }
  351. else
  352. {
  353. if ( sheet != 0 )
  354. {
  355. _sheet = sheet;
  356. _sheetName = sheet->sheetName();
  357. }
  358. else
  359. _sheet = 0;
  360. }
  361. init( str.mid( p ) );
  362. }
  363. Cell *Point::cell() const
  364. {
  365. return _sheet->cellAt(_pos);
  366. }
  367. bool Point::operator== (const Point &cell) const
  368. {
  369. //sheet info ignored
  370. return (_pos == cell.pos());
  371. }
  372. bool Point::operator< (const Point &cell) const
  373. {
  374. //sheet info ignored
  375. return (pos().y() < cell.pos().y()) ? true :
  376. ((pos().y() == cell.pos().y()) && (pos().x() < cell.pos().x()));
  377. }
  378. bool Range::operator ==(const Range& otherRange) const
  379. {
  380. if ( _range == otherRange._range
  381. && _leftFixed == otherRange._leftFixed
  382. && _rightFixed == otherRange._rightFixed
  383. && _bottomFixed == otherRange._bottomFixed
  384. && _topFixed == otherRange._topFixed
  385. && _sheet == otherRange._sheet )
  386. return true;
  387. else
  388. return false;
  389. }
  390. Range::Range()
  391. {
  392. _sheet = 0;
  393. _range.setLeft( -1 );
  394. _leftFixed=false;
  395. _rightFixed=false;
  396. _topFixed=false;
  397. _bottomFixed=false;
  398. }
  399. Range::Range(const TQString & _str)
  400. {
  401. _range.setLeft(-1);
  402. _sheet = 0;
  403. int p = _str.find(':');
  404. // if (p == -1)
  405. // return;
  406. Point ul;
  407. Point lr; ;
  408. if ( p != -1)
  409. {
  410. ul = Point(_str.left(p));
  411. lr = Point(_str.mid(p + 1));
  412. }
  413. else
  414. {
  415. ul = Point(_str);
  416. lr = ul;
  417. }
  418. _range = TQRect(ul.pos(), lr.pos());
  419. _sheetName = ul.sheetName();
  420. _leftFixed = ul.columnFixed();
  421. _rightFixed = lr.columnFixed();
  422. _topFixed = ul.rowFixed();
  423. _bottomFixed = lr.rowFixed();
  424. }
  425. Range::Range( const Range& r )
  426. {
  427. _sheet = r.sheet();
  428. _sheetName = r.sheetName();
  429. _range = r.range();
  430. _namedArea = r.namedArea();
  431. _leftFixed=r._leftFixed;
  432. _rightFixed=r._rightFixed;
  433. _topFixed=r._topFixed;
  434. _bottomFixed=r._bottomFixed;
  435. }
  436. Range::Range( const Point& ul, const Point& lr )
  437. {
  438. _range = TQRect( ul.pos(), lr.pos() );
  439. if ( ul.sheetName() != lr.sheetName() )
  440. {
  441. _range.setLeft( -1 );
  442. return;
  443. }
  444. _sheetName = ul.sheetName();
  445. _sheet = ul.sheet();
  446. _leftFixed = ul.columnFixed();
  447. _rightFixed = lr.columnFixed();
  448. _topFixed = ul.rowFixed();
  449. _bottomFixed = lr.rowFixed();
  450. }
  451. Range::Range(const TQString & str, Map * map,
  452. Sheet * sheet)
  453. {
  454. _range.setLeft(-1);
  455. _sheet = 0;
  456. //try to parse as named area
  457. bool gotNamed = false;
  458. TQString tmp = str.lower();
  459. TQValueList < Reference >::Iterator it;
  460. TQValueList < Reference > area = map->doc()->listArea();
  461. for (it = area.begin(); it != area.end(); ++it) {
  462. if ((*it).ref_name.lower() == tmp) {
  463. // success - such named area exists
  464. _range = (*it).rect;
  465. _sheet = map->findSheet((*it).sheet_name);
  466. gotNamed = true;
  467. _namedArea = tmp;
  468. break;
  469. }
  470. }
  471. if (gotNamed) {
  472. // we have a named area - no need to proceed further
  473. _leftFixed = false;
  474. _rightFixed = false;
  475. _topFixed = false;
  476. _bottomFixed = false;
  477. return;
  478. }
  479. _range.setLeft(-1);
  480. _sheet = 0;
  481. int p = 0;
  482. int p2 = str.find('!');
  483. if (p2 != -1)
  484. {
  485. _sheetName = str.left(p2++);
  486. while ( true )
  487. {
  488. _sheet = map->findSheet(_sheetName);
  489. if ( !_sheet && _sheetName[0] == ' ' )
  490. {
  491. _sheetName = _sheetName.right( _sheetName.length() - 1 );
  492. continue;
  493. }
  494. break;
  495. }
  496. p = p2;
  497. } else
  498. _sheet = sheet;
  499. int p3 = str.find(':', p);
  500. if (p3 == -1)
  501. return;
  502. Point ul(str.mid(p, p3 - p));
  503. Point lr(str.mid(p3 + 1));
  504. _range = TQRect(ul.pos(), lr.pos());
  505. _leftFixed = ul.columnFixed();
  506. _rightFixed = lr.columnFixed();
  507. _topFixed = ul.rowFixed();
  508. _bottomFixed = lr.rowFixed();
  509. }
  510. TQString Range::toString() const
  511. {
  512. TQString result;
  513. if (_sheet)
  514. {
  515. result=util_rangeName(_sheet,_range);
  516. }
  517. else
  518. {
  519. result=util_rangeName(_range);
  520. }
  521. //Insert $ characters to show fixed parts of range
  522. int pos=result.find("!")+1;
  523. Q_ASSERT(pos != -1);
  524. if (_leftFixed)
  525. {
  526. result.insert(pos,'$');
  527. pos++; //Takes account of extra character added in
  528. }
  529. if (_topFixed)
  530. {
  531. result.insert(pos+Cell::columnName(_range.left()).length(),'$');
  532. }
  533. pos=result.find(":")+1;
  534. Q_ASSERT(pos != -1);
  535. if (_rightFixed)
  536. {
  537. result.insert(pos,'$');
  538. pos++; //Takes account of extra character added in
  539. }
  540. if (_bottomFixed)
  541. {
  542. result.insert(pos+Cell::columnName(_range.right()).length(),'$');
  543. }
  544. return result;
  545. }
  546. void Range::getStartPoint(Point* pt)
  547. {
  548. if (!isValid()) return;
  549. pt->setRow(startRow());
  550. pt->setColumn(startCol());
  551. pt->setColumnFixed(_leftFixed);
  552. pt->setRowFixed(_topFixed);
  553. pt->setSheet(_sheet);
  554. pt->setSheetName(_sheetName);
  555. }
  556. void Range::getEndPoint(Point* pt)
  557. {
  558. if (!isValid()) return;
  559. pt->setRow(endRow());
  560. pt->setColumn(endCol());
  561. pt->setColumnFixed(_rightFixed);
  562. pt->setRowFixed(_bottomFixed);
  563. pt->setSheet(_sheet);
  564. pt->setSheetName(_sheetName);
  565. }
  566. bool Range::contains (const Point &cell) const
  567. {
  568. return _range.contains (cell.pos());
  569. }
  570. bool Range::intersects (const Range &r) const
  571. {
  572. return _range.intersects (r.range());
  573. }
  574. bool Range::isValid() const
  575. {
  576. return ( _range.left() >= 0 ) &&
  577. ( _range.right() >= 0 ) &&
  578. ( _sheet != 0 || _sheetName.isEmpty() ) &&
  579. ( _range.isValid() ) ;
  580. }
  581. TQRect Range::range() const
  582. {
  583. return _range;
  584. }
  585. void Range::setLeftFixed(bool fixed)
  586. {
  587. _leftFixed=fixed;
  588. }
  589. bool Range::leftFixed() const
  590. {
  591. return _leftFixed;
  592. }
  593. void Range::setRightFixed(bool fixed)
  594. {
  595. _rightFixed=fixed;
  596. }
  597. bool Range::rightFixed() const
  598. {
  599. return _rightFixed;
  600. }
  601. void Range::setTopFixed(bool fixed)
  602. {
  603. _topFixed=fixed;
  604. }
  605. bool Range::topFixed() const
  606. {
  607. return _topFixed;
  608. }
  609. void Range::setBottomFixed(bool fixed)
  610. {
  611. _bottomFixed=fixed;
  612. }
  613. bool Range::bottomFixed() const
  614. {
  615. return _bottomFixed;
  616. }
  617. void Range::setSheet(Sheet* sheet)
  618. {
  619. _sheet=sheet;
  620. }
  621. KSpread::Sheet* Range::sheet() const
  622. {
  623. return _sheet;
  624. }
  625. void Range::setSheetName(TQString sheetName)
  626. {
  627. _sheetName=sheetName;
  628. }
  629. TQString Range::sheetName() const
  630. {
  631. return _sheetName;
  632. }
  633. TQString Range::namedArea() const
  634. {
  635. return _namedArea;
  636. }
  637. bool KSpread::util_isAllSelected(const TQRect &selection)
  638. {
  639. return ( selection.top() == 1 && selection.bottom() == KS_rowMax
  640. && selection.left() == 1 && selection.right() == KS_colMax);
  641. }
  642. bool KSpread::util_isColumnSelected(const TQRect &selection)
  643. {
  644. return ( (selection.top() == 1) && (selection.bottom() == KS_rowMax) );
  645. }
  646. bool KSpread::util_isRowSelected(const TQRect &selection)
  647. {
  648. return ( (selection.left() == 1) && (selection.right() == KS_colMax) );
  649. }
  650. bool KSpread::util_isRowOrColumnSelected(const TQRect &selection)
  651. {
  652. return ( (selection.left() == 1) && (selection.right() == KS_colMax)
  653. || (selection.top() == 1) && (selection.bottom() == KS_rowMax) );
  654. }
  655. //used in View::slotRename
  656. bool KSpread::util_validateSheetName(const TQString &name)
  657. {
  658. if (name[0] == ' ')
  659. {
  660. return false;
  661. }
  662. for (unsigned int i = 0; i < name.length(); i++)
  663. {
  664. if ( !(name[i].isLetterOrNumber() ||
  665. name[i] == ' ' || name[i] == '.' ||
  666. name[i] == '_'))
  667. {
  668. return false;
  669. }
  670. }
  671. return true;
  672. }
  673. RangeIterator::RangeIterator(TQRect _range, Sheet* _sheet)
  674. {
  675. range = _range;
  676. sheet = _sheet;
  677. current = TQPoint(0,0);
  678. }
  679. RangeIterator::~RangeIterator()
  680. {
  681. }
  682. Cell* RangeIterator::first()
  683. {
  684. current.setY(range.top());
  685. /* OK, because even if this equals zero, the 'getNextCellRight' won't
  686. try to access it*/
  687. current.setX(range.left() - 1);
  688. return next();
  689. }
  690. Cell* RangeIterator::next()
  691. {
  692. if (current.x() == 0 && current.y() == 0)
  693. {
  694. return first();
  695. }
  696. Cell* cell = NULL;
  697. bool done = false;
  698. while (cell == NULL && !done)
  699. {
  700. cell = sheet->getNextCellRight(current.x(), current.y());
  701. if (cell != NULL && cell->column() > range.right())
  702. {
  703. cell = NULL;
  704. }
  705. if (cell == NULL)
  706. {
  707. current.setX(range.left() - 1);
  708. current.setY(current.y() + 1);
  709. done = (current.y() > range.bottom());
  710. }
  711. }
  712. return cell;
  713. }
  714. //not used anywhere
  715. int KSpread::util_penCompare( TQPen const & pen1, TQPen const & pen2 )
  716. {
  717. if ( pen1.style() == TQt::NoPen && pen2.style() == TQt::NoPen )
  718. return 0;
  719. if ( pen1.style() == TQt::NoPen )
  720. return -1;
  721. if ( pen2.style() == TQt::NoPen )
  722. return 1;
  723. if ( pen1.width() < pen2.width() )
  724. return -1;
  725. if ( pen1.width() > pen2.width() )
  726. return 1;
  727. if ( pen1.style() < pen2.style() )
  728. return -1;
  729. if ( pen1.style() > pen2.style() )
  730. return 1;
  731. if ( pen1.color().name() < pen2.color().name() )
  732. return -1;
  733. if ( pen1.color().name() > pen2.color().name() )
  734. return 1;
  735. return 0;
  736. }
  737. TQString KSpread::convertRefToBase( const TQString & sheet, const TQRect & rect )
  738. {
  739. TQPoint bottomRight( rect.bottomRight() );
  740. TQString s( "$" );
  741. s += sheet;
  742. s += ".$";
  743. s += Cell::columnName( bottomRight.x() );
  744. s += '$';
  745. s += TQString::number( bottomRight.y() );
  746. return s;
  747. }
  748. TQString KSpread::convertRefToRange( const TQString & sheet, const TQRect & rect )
  749. {
  750. TQPoint topLeft( rect.topLeft() );
  751. TQPoint bottomRight( rect.bottomRight() );
  752. if ( topLeft == bottomRight )
  753. return convertRefToBase( sheet, rect );
  754. TQString s( "$" );
  755. s += sheet;
  756. s += ".$";
  757. s += /*util_encodeColumnLabelText*/Cell::columnName( topLeft.x() );
  758. s += '$';
  759. s += TQString::number( topLeft.y() );
  760. s += ":.$";
  761. s += /*util_encodeColumnLabelText*/Cell::columnName( bottomRight.x() );
  762. s += '$';
  763. s += TQString::number( bottomRight.y() );
  764. return s;
  765. }
  766. //used in Cell::convertFormulaToOasisFormat
  767. void KSpread::insertBracket( TQString & s )
  768. {
  769. TQChar c;
  770. int i = (int) s.length() - 1;
  771. while ( i >= 0 )
  772. {
  773. c = s[i];
  774. if ( c == ' ' )
  775. s[i] = '_';
  776. if ( !(c.isLetterOrNumber() || c == ' ' || c == '.'
  777. || c == '_') )
  778. {
  779. s.insert( i + 1, '[' );
  780. return;
  781. }
  782. --i;
  783. }
  784. }
  785. // e.g.: Sheet4.A1:Sheet4.E28
  786. //used in Sheet::saveOasis
  787. TQString KSpread::convertRangeToRef( const TQString & sheetName, const TQRect & _area )
  788. {
  789. return sheetName + "." + Cell::name( _area.left(), _area.top() ) + ":" + sheetName + "."+ Cell::name( _area.right(), _area.bottom() );
  790. }
  791. TQString KSpread::convertOasisPenToString( const TQPen & pen )
  792. {
  793. // kdDebug()<<"convertOasisPenToString( const TQPen & pen ) :"<<pen<<endl;
  794. // NOTE Stefan: TQPen api docs:
  795. // For horizontal and vertical lines a line width of 0 is
  796. // the same as a line width of 1.
  797. // A line width of 0 will produce a 1 pixel wide line using
  798. // a fast algorithm for diagonals. A line width of 1 will
  799. // also produce a 1 pixel wide line, but uses a slower more
  800. // accurate algorithm for diagonals.
  801. TQString s = TQString( "%1pt " ).arg( (pen.width() == 0) ? 1 : pen.width() );
  802. switch( pen.style() )
  803. {
  804. case TQt::NoPen:
  805. return "none";
  806. case TQt::SolidLine:
  807. s+="solid";
  808. break;
  809. case TQt::DashLine:
  810. s+="dashed";
  811. break;
  812. case TQt::DotLine:
  813. s+="dotted";
  814. break;
  815. case TQt::DashDotLine:
  816. s+="dot-dash";
  817. break;
  818. case TQt::DashDotDotLine:
  819. s+="dot-dot-dash";
  820. break;
  821. default: break;
  822. }
  823. kdDebug()<<" convertOasisPenToString :"<<s<<endl;
  824. if ( pen.color().isValid() )
  825. {
  826. s+=' ';
  827. s+=Style::colorName(pen.color());
  828. }
  829. return s;
  830. }
  831. TQPen KSpread::convertOasisStringToPen( const TQString &border )
  832. {
  833. TQPen pen;
  834. //string like "0.088cm solid #800000"
  835. if (border.isEmpty() || border=="none" || border=="hidden") // in fact no border
  836. {
  837. pen.setStyle( Qt::NoPen );
  838. return pen;
  839. }
  840. //code from koborder, for the moment kspread doesn't use koborder
  841. // ## isn't it faster to use TQStringList::split than parse it 3 times?
  842. TQString _width = border.section(' ', 0, 0);
  843. TQCString _style = border.section(' ', 1, 1).latin1();
  844. TQString _color = border.section(' ', 2, 2);
  845. pen.setWidth( ( int )( KoUnit::parseValue( _width, 1.0 ) ) );
  846. if ( _style =="none" )
  847. pen.setStyle( Qt::NoPen );
  848. else if ( _style =="solid" )
  849. pen.setStyle( Qt::SolidLine );
  850. else if ( _style =="dashed" )
  851. pen.setStyle( Qt::DashLine );
  852. else if ( _style =="dotted" )
  853. pen.setStyle( Qt::DotLine );
  854. else if ( _style =="dot-dash" )
  855. pen.setStyle( Qt::DashDotLine );
  856. else if ( _style =="dot-dot-dash" )
  857. pen.setStyle( Qt::DashDotDotLine );
  858. else
  859. kdDebug()<<" style undefined : "<<_style<<endl;
  860. if ( _color.isEmpty() )
  861. pen.setColor( TQColor() );
  862. else
  863. pen.setColor( TQColor( _color ) );
  864. return pen;
  865. }
  866. //Return true when it's a reference to cell from sheet.
  867. bool KSpread::localReferenceAnchor( const TQString &_ref )
  868. {
  869. bool isLocalRef = (_ref.find("http://") != 0 &&
  870. _ref.find("mailto:") != 0 &&
  871. _ref.find("ftp://") != 0 &&
  872. _ref.find("file:") != 0 );
  873. return isLocalRef;
  874. }
  875. TQString KSpread::Oasis::decodeFormula(const TQString& expr, const TDELocale* locale)
  876. {
  877. // parsing state
  878. enum { Start, InNumber, InString, InIdentifier, InReference, InSheetName } state;
  879. // use locale settings
  880. TQString decimal = locale ? locale->decimalSymbol() : ".";
  881. // initialize variables
  882. state = Start;
  883. unsigned int i = 0;
  884. const TQString ex = expr;
  885. TQString result;
  886. if (ex[0] == '=')
  887. {
  888. result="=";
  889. ++i;
  890. }
  891. // main loop
  892. while( i < ex.length() )
  893. {
  894. TQChar ch = ex[i];
  895. switch( state )
  896. {
  897. case Start:
  898. {
  899. // check for number
  900. if( ch.isDigit() )
  901. {
  902. state = InNumber;
  903. }
  904. // a string?
  905. else if ( ch == '"' )
  906. {
  907. state = InString;
  908. result.append( ex[i++] );
  909. }
  910. // beginning with alphanumeric ?
  911. // could be identifier, cell, range, or function...
  912. else if( isIdentifier( ch ) )
  913. {
  914. state = InIdentifier;
  915. }
  916. // [ marks sheet name for 3-d cell, e.g ['Sales Q3'.A4]
  917. else if ( ch.unicode() == '[' )
  918. {
  919. ++i;
  920. state = InReference;
  921. // NOTE Stefan: As long as KSpread does not support fixed sheets eat the dollar sign.
  922. if ( ex[i] == '$' ) ++i;
  923. }
  924. // decimal dot ?
  925. else if ( ch == '.' )
  926. {
  927. if ( ex[i+1].isDigit() )
  928. state = InNumber;
  929. else
  930. state = InReference;
  931. }
  932. // look for operator match
  933. else
  934. {
  935. int op;
  936. TQString s;
  937. // check for two-chars operator, such as '<=', '>=', etc
  938. s.append( ch ).append( ex[i+1] );
  939. op = matchOperator( s );
  940. // check for one-char operator, such as '+', ';', etc
  941. if( op == Token::InvalidOp )
  942. {
  943. s = TQString( ch );
  944. op = matchOperator( s );
  945. }
  946. // any matched operator ?
  947. if ( op == Token::Equal )
  948. {
  949. result.append( "==" );
  950. }
  951. else
  952. {
  953. result.append( s );
  954. }
  955. if( op != Token::InvalidOp )
  956. {
  957. int len = s.length();
  958. i += len;
  959. }
  960. else
  961. {
  962. ++i;
  963. state = Start;
  964. }
  965. }
  966. break;
  967. }
  968. case InReference:
  969. {
  970. // consume as long as alpha, dollar sign, underscore, or digit, or colon
  971. if( isIdentifier( ch ) || ch.isDigit() || ch == ':' )
  972. result.append( ex[i] );
  973. else if ( ch == '.' && i > 0 && ex[i-1] != '[' && ex[i-1] != ':' )
  974. result.append( '!' );
  975. else if( ch == ']' )
  976. state = Start;
  977. else if ( ch == '\'' )
  978. {
  979. result.append( ex[i] );
  980. state = InSheetName;
  981. // NOTE Stefan: As long as KSpread does not support fixed sheets eat the dollar sign.
  982. if ( ex[i] == '$' ) ++i;
  983. }
  984. else if ( ch != '.' )
  985. {
  986. state = Start;
  987. break;
  988. }
  989. ++i;
  990. break;
  991. }
  992. case InSheetName:
  993. {
  994. if ( ch == '\'' )
  995. state = InReference;
  996. result.append( ex[i] );
  997. ++i;
  998. break;
  999. }
  1000. case InNumber:
  1001. {
  1002. // consume as long as it's digit
  1003. if( ch.isDigit() )
  1004. result.append( ex[i++] );
  1005. // convert '.' to decimal separator
  1006. else if ( ch == '.' )
  1007. {
  1008. result.append( decimal );
  1009. ++i;
  1010. }
  1011. // exponent ?
  1012. else if( ch.upper() == 'E' )
  1013. {
  1014. result.append( 'E' );
  1015. ++i;
  1016. }
  1017. // we're done with integer number
  1018. else
  1019. state = Start;
  1020. break;
  1021. }
  1022. case InString:
  1023. {
  1024. // consume until "
  1025. if( ch != '"' )
  1026. {
  1027. result.append( ex[i++] );
  1028. }
  1029. // we're done
  1030. else
  1031. {
  1032. result.append( ch );
  1033. ++i;
  1034. state = Start;
  1035. }
  1036. break;
  1037. }
  1038. case InIdentifier:
  1039. {
  1040. // consume as long as alpha, dollar sign, underscore, or digit
  1041. if( isIdentifier( ch ) || ch.isDigit() )
  1042. result.append( ex[i++] );
  1043. // we're done
  1044. else
  1045. state = Start;
  1046. break;
  1047. }
  1048. default:
  1049. break;
  1050. }
  1051. }
  1052. return result;
  1053. }
  1054. /*TQString KSpread::Oasis::encodeFormula(const TQString& expr, const TDELocale* locale)
  1055. {
  1056. // TODO move Cell::convertFormulaToOasisFormat to this point
  1057. //expr = "not here yet";
  1058. //Q_UNUSED(locale);
  1059. kdDebug() << k_funcinfo << " not implemented"
  1060. tqFatal(0);
  1061. }*/