File indexing completed on 2024-04-21 03:56:05
0001 /* 0002 SPDX-FileCopyrightText: 2010 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.net> 0003 SPDX-FileContributor: Stephen Kelly <stephen@kdab.com> 0004 0005 SPDX-License-Identifier: LGPL-2.0-or-later 0006 */ 0007 0008 #include "modeleventlogger.h" 0009 #include "indexfinder.h" 0010 #include "modeldumper.h" 0011 0012 #include "eventloggerregister.h" 0013 0014 #include <QDebug> 0015 #include <QFile> 0016 #include <QStringList> 0017 0018 #ifdef Grantlee_FOUND 0019 #include "grantlee_paths.h" 0020 #include <grantlee_core.h> 0021 0022 /** 0023 Don't escape the code generation output. 0024 0025 'const QString &' should not become 'const QString &' 0026 */ 0027 class NoEscapeOutputStream : public Grantlee::OutputStream 0028 { 0029 public: 0030 NoEscapeOutputStream() 0031 : Grantlee::OutputStream() 0032 { 0033 } 0034 0035 NoEscapeOutputStream(QTextStream *stream) 0036 : OutputStream(stream) 0037 { 0038 } 0039 0040 virtual QSharedPointer<Grantlee::OutputStream> clone() const 0041 { 0042 return QSharedPointer<Grantlee::OutputStream>(new NoEscapeOutputStream); 0043 } 0044 0045 virtual QString escape(const QString &input) const 0046 { 0047 return input; 0048 } 0049 }; 0050 #endif 0051 0052 class ModelWrapper : public QAbstractItemModel 0053 { 0054 public: 0055 ModelWrapper(QAbstractItemModel * /*model*/, QObject *parent = nullptr) 0056 : QAbstractItemModel(parent) 0057 { 0058 } 0059 0060 QModelIndexList per() const 0061 { 0062 return persistentIndexList(); 0063 } 0064 0065 QModelIndex index(int /*row*/, int /*column*/, const QModelIndex & /*parent*/ = QModelIndex()) const override 0066 { 0067 return QModelIndex(); 0068 } 0069 int rowCount(const QModelIndex & /*parent*/ = QModelIndex()) const override 0070 { 0071 return 0; 0072 } 0073 QModelIndex parent(const QModelIndex & /*child*/) const override 0074 { 0075 return QModelIndex(); 0076 } 0077 int columnCount(const QModelIndex & /*parent*/ = QModelIndex()) const override 0078 { 0079 return 0; 0080 } 0081 QVariant data(const QModelIndex & /*index*/, int /*role*/ = Qt::DisplayRole) const override 0082 { 0083 return QVariant(); 0084 } 0085 }; 0086 0087 ModelEvent::ModelEvent(QObject *parent) 0088 : QObject(parent) 0089 { 0090 } 0091 0092 static const char *const sTypes[] = {"Init", "RowsInserted", "RowsRemoved", "DataChanged", "LayoutChanged", "ModelReset"}; 0093 0094 QString ModelEvent::type() const 0095 { 0096 return QLatin1String(*(sTypes + m_type)); 0097 } 0098 0099 // ModelEvent::Type ModelEvent::type() const 0100 // { 0101 // return m_type; 0102 // } 0103 0104 void ModelEvent::setType(ModelEvent::Type type) 0105 { 0106 m_type = type; 0107 } 0108 0109 int ModelEvent::start() const 0110 { 0111 return m_start; 0112 } 0113 0114 void ModelEvent::setStart(int start) 0115 { 0116 m_start = start; 0117 } 0118 0119 int ModelEvent::end() const 0120 { 0121 return m_end; 0122 } 0123 0124 void ModelEvent::setEnd(int end) 0125 { 0126 m_end = end; 0127 } 0128 0129 QString ModelEvent::rowAncestors() const 0130 { 0131 QString result(QStringLiteral("QList<int>()")); 0132 0133 for (const int row : std::as_const(m_rowAncestors)) { 0134 result.append(" << "); 0135 result.append(QString::number(row)); 0136 } 0137 return result; 0138 } 0139 0140 // QList< int > ModelEvent::rowAncestors() const 0141 // { 0142 // return m_rowAncestors; 0143 // } 0144 0145 void ModelEvent::setRowAncestors(QList<int> rowAncestors) 0146 { 0147 m_rowAncestors = rowAncestors; 0148 } 0149 0150 bool ModelEvent::hasInterpretString() const 0151 { 0152 return !m_interpretString.isEmpty(); 0153 } 0154 0155 QString ModelEvent::interpretString() const 0156 { 0157 return m_interpretString; 0158 } 0159 0160 void ModelEvent::setInterpretString(const QString &interpretString) 0161 { 0162 m_interpretString = interpretString; 0163 } 0164 0165 ModelEventLogger::ModelEventLogger(QAbstractItemModel *model, QObject *parent) 0166 : QObject(parent) 0167 , m_model(model) 0168 , m_modelDumper(new ModelDumper) 0169 , m_numLogs(0) 0170 { 0171 connect(model, &QAbstractItemModel::dataChanged, this, &ModelEventLogger::dataChanged); 0172 connect(model, &QAbstractItemModel::layoutAboutToBeChanged, this, &ModelEventLogger::layoutAboutToBeChanged); 0173 connect(model, &QAbstractItemModel::layoutChanged, this, &ModelEventLogger::layoutChanged); 0174 connect(model, &QAbstractItemModel::modelReset, this, &ModelEventLogger::modelReset); 0175 connect(model, &QAbstractItemModel::rowsInserted, this, &ModelEventLogger::rowsInserted); 0176 connect(model, &QAbstractItemModel::rowsRemoved, this, &ModelEventLogger::rowsRemoved); 0177 0178 ModelEvent *modelEvent = new ModelEvent(this); 0179 modelEvent->setType(ModelEvent::Init); 0180 modelEvent->setInterpretString(m_modelDumper->dumpModel(model)); 0181 0182 m_modelName = QString::fromLatin1(model->metaObject()->className()).toLower(); 0183 0184 m_initEvent = QVariant::fromValue(static_cast<QObject *>(modelEvent)); 0185 0186 EventLoggerRegister::instance()->registerLogger(this); 0187 } 0188 0189 void ModelEventLogger::writeLog() 0190 { 0191 #ifdef Grantlee_FOUND 0192 QString logFileName = QString("main.%1.%2.%3.cpp").arg(m_modelName).arg(reinterpret_cast<qint64>(this)).arg(m_numLogs++); 0193 qDebug() << "Writing to " << logFileName; 0194 QFile outputFile(logFileName); 0195 const bool logFileOpened = outputFile.open(QFile::WriteOnly | QFile::Text); 0196 Q_ASSERT(logFileOpened); 0197 0198 Grantlee::Engine engine; 0199 Grantlee::FileSystemTemplateLoader::Ptr loader(new Grantlee::FileSystemTemplateLoader); 0200 loader->setTemplateDirs(QStringList() << ":/templates"); 0201 engine.addTemplateLoader(loader); 0202 engine.setPluginPaths(QStringList() << GRANTLEE_PLUGIN_PATH); 0203 0204 // Write out. 0205 Grantlee::Template t = engine.loadByName("main.cpp"); 0206 if (!t->error()) { 0207 Grantlee::Context c; 0208 c.insert("initEvent", m_initEvent); 0209 c.insert("events", m_events); 0210 0211 QTextStream textStream(&outputFile); 0212 NoEscapeOutputStream outputStream(&textStream); 0213 t->render(&outputStream, &c); 0214 } 0215 outputFile.close(); 0216 0217 if (t->error()) { 0218 qDebug() << t->errorString(); 0219 } 0220 #else 0221 qDebug() << "Grantlee not found. No log written."; 0222 #endif 0223 } 0224 0225 ModelEventLogger::~ModelEventLogger() 0226 { 0227 writeLog(); 0228 delete m_modelDumper; 0229 EventLoggerRegister::instance()->unregisterLogger(this); 0230 } 0231 0232 void ModelEventLogger::dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight) 0233 { 0234 ModelEvent *modelEvent = new ModelEvent(this); 0235 modelEvent->setType(ModelEvent::DataChanged); 0236 modelEvent->setRowAncestors(IndexFinder::indexToIndexFinder(topLeft.parent()).rows()); 0237 modelEvent->setStart(topLeft.row()); 0238 modelEvent->setEnd(bottomRight.row()); 0239 0240 m_events.append(QVariant::fromValue(static_cast<QObject *>(modelEvent))); 0241 } 0242 0243 void ModelEventLogger::persistChildren(const QModelIndex & /*parent*/) 0244 { 0245 } 0246 0247 void ModelEventLogger::layoutAboutToBeChanged() 0248 { 0249 m_oldPaths.clear(); 0250 m_persistentIndexes.clear(); 0251 const QModelIndexList list = static_cast<const ModelWrapper *>(m_model)->per(); 0252 for (const QModelIndex &idx : list) { 0253 m_persistentIndexes.append(QPersistentModelIndex(idx)); 0254 m_oldPaths.append(IndexFinder::indexToIndexFinder(idx).rows()); 0255 } 0256 } 0257 0258 void ModelEventLogger::layoutChanged() 0259 { 0260 ModelEvent *modelEvent = new ModelEvent(this); 0261 modelEvent->setType(ModelEvent::LayoutChanged); 0262 modelEvent->setInterpretString(m_modelDumper->dumpModel(m_model)); 0263 0264 QList<PersistentChange *> changes; 0265 0266 for (int i = 0; i < m_persistentIndexes.size(); ++i) { 0267 const QPersistentModelIndex pIdx = m_persistentIndexes.at(i); 0268 if (!pIdx.isValid()) { 0269 PersistentChange *change = new PersistentChange(this); 0270 change->newPath = QList<int>(); 0271 change->oldPath = m_oldPaths.at(i); 0272 changes.append(change); 0273 continue; 0274 } 0275 const QList<int> rows = IndexFinder::indexToIndexFinder(pIdx).rows(); 0276 if (m_oldPaths.at(i) == rows) { 0277 continue; 0278 } 0279 0280 PersistentChange *change = new PersistentChange(this); 0281 change->newPath = rows; 0282 change->oldPath = m_oldPaths.at(i); 0283 changes.append(change); 0284 } 0285 0286 modelEvent->setChanges(changes); 0287 0288 m_events.append(QVariant::fromValue(static_cast<QObject *>(modelEvent))); 0289 } 0290 0291 void ModelEventLogger::modelReset() 0292 { 0293 ModelEvent *modelEvent = new ModelEvent(this); 0294 modelEvent->setType(ModelEvent::ModelReset); 0295 modelEvent->setInterpretString(m_modelDumper->dumpModel(m_model)); 0296 0297 m_events.append(QVariant::fromValue(static_cast<QObject *>(modelEvent))); 0298 } 0299 0300 void ModelEventLogger::rowsInserted(const QModelIndex &parent, int start, int end) 0301 { 0302 ModelEvent *modelEvent = new ModelEvent(this); 0303 modelEvent->setType(ModelEvent::RowsInserted); 0304 modelEvent->setRowAncestors(IndexFinder::indexToIndexFinder(parent).rows()); 0305 modelEvent->setStart(start); 0306 QString s = m_modelDumper->dumpTree(m_model, parent, start, end); 0307 modelEvent->setInterpretString(s); 0308 0309 m_events.append(QVariant::fromValue(static_cast<QObject *>(modelEvent))); 0310 } 0311 0312 void ModelEventLogger::rowsRemoved(const QModelIndex &parent, int start, int end) 0313 { 0314 ModelEvent *modelEvent = new ModelEvent(this); 0315 modelEvent->setType(ModelEvent::RowsRemoved); 0316 modelEvent->setRowAncestors(IndexFinder::indexToIndexFinder(parent).rows()); 0317 modelEvent->setStart(start); 0318 modelEvent->setEnd(end); 0319 0320 m_events.append(QVariant::fromValue(static_cast<QObject *>(modelEvent))); 0321 } 0322 0323 #include "moc_modeleventlogger.cpp"