]> git.cworth.org Git - apitrace/commitdiff
Add a basic gui for apitrace.
authorZack Rusin <zack@kde.org>
Fri, 25 Mar 2011 02:23:21 +0000 (22:23 -0400)
committerZack Rusin <zack@kde.org>
Thu, 31 Mar 2011 02:48:41 +0000 (22:48 -0400)
CMakeLists.txt
gui/CMakeLists.txt [new file with mode: 0644]
gui/apitracecall.h [new file with mode: 0644]
gui/apitracemodel.cpp [new file with mode: 0644]
gui/apitracemodel.h [new file with mode: 0644]
gui/loaderthread.cpp [new file with mode: 0644]
gui/loaderthread.h [new file with mode: 0644]
gui/main.cpp [new file with mode: 0644]
gui/mainwindow.cpp [new file with mode: 0644]
gui/mainwindow.h [new file with mode: 0644]
gui/ui/mainwindow.ui [new file with mode: 0644]

index 3528b5f6d7d9e7fa146451e48bce06d0cfc172f4..4e6d2ad01cfc201af522e44102720bfbccad719d 100644 (file)
@@ -238,4 +238,4 @@ if (GLUT_INCLUDE_DIR)
     )
 endif (GLUT_INCLUDE_DIR)
 
-
+add_subdirectory(gui)
diff --git a/gui/CMakeLists.txt b/gui/CMakeLists.txt
new file mode 100644 (file)
index 0000000..161bfef
--- /dev/null
@@ -0,0 +1,53 @@
+cmake_minimum_required(VERSION 2.8)
+
+find_package(Qt4 REQUIRED)
+
+set(qapitrace_SRCS
+   ../trace_model.cpp
+   apitracemodel.cpp
+   loaderthread.cpp
+   mainwindow.cpp
+   main.cpp
+ )
+
+qt4_automoc(${qapitrace_SRCS})
+
+set(qapitrace_UIS
+   ui/mainwindow.ui)
+
+QT4_WRAP_UI(qapitrace_UIS_H ${qapitrace_UIS})
+
+#add_app_icon(qapitrace_SRCS ../icons/hi*-qapitrace.png)
+
+if (ZLIB_FOUND)
+    include_directories (${ZLIB_INCLUDE_DIRS})
+    link_libraries (${ZLIB_LIBRARIES})
+else (ZLIB_FOUND)
+    add_library (zlib STATIC
+        ../zlib/adler32.c
+        ../zlib/compress.c
+        ../zlib/crc32.c
+        ../zlib/gzio.c
+        ../zlib/uncompr.c
+        ../zlib/deflate.c
+        ../zlib/trees.c
+        ../zlib/zutil.c
+        ../zlib/inflate.c
+        ../zlib/infback.c
+        ../zlib/inftrees.c
+        ../zlib/inffast.c
+    )
+    include_directories (zlib)
+    link_libraries (zlib)
+endif (ZLIB_FOUND)
+
+include_directories(${QT_INCLUDES} ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/..)
+
+add_executable(qapitrace ${qapitrace_SRCS} ${qapitrace_UIS_H})
+
+target_link_libraries(qapitrace ${QT_QTCORE_LIBRARIES} ${QT_QTGUI_LIBRARIES} )
+
+########### install files ###############
+
+#install(TARGETS qapitrace ${INSTALL_TARGETS_DEFAULT_ARGS} )
+#install( FILES qapitrace.desktop  DESTINATION ${XDG_APPS_INSTALL_DIR} )
diff --git a/gui/apitracecall.h b/gui/apitracecall.h
new file mode 100644 (file)
index 0000000..6474663
--- /dev/null
@@ -0,0 +1,16 @@
+#ifndef APITRACECALL_H
+#define APITRACECALL_H
+
+#include <QStringList>
+#include <QVariant>
+
+class ApiTraceCall
+{
+public:
+    QString name;
+    QStringList argNames;
+    QVariantList argValues;
+    QVariant returnValue;
+};
+
+#endif
diff --git a/gui/apitracemodel.cpp b/gui/apitracemodel.cpp
new file mode 100644 (file)
index 0000000..826a35b
--- /dev/null
@@ -0,0 +1,267 @@
+#include "apitracemodel.h"
+
+#include "apitracecall.h"
+#include "loaderthread.h"
+#include "trace_parser.hpp"
+
+#include <QVariant>
+
+class VariantVisitor : public Trace::Visitor
+{
+public:
+    virtual void visit(Trace::Null *)
+    {
+        // Nothing
+    }
+    virtual void visit(Trace::Bool *node)
+    {
+        m_variant = QVariant(node->value);
+    }
+    virtual void visit(Trace::SInt *node)
+    {
+        m_variant = QVariant(node->value);
+    }
+    virtual void visit(Trace::UInt *node)
+    {
+        m_variant = QVariant(node->value);
+    }
+    virtual void visit(Trace::Float *node)
+    {
+        m_variant = QVariant(node->value);
+    }
+    virtual void visit(Trace::String *node)
+    {
+        m_variant = QVariant(QString::fromStdString(node->value));
+    }
+    virtual void visit(Trace::Enum *e)
+    {
+        m_variant = QVariant(QString::fromStdString(e->sig->first));
+    }
+    virtual void visit(Trace::Bitmask *bitmask)
+    {
+        //XXX we should probably convert it to QImage
+        visit(static_cast<Trace::UInt *>(bitmask));
+    }
+    virtual void visit(Trace::Struct *str)
+    {
+        //XXX: need a custom QVariant type for this one
+        QVariantList lst;
+        for (int i = 0; i < str->members.size(); ++i) {
+            VariantVisitor vst;
+            str->members[i]->visit(vst);
+            lst.append(vst.variant());
+        }
+        m_variant = QVariant(lst);
+    }
+    virtual void visit(Trace::Array *array)
+    {
+        QVariantList lst;
+        for (int i = 0; i < array->values.size(); ++i) {
+            VariantVisitor vst;
+            array->values[i]->visit(vst);
+            lst.append(vst.variant());
+        }
+        m_variant = QVariant(lst);
+    }
+    virtual void visit(Trace::Blob *blob)
+    {
+        QByteArray barray = QByteArray::fromRawData(blob->buf, blob->size);
+        m_variant = QVariant(barray);
+    }
+    virtual void visit(Trace::Pointer *ptr)
+    {
+        m_variant = QVariant(ptr->value);
+    }
+
+    QVariant variant() const
+    {
+        return m_variant;
+    }
+private:
+    QVariant m_variant;
+};
+
+ApiTraceModel::ApiTraceModel(QObject *parent)
+    : QAbstractItemModel(parent)
+{
+    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;
+}
+
+QVariant ApiTraceModel::data(const QModelIndex &index, int role) const
+{
+    if (!index.isValid())
+        return QVariant();
+
+    if (role != Qt::DisplayRole)
+        return QVariant();
+
+    ApiTraceCall *item = m_calls.value(index.row());
+
+    if (!item)
+        return QVariant();
+
+    switch (index.column()) {
+    case 0:
+        return item->name;
+    case 1: {
+        QString str;
+        for (int i = 0; i < item->argNames.count(); ++i) {
+            str += item->argNames[i];
+            str += QString::fromLatin1(" = ");
+            str += item->argValues[i].toString();
+            if (i < item->argNames.count() - 1)
+                str += QString::fromLatin1(", ");
+        }
+        return str;
+    }
+    case 2:
+        return item->returnValue.toString();
+    default:
+        return QVariant();
+    }
+}
+
+Qt::ItemFlags ApiTraceModel::flags(const QModelIndex &index) const
+{
+    if (!index.isValid())
+        return 0;
+
+    return Qt::ItemIsEnabled | Qt::ItemIsSelectable;
+}
+
+QVariant ApiTraceModel::headerData(int section, Qt::Orientation orientation,
+                                   int role ) const
+{
+    if (orientation == Qt::Horizontal && role == Qt::DisplayRole) {
+        switch (section) {
+        case 0:
+            return tr("Function");
+        case 1:
+            return tr("Arguments");
+        case 2:
+            return tr("Return");
+        default:
+            //fall through
+            break;
+        }
+    }
+
+    return QVariant();
+}
+
+QModelIndex ApiTraceModel::index(int row, int column,
+                                 const QModelIndex &parent) const
+{
+    if (parent.isValid() && parent.column() != 0)
+        return QModelIndex();
+
+    ApiTraceCall *call = m_calls.value(row);
+
+    if (call)
+        return createIndex(row, column, call);
+    else
+        return QModelIndex();
+}
+
+bool ApiTraceModel::hasChildren(const QModelIndex &parent) const
+{
+    return parent.isValid() ? false : (rowCount() > 0);
+}
+
+QModelIndex ApiTraceModel::parent(const QModelIndex &index) const
+{
+    if (!index.isValid())
+        return QModelIndex();
+
+    //list for now
+    return QModelIndex();
+}
+
+int ApiTraceModel::rowCount(const QModelIndex &parent) const
+{
+    return m_calls.count();
+}
+
+int ApiTraceModel::columnCount(const QModelIndex &parent) const
+{
+    return parent.isValid() ? 0 : 3;
+}
+
+
+bool ApiTraceModel::insertRows(int position, int rows,
+                               const QModelIndex &parent)
+{
+    return false;
+}
+
+bool ApiTraceModel::removeRows(int position, int rows,
+                               const QModelIndex &parent)
+{
+    bool success = true;
+
+    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;
+    }
+    endRemoveRows();
+
+    return success;
+}
+
+void ApiTraceModel::loadTraceFile(const QString &fileName)
+{
+    if (m_loader->isRunning()) {
+        m_loader->terminate();
+        m_loader->wait();
+    }
+    removeRows(0, m_calls.count(), QModelIndex());
+
+    m_loader->loadFile(fileName);
+}
+
+void ApiTraceModel::appendCalls(const QList<Trace::Call*> traceCalls)
+{
+    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);
+
+        QString argumentsText;
+        for (int i = 0; i < call->sig->arg_names.size(); ++i) {
+            apiCall->argNames +=
+                QString::fromStdString(call->sig->arg_names[i]);
+        }
+        VariantVisitor retVisitor;
+        if (call->ret) {
+            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();
+        }
+        m_calls.append(apiCall);
+    }
+    endInsertRows();
+
+    qDeleteAll(traceCalls);
+}
+
+#include "apitracemodel.moc"
diff --git a/gui/apitracemodel.h b/gui/apitracemodel.h
new file mode 100644 (file)
index 0000000..422259e
--- /dev/null
@@ -0,0 +1,48 @@
+#ifndef APITRACEMODEL_H
+#define APITRACEMODEL_H
+
+
+#include <QAbstractItemModel>
+#include <QModelIndex>
+#include <QVariant>
+
+class ApiTraceCall;
+class LoaderThread;
+namespace Trace {
+    class Call;
+}
+
+class ApiTraceModel : public QAbstractItemModel
+{
+    Q_OBJECT
+
+public:
+    ApiTraceModel(QObject *parent = 0);
+    ~ApiTraceModel();
+
+    QVariant data(const QModelIndex &index, int role) const;
+    Qt::ItemFlags flags(const QModelIndex &index) const;
+    QVariant headerData(int section, Qt::Orientation orientation,
+                        int role = Qt::DisplayRole) const;
+    QModelIndex index(int row, int column,
+                      const QModelIndex &parent = QModelIndex()) const;
+    bool hasChildren(const QModelIndex &parent) const;
+    QModelIndex parent(const QModelIndex &index) const;
+    int rowCount(const QModelIndex &parent = QModelIndex()) const;
+    int columnCount(const QModelIndex &parent = QModelIndex()) const;
+
+    bool insertRows(int position, int rows,
+                    const QModelIndex &parent = QModelIndex());
+    bool removeRows(int position, int rows,
+                    const QModelIndex &parent = QModelIndex());
+
+public slots:
+    void loadTraceFile(const QString &fileName);
+    void appendCalls(const QList<Trace::Call*> traceCalls);
+
+private:
+    QList<ApiTraceCall*> m_calls;
+    LoaderThread        *m_loader;
+};
+
+#endif
diff --git a/gui/loaderthread.cpp b/gui/loaderthread.cpp
new file mode 100644 (file)
index 0000000..c8cbe57
--- /dev/null
@@ -0,0 +1,39 @@
+#include "loaderthread.h"
+
+#include "trace_parser.hpp"
+
+LoaderThread::LoaderThread(QObject *parent)
+    : QThread(parent)
+{
+}
+
+void LoaderThread::run()
+{
+    QList<Trace::Call*> traceCalls;
+    Trace::Parser p;
+    if (p.open(m_fileName.toLatin1().constData())) {
+        Trace::Call *call;
+        call = p.parse_call();
+        while (call) {
+            //std::cout << *call;
+            traceCalls.append(call);
+            if (traceCalls.count() >= 1000) {
+                emit parsedCalls(traceCalls);
+                traceCalls.clear();
+            }
+            call = p.parse_call();
+        }
+    }
+    if (traceCalls.count()) {
+        emit parsedCalls(traceCalls);
+        traceCalls.clear();
+    }
+}
+
+void LoaderThread::loadFile(const QString &fileName)
+{
+    m_fileName = fileName;
+    start();
+}
+
+#include "loaderthread.moc"
diff --git a/gui/loaderthread.h b/gui/loaderthread.h
new file mode 100644 (file)
index 0000000..4914815
--- /dev/null
@@ -0,0 +1,31 @@
+#ifndef LOADERTHREAD_H
+#define LOADERTHREAD_H
+
+#include <QThread>
+#include <QList>
+
+class ApiTraceCall;
+namespace Trace {
+    class Call;
+}
+
+class LoaderThread : public QThread
+{
+    Q_OBJECT
+public:
+    LoaderThread(QObject *parent=0);
+
+public slots:
+    void loadFile(const QString &fileName);
+
+signals:
+    void parsedCalls(const QList<Trace::Call*> &calls);
+
+protected:
+    virtual void run();
+
+private:
+    QString m_fileName;
+};
+
+#endif
diff --git a/gui/main.cpp b/gui/main.cpp
new file mode 100644 (file)
index 0000000..dcfb6c2
--- /dev/null
@@ -0,0 +1,24 @@
+#include "mainwindow.h"
+
+#include "trace_model.hpp"
+
+#include <QApplication>
+#include <QMetaType>
+#include <QVariant>
+
+Q_DECLARE_METATYPE(QList<Trace::Call*>);
+
+int main(int argc, char **argv)
+{
+    QApplication app(argc, argv);
+
+    qRegisterMetaType<QList<Trace::Call*> >();
+    MainWindow window;
+
+    window.show();
+
+    if (app.arguments().count() == 2)
+        window.loadTrace(app.arguments()[1]);
+
+    app.exec();
+}
diff --git a/gui/mainwindow.cpp b/gui/mainwindow.cpp
new file mode 100644 (file)
index 0000000..d04b61d
--- /dev/null
@@ -0,0 +1,46 @@
+#include "mainwindow.h"
+
+#include "apitracemodel.h"
+
+#include <QAction>
+#include <QDebug>
+#include <QDir>
+#include <QFileDialog>
+
+
+MainWindow::MainWindow()
+    : QMainWindow()
+{
+    m_ui.setupUi(this);
+
+    m_model = new ApiTraceModel();
+    m_ui.callView->setModel(m_model);
+    for (int column = 0; column < m_model->columnCount(); ++column)
+        m_ui.callView->resizeColumnToContents(column);
+
+    connect(m_ui.actionOpen, SIGNAL(triggered()),
+            this, SLOT(openTrace()));
+}
+
+void MainWindow::openTrace()
+{
+    QString fileName =
+        QFileDialog::getOpenFileName(
+            this,
+            tr("Open Trace"),
+            QDir::homePath(),
+            tr("Trace Files (*.trace)"));
+
+    qDebug()<< "File name : " <<fileName;
+
+    m_model->loadTraceFile(fileName);
+}
+
+void MainWindow::loadTrace(const QString &fileName)
+{
+    qDebug()<< "Loading  : " <<fileName;
+
+    m_model->loadTraceFile(fileName);
+}
+
+#include "mainwindow.moc"
diff --git a/gui/mainwindow.h b/gui/mainwindow.h
new file mode 100644 (file)
index 0000000..e7107f5
--- /dev/null
@@ -0,0 +1,28 @@
+#ifndef MAINWINDOW_H
+#define MAINWINDOW_H
+
+#include "ui_mainwindow.h"
+
+#include <QtGui/QMainWindow>
+
+class ApiTraceModel;
+
+class MainWindow : public QMainWindow
+{
+    Q_OBJECT
+public:
+    MainWindow();
+
+public slots:
+    void loadTrace(const QString &fileName);
+
+private slots:
+    void openTrace();
+
+private:
+    Ui_MainWindow m_ui;
+    ApiTraceModel *m_model;
+};
+
+
+#endif
diff --git a/gui/ui/mainwindow.ui b/gui/ui/mainwindow.ui
new file mode 100644 (file)
index 0000000..4cc5d09
--- /dev/null
@@ -0,0 +1,66 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>MainWindow</class>
+ <widget class="QMainWindow" name="MainWindow">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>799</width>
+    <height>590</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>MainWindow</string>
+  </property>
+  <widget class="QWidget" name="centralwidget">
+   <layout class="QHBoxLayout" name="horizontalLayout">
+    <item>
+     <widget class="QTreeView" name="callView">
+      <property name="alternatingRowColors">
+       <bool>true</bool>
+      </property>
+      <property name="uniformRowHeights">
+       <bool>true</bool>
+      </property>
+     </widget>
+    </item>
+   </layout>
+  </widget>
+  <widget class="QMenuBar" name="menubar">
+   <property name="geometry">
+    <rect>
+     <x>0</x>
+     <y>0</y>
+     <width>799</width>
+     <height>21</height>
+    </rect>
+   </property>
+   <widget class="QMenu" name="menuFile">
+    <property name="title">
+     <string>File</string>
+    </property>
+    <addaction name="actionOpen"/>
+   </widget>
+   <addaction name="menuFile"/>
+  </widget>
+  <widget class="QStatusBar" name="statusbar"/>
+  <action name="actionExit">
+   <property name="text">
+    <string>Exit</string>
+   </property>
+  </action>
+  <action name="actionExit_2">
+   <property name="text">
+    <string>Exit</string>
+   </property>
+  </action>
+  <action name="actionOpen">
+   <property name="text">
+    <string>Open</string>
+   </property>
+  </action>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>