#include "qtdebugger.h" #include "ui_debugwindow.h" #include #include #include #include #include #include #include #include QtDebugger::QtDebugger(QObject* parent) : QObject(parent), debugWindow( new QMainWindow() ), ui( new Ui::DebugWindow() ) { this->ui->setupUi( debugWindow ); debugWindow->show(); QList 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 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 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() ? propVal.value() : ""; 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() ); }