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.

671 lines
19KB

  1. /* This file is part of the KDE project
  2. Copyright 1998, 1999 Torben Weis <weis@kde.org>
  3. Copyright 1999- 2003 The KSpread Team
  4. www.koffice.org/kspread
  5. This library is free software; you can redistribute it and/or
  6. modify it under the terms of the GNU Library General Public
  7. License as published by the Free Software Foundation; either
  8. version 2 of the License, or (at your option) any later version.
  9. This library is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  12. Library General Public License for more details.
  13. You should have received a copy of the GNU Library General Public License
  14. along with this library; see the file COPYING.LIB. If not, write to
  15. the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
  16. * Boston, MA 02110-1301, USA.
  17. */
  18. #include <float.h>
  19. #include "kspread_cell.h"
  20. #include "kspread_sheet.h"
  21. #include "kspread_doc.h"
  22. #include "kspread_style.h"
  23. #include "kspread_style_manager.h"
  24. #include "kspread_util.h"
  25. #include <KoGenStyles.h>
  26. #include <KoXmlWriter.h>
  27. #include <KoXmlNS.h>
  28. #include <kdebug.h>
  29. #include <tqdom.h>
  30. #include <tqbuffer.h>
  31. #include "kspread_condition.h"
  32. using namespace KSpread;
  33. Conditional::Conditional():
  34. val1( 0.0 ), val2( 0.0 ), strVal1( 0 ), strVal2( 0 ),
  35. colorcond( 0 ), fontcond( 0 ), styleName( 0 ),
  36. style( 0 ), cond( None )
  37. {
  38. }
  39. Conditional::~Conditional()
  40. {
  41. delete strVal1;
  42. delete strVal2;
  43. delete colorcond;
  44. delete fontcond;
  45. delete styleName;
  46. }
  47. Conditional::Conditional( const Conditional& c )
  48. {
  49. operator=( c );
  50. }
  51. Conditional& Conditional::operator=( const Conditional& d )
  52. {
  53. strVal1 = d.strVal1 ? new TQString( *d.strVal1 ) : 0;
  54. strVal2 = d.strVal2 ? new TQString( *d.strVal2 ) : 0;
  55. styleName = d.styleName ? new TQString( *d.styleName ) : 0;
  56. fontcond = d.fontcond ? new TQFont( *d.fontcond ) : 0;
  57. colorcond = d.colorcond ? new TQColor( *d.colorcond ) : 0;
  58. val1 = d.val1;
  59. val2 = d.val2;
  60. style = d.style;
  61. cond = d.cond;
  62. return *this;
  63. }
  64. bool Conditional::operator==(const Conditional& other) const
  65. {
  66. if ( cond == other.cond &&
  67. val1 == other.val1 &&
  68. val2 == other.val2 &&
  69. *strVal1 == *other.strVal1 &&
  70. *strVal2 == *other.strVal2 &&
  71. *colorcond == *other.colorcond &&
  72. *fontcond == *other.fontcond &&
  73. *styleName == *other.styleName &&
  74. *style == *other.style )
  75. {
  76. return true;
  77. }
  78. return false;
  79. }
  80. Conditions::Conditions( const Cell * ownerCell )
  81. : m_cell( ownerCell ), m_matchedStyle( 0 )
  82. {
  83. Q_ASSERT( ownerCell != NULL );
  84. }
  85. Conditions::~Conditions()
  86. {
  87. m_condList.clear();
  88. }
  89. void Conditions::checkMatches()
  90. {
  91. Conditional condition;
  92. if ( currentCondition( condition ) )
  93. m_matchedStyle = condition.style;
  94. else
  95. m_matchedStyle = 0;
  96. }
  97. bool Conditions::currentCondition( Conditional & condition )
  98. {
  99. /* for now, the first condition that is true is the one that will be used */
  100. TQValueList<Conditional>::const_iterator it;
  101. double value = m_cell->value().asFloat();
  102. TQString strVal = m_cell->value().asString();
  103. for ( it = m_condList.begin(); it != m_condList.end(); ++it )
  104. {
  105. condition = *it;
  106. // if ( (*it).styleName )
  107. // kdDebug()<<"*it :"<< *( ( *it ).styleName ) <<endl;
  108. //
  109. // kdDebug()<<"*it style :"<<( *it ).style <<endl;
  110. if ( condition.strVal1 && m_cell->value().isNumber() )
  111. continue;
  112. switch ( condition.cond )
  113. {
  114. case Conditional::Equal:
  115. if ( condition.strVal1 )
  116. {
  117. if ( strVal == *condition.strVal1 )
  118. return true;
  119. }
  120. else
  121. if ( value - condition.val1 < DBL_EPSILON &&
  122. value - condition.val1 > (0.0 - DBL_EPSILON) )
  123. {
  124. return true;
  125. }
  126. break;
  127. case Conditional::Superior:
  128. if ( condition.strVal1 )
  129. {
  130. if ( strVal > *condition.strVal1 )
  131. return true;
  132. }
  133. else
  134. if ( value > condition.val1 )
  135. {
  136. return true;
  137. }
  138. break;
  139. case Conditional::Inferior:
  140. if ( condition.strVal1 )
  141. {
  142. if ( strVal < *condition.strVal1 )
  143. return true;
  144. }
  145. else
  146. if ( value < condition.val1 )
  147. {
  148. return true;
  149. }
  150. break;
  151. case Conditional::SuperiorEqual :
  152. if ( condition.strVal1 )
  153. {
  154. if ( strVal >= *condition.strVal1 )
  155. return true;
  156. }
  157. else
  158. if ( value >= condition.val1 )
  159. {
  160. return true;
  161. }
  162. break;
  163. case Conditional::InferiorEqual :
  164. if ( condition.strVal1 )
  165. {
  166. if ( strVal <= *condition.strVal1 )
  167. return true;
  168. }
  169. else
  170. if ( value <= condition.val1 )
  171. {
  172. return true;
  173. }
  174. break;
  175. case Conditional::Between :
  176. if ( condition.strVal1 && condition.strVal2 )
  177. {
  178. if ( strVal > *condition.strVal1 && strVal < *condition.strVal2 )
  179. return true;
  180. }
  181. else
  182. if ( ( value > TQMIN(condition.val1, condition.val2 ) )
  183. && ( value < TQMAX(condition.val1, condition.val2 ) ) )
  184. {
  185. return true;
  186. }
  187. break;
  188. case Conditional::Different :
  189. if ( condition.strVal1 && condition.strVal2 )
  190. {
  191. if ( strVal < *condition.strVal1 || strVal > *condition.strVal2 )
  192. return true;
  193. }
  194. else
  195. if ( ( value < TQMIN(condition.val1, condition.val2 ) )
  196. || ( value > TQMAX(condition.val1, condition.val2) ) )
  197. {
  198. return true;
  199. }
  200. break;
  201. case Conditional::DifferentTo :
  202. if ( condition.strVal1 )
  203. {
  204. if ( strVal != *condition.strVal1 )
  205. return true;
  206. }
  207. else
  208. if ( value != condition.val1 )
  209. {
  210. return true;
  211. }
  212. break;
  213. default:
  214. break;
  215. }
  216. }
  217. return false;
  218. }
  219. TQValueList<Conditional> Conditions::conditionList() const
  220. {
  221. return m_condList;
  222. }
  223. void Conditions::setConditionList( const TQValueList<Conditional> & list )
  224. {
  225. m_condList.clear();
  226. TQValueList<Conditional>::const_iterator it;
  227. for ( it = list.begin(); it != list.end(); ++it )
  228. {
  229. Conditional d = *it;
  230. m_condList.append( Conditional( d ) );
  231. }
  232. }
  233. void Conditions::saveOasisConditions( KoGenStyle &currentCellStyle )
  234. {
  235. //todo fix me with kspread old format!!!
  236. if ( m_condList.isEmpty() )
  237. return;
  238. TQValueList<Conditional>::const_iterator it;
  239. int i = 0;
  240. for ( it = m_condList.begin(); it != m_condList.end(); ++it, ++i )
  241. {
  242. Conditional condition = *it;
  243. //<style:map style:condition="cell-content()=45" style:apply-style-name="Default" style:base-cell-address="Sheet1.E10"/>
  244. TQMap<TQString, TQString> map;
  245. map.insert( "style:condition", saveOasisConditionValue( condition ) );
  246. map.insert( "style:apply-style-name", *( condition.styleName ) );
  247. //map.insert( ""style:base-cell-address", "..." );//todo
  248. currentCellStyle.addStyleMap( map );
  249. }
  250. }
  251. TQString Conditions::saveOasisConditionValue( Conditional &condition)
  252. {
  253. //we can also compare text value.
  254. //todo adapt it.
  255. TQString value;
  256. switch( condition.cond )
  257. {
  258. case Conditional::None:
  259. break;
  260. case Conditional::Equal:
  261. value="cell-content()=";
  262. if ( condition.strVal1 )
  263. value+=*condition.strVal1;
  264. else
  265. value+=TQString::number( condition.val1 );
  266. break;
  267. case Conditional::Superior:
  268. value="cell-content()>";
  269. if ( condition.strVal1 )
  270. value+=*condition.strVal1;
  271. else
  272. value+=TQString::number( condition.val1 );
  273. break;
  274. case Conditional::Inferior:
  275. value="cell-content()<";
  276. if ( condition.strVal1 )
  277. value+=*condition.strVal1;
  278. else
  279. value+=TQString::number( condition.val1 );
  280. break;
  281. case Conditional::SuperiorEqual:
  282. value="cell-content()>=";
  283. if ( condition.strVal1 )
  284. value+=*condition.strVal1;
  285. else
  286. value+=TQString::number( condition.val1 );
  287. break;
  288. case Conditional::InferiorEqual:
  289. value="cell-content()<=";
  290. if ( condition.strVal1 )
  291. value+=*condition.strVal1;
  292. else
  293. value+=TQString::number( condition.val1 );
  294. break;
  295. case Conditional::Between:
  296. value="cell-content-is-between(";
  297. if ( condition.strVal1 )
  298. {
  299. value+=*condition.strVal1;
  300. value+=",";
  301. if ( condition.strVal2 )
  302. value+=*condition.strVal2;
  303. }
  304. else
  305. {
  306. value+=TQString::number( condition.val1 );
  307. value+=",";
  308. value+=TQString::number( condition.val2 );
  309. }
  310. value+=")";
  311. break;
  312. case Conditional::DifferentTo:
  313. value="cell-content()!="; //FIXME not good here !
  314. if ( condition.strVal1 )
  315. value+=*condition.strVal1;
  316. else
  317. value+=TQString::number( condition.val1 );
  318. break;
  319. case Conditional::Different:
  320. value="cell-content-is-not-between(";
  321. if ( condition.strVal1 )
  322. {
  323. value+=*condition.strVal1;
  324. value+=",";
  325. if ( condition.strVal2 )
  326. value+=*condition.strVal2;
  327. }
  328. else
  329. {
  330. value+=TQString::number( condition.val1 );
  331. value+=",";
  332. value+=TQString::number( condition.val2 );
  333. }
  334. value+=")";
  335. break;
  336. }
  337. return value;
  338. }
  339. TQDomElement Conditions::saveConditions( TQDomDocument & doc ) const
  340. {
  341. TQDomElement conditions = doc.createElement("condition");
  342. TQValueList<Conditional>::const_iterator it;
  343. TQDomElement child;
  344. int num = 0;
  345. TQString name;
  346. for ( it = m_condList.begin(); it != m_condList.end(); ++it )
  347. {
  348. Conditional condition = *it;
  349. /* the name of the element will be "condition<n>"
  350. * This is unimportant now but in older versions three conditions were
  351. * hardcoded with names "first" "second" and "third"
  352. */
  353. name.setNum( num );
  354. name.prepend( "condition" );
  355. child = doc.createElement( name );
  356. child.setAttribute( "cond", (int) condition.cond );
  357. // TODO: saving in KSpread 1.1 | KSpread 1.2 format
  358. if ( condition.strVal1 )
  359. {
  360. child.setAttribute( "strval1", *condition.strVal1 );
  361. if ( condition.strVal2 )
  362. child.setAttribute( "strval2", *condition.strVal2 );
  363. }
  364. else
  365. {
  366. child.setAttribute( "val1", condition.val1 );
  367. child.setAttribute( "val2", condition.val2 );
  368. }
  369. if ( condition.styleName )
  370. {
  371. child.setAttribute( "style", *condition.styleName );
  372. }
  373. else
  374. {
  375. child.setAttribute( "color", condition.colorcond->name() );
  376. child.appendChild( util_createElement( "font", *condition.fontcond, doc ) );
  377. }
  378. conditions.appendChild( child );
  379. ++num;
  380. }
  381. if ( num == 0 )
  382. {
  383. /* there weren't any real conditions -- return a null dom element */
  384. return TQDomElement();
  385. }
  386. else
  387. {
  388. return conditions;
  389. }
  390. }
  391. void Conditions::loadOasisConditions( const TQDomElement & element )
  392. {
  393. kdDebug(36003) << "Loading conditional styles" << endl;
  394. TQDomNode node( element );
  395. StyleManager * manager = m_cell->sheet()->doc()->styleManager();
  396. while ( !node.isNull() )
  397. {
  398. TQDomElement elementItem = node.toElement();
  399. if ( elementItem.tagName()== "map" && elementItem.namespaceURI() == KoXmlNS::style )
  400. {
  401. bool ok = true;
  402. kdDebug(36003) << "\tcondition: "<< elementItem.attributeNS( KoXmlNS::style, "condition", TQString() )<<endl;
  403. Conditional newCondition;
  404. loadOasisConditionValue( elementItem.attributeNS( KoXmlNS::style, "condition", TQString() ), newCondition );
  405. if ( elementItem.hasAttributeNS( KoXmlNS::style, "apply-style-name" ) )
  406. {
  407. kdDebug(36003)<<"\tstyle: "<<elementItem.attributeNS( KoXmlNS::style, "apply-style-name", TQString() )<<endl;
  408. newCondition.styleName = new TQString( elementItem.attributeNS( KoXmlNS::style, "apply-style-name", TQString() ) );
  409. newCondition.style = manager->style( *newCondition.styleName );
  410. if ( !newCondition.style )
  411. ok = false;
  412. else
  413. ok = true;
  414. }
  415. if ( ok )
  416. m_condList.append( newCondition );
  417. else
  418. kdDebug(36003) << "Error loading condition " << elementItem.nodeName()<< endl;
  419. }
  420. node = node.nextSibling();
  421. }
  422. }
  423. void Conditions::loadOasisConditionValue( const TQString &styleCondition, Conditional &newCondition )
  424. {
  425. TQString val( styleCondition );
  426. if ( val.contains( "cell-content()" ) )
  427. {
  428. val = val.remove( "cell-content()" );
  429. loadOasisCondition( val,newCondition );
  430. }
  431. //GetFunction ::= cell-content-is-between(Value, Value) | cell-content-is-not-between(Value, Value)
  432. //for the moment we support just int/double value, not text/date/time :(
  433. if ( val.contains( "cell-content-is-between(" ) )
  434. {
  435. val = val.remove( "cell-content-is-between(" );
  436. val = val.remove( ")" );
  437. TQStringList listVal = TQStringList::split( "," , val );
  438. loadOasisValidationValue( listVal, newCondition );
  439. newCondition.cond = Conditional::Between;
  440. }
  441. if ( val.contains( "cell-content-is-not-between(" ) )
  442. {
  443. val = val.remove( "cell-content-is-not-between(" );
  444. val = val.remove( ")" );
  445. TQStringList listVal = TQStringList::split( ",", val );
  446. loadOasisValidationValue( listVal,newCondition );
  447. newCondition.cond = Conditional::Different;
  448. }
  449. }
  450. void Conditions::loadOasisCondition( TQString &valExpression, Conditional &newCondition )
  451. {
  452. TQString value;
  453. if (valExpression.find( "<=" )==0 )
  454. {
  455. value = valExpression.remove( 0,2 );
  456. newCondition.cond = Conditional::InferiorEqual;
  457. }
  458. else if (valExpression.find( ">=" )==0 )
  459. {
  460. value = valExpression.remove( 0,2 );
  461. newCondition.cond = Conditional::SuperiorEqual;
  462. }
  463. else if (valExpression.find( "!=" )==0 )
  464. {
  465. //add Differentto attribute
  466. value = valExpression.remove( 0,2 );
  467. newCondition.cond = Conditional::DifferentTo;
  468. }
  469. else if ( valExpression.find( "<" )==0 )
  470. {
  471. value = valExpression.remove( 0,1 );
  472. newCondition.cond = Conditional::Inferior;
  473. }
  474. else if(valExpression.find( ">" )==0 )
  475. {
  476. value = valExpression.remove( 0,1 );
  477. newCondition.cond = Conditional::Superior;
  478. }
  479. else if (valExpression.find( "=" )==0 )
  480. {
  481. value = valExpression.remove( 0,1 );
  482. newCondition.cond = Conditional::Equal;
  483. }
  484. else
  485. kdDebug()<<" I don't know how to parse it :"<<valExpression<<endl;
  486. kdDebug(36003) << "\tvalue: " << value << endl;
  487. bool ok = false;
  488. newCondition.val1 = value.toDouble(&ok);
  489. if ( !ok )
  490. {
  491. newCondition.val1 = value.toInt(&ok);
  492. if ( !ok )
  493. {
  494. newCondition.strVal1 = new TQString( value );
  495. kdDebug()<<" Try to parse this value :"<<value<<endl;
  496. }
  497. }
  498. }
  499. void Conditions::loadOasisValidationValue( const TQStringList &listVal, Conditional &newCondition )
  500. {
  501. bool ok = false;
  502. kdDebug()<<" listVal[0] :"<<listVal[0]<<" listVal[1] :"<<listVal[1]<<endl;
  503. newCondition.val1 = listVal[0].toDouble(&ok);
  504. if ( !ok )
  505. {
  506. newCondition.val1 = listVal[0].toInt(&ok);
  507. if ( !ok )
  508. {
  509. newCondition.strVal1 = new TQString( listVal[0] );
  510. kdDebug()<<" Try to parse this value :"<<listVal[0]<<endl;
  511. }
  512. }
  513. ok=false;
  514. newCondition.val2 = listVal[1].toDouble(&ok);
  515. if ( !ok )
  516. {
  517. newCondition.val2 = listVal[1].toInt(&ok);
  518. if ( !ok )
  519. {
  520. newCondition.strVal2 = new TQString( listVal[1] );
  521. kdDebug()<<" Try to parse this value :"<<listVal[1]<<endl;
  522. }
  523. }
  524. }
  525. void Conditions::loadConditions( const TQDomElement & element )
  526. {
  527. TQDomNodeList nodeList = element.childNodes();
  528. Conditional newCondition;
  529. bool ok;
  530. StyleManager * manager = m_cell->sheet()->doc()->styleManager();
  531. for ( int i = 0; i < (int)(nodeList.length()); ++i )
  532. {
  533. newCondition.strVal1 = 0;
  534. newCondition.strVal2 = 0;
  535. newCondition.styleName = 0;
  536. newCondition.fontcond = 0;
  537. newCondition.colorcond = 0;
  538. TQDomElement conditionElement = nodeList.item( i ).toElement();
  539. ok = conditionElement.hasAttribute( "cond" );
  540. if ( ok )
  541. newCondition.cond = (Conditional::Type) conditionElement.attribute( "cond" ).toInt( &ok );
  542. else continue;
  543. if ( conditionElement.hasAttribute( "val1" ) )
  544. {
  545. newCondition.val1 = conditionElement.attribute( "val1" ).toDouble( &ok );
  546. if ( conditionElement.hasAttribute( "val2" ) )
  547. newCondition.val2 = conditionElement.attribute("val2").toDouble( &ok );
  548. }
  549. if ( conditionElement.hasAttribute( "strval1" ) )
  550. {
  551. newCondition.strVal1 = new TQString( conditionElement.attribute( "strval1" ) );
  552. if ( conditionElement.hasAttribute( "strval2" ) )
  553. newCondition.strVal2 = new TQString( conditionElement.attribute( "strval2" ) );
  554. }
  555. if ( conditionElement.hasAttribute( "color" ) )
  556. newCondition.colorcond = new TQColor( conditionElement.attribute( "color" ) );
  557. TQDomElement font = conditionElement.namedItem( "font" ).toElement();
  558. if ( !font.isNull() )
  559. newCondition.fontcond = new TQFont( util_toFont( font ) );
  560. if ( conditionElement.hasAttribute( "style" ) )
  561. {
  562. newCondition.styleName = new TQString( conditionElement.attribute( "style" ) );
  563. newCondition.style = manager->style( *newCondition.styleName );
  564. if ( !newCondition.style )
  565. ok = false;
  566. }
  567. if ( ok )
  568. {
  569. m_condList.append( newCondition );
  570. }
  571. else
  572. {
  573. kdDebug(36001) << "Error loading condition " << conditionElement.nodeName()<< endl;
  574. }
  575. }
  576. }
  577. bool Conditions::operator==( const Conditions& other ) const
  578. {
  579. if ( !( *m_matchedStyle == *other.m_matchedStyle ) )
  580. return false;
  581. if ( m_condList.count() != other.m_condList.count() )
  582. return false;
  583. TQValueList<Conditional>::ConstIterator end( m_condList.end() );
  584. for ( TQValueList<Conditional>::ConstIterator it( m_condList.begin() ); it != end; ++it )
  585. {
  586. bool found = false;
  587. TQValueList<Conditional>::ConstIterator otherEnd( other.m_condList.end() );
  588. for ( TQValueList<Conditional>::ConstIterator otherIt( other.m_condList.begin() ); otherIt != otherEnd; ++otherIt )
  589. {
  590. if ( (*it) == (*otherIt) )
  591. found = true;
  592. }
  593. if ( !found )
  594. return false;
  595. }
  596. return true;
  597. }