#include "apitracemodel.h"
#include "apitracecall.h"
-#include "loaderthread.h"
+#include "traceloader.h"
#include "trace_parser.hpp"
+#include <QBuffer>
#include <QDebug>
+#include <QImage>
#include <QVariant>
ApiTraceModel::ApiTraceModel(QObject *parent)
- : QAbstractItemModel(parent)
+ : QAbstractItemModel(parent),
+ m_trace(0)
{
- m_loader = new LoaderThread();
-
- connect(m_loader, SIGNAL(parsedCalls(const QList<Trace::Call*>&)),
- SLOT(appendCalls(const QList<Trace::Call*>&)));
}
ApiTraceModel::~ApiTraceModel()
{
- qDeleteAll(m_calls);
- delete m_loader;
+ m_trace = 0;
}
QVariant ApiTraceModel::data(const QModelIndex &index, int role) const
if (!index.isValid())
return QVariant();
- if (role != Qt::DisplayRole)
+ if (index.column() != 0)
return QVariant();
- ApiTraceCall *item = m_calls.value(index.row());
-
- if (!item)
+ ApiTraceEvent *itm = item(index);
+ if (!itm) {
return QVariant();
+ }
- switch (index.column()) {
- case 0: {
- return QVariant::fromValue(item);
+ switch (role) {
+ case Qt::DisplayRole:
+ return itm->staticText().text();
+ case Qt::DecorationRole:
+ return QImage();
+ case Qt::ToolTipRole: {
+ const QString stateText = tr("State info available.");
+ if (itm->type() == ApiTraceEvent::Call) {
+ ApiTraceCall *call = static_cast<ApiTraceCall*>(itm);
+ if (!call->hasState())
+ return QString::fromLatin1("%1) <b>%2</b>")
+ .arg(call->index())
+ .arg(call->name());
+ else
+ return QString::fromLatin1("%1) <b>%2</b><br/>%3")
+ .arg(call->index())
+ .arg(call->name())
+ .arg(stateText);
+ } else {
+ const char *htmlTempl =
+ "<div>\n"
+ "<div>\n"
+ "%1"
+ "<span style=\"font-weight:bold; font-size:large; vertical-align:center; padding-bottom: 30px \">\n"
+ "Frame %2</span>\n"
+ "</div>\n"
+ "<div >%3 calls%4</div>\n"
+ "</div>\n";
+
+
+ ApiTraceFrame *frame = static_cast<ApiTraceFrame*>(itm);
+ QString thumbStr, sizeStr;
+
+ if (frame->hasState()) {
+ static const char *imgTempl =
+ "<img style=\"float:left;\" "
+ "src=\"data:image/png;base64,%1\"/>\n";
+ static const char *sizeTempl =
+ ", %1kb";
+
+ ApiFramebuffer fbo = frame->state()->colorBuffer();
+ QImage thumb = fbo.thumb();
+ if (!thumb.isNull()) {
+ QByteArray ba;
+ QBuffer buffer(&ba);
+ buffer.open(QIODevice::WriteOnly);
+ thumb.save(&buffer, "PNG");
+ thumbStr = tr(imgTempl).arg(
+ QString(buffer.data().toBase64()));
+ }
+
+ int binaryDataSize = frame->binaryDataSize() / 1024;
+ if (binaryDataSize > 0) {
+ sizeStr = tr(sizeTempl).arg(binaryDataSize);
+ }
+ }
+
+ int numCalls = frame->isLoaded()
+ ? frame->numChildren()
+ : frame->numChildrenToLoad();
+
+ return tr(htmlTempl)
+ .arg(thumbStr)
+ .arg(frame->number)
+ .arg(numCalls)
+ .arg(sizeStr);
+ }
}
- default:
- return QVariant();
+ case ApiTraceModel::EventRole:
+ return QVariant::fromValue(itm);
}
+
+ return QVariant();
}
Qt::ItemFlags ApiTraceModel::flags(const QModelIndex &index) const
if (orientation == Qt::Horizontal && role == Qt::DisplayRole) {
switch (section) {
case 0:
- return tr("Function");
+ return tr("Events");
+ case 1:
+ return tr("Flags");
default:
//fall through
break;
QModelIndex ApiTraceModel::index(int row, int column,
const QModelIndex &parent) const
{
- if (parent.isValid() && parent.column() != 0)
+ if ((parent.isValid() && parent.column() != 0) || column != 0)
return QModelIndex();
- ApiTraceCall *call = m_calls.value(row);
-
- if (call)
- return createIndex(row, column, call);
- else
- return QModelIndex();
+ ApiTraceEvent *event = item(parent);
+ if (event) {
+ if (event->type() != ApiTraceEvent::Frame) {
+ qDebug()<<"got a valid parent but it's not a frame "<<event->type();
+ return QModelIndex();
+ }
+ ApiTraceFrame *frame = static_cast<ApiTraceFrame*>(event);
+ ApiTraceCall *call = frame->call(row);
+ if (call)
+ return createIndex(row, column, call);
+ else
+ return QModelIndex();
+ } else {
+ ApiTraceFrame *frame = m_trace->frameAt(row);
+ if (frame)
+ return createIndex(row, column, frame);
+ else
+ return QModelIndex();
+ }
+ return QModelIndex();
}
bool ApiTraceModel::hasChildren(const QModelIndex &parent) const
{
- return parent.isValid() ? false : (rowCount() > 0);
+ if (parent.isValid()) {
+ ApiTraceEvent *event = item(parent);
+ if (event && event->type() == ApiTraceEvent::Frame) {
+ ApiTraceFrame *frame = static_cast<ApiTraceFrame*>(event);
+ return !frame->isEmpty();
+ } else
+ return false;
+ } else {
+ return (rowCount() > 0);
+ }
}
QModelIndex ApiTraceModel::parent(const QModelIndex &index) const
if (!index.isValid())
return QModelIndex();
- //list for now
+ ApiTraceEvent *event = item(index);
+ if (event && event->type() == ApiTraceEvent::Call) {
+ ApiTraceCall *call = static_cast<ApiTraceCall*>(event);
+ Q_ASSERT(call->parentFrame());
+ return createIndex(call->parentFrame()->number,
+ 0, call->parentFrame());
+ }
return QModelIndex();
}
int ApiTraceModel::rowCount(const QModelIndex &parent) const
{
- return m_calls.count();
+ if (!parent.isValid())
+ return m_trace->numFrames();
+
+ ApiTraceEvent *event = item(parent);
+ if (!event || event->type() == ApiTraceEvent::Call)
+ return 0;
+
+ ApiTraceFrame *frame = static_cast<ApiTraceFrame*>(event);
+ if (frame)
+ return frame->numChildren();
+
+ return 0;
}
int ApiTraceModel::columnCount(const QModelIndex &parent) const
{
- return parent.isValid() ? 0 : 1;
+ return 1;
}
-
bool ApiTraceModel::insertRows(int position, int rows,
const QModelIndex &parent)
{
Q_UNUSED(parent);
- if (m_calls.count() <= position)
- return false;
-
beginRemoveRows(parent, position, position + rows - 1);
- for (int i = 0; i < rows; ++i) {
- ApiTraceCall *call = m_calls.value(i);
- m_calls.removeAt(i);
- delete call;
- }
+ //XXX remove it from ApiTrace
endRemoveRows();
return success;
}
-void ApiTraceModel::loadTraceFile(const QString &fileName)
+void ApiTraceModel::setApiTrace(ApiTrace *trace)
+{
+ if (m_trace == trace)
+ return;
+ if (m_trace)
+ disconnect(m_trace);
+ m_trace = trace;
+ connect(m_trace, SIGNAL(invalidated()),
+ this, SLOT(invalidateFrames()));
+ connect(m_trace, SIGNAL(framesInvalidated()),
+ this, SLOT(invalidateFrames()));
+ connect(m_trace, SIGNAL(beginAddingFrames(int, int)),
+ this, SLOT(beginAddingFrames(int, int)));
+ connect(m_trace, SIGNAL(endAddingFrames()),
+ this, SLOT(endAddingFrames()));
+ connect(m_trace, SIGNAL(changed(ApiTraceCall*)),
+ this, SLOT(callChanged(ApiTraceCall*)));
+ connect(m_trace, SIGNAL(beginLoadingFrame(ApiTraceFrame*,int)),
+ this, SLOT(beginLoadingFrame(ApiTraceFrame*,int)));
+ connect(m_trace, SIGNAL(endLoadingFrame(ApiTraceFrame*)),
+ this, SLOT(endLoadingFrame(ApiTraceFrame*)));
+
+}
+
+const ApiTrace * ApiTraceModel::apiTrace() const
+{
+ return m_trace;
+}
+
+void ApiTraceModel::invalidateFrames()
+{
+ beginResetModel();
+ endResetModel();
+}
+
+void ApiTraceModel::beginAddingFrames(int oldCount, int numAdded)
+{
+ beginInsertRows(QModelIndex(), oldCount,
+ oldCount + numAdded - 1);
+}
+
+ApiTraceEvent * ApiTraceModel::item(const QModelIndex &index) const
+{
+ if (!index.isValid())
+ return 0;
+ return static_cast<ApiTraceEvent*>(index.internalPointer());
+}
+
+void ApiTraceModel::stateSetOnEvent(ApiTraceEvent *event)
{
- if (m_loader->isRunning()) {
- m_loader->terminate();
- m_loader->wait();
+ if (!event)
+ return;
+
+ if (event->type() == ApiTraceEvent::Call) {
+ ApiTraceCall *call = static_cast<ApiTraceCall*>(event);
+ ApiTraceFrame *frame = call->parentFrame();
+ int row = frame->callIndex(call);
+ QModelIndex index = createIndex(row, 0, call);
+ emit dataChanged(index, index);
+ } else if (event->type() == ApiTraceEvent::Frame) {
+ ApiTraceFrame *frame = static_cast<ApiTraceFrame*>(event);
+ const QList<ApiTraceFrame*> frames = m_trace->frames();
+ int row = frames.indexOf(frame);
+ QModelIndex index = createIndex(row, 0, frame);
+ emit dataChanged(index, index);
+ }
+}
+
+QModelIndex ApiTraceModel::indexForCall(ApiTraceCall *call) const
+{
+ if (!call) {
+ return QModelIndex();
}
- removeRows(0, m_calls.count(), QModelIndex());
- m_loader->loadFile(fileName);
+ ApiTraceFrame *frame = call->parentFrame();
+ Q_ASSERT(frame);
+
+ int row = frame->callIndex(call);
+ if (row < 0) {
+ qDebug() << "Couldn't find call num "<<call->index()<<" inside parent!";
+ return QModelIndex();
+ }
+ return createIndex(row, 0, call);
}
-void ApiTraceModel::appendCalls(const QList<Trace::Call*> traceCalls)
+void ApiTraceModel::callChanged(ApiTraceCall *call)
{
- beginInsertRows(QModelIndex(), m_calls.count(),
- m_calls.count() + traceCalls.count());
- foreach(Trace::Call *call, traceCalls) {
- ApiTraceCall *apiCall = new ApiTraceCall;
- apiCall->name = QString::fromStdString(call->sig->name);
+ ApiTrace *trace = call->parentFrame()->parentTrace();
+
+#if 0
+ qDebug()<<"Call changed = "<<call->edited();
+ qDebug()<<"\ttrace edited = "<<trace->edited();
+ qDebug()<<"\ttrace file = "<<trace->fileName();
+ qDebug()<<"\ttrace needs saving = "<<trace->needsSaving();
+#endif
+
+ Q_ASSERT(trace);
+ if (trace->needsSaving())
+ trace->save();
+
+ ApiTraceFrame *frame = call->parentFrame();
+ int row = frame->callIndex(call);
+ QModelIndex index = createIndex(row, 0, call);
+ emit dataChanged(index, index);
+}
- QString argumentsText;
- for (int i = 0; i < call->sig->arg_names.size(); ++i) {
- apiCall->argNames +=
- QString::fromStdString(call->sig->arg_names[i]);
- }
- if (call->ret) {
- VariantVisitor retVisitor;
- call->ret->visit(retVisitor);
- apiCall->returnValue = retVisitor.variant();
- }
- for (int i = 0; i < call->args.size(); ++i) {
- VariantVisitor argVisitor;
- call->args[i]->visit(argVisitor);
- apiCall->argValues += argVisitor.variant();
- }
+void ApiTraceModel::endAddingFrames()
+{
+ endInsertRows();
+}
+
+bool ApiTraceModel::canFetchMore(const QModelIndex &parent) const
+{
+ if (parent.isValid()) {
+ ApiTraceEvent *event = item(parent);
+ if (event && event->type() == ApiTraceEvent::Frame) {
+ ApiTraceFrame *frame = static_cast<ApiTraceFrame*>(event);
+ return !frame->isLoaded() && !m_loadingFrames.contains(frame);
+ } else
+ return false;
+ } else {
+ return false;
+ }
+}
+
+void ApiTraceModel::fetchMore(const QModelIndex &parent)
+{
+ if (parent.isValid()) {
+ ApiTraceEvent *event = item(parent);
+ if (event && event->type() == ApiTraceEvent::Frame) {
+ ApiTraceFrame *frame = static_cast<ApiTraceFrame*>(event);
+ QModelIndex index = createIndex(frame->number, 0, frame);
+
+ Q_ASSERT(!frame->isLoaded());
+ m_loadingFrames.insert(frame);
- m_calls.append(apiCall);
+ m_trace->loadFrame(frame);
+ }
}
+}
+
+void ApiTraceModel::beginLoadingFrame(ApiTraceFrame *frame, int numAdded)
+{
+ QModelIndex index = createIndex(frame->number, 0, frame);
+ beginInsertRows(index, 0, numAdded - 1);
+}
+
+void ApiTraceModel::endLoadingFrame(ApiTraceFrame *frame)
+{
+ QModelIndex index = createIndex(frame->number, 0, frame);
+#if 0
+ qDebug()<<"Frame loaded = "<<frame->loaded();
+ qDebug()<<"\tframe idx = "<<frame->number;
+ qDebug()<<"\tis empty = "<<frame->isEmpty();
+ qDebug()<<"\tnum children = "<<frame->numChildren();
+ qDebug()<<"\tindex is "<<index;
+#endif
+
endInsertRows();
- qDeleteAll(traceCalls);
+ emit dataChanged(index, index);
+
+ m_loadingFrames.remove(frame);
}
#include "apitracemodel.moc"