kspread Library API Documentation

kspread_autofill.cc

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