]> git.cworth.org Git - apitrace/blobdiff - gui/apitracemodel.cpp
Implement grouping of calls.
[apitrace] / gui / apitracemodel.cpp
index c135bc15fac605d12a500dab081c3e0252b3bd2f..fb339677c5934c7825053a7ed7c098fd6e00fc89 100644 (file)
@@ -1,10 +1,12 @@
 #include "apitracemodel.h"
 
 #include "apitracecall.h"
-#include "loaderthread.h"
+#include "traceloader.h"
 #include "trace_parser.hpp"
 
+#include <QBuffer>
 #include <QDebug>
+#include <QImage>
 #include <QVariant>
 
 
@@ -24,25 +26,85 @@ QVariant ApiTraceModel::data(const QModelIndex &index, int role) const
     if (!index.isValid())
         return QVariant();
 
-    if (role != Qt::DisplayRole)
-        return QVariant();
-
-    //data only in the first column
     if (index.column() != 0)
         return QVariant();
 
     ApiTraceEvent *itm = item(index);
-    if (itm) {
-        if (itm->type() == ApiTraceEvent::Frame) {
-            ApiTraceFrame *frame =
-                static_cast<ApiTraceFrame *>(itm);
-            return QVariant::fromValue(frame);
-        } else if (itm->type() == ApiTraceEvent::Call) {
-            ApiTraceCall *call =
-                static_cast<ApiTraceCall *>(itm);
-            return QVariant::fromValue(call);
+    if (!itm) {
+        return QVariant();
+    }
+
+    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->numTotalCalls()
+                    : frame->numChildrenToLoad();
+
+            return tr(htmlTempl)
+                    .arg(thumbStr)
+                    .arg(frame->number)
+                    .arg(numCalls)
+                    .arg(sizeStr);
         }
     }
+    case ApiTraceModel::EventRole:
+        return QVariant::fromValue(itm);
+    }
 
     return QVariant();
 }
