1 /* This file is part of the KDE project
2    Copyright 2006-2007 Stefan Nikolaus <stefan.nikolaus@kdemail.net>
3    Copyright 2005 Raphael Langerhorst <raphael.langerhorst@kdemail.net>
4    Copyright 2002-2004 Ariya Hidayat <ariya@kde.org>
5    Copyright 2002-2003 Norbert Andres <nandres@web.de>
6    Copyright 2002 John Dailey <dailey@vt.edu>
7    Copyright 2001-2002 Philipp Mueller <philipp.mueller@gmx.de>
8    Copyright 2000-2002 Laurent Montel <montel@kde.org>
9    Copyright 2000-2001 Werner Trobin <trobin@kde.org>
10    Copyright 1999-2001 David Faure <faure@kde.org>
11    Copyright 1998-2000 Torben Weis <weis@kde.org>
12    Copyright 1998-1999 Stephan Kulow <coolo@kde.org>
13    Copyright 1998 Reginald Stadlbauer <reggie@kde.org>
14 
15    This library is free software; you can redistribute it and/or
16    modify it under the terms of the GNU Library General Public
17    License as published by the Free Software Foundation; either
18    version 2 of the License, or (at your option) any later version.
19 
20    This library is distributed in the hope that it will be useful,
21    but WITHOUT ANY WARRANTY; without even the implied warranty of
22    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
23    Library General Public License for more details.
24 
25    You should have received a copy of the GNU Library General Public License
26    along with this library; see the file COPYING.LIB.  If not, write to
27    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
28    Boston, MA 02110-1301, USA.
29 */
30 
31 #include "AutoFillCommand.h"
32 
33 #include "Localization.h"
34 #include "Map.h"
35 #include "Sheet.h"
36 #include "Value.h"
37 #include "ValueConverter.h"
38 #include "SheetsDebug.h"
39 
40 #include <KSharedConfig>
41 #include <kconfig.h>
42 #include <kconfiggroup.h>
43 
44 #include <QList>
45 #include <QRegExp>
46 
47 #include <math.h>
48 
49 using namespace Calligra::Sheets;
50 
51 QStringList *AutoFillCommand::month = 0;
52 QStringList *AutoFillCommand::shortMonth = 0;
53 QStringList *AutoFillCommand::day = 0;
54 QStringList *AutoFillCommand::shortDay = 0;
55 QStringList *AutoFillCommand::other = 0;
56 
57 /**********************************************************************************
58  *
59  * AutoFillSequenceItem
60  *
61  **********************************************************************************/
62 
63 namespace Calligra
64 {
65 namespace Sheets
66 {
67 /**
68  * A cell content for auto-filling.
69  */
70 class AutoFillSequenceItem
71 {
72 public:
73     enum Type { VALUE, FORMULA, DAY, SHORTDAY, MONTH, SHORTMONTH, OTHER };
74 
75     explicit AutoFillSequenceItem(const Cell& cell);
76 
77     Value delta(AutoFillSequenceItem *_seq, bool *ok) const;
78 
79     Value nextValue(int _no, Value _delta) const;
80     Value prevValue(int _no, Value _delta) const;
81 
type() const82     Type type() const {
83         return m_type;
84     }
value() const85     Value value() const {
86         return m_value;
87     }
otherEnd() const88     int otherEnd() const {
89         return m_otherEnd;
90     }
otherBegin() const91     int otherBegin() const {
92         return m_otherBegin;
93     }
94 
95 protected:
96     Value   m_value;
97     Type    m_type;
98     int     m_otherBegin;
99     int     m_otherEnd;
100 };
101 
102 } // namespace Sheets
103 } // namespace Calligra
104 
105 
AutoFillSequenceItem(const Cell & cell)106 AutoFillSequenceItem::AutoFillSequenceItem(const Cell& cell)
107         : m_value()
108         , m_type(VALUE)
109         , m_otherBegin(0)
110         , m_otherEnd(0)
111 {
112     if (cell.isFormula()) {
113         m_value = Value(cell.encodeFormula());
114         m_type = FORMULA;
115     } else if (cell.isDate()) {
116         m_value = cell.sheet()->map()->converter()->asDate(cell.value());
117         m_type = VALUE;
118     } else if (cell.isTime() || cell.value().format() == Value::fmt_DateTime) {
119         m_value = cell.sheet()->map()->converter()->asDateTime(cell.value());
120         m_type = VALUE;
121     } else if (cell.value().isNumber()) {
122         m_value = cell.value();
123         m_type = VALUE;
124     } else {
125         m_value = cell.value();
126         m_type = VALUE;
127 
128         if (AutoFillCommand::month == 0) {
129             AutoFillCommand::month = new QStringList();
130             AutoFillCommand::month->append(i18n("January"));
131             AutoFillCommand::month->append(i18n("February"));
132             AutoFillCommand::month->append(i18n("March"));
133             AutoFillCommand::month->append(i18n("April"));
134             AutoFillCommand::month->append(i18n("May"));
135             AutoFillCommand::month->append(i18n("June"));
136             AutoFillCommand::month->append(i18n("July"));
137             AutoFillCommand::month->append(i18n("August"));
138             AutoFillCommand::month->append(i18n("September"));
139             AutoFillCommand::month->append(i18n("October"));
140             AutoFillCommand::month->append(i18n("November"));
141             AutoFillCommand::month->append(i18n("December"));
142         }
143 
144         if (AutoFillCommand::shortMonth == 0) {
145             AutoFillCommand::shortMonth = new QStringList();
146             AutoFillCommand::shortMonth->append(i18n("Jan"));
147             AutoFillCommand::shortMonth->append(i18n("Feb"));
148             AutoFillCommand::shortMonth->append(i18n("Mar"));
149             AutoFillCommand::shortMonth->append(i18n("Apr"));
150             AutoFillCommand::shortMonth->append(i18nc("May short", "May"));
151             AutoFillCommand::shortMonth->append(i18n("Jun"));
152             AutoFillCommand::shortMonth->append(i18n("Jul"));
153             AutoFillCommand::shortMonth->append(i18n("Aug"));
154             AutoFillCommand::shortMonth->append(i18n("Sep"));
155             AutoFillCommand::shortMonth->append(i18n("Oct"));
156             AutoFillCommand::shortMonth->append(i18n("Nov"));
157             AutoFillCommand::shortMonth->append(i18n("Dec"));
158         }
159 
160         if (AutoFillCommand::day == 0) {
161             AutoFillCommand::day = new QStringList();
162             AutoFillCommand::day->append(i18n("Monday"));
163             AutoFillCommand::day->append(i18n("Tuesday"));
164             AutoFillCommand::day->append(i18n("Wednesday"));
165             AutoFillCommand::day->append(i18n("Thursday"));
166             AutoFillCommand::day->append(i18n("Friday"));
167             AutoFillCommand::day->append(i18n("Saturday"));
168             AutoFillCommand::day->append(i18n("Sunday"));
169         }
170 
171         if (AutoFillCommand::shortDay == 0) {
172             AutoFillCommand::shortDay = new QStringList();
173             AutoFillCommand::shortDay->append(i18n("Mon"));
174             AutoFillCommand::shortDay->append(i18n("Tue"));
175             AutoFillCommand::shortDay->append(i18n("Wed"));
176             AutoFillCommand::shortDay->append(i18n("Thu"));
177             AutoFillCommand::shortDay->append(i18n("Fri"));
178             AutoFillCommand::shortDay->append(i18n("Sat"));
179             AutoFillCommand::shortDay->append(i18n("Sun"));
180         }
181 
182         if (AutoFillCommand::other == 0) {
183             // AutoFillCommand::other = new QStringList();
184             KSharedConfigPtr config = KSharedConfig::openConfig();
185             AutoFillCommand::other = new QStringList(config->group("Parameters").readEntry("Other list", QStringList()));
186         }
187 
188         if (AutoFillCommand::month->contains(m_value.asString())) {
189             m_type = MONTH;
190             return;
191         }
192 
193         if (AutoFillCommand::shortMonth->contains(m_value.asString())) {
194             m_type = SHORTMONTH;
195             return;
196         }
197 
198         if (AutoFillCommand::day->contains(m_value.asString())) {
199             m_type = DAY;
200             return;
201         }
202 
203         if (AutoFillCommand::shortDay->contains(m_value.asString())) {
204             m_type = SHORTDAY;
205             return;
206         }
207 
208         if (AutoFillCommand::other->contains(m_value.asString())) {
209             m_type = OTHER;
210             int index = AutoFillCommand::other->indexOf(m_value.asString());
211             int otherBegin = AutoFillCommand::other->lastIndexOf("\\", index); // backward
212             int otherEnd = AutoFillCommand::other->indexOf("\\", index); // forward
213             m_otherBegin = (otherBegin != -1) ? otherBegin : 0;
214             m_otherEnd = (otherEnd != -1) ? otherEnd : AutoFillCommand::other->count();
215             return;
216         }
217     }
218 }
219 
delta(AutoFillSequenceItem * seq,bool * ok) const220 Value AutoFillSequenceItem::delta(AutoFillSequenceItem *seq, bool *ok) const
221 {
222     if (seq->type() != m_type) {
223         *ok = false;
224         return Value();
225     }
226 
227     *ok = true;
228 
229     switch (m_type) {
230     case VALUE:
231     case FORMULA: {
232         switch (m_value.type()) {
233         case Value::Boolean: {
234             // delta indicates a flipping of the boolean
235             if (seq->value().type() != Value::Boolean)
236                 *ok = false;
237             return Value(seq->value().asBoolean() != m_value.asBoolean());
238         }
239         case Value::Integer: {
240             if (seq->value().type() == Value::Empty)
241                 *ok = false;
242             Value value(seq->value().asInteger() - m_value.asInteger());
243             value.setFormat(m_value.format()); // may be a date format
244             return value;
245         }
246         case Value::Float: {
247             if (seq->value().type() == Value::Empty)
248                 *ok = false;
249             Value value(seq->value().asFloat() - m_value.asFloat());
250             value.setFormat(m_value.format()); // may be a time format
251             return value;
252         }
253         case Value::Complex: {
254             if (seq->value().type() == Value::Empty)
255                 *ok = false;
256             return Value(seq->value().asComplex() - m_value.asComplex());
257         }
258         case Value::Empty:
259         case Value::String:
260         case Value::Array:
261         case Value::CellRange:
262         case Value::Error: {
263             *ok = (m_value == seq->value());
264             return Value();
265         }
266         }
267     }
268     case MONTH: {
269         const int i = AutoFillCommand::month->indexOf(m_value.asString());
270         const int j = AutoFillCommand::month->indexOf(seq->value().asString());
271         return Value(j - i);
272     }
273     case SHORTMONTH: {
274         const int i = AutoFillCommand::shortMonth->indexOf(m_value.asString());
275         const int j = AutoFillCommand::shortMonth->indexOf(seq->value().asString());
276         return Value(j - i);
277     }
278     case DAY: {
279         const int i = AutoFillCommand::day->indexOf(m_value.asString());
280         const int j = AutoFillCommand::day->indexOf(seq->value().asString());
281         return Value(j - i);
282     }
283     case SHORTDAY: {
284         const int i = AutoFillCommand::shortDay->indexOf(m_value.asString());
285         const int j = AutoFillCommand::shortDay->indexOf(seq->value().asString());
286         return Value(j - i);
287     }
288     case OTHER: {
289         *ok = (m_otherEnd != seq->otherEnd() || m_otherBegin != seq->otherBegin());
290         const int i = AutoFillCommand::other->indexOf(m_value.asString());
291         const int j = AutoFillCommand::other->indexOf(seq->value().asString());
292         int k = j;
293         if (j < i)
294             k += (m_otherEnd - m_otherBegin - 1);
295         /*        if (j + 1 == i)
296                     return -1.0;
297                 else*/
298         return Value(k - i);
299     }
300     default:
301         *ok = false;
302     }
303     return Value();
304 }
305 
nextValue(int _no,Value _delta) const306 Value AutoFillSequenceItem::nextValue(int _no, Value _delta) const
307 {
308     switch (m_type) {
309     case VALUE:
310     case FORMULA: {
311         if (m_value.isBoolean()) {
312             if (!_delta.asBoolean() || _delta.isEmpty()) // no change?
313                 return m_value;
314             return Value((_no % 2) ? !m_value.asBoolean() : m_value.asBoolean());
315         } else if (m_value.isInteger()) {
316             Value value(m_value.asInteger() + _no * _delta.asInteger());
317             value.setFormat(_delta.format());
318             return value;
319         } else if (m_value.isFloat()) {
320             Value value(m_value.asFloat() + (long double)_no * _delta.asFloat());
321             value.setFormat(_delta.format());
322             return value;
323         } else if (m_value.isComplex()) {
324             Value value(m_value.asComplex() + (long double)_no * _delta.asComplex());
325             value.setFormat(_delta.format());
326             return value;
327         } else // string or empty
328             return m_value;
329     }
330     case MONTH: {
331         int i = AutoFillCommand::month->indexOf(m_value.asString());
332         int j = i + _no * _delta.asInteger();
333         while (j < 0)
334             j += AutoFillCommand::month->count();
335         int k = j % AutoFillCommand::month->count();
336         return Value(AutoFillCommand::month->at(k));
337     }
338     case SHORTMONTH: {
339         int i = AutoFillCommand::shortMonth->indexOf(m_value.asString());
340         int j = i + _no * _delta.asInteger();
341         while (j < 0)
342             j += AutoFillCommand::shortMonth->count();
343         int k = j % AutoFillCommand::shortMonth->count();
344         return Value(AutoFillCommand::shortMonth->at(k));
345     }
346     case DAY: {
347         int i = AutoFillCommand::day->indexOf(m_value.asString());
348         int j = i + _no * _delta.asInteger();
349         while (j < 0)
350             j += AutoFillCommand::day->count();
351         int k = j % AutoFillCommand::day->count();
352         return Value(AutoFillCommand::day->at(k));
353     }
354     case SHORTDAY: {
355         int i = AutoFillCommand::shortDay->indexOf(m_value.asString());
356         int j = i + _no * _delta.asInteger();
357         while (j < 0)
358             j += AutoFillCommand::shortDay->count();
359         int k = j % AutoFillCommand::shortDay->count();
360         return Value(AutoFillCommand::shortDay->at(k));
361     }
362     case OTHER: {
363         int i = AutoFillCommand::other->indexOf(m_value.asString()) - (m_otherBegin + 1);
364         int j = i + _no * _delta.asInteger();
365         int k = j % (m_otherEnd - m_otherBegin - 1);
366         return Value(AutoFillCommand::other->at((k + m_otherBegin + 1)));
367     }
368     default:
369         break;
370     }
371     return Value();
372 }
373 
prevValue(int _no,Value _delta) const374 Value AutoFillSequenceItem::prevValue(int _no, Value _delta) const
375 {
376     switch (m_type) {
377     case VALUE:
378     case FORMULA: {
379         if (m_value.isBoolean()) {
380             if (!_delta.asBoolean() || _delta.isEmpty()) // no change?
381                 return m_value;
382             return Value((_no % 2) ? !m_value.asBoolean() : m_value.asBoolean());
383         } else if (m_value.isInteger()) {
384             Value value(m_value.asInteger() - _no * _delta.asInteger());
385             value.setFormat(_delta.format());
386             return value;
387         } else if (m_value.isFloat()) {
388             Value value(m_value.asFloat() - (long double)_no * _delta.asFloat());
389             value.setFormat(_delta.format());
390             return value;
391         } else if (m_value.isComplex()) {
392             Value value(m_value.asComplex() - (long double)_no * _delta.asComplex());
393             value.setFormat(_delta.format());
394             return value;
395         } else // string or empty
396             return m_value;
397     }
398     case MONTH: {
399         int i = AutoFillCommand::month->indexOf(m_value.asString());
400         int j = i - _no * _delta.asInteger();
401         while (j < 0)
402             j += AutoFillCommand::month->count();
403         int k = j % AutoFillCommand::month->count();
404         return Value(AutoFillCommand::month->at(k));
405     }
406     case SHORTMONTH: {
407         int i = AutoFillCommand::shortMonth->indexOf(m_value.asString());
408         int j = i - _no * _delta.asInteger();
409         while (j < 0)
410             j += AutoFillCommand::shortMonth->count();
411         int k = j % AutoFillCommand::shortMonth->count();
412         return Value(AutoFillCommand::shortMonth->at(k));
413     }
414     case DAY: {
415         int i = AutoFillCommand::day->indexOf(m_value.asString());
416         int j = i - _no * _delta.asInteger();
417         while (j < 0)
418             j += AutoFillCommand::day->count();
419         int k = j % AutoFillCommand::day->count();
420         return Value(AutoFillCommand::day->at(k));
421     }
422     case SHORTDAY: {
423         int i = AutoFillCommand::shortDay->indexOf(m_value.asString());
424         int j = i - _no * _delta.asInteger();
425         while (j < 0)
426             j += AutoFillCommand::shortDay->count();
427         int k = j % AutoFillCommand::shortDay->count();
428         return Value(AutoFillCommand::shortDay->at(k));
429     }
430     case OTHER: {
431         int i = AutoFillCommand::other->indexOf(m_value.asString()) - (m_otherBegin + 1);
432         int j = i - _no * _delta.asInteger();
433         while (j < 0)
434             j += (m_otherEnd - m_otherBegin - 1);
435         int k = j % (m_otherEnd - m_otherBegin - 1);
436         return Value(AutoFillCommand::other->at((k + m_otherBegin + 1)));
437     }
438     default:
439         break;
440     }
441     return Value();
442 }
443 
444 
445 /**********************************************************************************
446  *
447  * AutoFillSequence
448  *
449  **********************************************************************************/
450 
451 namespace Calligra
452 {
453 namespace Sheets
454 {
455 /**
456  * A sequence of cell contents for auto-filling.
457  */
458 class AutoFillSequence : public QList<AutoFillSequenceItem*>
459 {
460 public:
461     AutoFillSequence();
462     AutoFillSequence(const QList<AutoFillSequenceItem*>&);
463     ~AutoFillSequence();
464 
465     QList<Value> createDeltaSequence(int intervalLength) const;
466 };
467 
468 } // namespace Sheets
469 } // namespace Calligra
470 
AutoFillSequence()471 AutoFillSequence::AutoFillSequence()
472 {
473 }
474 
AutoFillSequence(const QList<AutoFillSequenceItem * > & list)475 AutoFillSequence::AutoFillSequence(const QList<AutoFillSequenceItem*>& list)
476         : QList<AutoFillSequenceItem*>(list)
477 {
478 }
479 
~AutoFillSequence()480 AutoFillSequence::~AutoFillSequence()
481 {
482 }
483 
createDeltaSequence(int intervalLength) const484 QList<Value> AutoFillSequence::createDeltaSequence(int intervalLength) const
485 {
486     bool ok = true;
487     QList<Value> deltaSequence;
488 
489     // Guess the delta by looking at cells 0...2*intervalLength-1
490     //
491     // Since the interval may be of length 'intervalLength' we calculate the delta
492     // between cells 0 and intervalLength, 1 and intervalLength+1, ...., intervalLength-1 and 2*intervalLength-1.
493     for (int t = 0; t < intervalLength /*&& t + intervalLength < count()*/; ++t) {
494         deltaSequence.append(value(t)->delta(value((t + intervalLength) % count()), &ok));
495         if (!ok)
496             return QList<Value>();
497     }
498 
499     // fill to the interval length
500     while (deltaSequence.count() < intervalLength)
501         deltaSequence.append(Value());
502 
503     return deltaSequence;
504 }
505 
506 
507 /**********************************************************************************
508  *
509  * File static helper functions
510  *
511  **********************************************************************************/
512 
findInterval(const AutoFillSequence & _seqList)513 static QList<Value> findInterval(const AutoFillSequence& _seqList)
514 {
515     // What is the interval (block)? If your sheet looks like this:
516     // 1 3 5 7 9
517     // then the interval has the length 1 and the delta list is [2].
518     // 2 200 3 300 4 400
519     // Here the interval has length 2 and the delta list is [1,100]
520 
521     QList<Value> deltaSequence;
522 
523     debugSheets << "Sequence length:" << _seqList.count();
524 
525     // How big is the interval. It is in the range from [1...n].
526     //
527     // We try to find the shortest interval.
528     int intervalLength = 1;
529     for (intervalLength = 1; intervalLength < _seqList.count(); ++intervalLength) {
530         debugSheets << "Checking interval of length:" << intervalLength;
531 
532         // Create the delta list.
533         deltaSequence = _seqList.createDeltaSequence(intervalLength);
534 
535         QString str("Deltas: [ ");
536         foreach(const Value &v, deltaSequence) {
537             if (v.isBoolean())
538                 str += v.asBoolean() ? "change " : "nochange ";
539             else if (v.isInteger())
540                 str += QString::number(v.asInteger()) + ' ';
541             else if (v.isFloat())
542                 str += QString::number((double) v.asFloat()) + ' ';
543             else
544                 str += v.asString() + ' ';
545         }
546         str += ']';
547         debugSheets << str;
548 
549         // Verify the delta by looking at cells intervalLength.._seqList.count().
550         // We only looked at the cells 0..2*intervalLength-1.
551         // Now test whether the cells from "(i-1) * intervalLength + s" share the same delta
552         // with the cell "i * intervalLength + s" for all test=1..._seqList.count()/intervalLength
553         // and for all s=0...intervalLength-1.
554         for (int i = 1; (i + 1) * intervalLength < _seqList.count(); ++i) {
555             AutoFillSequence tail = _seqList.mid(i * intervalLength);
556 //             debugSheets <<"Verifying for sequence after" << i * intervalLength <<", length:" << tail.count();
557             QList<Value> otherDeltaSequence = tail.createDeltaSequence(intervalLength);
558             if (deltaSequence != otherDeltaSequence) {
559                 debugSheets << "Interval does not match.";
560                 deltaSequence.clear();
561                 break;
562             }
563         }
564 
565         // Did we find a valid interval?
566         if (!deltaSequence.isEmpty())
567             break;
568     }
569 
570     // if the full interval has to be taken fill the delta sequence with zeros
571     if (intervalLength == _seqList.count()) {
572         while (intervalLength--)
573             deltaSequence.append(Value());
574 
575         QString str("Deltas: [ ");
576         foreach(const Value &v, deltaSequence) {
577             if (v.isBoolean())
578                 str += v.asBoolean() ? "change " : "nochange ";
579             else if (v.isInteger())
580                 str += QString::number(v.asInteger()) + ' ';
581             else if (v.isFloat())
582                 str += QString::number((double) v.asFloat()) + ' ';
583             else
584                 str += v.asString() + ' ';
585         }
586         str += ']';
587         debugSheets << str;
588     }
589 
590     return deltaSequence;
591 }
592 
fillSequence(const QList<Cell> & _srcList,const QList<Cell> & _destList,const AutoFillSequence & _seqList,const QList<Value> & deltaSequence,bool down)593 static void fillSequence(const QList<Cell>& _srcList,
594                          const QList<Cell>& _destList,
595                          const AutoFillSequence& _seqList,
596                          const QList<Value>& deltaSequence,
597                          bool down)
598 {
599     const int intervalLength = deltaSequence.count();
600     // starting position depends on the sequence and interval length
601     int s = _srcList.count() % intervalLength;
602     // Amount of intervals (blocks)
603     int block = _srcList.count() / intervalLength;
604     debugSheets << "Valid interval, number of intervals:" << block;
605 
606     // Start iterating with the first cell
607     Cell cell;
608     int destIndex = 0;
609     if (down)
610         cell = _destList.first();
611     else {
612         cell = _destList.last();
613         destIndex = _destList.count() - 1;
614         block -= (_srcList.count() - 1);
615     }
616 
617     // Fill destination cells
618     //
619     while (!cell.isNull()) {
620         // End of block? -> start again from beginning
621         if (down) {
622             if (s == intervalLength) {
623                 ++block;
624                 s = 0;
625             }
626         } else {
627             if (s == -1) {
628                 s = intervalLength - 1;
629                 ++block;
630             }
631         }
632 
633         debugSheets << "Cell:" << cell.name() << ", position:" << s << ", block:" << block;
634 
635         // Calculate the new value of 'cell' by adding 'block' times the delta to the
636         // value of cell 's'.
637         //
638         Value value;
639         if (down)
640             value = _seqList.value(s)->nextValue(block, deltaSequence.value(s));
641         else
642             value = _seqList.value(s)->prevValue(block, deltaSequence.value(s));
643 
644         // insert the new value
645         //
646         if (_seqList.value(s)->type() == AutoFillSequenceItem::FORMULA) {
647             // Special handling for formulas
648             cell.parseUserInput(cell.decodeFormula(_seqList.value(s)->value().asString()));
649         } else if (value.format() == Value::fmt_Time) {
650             const Value timeValue = cell.sheet()->map()->converter()->asTime(value);
651             cell.setValue(timeValue);
652             cell.setUserInput(cell.sheet()->map()->converter()->asString(timeValue).asString());
653         } else if (value.format() == Value::fmt_Date) {
654             const Value dateValue = cell.sheet()->map()->converter()->asDate(value);
655             cell.setValue(dateValue);
656             cell.setUserInput(cell.sheet()->map()->converter()->asString(dateValue).asString());
657         } else if (value.type() == Value::Boolean ||
658                    value.type() == Value::Complex ||
659                    value.type() == Value::Float ||
660                    value.type() == Value::Integer) {
661             cell.setValue(value);
662             cell.setUserInput(cell.sheet()->map()->converter()->asString(value).asString());
663         } else { // if (value.type() == Value::String)
664             QRegExp number("(\\d+)");
665             int pos = number.indexIn(value.asString());
666             if (pos != -1) {
667                 const int num = number.cap(1).toInt() + 1;
668                 cell.parseUserInput(value.asString().replace(number, QString::number(num)));
669             } else if (!_srcList.at(s).link().isEmpty()) {
670                 cell.parseUserInput(value.asString());
671                 cell.setLink(_srcList.at(s).link());
672             } else {
673                 cell.setValue(value);
674                 cell.setUserInput(value.asString());
675             }
676         }
677 
678         // copy the style of the source cell
679         //
680         cell.copyFormat(_srcList.at(s));
681 
682         // next/previous cell
683         if (down) {
684             cell = _destList.value(++destIndex);
685             ++s;
686         } else {
687             cell = _destList.value(--destIndex);
688             --s;
689         }
690     }
691 }
692 
693 
694 /**********************************************************************************
695  *
696  * AutoFillCommand
697  *
698  **********************************************************************************/
699 
AutoFillCommand()700 AutoFillCommand::AutoFillCommand()
701 {
702     setText(kundo2_i18n("Autofill"));
703 }
704 
~AutoFillCommand()705 AutoFillCommand::~AutoFillCommand()
706 {
707 }
708 
setSourceRange(const QRect & range)709 void AutoFillCommand::setSourceRange(const QRect& range)
710 {
711     m_sourceRange = range;
712 }
713 
setTargetRange(const QRect & range)714 void AutoFillCommand::setTargetRange(const QRect& range)
715 {
716     m_targetRange = range;
717 }
718 
mainProcessing()719 bool AutoFillCommand::mainProcessing()
720 {
721     if (m_sourceRange.contains(m_targetRange))
722         return false;
723 
724     if (m_reverse) {
725         // reverse - use the stored value
726         AbstractDataManipulator::mainProcessing();
727         return true;
728     }
729 
730     // Fill from left to right
731     if (m_sourceRange.left() == m_targetRange.left() && m_sourceRange.right() < m_targetRange.right()) {
732         for (int y = m_sourceRange.top(); y <= m_sourceRange.bottom(); ++y) {
733             int x;
734             QList<Cell> destList;
735             for (x = m_sourceRange.right() + 1; x <= m_targetRange.right(); ++x)
736                 destList.append(Cell(m_sheet, x, y));
737             QList<Cell> srcList;
738             for (x = m_sourceRange.left(); x <= m_sourceRange.right(); ++x)
739                 srcList.append(Cell(m_sheet, x, y));
740             AutoFillSequence seqList;
741             for (x = m_sourceRange.left(); x <= m_sourceRange.right(); ++x)
742                 seqList.append(new AutoFillSequenceItem(Cell(m_sheet, x, y)));
743             fillSequence(srcList, destList, seqList);
744             qDeleteAll(seqList);
745         }
746     }
747 
748     // Fill from top to bottom
749     if (m_sourceRange.top() == m_targetRange.top() && m_sourceRange.bottom() < m_targetRange.bottom()) {
750         for (int x = m_sourceRange.left(); x <= m_targetRange.right(); ++x) {
751             int y;
752             QList<Cell> destList;
753             for (y = m_sourceRange.bottom() + 1; y <= m_targetRange.bottom(); ++y)
754                 destList.append(Cell(m_sheet, x, y));
755             QList<Cell> srcList;
756             for (y = m_sourceRange.top(); y <= m_sourceRange.bottom(); ++y)
757                 srcList.append(Cell(m_sheet, x, y));
758             AutoFillSequence seqList;
759             for (y = m_sourceRange.top(); y <= m_sourceRange.bottom(); ++y)
760                 seqList.append(new AutoFillSequenceItem(Cell(m_sheet, x, y)));
761             fillSequence(srcList, destList, seqList);
762             qDeleteAll(seqList);
763         }
764     }
765 
766     // Fill from right to left
767     if (m_sourceRange.left() == m_targetRange.right() && m_sourceRange.right() >= m_targetRange.right()) {
768         for (int y = m_targetRange.top(); y <= m_targetRange.bottom(); ++y) {
769             int x;
770             QList<Cell> destList;
771             for (x = m_targetRange.left(); x < m_sourceRange.left(); ++x)
772                 destList.append(Cell(m_sheet, x, y));
773             QList<Cell> srcList;
774             for (x = m_sourceRange.left(); x <= m_sourceRange.right(); ++x)
775                 srcList.append(Cell(m_sheet, x, y));
776             AutoFillSequence seqList;
777             for (x = m_sourceRange.left(); x <= m_sourceRange.right(); ++x)
778                 seqList.append(new AutoFillSequenceItem(Cell(m_sheet, x, y)));
779             fillSequence(srcList, destList, seqList, false);
780             qDeleteAll(seqList);
781         }
782     }
783 
784     // Fill from bottom to top
785     if (m_sourceRange.top() == m_targetRange.bottom() && m_sourceRange.bottom() >= m_targetRange.bottom()) {
786         const int startVal = qMin(m_targetRange.left(), m_sourceRange.left());
787         const int endVal = qMax(m_sourceRange.right(), m_targetRange.right());
788         for (int x = startVal; x <= endVal; ++x) {
789             int y;
790             QList<Cell> destList;
791             for (y = m_targetRange.top(); y < m_sourceRange.top(); ++y)
792                 destList.append(Cell(m_sheet, x, y));
793             QList<Cell> srcList;
794             for (y = m_sourceRange.top(); y <= m_sourceRange.bottom(); ++y)
795                 srcList.append(Cell(m_sheet, x, y));
796             AutoFillSequence seqList;
797             for (y = m_sourceRange.top(); y <= m_sourceRange.bottom(); ++y)
798                 seqList.append(new AutoFillSequenceItem(Cell(m_sheet, x, y)));
799             fillSequence(srcList, destList, seqList, false);
800             qDeleteAll(seqList);
801         }
802     }
803     return true;
804 }
805 
fillSequence(const QList<Cell> & _srcList,const QList<Cell> & _destList,const AutoFillSequence & _seqList,bool down)806 void AutoFillCommand::fillSequence(const QList<Cell>& _srcList,
807                                    const QList<Cell>& _destList,
808                                    const AutoFillSequence& _seqList,
809                                    bool down)
810 {
811     if (_srcList.isEmpty() || _destList.isEmpty())
812         return;
813 
814     // find an interval to use to fill the sequence
815     QList<Value> deltaSequence;
816 
817     //If we only have a single cell, the interval will depend upon the data type.
818     //- For numeric values, set the interval to 0 as we don't know what might be useful as a sequence
819     //- For time values, set the interval to one hour, as this will probably be the most useful setting
820     //- For date values, set the interval to one day, as this will probably be the most useful setting
821     //
822     //Note that the above options were chosen for consistency with Excel.  Gnumeric (1.59) sets
823     //the interval to 0 for all types, OpenOffice.org (2.00) uses increments of 1.00, 1 hour and 1 day
824     //respectively
825     if (_srcList.count() == 1) {
826         const Cell cell = _srcList.value(0);
827         if (cell.isTime() || cell.value().format() == Value::fmt_DateTime) {
828             // TODO Stefan: delta depending on minimum unit of format
829             deltaSequence.append(Value(QTime(1, 0)));
830         } else if (cell.isDate()) {
831             // TODO Stefan: delta depending on minimum unit of format
832             Value value(1);
833             value.setFormat(Value::fmt_Date);
834             deltaSequence.append(value);
835         } else
836             deltaSequence.append(Value());
837     } else
838         deltaSequence = findInterval(_seqList);
839 
840     // fill the sequence
841     ::fillSequence(_srcList, _destList, _seqList, deltaSequence, down);
842 }
843