]> git.cworth.org Git - apitrace/blobdiff - gui/apitracemodel.cpp
Update downloads link.
[apitrace] / gui / apitracemodel.cpp
index 0a31ce8fba45c908fa2e64ced005be3e8cd53930..0863c1b5bc0eb19ad1b649b9d83442483a2fc5ad 100644 (file)
@@ -1,26 +1,24 @@
 #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
@@ -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<ApiTraceCall*>(itm);
+            if (!call->hasState())
+                return QString::fromLatin1("%1)&nbsp;<b>%2</b>")
+                    .arg(call->index())
+                    .arg(call->name());
+            else
+                return QString::fromLatin1("%1)&nbsp;<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
@@ -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 "<<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
@@ -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<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)
 {
@@ -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<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);
     }
-    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 "<<call->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<ApiTraceCall*>(event));
+    } else if (event->type() == ApiTraceEvent::Frame) {
+        frameChanged(static_cast<ApiTraceFrame*>(event));
+    }
 }
 
-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::frameChanged(ApiTraceFrame *frame)
+{
+    const QList<ApiTraceFrame*> & 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<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_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"