00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include <float.h>
00023
00024 #include "kspread_cell.h"
00025 #include "kspread_sheet.h"
00026 #include "kspread_doc.h"
00027 #include "kspread_style.h"
00028 #include "kspread_style_manager.h"
00029 #include "kspread_util.h"
00030
00031 #include <KoGenStyles.h>
00032
00033 #include <KoXmlWriter.h>
00034 #include <KoXmlNS.h>
00035 #include <kdebug.h>
00036 #include <qdom.h>
00037 #include <qbuffer.h>
00038
00039 #include "kspread_condition.h"
00040
00041 using namespace KSpread;
00042
00043 Conditional::Conditional():
00044 val1( 0.0 ), val2( 0.0 ), strVal1( 0 ), strVal2( 0 ),
00045 colorcond( 0 ), fontcond( 0 ), styleName( 0 ),
00046 style( 0 ), cond( None )
00047 {
00048 }
00049
00050 Conditional::~Conditional()
00051 {
00052 delete strVal1;
00053 delete strVal2;
00054 delete colorcond;
00055 delete fontcond;
00056 delete styleName;
00057 }
00058
00059 Conditional::Conditional( const Conditional& c )
00060 {
00061 operator=( c );
00062 }
00063
00064 Conditional& Conditional::operator=( const Conditional& d )
00065 {
00066 strVal1 = d.strVal1 ? new QString( *d.strVal1 ) : 0;
00067 strVal2 = d.strVal2 ? new QString( *d.strVal2 ) : 0;
00068 styleName = d.styleName ? new QString( *d.styleName ) : 0;
00069 fontcond = d.fontcond ? new QFont( *d.fontcond ) : 0;
00070 colorcond = d.colorcond ? new QColor( *d.colorcond ) : 0;
00071 val1 = d.val1;
00072 val2 = d.val2;
00073 style = d.style;
00074 cond = d.cond;
00075
00076 return *this;
00077 }
00078
00079 bool Conditional::operator==(const Conditional& other) const
00080 {
00081 if ( cond == other.cond &&
00082 val1 == other.val1 &&
00083 val2 == other.val2 &&
00084 *strVal1 == *other.strVal1 &&
00085 *strVal2 == *other.strVal2 &&
00086 *colorcond == *other.colorcond &&
00087 *fontcond == *other.fontcond &&
00088 *styleName == *other.styleName &&
00089 *style == *other.style )
00090 {
00091 return true;
00092 }
00093 return false;
00094 }
00095
00096 Conditions::Conditions( const Cell * ownerCell )
00097 : m_cell( ownerCell ), m_matchedStyle( 0 )
00098 {
00099 Q_ASSERT( ownerCell != NULL );
00100 }
00101
00102 Conditions::~Conditions()
00103 {
00104 m_condList.clear();
00105 }
00106
00107 void Conditions::checkMatches()
00108 {
00109 Conditional condition;
00110
00111 if ( currentCondition( condition ) )
00112 m_matchedStyle = condition.style;
00113 else
00114 m_matchedStyle = 0;
00115 }
00116
00117 bool Conditions::currentCondition( Conditional & condition )
00118 {
00119
00120
00121 QValueList<Conditional>::const_iterator it;
00122 double value = m_cell->value().asFloat();
00123 QString strVal = m_cell->value().asString();
00124
00125
00126 for ( it = m_condList.begin(); it != m_condList.end(); ++it )
00127 {
00128 condition = *it;
00129
00130
00131
00132
00133
00134
00135
00136 if ( condition.strVal1 && m_cell->value().isNumber() )
00137 continue;
00138
00139 switch ( condition.cond )
00140 {
00141 case Conditional::Equal:
00142 if ( condition.strVal1 )
00143 {
00144 if ( strVal == *condition.strVal1 )
00145 return true;
00146 }
00147 else
00148 if ( value - condition.val1 < DBL_EPSILON &&
00149 value - condition.val1 > (0.0 - DBL_EPSILON) )
00150 {
00151 return true;
00152 }
00153 break;
00154
00155 case Conditional::Superior:
00156 if ( condition.strVal1 )
00157 {
00158 if ( strVal > *condition.strVal1 )
00159 return true;
00160 }
00161 else
00162 if ( value > condition.val1 )
00163 {
00164 return true;
00165 }
00166 break;
00167
00168 case Conditional::Inferior:
00169 if ( condition.strVal1 )
00170 {
00171 if ( strVal < *condition.strVal1 )
00172 return true;
00173 }
00174 else
00175 if ( value < condition.val1 )
00176 {
00177 return true;
00178 }
00179 break;
00180
00181 case Conditional::SuperiorEqual :
00182 if ( condition.strVal1 )
00183 {
00184 if ( strVal >= *condition.strVal1 )
00185 return true;
00186 }
00187 else
00188 if ( value >= condition.val1 )
00189 {
00190 return true;
00191 }
00192 break;
00193
00194 case Conditional::InferiorEqual :
00195 if ( condition.strVal1 )
00196 {
00197 if ( strVal <= *condition.strVal1 )
00198 return true;
00199 }
00200 else
00201 if ( value <= condition.val1 )
00202 {
00203 return true;
00204 }
00205 break;
00206
00207 case Conditional::Between :
00208 if ( condition.strVal1 && condition.strVal2 )
00209 {
00210 if ( strVal > *condition.strVal1 && strVal < *condition.strVal2 )
00211 return true;
00212 }
00213 else
00214 if ( ( value > QMIN(condition.val1, condition.val2 ) )
00215 && ( value < QMAX(condition.val1, condition.val2 ) ) )
00216 {
00217 return true;
00218 }
00219 break;
00220
00221 case Conditional::Different :
00222 if ( condition.strVal1 && condition.strVal2 )
00223 {
00224 if ( strVal < *condition.strVal1 || strVal > *condition.strVal2 )
00225 return true;
00226 }
00227 else
00228 if ( ( value < QMIN(condition.val1, condition.val2 ) )
00229 || ( value > QMAX(condition.val1, condition.val2) ) )
00230 {
00231 return true;
00232 }
00233 break;
00234 case Conditional::DifferentTo :
00235 if ( condition.strVal1 )
00236 {
00237 if ( strVal != *condition.strVal1 )
00238 return true;
00239 }
00240 else
00241 if ( value != condition.val1 )
00242 {
00243 return true;
00244 }
00245 break;
00246
00247 default:
00248 break;
00249 }
00250 }
00251 return false;
00252 }
00253
00254 QValueList<Conditional> Conditions::conditionList() const
00255 {
00256 return m_condList;
00257 }
00258
00259 void Conditions::setConditionList( const QValueList<Conditional> & list )
00260 {
00261 m_condList.clear();
00262
00263 QValueList<Conditional>::const_iterator it;
00264 for ( it = list.begin(); it != list.end(); ++it )
00265 {
00266 Conditional d = *it;
00267 m_condList.append( Conditional( d ) );
00268 }
00269 }
00270
00271 void Conditions::saveOasisConditions( KoGenStyle ¤tCellStyle )
00272 {
00273
00274 if ( m_condList.isEmpty() )
00275 return;
00276 QValueList<Conditional>::const_iterator it;
00277 int i = 0;
00278 for ( it = m_condList.begin(); it != m_condList.end(); ++it, ++i )
00279 {
00280 Conditional condition = *it;
00281
00282 QMap<QString, QString> map;
00283 map.insert( "style:condition", saveOasisConditionValue( condition ) );
00284 map.insert( "style:apply-style-name", *( condition.styleName ) );
00285
00286 currentCellStyle.addStyleMap( map );
00287 }
00288 }
00289
00290 QString Conditions::saveOasisConditionValue( Conditional &condition)
00291 {
00292
00293
00294 QString value;
00295 switch( condition.cond )
00296 {
00297 case Conditional::None:
00298 break;
00299 case Conditional::Equal:
00300 value="cell-content()=";
00301 if ( condition.strVal1 )
00302 value+=*condition.strVal1;
00303 else
00304 value+=QString::number( condition.val1 );
00305 break;
00306 case Conditional::Superior:
00307 value="cell-content()>";
00308 if ( condition.strVal1 )
00309 value+=*condition.strVal1;
00310 else
00311 value+=QString::number( condition.val1 );
00312 break;
00313 case Conditional::Inferior:
00314 value="cell-content()<";
00315 if ( condition.strVal1 )
00316 value+=*condition.strVal1;
00317 else
00318 value+=QString::number( condition.val1 );
00319 break;
00320 case Conditional::SuperiorEqual:
00321 value="cell-content()>=";
00322 if ( condition.strVal1 )
00323 value+=*condition.strVal1;
00324 else
00325 value+=QString::number( condition.val1 );
00326 break;
00327 case Conditional::InferiorEqual:
00328 value="cell-content()<=";
00329 if ( condition.strVal1 )
00330 value+=*condition.strVal1;
00331 else
00332 value+=QString::number( condition.val1 );
00333 break;
00334 case Conditional::Between:
00335 value="cell-content-is-between(";
00336 if ( condition.strVal1 )
00337 {
00338 value+=*condition.strVal1;
00339 value+=",";
00340 if ( condition.strVal2 )
00341 value+=*condition.strVal2;
00342 }
00343 else
00344 {
00345 value+=QString::number( condition.val1 );
00346 value+=",";
00347 value+=QString::number( condition.val2 );
00348 }
00349 value+=")";
00350 break;
00351 case Conditional::DifferentTo:
00352 value="cell-content()!=";
00353 if ( condition.strVal1 )
00354 value+=*condition.strVal1;
00355 else
00356 value+=QString::number( condition.val1 );
00357 break;
00358 case Conditional::Different:
00359 value="cell-content-is-not-between(";
00360 if ( condition.strVal1 )
00361 {
00362 value+=*condition.strVal1;
00363 value+=",";
00364 if ( condition.strVal2 )
00365 value+=*condition.strVal2;
00366 }
00367 else
00368 {
00369 value+=QString::number( condition.val1 );
00370 value+=",";
00371 value+=QString::number( condition.val2 );
00372 }
00373 value+=")";
00374 break;
00375 }
00376 return value;
00377 }
00378
00379
00380 QDomElement Conditions::saveConditions( QDomDocument & doc ) const
00381 {
00382 QDomElement conditions = doc.createElement("condition");
00383 QValueList<Conditional>::const_iterator it;
00384 QDomElement child;
00385 int num = 0;
00386 QString name;
00387
00388 for ( it = m_condList.begin(); it != m_condList.end(); ++it )
00389 {
00390 Conditional condition = *it;
00391
00392
00393
00394
00395
00396 name.setNum( num );
00397 name.prepend( "condition" );
00398
00399 child = doc.createElement( name );
00400 child.setAttribute( "cond", (int) condition.cond );
00401
00402
00403 if ( condition.strVal1 )
00404 {
00405 child.setAttribute( "strval1", *condition.strVal1 );
00406 if ( condition.strVal2 )
00407 child.setAttribute( "strval2", *condition.strVal2 );
00408 }
00409 else
00410 {
00411 child.setAttribute( "val1", condition.val1 );
00412 child.setAttribute( "val2", condition.val2 );
00413 }
00414 if ( condition.styleName )
00415 {
00416 child.setAttribute( "style", *condition.styleName );
00417 }
00418 else
00419 {
00420 child.setAttribute( "color", condition.colorcond->name() );
00421 child.appendChild( util_createElement( "font", *condition.fontcond, doc ) );
00422 }
00423
00424 conditions.appendChild( child );
00425
00426 ++num;
00427 }
00428
00429 if ( num == 0 )
00430 {
00431
00432 return QDomElement();
00433 }
00434 else
00435 {
00436 return conditions;
00437 }
00438 }
00439
00440 void Conditions::loadOasisConditions( const QDomElement & element )
00441 {
00442 kdDebug(36003) << "Loading conditional styles" << endl;
00443 QDomNode node( element );
00444 StyleManager * manager = m_cell->sheet()->doc()->styleManager();
00445
00446 while ( !node.isNull() )
00447 {
00448 QDomElement elementItem = node.toElement();
00449 if ( elementItem.tagName()== "map" && elementItem.namespaceURI() == KoXmlNS::style )
00450 {
00451 bool ok = true;
00452 kdDebug(36003) << "\tcondition: "<< elementItem.attributeNS( KoXmlNS::style, "condition", QString::null )<<endl;
00453 Conditional newCondition;
00454 loadOasisConditionValue( elementItem.attributeNS( KoXmlNS::style, "condition", QString::null ), newCondition );
00455 if ( elementItem.hasAttributeNS( KoXmlNS::style, "apply-style-name" ) )
00456 {
00457 kdDebug(36003)<<"\tstyle: "<<elementItem.attributeNS( KoXmlNS::style, "apply-style-name", QString::null )<<endl;
00458 newCondition.styleName = new QString( elementItem.attributeNS( KoXmlNS::style, "apply-style-name", QString::null ) );
00459 newCondition.style = manager->style( *newCondition.styleName );
00460 if ( !newCondition.style )
00461 ok = false;
00462 else
00463 ok = true;
00464 }
00465
00466 if ( ok )
00467 m_condList.append( newCondition );
00468 else
00469 kdDebug(36003) << "Error loading condition " << elementItem.nodeName()<< endl;
00470 }
00471 node = node.nextSibling();
00472 }
00473 }
00474
00475 void Conditions::loadOasisConditionValue( const QString &styleCondition, Conditional &newCondition )
00476 {
00477 QString val( styleCondition );
00478 if ( val.contains( "cell-content()" ) )
00479 {
00480 val = val.remove( "cell-content()" );
00481 loadOasisCondition( val,newCondition );
00482 }
00483
00484
00485 if ( val.contains( "cell-content-is-between(" ) )
00486 {
00487 val = val.remove( "cell-content-is-between(" );
00488 val = val.remove( ")" );
00489 QStringList listVal = QStringList::split( "," , val );
00490 loadOasisValidationValue( listVal, newCondition );
00491 newCondition.cond = Conditional::Between;
00492 }
00493 if ( val.contains( "cell-content-is-not-between(" ) )
00494 {
00495 val = val.remove( "cell-content-is-not-between(" );
00496 val = val.remove( ")" );
00497 QStringList listVal = QStringList::split( ",", val );
00498 loadOasisValidationValue( listVal,newCondition );
00499 newCondition.cond = Conditional::Different;
00500 }
00501
00502 }
00503
00504
00505 void Conditions::loadOasisCondition( QString &valExpression, Conditional &newCondition )
00506 {
00507 QString value;
00508 if (valExpression.find( "<=" )==0 )
00509 {
00510 value = valExpression.remove( 0,2 );
00511 newCondition.cond = Conditional::InferiorEqual;
00512 }
00513 else if (valExpression.find( ">=" )==0 )
00514 {
00515 value = valExpression.remove( 0,2 );
00516 newCondition.cond = Conditional::SuperiorEqual;
00517 }
00518 else if (valExpression.find( "!=" )==0 )
00519 {
00520
00521 value = valExpression.remove( 0,2 );
00522 newCondition.cond = Conditional::DifferentTo;
00523 }
00524 else if ( valExpression.find( "<" )==0 )
00525 {
00526 value = valExpression.remove( 0,1 );
00527 newCondition.cond = Conditional::Inferior;
00528 }
00529 else if(valExpression.find( ">" )==0 )
00530 {
00531 value = valExpression.remove( 0,1 );
00532 newCondition.cond = Conditional::Superior;
00533 }
00534 else if (valExpression.find( "=" )==0 )
00535 {
00536 value = valExpression.remove( 0,1 );
00537 newCondition.cond = Conditional::Equal;
00538 }
00539 else
00540 kdDebug()<<" I don't know how to parse it :"<<valExpression<<endl;
00541 kdDebug(36003) << "\tvalue: " << value << endl;
00542 bool ok = false;
00543 newCondition.val1 = value.toDouble(&ok);
00544 if ( !ok )
00545 {
00546 newCondition.val1 = value.toInt(&ok);
00547 if ( !ok )
00548 {
00549 newCondition.strVal1 = new QString( value );
00550 kdDebug()<<" Try to parse this value :"<<value<<endl;
00551 }
00552 }
00553 }
00554
00555
00556 void Conditions::loadOasisValidationValue( const QStringList &listVal, Conditional &newCondition )
00557 {
00558 bool ok = false;
00559 kdDebug()<<" listVal[0] :"<<listVal[0]<<" listVal[1] :"<<listVal[1]<<endl;
00560
00561 newCondition.val1 = listVal[0].toDouble(&ok);
00562 if ( !ok )
00563 {
00564 newCondition.val1 = listVal[0].toInt(&ok);
00565 if ( !ok )
00566 {
00567 newCondition.strVal1 = new QString( listVal[0] );
00568 kdDebug()<<" Try to parse this value :"<<listVal[0]<<endl;
00569 }
00570 }
00571 ok=false;
00572 newCondition.val2 = listVal[1].toDouble(&ok);
00573 if ( !ok )
00574 {
00575 newCondition.val2 = listVal[1].toInt(&ok);
00576 if ( !ok )
00577 {
00578 newCondition.strVal2 = new QString( listVal[1] );
00579 kdDebug()<<" Try to parse this value :"<<listVal[1]<<endl;
00580 }
00581 }
00582 }
00583
00584
00585 void Conditions::loadConditions( const QDomElement & element )
00586 {
00587 QDomNodeList nodeList = element.childNodes();
00588 Conditional newCondition;
00589 bool ok;
00590 StyleManager * manager = m_cell->sheet()->doc()->styleManager();
00591
00592 for ( int i = 0; i < (int)(nodeList.length()); ++i )
00593 {
00594 newCondition.strVal1 = 0;
00595 newCondition.strVal2 = 0;
00596 newCondition.styleName = 0;
00597 newCondition.fontcond = 0;
00598 newCondition.colorcond = 0;
00599
00600 QDomElement conditionElement = nodeList.item( i ).toElement();
00601
00602 ok = conditionElement.hasAttribute( "cond" );
00603
00604 if ( ok )
00605 newCondition.cond = (Conditional::Type) conditionElement.attribute( "cond" ).toInt( &ok );
00606 else continue;
00607
00608 if ( conditionElement.hasAttribute( "val1" ) )
00609 {
00610 newCondition.val1 = conditionElement.attribute( "val1" ).toDouble( &ok );
00611
00612 if ( conditionElement.hasAttribute( "val2" ) )
00613 newCondition.val2 = conditionElement.attribute("val2").toDouble( &ok );
00614 }
00615
00616 if ( conditionElement.hasAttribute( "strval1" ) )
00617 {
00618 newCondition.strVal1 = new QString( conditionElement.attribute( "strval1" ) );
00619
00620 if ( conditionElement.hasAttribute( "strval2" ) )
00621 newCondition.strVal2 = new QString( conditionElement.attribute( "strval2" ) );
00622 }
00623
00624 if ( conditionElement.hasAttribute( "color" ) )
00625 newCondition.colorcond = new QColor( conditionElement.attribute( "color" ) );
00626
00627 QDomElement font = conditionElement.namedItem( "font" ).toElement();
00628 if ( !font.isNull() )
00629 newCondition.fontcond = new QFont( util_toFont( font ) );
00630
00631 if ( conditionElement.hasAttribute( "style" ) )
00632 {
00633 newCondition.styleName = new QString( conditionElement.attribute( "style" ) );
00634 newCondition.style = manager->style( *newCondition.styleName );
00635 if ( !newCondition.style )
00636 ok = false;
00637 }
00638
00639 if ( ok )
00640 {
00641 m_condList.append( newCondition );
00642 }
00643 else
00644 {
00645 kdDebug(36001) << "Error loading condition " << conditionElement.nodeName()<< endl;
00646 }
00647 }
00648 }
00649
00650 bool Conditions::operator==( const Conditions& other ) const
00651 {
00652 if ( !( *m_matchedStyle == *other.m_matchedStyle ) )
00653 return false;
00654 if ( m_condList.count() != other.m_condList.count() )
00655 return false;
00656 QValueList<Conditional>::ConstIterator end( m_condList.end() );
00657 for ( QValueList<Conditional>::ConstIterator it( m_condList.begin() ); it != end; ++it )
00658 {
00659 bool found = false;
00660 QValueList<Conditional>::ConstIterator otherEnd( other.m_condList.end() );
00661 for ( QValueList<Conditional>::ConstIterator otherIt( other.m_condList.begin() ); otherIt != otherEnd; ++otherIt )
00662 {
00663 if ( (*it) == (*otherIt) )
00664 found = true;
00665 }
00666 if ( !found )
00667 return false;
00668 }
00669 return true;
00670 }