File indexing completed on 2024-05-12 16:35:10
0001 /* This file is part of the KDE project 0002 Copyright 2006-2007 Stefan Nikolaus <stefan.nikolaus@kdemail.net> 0003 Copyright 2005 Raphael Langerhorst <raphael.langerhorst@kdemail.net> 0004 Copyright 2002-2004 Ariya Hidayat <ariya@kde.org> 0005 Copyright 2002-2003 Norbert Andres <nandres@web.de> 0006 Copyright 2002 John Dailey <dailey@vt.edu> 0007 Copyright 2001-2002 Philipp Mueller <philipp.mueller@gmx.de> 0008 Copyright 2000-2002 Laurent Montel <montel@kde.org> 0009 Copyright 2000-2001 Werner Trobin <trobin@kde.org> 0010 Copyright 1999-2001 David Faure <faure@kde.org> 0011 Copyright 1998-2000 Torben Weis <weis@kde.org> 0012 Copyright 1998-1999 Stephan Kulow <coolo@kde.org> 0013 Copyright 1998 Reginald Stadlbauer <reggie@kde.org> 0014 0015 This library is free software; you can redistribute it and/or 0016 modify it under the terms of the GNU Library General Public 0017 License as published by the Free Software Foundation; either 0018 version 2 of the License, or (at your option) any later version. 0019 0020 This library is distributed in the hope that it will be useful, 0021 but WITHOUT ANY WARRANTY; without even the implied warranty of 0022 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 0023 Library General Public License for more details. 0024 0025 You should have received a copy of the GNU Library General Public License 0026 along with this library; see the file COPYING.LIB. If not, write to 0027 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 0028 Boston, MA 02110-1301, USA. 0029 */ 0030 0031 #include "AutoFillCommand.h" 0032 0033 #include "Localization.h" 0034 #include "Map.h" 0035 #include "Sheet.h" 0036 #include "Value.h" 0037 #include "ValueConverter.h" 0038 #include "SheetsDebug.h" 0039 0040 #include <KSharedConfig> 0041 #include <kconfig.h> 0042 #include <kconfiggroup.h> 0043 0044 #include <QList> 0045 #include <QRegExp> 0046 0047 #include <math.h> 0048 0049 using namespace Calligra::Sheets; 0050 0051 QStringList *AutoFillCommand::month = 0; 0052 QStringList *AutoFillCommand::shortMonth = 0; 0053 QStringList *AutoFillCommand::day = 0; 0054 QStringList *AutoFillCommand::shortDay = 0; 0055 QStringList *AutoFillCommand::other = 0; 0056 0057 /********************************************************************************** 0058 * 0059 * AutoFillSequenceItem 0060 * 0061 **********************************************************************************/ 0062 0063 namespace Calligra 0064 { 0065 namespace Sheets 0066 { 0067 /** 0068 * A cell content for auto-filling. 0069 */ 0070 class AutoFillSequenceItem 0071 { 0072 public: 0073 enum Type { VALUE, FORMULA, DAY, SHORTDAY, MONTH, SHORTMONTH, OTHER }; 0074 0075 explicit AutoFillSequenceItem(const Cell& cell); 0076 0077 Value delta(AutoFillSequenceItem *_seq, bool *ok) const; 0078 0079 Value nextValue(int _no, Value _delta) const; 0080 Value prevValue(int _no, Value _delta) const; 0081 0082 Type type() const { 0083 return m_type; 0084 } 0085 Value value() const { 0086 return m_value; 0087 } 0088 int otherEnd() const { 0089 return m_otherEnd; 0090 } 0091 int otherBegin() const { 0092 return m_otherBegin; 0093 } 0094 0095 protected: 0096 Value m_value; 0097 Type m_type; 0098 int m_otherBegin; 0099 int m_otherEnd; 0100 }; 0101 0102 } // namespace Sheets 0103 } // namespace Calligra 0104 0105 0106 AutoFillSequenceItem::AutoFillSequenceItem(const Cell& cell) 0107 : m_value() 0108 , m_type(VALUE) 0109 , m_otherBegin(0) 0110 , m_otherEnd(0) 0111 { 0112 if (cell.isFormula()) { 0113 m_value = Value(cell.encodeFormula()); 0114 m_type = FORMULA; 0115 } else if (cell.isDate()) { 0116 m_value = cell.sheet()->map()->converter()->asDate(cell.value()); 0117 m_type = VALUE; 0118 } else if (cell.isTime() || cell.value().format() == Value::fmt_DateTime) { 0119 m_value = cell.sheet()->map()->converter()->asDateTime(cell.value()); 0120 m_type = VALUE; 0121 } else if (cell.value().isNumber()) { 0122 m_value = cell.value(); 0123 m_type = VALUE; 0124 } else { 0125 m_value = cell.value(); 0126 m_type = VALUE; 0127 0128 if (AutoFillCommand::month == 0) { 0129 AutoFillCommand::month = new QStringList(); 0130 AutoFillCommand::month->append(i18n("January")); 0131 AutoFillCommand::month->append(i18n("February")); 0132 AutoFillCommand::month->append(i18n("March")); 0133 AutoFillCommand::month->append(i18n("April")); 0134 AutoFillCommand::month->append(i18n("May")); 0135 AutoFillCommand::month->append(i18n("June")); 0136 AutoFillCommand::month->append(i18n("July")); 0137 AutoFillCommand::month->append(i18n("August")); 0138 AutoFillCommand::month->append(i18n("September")); 0139 AutoFillCommand::month->append(i18n("October")); 0140 AutoFillCommand::month->append(i18n("November")); 0141 AutoFillCommand::month->append(i18n("December")); 0142 } 0143 0144 if (AutoFillCommand::shortMonth == 0) { 0145 AutoFillCommand::shortMonth = new QStringList(); 0146 AutoFillCommand::shortMonth->append(i18n("Jan")); 0147 AutoFillCommand::shortMonth->append(i18n("Feb")); 0148 AutoFillCommand::shortMonth->append(i18n("Mar")); 0149 AutoFillCommand::shortMonth->append(i18n("Apr")); 0150 AutoFillCommand::shortMonth->append(i18nc("May short", "May")); 0151 AutoFillCommand::shortMonth->append(i18n("Jun")); 0152 AutoFillCommand::shortMonth->append(i18n("Jul")); 0153 AutoFillCommand::shortMonth->append(i18n("Aug")); 0154 AutoFillCommand::shortMonth->append(i18n("Sep")); 0155 AutoFillCommand::shortMonth->append(i18n("Oct")); 0156 AutoFillCommand::shortMonth->append(i18n("Nov")); 0157 AutoFillCommand::shortMonth->append(i18n("Dec")); 0158 } 0159 0160 if (AutoFillCommand::day == 0) { 0161 AutoFillCommand::day = new QStringList(); 0162 AutoFillCommand::day->append(i18n("Monday")); 0163 AutoFillCommand::day->append(i18n("Tuesday")); 0164 AutoFillCommand::day->append(i18n("Wednesday")); 0165 AutoFillCommand::day->append(i18n("Thursday")); 0166 AutoFillCommand::day->append(i18n("Friday")); 0167 AutoFillCommand::day->append(i18n("Saturday")); 0168 AutoFillCommand::day->append(i18n("Sunday")); 0169 } 0170 0171 if (AutoFillCommand::shortDay == 0) { 0172 AutoFillCommand::shortDay = new QStringList(); 0173 AutoFillCommand::shortDay->append(i18n("Mon")); 0174 AutoFillCommand::shortDay->append(i18n("Tue")); 0175 AutoFillCommand::shortDay->append(i18n("Wed")); 0176 AutoFillCommand::shortDay->append(i18n("Thu")); 0177 AutoFillCommand::shortDay->append(i18n("Fri")); 0178 AutoFillCommand::shortDay->append(i18n("Sat")); 0179 AutoFillCommand::shortDay->append(i18n("Sun")); 0180 } 0181 0182 if (AutoFillCommand::other == 0) { 0183 // AutoFillCommand::other = new QStringList(); 0184 KSharedConfigPtr config = KSharedConfig::openConfig(); 0185 AutoFillCommand::other = new QStringList(config->group("Parameters").readEntry("Other list", QStringList())); 0186 } 0187 0188 if (AutoFillCommand::month->contains(m_value.asString())) { 0189 m_type = MONTH; 0190 return; 0191 } 0192 0193 if (AutoFillCommand::shortMonth->contains(m_value.asString())) { 0194 m_type = SHORTMONTH; 0195 return; 0196 } 0197 0198 if (AutoFillCommand::day->contains(m_value.asString())) { 0199 m_type = DAY; 0200 return; 0201 } 0202 0203 if (AutoFillCommand::shortDay->contains(m_value.asString())) { 0204 m_type = SHORTDAY; 0205 return; 0206 } 0207 0208 if (AutoFillCommand::other->contains(m_value.asString())) { 0209 m_type = OTHER; 0210 int index = AutoFillCommand::other->indexOf(m_value.asString()); 0211 int otherBegin = AutoFillCommand::other->lastIndexOf("\\", index); // backward 0212 int otherEnd = AutoFillCommand::other->indexOf("\\", index); // forward 0213 m_otherBegin = (otherBegin != -1) ? otherBegin : 0; 0214 m_otherEnd = (otherEnd != -1) ? otherEnd : AutoFillCommand::other->count(); 0215 return; 0216 } 0217 } 0218 } 0219 0220 Value AutoFillSequenceItem::delta(AutoFillSequenceItem *seq, bool *ok) const 0221 { 0222 if (seq->type() != m_type) { 0223 *ok = false; 0224 return Value(); 0225 } 0226 0227 *ok = true; 0228 0229 switch (m_type) { 0230 case VALUE: 0231 case FORMULA: { 0232 switch (m_value.type()) { 0233 case Value::Boolean: { 0234 // delta indicates a flipping of the boolean 0235 if (seq->value().type() != Value::Boolean) 0236 *ok = false; 0237 return Value(seq->value().asBoolean() != m_value.asBoolean()); 0238 } 0239 case Value::Integer: { 0240 if (seq->value().type() == Value::Empty) 0241 *ok = false; 0242 Value value(seq->value().asInteger() - m_value.asInteger()); 0243 value.setFormat(m_value.format()); // may be a date format 0244 return value; 0245 } 0246 case Value::Float: { 0247 if (seq->value().type() == Value::Empty) 0248 *ok = false; 0249 Value value(seq->value().asFloat() - m_value.asFloat()); 0250 value.setFormat(m_value.format()); // may be a time format 0251 return value; 0252 } 0253 case Value::Complex: { 0254 if (seq->value().type() == Value::Empty) 0255 *ok = false; 0256 return Value(seq->value().asComplex() - m_value.asComplex()); 0257 } 0258 case Value::Empty: 0259 case Value::String: 0260 case Value::Array: 0261 case Value::CellRange: 0262 case Value::Error: { 0263 *ok = (m_value == seq->value()); 0264 return Value(); 0265 } 0266 } 0267 } 0268 case MONTH: { 0269 const int i = AutoFillCommand::month->indexOf(m_value.asString()); 0270 const int j = AutoFillCommand::month->indexOf(seq->value().asString()); 0271 return Value(j - i); 0272 } 0273 case SHORTMONTH: { 0274 const int i = AutoFillCommand::shortMonth->indexOf(m_value.asString()); 0275 const int j = AutoFillCommand::shortMonth->indexOf(seq->value().asString()); 0276 return Value(j - i); 0277 } 0278 case DAY: { 0279 const int i = AutoFillCommand::day->indexOf(m_value.asString()); 0280 const int j = AutoFillCommand::day->indexOf(seq->value().asString()); 0281 return Value(j - i); 0282 } 0283 case SHORTDAY: { 0284 const int i = AutoFillCommand::shortDay->indexOf(m_value.asString()); 0285 const int j = AutoFillCommand::shortDay->indexOf(seq->value().asString()); 0286 return Value(j - i); 0287 } 0288 case OTHER: { 0289 *ok = (m_otherEnd != seq->otherEnd() || m_otherBegin != seq->otherBegin()); 0290 const int i = AutoFillCommand::other->indexOf(m_value.asString()); 0291 const int j = AutoFillCommand::other->indexOf(seq->value().asString()); 0292 int k = j; 0293 if (j < i) 0294 k += (m_otherEnd - m_otherBegin - 1); 0295 /* if (j + 1 == i) 0296 return -1.0; 0297 else*/ 0298 return Value(k - i); 0299 } 0300 default: 0301 *ok = false; 0302 } 0303 return Value(); 0304 } 0305 0306 Value AutoFillSequenceItem::nextValue(int _no, Value _delta) const 0307 { 0308 switch (m_type) { 0309 case VALUE: 0310 case FORMULA: { 0311 if (m_value.isBoolean()) { 0312 if (!_delta.asBoolean() || _delta.isEmpty()) // no change? 0313 return m_value; 0314 return Value((_no % 2) ? !m_value.asBoolean() : m_value.asBoolean()); 0315 } else if (m_value.isInteger()) { 0316 Value value(m_value.asInteger() + _no * _delta.asInteger()); 0317 value.setFormat(_delta.format()); 0318 return value; 0319 } else if (m_value.isFloat()) { 0320 Value value(m_value.asFloat() + (long double)_no * _delta.asFloat()); 0321 value.setFormat(_delta.format()); 0322 return value; 0323 } else if (m_value.isComplex()) { 0324 Value value(m_value.asComplex() + (long double)_no * _delta.asComplex()); 0325 value.setFormat(_delta.format()); 0326 return value; 0327 } else // string or empty 0328 return m_value; 0329 } 0330 case MONTH: { 0331 int i = AutoFillCommand::month->indexOf(m_value.asString()); 0332 int j = i + _no * _delta.asInteger(); 0333 while (j < 0) 0334 j += AutoFillCommand::month->count(); 0335 int k = j % AutoFillCommand::month->count(); 0336 return Value(AutoFillCommand::month->at(k)); 0337 } 0338 case SHORTMONTH: { 0339 int i = AutoFillCommand::shortMonth->indexOf(m_value.asString()); 0340 int j = i + _no * _delta.asInteger(); 0341 while (j < 0) 0342 j += AutoFillCommand::shortMonth->count(); 0343 int k = j % AutoFillCommand::shortMonth->count(); 0344 return Value(AutoFillCommand::shortMonth->at(k)); 0345 } 0346 case DAY: { 0347 int i = AutoFillCommand::day->indexOf(m_value.asString()); 0348 int j = i + _no * _delta.asInteger(); 0349 while (j < 0) 0350 j += AutoFillCommand::day->count(); 0351 int k = j % AutoFillCommand::day->count(); 0352 return Value(AutoFillCommand::day->at(k)); 0353 } 0354 case SHORTDAY: { 0355 int i = AutoFillCommand::shortDay->indexOf(m_value.asString()); 0356 int j = i + _no * _delta.asInteger(); 0357 while (j < 0) 0358 j += AutoFillCommand::shortDay->count(); 0359 int k = j % AutoFillCommand::shortDay->count(); 0360 return Value(AutoFillCommand::shortDay->at(k)); 0361 } 0362 case OTHER: { 0363 int i = AutoFillCommand::other->indexOf(m_value.asString()) - (m_otherBegin + 1); 0364 int j = i + _no * _delta.asInteger(); 0365 int k = j % (m_otherEnd - m_otherBegin - 1); 0366 return Value(AutoFillCommand::other->at((k + m_otherBegin + 1))); 0367 } 0368 default: 0369 break; 0370 } 0371 return Value(); 0372 } 0373 0374 Value AutoFillSequenceItem::prevValue(int _no, Value _delta) const 0375 { 0376 switch (m_type) { 0377 case VALUE: 0378 case FORMULA: { 0379 if (m_value.isBoolean()) { 0380 if (!_delta.asBoolean() || _delta.isEmpty()) // no change? 0381 return m_value; 0382 return Value((_no % 2) ? !m_value.asBoolean() : m_value.asBoolean()); 0383 } else if (m_value.isInteger()) { 0384 Value value(m_value.asInteger() - _no * _delta.asInteger()); 0385 value.setFormat(_delta.format()); 0386 return value; 0387 } else if (m_value.isFloat()) { 0388 Value value(m_value.asFloat() - (long double)_no * _delta.asFloat()); 0389 value.setFormat(_delta.format()); 0390 return value; 0391 } else if (m_value.isComplex()) { 0392 Value value(m_value.asComplex() - (long double)_no * _delta.asComplex()); 0393 value.setFormat(_delta.format()); 0394 return value; 0395 } else // string or empty 0396 return m_value; 0397 } 0398 case MONTH: { 0399 int i = AutoFillCommand::month->indexOf(m_value.asString()); 0400 int j = i - _no * _delta.asInteger(); 0401 while (j < 0) 0402 j += AutoFillCommand::month->count(); 0403 int k = j % AutoFillCommand::month->count(); 0404 return Value(AutoFillCommand::month->at(k)); 0405 } 0406 case SHORTMONTH: { 0407 int i = AutoFillCommand::shortMonth->indexOf(m_value.asString()); 0408 int j = i - _no * _delta.asInteger(); 0409 while (j < 0) 0410 j += AutoFillCommand::shortMonth->count(); 0411 int k = j % AutoFillCommand::shortMonth->count(); 0412 return Value(AutoFillCommand::shortMonth->at(k)); 0413 } 0414 case DAY: { 0415 int i = AutoFillCommand::day->indexOf(m_value.asString()); 0416 int j = i - _no * _delta.asInteger(); 0417 while (j < 0) 0418 j += AutoFillCommand::day->count(); 0419 int k = j % AutoFillCommand::day->count(); 0420 return Value(AutoFillCommand::day->at(k)); 0421 } 0422 case SHORTDAY: { 0423 int i = AutoFillCommand::shortDay->indexOf(m_value.asString()); 0424 int j = i - _no * _delta.asInteger(); 0425 while (j < 0) 0426 j += AutoFillCommand::shortDay->count(); 0427 int k = j % AutoFillCommand::shortDay->count(); 0428 return Value(AutoFillCommand::shortDay->at(k)); 0429 } 0430 case OTHER: { 0431 int i = AutoFillCommand::other->indexOf(m_value.asString()) - (m_otherBegin + 1); 0432 int j = i - _no * _delta.asInteger(); 0433 while (j < 0) 0434 j += (m_otherEnd - m_otherBegin - 1); 0435 int k = j % (m_otherEnd - m_otherBegin - 1); 0436 return Value(AutoFillCommand::other->at((k + m_otherBegin + 1))); 0437 } 0438 default: 0439 break; 0440 } 0441 return Value(); 0442 } 0443 0444 0445 /********************************************************************************** 0446 * 0447 * AutoFillSequence 0448 * 0449 **********************************************************************************/ 0450 0451 namespace Calligra 0452 { 0453 namespace Sheets 0454 { 0455 /** 0456 * A sequence of cell contents for auto-filling. 0457 */ 0458 class AutoFillSequence : public QList<AutoFillSequenceItem*> 0459 { 0460 public: 0461 AutoFillSequence(); 0462 AutoFillSequence(const QList<AutoFillSequenceItem*>&); 0463 ~AutoFillSequence(); 0464 0465 QList<Value> createDeltaSequence(int intervalLength) const; 0466 }; 0467 0468 } // namespace Sheets 0469 } // namespace Calligra 0470 0471 AutoFillSequence::AutoFillSequence() 0472 { 0473 } 0474 0475 AutoFillSequence::AutoFillSequence(const QList<AutoFillSequenceItem*>& list) 0476 : QList<AutoFillSequenceItem*>(list) 0477 { 0478 } 0479 0480 AutoFillSequence::~AutoFillSequence() 0481 { 0482 } 0483 0484 QList<Value> AutoFillSequence::createDeltaSequence(int intervalLength) const 0485 { 0486 bool ok = true; 0487 QList<Value> deltaSequence; 0488 0489 // Guess the delta by looking at cells 0...2*intervalLength-1 0490 // 0491 // Since the interval may be of length 'intervalLength' we calculate the delta 0492 // between cells 0 and intervalLength, 1 and intervalLength+1, ...., intervalLength-1 and 2*intervalLength-1. 0493 for (int t = 0; t < intervalLength /*&& t + intervalLength < count()*/; ++t) { 0494 deltaSequence.append(value(t)->delta(value((t + intervalLength) % count()), &ok)); 0495 if (!ok) 0496 return QList<Value>(); 0497 } 0498 0499 // fill to the interval length 0500 while (deltaSequence.count() < intervalLength) 0501 deltaSequence.append(Value()); 0502 0503 return deltaSequence; 0504 } 0505 0506 0507 /********************************************************************************** 0508 * 0509 * File static helper functions 0510 * 0511 **********************************************************************************/ 0512 0513 static QList<Value> findInterval(const AutoFillSequence& _seqList) 0514 { 0515 // What is the interval (block)? If your sheet looks like this: 0516 // 1 3 5 7 9 0517 // then the interval has the length 1 and the delta list is [2]. 0518 // 2 200 3 300 4 400 0519 // Here the interval has length 2 and the delta list is [1,100] 0520 0521 QList<Value> deltaSequence; 0522 0523 debugSheets << "Sequence length:" << _seqList.count(); 0524 0525 // How big is the interval. It is in the range from [1...n]. 0526 // 0527 // We try to find the shortest interval. 0528 int intervalLength = 1; 0529 for (intervalLength = 1; intervalLength < _seqList.count(); ++intervalLength) { 0530 debugSheets << "Checking interval of length:" << intervalLength; 0531 0532 // Create the delta list. 0533 deltaSequence = _seqList.createDeltaSequence(intervalLength); 0534 0535 QString str("Deltas: [ "); 0536 foreach(const Value &v, deltaSequence) { 0537 if (v.isBoolean()) 0538 str += v.asBoolean() ? "change " : "nochange "; 0539 else if (v.isInteger()) 0540 str += QString::number(v.asInteger()) + ' '; 0541 else if (v.isFloat()) 0542 str += QString::number((double) v.asFloat()) + ' '; 0543 else 0544 str += v.asString() + ' '; 0545 } 0546 str += ']'; 0547 debugSheets << str; 0548 0549 // Verify the delta by looking at cells intervalLength.._seqList.count(). 0550 // We only looked at the cells 0..2*intervalLength-1. 0551 // Now test whether the cells from "(i-1) * intervalLength + s" share the same delta 0552 // with the cell "i * intervalLength + s" for all test=1..._seqList.count()/intervalLength 0553 // and for all s=0...intervalLength-1. 0554 for (int i = 1; (i + 1) * intervalLength < _seqList.count(); ++i) { 0555 AutoFillSequence tail = _seqList.mid(i * intervalLength); 0556 // debugSheets <<"Verifying for sequence after" << i * intervalLength <<", length:" << tail.count(); 0557 QList<Value> otherDeltaSequence = tail.createDeltaSequence(intervalLength); 0558 if (deltaSequence != otherDeltaSequence) { 0559 debugSheets << "Interval does not match."; 0560 deltaSequence.clear(); 0561 break; 0562 } 0563 } 0564 0565 // Did we find a valid interval? 0566 if (!deltaSequence.isEmpty()) 0567 break; 0568 } 0569 0570 // if the full interval has to be taken fill the delta sequence with zeros 0571 if (intervalLength == _seqList.count()) { 0572 while (intervalLength--) 0573 deltaSequence.append(Value()); 0574 0575 QString str("Deltas: [ "); 0576 foreach(const Value &v, deltaSequence) { 0577 if (v.isBoolean()) 0578 str += v.asBoolean() ? "change " : "nochange "; 0579 else if (v.isInteger()) 0580 str += QString::number(v.asInteger()) + ' '; 0581 else if (v.isFloat()) 0582 str += QString::number((double) v.asFloat()) + ' '; 0583 else 0584 str += v.asString() + ' '; 0585 } 0586 str += ']'; 0587 debugSheets << str; 0588 } 0589 0590 return deltaSequence; 0591 } 0592 0593 static void fillSequence(const QList<Cell>& _srcList, 0594 const QList<Cell>& _destList, 0595 const AutoFillSequence& _seqList, 0596 const QList<Value>& deltaSequence, 0597 bool down) 0598 { 0599 const int intervalLength = deltaSequence.count(); 0600 // starting position depends on the sequence and interval length 0601 int s = _srcList.count() % intervalLength; 0602 // Amount of intervals (blocks) 0603 int block = _srcList.count() / intervalLength; 0604 debugSheets << "Valid interval, number of intervals:" << block; 0605 0606 // Start iterating with the first cell 0607 Cell cell; 0608 int destIndex = 0; 0609 if (down) 0610 cell = _destList.first(); 0611 else { 0612 cell = _destList.last(); 0613 destIndex = _destList.count() - 1; 0614 block -= (_srcList.count() - 1); 0615 } 0616 0617 // Fill destination cells 0618 // 0619 while (!cell.isNull()) { 0620 // End of block? -> start again from beginning 0621 if (down) { 0622 if (s == intervalLength) { 0623 ++block; 0624 s = 0; 0625 } 0626 } else { 0627 if (s == -1) { 0628 s = intervalLength - 1; 0629 ++block; 0630 } 0631 } 0632 0633 debugSheets << "Cell:" << cell.name() << ", position:" << s << ", block:" << block; 0634 0635 // Calculate the new value of 'cell' by adding 'block' times the delta to the 0636 // value of cell 's'. 0637 // 0638 Value value; 0639 if (down) 0640 value = _seqList.value(s)->nextValue(block, deltaSequence.value(s)); 0641 else 0642 value = _seqList.value(s)->prevValue(block, deltaSequence.value(s)); 0643 0644 // insert the new value 0645 // 0646 if (_seqList.value(s)->type() == AutoFillSequenceItem::FORMULA) { 0647 // Special handling for formulas 0648 cell.parseUserInput(cell.decodeFormula(_seqList.value(s)->value().asString())); 0649 } else if (value.format() == Value::fmt_Time) { 0650 const Value timeValue = cell.sheet()->map()->converter()->asTime(value); 0651 cell.setValue(timeValue); 0652 cell.setUserInput(cell.sheet()->map()->converter()->asString(timeValue).asString()); 0653 } else if (value.format() == Value::fmt_Date) { 0654 const Value dateValue = cell.sheet()->map()->converter()->asDate(value); 0655 cell.setValue(dateValue); 0656 cell.setUserInput(cell.sheet()->map()->converter()->asString(dateValue).asString()); 0657 } else if (value.type() == Value::Boolean || 0658 value.type() == Value::Complex || 0659 value.type() == Value::Float || 0660 value.type() == Value::Integer) { 0661 cell.setValue(value); 0662 cell.setUserInput(cell.sheet()->map()->converter()->asString(value).asString()); 0663 } else { // if (value.type() == Value::String) 0664 QRegExp number("(\\d+)"); 0665 int pos = number.indexIn(value.asString()); 0666 if (pos != -1) { 0667 const int num = number.cap(1).toInt() + 1; 0668 cell.parseUserInput(value.asString().replace(number, QString::number(num))); 0669 } else if (!_srcList.at(s).link().isEmpty()) { 0670 cell.parseUserInput(value.asString()); 0671 cell.setLink(_srcList.at(s).link()); 0672 } else { 0673 cell.setValue(value); 0674 cell.setUserInput(value.asString()); 0675 } 0676 } 0677 0678 // copy the style of the source cell 0679 // 0680 cell.copyFormat(_srcList.at(s)); 0681 0682 // next/previous cell 0683 if (down) { 0684 cell = _destList.value(++destIndex); 0685 ++s; 0686 } else { 0687 cell = _destList.value(--destIndex); 0688 --s; 0689 } 0690 } 0691 } 0692 0693 0694 /********************************************************************************** 0695 * 0696 * AutoFillCommand 0697 * 0698 **********************************************************************************/ 0699 0700 AutoFillCommand::AutoFillCommand() 0701 { 0702 setText(kundo2_i18n("Autofill")); 0703 } 0704 0705 AutoFillCommand::~AutoFillCommand() 0706 { 0707 } 0708 0709 void AutoFillCommand::setSourceRange(const QRect& range) 0710 { 0711 m_sourceRange = range; 0712 } 0713 0714 void AutoFillCommand::setTargetRange(const QRect& range) 0715 { 0716 m_targetRange = range; 0717 } 0718 0719 bool AutoFillCommand::mainProcessing() 0720 { 0721 if (m_sourceRange.contains(m_targetRange)) 0722 return false; 0723 0724 if (m_reverse) { 0725 // reverse - use the stored value 0726 AbstractDataManipulator::mainProcessing(); 0727 return true; 0728 } 0729 0730 // Fill from left to right 0731 if (m_sourceRange.left() == m_targetRange.left() && m_sourceRange.right() < m_targetRange.right()) { 0732 for (int y = m_sourceRange.top(); y <= m_sourceRange.bottom(); ++y) { 0733 int x; 0734 QList<Cell> destList; 0735 for (x = m_sourceRange.right() + 1; x <= m_targetRange.right(); ++x) 0736 destList.append(Cell(m_sheet, x, y)); 0737 QList<Cell> srcList; 0738 for (x = m_sourceRange.left(); x <= m_sourceRange.right(); ++x) 0739 srcList.append(Cell(m_sheet, x, y)); 0740 AutoFillSequence seqList; 0741 for (x = m_sourceRange.left(); x <= m_sourceRange.right(); ++x) 0742 seqList.append(new AutoFillSequenceItem(Cell(m_sheet, x, y))); 0743 fillSequence(srcList, destList, seqList); 0744 qDeleteAll(seqList); 0745 } 0746 } 0747 0748 // Fill from top to bottom 0749 if (m_sourceRange.top() == m_targetRange.top() && m_sourceRange.bottom() < m_targetRange.bottom()) { 0750 for (int x = m_sourceRange.left(); x <= m_targetRange.right(); ++x) { 0751 int y; 0752 QList<Cell> destList; 0753 for (y = m_sourceRange.bottom() + 1; y <= m_targetRange.bottom(); ++y) 0754 destList.append(Cell(m_sheet, x, y)); 0755 QList<Cell> srcList; 0756 for (y = m_sourceRange.top(); y <= m_sourceRange.bottom(); ++y) 0757 srcList.append(Cell(m_sheet, x, y)); 0758 AutoFillSequence seqList; 0759 for (y = m_sourceRange.top(); y <= m_sourceRange.bottom(); ++y) 0760 seqList.append(new AutoFillSequenceItem(Cell(m_sheet, x, y))); 0761 fillSequence(srcList, destList, seqList); 0762 qDeleteAll(seqList); 0763 } 0764 } 0765 0766 // Fill from right to left 0767 if (m_sourceRange.left() == m_targetRange.right() && m_sourceRange.right() >= m_targetRange.right()) { 0768 for (int y = m_targetRange.top(); y <= m_targetRange.bottom(); ++y) { 0769 int x; 0770 QList<Cell> destList; 0771 for (x = m_targetRange.left(); x < m_sourceRange.left(); ++x) 0772 destList.append(Cell(m_sheet, x, y)); 0773 QList<Cell> srcList; 0774 for (x = m_sourceRange.left(); x <= m_sourceRange.right(); ++x) 0775 srcList.append(Cell(m_sheet, x, y)); 0776 AutoFillSequence seqList; 0777 for (x = m_sourceRange.left(); x <= m_sourceRange.right(); ++x) 0778 seqList.append(new AutoFillSequenceItem(Cell(m_sheet, x, y))); 0779 fillSequence(srcList, destList, seqList, false); 0780 qDeleteAll(seqList); 0781 } 0782 } 0783 0784 // Fill from bottom to top 0785 if (m_sourceRange.top() == m_targetRange.bottom() && m_sourceRange.bottom() >= m_targetRange.bottom()) { 0786 const int startVal = qMin(m_targetRange.left(), m_sourceRange.left()); 0787 const int endVal = qMax(m_sourceRange.right(), m_targetRange.right()); 0788 for (int x = startVal; x <= endVal; ++x) { 0789 int y; 0790 QList<Cell> destList; 0791 for (y = m_targetRange.top(); y < m_sourceRange.top(); ++y) 0792 destList.append(Cell(m_sheet, x, y)); 0793 QList<Cell> srcList; 0794 for (y = m_sourceRange.top(); y <= m_sourceRange.bottom(); ++y) 0795 srcList.append(Cell(m_sheet, x, y)); 0796 AutoFillSequence seqList; 0797 for (y = m_sourceRange.top(); y <= m_sourceRange.bottom(); ++y) 0798 seqList.append(new AutoFillSequenceItem(Cell(m_sheet, x, y))); 0799 fillSequence(srcList, destList, seqList, false); 0800 qDeleteAll(seqList); 0801 } 0802 } 0803 return true; 0804 } 0805 0806 void AutoFillCommand::fillSequence(const QList<Cell>& _srcList, 0807 const QList<Cell>& _destList, 0808 const AutoFillSequence& _seqList, 0809 bool down) 0810 { 0811 if (_srcList.isEmpty() || _destList.isEmpty()) 0812 return; 0813 0814 // find an interval to use to fill the sequence 0815 QList<Value> deltaSequence; 0816 0817 //If we only have a single cell, the interval will depend upon the data type. 0818 //- For numeric values, set the interval to 0 as we don't know what might be useful as a sequence 0819 //- For time values, set the interval to one hour, as this will probably be the most useful setting 0820 //- For date values, set the interval to one day, as this will probably be the most useful setting 0821 // 0822 //Note that the above options were chosen for consistency with Excel. Gnumeric (1.59) sets 0823 //the interval to 0 for all types, OpenOffice.org (2.00) uses increments of 1.00, 1 hour and 1 day 0824 //respectively 0825 if (_srcList.count() == 1) { 0826 const Cell cell = _srcList.value(0); 0827 if (cell.isTime() || cell.value().format() == Value::fmt_DateTime) { 0828 // TODO Stefan: delta depending on minimum unit of format 0829 deltaSequence.append(Value(QTime(1, 0))); 0830 } else if (cell.isDate()) { 0831 // TODO Stefan: delta depending on minimum unit of format 0832 Value value(1); 0833 value.setFormat(Value::fmt_Date); 0834 deltaSequence.append(value); 0835 } else 0836 deltaSequence.append(Value()); 0837 } else 0838 deltaSequence = findInterval(_seqList); 0839 0840 // fill the sequence 0841 ::fillSequence(_srcList, _destList, _seqList, deltaSequence, down); 0842 }