kspread

kspread_autofill.cc

00001 /* This file is part of the KDE project
00002 
00003    Copyright 2005 Raphael Langerhorst <raphael.langerhorst@kdemail.net>
00004    Copyright 2002-2004 Ariya Hidayat <ariya@kde.org>
00005    Copyright 2002-2003 Norbert Andres <nandres@web.de>
00006    Copyright 2002 John Dailey <dailey@vt.edu>
00007    Copyright 2001-2002 Philipp Mueller <philipp.mueller@gmx.de>
00008    Copyright 2000-2002 Laurent Montel <montel@kde.org>
00009    Copyright 2000-2001 Werner Trobin <trobin@kde.org>
00010    Copyright 1999-2001 David Faure <faure@kde.org>
00011    Copyright 1998-2000 Torben Weis <weis@kde.org>
00012    Copyright 1998-1999 Stephan Kulow <coolo@kde.org>
00013    Copyright 1998 Reginald Stadlbauer <reggie@kde.org>
00014 
00015    This library is free software; you can redistribute it and/or
00016    modify it under the terms of the GNU Library General Public
00017    License as published by the Free Software Foundation; either
00018    version 2 of the License, or (at your option) any later version.
00019 
00020    This library is distributed in the hope that it will be useful,
00021    but WITHOUT ANY WARRANTY; without even the implied warranty of
00022    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00023    Library General Public License for more details.
00024 
00025    You should have received a copy of the GNU Library General Public License
00026    along with this library; see the file COPYING.LIB.  If not, write to
00027    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00028  * Boston, MA 02110-1301, USA.
00029 */
00030 
00031 #include <math.h>
00032 
00033 #include <qregexp.h>
00034 
00035 #include <kconfig.h>
00036 #include <kdebug.h>
00037 
00038 #include "kspread_doc.h"
00039 #include "kspread_locale.h"
00040 #include "kspread_sheet.h"
00041 #include "kspread_undo.h"
00042 #include "kspread_value.h"
00043 #include "valueconverter.h"
00044 #include "kspread_autofill.h"
00045 
00046 using namespace KSpread;
00047 
00048 QStringList *AutoFillSequenceItem::month = 0L;
00049 QStringList *AutoFillSequenceItem::shortMonth = 0L;
00050 QStringList *AutoFillSequenceItem::day = 0L;
00051 QStringList *AutoFillSequenceItem::shortDay = 0L;
00052 QStringList *AutoFillSequenceItem::other = 0L;
00053 /**********************************************************************************
00054  *
00055  * AutoFillDeltaSequence
00056  *
00057  **********************************************************************************/
00058 
00059 AutoFillDeltaSequence::AutoFillDeltaSequence( AutoFillSequence *_first, AutoFillSequence *_next )
00060   : m_ok(true),
00061     m_sequence(0L)
00062 {
00063   if ( _first->count() != _next->count() )
00064   {
00065     m_ok = false;
00066     return;
00067   }
00068 
00069   m_sequence = new QMemArray<double> ( _first->count() );
00070 
00071   AutoFillSequenceItem *item = _first->getFirst();
00072   AutoFillSequenceItem *item2 = _next->getFirst();
00073   int i = 0;
00074   // for( item = _first->getFirst(); item != 0L && item2 != 0L; item = _first->getNext() );
00075   for ( i = 0; i < _first->count(); i++ )
00076   {
00077     double d;
00078     if ( !item->getDelta( item2, d ) )
00079       {
00080         m_ok = false;
00081         return;
00082       }
00083     m_sequence->at( i++ ) = d;
00084     item2 = _next->getNext();
00085     item = _first->getNext();
00086   }
00087 }
00088 
00089 AutoFillDeltaSequence::~AutoFillDeltaSequence()
00090 {
00091     delete m_sequence;
00092 }
00093 
00094 bool AutoFillDeltaSequence::equals( AutoFillDeltaSequence *_delta )
00095 {
00096   if ( m_sequence == 0L )
00097     return false;
00098   if ( _delta->getSequence() == 0L )
00099     return false;
00100   if ( m_sequence->size() != _delta->getSequence()->size() )
00101     return false;
00102 
00103   for ( unsigned int i = 0; i < m_sequence->size(); i++ )
00104   {
00105     if ( m_sequence->at( i ) != _delta->getSequence()->at( i ) )
00106       return false;
00107   }
00108 
00109   return true;
00110 }
00111 
00112 double AutoFillDeltaSequence::getItemDelta( int _pos )
00113 {
00114   if ( m_sequence == 0L )
00115     return 0.0;
00116 
00117   return m_sequence->at( _pos );
00118 }
00119 
00120 /**********************************************************************************
00121  *
00122  * AutoFillSequenceItem
00123  *
00124  **********************************************************************************/
00125 
00126 AutoFillSequenceItem::AutoFillSequenceItem( int _i )
00127 {
00128     m_IValue = _i;
00129     m_Type = INTEGER;
00130 }
00131 
00132 AutoFillSequenceItem::AutoFillSequenceItem( double _d )
00133 {
00134     m_DValue = _d;
00135     m_Type = FLOAT;
00136 }
00137 
00138 AutoFillSequenceItem::AutoFillSequenceItem( const QString &_str )
00139 {
00140     m_String = _str;
00141     m_Type = STRING;
00142 
00143     if ( month == 0L )
00144     {
00145         month = new QStringList();
00146         month->append( i18n("January") );
00147         month->append( i18n("February") );
00148         month->append( i18n("March") );
00149         month->append( i18n("April") );
00150         month->append( i18n("May") );
00151         month->append( i18n("June") );
00152         month->append( i18n("July") );
00153         month->append( i18n("August") );
00154         month->append( i18n("September") );
00155         month->append( i18n("October") );
00156         month->append( i18n("November") );
00157         month->append( i18n("December") );
00158     }
00159 
00160     if ( shortMonth == 0L )
00161     {
00162         shortMonth = new QStringList();
00163         shortMonth->append( i18n("Jan") );
00164         shortMonth->append( i18n("Feb") );
00165         shortMonth->append( i18n("Mar") );
00166         shortMonth->append( i18n("Apr") );
00167         shortMonth->append( i18n("May short", "May") );
00168         shortMonth->append( i18n("Jun") );
00169         shortMonth->append( i18n("Jul") );
00170         shortMonth->append( i18n("Aug") );
00171         shortMonth->append( i18n("Sep") );
00172         shortMonth->append( i18n("Oct") );
00173         shortMonth->append( i18n("Nov") );
00174         shortMonth->append( i18n("Dec") );
00175     }
00176 
00177     if ( day == 0L )
00178     {
00179         day = new QStringList();
00180         day->append( i18n("Monday") );
00181         day->append( i18n("Tuesday") );
00182         day->append( i18n("Wednesday") );
00183         day->append( i18n("Thursday") );
00184         day->append( i18n("Friday") );
00185         day->append( i18n("Saturday") );
00186         day->append( i18n("Sunday") );
00187     }
00188 
00189     if ( shortDay == 0L )
00190     {
00191         shortDay = new QStringList();
00192         shortDay->append( i18n("Mon") );
00193         shortDay->append( i18n("Tue") );
00194         shortDay->append( i18n("Wed") );
00195         shortDay->append( i18n("Thu") );
00196         shortDay->append( i18n("Fri") );
00197         shortDay->append( i18n("Sat") );
00198         shortDay->append( i18n("Sun") );
00199     }
00200 
00201     if( other==0L)
00202       {
00203     //  other=new QStringList();
00204     KConfig *config = Factory::global()->config();
00205     config->setGroup( "Parameters" );
00206     other=new QStringList(config->readListEntry("Other list"));
00207       }
00208 
00209     if ( month->find( _str ) != month->end() )
00210     {
00211         m_Type = MONTH;
00212         return;
00213     }
00214 
00215     if ( shortMonth->find( _str ) != shortMonth->end() )
00216     {
00217         m_Type = SHORTMONTH;
00218         return;
00219     }
00220 
00221     if ( day->find( _str ) != day->end() )
00222     {
00223       m_Type = DAY;
00224       return;
00225     }
00226 
00227     if ( shortDay->find( _str ) != shortDay->end() )
00228     {
00229       m_Type = SHORTDAY;
00230       return;
00231     }
00232 
00233     if( other->find(_str)!=other->end())
00234       {
00235     m_Type = OTHER;
00236     m_OtherBegin=0;
00237     m_OtherEnd=other->count();
00238     int index= other->findIndex(_str);
00239     //find end and begin of qstringlist of other.
00240     for ( QStringList::Iterator it = other->find(_str); it != other->end();++it )
00241       {
00242         if((*it)=="\\")
00243           {
00244           m_OtherEnd=index;
00245           break;
00246           }
00247         index++;
00248       }
00249     index= other->findIndex(_str);
00250     for ( QStringList::Iterator it = other->find(_str); it != other->begin();--it )
00251       {
00252         if((*it)=="\\")
00253           {
00254           m_OtherBegin=index;
00255           break;
00256           }
00257         index--;
00258       }
00259     return;
00260       }
00261 
00262     if ( m_String[0] == '=' )
00263         m_Type = FORMULA;
00264 }
00265 
00266 bool AutoFillSequenceItem::getDelta( AutoFillSequenceItem *seq, double &_delta )
00267 {
00268     if ( seq->getType() != m_Type )
00269         return false;
00270 
00271     switch( m_Type )
00272     {
00273     case INTEGER:
00274         _delta = (double)( seq->getIValue() - m_IValue );
00275         return true;
00276     case FLOAT:
00277         _delta = seq->getDValue() - m_DValue;
00278         return true;
00279     case FORMULA:
00280     case STRING:
00281         if ( m_String == seq->getString() )
00282         {
00283             _delta = 0.0;
00284             return true;
00285         }
00286         return false;
00287     case MONTH:
00288         {
00289             int i = month->findIndex( m_String );
00290             int j = month->findIndex( seq->getString() );
00291             int k = j;
00292 
00293             if ( j + 1 == i )
00294                 _delta = -1.0;
00295             else
00296                 _delta = ( double )( k - i );
00297             return true;
00298         }
00299 
00300     case SHORTMONTH:
00301         {
00302             int i = shortMonth->findIndex( m_String );
00303             int j = shortMonth->findIndex( seq->getString() );
00304             int k = j;
00305 
00306             if ( j + 1 == i )
00307                 _delta = -1.0;
00308             else
00309                 _delta = ( double )( k - i );
00310             return true;
00311         }
00312 
00313     case DAY:
00314         {
00315             int i = day->findIndex( m_String );
00316             int j = day->findIndex( seq->getString() );
00317             int k = j;
00318 
00319             if ( j + 1 == i )
00320                 _delta = -1.0;
00321             else
00322                 _delta = ( double )( k - i );
00323             kdDebug() << m_String << " i: " << i << " j: " << j << " k: " << k << " delta: " << _delta << endl;
00324             return true;
00325         }
00326 
00327     case SHORTDAY:
00328         {
00329             int i = shortDay->findIndex( m_String );
00330             int j = shortDay->findIndex( seq->getString() );
00331             int k = j;
00332 
00333             if ( j + 1 == i )
00334                 _delta = -1.0;
00335             else
00336                 _delta = ( double )( k - i );
00337             return true;
00338         }
00339     case OTHER:
00340       {
00341     if( m_OtherEnd!= seq->getIOtherEnd() || m_OtherBegin!= seq->getIOtherBegin())
00342       return false;
00343     int i = other->findIndex( m_String );
00344     int j = other->findIndex( seq->getString() );
00345     int k = j;
00346     if ( j < i )
00347       k += (m_OtherEnd - m_OtherBegin - 1);
00348     /*if ( j + 1 == i )
00349       _delta = -1.0;
00350       else*/
00351       _delta = ( double )( k - i );
00352     return true;
00353       }
00354      default:
00355       return false;
00356     }
00357 }
00358 
00359 QString AutoFillSequenceItem::getSuccessor( int _no, double _delta )
00360 {
00361     QString erg;
00362     switch( m_Type )
00363     {
00364     case INTEGER:
00365         erg.sprintf("%i", m_IValue + _no * (int)_delta );
00366         break;
00367     case FLOAT:
00368         erg.sprintf("%f", m_DValue + (double)_no * _delta );
00369         break;
00370     case FORMULA:
00371     case STRING:
00372         erg = m_String;
00373         break;
00374     case MONTH:
00375         {
00376             int i = month->findIndex( m_String );
00377             int j = i + _no * (int) _delta;
00378             while (j < 0)
00379               j += month->count();
00380             int k = j % month->count();
00381             erg = (*month->at( k ));
00382         }
00383         break;
00384     case SHORTMONTH:
00385         {
00386             int i = shortMonth->findIndex( m_String );
00387             int j = i + _no * (int) _delta;
00388             while (j < 0)
00389               j += shortMonth->count();
00390             int k = j % shortMonth->count();
00391             erg = (*shortMonth->at( k ));
00392         }
00393         break;
00394     case DAY:
00395         {
00396             int i = day->findIndex( m_String );
00397             int j = i + _no * (int) _delta;
00398             while (j < 0)
00399               j += day->count();
00400             int k = j % day->count();
00401             erg = (*day->at( k ));
00402         }
00403     break;
00404     case SHORTDAY:
00405         {
00406             int i = shortDay->findIndex( m_String );
00407             int j = i + _no * (int) _delta;
00408             while (j < 0)
00409               j += shortDay->count();
00410             int k = j % shortDay->count();
00411             erg = (*shortDay->at( k ));
00412         }
00413         break;
00414     case OTHER:
00415       {
00416      int i = other->findIndex( m_String )-(m_OtherBegin+1);
00417      int j = i + _no * (int) _delta;
00418      int k = j % (m_OtherEnd - m_OtherBegin-1);
00419      erg = (*other->at( (k+m_OtherBegin+1) ));
00420       }
00421      case TIME:
00422      case DATE:
00423       // gets never called but fixes a warning while compiling
00424       break;
00425     }
00426 
00427     return QString( erg );
00428 }
00429 
00430 QString AutoFillSequenceItem::getPredecessor( int _no, double _delta )
00431 {
00432   QString erg;
00433   switch( m_Type )
00434   {
00435    case INTEGER:
00436     erg.sprintf("%i", m_IValue - _no * (int)_delta );
00437     break;
00438    case FLOAT:
00439     erg.sprintf("%f", m_DValue - (double)_no * _delta );
00440     break;
00441    case FORMULA:
00442    case STRING:
00443     erg = m_String;
00444     break;
00445    case MONTH:
00446     {
00447       int i = month->findIndex( m_String );
00448       int j = i - _no * (int) _delta;
00449       while ( j < 0 )
00450         j += month->count();
00451       int k = j % month->count();
00452       erg = (*month->at( k ));
00453     }
00454     break;
00455    case SHORTMONTH:
00456     {
00457       int i = shortMonth->findIndex( m_String );
00458       int j = i - _no * (int) _delta;
00459       while ( j < 0 )
00460         j += shortMonth->count();
00461       int k = j % shortMonth->count();
00462       erg = (*shortMonth->at( k ));
00463     }
00464     break;
00465    case DAY:
00466     {
00467       int i = day->findIndex( m_String );
00468       int j = i - _no * (int) _delta;
00469       while ( j < 0 )
00470         j += day->count();
00471       int k = j % day->count();
00472       erg = (*day->at( k ));
00473     }
00474    case SHORTDAY:
00475     {
00476       int i = shortDay->findIndex( m_String );
00477       int j = i - _no * (int) _delta;
00478       while ( j < 0 )
00479         j += shortDay->count();
00480       int k = j % shortDay->count();
00481       erg = (*shortDay->at( k ));
00482     }
00483     break;
00484    case OTHER:
00485     {
00486       int i = other->findIndex( m_String ) - (m_OtherBegin + 1);
00487       int j = i - _no * (int) _delta;
00488       while ( j < 0 )
00489         j += (m_OtherEnd - m_OtherBegin - 1);
00490       int k = j % (m_OtherEnd - m_OtherBegin - 1);
00491       erg = (*other->at( (k + m_OtherBegin + 1) ));
00492     }
00493    case TIME:
00494    case DATE:
00495     // gets never called but fixes a warning while compiling
00496     break;
00497   }
00498 
00499   return QString( erg );
00500 }
00501 
00502 /**********************************************************************************
00503  *
00504  * AutoFillSequence
00505  *
00506  **********************************************************************************/
00507 
00508 AutoFillSequence::AutoFillSequence( Cell *_cell )
00509 {
00510     sequence.setAutoDelete( true );
00511 
00512     if ( _cell->isFormula() )
00513     {
00514         QString d = _cell->encodeFormula();
00515         sequence.append( new AutoFillSequenceItem( d ) );
00516     }
00517     else if ( _cell->value().isNumber() )
00518     {
00519         if ( floor( _cell->value().asFloat() ) == _cell->value().asFloat() )
00520         {
00521             sequence.append( new AutoFillSequenceItem( (int)_cell->value().asFloat()) );
00522         }
00523         else
00524             sequence.append( new AutoFillSequenceItem(_cell->value().asFloat() ) );
00525     }
00526     else if ( !_cell->text().isEmpty() )
00527         sequence.append( new AutoFillSequenceItem( _cell->text() ) );
00528 }
00529 
00530 bool AutoFillSequence::matches( AutoFillSequence* _seq, AutoFillDeltaSequence *_delta )
00531 {
00532     AutoFillDeltaSequence delta( this, _seq );
00533     if ( !delta.isOk() )
00534         return false;
00535 
00536     if ( delta.equals( _delta ) )
00537          return true;
00538 
00539     return false;
00540 }
00541 
00542 void AutoFillSequence::fillCell( Cell *src, Cell *dest, AutoFillDeltaSequence *delta, int _block, bool down )
00543 {
00544     QString erg = "";
00545 
00546     // Special handling for formulas
00547     if ( sequence.first() != 0L && sequence.first()->getType() == AutoFillSequenceItem::FORMULA )
00548     {
00549         QString f = dest->decodeFormula( sequence.first()->getString() );
00550         dest->setCellText( f );
00551         dest->copyFormat( src );
00552         return;
00553     }
00554 
00555     AutoFillSequenceItem *item;
00556     int i = 0;
00557     if (down)
00558     {
00559       for ( item = sequence.first(); item != 0L; item = sequence.next() )
00560         erg += item->getSuccessor( _block, delta->getItemDelta( i++ ) );
00561     }
00562     else
00563     {
00564       for ( item = sequence.first(); item != 0L; item = sequence.next() )
00565         erg += item->getPredecessor( _block, delta->getItemDelta( i++ ) );
00566     }
00567 
00568     dest->setCellText( erg );
00569     dest->copyFormat( src );
00570 }
00571 
00572 /**********************************************************************************
00573  *
00574  * Sheet
00575  *
00576  **********************************************************************************/
00577 
00578 void Sheet::autofill( QRect &src, QRect &dest )
00579 {
00580     if (src == dest)
00581     {
00582         return;
00583     }
00584 
00585     setRegionPaintDirty( dest );
00586 
00587     doc()->emitBeginOperation();
00588 
00589     if ( !doc()->undoLocked() )
00590     {
00591       UndoAutofill *undo = new UndoAutofill( doc(), this, dest );
00592       doc()->addCommand( undo );
00593     }
00594 
00595     // Fill from left to right
00596     if ( src.left() == dest.left() && src.right() < dest.right() )
00597     {
00598         for ( int y = src.top(); y <= src.bottom(); y++ )
00599         {
00600             int x;
00601             QPtrList<Cell> destList;
00602             for ( x = src.right() + 1; x <= dest.right(); x++ )
00603                 destList.append( nonDefaultCell( x, y ) );
00604             QPtrList<Cell> srcList;
00605             for ( x = src.left(); x <= src.right(); x++ )
00606                 srcList.append( cellAt( x, y ) );
00607             QPtrList<AutoFillSequence> seqList;
00608             seqList.setAutoDelete( true );
00609             for ( x = src.left(); x <= src.right(); x++ )
00610                 seqList.append( new AutoFillSequence( cellAt( x, y ) ) );
00611             fillSequence( srcList, destList, seqList );
00612         }
00613     }
00614 
00615     // Fill from top to bottom
00616     if ( src.top() == dest.top() && src.bottom() < dest.bottom() )
00617     {
00618         for ( int x = src.left(); x <= dest.right(); x++ )
00619         {
00620             int y;
00621             QPtrList<Cell> destList;
00622             for ( y = src.bottom() + 1; y <= dest.bottom(); y++ )
00623                 destList.append( nonDefaultCell( x, y ) );
00624             QPtrList<Cell> srcList;
00625             for ( y = src.top(); y <= src.bottom(); y++ )
00626             {
00627                 srcList.append( cellAt( x, y ) );
00628             }
00629             QPtrList<AutoFillSequence> seqList;
00630             seqList.setAutoDelete( true );
00631             for ( y = src.top(); y <= src.bottom(); y++ )
00632                 seqList.append( new AutoFillSequence( cellAt( x, y ) ) );
00633             fillSequence( srcList, destList, seqList );
00634         }
00635     }
00636 
00637     // Fill from right to left
00638     if ( ( src.left() == dest.right() || src.left() == dest.right() - 1) && src.right() >= dest.right() )
00639     {
00640         if ( src.left() != dest.right() )
00641             dest.setRight( dest.right() - 1 );
00642 
00643         for ( int y = dest.top(); y <= dest.bottom(); y++ )
00644         {
00645             int x;
00646             QPtrList<Cell> destList;
00647 
00648             for ( x = dest.left(); x < src.left(); x++ )
00649             {
00650                 destList.append( nonDefaultCell( x, y ) );
00651             }
00652             QPtrList<Cell> srcList;
00653             for ( x = src.left(); x <= src.right(); x++ )
00654             {
00655                 srcList.append( cellAt( x, y ) );
00656             }
00657             QPtrList<AutoFillSequence> seqList;
00658             seqList.setAutoDelete( true );
00659             for ( x = src.left(); x <= src.right(); x++ )
00660                 seqList.append( new AutoFillSequence( cellAt( x, y ) ) );
00661             fillSequence( srcList, destList, seqList, false );
00662         }
00663     }
00664 
00665     // Fill from bottom to top
00666     if ( (src.top() == dest.bottom() || src.top() == (dest.bottom() - 1) ) && src.bottom() >= dest.bottom() )
00667     {
00668         if (src.top() != dest.bottom() )
00669             dest.setBottom(dest.bottom() - 1);
00670         int startVal = QMIN( dest.left(), src.left());
00671         int endVal = QMAX(src.right(), dest.right());
00672         for ( int x = startVal; x <= endVal; x++ )
00673         {
00674             int y;
00675             QPtrList<Cell> destList;
00676             for ( y = dest.top(); y < src.top(); y++ )
00677                 destList.append( nonDefaultCell( x, y ) );
00678             QPtrList<Cell> srcList;
00679             for ( y = src.top(); y <= src.bottom(); ++y )
00680             {
00681                 srcList.append( cellAt( x, y ) );
00682             }
00683             QPtrList<AutoFillSequence> seqList;
00684             seqList.setAutoDelete( true );
00685             for ( y = src.top(); y <= src.bottom(); y++ )
00686                 seqList.append( new AutoFillSequence( cellAt( x, y ) ) );
00687             fillSequence( srcList, destList, seqList, false );
00688         }
00689     }
00690 
00691     emit sig_updateView( this );
00692     // doc()->emitEndOperation();
00693 }
00694 
00695 
00696 void Sheet::fillSequence( QPtrList<Cell>& _srcList,
00697                  QPtrList<Cell>& _destList,
00698                                  QPtrList<AutoFillSequence>& _seqList,
00699                                  bool down)
00700 {
00701     doc()->emitBeginOperation(true);
00702     
00703     /* try finding an interval to use to fill the sequence */
00704     if (!FillSequenceWithInterval(_srcList, _destList, _seqList, down))
00705     {
00706       /* if no interval was found, just copy down through */
00707       FillSequenceWithCopy(_srcList, _destList, down);
00708     }
00709 
00710     doc()->emitEndOperation();
00711 
00712 }
00713 
00714 QVariant getDiff( const Value& value1, const Value& value2  , AutoFillSequenceItem::Type type  )
00715 {
00716   if ( type == AutoFillSequenceItem::FLOAT )
00717       return QVariant( value2.asFloat() - value1.asFloat() );
00718   if ( type == AutoFillSequenceItem::TIME || type == AutoFillSequenceItem::DATE )
00719       return QVariant( (int)( value2.asInteger() - value1.asInteger() ) );
00720 
00721   return QVariant( (int)0 );
00722   // note: date and time difference can be calculated as
00723   // the difference of the serial number
00724  /* if( (type == AutoFillSequenceItem::FLOAT) ||
00725       (type == AutoFillSequenceItem::DATE) ||
00726       (type == AutoFillSequenceItem::TIME) )
00727     return ( value2.asFloat() - value1.asFloat() );
00728   else
00729     return 0.0;*/
00730 }
00731 
00732 bool Sheet::FillSequenceWithInterval(QPtrList<Cell>& _srcList,
00733                                             QPtrList<Cell>& _destList,
00734                                             QPtrList<AutoFillSequence>& _seqList,
00735                                             bool down)
00736 {
00737   if (_srcList.first()->isFormula())
00738     return false;
00739 
00740   QPtrList<AutoFillDeltaSequence> deltaList;
00741   deltaList.setAutoDelete( true );
00742   bool ok = false;
00743 
00744   if ( _srcList.first()->value().isNumber() || _srcList.first()->isDate() || _srcList.first()->isTime() )
00745   {
00746     AutoFillSequenceItem::Type type;
00747 
00748     QValueVector< QVariant > tmp( _seqList.count() );  /*= new QValueList< QVariant > ( _seqList.count() )*/;
00749     QValueVector< QVariant > diff( _seqList.count() ); /*= new QValueList< QVariant > ( _seqList.count() )*/;
00750     int p = -1;
00751     int count = 0;
00752     int tmpcount = 0;
00753 
00754     Cell * cell = _srcList.first();
00755     Cell * cell2 = _srcList.next();
00756 
00757     bool singleCellOnly = (cell2 == 0);
00758     
00759     if ( cell->isDate() )
00760       type = AutoFillSequenceItem::DATE;
00761     else if ( cell->isTime() )
00762       type = AutoFillSequenceItem::TIME;
00763     else if ( cell->value().isNumber() )
00764       type = AutoFillSequenceItem::FLOAT;
00765     else
00766       return false; // Cannot happen due to if condition
00767 
00768     while ( cell && (cell2 || singleCellOnly) )
00769     {
00770       
00771       Value cellValue = cell->value();
00772       Value cell2Value;
00773 
00774       //If we only have a single cell, the interval will depend upon the data type.
00775       //- For numeric values, set the interval to 0 as we don't know what might be useful as a sequence
00776       //- For time values, set the interval to one hour, as this will probably be the most useful setting
00777       //- For date values, set the interval to one day, as this will probably be the most useful setting
00778       //
00779       //Note that the above options were chosen for consistency with Excel.  Gnumeric (1.59) sets
00780       //the interval to 0 for all types, OpenOffice.org (2.00) uses increments of 1.00, 1 hour and 1 day
00781       //respectively
00782       if (singleCellOnly)
00783       {
00784         if (type == AutoFillSequenceItem::FLOAT)
00785         cell2Value = cellValue;
00786     else if ( type == AutoFillSequenceItem::TIME)
00787         cell2Value = Value( cellValue.asTime().addSecs( 60*60 ) );
00788     else if ( type == AutoFillSequenceItem::DATE)
00789         cell2Value = Value ( cellValue.asDate().addDays( 1 ) );
00790       }
00791       else
00792       {
00793     cell2Value = cell2->value();      
00794           
00795         // check if both cells contain the same type
00796         if ( ( !cellValue.isNumber() )
00797            || ( cell2->isDate() && type != AutoFillSequenceItem::DATE )
00798            || ( cell2->isTime() && type != AutoFillSequenceItem::TIME ) )
00799         {
00800             count = 0;
00801             ok = false;
00802             break;
00803         }
00804       }
00805 
00806       QVariant delta = getDiff(cellValue , cell2Value , type ); 
00807       
00808       if (count < 1)
00809       {
00810         p = count;
00811         diff[ count++ ] = delta;
00812       }
00813       else
00814       {
00815         // same value again?
00816         if (diff[ p ] == delta)
00817         {
00818           // store it somewhere else for the case we need it later
00819           ++p;
00820           tmp[ tmpcount++ ] = delta;
00821         }
00822         else
00823         {
00824           // if we have saved values in another buffer we have to insert them first
00825           if ( tmpcount > 0 )
00826           {
00827             for ( int i = 0; i < tmpcount; ++i )
00828             {
00829               diff[ count++ ] = tmp.at( i );
00830             }
00831 
00832             tmpcount = 0;
00833           }
00834 
00835           // insert the value
00836           p = 0;
00837           diff[ count++ ] = delta;
00838         }
00839       }
00840 
00841       // check next cell pair
00842       cell  = cell2;
00843       cell2 = _srcList.next();
00844     }
00845 
00846     // we have found something:
00847     if (count > 0 && (tmpcount > 0 || count == 1))
00848     {
00849       QVariant cellValue( (int) 0 );
00850 
00851       Cell * dest;
00852       Cell * src;
00853 
00854       int i = tmpcount;
00855       if (down)
00856       {
00857         dest = _destList.first();
00858         src  = _srcList.last();
00859       }
00860       else
00861       {
00862         dest = _destList.last();
00863         src  = _srcList.first();
00864 
00865         i   *= -1;
00866       }
00867 
00868       if ( type == AutoFillSequenceItem::FLOAT )
00869           cellValue = src->value().asFloat();
00870       else
00871           cellValue = (int)src->value().asInteger();
00872 
00873       QString res;
00874       // copy all the data
00875       while (dest)
00876       {
00877         if (down)
00878         {
00879           while ( i >= count )
00880             i -= count;
00881         }
00882         else
00883         {
00884           while ( i < 0)
00885             i += count;
00886         }
00887     
00888     QVariant currentDiff = diff.at( i );
00889     
00890     if (cellValue.type() == QVariant::Double)
00891             if (down)
00892                     cellValue = cellValue.asDouble() + currentDiff.asDouble();      
00893             else
00894                     cellValue = cellValue.asDouble() -  currentDiff.asDouble();
00895     else
00896         if (down)
00897             cellValue = cellValue.asInt() + currentDiff.asInt();
00898         else
00899             cellValue = cellValue.asInt() - currentDiff.asInt();
00900 
00901     if ( type == AutoFillSequenceItem::TIME)
00902     {
00903         Value timeValue = doc()->converter()->asTime( Value(cellValue.asInt()) );
00904         Value stringValue = doc()->converter()->asString( timeValue );
00905         dest->setCellText( stringValue.asString() );
00906     }
00907     else if ( type == AutoFillSequenceItem::DATE)
00908     {
00909         Value dateValue = doc()->converter()->asDate( Value(cellValue.asInt()) );
00910         Value stringValue = doc()->converter()->asString( dateValue );
00911         dest->setCellText( stringValue.asString() );
00912     }
00913     else
00914             dest->setCellText( cellValue.asString() );
00915         
00916     dest->copyFormat( src );
00917 
00918         if (down)
00919         {
00920           ++i;
00921           dest = _destList.next();
00922           src = _srcList.next();
00923         }
00924         else
00925         {
00926           --i;
00927           dest = _destList.prev();
00928           src = _srcList.prev();
00929         }
00930 
00931         if (!src)
00932           src = _srcList.last();
00933       }
00934 
00935       ok = true;
00936     }
00937     else
00938     {
00939       ok = false;
00940     }
00941 
00942    // delete tmp;
00943    // delete diff;
00944 
00945     return ok;
00946   }
00947 
00948   // What is the interval (block)? If your sheet looks like this:
00949   // 1 3 5 7 9
00950   // then the interval has the length 1 and the delta list is [2].
00951   // 2 200 3 300 4 400
00952   // Here the interval has length 2 and the delta list is [1,100]
00953 
00954 
00955   // How big is the interval. It is in the range from [2...n/2].
00956   // The case of an interval of length n is handled below.
00957   //
00958   // We try to find the shortest interval.
00959   for ( unsigned int step = 1; step <= _seqList.count() / 2; step++ )
00960   {
00961     kdDebug() << "Looking for interval: " << step << " seqList count: " << _seqList.count() << endl;
00962     // If the interval is of length 'step' then the _seqList size must
00963     // be a multiple of 'step'
00964     if ( _seqList.count() % step == 0 )
00965     {
00966       // Be optimistic
00967       ok = true;
00968 
00969       deltaList.clear();
00970 
00971       // Guess the delta by looking at cells 0...2*step-1
00972       //
00973       // Since the interval may be of length 'step' we calculate the delta
00974       // between cells 0 and step, 1 and step+1, ...., step-1 and 2*step-1
00975       for ( unsigned int t = 0; t < step; t++ )
00976       {
00977     deltaList.append( new AutoFillDeltaSequence( _seqList.at(t),
00978                              _seqList.at(t+step) ) );
00979     ok = deltaList.getLast()->isOk();
00980       }
00981 
00982       /* Verify the delta by looking at cells step..._seqList.count()
00983      We only looked at the cells 0 ... '2*step-1'.
00984      Now test wether the cells from "(tst-1) * step + s" share the same delta
00985      with the cell "tst * step + s" for all test=1..._seqList.count()/step
00986      and for all s=0...step-1.
00987       */
00988       for ( unsigned int tst = 1; ok && ( tst * step < _seqList.count() );
00989         tst++ )
00990       {
00991     for ( unsigned int s = 0; ok && ( s < step ); s++ )
00992     {
00993       if ( !_seqList.at( (tst-1) * step + s )->
00994            matches( _seqList.at( tst * step + s ), deltaList.at( s ) ) )
00995         ok = false;
00996     }
00997       }
00998       // Did we find a valid interval ?
00999       if ( ok )
01000       {
01001     unsigned int s = 0;
01002     // Amount of intervals (blocks)
01003     int block = _seqList.count() / step;
01004 
01005     // Start iterating with the first cell
01006     Cell * cell;
01007         if (down)
01008           cell = _destList.first();
01009         else
01010         {
01011           cell = _destList.last();
01012           block -= (_seqList.count() - 1);
01013         }
01014 
01015 
01016     // Loop over all destination cells
01017     while ( cell )
01018     {
01019           kdDebug() << "Valid interval, cell: " << cell->row() << " block: " << block << endl;
01020 
01021       // End of block? -> start again from beginning
01022           if (down)
01023           {
01024             if ( s == step )
01025             {
01026               ++block;
01027               s = 0;
01028             }
01029           }
01030           else
01031           {
01032             if ( s >= step )
01033             {
01034               s = step - 1;
01035               ++block;
01036             }
01037           }
01038 
01039           kdDebug() << "Step: " << step << " S: " << s << " Block " << block
01040                     << " SeqList: " << _seqList.count()
01041                     << " SrcList: " << _srcList.count() << " DeltaList: " << deltaList.count()
01042                     << endl;
01043 
01044       // Set the value of 'cell' by adding 'block' times the delta tp the
01045       // value of cell 's'.
01046       _seqList.at( s )->fillCell( _srcList.at( s ), cell,
01047                       deltaList.at( s ), block, down );
01048 
01049           if (down)
01050           {
01051             // Next cell
01052             cell = _destList.next();
01053             ++s;
01054           }
01055           else
01056           {
01057             // Previous cell
01058             cell = _destList.prev();
01059             --s;
01060           }
01061     }
01062       }
01063     }
01064   }
01065   return ok;
01066 }
01067 
01068 void Sheet::FillSequenceWithCopy(QPtrList<Cell>& _srcList,
01069                                         QPtrList<Cell>& _destList,
01070                                         bool down)
01071 {
01072   // We did not find any valid interval. So just copy over the marked
01073   // area.
01074   Cell * cell;
01075 
01076   if (down)
01077     cell = _destList.first();
01078   else
01079     cell = _destList.last();
01080   int incr = 1;
01081   unsigned int s = 0;
01082   double factor = 1;
01083 
01084   if (!down)
01085     s = _srcList.count() - 1;
01086 
01087   if ( _srcList.at( s )->value().isNumber() &&
01088        !(_srcList.at( s )->isDate() || _srcList.at( s )->isTime() ) )
01089     factor = _srcList.at( s )->value().asFloat();
01090 
01091   while ( cell )
01092   {
01093     if (down)
01094     {
01095       if ( s == _srcList.count() )
01096         s = 0;
01097     }
01098     else
01099     {
01100       if ( s >= _srcList.count() )
01101         s = _srcList.count() - 1;
01102     }
01103 
01104     if ( !_srcList.at( s )->text().isEmpty() )
01105     {
01106       if ( _srcList.at( s )->isFormula() )
01107       {
01108         QString d = _srcList.at( s )->encodeFormula();
01109         cell->setCellText( cell->decodeFormula( d ) );
01110       }
01111       else if(_srcList.at( s )->value().isNumber() && _srcList.count()==1)
01112       {
01113         double val;
01114         int format_type = _srcList.at( s )->formatType();
01115         if ( format_type == Percentage_format )
01116         {
01117           factor = 0.01;  // one percent
01118         }
01119         else if ( _srcList.at( s )->isTime() )
01120         {
01121           // FIXME this is a workaround to avoid those nasty one minute off
01122           //       "dragging down" time is inaccurate overa large lists!
01123           //       This is the best approximation I could find (raphael)
01124           if (down)
01125           {
01126 //             factor = 1.000002/24.  + 0.000000001;
01127             factor = 0.041666751;
01128           }
01129           else
01130           {  //when dragging "up" the error must of course be the other way round
01131             factor = 0.0416665;
01132           }
01133         }
01134 
01135         if (!down)
01136           val = (_srcList.at( s )->value().asFloat() - (incr * factor));
01137         else
01138           val = (_srcList.at( s )->value().asFloat() + (incr * factor));
01139         
01140         QString tmp;
01141         tmp = tmp.setNum(val);
01142         cell->setCellText( tmp );
01143         ++incr;
01144       }
01145       else if((AutoFillSequenceItem::month != 0L)
01146           && AutoFillSequenceItem::month->find( _srcList.at( s )->text()) != 0L
01147           && AutoFillSequenceItem::month->find( _srcList.at( s )->text()) != AutoFillSequenceItem::month->end()
01148           && _srcList.count() == 1)
01149       {
01150     QString strMonth=_srcList.at( s )->text();
01151     int i = AutoFillSequenceItem::month->findIndex( strMonth )+incr;
01152     int k = (i) % AutoFillSequenceItem::month->count();
01153     cell->setCellText((*AutoFillSequenceItem::month->at( k )));
01154         incr++;
01155       }
01156       else if(AutoFillSequenceItem::day != 0L
01157           && AutoFillSequenceItem::day->find( _srcList.at( s )->text()) != 0L
01158           && AutoFillSequenceItem::day->find( _srcList.at( s )->text())
01159              != AutoFillSequenceItem::day->end()
01160           && _srcList.count()==1)
01161       {
01162     QString strDay=_srcList.at( s )->text();
01163     int i = AutoFillSequenceItem::day->findIndex( strDay )+incr;
01164     int k = (i) % AutoFillSequenceItem::day->count();
01165     cell->setCellText((*AutoFillSequenceItem::day->at( k )));
01166         incr++;
01167       }
01168       else
01169       {
01170     QRegExp number("(\\d+)");
01171     int pos =number.search(_srcList.at( s )->text());
01172     if( pos!=-1 )
01173     {
01174       QString tmp=number.cap(1);
01175       int num=tmp.toInt()+incr;
01176       cell->setCellText(_srcList.at( s )->text().replace(number,QString::number(num)));
01177           ++incr;
01178     }
01179     else if ( !_srcList.at( s )->link().isEmpty() )
01180         {
01181       cell->setCellText( _srcList.at( s )->text() );
01182       cell->setLink( _srcList.at( s )->link() );
01183         }
01184         else
01185         {
01186       cell->setCellText( _srcList.at( s )->text() );
01187         }
01188       }
01189     }
01190     else
01191       cell->setCellText( "" );
01192 
01193     cell->copyFormat( _srcList.at( s ) );
01194 
01195     if (down)
01196     {
01197       cell = _destList.next();
01198       ++s;
01199     }
01200     else
01201     {
01202       cell = _destList.prev();
01203       --s;
01204     }
01205   }
01206   return;
01207 }
KDE Home | KDE Accessibility Home | Description of Access Keys