File indexing completed on 2024-05-19 16:06:25
0001 /* This file is part of the KDE project 0002 0003 Copyright 2008 Johannes Simon <johannes.simon@gmail.com> 0004 Copyright 2008 Inge Wallin <inge@lysator.liu.se> 0005 0006 This library is free software; you can redistribute it and/or 0007 modify it under the terms of the GNU Library General Public 0008 License as published by the Free Software Foundation; either 0009 version 2 of the License, or (at your option) any later version. 0010 0011 This library is distributed in the hope that it will be useful, 0012 but WITHOUT ANY WARRANTY; without even the implied warranty of 0013 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 0014 Library General Public License for more details. 0015 0016 You should have received a copy of the GNU Library General Public License 0017 along with this library; see the file COPYING.LIB. If not, write to 0018 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 0019 * Boston, MA 02110-1301, USA. 0020 */ 0021 0022 0023 // Own 0024 #include "CellRegion.h" 0025 0026 // C 0027 #include <cmath> 0028 0029 // Qt 0030 #include <QPoint> 0031 #include <QRect> 0032 #include <QVector> 0033 #include <QStringList> 0034 0035 // KoChart 0036 #include "TableSource.h" 0037 #include "ChartDebug.h" 0038 0039 0040 using std::pow; 0041 using namespace KoChart; 0042 0043 /************************RegionParser*******************************/ 0044 0045 class Parser 0046 { 0047 public: 0048 Parser(const QString & input) 0049 : m_pos(m_input.constEnd()) 0050 { 0051 m_input = input; 0052 if (m_input.contains(":.")) { 0053 // FIXME 0054 warnChartParse<<"Handle 'DotDoubleDot' in input string"; 0055 m_input.replace(QStringLiteral(":."), QChar(':')); 0056 } 0057 m_delimiter.append(QChar::fromLatin1('.')); 0058 m_delimiter.append(QChar::fromLatin1(':')); 0059 m_delimiter.append(QChar::fromLatin1(';')); 0060 m_delimiter.append(QChar::fromLatin1(' ')); 0061 } 0062 bool parse(); 0063 QList< QRect > getResult() const { return m_result; } 0064 QString tableName() const { return m_tableName; } 0065 0066 private: 0067 struct Token 0068 { 0069 enum TokenType{ Dot = 0, DoubleDot = 1, Space = 2, Spacer = 3, Identifier = 4, End }; 0070 Token(TokenType type, const QString & identifier): m_type(type), m_identifier(identifier){} 0071 Token(): m_type(End) {} 0072 TokenType m_type; 0073 QString m_identifier; 0074 }; 0075 0076 inline Token parseToken(); 0077 inline void eatWhitespaces(); 0078 inline bool parseRegionList(); 0079 inline bool parseRegion(); 0080 inline bool parseName(); 0081 inline bool parseName2(); 0082 inline bool parsePoint(); 0083 inline bool parseRegion2(); 0084 inline void setTableName(const QString &name); 0085 0086 public: 0087 QString toString(Token &token) 0088 { 0089 QString types = "Dot,DoubleDot,Space,Spacer,Identifier,End"; 0090 QString s = QString("Token[%1").arg(types.split(',').value(token.m_type)); 0091 if (token.m_type == Token::Identifier) { 0092 s += ", " + token.m_identifier; 0093 } 0094 s += ']'; 0095 return s; 0096 } 0097 0098 private: 0099 QString m_input; 0100 QString::ConstIterator m_pos; 0101 QList< QRect > m_result; 0102 Token m_currentToken; 0103 QRect m_currentRect; 0104 QPoint m_currentPoint; 0105 QString m_tableName; 0106 int m_index; 0107 QVector< QChar > m_delimiter; 0108 }; 0109 0110 void Parser::setTableName(const QString &name) 0111 { 0112 QString strippedName = name; 0113 if (name.startsWith(QChar::fromLatin1('$'))) 0114 strippedName.remove(0, 1); 0115 if (m_tableName.isEmpty()) 0116 m_tableName = strippedName; 0117 else 0118 if (strippedName != m_tableName) 0119 debugChartParse << "More than one sheet referenced, this is currently not supported"; 0120 } 0121 0122 bool Parser::parse() 0123 { 0124 debugChartParse << "Input " << m_input; 0125 m_pos = m_input.constBegin(); 0126 m_index = 0; 0127 m_currentToken = parseToken(); 0128 return parseRegionList(); 0129 } 0130 0131 Parser::Token Parser::parseToken() 0132 { 0133 Token::TokenType type = Token::End; 0134 if (m_pos != m_input.constEnd()) { 0135 switch(m_delimiter.indexOf(*m_pos)) { 0136 case(0): 0137 type = Token::Dot; 0138 break; 0139 case(1): 0140 type = Token::DoubleDot; 0141 break; 0142 case(2): 0143 case(3): 0144 type = Token::Space; 0145 break; 0146 default: 0147 type = Token::Identifier; 0148 } 0149 } 0150 if (m_index >= m_input.size()) 0151 type = Token::End; 0152 else if (*m_pos == QChar::fromLatin1('$')) { 0153 ++m_pos; 0154 ++m_index; 0155 } 0156 QString identifier; 0157 if (m_pos != m_input.constEnd() && *m_pos == QChar::fromLatin1('\'')) { 0158 ++m_pos; 0159 ++m_index; 0160 int startPos = m_index; 0161 for (; m_pos != m_input.constEnd() && *m_pos != QChar::fromLatin1('\''); ++m_pos, ++m_index) 0162 ; 0163 0164 if (type == Token::Identifier) 0165 identifier = m_input.mid(startPos, m_index - startPos); 0166 if (m_pos != m_input.constEnd()) { 0167 ++m_pos; 0168 ++m_index; 0169 } 0170 } 0171 else { 0172 int startPos = m_index; 0173 for (; m_pos != m_input.constEnd() && !m_delimiter.contains(*m_pos); ++m_pos, ++m_index) 0174 ; 0175 if (m_pos != m_input.constEnd() && startPos == m_index) { 0176 ++m_index; 0177 ++m_pos; 0178 } 0179 if (type == Token::Identifier) 0180 identifier = m_input.mid(startPos, m_index - startPos); 0181 } 0182 0183 Token t(type, identifier); 0184 debugChartParse<<toString(t); 0185 return t; 0186 } 0187 0188 void Parser::eatWhitespaces() 0189 { 0190 for (; m_pos != m_input.constEnd() && *m_pos == QChar::fromLatin1(' '); ++m_pos, ++m_index) 0191 ; 0192 } 0193 0194 bool Parser::parseRegionList() 0195 { 0196 bool res = true; 0197 for (; m_currentToken.m_type != Token::End; m_currentToken = parseToken()) { 0198 if (m_currentToken.m_type != Token::Space) { 0199 if (m_currentToken.m_type == Token::Identifier) 0200 res = parseRegion(); 0201 else 0202 res = false; 0203 } 0204 } 0205 return res; 0206 } 0207 0208 bool Parser::parseRegion() 0209 { 0210 debugChartParse << "parseRegion"; 0211 bool res = true; 0212 res &= parseRegion2(); 0213 m_currentToken = parseToken(); 0214 debugChartParse << "CurrentToken " << m_currentToken.m_identifier << m_currentToken.m_type; 0215 if (m_currentToken.m_type == Token::DoubleDot) { 0216 const QPoint topLeft = m_currentPoint; 0217 m_currentToken = parseToken(); 0218 res &= parseRegion2(); 0219 //m_currentToken = parseToken(); 0220 m_result.append(QRect(topLeft, m_currentPoint)); 0221 debugChartParse << "DoubleDot"<<"result:"<<m_result; 0222 } 0223 else { 0224 m_result.append(QRect(m_currentPoint, m_currentPoint)); 0225 debugChartParse << "NoDoubleDot"<<"result:"<<m_result;; 0226 } 0227 0228 if (m_currentToken.m_type == Token::Space) { 0229 res &= parseRegionList(); 0230 } else if (m_currentToken.m_type == Token::End) { 0231 debugChartParse<<"ParseRegion:"<<res<<toString(m_currentToken)<<m_result;; 0232 return res; 0233 } else { 0234 res = false; 0235 } 0236 debugChartParse<<"ParseRegion:"<<res<<toString(m_currentToken)<<m_result;; 0237 return res; 0238 } 0239 0240 bool Parser::parseRegion2() 0241 { 0242 //debugChart << "ParseRegion2"; 0243 bool res = true; 0244 0245 if (m_currentToken.m_type != Token::Identifier && m_currentToken.m_type != Token::Dot) 0246 res = false; 0247 0248 const QString firstIdentifier = m_currentToken.m_type != Token::Dot ? m_currentToken.m_identifier : tableName(); 0249 if (m_currentToken.m_type != Token::Dot) 0250 m_currentToken = parseToken(); 0251 if (m_currentToken.m_type == Token::Dot) 0252 { 0253 m_currentToken = parseToken(); 0254 if (m_currentToken.m_type == Token::Identifier) 0255 { 0256 QRegExp regEx(QString::fromLatin1("([$]*)([A-Z]+)([$]*)([0-9]+)")); 0257 regEx.exactMatch(m_currentToken.m_identifier); 0258 m_currentPoint = QPoint(CellRegion::rangeStringToInt(regEx.cap(2)), regEx.cap(4).toInt()); 0259 //debugChart << "FUN" << regEx.cap(2) << " " << regEx.cap(4); 0260 setTableName(firstIdentifier); 0261 } 0262 else 0263 res = false; 0264 } 0265 else 0266 { 0267 QRegExp regEx(QString::fromLatin1("([$]*)([A-Z]+)([$]*)([0-9]+)")); 0268 regEx.exactMatch(firstIdentifier); 0269 //debugChart << "FUN" << regEx.cap(2) << " " << regEx.cap(4); 0270 m_currentPoint = QPoint(CellRegion::rangeStringToInt(regEx.cap(2)), regEx.cap(4).toInt()); 0271 } 0272 //debugChart << "TableName "<< m_tableName; 0273 //debugChart << firstIdentifier; 0274 //debugChart << "Point" << m_currentPoint; 0275 //debugChart << m_currentToken.m_identifier; 0276 //debugChart << m_currentToken.m_type; 0277 0278 return res; 0279 0280 } 0281 0282 // bool Parser::parsePoint() 0283 // { 0284 // bool res = true; 0285 // int startIndex = m_index; 0286 // while(m_pos != m_input.end() && *m_pos != QChar::fromLatin1(':')) 0287 // { 0288 // ++m_pos; 0289 // ++m_index; 0290 // } 0291 // const QString currentString = m_input.mid(startIndex, m_index - startIndex); 0292 // debugChart << "PointString" << currentString; 0293 // QRegExp regEx(QString::fromLatin1("[A-Z]+[0-9]+")); 0294 // regEx.indexIn(currentString); 0295 // m_currentPoint = QPoint(CellRegion::rangeStringToInt(regEx.cap(0)), regEx.cap(1).toInt()); 0296 // return res; 0297 // } 0298 /************************ENDRegionParser*******************************/ 0299 0300 static QString columnName(uint column); 0301 //static int rangeCharToInt(char c); 0302 0303 /** 0304 * Makes sure that quotes are added if name contains spaces or special 0305 * characters. May also be used to escape certain characters if needed. 0306 */ 0307 static QString formatTableName(const QString &name) 0308 { 0309 static const QList<QChar> specialChars = 0310 QList<QChar>() << ' ' << '\t' << '-' << '\''; 0311 0312 bool containsSpecialChars = false; 0313 foreach(QChar c, specialChars) 0314 containsSpecialChars = containsSpecialChars || name.contains(c); 0315 0316 if(containsSpecialChars) 0317 return QLatin1Char('\'') + name + QLatin1Char('\''); 0318 0319 return name; 0320 } 0321 0322 /** 0323 * Reverts any operation done by formatTableName(), so that ideally 0324 * unformatTableName(formatTableName(name)) == name 0325 */ 0326 /* currently not used in CellRegion(TableSource *source, const QString& regions) 0327 static QString unformatTableName(QString name) 0328 { 0329 if (name.startsWith(QLatin1Char('\'')) && name.endsWith(QLatin1Char('\''))) { 0330 name.remove(0, 1).chop(1); 0331 } 0332 0333 return name; 0334 } 0335 */ 0336 class CellRegion::Private 0337 { 0338 public: 0339 Private(); 0340 ~Private(); 0341 0342 QString pointToString(const QPoint &point) const; 0343 0344 // These are actually one-dimensional, but can have different 0345 // orientations (hor / vert). 0346 QVector<QRect> rects; 0347 0348 QRect boundingRect; 0349 // NOTE: Don't forget to extend operator=() if you add new members 0350 0351 /// Table this region is in (name/model pair provided by TableSource) 0352 Table *table; 0353 }; 0354 0355 0356 CellRegion::Private::Private() 0357 { 0358 table = 0; 0359 } 0360 0361 CellRegion::Private::~Private() 0362 { 0363 } 0364 0365 0366 // ================================================================ 0367 // Class CellRegion 0368 0369 0370 CellRegion::CellRegion() 0371 : d(new Private()) 0372 { 0373 } 0374 0375 CellRegion::CellRegion(const CellRegion ®ion) 0376 : d(new Private()) 0377 { 0378 // Use operator=(); 0379 *this = region; 0380 } 0381 0382 CellRegion::CellRegion(TableSource *source, const QString& regions) 0383 : d(new Private()) 0384 { 0385 // A dollar sign before a part of the address means that this part 0386 // is absolute. This is irrelevant for us, however, thus we can remove 0387 // all occurrences of '$', and handle relative and absolute addresses in 0388 // the same way. 0389 // See ODF specs $8.3.1 "Referencing Table Cells" 0390 Parser parser(regions); 0391 const bool success = parser.parse(); 0392 if (!success) 0393 warnChart << "Parsing cell region failed:"<<regions; 0394 0395 QVector<QRect> rects = parser.getResult().toVector(); 0396 for (int i = 0; i < rects.count(); ++i) { 0397 add(rects.at(i)); 0398 } 0399 d->table = source->get(parser.tableName()); 0400 // QStringList regionsList = regions.split(' ', QString::SkipEmptyParts); 0401 // Q_FOREACH(const QString& region, regionsList) { 0402 // QString searchStr = QString(region).remove('$'); 0403 // QRegExp regEx; 0404 // 0405 // QStringList regionList = searchStr.split(';'); 0406 // Q_FOREACH(const QString ®ion, regionList) { 0407 // const bool isPoint = !region.contains(':'); 0408 // if (isPoint) 0409 // regEx = QRegExp("(|.*\\.)([A-Z]+)([0-9]+)"); 0410 // else // support range-notations like Sheet1.D2:Sheet1.F2 Sheet1.D2:F2 D2:F2 0411 // regEx = QRegExp ("(|.*\\.)([A-Z]+)([0-9]+)\\:(|.*\\.)([A-Z]+)([0-9]+)"); 0412 // 0413 // // Check if region string is valid (e.g. not empty) 0414 // if (regEx.indexIn(region) >= 0) { 0415 // // It is possible for a cell-range-address as defined in ODF to contain 0416 // // refernces to cells of more than one sheet. This, however, we ignore 0417 // // here. We do not support more than one table in a cell region. 0418 // // Also we do not support regions spanned over different sheets. For us 0419 // // everything is either on no sheet or on the same sheet. 0420 // QString sheetName = regEx.cap(1); 0421 // if (sheetName.endsWith(".")) 0422 // sheetName = sheetName.left(sheetName.length() - 1); 0423 // // TODO: Support for multiple tables in one region 0424 // d->table = source->get(unformatTableName(sheetName)); 0425 // 0426 // QPoint topLeft(rangeStringToInt(regEx.cap(2)), regEx.cap(3).toInt()); 0427 // if (isPoint) { 0428 // d->rects.append(QRect(topLeft, QSize(1, 1))); 0429 // } else { 0430 // QPoint bottomRight(rangeStringToInt(regEx.cap(5)), regEx.cap(6).toInt()); 0431 // d->rects.append(QRect(topLeft, bottomRight)); 0432 // } 0433 // } 0434 // } 0435 // } 0436 } 0437 0438 CellRegion::CellRegion(Table *table, const QPoint &point) 0439 : d(new Private()) 0440 { 0441 d->table = table; 0442 add(point); 0443 } 0444 0445 CellRegion::CellRegion(Table *table, const QRect &rect) 0446 : d(new Private()) 0447 { 0448 d->table = table; 0449 add(rect); 0450 } 0451 0452 CellRegion::CellRegion(Table *table, const QVector<QRect> &rects) 0453 : d(new Private()) 0454 { 0455 d->table = table; 0456 foreach(const QRect& rect, rects) 0457 add(rect); 0458 } 0459 0460 CellRegion::CellRegion(Table *table) 0461 : d(new Private()) 0462 { 0463 d->table = table; 0464 } 0465 0466 CellRegion::~CellRegion() 0467 { 0468 delete d; 0469 } 0470 0471 0472 CellRegion& CellRegion::operator = (const CellRegion& region) 0473 { 0474 d->rects = region.d->rects; 0475 d->boundingRect = region.d->boundingRect; 0476 d->table = region.d->table; 0477 0478 return *this; 0479 } 0480 0481 bool CellRegion::operator == (const CellRegion &other) const 0482 { 0483 return d->rects == other.d->rects; 0484 } 0485 0486 0487 Table *CellRegion::table() const 0488 { 0489 return d->table; 0490 } 0491 0492 QVector<QRect> CellRegion::rects() const 0493 { 0494 return d->rects; 0495 } 0496 0497 int CellRegion::rectCount() const 0498 { 0499 return d->rects.size(); 0500 } 0501 0502 QString CellRegion::sheetName() const 0503 { 0504 return d->table->name(); 0505 } 0506 0507 bool CellRegion::isValid() const 0508 { 0509 return d->rects.size() > 0 && d->table ; 0510 } 0511 0512 QString CellRegion::Private::pointToString(const QPoint &point) const 0513 { 0514 QString result; 0515 0516 result.append('$' + columnName(point.x())); 0517 result.append('$' + QString::number(point.y())); 0518 0519 return result; 0520 } 0521 0522 QString CellRegion::toString() const 0523 { 0524 if (!isValid()) 0525 return QString(); 0526 0527 QString result; 0528 for (int i = 0; i < d->rects.count(); ++i) { 0529 const QRect range = d->rects[i]; 0530 // Top-left corner 0531 if (table()) 0532 result.append('$' + formatTableName(table()->name()) + '.'); 0533 result.append(d->pointToString(range.topLeft())); 0534 0535 // If it is not a point, append rect's bottom-right corner 0536 if (range.topLeft() != range.bottomRight()) { 0537 result.append(':'); 0538 result.append(d->pointToString(range.bottomRight())); 0539 } 0540 0541 // Separate ranges by a space 0542 // See odf 18.3.6cellRangeAddressList 0543 if (i < d->rects.count() - 1) 0544 result.append(' '); 0545 } 0546 return result; 0547 } 0548 0549 0550 bool CellRegion::contains(const QPoint &point, bool proper) const 0551 { 0552 foreach (const QRect &rect, d->rects) { 0553 if (rect.contains(point, proper)) 0554 return true; 0555 } 0556 0557 return false; 0558 } 0559 0560 bool CellRegion::contains(const QRect &rect, bool proper) const 0561 { 0562 foreach (const QRect &r, d->rects) { 0563 if (r.contains(rect, proper)) 0564 return true; 0565 } 0566 0567 return false; 0568 } 0569 0570 bool CellRegion::intersects(const CellRegion &other) const 0571 { 0572 // If both regions lie within only one table and these tables 0573 // are different, they trivially do not intersect. 0574 if (table() && other.table() && 0575 table() != other.table()) 0576 return false; 0577 0578 foreach (const QRect &r, d->rects) { 0579 foreach(const QRect &_r, other.d->rects) { 0580 if (r.intersects(_r)) 0581 return true; 0582 } 0583 } 0584 0585 return false; 0586 } 0587 0588 CellRegion CellRegion::intersected(const QRect &rect) const 0589 { 0590 CellRegion intersections; 0591 0592 foreach (const QRect &r, d->rects) { 0593 if (r.intersects(rect)) 0594 intersections.add(r.intersected(rect)); 0595 } 0596 0597 return intersections; 0598 } 0599 0600 Qt::Orientation CellRegion::orientation() const 0601 { 0602 foreach (const QRect &rect, d->rects) { 0603 if (rect.width() > 1) 0604 return Qt::Horizontal; 0605 if (rect.height() > 1) 0606 return Qt::Vertical; 0607 } 0608 0609 // Default if region is only one cell 0610 return Qt::Vertical; 0611 } 0612 0613 int CellRegion::cellCount() const 0614 { 0615 int count = 0; 0616 0617 /*FIXME the following would be more correct cause it 0618 * would also cover multi-dimensional ranges (means 0619 * where rect.width()>1 *and* rect.height()>1). But 0620 * for that kchart needs lot of fixing (e.g. in 0621 * the CellRegion to proper handle multi-dimension 0622 * ranges too). 0623 * 0624 foreach (const QRect &rect, d->rects) 0625 count += (rect.width() * rect.height()); 0626 */ 0627 0628 if (orientation() == Qt::Horizontal) { 0629 foreach (const QRect &rect, d->rects) 0630 count += rect.width(); 0631 } 0632 else { 0633 foreach(const QRect &rect, d->rects) 0634 count += rect.height(); 0635 } 0636 return count; 0637 } 0638 0639 void CellRegion::add(const CellRegion &other) 0640 { 0641 add(other.rects()); 0642 } 0643 0644 void CellRegion::add(const QPoint &point) 0645 { 0646 add(QRect(point, QSize(1, 1))); 0647 } 0648 0649 void CellRegion::add(const QRect &rect) 0650 { 0651 // These checks are obsolete, a CellRegion can be used otherwise as well 0652 #if 0 0653 if (!rect.isValid()) { 0654 warnChart << "CellRegion::add() Attempt to add invalid rectangle"; 0655 warnChart << "CellRegion::add():" << rect; 0656 return; 0657 } 0658 0659 if (rect.width() > 1 && rect.height() > 1) { 0660 warnChart << "CellRegion::add() Attempt to add rectangle with height AND width > 1"; 0661 warnChart << "CellRegion::add():" << rect; 0662 return; 0663 } 0664 #endif 0665 0666 d->rects.append(rect); 0667 d->boundingRect |= rect; 0668 } 0669 0670 void CellRegion::add(const QVector<QRect> &rects) 0671 { 0672 foreach (const QRect &rect, rects) 0673 add(rect); 0674 } 0675 0676 QRect CellRegion::boundingRect() const 0677 { 0678 return d->boundingRect; 0679 } 0680 0681 bool CellRegion::hasPointAtIndex(int index) const 0682 { 0683 return pointAtIndex(index) != QPoint(-1, -1); 0684 } 0685 0686 QPoint CellRegion::pointAtIndex(int index) const 0687 { 0688 // sum of all previous rectangle indices 0689 int i = 0; 0690 0691 foreach (const QRect &rect, d->rects) { 0692 // Rectangle is horizontal 0693 if (rect.width() > 1) { 0694 // Found it! 0695 // Index refers to point in current rectangle 0696 if (i + rect.width() > index) { 0697 // Local index of point in this rectangle 0698 int j = index - i; 0699 return QPoint(rect.x() + j, rect.y()); 0700 } 0701 0702 // add number of indices in current rectangle to total index count 0703 i += rect.width(); 0704 } 0705 else { 0706 // Found it! 0707 // Index refers to point in current rectangle 0708 if (i + rect.height() > index) { 0709 // Local index of point in this rectangle 0710 int j = index - i; 0711 return QPoint(rect.x(), rect.y() + j); 0712 } 0713 0714 // add number of indices in current rectangle to total index count 0715 i += rect.height(); 0716 } 0717 } 0718 0719 // Invalid index! 0720 return QPoint(-1, -1); 0721 } 0722 0723 int CellRegion::indexAtPoint(const QPoint &point) const 0724 { 0725 int indicesLeftToPoint = 0; 0726 bool found = false; 0727 0728 foreach (const QRect &rect, d->rects) { 0729 if (!rect.contains(point)) { 0730 indicesLeftToPoint += rect.width() > 1 ? rect.width() : rect.height(); 0731 continue; 0732 } 0733 0734 found = true; 0735 if (rect.width() > 1) 0736 indicesLeftToPoint += point.x() - rect.topLeft().x(); 0737 else 0738 indicesLeftToPoint += point.y() - rect.topLeft().y(); 0739 } 0740 0741 return found ? indicesLeftToPoint : -1; 0742 } 0743 0744 #if 0 // Unused? 0745 static int rangeCharToInt(char c) 0746 { 0747 return (c >= 'A' && c <= 'Z') ? (c - 'A' + 1) : -1; 0748 } 0749 0750 static int rangeStringToInt(const QString &string) 0751 { 0752 int result = 0; 0753 const int size = string.size(); 0754 for (int i = 0; i < size; i++) { 0755 //debugChart << "---" << float(rangeCharToInt(string[i].toLatin1()) * pow(10.0, (size - i - 1))); 0756 result += rangeCharToInt(string[i].toLatin1()) * pow(10.0, (size - i - 1)); 0757 } 0758 //debugChart << "+++++ result=" << result; 0759 return result; 0760 } 0761 0762 static QString rangeIntToString(int i) 0763 { 0764 QString tmp = QString::number(i); 0765 for (int j = 0; j < tmp.size(); j++) { 0766 tmp[j] = 'A' + tmp[j].toLatin1() - '1'; 0767 } 0768 0769 //debugChart << "tmp=" << tmp; 0770 return tmp; 0771 } 0772 #endif 0773 0774 int CellRegion::rangeCharToInt(char c) 0775 { 0776 return (c >= 'A' && c <= 'Z') ? (c - 'A' + 1) : -1; 0777 } 0778 0779 int CellRegion::rangeStringToInt(const QString &string) 0780 { 0781 int result = 0; 0782 const int size = string.size(); 0783 for (int i = 0; i < size; i++) { 0784 result += rangeCharToInt(string[i].toLatin1()) * pow(10.0, (size - i - 1)); 0785 } 0786 0787 return result; 0788 } 0789 0790 QString CellRegion::rangeIntToString(int i) 0791 { 0792 QString tmp = QString::number(i); 0793 for (int j = 0; j < tmp.size(); j++) { 0794 tmp[j] = 'A' + tmp[j].toLatin1() - '1'; 0795 } 0796 0797 return tmp; 0798 } 0799 0800 // Return the symbolic name of any column. 0801 QString CellRegion::columnName(uint column) 0802 { 0803 if (column < 1 || column > 32767) 0804 return QString("@@@"); 0805 0806 QString str; 0807 unsigned digits = 1; 0808 unsigned offset = 0; 0809 0810 column--; 0811 0812 for (unsigned limit = 26; column >= limit + offset; limit *= 26, ++digits) 0813 offset += limit; 0814 0815 for (unsigned col = column - offset; digits; --digits, col /= 26) 0816 str.prepend(QChar('A' + (col % 26))); 0817 0818 return str; 0819 } 0820 0821 QDebug operator<<(QDebug dbg, const KoChart::CellRegion &r) 0822 { 0823 dbg << "CellRegion[" << r.toString() << ']'; 0824 return dbg; 0825 }