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"