kspread Library API Documentation

kspread_condition.cc

00001 /* This file is part of the KDE project
00002    Copyright (C) 1998, 1999 Torben Weis <weis@kde.org>
00003    Copyright (C) 1999 - 2003 The KSpread Team
00004                              www.koffice.org/kspread
00005 
00006    This library is free software; you can redistribute it and/or
00007    modify it under the terms of the GNU Library General Public
00008    License as published by the Free Software Foundation; either
00009    version 2 of the License, or (at your option) any later version.
00010 
00011    This library is distributed in the hope that it will be useful,
00012    but WITHOUT ANY WARRANTY; without even the implied warranty of
00013    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014    Library General Public License for more details.
00015 
00016    You should have received a copy of the GNU Library General Public License
00017    along with this library; see the file COPYING.LIB.  If not, write to
00018    the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
00019    Boston, MA 02111-1307, USA.
00020 */
00021 
00022 #include <float.h>
00023 
00024 #include "kspread_cell.h"
00025 #include "kspread_condition.h"
00026 #include "kspread_sheet.h"
00027 #include "kspread_doc.h"
00028 #include "kspread_style.h"
00029 #include "kspread_style_manager.h"
00030 #include "kspread_util.h"
00031 
00032 #include <koGenStyles.h>
00033 
00034 #include <koxmlwriter.h>
00035 #include <koxmlns.h>
00036 #include <kdebug.h>
00037 #include <qdom.h>
00038 #include <qbuffer.h>
00039 
00040 KSpreadConditional::KSpreadConditional():
00041   val1( 0.0 ), val2( 0.0 ), strVal1( 0 ), strVal2( 0 ),
00042   colorcond( 0 ), fontcond( 0 ), styleName( 0 ),
00043   style( 0 ), cond( None )
00044 {
00045 }
00046 
00047 KSpreadConditional::~KSpreadConditional()
00048 {
00049   delete strVal1;
00050   delete strVal2;
00051   delete colorcond;
00052   delete fontcond;
00053   delete styleName;
00054 }
00055 
00056 KSpreadConditional::KSpreadConditional( const KSpreadConditional& c )
00057 {
00058   operator=( c );
00059 }
00060 
00061 KSpreadConditional& KSpreadConditional::operator=( const KSpreadConditional& d )
00062 {
00063   strVal1 = d.strVal1 ? new QString( *d.strVal1 ) : 0;
00064   strVal2 = d.strVal2 ? new QString( *d.strVal2 ) : 0;
00065   styleName = d.styleName ? new QString( *d.styleName ) : 0;
00066   fontcond = d.fontcond ? new QFont( *d.fontcond ) : 0;
00067   colorcond = d.colorcond ? new QColor( *d.colorcond ) : 0;
00068   val1  = d.val1;
00069   val2  = d.val2;
00070   style = d.style;
00071   cond  = d.cond;
00072 
00073   return *this;
00074 }
00075 
00076 
00077 KSpreadConditions::KSpreadConditions( const KSpreadCell * ownerCell )
00078   : m_cell( ownerCell ), m_matchedStyle( 0 )
00079 {
00080   Q_ASSERT( ownerCell != NULL );
00081 }
00082 
00083 KSpreadConditions::~KSpreadConditions()
00084 {
00085   m_condList.clear();
00086 }
00087 
00088 void KSpreadConditions::checkMatches()
00089 {
00090   KSpreadConditional condition;
00091 
00092   if ( currentCondition( condition ) )
00093     m_matchedStyle = condition.style;
00094   else
00095     m_matchedStyle = 0;
00096 }
00097 
00098 bool KSpreadConditions::currentCondition( KSpreadConditional & condition )
00099 {
00100   /* for now, the first condition that is true is the one that will be used */
00101 
00102   QValueList<KSpreadConditional>::const_iterator it;
00103   double value   = m_cell->value().asFloat();
00104   QString strVal = m_cell->text();
00105 
00106   //  if ( m_cell->value().isNumber() && !m_cell->sheet()->getShowFormula())
00107   //  {
00108 
00109   for ( it = m_condList.begin(); it != m_condList.end(); ++it )
00110   {
00111     condition = *it;
00112     kdDebug()<<"*it :"<< *( ( *it ).styleName )<<endl;
00113     kdDebug()<<"*it style :"<<(  *it ).style <<endl;
00114 
00115     if ( condition.strVal1 && m_cell->value().isNumber() )
00116       continue;
00117 
00118     switch ( condition.cond )
00119     {
00120      case Equal:
00121       if ( condition.strVal1 )
00122       {
00123         if ( strVal == *condition.strVal1 )
00124           return true;
00125       }
00126       else
00127       if ( value - condition.val1 < DBL_EPSILON &&
00128            value - condition.val1 > (0.0 - DBL_EPSILON) )
00129       {
00130         return true;
00131       }
00132       break;
00133 
00134      case Superior:
00135       if ( condition.strVal1 )
00136       {
00137         if ( strVal > *condition.strVal1 )
00138           return true;
00139       }
00140       else
00141       if ( value > condition.val1 )
00142       {
00143         return true;
00144       }
00145       break;
00146 
00147      case Inferior:
00148       if ( condition.strVal1 )
00149       {
00150         if ( strVal < *condition.strVal1 )
00151           return true;
00152       }
00153       else
00154       if ( value < condition.val1 )
00155       {
00156         return true;
00157       }
00158       break;
00159 
00160      case SuperiorEqual :
00161       if ( condition.strVal1 )
00162       {
00163         if ( strVal >= *condition.strVal1 )
00164           return true;
00165       }
00166       else
00167       if ( value >= condition.val1 )
00168       {
00169         return true;
00170       }
00171       break;
00172 
00173      case InferiorEqual :
00174       if ( condition.strVal1 )
00175       {
00176         if ( strVal <= *condition.strVal1 )
00177           return true;
00178       }
00179       else
00180       if ( value <= condition.val1 )
00181       {
00182         return true;
00183       }
00184       break;
00185 
00186      case Between :
00187       if ( condition.strVal1 && condition.strVal2 )
00188       {
00189         if ( strVal > *condition.strVal1 && strVal < *condition.strVal2 )
00190           return true;
00191       }
00192       else
00193       if ( ( value > QMIN(condition.val1, condition.val2 ) )
00194            && ( value < QMAX(condition.val1, condition.val2 ) ) )
00195       {
00196         return true;
00197       }
00198       break;
00199 
00200      case Different :
00201       if ( condition.strVal1 && condition.strVal2 )
00202       {
00203         if ( strVal < *condition.strVal1 || strVal > *condition.strVal2 )
00204           return true;
00205       }
00206       else
00207       if ( ( value < QMIN(condition.val1, condition.val2 ) )
00208            || ( value > QMAX(condition.val1, condition.val2) ) )
00209       {
00210         return true;
00211       }
00212       break;
00213      case DifferentTo :
00214       if ( condition.strVal1 )
00215       {
00216         if ( strVal != *condition.strVal1 )
00217           return true;
00218       }
00219       else
00220       if ( value != condition.val1 )
00221       {
00222         return true;
00223       }
00224       break;
00225 
00226      default:
00227       break;
00228     }
00229   }
00230   return false;
00231 }
00232 
00233 QValueList<KSpreadConditional> KSpreadConditions::conditionList() const
00234 {
00235   return m_condList;
00236 }
00237 
00238 void KSpreadConditions::setConditionList( const QValueList<KSpreadConditional> & list )
00239 {
00240   m_condList.clear();
00241 
00242   QValueList<KSpreadConditional>::const_iterator it;
00243   for ( it = list.begin(); it != list.end(); ++it )
00244   {
00245     KSpreadConditional d = *it;
00246     m_condList.append( KSpreadConditional( d ) );
00247   }
00248 }
00249 
00250 void KSpreadConditions::saveOasisConditions( KoGenStyle &currentCellStyle )
00251 {
00252     //todo fix me with kspread old format!!!
00253     if ( m_condList.isEmpty() )
00254         return;
00255     QValueList<KSpreadConditional>::const_iterator it;
00256     int i = 0;
00257     for ( it = m_condList.begin(); it != m_condList.end(); ++it, ++i )
00258     {
00259         KSpreadConditional condition = *it;
00260         //<style:map style:condition="cell-content()=45" style:apply-style-name="Default" style:base-cell-address="Sheet1.E10"/>
00261         QMap<QString, QString> map;
00262         map.insert( "style:condition", saveOasisConditionValue( condition ) );
00263         map.insert( "style:apply-style-name",  *( condition.styleName ) );
00264         //map.insert( ""style:base-cell-address", "..." );//todo
00265         currentCellStyle.addStyleMap( map );
00266     }
00267 }
00268 
00269 QString KSpreadConditions::saveOasisConditionValue( KSpreadConditional &condition)
00270 {
00271     //we can also compare text value.
00272     //todo adapt it.
00273     QString value;
00274     switch( condition.cond )
00275     {
00276     case None:
00277         break;
00278     case Equal:
00279         value="cell-content()=";
00280         if ( condition.strVal1 )
00281             value+=*condition.strVal1;
00282         else
00283             value+=QString::number( condition.val1 );
00284         break;
00285     case Superior:
00286         value="cell-content()>";
00287         if ( condition.strVal1 )
00288             value+=*condition.strVal1;
00289         else
00290             value+=QString::number( condition.val1 );
00291         break;
00292     case Inferior:
00293         value="cell-content()<";
00294         if ( condition.strVal1 )
00295             value+=*condition.strVal1;
00296         else
00297             value+=QString::number( condition.val1 );
00298         break;
00299     case SuperiorEqual:
00300         value="cell-content()>=";
00301         if ( condition.strVal1 )
00302             value+=*condition.strVal1;
00303         else
00304             value+=QString::number( condition.val1 );
00305         break;
00306     case InferiorEqual:
00307         value="cell-content()<=";
00308         if ( condition.strVal1 )
00309             value+=*condition.strVal1;
00310         else
00311             value+=QString::number( condition.val1 );
00312         break;
00313     case Between:
00314         value="cell-content-is-between(";
00315         if ( condition.strVal1 )
00316         {
00317             value+=*condition.strVal1;
00318             value+=",";
00319             if ( condition.strVal2 )
00320                 value+=*condition.strVal2;
00321         }
00322         else
00323         {
00324             value+=QString::number( condition.val1 );
00325             value+=",";
00326             value+=QString::number( condition.val2 );
00327         }
00328         value+=")";
00329         break;
00330     case DifferentTo:
00331         value="cell-content()!="; //FIXME not good here !
00332         if ( condition.strVal1 )
00333             value+=*condition.strVal1;
00334         else
00335             value+=QString::number( condition.val1 );
00336         break;
00337     case Different:
00338         value="cell-content-is-not-between(";
00339         if ( condition.strVal1 )
00340         {
00341             value+=*condition.strVal1;
00342             value+=",";
00343             if ( condition.strVal2 )
00344                 value+=*condition.strVal2;
00345         }
00346         else
00347         {
00348             value+=QString::number( condition.val1 );
00349             value+=",";
00350             value+=QString::number( condition.val2 );
00351         }
00352         value+=")";
00353         break;
00354     }
00355     return value;
00356 }
00357 
00358 
00359 QDomElement KSpreadConditions::saveConditions( QDomDocument & doc ) const
00360 {
00361   QDomElement conditions = doc.createElement("condition");
00362   QValueList<KSpreadConditional>::const_iterator it;
00363   QDomElement child;
00364   int num = 0;
00365   QString name;
00366 
00367   for ( it = m_condList.begin(); it != m_condList.end(); ++it )
00368   {
00369     KSpreadConditional condition = *it;
00370 
00371     /* the name of the element will be "condition<n>"
00372      * This is unimportant now but in older versions three conditions were
00373      * hardcoded with names "first" "second" and "third"
00374      */
00375     name.setNum( num );
00376     name.prepend( "condition" );
00377 
00378     child = doc.createElement( name );
00379     child.setAttribute( "cond", (int) condition.cond );
00380 
00381     // TODO: saving in KSpread 1.1 | KSpread 1.2 format
00382     if ( condition.strVal1 )
00383     {
00384       child.setAttribute( "strval1", *condition.strVal1 );
00385       if ( condition.strVal2 )
00386         child.setAttribute( "strval2", *condition.strVal2 );
00387     }
00388     else
00389     {
00390       child.setAttribute( "val1", condition.val1 );
00391       child.setAttribute( "val2", condition.val2 );
00392     }
00393     if ( condition.styleName )
00394     {
00395       child.setAttribute( "style", *condition.styleName );
00396     }
00397     else
00398     {
00399       child.setAttribute( "color", condition.colorcond->name() );
00400       child.appendChild( util_createElement( "font", *condition.fontcond, doc ) );
00401     }
00402 
00403     conditions.appendChild( child );
00404 
00405     ++num;
00406   }
00407 
00408   if ( num == 0 )
00409   {
00410     /* there weren't any real conditions -- return a null dom element */
00411     return QDomElement();
00412   }
00413   else
00414   {
00415     return conditions;
00416   }
00417 }
00418 
00419 void KSpreadConditions::loadOasisConditions( const QDomElement & element )
00420 {
00421     kdDebug()<<"void KSpreadConditions::loadOasisConditions( const QDomElement & element )\n";
00422     QDomElement elementItem( element );
00423     KSpreadStyleManager * manager = m_cell->sheet()->doc()->styleManager();
00424 
00425     while ( !elementItem.isNull() )
00426     {
00427         kdDebug()<<"elementItem.tagName() :"<<elementItem.tagName()<<endl;
00428         if ( elementItem.tagName()== "map" && elementItem.namespaceURI() == KoXmlNS::style  )
00429         {
00430             bool ok = true;
00431             kdDebug()<<"elementItem.attribute(style:condition ) :"<<elementItem.attributeNS( KoXmlNS::style, "condition", QString::null )<<endl;
00432             KSpreadConditional newCondition;
00433             loadOasisConditionValue( elementItem.attributeNS( KoXmlNS::style, "condition", QString::null ), newCondition );
00434             if ( elementItem.hasAttributeNS( KoXmlNS::style, "apply-style-name" ) )
00435             {
00436                 kdDebug()<<"elementItem.attribute( style:apply-style-name ) :"<<elementItem.attributeNS( KoXmlNS::style, "apply-style-name", QString::null )<<endl;
00437                 newCondition.styleName = new QString( elementItem.attributeNS( KoXmlNS::style, "apply-style-name", QString::null ) );
00438                 newCondition.style = manager->style( *newCondition.styleName );
00439                 if ( !newCondition.style )
00440                     ok = false;
00441                 else
00442                     ok = true;
00443             }
00444 
00445             if ( ok )
00446                 m_condList.append( newCondition );
00447             else
00448                 kdDebug(36001) << "Error loading condition " << elementItem.nodeName()<< endl;
00449         }
00450         elementItem = elementItem.nextSibling().toElement();
00451     }
00452 }
00453 
00454 void KSpreadConditions::loadOasisConditionValue( const QString &styleCondition, KSpreadConditional &newCondition )
00455 {
00456     QString val( styleCondition );
00457     if ( val.contains( "cell-content()" ) )
00458     {
00459         val = val.remove( "cell-content()" );
00460         loadOasisCondition( val,newCondition );
00461     }
00462     //GetFunction ::= cell-content-is-between(Value, Value) | cell-content-is-not-between(Value, Value)
00463     //for the moment we support just int/double value, not text/date/time :(
00464     if ( val.contains( "cell-content-is-between(" ) )
00465     {
00466         val = val.remove( "cell-content-is-between(" );
00467         val = val.remove( ")" );
00468         QStringList listVal = QStringList::split( "," , val );
00469         loadOasisValidationValue( listVal, newCondition );
00470         newCondition.cond = Between;
00471     }
00472     if ( val.contains( "cell-content-is-not-between(" ) )
00473     {
00474         val = val.remove( "cell-content-is-not-between(" );
00475         val = val.remove( ")" );
00476         QStringList listVal = QStringList::split( ",", val );
00477         loadOasisValidationValue( listVal,newCondition );
00478         newCondition.cond = Different;
00479     }
00480 
00481 }
00482 
00483 
00484 void KSpreadConditions::loadOasisCondition( QString &valExpression, KSpreadConditional &newCondition )
00485 {
00486     QString value;
00487     if (valExpression.find( "<=" )==0 )
00488     {
00489         value = valExpression.remove( 0,2 );
00490         newCondition.cond = InferiorEqual;
00491     }
00492     else if (valExpression.find( ">=" )==0 )
00493     {
00494         value = valExpression.remove( 0,2 );
00495         newCondition.cond = SuperiorEqual;
00496     }
00497     else if (valExpression.find( "!=" )==0 )
00498     {
00499         //add Differentto attribute
00500         value = valExpression.remove( 0,2 );
00501         newCondition.cond = DifferentTo;
00502     }
00503     else if ( valExpression.find( "<" )==0 )
00504     {
00505         value = valExpression.remove( 0,1 );
00506         newCondition.cond = Inferior;
00507     }
00508     else if(valExpression.find( ">" )==0 )
00509     {
00510         value = valExpression.remove( 0,1 );
00511         newCondition.cond = Superior;
00512     }
00513     else if (valExpression.find( "=" )==0 )
00514     {
00515         value = valExpression.remove( 0,1 );
00516         newCondition.cond = Equal;
00517     }
00518     else
00519         kdDebug()<<" I don't know how to parse it :"<<valExpression<<endl;
00520     kdDebug()<<" value :"<<value<<endl;
00521     bool ok = false;
00522     newCondition.val1 = value.toDouble(&ok);
00523     if ( !ok )
00524     {
00525         newCondition.val1 = value.toInt(&ok);
00526         if ( !ok )
00527         {
00528             newCondition.strVal1 = new QString( value );
00529             kdDebug()<<" Try to parse this value :"<<value<<endl;
00530         }
00531 
00532     }
00533 }
00534 
00535 
00536 void KSpreadConditions::loadOasisValidationValue( const QStringList &listVal, KSpreadConditional &newCondition )
00537 {
00538     bool ok = false;
00539     kdDebug()<<" listVal[0] :"<<listVal[0]<<" listVal[1] :"<<listVal[1]<<endl;
00540 
00541     newCondition.val1 = listVal[0].toDouble(&ok);
00542     if ( !ok )
00543     {
00544         newCondition.val1 = listVal[0].toInt(&ok);
00545         if ( !ok )
00546         {
00547             newCondition.strVal1 = new QString( listVal[0] );
00548             kdDebug()<<" Try to parse this value :"<<listVal[0]<<endl;
00549         }
00550     }
00551     ok=false;
00552     newCondition.val2 = listVal[1].toDouble(&ok);
00553     if ( !ok )
00554     {
00555         newCondition.val2 = listVal[1].toInt(&ok);
00556         if ( !ok )
00557         {
00558             newCondition.strVal2 = new QString( listVal[1] );
00559             kdDebug()<<" Try to parse this value :"<<listVal[1]<<endl;
00560         }
00561     }
00562 }
00563 
00564 
00565 void KSpreadConditions::loadConditions( const QDomElement & element )
00566 {
00567   QDomNodeList nodeList = element.childNodes();
00568   KSpreadConditional newCondition;
00569   bool ok;
00570   KSpreadStyleManager * manager = m_cell->sheet()->doc()->styleManager();
00571 
00572   for ( int i = 0; i < (int)(nodeList.length()); ++i )
00573   {
00574     newCondition.strVal1   = 0;
00575     newCondition.strVal2   = 0;
00576     newCondition.styleName = 0;
00577     newCondition.fontcond  = 0;
00578     newCondition.colorcond = 0;
00579 
00580     QDomElement conditionElement = nodeList.item( i ).toElement();
00581 
00582     ok = conditionElement.hasAttribute( "cond" );
00583 
00584     if ( ok )
00585       newCondition.cond = (Conditional) conditionElement.attribute( "cond" ).toInt( &ok );
00586     else continue;
00587 
00588     if ( conditionElement.hasAttribute( "val1" ) )
00589     {
00590       newCondition.val1 = conditionElement.attribute( "val1" ).toDouble( &ok );
00591 
00592       if ( conditionElement.hasAttribute( "val2" ) )
00593         newCondition.val2 = conditionElement.attribute("val2").toDouble( &ok );
00594     }
00595 
00596     if ( conditionElement.hasAttribute( "strval1" ) )
00597     {
00598       newCondition.strVal1 = new QString( conditionElement.attribute( "strval1" ) );
00599 
00600       if ( conditionElement.hasAttribute( "strval2" ) )
00601         newCondition.strVal2 = new QString( conditionElement.attribute( "strval2" ) );
00602     }
00603 
00604     if ( conditionElement.hasAttribute( "color" ) )
00605       newCondition.colorcond = new QColor( conditionElement.attribute( "color" ) );
00606 
00607     QDomElement font = conditionElement.namedItem( "font" ).toElement();
00608     if ( !font.isNull() )
00609       newCondition.fontcond = new QFont( util_toFont( font ) );
00610 
00611     if ( conditionElement.hasAttribute( "style" ) )
00612     {
00613       newCondition.styleName = new QString( conditionElement.attribute( "style" ) );
00614       newCondition.style = manager->style( *newCondition.styleName );
00615       if ( !newCondition.style )
00616         ok = false;
00617     }
00618 
00619     if ( ok )
00620     {
00621       m_condList.append( newCondition );
00622     }
00623     else
00624     {
00625       kdDebug(36001) << "Error loading condition " << conditionElement.nodeName()<< endl;
00626     }
00627   }
00628 }
KDE Logo
This file is part of the documentation for kspread Library Version 1.4.2.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Mon Feb 13 09:42:54 2006 by doxygen 1.4.2 written by Dimitri van Heesch, © 1997-2003