kspread

AutoFillCommand.cpp

Go to the documentation of this file.
00001 /* This file is part of the KDE project
00002    Copyright 2006-2007 Stefan Nikolaus <stefan.nikolaus@kdemail.net>
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 "AutoFillCommand.h"
00032 
00033 #include "part/Factory.h" // FIXME detach from part
00034 #include "Localization.h"
00035 #include "Map.h"
00036 #include "Sheet.h"
00037 #include "Value.h"
00038 #include "ValueConverter.h"
00039 
00040 #include <kconfig.h>
00041 #include <kconfiggroup.h>
00042 #include <kdebug.h>
00043 
00044 #include <QList>
00045 #include <QRegExp>
00046 
00047 #include <math.h>
00048 
00049 using namespace KSpread;
00050 
00051 QStringList *AutoFillCommand::month = 0;
00052 QStringList *AutoFillCommand::shortMonth = 0;
00053 QStringList *AutoFillCommand::day = 0;
00054 QStringList *AutoFillCommand::shortDay = 0;
00055 QStringList *AutoFillCommand::other = 0;
00056 
00057 /**********************************************************************************
00058  *
00059  * AutoFillSequenceItem
00060  *
00061  **********************************************************************************/
00062 
00063 namespace KSpread
00064 {
00068 class AutoFillSequenceItem
00069 {
00070 public:
00071     enum Type { VALUE, FORMULA, DAY, SHORTDAY, MONTH, SHORTMONTH, OTHER };
00072 
00073     explicit AutoFillSequenceItem(const Cell& cell);
00074 
00075     Value delta(AutoFillSequenceItem *_seq, bool *ok) const;
00076 
00077     Value nextValue(int _no, Value _delta) const;
00078     Value prevValue(int _no, Value _delta) const;
00079 
00080     Type type() const { return m_type; }
00081     Value value() const { return m_value; }
00082     int otherEnd() const { return m_otherEnd; }
00083     int otherBegin() const { return m_otherBegin; }
00084 
00085 protected:
00086     Value   m_value;
00087     Type    m_type;
00088     int     m_otherBegin;
00089     int     m_otherEnd;
00090 };
00091 }
00092 
00093 AutoFillSequenceItem::AutoFillSequenceItem(const Cell& cell)
00094     : m_value()
00095     , m_type(VALUE)
00096     , m_otherBegin(0)
00097     , m_otherEnd(0)
00098 {
00099     if (cell.isFormula())
00100     {
00101         m_value = Value(cell.encodeFormula());
00102         m_type = FORMULA;
00103     }
00104     else if (cell.isDate())
00105     {
00106         m_value = cell.sheet()->map()->converter()->asDate(cell.value());
00107         m_type = VALUE;
00108     }
00109     else if (cell.isTime() || cell.value().format() == Value::fmt_DateTime)
00110     {
00111         m_value = cell.sheet()->map()->converter()->asDateTime(cell.value());
00112         m_type = VALUE;
00113     }
00114     else if (cell.value().isNumber())
00115     {
00116         m_value = cell.value();
00117         m_type = VALUE;
00118     }
00119     else
00120     {
00121         m_value = cell.value();
00122         m_type = VALUE;
00123 
00124         if (AutoFillCommand::month == 0)
00125         {
00126             AutoFillCommand::month = new QStringList();
00127             AutoFillCommand::month->append(i18n("January"));
00128             AutoFillCommand::month->append(i18n("February"));
00129             AutoFillCommand::month->append(i18n("March"));
00130             AutoFillCommand::month->append(i18n("April"));
00131             AutoFillCommand::month->append(i18n("May"));
00132             AutoFillCommand::month->append(i18n("June"));
00133             AutoFillCommand::month->append(i18n("July"));
00134             AutoFillCommand::month->append(i18n("August"));
00135             AutoFillCommand::month->append(i18n("September"));
00136             AutoFillCommand::month->append(i18n("October"));
00137             AutoFillCommand::month->append(i18n("November"));
00138             AutoFillCommand::month->append(i18n("December"));
00139         }
00140 
00141         if (AutoFillCommand::shortMonth == 0)
00142         {
00143             AutoFillCommand::shortMonth = new QStringList();
00144             AutoFillCommand::shortMonth->append(i18n("Jan"));
00145             AutoFillCommand::shortMonth->append(i18n("Feb"));
00146             AutoFillCommand::shortMonth->append(i18n("Mar"));
00147             AutoFillCommand::shortMonth->append(i18n("Apr"));
00148             AutoFillCommand::shortMonth->append(i18nc("May short", "May"));
00149             AutoFillCommand::shortMonth->append(i18n("Jun"));
00150             AutoFillCommand::shortMonth->append(i18n("Jul"));
00151             AutoFillCommand::shortMonth->append(i18n("Aug"));
00152             AutoFillCommand::shortMonth->append(i18n("Sep"));
00153             AutoFillCommand::shortMonth->append(i18n("Oct"));
00154             AutoFillCommand::shortMonth->append(i18n("Nov"));
00155             AutoFillCommand::shortMonth->append(i18n("Dec"));
00156         }
00157 
00158         if (AutoFillCommand::day == 0)
00159         {
00160             AutoFillCommand::day = new QStringList();
00161             AutoFillCommand::day->append(i18n("Monday"));
00162             AutoFillCommand::day->append(i18n("Tuesday"));
00163             AutoFillCommand::day->append(i18n("Wednesday"));
00164             AutoFillCommand::day->append(i18n("Thursday"));
00165             AutoFillCommand::day->append(i18n("Friday"));
00166             AutoFillCommand::day->append(i18n("Saturday"));
00167             AutoFillCommand::day->append(i18n("Sunday"));
00168         }
00169 
00170         if (AutoFillCommand::shortDay == 0)
00171         {
00172             AutoFillCommand::shortDay = new QStringList();
00173             AutoFillCommand::shortDay->append(i18n("Mon"));
00174             AutoFillCommand::shortDay->append(i18n("Tue"));
00175             AutoFillCommand::shortDay->append(i18n("Wed"));
00176             AutoFillCommand::shortDay->append(i18n("Thu"));
00177             AutoFillCommand::shortDay->append(i18n("Fri"));
00178             AutoFillCommand::shortDay->append(i18n("Sat"));
00179             AutoFillCommand::shortDay->append(i18n("Sun"));
00180         }
00181 
00182         if (AutoFillCommand::other == 0)
00183         {
00184             // AutoFillCommand::other = new QStringList();
00185             KSharedConfigPtr config = Factory::global().config();
00186             AutoFillCommand::other = new QStringList(config->group("Parameters").readEntry("Other list", QStringList()));
00187         }
00188 
00189         if (AutoFillCommand::month->contains(m_value.asString()))
00190         {
00191             m_type = MONTH;
00192             return;
00193         }
00194 
00195         if (AutoFillCommand::shortMonth->contains(m_value.asString()))
00196         {
00197             m_type = SHORTMONTH;
00198             return;
00199         }
00200 
00201         if (AutoFillCommand::day->contains(m_value.asString()))
00202         {
00203             m_type = DAY;
00204             return;
00205         }
00206 
00207         if (AutoFillCommand::shortDay->contains(m_value.asString()))
00208         {
00209             m_type = SHORTDAY;
00210             return;
00211         }
00212 
00213         if (AutoFillCommand::other->contains(m_value.asString()))
00214         {
00215             m_type = OTHER;
00216             int index = AutoFillCommand::other->indexOf(m_value.asString());
00217             int otherBegin = AutoFillCommand::other->lastIndexOf("\\", index); // backward
00218             int otherEnd = AutoFillCommand::other->indexOf("\\", index); // forward
00219             m_otherBegin = (otherBegin != -1) ? otherBegin : 0;
00220             m_otherEnd = (otherEnd != -1) ? otherEnd : AutoFillCommand::other->count();
00221             return;
00222         }
00223     }
00224 }
00225 
00226 Value AutoFillSequenceItem::delta(AutoFillSequenceItem *seq, bool *ok) const
00227 {
00228     if (seq->type() != m_type)
00229     {
00230         *ok = false;
00231         return Value();
00232     }
00233 
00234     *ok = true;
00235 
00236     switch(m_type)
00237     {
00238     case VALUE:
00239     case FORMULA:
00240     {
00241         switch (m_value.type())
00242         {
00243         case Value::Boolean:
00244         {
00245             // delta indicates a flipping of the boolean
00246             if (seq->value().type() != Value::Boolean)
00247                 *ok = false;
00248             return Value(seq->value().asBoolean() != m_value.asBoolean());
00249         }
00250         case Value::Integer:
00251         {
00252             if (seq->value().type() == Value::Empty)
00253                 *ok = false;
00254             Value value(seq->value().asInteger() - m_value.asInteger());
00255             value.setFormat(m_value.format()); // may be a date format
00256             return value;
00257         }
00258         case Value::Float:
00259         {
00260             if (seq->value().type() == Value::Empty)
00261                 *ok = false;
00262             Value value(seq->value().asFloat() - m_value.asFloat());
00263             value.setFormat(m_value.format()); // may be a time format
00264             return value;
00265         }
00266         case Value::Complex:
00267         {
00268             if (seq->value().type() == Value::Empty)
00269                 *ok = false;
00270             return Value(seq->value().asComplex() - m_value.asComplex());
00271         }
00272         case Value::Empty:
00273         case Value::String:
00274         case Value::Array:
00275         case Value::CellRange:
00276         case Value::Error:
00277         {
00278             *ok = (m_value == seq->value());
00279             return Value();
00280         }
00281         }
00282     }
00283     case MONTH:
00284     {
00285         const int i = AutoFillCommand::month->indexOf(m_value.asString());
00286         const int j = AutoFillCommand::month->indexOf(seq->value().asString());
00287         return Value(j - i);
00288     }
00289     case SHORTMONTH:
00290     {
00291         const int i = AutoFillCommand::shortMonth->indexOf(m_value.asString());
00292         const int j = AutoFillCommand::shortMonth->indexOf(seq->value().asString());
00293         return Value(j - i);
00294     }
00295     case DAY:
00296     {
00297         const int i = AutoFillCommand::day->indexOf(m_value.asString());
00298         const int j = AutoFillCommand::day->indexOf(seq->value().asString());
00299         return Value(j - i);
00300     }
00301     case SHORTDAY:
00302     {
00303         const int i = AutoFillCommand::shortDay->indexOf(m_value.asString());
00304         const int j = AutoFillCommand::shortDay->indexOf(seq->value().asString());
00305         return Value(j - i);
00306     }
00307     case OTHER:
00308     {
00309         *ok = (m_otherEnd != seq->otherEnd() || m_otherBegin != seq->otherBegin());
00310         const int i = AutoFillCommand::other->indexOf(m_value.asString());
00311         const int j = AutoFillCommand::other->indexOf(seq->value().asString());
00312         int k = j;
00313         if (j < i)
00314             k += (m_otherEnd - m_otherBegin - 1);
00315 /*        if (j + 1 == i)
00316             return -1.0;
00317         else*/
00318             return Value(k - i);
00319     }
00320     default:
00321         *ok = false;
00322     }
00323     return Value();
00324 }
00325 
00326 Value AutoFillSequenceItem::nextValue(int _no, Value _delta) const
00327 {
00328     switch(m_type)
00329     {
00330     case VALUE:
00331     case FORMULA:
00332     {
00333         if (m_value.isBoolean())
00334         {
00335             if (!_delta.asBoolean() || _delta.isEmpty()) // no change?
00336                 return m_value;
00337             return Value(_no % 2 ? !m_value.asBoolean() : m_value.asBoolean());
00338         }
00339         else if (m_value.isInteger())
00340         {
00341             Value value(m_value.asInteger() + _no * _delta.asInteger());
00342             value.setFormat(_delta.format());
00343             return value;
00344         }
00345         else if (m_value.isFloat())
00346         {
00347             Value value(m_value.asFloat() + (long double)_no * _delta.asFloat());
00348             value.setFormat(_delta.format());
00349             return value;
00350         }
00351         else if (m_value.isComplex())
00352         {
00353             Value value(m_value.asComplex() + (long double)_no * _delta.asComplex());
00354             value.setFormat(_delta.format());
00355             return value;
00356         }
00357         else // string or empty
00358             return m_value;
00359     }
00360     case MONTH:
00361     {
00362         int i = AutoFillCommand::month->indexOf(m_value.asString());
00363         int j = i + _no * _delta.asInteger();
00364         while (j < 0)
00365             j += AutoFillCommand::month->count();
00366         int k = j % AutoFillCommand::month->count();
00367         return Value(AutoFillCommand::month->at(k));
00368     }
00369     case SHORTMONTH:
00370     {
00371         int i = AutoFillCommand::shortMonth->indexOf(m_value.asString());
00372         int j = i + _no * _delta.asInteger();
00373         while (j < 0)
00374             j += AutoFillCommand::shortMonth->count();
00375         int k = j % AutoFillCommand::shortMonth->count();
00376         return Value(AutoFillCommand::shortMonth->at(k));
00377     }
00378     case DAY:
00379     {
00380         int i = AutoFillCommand::day->indexOf(m_value.asString());
00381         int j = i + _no * _delta.asInteger();
00382         while (j < 0)
00383             j += AutoFillCommand::day->count();
00384         int k = j % AutoFillCommand::day->count();
00385         return Value(AutoFillCommand::day->at(k));
00386     }
00387     case SHORTDAY:
00388     {
00389         int i = AutoFillCommand::shortDay->indexOf(m_value.asString());
00390         int j = i + _no * _delta.asInteger();
00391         while (j < 0)
00392             j += AutoFillCommand::shortDay->count();
00393         int k = j % AutoFillCommand::shortDay->count();
00394         return Value(AutoFillCommand::shortDay->at(k));
00395     }
00396     case OTHER:
00397     {
00398         int i = AutoFillCommand::other->indexOf(m_value.asString())-(m_otherBegin+1);
00399         int j = i + _no * _delta.asInteger();
00400         int k = j % (m_otherEnd - m_otherBegin-1);
00401         return Value(AutoFillCommand::other->at((k+m_otherBegin+1)));
00402     }
00403     default:
00404         break;
00405     }
00406     return Value();
00407 }
00408 
00409 Value AutoFillSequenceItem::prevValue(int _no, Value _delta) const
00410 {
00411     switch(m_type)
00412     {
00413     case VALUE:
00414     case FORMULA:
00415     {
00416         if (m_value.isBoolean())
00417         {
00418             if (!_delta.asBoolean() || _delta.isEmpty()) // no change?
00419                 return m_value;
00420             return Value(_no % 2 ? !m_value.asBoolean() : m_value.asBoolean());
00421         }
00422         else if (m_value.isInteger())
00423         {
00424             Value value(m_value.asInteger() - _no * _delta.asInteger());
00425             value.setFormat(_delta.format());
00426             return value;
00427         }
00428         else if (m_value.isFloat())
00429         {
00430             Value value(m_value.asFloat() - (long double)_no * _delta.asFloat());
00431             value.setFormat(_delta.format());
00432             return value;
00433         }
00434         else if (m_value.isComplex())
00435         {
00436             Value value(m_value.asComplex() - (long double)_no * _delta.asComplex());
00437             value.setFormat(_delta.format());
00438             return value;
00439         }
00440         else // string or empty
00441             return m_value;
00442     }
00443     case MONTH:
00444     {
00445         int i = AutoFillCommand::month->indexOf(m_value.asString());
00446         int j = i - _no * _delta.asInteger();
00447         while (j < 0)
00448             j += AutoFillCommand::month->count();
00449         int k = j % AutoFillCommand::month->count();
00450         return Value(AutoFillCommand::month->at(k));
00451     }
00452     case SHORTMONTH:
00453     {
00454         int i = AutoFillCommand::shortMonth->indexOf(m_value.asString());
00455         int j = i - _no * _delta.asInteger();
00456         while (j < 0)
00457             j += AutoFillCommand::shortMonth->count();
00458         int k = j % AutoFillCommand::shortMonth->count();
00459         return Value(AutoFillCommand::shortMonth->at(k));
00460     }
00461     case DAY:
00462     {
00463         int i = AutoFillCommand::day->indexOf(m_value.asString());
00464         int j = i - _no * _delta.asInteger();
00465         while (j < 0)
00466             j += AutoFillCommand::day->count();
00467         int k = j % AutoFillCommand::day->count();
00468         return Value(AutoFillCommand::day->at(k));
00469     }
00470     case SHORTDAY:
00471     {
00472         int i = AutoFillCommand::shortDay->indexOf(m_value.asString());
00473         int j = i - _no * _delta.asInteger();
00474         while (j < 0)
00475             j += AutoFillCommand::shortDay->count();
00476         int k = j % AutoFillCommand::shortDay->count();
00477         return Value(AutoFillCommand::shortDay->at(k));
00478     }
00479     case OTHER:
00480     {
00481         int i = AutoFillCommand::other->indexOf(m_value.asString()) - (m_otherBegin + 1);
00482         int j = i - _no * _delta.asInteger();
00483         while (j < 0)
00484             j += (m_otherEnd - m_otherBegin - 1);
00485         int k = j % (m_otherEnd - m_otherBegin - 1);
00486         return Value(AutoFillCommand::other->at((k + m_otherBegin + 1)));
00487     }
00488     default:
00489         break;
00490     }
00491     return Value();
00492 }
00493 
00494 
00495 /**********************************************************************************
00496  *
00497  * AutoFillSequence
00498  *
00499  **********************************************************************************/
00500 
00501 namespace KSpread
00502 {
00506 class AutoFillSequence : public QList<AutoFillSequenceItem*>
00507 {
00508 public:
00509     AutoFillSequence();
00510     AutoFillSequence(const QList<AutoFillSequenceItem*>&);
00511     ~AutoFillSequence();
00512 
00513     QList<Value> createDeltaSequence(int intervalLength) const;
00514 };
00515 }
00516 
00517 AutoFillSequence::AutoFillSequence()
00518 {
00519 }
00520 
00521 AutoFillSequence::AutoFillSequence(const QList<AutoFillSequenceItem*>& list)
00522     : QList<AutoFillSequenceItem*>(list)
00523 {
00524 }
00525 
00526 AutoFillSequence::~AutoFillSequence()
00527 {
00528 }
00529 
00530 QList<Value> AutoFillSequence::createDeltaSequence(int intervalLength) const
00531 {
00532     bool ok = true;
00533     QList<Value> deltaSequence;
00534 
00535     // Guess the delta by looking at cells 0...2*intervalLength-1
00536     //
00537     // Since the interval may be of length 'intervalLength' we calculate the delta
00538     // between cells 0 and intervalLength, 1 and intervalLength+1, ...., intervalLength-1 and 2*intervalLength-1.
00539     for (int t = 0; t < intervalLength /*&& t + intervalLength < count()*/; ++t)
00540     {
00541         deltaSequence.append(value(t)->delta(value((t + intervalLength) % count()), &ok));
00542         if (!ok)
00543             return QList<Value>();
00544     }
00545 
00546     // fill to the interval length
00547     while (deltaSequence.count() < intervalLength)
00548         deltaSequence.append(Value());
00549 
00550     return deltaSequence;
00551 }
00552 
00553 
00554 /**********************************************************************************
00555  *
00556  * File static helper functions
00557  *
00558  **********************************************************************************/
00559 
00560 static QList<Value> findInterval(const AutoFillSequence& _seqList)
00561 {
00562     // What is the interval (block)? If your sheet looks like this:
00563     // 1 3 5 7 9
00564     // then the interval has the length 1 and the delta list is [2].
00565     // 2 200 3 300 4 400
00566     // Here the interval has length 2 and the delta list is [1,100]
00567 
00568     QList<Value> deltaSequence;
00569 
00570     kDebug() <<"Sequence length:" << _seqList.count();
00571 
00572     // How big is the interval. It is in the range from [1...n].
00573     //
00574     // We try to find the shortest interval.
00575     int intervalLength = 1;
00576     for (intervalLength = 1; intervalLength < _seqList.count(); ++intervalLength)
00577     {
00578         kDebug() <<"Checking interval of length:" << intervalLength;
00579 
00580         // Create the delta list.
00581         deltaSequence = _seqList.createDeltaSequence(intervalLength);
00582 
00583         QString str("Deltas: [ ");
00584         foreach (Value v, deltaSequence)
00585         {
00586             if (v.isBoolean())
00587                 str += v.asBoolean() ? "change " : "nochange ";
00588             else if (v.isInteger())
00589                 str += QString::number(v.asInteger()) + ' ';
00590             else if (v.isFloat())
00591                 str += QString::number((double) v.asFloat()) + ' ';
00592             else
00593                 str += v.asString() + ' ';
00594         }
00595         str += ']';
00596         kDebug() << str;
00597 
00598         // Verify the delta by looking at cells intervalLength.._seqList.count().
00599         // We only looked at the cells 0..2*intervalLength-1.
00600         // Now test whether the cells from "(i-1) * intervalLength + s" share the same delta
00601         // with the cell "i * intervalLength + s" for all test=1..._seqList.count()/intervalLength
00602         // and for all s=0...intervalLength-1.
00603         for (int i = 1; (i+1) * intervalLength < _seqList.count(); ++i)
00604         {
00605             AutoFillSequence tail = _seqList.mid(i * intervalLength);
00606 //             kDebug() <<"Verifying for sequence after" << i * intervalLength <<", length:" << tail.count();
00607             QList<Value> otherDeltaSequence = tail.createDeltaSequence(intervalLength);
00608             if (deltaSequence != otherDeltaSequence)
00609             {
00610                 kDebug() <<"Interval does not match.";
00611                 deltaSequence.clear();
00612                 break;
00613             }
00614         }
00615 
00616         // Did we find a valid interval?
00617         if (!deltaSequence.isEmpty())
00618             break;
00619     }
00620 
00621     // if the full interval has to be taken fill the delta sequence with zeros
00622     if (intervalLength == _seqList.count())
00623     {
00624         while (intervalLength--)
00625             deltaSequence.append(Value());
00626 
00627         QString str("Deltas: [ ");
00628         foreach (Value v, deltaSequence)
00629         {
00630             if (v.isBoolean())
00631                 str += v.asBoolean() ? "change " : "nochange ";
00632             else if (v.isInteger())
00633                 str += QString::number(v.asInteger()) + ' ';
00634             else if (v.isFloat())
00635                 str += QString::number((double) v.asFloat()) + ' ';
00636             else
00637                 str += v.asString() + ' ';
00638         }
00639         str += ']';
00640         kDebug() << str;
00641     }
00642 
00643     return deltaSequence;
00644 }
00645 
00646 static void fillSequence(const QList<Cell>& _srcList,
00647                          const QList<Cell>& _destList,
00648                          const AutoFillSequence& _seqList,
00649                          const QList<Value>& deltaSequence,
00650                          bool down)
00651 {
00652     const int intervalLength = deltaSequence.count();
00653     // starting position depends on the sequence and interval length
00654     int s = _srcList.count() % intervalLength;
00655     // Amount of intervals (blocks)
00656     int block = _srcList.count() / intervalLength;
00657     kDebug() <<"Valid interval, number of intervals:" << block;
00658 
00659     // Start iterating with the first cell
00660     Cell cell;
00661     int destIndex = 0;
00662     if (down)
00663         cell = _destList.first();
00664     else
00665     {
00666         cell = _destList.last();
00667         destIndex = _destList.count() - 1;
00668         block -= (_srcList.count() - 1);
00669     }
00670 
00671     // Fill destination cells
00672     //
00673     while (!cell.isNull())
00674     {
00675         // End of block? -> start again from beginning
00676         if (down)
00677         {
00678             if (s == intervalLength)
00679             {
00680                 ++block;
00681                 s = 0;
00682             }
00683         }
00684         else
00685         {
00686             if (s == -1)
00687             {
00688                 s = intervalLength - 1;
00689                 ++block;
00690             }
00691         }
00692 
00693         kDebug() <<"Cell:" << cell.name() <<", position:" << s <<", block:" << block;
00694 
00695         // Calculate the new value of 'cell' by adding 'block' times the delta to the
00696         // value of cell 's'.
00697         //
00698         Value value;
00699         if (down)
00700             value = _seqList.value(s)->nextValue(block, deltaSequence.value(s));
00701         else
00702             value = _seqList.value(s)->prevValue(block, deltaSequence.value(s));
00703 
00704         // insert the new value
00705         //
00706         if (_seqList.value(s)->type() == AutoFillSequenceItem::FORMULA)
00707         {
00708             // Special handling for formulas
00709             cell.parseUserInput(cell.decodeFormula(_seqList.value(s)->value().asString()));
00710         }
00711         else if (value.format() == Value::fmt_Time)
00712         {
00713             const Value timeValue = cell.sheet()->map()->converter()->asTime(value);
00714             cell.setValue(timeValue);
00715             cell.setUserInput(cell.sheet()->map()->converter()->asString(timeValue).asString());
00716         }
00717         else if (value.format() == Value::fmt_Date)
00718         {
00719             const Value dateValue = cell.sheet()->map()->converter()->asDate(value);
00720             cell.setValue(dateValue);
00721             cell.setUserInput(cell.sheet()->map()->converter()->asString(dateValue).asString());
00722         }
00723         else if (value.type() == Value::Boolean ||
00724                  value.type() == Value::Complex ||
00725                  value.type() == Value::Float ||
00726                  value.type() == Value::Integer)
00727         {
00728             cell.setValue(value);
00729             cell.setUserInput(cell.sheet()->map()->converter()->asString(value).asString());
00730         }
00731         else // if (value.type() == Value::String)
00732         {
00733             QRegExp number("(\\d+)");
00734             int pos = number.indexIn(value.asString());
00735             if (pos!=-1)
00736             {
00737                 const int num = number.cap(1).toInt() + 1;
00738                 cell.parseUserInput(value.asString().replace(number, QString::number(num)));
00739             }
00740             else if (!_srcList.at(s).link().isEmpty())
00741             {
00742                 cell.parseUserInput(value.asString());
00743                 cell.setLink(_srcList.at(s).link());
00744             }
00745             else
00746             {
00747                 cell.setValue(value);
00748                 cell.setUserInput(value.asString());
00749             }
00750         }
00751 
00752         // copy the style of the source cell
00753         //
00754         cell.copyFormat(_srcList.at(s));
00755 
00756         // next/previous cell
00757         if (down)
00758         {
00759             cell = _destList.value(++destIndex);
00760             ++s;
00761         }
00762         else
00763         {
00764             cell = _destList.value(--destIndex);
00765             --s;
00766         }
00767     }
00768 }
00769 
00770 
00771 /**********************************************************************************
00772  *
00773  * AutoFillCommand
00774  *
00775  **********************************************************************************/
00776 
00777 AutoFillCommand::AutoFillCommand()
00778 {
00779     setText(i18n("Autofill"));
00780 }
00781 
00782 AutoFillCommand::~AutoFillCommand()
00783 {
00784 }
00785 
00786 void AutoFillCommand::setSourceRange(const QRect& range)
00787 {
00788     m_sourceRange = range;
00789 }
00790 
00791 void AutoFillCommand::setTargetRange(const QRect& range)
00792 {
00793     m_targetRange = range;
00794 }
00795 
00796 bool AutoFillCommand::mainProcessing()
00797 {
00798     if (m_sourceRange.contains(m_targetRange))
00799         return false;
00800 
00801     if (m_reverse)
00802     {
00803         // reverse - use the stored value
00804         AbstractDataManipulator::mainProcessing();
00805         return true;
00806     }
00807 
00808     // Fill from left to right
00809     if (m_sourceRange.left() == m_targetRange.left() && m_sourceRange.right() < m_targetRange.right())
00810     {
00811         for (int y = m_sourceRange.top(); y <= m_sourceRange.bottom(); y++)
00812         {
00813             int x;
00814             QList<Cell> destList;
00815             for (x = m_sourceRange.right() + 1; x <= m_targetRange.right(); x++)
00816                 destList.append(Cell(m_sheet, x, y));
00817             QList<Cell> srcList;
00818             for (x = m_sourceRange.left(); x <= m_sourceRange.right(); x++)
00819                 srcList.append(Cell(m_sheet, x, y));
00820             AutoFillSequence seqList;
00821             for (x = m_sourceRange.left(); x <= m_sourceRange.right(); x++)
00822                 seqList.append(new AutoFillSequenceItem(Cell(m_sheet, x, y)));
00823             fillSequence(srcList, destList, seqList);
00824             qDeleteAll(seqList);
00825         }
00826     }
00827 
00828     // Fill from top to bottom
00829     if (m_sourceRange.top() == m_targetRange.top() && m_sourceRange.bottom() < m_targetRange.bottom())
00830     {
00831         for (int x = m_sourceRange.left(); x <= m_targetRange.right(); x++)
00832         {
00833             int y;
00834             QList<Cell> destList;
00835             for (y = m_sourceRange.bottom() + 1; y <= m_targetRange.bottom(); y++)
00836                 destList.append(Cell(m_sheet, x, y));
00837             QList<Cell> srcList;
00838             for (y = m_sourceRange.top(); y <= m_sourceRange.bottom(); y++)
00839                 srcList.append(Cell(m_sheet, x, y));
00840             AutoFillSequence seqList;
00841             for (y = m_sourceRange.top(); y <= m_sourceRange.bottom(); y++)
00842                 seqList.append(new AutoFillSequenceItem(Cell(m_sheet, x, y)));
00843             fillSequence(srcList, destList, seqList);
00844             qDeleteAll(seqList);
00845         }
00846     }
00847 
00848     // Fill from right to left
00849     if (m_sourceRange.left() == m_targetRange.right() && m_sourceRange.right() >= m_targetRange.right())
00850     {
00851         for (int y = m_targetRange.top(); y <= m_targetRange.bottom(); y++)
00852         {
00853             int x;
00854             QList<Cell> destList;
00855             for (x = m_targetRange.left(); x < m_sourceRange.left(); x++)
00856                 destList.append(Cell(m_sheet, x, y));
00857             QList<Cell> srcList;
00858             for (x = m_sourceRange.left(); x <= m_sourceRange.right(); x++)
00859                 srcList.append(Cell(m_sheet, x, y));
00860             AutoFillSequence seqList;
00861             for (x = m_sourceRange.left(); x <= m_sourceRange.right(); x++)
00862                 seqList.append(new AutoFillSequenceItem(Cell(m_sheet, x, y)));
00863             fillSequence(srcList, destList, seqList, false);
00864             qDeleteAll(seqList);
00865         }
00866     }
00867 
00868     // Fill from bottom to top
00869     if (m_sourceRange.top() == m_targetRange.bottom() && m_sourceRange.bottom() >= m_targetRange.bottom())
00870     {
00871         const int startVal = qMin(m_targetRange.left(), m_sourceRange.left());
00872         const int endVal = qMax(m_sourceRange.right(), m_targetRange.right());
00873         for (int x = startVal; x <= endVal; x++)
00874         {
00875             int y;
00876             QList<Cell> destList;
00877             for (y = m_targetRange.top(); y < m_sourceRange.top(); y++)
00878                 destList.append(Cell(m_sheet, x, y));
00879             QList<Cell> srcList;
00880             for (y = m_sourceRange.top(); y <= m_sourceRange.bottom(); ++y)
00881                 srcList.append(Cell(m_sheet, x, y));
00882             AutoFillSequence seqList;
00883             for (y = m_sourceRange.top(); y <= m_sourceRange.bottom(); y++)
00884                 seqList.append(new AutoFillSequenceItem(Cell(m_sheet, x, y)));
00885             fillSequence(srcList, destList, seqList, false);
00886             qDeleteAll(seqList);
00887         }
00888     }
00889     return true;
00890 }
00891 
00892 void AutoFillCommand::fillSequence(const QList<Cell>& _srcList,
00893                                    const QList<Cell>& _destList,
00894                                    const AutoFillSequence& _seqList,
00895                                    bool down)
00896 {
00897     if (_srcList.isEmpty() || _destList.isEmpty())
00898         return;
00899 
00900     // find an interval to use to fill the sequence
00901     QList<Value> deltaSequence;
00902 
00903     //If we only have a single cell, the interval will depend upon the data type.
00904     //- For numeric values, set the interval to 0 as we don't know what might be useful as a sequence
00905     //- For time values, set the interval to one hour, as this will probably be the most useful setting
00906     //- For date values, set the interval to one day, as this will probably be the most useful setting
00907     //
00908     //Note that the above options were chosen for consistency with Excel.  Gnumeric (1.59) sets
00909     //the interval to 0 for all types, OpenOffice.org (2.00) uses increments of 1.00, 1 hour and 1 day
00910     //respectively
00911     if (_srcList.count() == 1)
00912     {
00913         const Cell cell = _srcList.value(0);
00914         if (cell.isTime() || cell.value().format() == Value::fmt_DateTime)
00915         {
00916             // TODO Stefan: delta depending on minimum unit of format
00917             deltaSequence.append(Value(QTime(1, 0), m_sheet->map()->calculationSettings()));
00918         }
00919         else if (cell.isDate())
00920         {
00921             // TODO Stefan: delta depending on minimum unit of format
00922             Value value(1);
00923             value.setFormat(Value::fmt_Date);
00924             deltaSequence.append(value);
00925         }
00926         else
00927             deltaSequence.append(Value());
00928     }
00929     else
00930         deltaSequence = findInterval(_seqList);
00931 
00932     // fill the sequence
00933     ::fillSequence(_srcList, _destList, _seqList, deltaSequence, down);
00934 }