You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
343 lines
9.5 KiB
343 lines
9.5 KiB
/* |
|
Copyright (C) 2010 Klarälvdalens Datakonsult AB, |
|
a KDAB Group company, info@kdab.net, |
|
author Stephen Kelly <stephen@kdab.com> |
|
|
|
This library is free software; you can redistribute it and/or modify it |
|
under the terms of the GNU Library General Public License as published by |
|
the Free Software Foundation; either version 2 of the License, or (at your |
|
option) any later version. |
|
|
|
This library is distributed in the hope that it will be useful, but WITHOUT |
|
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
|
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public |
|
License for more details. |
|
|
|
You should have received a copy of the GNU Library General Public License |
|
along with this library; see the file COPYING.LIB. If not, write to the |
|
Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA |
|
02110-1301, USA. |
|
*/ |
|
|
|
#include "modeleventlogger.h" |
|
#include "modeldumper.h" |
|
#include "indexfinder.h" |
|
|
|
#include "eventloggerregister.h" |
|
|
|
#include <QStringList> |
|
#include <QFile> |
|
#include <QDebug> |
|
|
|
#ifdef Grantlee_FOUND |
|
#include <grantlee_core.h> |
|
#include "grantlee_paths.h" |
|
|
|
/** |
|
Don't escape the code generation output. |
|
|
|
'const QString &' should not become 'const QString &' |
|
*/ |
|
class NoEscapeOutputStream : public Grantlee::OutputStream |
|
{ |
|
public: |
|
NoEscapeOutputStream() |
|
: Grantlee::OutputStream() |
|
{ |
|
|
|
} |
|
|
|
NoEscapeOutputStream(QTextStream *stream) |
|
: OutputStream(stream) |
|
{ |
|
|
|
} |
|
|
|
virtual QSharedPointer< Grantlee::OutputStream > clone() const |
|
{ |
|
return QSharedPointer<Grantlee::OutputStream>(new NoEscapeOutputStream); |
|
} |
|
|
|
virtual QString escape(const QString &input) const |
|
{ |
|
return input; |
|
} |
|
}; |
|
#endif |
|
|
|
class ModelWrapper : public QAbstractItemModel |
|
{ |
|
public: |
|
ModelWrapper(QAbstractItemModel */*model*/, QObject *parent = 0) |
|
: QAbstractItemModel(parent) |
|
{ |
|
|
|
} |
|
|
|
QModelIndexList per() const |
|
{ |
|
return persistentIndexList(); |
|
} |
|
|
|
QModelIndex index(int /*row*/, int /*column*/, const QModelIndex & /*parent*/ = QModelIndex()) const Q_DECL_OVERRIDE |
|
{ |
|
return QModelIndex(); |
|
} |
|
int rowCount(const QModelIndex & /*parent*/ = QModelIndex()) const Q_DECL_OVERRIDE |
|
{ |
|
return 0; |
|
} |
|
QModelIndex parent(const QModelIndex & /*child*/) const Q_DECL_OVERRIDE |
|
{ |
|
return QModelIndex(); |
|
} |
|
int columnCount(const QModelIndex & /*parent*/ = QModelIndex()) const Q_DECL_OVERRIDE |
|
{ |
|
return 0; |
|
} |
|
QVariant data(const QModelIndex & /*index*/, int /*role*/ = Qt::DisplayRole) const Q_DECL_OVERRIDE |
|
{ |
|
return QVariant(); |
|
} |
|
}; |
|
|
|
ModelEvent::ModelEvent(QObject *parent) |
|
: QObject(parent) |
|
{ |
|
|
|
} |
|
|
|
static const char *const sTypes[] = { |
|
"Init", |
|
"RowsInserted", |
|
"RowsRemoved", |
|
"DataChanged", |
|
"LayoutChanged", |
|
"ModelReset" |
|
}; |
|
|
|
QString ModelEvent::type() const |
|
{ |
|
return QLatin1String(*(sTypes + m_type)); |
|
} |
|
|
|
// ModelEvent::Type ModelEvent::type() const |
|
// { |
|
// return m_type; |
|
// } |
|
|
|
void ModelEvent::setType(ModelEvent::Type type) |
|
{ |
|
m_type = type; |
|
} |
|
|
|
int ModelEvent::start() const |
|
{ |
|
return m_start; |
|
} |
|
|
|
void ModelEvent::setStart(int start) |
|
{ |
|
m_start = start; |
|
} |
|
|
|
int ModelEvent::end() const |
|
{ |
|
return m_end; |
|
} |
|
|
|
void ModelEvent::setEnd(int end) |
|
{ |
|
m_end = end; |
|
} |
|
|
|
QString ModelEvent::rowAncestors() const |
|
{ |
|
QString result(QStringLiteral("QList<int>()")); |
|
|
|
Q_FOREACH (const int row, m_rowAncestors) { |
|
result.append(" << "); |
|
result.append(QString::number(row)); |
|
} |
|
return result; |
|
} |
|
|
|
// QList< int > ModelEvent::rowAncestors() const |
|
// { |
|
// return m_rowAncestors; |
|
// } |
|
|
|
void ModelEvent::setRowAncestors(QList< int > rowAncestors) |
|
{ |
|
m_rowAncestors = rowAncestors; |
|
} |
|
|
|
bool ModelEvent::hasInterpretString() const |
|
{ |
|
return !m_interpretString.isEmpty(); |
|
} |
|
|
|
QString ModelEvent::interpretString() const |
|
{ |
|
return m_interpretString; |
|
} |
|
|
|
void ModelEvent::setInterpretString(const QString &interpretString) |
|
{ |
|
m_interpretString = interpretString; |
|
} |
|
|
|
ModelEventLogger::ModelEventLogger(QAbstractItemModel *model, QObject *parent) |
|
: QObject(parent), m_model(model), m_modelDumper(new ModelDumper), m_numLogs(0) |
|
{ |
|
connect(model, SIGNAL(dataChanged(QModelIndex,QModelIndex)), SLOT(dataChanged(QModelIndex,QModelIndex))); |
|
connect(model, SIGNAL(layoutAboutToBeChanged()), SLOT(layoutAboutToBeChanged())); |
|
connect(model, SIGNAL(layoutChanged()), SLOT(layoutChanged())); |
|
connect(model, SIGNAL(modelReset()), SLOT(modelReset())); |
|
connect(model, SIGNAL(rowsInserted(QModelIndex,int,int)), SLOT(rowsInserted(QModelIndex,int,int))); |
|
connect(model, SIGNAL(rowsRemoved(QModelIndex,int,int)), SLOT(rowsRemoved(QModelIndex,int,int))); |
|
|
|
ModelEvent *modelEvent = new ModelEvent(this); |
|
modelEvent->setType(ModelEvent::Init); |
|
modelEvent->setInterpretString(m_modelDumper->dumpModel(model)); |
|
|
|
m_modelName = QString::fromLatin1(model->metaObject()->className()).toLower(); |
|
|
|
m_initEvent = QVariant::fromValue(static_cast<QObject *>(modelEvent)); |
|
|
|
EventLoggerRegister::instance()->registerLogger(this); |
|
} |
|
|
|
void ModelEventLogger::writeLog() |
|
{ |
|
#ifdef Grantlee_FOUND |
|
QString logFileName = QString("main.%1.%2.%3.cpp").arg(m_modelName).arg(reinterpret_cast<qint64>(this)).arg(m_numLogs++); |
|
qDebug() << "Writing to " << logFileName; |
|
QFile outputFile(logFileName); |
|
const bool logFileOpened = outputFile.open(QFile::WriteOnly | QFile::Text); |
|
Q_ASSERT(logFileOpened); |
|
|
|
Grantlee::Engine engine; |
|
Grantlee::FileSystemTemplateLoader::Ptr loader(new Grantlee::FileSystemTemplateLoader); |
|
loader->setTemplateDirs(QStringList() << ":/templates"); |
|
engine.addTemplateLoader(loader); |
|
engine.setPluginPaths(QStringList() << GRANTLEE_PLUGIN_PATH); |
|
|
|
// Write out. |
|
Grantlee::Template t = engine.loadByName("main.cpp"); |
|
if (!t->error()) { |
|
Grantlee::Context c; |
|
c.insert("initEvent", m_initEvent); |
|
c.insert("events", m_events); |
|
|
|
QTextStream textStream(&outputFile); |
|
NoEscapeOutputStream outputStream(&textStream); |
|
t->render(&outputStream, &c); |
|
} |
|
outputFile.close(); |
|
|
|
if (t->error()) { |
|
qDebug() << t->errorString(); |
|
} |
|
#else |
|
qDebug() << "Grantlee not found. No log written."; |
|
#endif |
|
} |
|
|
|
ModelEventLogger::~ModelEventLogger() |
|
{ |
|
writeLog(); |
|
delete m_modelDumper; |
|
EventLoggerRegister::instance()->unregisterLogger(this); |
|
} |
|
|
|
void ModelEventLogger::dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight) |
|
{ |
|
ModelEvent *modelEvent = new ModelEvent(this); |
|
modelEvent->setType(ModelEvent::DataChanged); |
|
modelEvent->setRowAncestors(IndexFinder::indexToIndexFinder(topLeft.parent()).rows()); |
|
modelEvent->setStart(topLeft.row()); |
|
modelEvent->setEnd(bottomRight.row()); |
|
|
|
m_events.append(QVariant::fromValue(static_cast<QObject *>(modelEvent))); |
|
} |
|
|
|
void ModelEventLogger::persistChildren(const QModelIndex &/*parent*/) |
|
{ |
|
} |
|
|
|
void ModelEventLogger::layoutAboutToBeChanged() |
|
{ |
|
m_oldPaths.clear(); |
|
m_persistentIndexes.clear(); |
|
const QModelIndexList list = static_cast<const ModelWrapper *>(m_model)->per(); |
|
Q_FOREACH (const QPersistentModelIndex &idx, list) { |
|
m_persistentIndexes.append(idx); |
|
m_oldPaths.append(IndexFinder::indexToIndexFinder(idx).rows()); |
|
} |
|
} |
|
|
|
void ModelEventLogger::layoutChanged() |
|
{ |
|
ModelEvent *modelEvent = new ModelEvent(this); |
|
modelEvent->setType(ModelEvent::LayoutChanged); |
|
modelEvent->setInterpretString(m_modelDumper->dumpModel(m_model)); |
|
|
|
QList<PersistentChange *> changes; |
|
|
|
for (int i = 0; i < m_persistentIndexes.size(); ++i) { |
|
const QPersistentModelIndex pIdx = m_persistentIndexes.at(i); |
|
if (!pIdx.isValid()) { |
|
PersistentChange *change = new PersistentChange(this); |
|
change->newPath = QList<int>(); |
|
change->oldPath = m_oldPaths.at(i); |
|
changes.append(change); |
|
continue; |
|
} |
|
const QList<int> rows = IndexFinder::indexToIndexFinder(pIdx).rows(); |
|
if (m_oldPaths.at(i) == rows) { |
|
continue; |
|
} |
|
|
|
PersistentChange *change = new PersistentChange(this); |
|
change->newPath = rows; |
|
change->oldPath = m_oldPaths.at(i); |
|
changes.append(change); |
|
} |
|
|
|
modelEvent->setChanges(changes); |
|
|
|
m_events.append(QVariant::fromValue(static_cast<QObject *>(modelEvent))); |
|
} |
|
|
|
void ModelEventLogger::modelReset() |
|
{ |
|
ModelEvent *modelEvent = new ModelEvent(this); |
|
modelEvent->setType(ModelEvent::ModelReset); |
|
modelEvent->setInterpretString(m_modelDumper->dumpModel(m_model)); |
|
|
|
m_events.append(QVariant::fromValue(static_cast<QObject *>(modelEvent))); |
|
} |
|
|
|
void ModelEventLogger::rowsInserted(const QModelIndex &parent, int start, int end) |
|
{ |
|
ModelEvent *modelEvent = new ModelEvent(this); |
|
modelEvent->setType(ModelEvent::RowsInserted); |
|
modelEvent->setRowAncestors(IndexFinder::indexToIndexFinder(parent).rows()); |
|
modelEvent->setStart(start); |
|
QString s = m_modelDumper->dumpTree(m_model, parent, start, end); |
|
modelEvent->setInterpretString(s); |
|
|
|
m_events.append(QVariant::fromValue(static_cast<QObject *>(modelEvent))); |
|
} |
|
|
|
void ModelEventLogger::rowsRemoved(const QModelIndex &parent, int start, int end) |
|
{ |
|
ModelEvent *modelEvent = new ModelEvent(this); |
|
modelEvent->setType(ModelEvent::RowsRemoved); |
|
modelEvent->setRowAncestors(IndexFinder::indexToIndexFinder(parent).rows()); |
|
modelEvent->setStart(start); |
|
modelEvent->setEnd(end); |
|
|
|
m_events.append(QVariant::fromValue(static_cast<QObject *>(modelEvent))); |
|
}
|
|
|