File indexing completed on 2024-10-13 03:30:47

0001 // xlsxcellreference.cpp
0002 
0003 #include "xlsxcellreference.h"
0004 #include <QStringList>
0005 #include <QMap>
0006 
0007 #include <QRegularExpression>
0008 
0009 QT_BEGIN_NAMESPACE_XLSX
0010 
0011 namespace {
0012 
0013 int intPow(int x, int p)
0014 {
0015   if (p == 0) return 1;
0016   if (p == 1) return x;
0017 
0018   int tmp = intPow(x, p/2);
0019   if (p%2 == 0) return tmp * tmp;
0020   else return x * tmp * tmp;
0021 }
0022 
0023 QString col_to_name(int col_num)
0024 {
0025     static thread_local QMap<int, QString> col_cache;
0026 
0027     auto it = col_cache.find(col_num);
0028     if (it == col_cache.end()) {
0029         QString col_str;
0030         int remainder;
0031         while (col_num) {
0032             remainder = col_num % 26;
0033             if (remainder == 0)
0034                 remainder = 26;
0035             col_str.prepend(QChar('A'+remainder-1));
0036             col_num = (col_num - 1) / 26;
0037         }
0038         it = col_cache.insert(col_num, col_str);
0039     }
0040 
0041     return it.value();
0042 }
0043 
0044 int col_from_name(const QString &col_str)
0045 {
0046     int col = 0;
0047     int expn = 0;
0048     for (int i=col_str.size()-1; i>-1; --i) {
0049         col += (col_str[i].unicode() - 'A' + 1) * intPow(26, expn);
0050         expn++;
0051     }
0052 
0053     return col;
0054 }
0055 } //namespace
0056 
0057 /*!
0058     \class CellReference
0059     \brief For one single cell such as "A1"
0060     \inmodule QtXlsx
0061 
0062     The CellReference class stores the cell location in a worksheet.
0063 */
0064 
0065 /*!
0066     Constructs an invalid Cell Reference
0067 */
0068 CellReference::CellReference()
0069     : _row(-1), _column(-1)
0070 {
0071 }
0072 
0073 /*!
0074     Constructs the Reference from the given \a row, and \a column.
0075 */
0076 CellReference::CellReference(int row, int column)
0077     : _row(row), _column(column)
0078 {
0079 }
0080 
0081 /*!
0082     \overload
0083     Constructs the Reference form the given \a cell string.
0084 */
0085 CellReference::CellReference(const QString &cell)
0086 {
0087     init(cell);
0088 }
0089 
0090 /*!
0091     \overload
0092     Constructs the Reference form the given \a cell string.
0093 */
0094 CellReference::CellReference(const char *cell)
0095 {
0096     init(QString::fromLatin1(cell));
0097 }
0098 
0099 void CellReference::init(const QString &cell_str)
0100 {
0101     static thread_local QRegularExpression re(QStringLiteral("^\\$?([A-Z]{1,3})\\$?(\\d+)$"));
0102     QRegularExpressionMatch match = re.match(cell_str);
0103     if (match.hasMatch()) {
0104         const QString col_str = match.captured(1);
0105         const QString row_str = match.captured(2);
0106         _row = row_str.toInt();
0107         _column = col_from_name(col_str);
0108     }
0109 }
0110 
0111 /*!
0112     Constructs a Reference by copying the given \a
0113     other Reference.
0114 */
0115 CellReference::CellReference(const CellReference &other)
0116     : _row(other._row), _column(other._column)
0117 {
0118 }
0119 
0120 /*!
0121     Destroys the Reference.
0122 */
0123 CellReference::~CellReference()
0124 {
0125 }
0126 
0127 /*!
0128      Convert the Reference to string notation, such as "A1" or "$A$1".
0129      If current object is invalid, an empty string will be returned.
0130 */
0131 QString CellReference::toString(bool row_abs, bool col_abs) const
0132 {
0133     if (!isValid())
0134         return QString();
0135 
0136     QString cell_str;
0137     if (col_abs)
0138         cell_str.append(QLatin1Char('$'));
0139     cell_str.append(col_to_name(_column));
0140     if (row_abs)
0141         cell_str.append(QLatin1Char('$'));
0142     cell_str.append(QString::number(_row));
0143     return cell_str;
0144 }
0145 
0146 /*!
0147  * Returns true if the Reference is valid.
0148  */
0149 bool CellReference::isValid() const
0150 {
0151     return _row > 0 && _column > 0;
0152 }
0153 
0154 QT_END_NAMESPACE_XLSX