X-Git-Url: https://git.cworth.org/git?a=blobdiff_plain;f=gui%2Fapitracemodel.cpp;h=0863c1b5bc0eb19ad1b649b9d83442483a2fc5ad;hb=3801952b80cd7a7160f6410518f6e3740d461b60;hp=0a31ce8fba45c908fa2e64ced005be3e8cd53930;hpb=96130aca85f0d828cae3da84dc9a7e258cbeb22a;p=apitrace diff --git a/gui/apitracemodel.cpp b/gui/apitracemodel.cpp index 0a31ce8..0863c1b 100644 --- a/gui/apitracemodel.cpp +++ b/gui/apitracemodel.cpp @@ -1,26 +1,24 @@ #include "apitracemodel.h" #include "apitracecall.h" -#include "loaderthread.h" +#include "traceloader.h" #include "trace_parser.hpp" +#include #include +#include #include ApiTraceModel::ApiTraceModel(QObject *parent) - : QAbstractItemModel(parent) + : QAbstractItemModel(parent), + m_trace(0) { - m_loader = new LoaderThread(); - - connect(m_loader, SIGNAL(parsedCalls(const QList&)), - SLOT(appendCalls(const QList&))); } ApiTraceModel::~ApiTraceModel() { - qDeleteAll(m_calls); - delete m_loader; + m_trace = 0; } QVariant ApiTraceModel::data(const QModelIndex &index, int role) const @@ -28,21 +26,87 @@ 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(itm); + if (!call->hasState()) + return QString::fromLatin1("%1) %2") + .arg(call->index()) + .arg(call->name()); + else + return QString::fromLatin1("%1) %2
%3") + .arg(call->index()) + .arg(call->name()) + .arg(stateText); + } else { + const char *htmlTempl = + "
\n" + "
\n" + "%1" + "\n" + "Frame %2\n" + "
\n" + "
%3 calls%4
\n" + "
\n"; + + + ApiTraceFrame *frame = static_cast(itm); + QString thumbStr, sizeStr; + + if (frame->hasState()) { + static const char *imgTempl = + "\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 @@ -59,7 +123,9 @@ QVariant ApiTraceModel::headerData(int section, Qt::Orientation orientation, 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; @@ -72,20 +138,43 @@ QVariant ApiTraceModel::headerData(int section, Qt::Orientation orientation, 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 "<type(); + return QModelIndex(); + } + ApiTraceFrame *frame = static_cast(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(event); + return !frame->isEmpty(); + } else + return false; + } else { + return (rowCount() > 0); + } } QModelIndex ApiTraceModel::parent(const QModelIndex &index) const @@ -93,21 +182,37 @@ 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(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(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) { @@ -121,60 +226,193 @@ bool ApiTraceModel::removeRows(int position, int rows, 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(ApiTraceEvent*)), + this, SLOT(changed(ApiTraceEvent*))); + 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(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(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(event); + const QList & frames = m_trace->frames(); + int row = frames.indexOf(frame); + QModelIndex index = createIndex(row, 0, frame); + emit dataChanged(index, index); } - removeRows(0, m_calls.count(), QModelIndex()); +} + +QModelIndex ApiTraceModel::indexForCall(ApiTraceCall *call) const +{ + if (!call) { + return QModelIndex(); + } + + ApiTraceFrame *frame = call->parentFrame(); + Q_ASSERT(frame); + + int row = frame->callIndex(call); + if (row < 0) { + qDebug() << "Couldn't find call num "<index()<<" inside parent!"; + return QModelIndex(); + } + return createIndex(row, 0, call); +} - m_loader->loadFile(fileName); +void ApiTraceModel::changed(ApiTraceEvent *event) +{ + if (event->type() == ApiTraceEvent::Call) { + callChanged(static_cast(event)); + } else if (event->type() == ApiTraceEvent::Frame) { + frameChanged(static_cast(event)); + } } -void ApiTraceModel::appendCalls(const QList 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 = "<edited(); + qDebug()<<"\ttrace edited = "<edited(); + qDebug()<<"\ttrace file = "<fileName(); + qDebug()<<"\ttrace needs saving = "<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::frameChanged(ApiTraceFrame *frame) +{ + const QList & frames = m_trace->frames(); + int row = frames.indexOf(frame); + QModelIndex index = createIndex(row, 0, frame); + emit dataChanged(index, index); +} - m_calls.append(apiCall); +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(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(event); + QModelIndex index = createIndex(frame->number, 0, frame); + + Q_ASSERT(!frame->isLoaded()); + m_loadingFrames.insert(frame); + + 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 = "<loaded(); + qDebug()<<"\tframe idx = "<number; + qDebug()<<"\tis empty = "<isEmpty(); + qDebug()<<"\tnum children = "<numChildren(); + qDebug()<<"\tindex is "<