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