File indexing completed on 2025-01-19 04:46:30

0001 /*
0002   SPDX-FileCopyrightText: 2009 Tobias Koenig <tokoe@kde.org>
0003 
0004   SPDX-License-Identifier: LGPL-2.0-or-later
0005 */
0006 
0007 #include "qcsvmodel.h"
0008 #include "qcsvmodel_p.h"
0009 #include "qcsvreader.h"
0010 #include <QIODevice>
0011 #include <QPair>
0012 
0013 CsvParser::CsvParser(QObject *parent)
0014     : QThread(parent)
0015     , mReader(new QCsvReader(this))
0016 {
0017 }
0018 
0019 CsvParser::~CsvParser()
0020 {
0021     delete mReader;
0022 }
0023 
0024 void CsvParser::load(QIODevice *device)
0025 {
0026     mDevice = device;
0027 
0028     start();
0029 }
0030 
0031 void CsvParser::begin()
0032 {
0033     mCacheCounter = 0;
0034     mRowCount = 0;
0035     mColumnCount = 0;
0036 }
0037 
0038 void CsvParser::beginLine()
0039 {
0040     mRowCount++;
0041 }
0042 
0043 void CsvParser::field(const QString &data, uint row, uint column)
0044 {
0045     const int tmp = qMax(mColumnCount, (int)column + 1);
0046     if (tmp != mColumnCount) {
0047         mColumnCount = tmp;
0048         Q_EMIT columnCountChanged(tmp);
0049     }
0050 
0051     Q_EMIT dataChanged(data, row, column);
0052 }
0053 
0054 void CsvParser::endLine()
0055 {
0056     mCacheCounter++;
0057     if (mCacheCounter == 50) {
0058         Q_EMIT rowCountChanged(mRowCount);
0059         mCacheCounter = 0;
0060     }
0061 }
0062 
0063 void CsvParser::end()
0064 {
0065     Q_EMIT rowCountChanged(mRowCount);
0066     Q_EMIT ended();
0067 }
0068 
0069 void CsvParser::error(const QString &)
0070 {
0071 }
0072 
0073 void CsvParser::run()
0074 {
0075     if (!mDevice->isOpen()) {
0076         mDevice->open(QIODevice::ReadOnly);
0077     }
0078 
0079     mDevice->reset();
0080     mReader->read(mDevice);
0081 }
0082 
0083 void QCsvModel::columnCountChanged(int columns)
0084 {
0085     mColumnCount = columns;
0086     mFieldIdentifiers.resize(columns);
0087     mFieldIdentifiers[columns - 1] = QStringLiteral("0");
0088     Q_EMIT layoutChanged();
0089 }
0090 
0091 void QCsvModel::rowCountChanged(int rows)
0092 {
0093     mRowCount = rows;
0094     Q_EMIT layoutChanged();
0095 }
0096 
0097 void QCsvModel::fieldChanged(const QString &data, int row, int column)
0098 {
0099     mFields.insert(QPair<int, int>(row, column), data);
0100 }
0101 
0102 QCsvModel::QCsvModel(QObject *parent)
0103     : QAbstractTableModel(parent)
0104 {
0105     mParser = new CsvParser(this);
0106 
0107     connect(mParser, &CsvParser::columnCountChanged, this, &QCsvModel::columnCountChanged, Qt::QueuedConnection);
0108     connect(mParser, &CsvParser::rowCountChanged, this, &QCsvModel::rowCountChanged, Qt::QueuedConnection);
0109     connect(mParser, &CsvParser::dataChanged, this, &QCsvModel::fieldChanged, Qt::QueuedConnection);
0110     connect(mParser, &CsvParser::ended, this, &QCsvModel::finishedLoading);
0111 }
0112 
0113 QCsvModel::~QCsvModel() = default;
0114 
0115 bool QCsvModel::load(QIODevice *device)
0116 {
0117     mDevice = device;
0118     mRowCount = 0;
0119     mColumnCount = 0;
0120 
0121     Q_EMIT layoutChanged();
0122 
0123     mParser->load(device);
0124 
0125     return true;
0126 }
0127 
0128 void QCsvModel::setTextQuote(QChar textQuote)
0129 {
0130     const bool isRunning = mParser->isRunning();
0131 
0132     if (isRunning) {
0133         mParser->reader()->terminate();
0134         mParser->wait();
0135     }
0136 
0137     mParser->reader()->setTextQuote(textQuote);
0138 
0139     if (isRunning) {
0140         load(mDevice);
0141     }
0142 }
0143 
0144 QChar QCsvModel::textQuote() const
0145 {
0146     return mParser->reader()->textQuote();
0147 }
0148 
0149 void QCsvModel::setDelimiter(QChar delimiter)
0150 {
0151     const bool isRunning = mParser->isRunning();
0152 
0153     if (isRunning) {
0154         mParser->reader()->terminate();
0155         mParser->wait();
0156     }
0157 
0158     mParser->reader()->setDelimiter(delimiter);
0159 
0160     if (isRunning) {
0161         load(mDevice);
0162     }
0163 }
0164 
0165 QChar QCsvModel::delimiter() const
0166 {
0167     return mParser->reader()->delimiter();
0168 }
0169 
0170 void QCsvModel::setStartRow(uint startRow)
0171 {
0172     const bool isRunning = mParser->isRunning();
0173 
0174     if (isRunning) {
0175         mParser->reader()->terminate();
0176         mParser->wait();
0177     }
0178 
0179     mParser->reader()->setStartRow(startRow);
0180 
0181     if (isRunning) {
0182         load(mDevice);
0183     }
0184 }
0185 
0186 uint QCsvModel::startRow() const
0187 {
0188     return mParser->reader()->startRow();
0189 }
0190 
0191 void QCsvModel::setTextCodec(QTextCodec *textCodec)
0192 {
0193     const bool isRunning = mParser->isRunning();
0194 
0195     if (isRunning) {
0196         mParser->reader()->terminate();
0197         mParser->wait();
0198     }
0199 
0200     mParser->reader()->setTextCodec(textCodec);
0201 
0202     if (isRunning) {
0203         load(mDevice);
0204     }
0205 }
0206 
0207 QTextCodec *QCsvModel::textCodec() const
0208 {
0209     return mParser->reader()->textCodec();
0210 }
0211 
0212 int QCsvModel::columnCount(const QModelIndex &parent) const
0213 {
0214     if (!parent.isValid()) {
0215         return mColumnCount;
0216     } else {
0217         return 0;
0218     }
0219 }
0220 
0221 int QCsvModel::rowCount(const QModelIndex &parent) const
0222 {
0223     if (!parent.isValid()) {
0224         return mRowCount + 1; // +1 for the header row
0225     } else {
0226         return 0;
0227     }
0228 }
0229 
0230 QVariant QCsvModel::data(const QModelIndex &index, int role) const
0231 {
0232     if (!index.isValid()) {
0233         return {};
0234     }
0235 
0236     if (index.row() == 0) {
0237         if (index.column() >= mFieldIdentifiers.count()) {
0238             return {};
0239         }
0240 
0241         if (role == Qt::DisplayRole || role == Qt::EditRole) {
0242             return mFieldIdentifiers.at(index.column());
0243         }
0244 
0245         return {};
0246     }
0247 
0248     const QPair<int, int> pair(index.row() - 1, index.column());
0249     if (!mFields.contains(pair)) {
0250         return {};
0251     }
0252 
0253     const QString data = mFields.value(pair);
0254 
0255     if (role == Qt::DisplayRole) {
0256         return data;
0257     } else {
0258         return {};
0259     }
0260 }
0261 
0262 bool QCsvModel::setData(const QModelIndex &index, const QVariant &data, int role)
0263 {
0264     if (role == Qt::EditRole && index.row() == 0 && index.column() <= mFieldIdentifiers.count()) {
0265         mFieldIdentifiers[index.column()] = data.toString();
0266 
0267         Q_EMIT dataChanged(index, index);
0268         return true;
0269     }
0270 
0271     return false;
0272 }
0273 
0274 Qt::ItemFlags QCsvModel::flags(const QModelIndex &index) const
0275 {
0276     Qt::ItemFlags flags = Qt::ItemIsSelectable | Qt::ItemIsEnabled;
0277     if (index.row() == 0) {
0278         flags |= Qt::ItemIsEditable;
0279     }
0280 
0281     return flags;
0282 }
0283 
0284 #include "moc_qcsvmodel.cpp"
0285 #include "moc_qcsvmodel_p.cpp"