@@ -61,7 +123,9 @@ QVariant ApiTraceModel::headerData(int section, Qt::Orientation orientation,
     if (orientation == Qt::Horizontal && role == Qt::DisplayRole) {
         switch (section) {
         case 0:
-            return tr("Event");
+            return tr("Events");
+        case 1:
+            return tr("Flags");
         default:
             //fall through
             break;
@@ -74,21 +138,19 @@ 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();
 
-    if (parent.isValid()) {
-        QVariant data = parent.data();
-        ApiTraceFrame *frame = data.value<ApiTraceFrame*>();
-        if (!frame) {
-            qDebug()<<"got a valid parent but it's not a frame "<<data;
+    //qDebug()<<"At row = "<<row<<", column = "<<column<<", parent "<<parent;
+    ApiTraceEvent *parentEvent = item(parent);
+    if (parentEvent) {
+        ApiTraceEvent *event = parentEvent->eventAtRow(row);
+        if (event) {
+            Q_ASSERT(event->type() == ApiTraceEvent::Call);
+            return createIndex(row, column, event);
+        } else {
             return QModelIndex();
         }
-        ApiTraceCall *call = frame->calls.value(row);
-        if (call)
-            return createIndex(row, column, call);
-        else
-            return QModelIndex();
     } else {
         ApiTraceFrame *frame = m_trace->frameAt(row);
         if (frame)
@@ -102,11 +164,17 @@ QModelIndex ApiTraceModel::index(int row, int column,
 bool ApiTraceModel::hasChildren(const QModelIndex &parent) const
 {
     if (parent.isValid()) {
-        ApiTraceFrame *frame = parent.data().value<ApiTraceFrame*>();
-        if (frame)
-            return !frame->calls.isEmpty();
-        else
+        ApiTraceEvent *event = item(parent);
+        if (!event)
             return false;
+        if (event->type() == ApiTraceEvent::Frame) {
+            ApiTraceFrame *frame = static_cast<ApiTraceFrame*>(event);
+            return !frame->isEmpty();
+        } else {
+            Q_ASSERT(event->type() == ApiTraceEvent::Call);
+            ApiTraceCall *call = static_cast<ApiTraceCall*>(event);
+            return call->numChildren() != 0;
+        }
     } else {
         return (rowCount() > 0);
     }
@@ -117,11 +185,20 @@ QModelIndex ApiTraceModel::parent(const QModelIndex &index) const
     if (!index.isValid())
         return QModelIndex();
 
-    ApiTraceCall *call = index.data().value<ApiTraceCall*>();
-    if (call) {
-        Q_ASSERT(call->parentFrame);
-        return createIndex(call->parentFrame->number,
-                           0, call->parentFrame);
+    ApiTraceEvent *event = item(index);
+
+    if (event->type() == ApiTraceEvent::Call) {
+        ApiTraceCall *call = static_cast<ApiTraceCall*>(event);
+
+        if (call->parentCall()) {
+            ApiTraceCall *parentCall = call->parentCall();
+            ApiTraceEvent *topEvent = parentCall->parentEvent();
+            return createIndex(topEvent->callIndex(parentCall), 0, parentCall);
+        } else {
+            Q_ASSERT(call->parentFrame());
+            return createIndex(call->parentFrame()->number,
+                               0, call->parentFrame());
+        }
     }
     return QModelIndex();
 }
@@ -131,15 +208,11 @@ int ApiTraceModel::rowCount(const QModelIndex &parent) const
     if (!parent.isValid())
         return m_trace->numFrames();
 
-    ApiTraceCall *call = parent.data().value<ApiTraceCall*>();
-    if (call)
+    ApiTraceEvent *event = item(parent);
+    if (!event)
         return 0;
 
-    ApiTraceFrame *frame = parent.data().value<ApiTraceFrame*>();
-    if (frame)
-        return frame->calls.count();
-
-    return 0;
+    return event->numChildren();
 }
 
 int ApiTraceModel::columnCount(const QModelIndex &parent) const
@@ -147,7 +220,6 @@ int ApiTraceModel::columnCount(const QModelIndex &parent) const
     return 1;
 }
 
-
 bool ApiTraceModel::insertRows(int position, int rows,
                                const QModelIndex &parent)
 {
@@ -175,10 +247,21 @@ void ApiTraceModel::setApiTrace(ApiTrace *trace)
     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(framesAdded(int, int)),
-            this, SLOT(appendFrames(int, int)));
+    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
@@ -192,11 +275,10 @@ void ApiTraceModel::invalidateFrames()
     endResetModel();
 }
 
-void ApiTraceModel::appendFrames(int oldCount, int numAdded)
+void ApiTraceModel::beginAddingFrames(int oldCount, int numAdded)
 {
     beginInsertRows(QModelIndex(), oldCount,
-                    oldCount + numAdded);
-    endInsertRows();
+                    oldCount + numAdded - 1);
 }
 
 ApiTraceEvent * ApiTraceModel::item(const QModelIndex &index) const
@@ -206,4 +288,134 @@ ApiTraceEvent * ApiTraceModel::item(const QModelIndex &index) const
     return static_cast<ApiTraceEvent*>(index.internalPointer());
 }
 
+void ApiTraceModel::stateSetOnEvent(ApiTraceEvent *event)
+{
+    if (!event)
+        return;
+
+    if (event->type() == ApiTraceEvent::Call) {
+        ApiTraceCall *call = static_cast<ApiTraceCall*>(event);
+        QModelIndex index = indexForCall(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();
+    }
+
+    ApiTraceEvent *parentEvent = call->parentEvent();
+    Q_ASSERT(parentEvent);
+
+    int row = parentEvent->callIndex(call);
+    if (row < 0) {
+        qDebug() << "Couldn't find call num "<<call->index()<<" inside parent!";
+        return QModelIndex();
+    }
+    return createIndex(row, 0, call);
+}
+
+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::callChanged(ApiTraceCall *call)
+{
+    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();
+
+    QModelIndex index = indexForCall(call);
+    emit dataChanged(index, index);
+}
+
+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);
+}
+
+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();
+
+    emit dataChanged(index, index);
+
+    m_loadingFrames.remove(frame);
+}
+
 #include "apitracemodel.moc"