QtDebugger/src/qtdebugger.cpp

154 lines
4.3 KiB
C++

#include "qtdebugger.h"
#include "ui_debugwindow.h"
#include <QApplication>
#include <QDebug>
#include <QMetaProperty>
#include <QMainWindow>
#include <QSplitter>
#include <QWindow>
#include <functional>
#include <set>
QtDebugger::QtDebugger(QObject* parent) : QObject(parent), debugWindow( new QMainWindow() ), ui( new Ui::DebugWindow() ) {
this->ui->setupUi( debugWindow );
debugWindow->show();
QList<int> sizes;
sizes << 40 << 70 << 150 << 490;
this->ui->splitter->setSizes( sizes );
QObject::connect( this->ui->refreshButton, &QPushButton::clicked, this, &QtDebugger::refresh );
QObject::connect( this->ui->windowList, &QListWidget::currentRowChanged, this, &QtDebugger::currentWindowChanged );
QObject::connect( this->ui->objectTree, &QTreeWidget::currentItemChanged, this, &QtDebugger::currentObjectChanged );
this->refresh();
}
QtDebugger::~QtDebugger() {
delete this->debugWindow;
delete this->ui;
}
void QtDebugger::refresh() {
this->ui->windowList->clear();
this->ui->objectTree->clear();
this->ui->propertiesTree->clear();
// get windows
QWindowList windows = qApp->allWindows();
for( const QWindow* win : windows ) {
QListWidgetItem* item = new QListWidgetItem( win->title() );
if ( win->winId() == debugWindow->winId() ) {
// not selectable or anything
item->setFlags( item->flags() & ~(Qt::ItemIsSelectable | Qt::ItemIsUserCheckable | Qt::ItemIsEnabled) );
}
item->setData(Qt::UserRole, win->winId());
this->ui->windowList->addItem( item );
}
this->currentWindowChanged( 0 );
}
void QtDebugger::currentWindowChanged( int row ) {
this->ui->objectTree->clear();
this->ui->propertiesTree->clear();
if ( row == -1) {
return;
}
// find the window id
QListWidgetItem* item = this->ui->windowList->item( row );
if( !item ) {
return;
}
QVariant data = item->data(Qt::UserRole);
bool ok = true;
WId wid = data.toULongLong( &ok );
// find the window
QWindowList windows = qApp->allWindows();
auto it = std::find_if( windows.constBegin(), windows.constEnd(), [wid](const QWindow* w){ return w->winId() == wid; } );
if( !ok || it == windows.constEnd() ) {
qWarning() << "invalid window";
return;
}
const QWindow* win = *it;
// update the tree
QTreeWidgetItem* root = new QTreeWidgetItem( );
root->setText( 0, "root" );
this->ui->objectTree->insertTopLevelItem( 0, root );
std::function<void(const QObject*, uint32_t, uint32_t, QTreeWidgetItem*)> walkTree = [&](const QObject* obj, uint32_t maxdepth, uint32_t currentDepth, QTreeWidgetItem* root) {
if ( !obj ) {
return;
}
QTreeWidgetItem* item = new QTreeWidgetItem( );
item->setText(0, obj->metaObject()->className() );
item->setText(1, obj->objectName() );
item->setData(0, Qt::UserRole, QVariant((unsigned long long) obj));
root->addChild( item );
if( currentDepth < maxdepth ) {
const QObjectList& childs = obj->children();
for( const QObject* child : childs ) {
walkTree( child, maxdepth, currentDepth+1, item );
}
}
};
walkTree( qApp, 128, 0, root);
walkTree( win, 128, 0, root);
}
void QtDebugger::currentObjectChanged( QTreeWidgetItem* new_ ) {
this->ui->propertiesTree->clear();
if ( !new_ ) {
qWarning() << "invalid row";
return;
}
// find the object
QVariant variant = new_->data(0, Qt::UserRole);
QObject* obj = (QObject*) variant.toULongLong();
if( !obj ) {
qWarning() << "invalid Object";
return;
}
// update the tree
std::function<void(const QMetaObject*)> readProperties
= [&] (const QMetaObject* meta) {
if (!meta) {
return;
}
QTreeWidgetItem* item = new QTreeWidgetItem();
item->setText(0, meta->className());
this->ui->propertiesTree->insertTopLevelItem( 0, item );
item->setExpanded( true );
// read superclass properties
readProperties(meta->superClass());
for( int32_t i = meta->propertyOffset(); i < meta->propertyCount(); ++i ) {
QMetaProperty prop = meta->property(i);
QString propName = prop.name();
QVariant propVal = prop.read(obj);
// QString value = propVal.canConvert<QString>() ? propVal.value<QString>() : "<unconvertable>";
QTreeWidgetItem* propItem = new QTreeWidgetItem();
propItem->setText(0, prop.typeName());
propItem->setText(1, propName);
propItem->setData(2, Qt::DisplayRole, propVal);
item->addChild( propItem );
}
};
readProperties( obj->metaObject() );
}