From: Zack Rusin Date: Fri, 25 Mar 2011 02:23:21 +0000 (-0400) Subject: Add a basic gui for apitrace. X-Git-Url: https://git.cworth.org/git?a=commitdiff_plain;h=601e8376b1496ff2a46f9d5c1ff82c29f2446fa3;p=apitrace Add a basic gui for apitrace. --- diff --git a/CMakeLists.txt b/CMakeLists.txt index 3528b5f..4e6d2ad 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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 index 0000000..161bfef --- /dev/null +++ b/gui/CMakeLists.txt @@ -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 index 0000000..6474663 --- /dev/null +++ b/gui/apitracecall.h @@ -0,0 +1,16 @@ +#ifndef APITRACECALL_H +#define APITRACECALL_H + +#include +#include + +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 index 0000000..826a35b --- /dev/null +++ b/gui/apitracemodel.cpp @@ -0,0 +1,267 @@ +#include "apitracemodel.h" + +#include "apitracecall.h" +#include "loaderthread.h" +#include "trace_parser.hpp" + +#include + +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(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&)), + SLOT(appendCalls(const QList&))); +} + +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 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 index 0000000..422259e --- /dev/null +++ b/gui/apitracemodel.h @@ -0,0 +1,48 @@ +#ifndef APITRACEMODEL_H +#define APITRACEMODEL_H + + +#include +#include +#include + +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 traceCalls); + +private: + QList m_calls; + LoaderThread *m_loader; +}; + +#endif diff --git a/gui/loaderthread.cpp b/gui/loaderthread.cpp new file mode 100644 index 0000000..c8cbe57 --- /dev/null +++ b/gui/loaderthread.cpp @@ -0,0 +1,39 @@ +#include "loaderthread.h" + +#include "trace_parser.hpp" + +LoaderThread::LoaderThread(QObject *parent) + : QThread(parent) +{ +} + +void LoaderThread::run() +{ + QList 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 index 0000000..4914815 --- /dev/null +++ b/gui/loaderthread.h @@ -0,0 +1,31 @@ +#ifndef LOADERTHREAD_H +#define LOADERTHREAD_H + +#include +#include + +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 &calls); + +protected: + virtual void run(); + +private: + QString m_fileName; +}; + +#endif diff --git a/gui/main.cpp b/gui/main.cpp new file mode 100644 index 0000000..dcfb6c2 --- /dev/null +++ b/gui/main.cpp @@ -0,0 +1,24 @@ +#include "mainwindow.h" + +#include "trace_model.hpp" + +#include +#include +#include + +Q_DECLARE_METATYPE(QList); + +int main(int argc, char **argv) +{ + QApplication app(argc, argv); + + qRegisterMetaType >(); + 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 index 0000000..d04b61d --- /dev/null +++ b/gui/mainwindow.cpp @@ -0,0 +1,46 @@ +#include "mainwindow.h" + +#include "apitracemodel.h" + +#include +#include +#include +#include + + +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 : " <loadTraceFile(fileName); +} + +void MainWindow::loadTrace(const QString &fileName) +{ + qDebug()<< "Loading : " <loadTraceFile(fileName); +} + +#include "mainwindow.moc" diff --git a/gui/mainwindow.h b/gui/mainwindow.h new file mode 100644 index 0000000..e7107f5 --- /dev/null +++ b/gui/mainwindow.h @@ -0,0 +1,28 @@ +#ifndef MAINWINDOW_H +#define MAINWINDOW_H + +#include "ui_mainwindow.h" + +#include + +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 index 0000000..4cc5d09 --- /dev/null +++ b/gui/ui/mainwindow.ui @@ -0,0 +1,66 @@ + + + MainWindow + + + + 0 + 0 + 799 + 590 + + + + MainWindow + + + + + + + true + + + true + + + + + + + + + 0 + 0 + 799 + 21 + + + + + File + + + + + + + + + Exit + + + + + Exit + + + + + Open + + + + + +