mirror of
https://bitbucket.org/smil3y/kdelibs.git
synced 2025-02-23 10:22:48 +00:00
kdeui: new KDebugger class
I've had the idea about it in my head for years Signed-off-by: Ivailo Monev <xakepa10@gmail.com>
This commit is contained in:
parent
76d8f5c423
commit
ec7b5bd959
5 changed files with 418 additions and 3 deletions
|
@ -279,6 +279,7 @@ KCmdLineArgsStatic::KCmdLineArgsStatic () {
|
|||
#endif
|
||||
kde_options.add("geometry <geometry>", ki18n("sets the client geometry of the main widget - see man X for the argument format (usually WidthxHeight+XPos+YPos)"));
|
||||
kde_options.add("smkey <sessionKey>"); // this option is obsolete and exists only to allow smooth upgrades from sessions
|
||||
kde_options.add("debugger", ki18n("Show debugger"));
|
||||
}
|
||||
|
||||
KCmdLineArgsStatic::~KCmdLineArgsStatic ()
|
||||
|
|
|
@ -169,6 +169,7 @@ set(kdeui_LIB_SRCS
|
|||
util/kimageio.cpp
|
||||
util/kkeyserver_x11.cpp
|
||||
util/kkeyboardlayout.cpp
|
||||
util/kdebugger.cpp
|
||||
widgets/kactionselector.cpp
|
||||
widgets/kdialogbuttonbox.cpp
|
||||
widgets/kbuttongroup.cpp
|
||||
|
@ -397,6 +398,7 @@ install(
|
|||
util/kguiitem.h
|
||||
util/kkeyserver.h
|
||||
util/kkeyboardlayout.h
|
||||
util/kdebugger.h
|
||||
util/kselectionowner.h
|
||||
util/knumvalidator.h
|
||||
util/kpassivepopup.h
|
||||
|
|
|
@ -58,6 +58,7 @@
|
|||
#include "kmenu.h"
|
||||
#include "kconfiggroup.h"
|
||||
#include "kactioncollection.h"
|
||||
#include "kdebugger.h"
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
|
@ -127,6 +128,7 @@ public:
|
|||
, session_save(false)
|
||||
, pSessionConfig(nullptr)
|
||||
, bSessionManagement(true)
|
||||
, debugger(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -138,6 +140,7 @@ public:
|
|||
, session_save(false)
|
||||
, pSessionConfig(nullptr)
|
||||
, bSessionManagement(true)
|
||||
, debugger(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -149,6 +152,7 @@ public:
|
|||
, session_save(false)
|
||||
, pSessionConfig(nullptr)
|
||||
, bSessionManagement(true)
|
||||
, debugger(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -170,6 +174,8 @@ public:
|
|||
QString sessionKey;
|
||||
KConfig* pSessionConfig; //instance specific application config object
|
||||
bool bSessionManagement;
|
||||
|
||||
KDebugger* debugger;
|
||||
};
|
||||
|
||||
static QList< QWeakPointer< QWidget > > *x11Filter = 0;
|
||||
|
@ -652,15 +658,24 @@ void KApplicationPrivate::parseCommandLine( )
|
|||
if (args->isSet("smkey")) {
|
||||
sessionKey = args->getOption("smkey");
|
||||
}
|
||||
|
||||
if (args->isSet("debugger")) {
|
||||
debugger = new KDebugger();
|
||||
debugger->show();
|
||||
}
|
||||
}
|
||||
|
||||
KApplication::~KApplication()
|
||||
{
|
||||
delete d;
|
||||
KApp = 0;
|
||||
if (d->debugger) {
|
||||
delete d->debugger;
|
||||
}
|
||||
|
||||
delete d;
|
||||
KApp = 0;
|
||||
|
||||
#ifdef Q_WS_X11
|
||||
mySmcConnection = 0;
|
||||
mySmcConnection = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
350
kdeui/util/kdebugger.cpp
Normal file
350
kdeui/util/kdebugger.cpp
Normal file
|
@ -0,0 +1,350 @@
|
|||
/*
|
||||
This file is part of the KDE libraries
|
||||
Copyright (C) 2024 Ivailo Monev <xakepa10@gmail.com>
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public
|
||||
License version 2, as published by the Free Software Foundation.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public License
|
||||
along with this library; see the file COPYING.LIB. If not, write to
|
||||
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "kdebugger.h"
|
||||
#include "ktreewidgetsearchline.h"
|
||||
#include "kpushbutton.h"
|
||||
#include "ktabwidget.h"
|
||||
#include "ktextedit.h"
|
||||
#include "klocale.h"
|
||||
#include "kdebug.h"
|
||||
|
||||
#include <QApplication>
|
||||
#include <QGridLayout>
|
||||
#include <QTreeWidget>
|
||||
#include <QTableWidget>
|
||||
#include <QHeaderView>
|
||||
#include <QMetaProperty>
|
||||
|
||||
Q_DECLARE_METATYPE(QObject*);
|
||||
|
||||
static QString kObjectString(const QObject *object)
|
||||
{
|
||||
const QString objectname = object->objectName();
|
||||
if (!objectname.isEmpty()) {
|
||||
return objectname;
|
||||
}
|
||||
return QString::number(quintptr(object), 16);
|
||||
}
|
||||
|
||||
class KDebuggerPrivate : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
KDebuggerPrivate(QObject *parent = nullptr);
|
||||
|
||||
QWidget* mainwidget;
|
||||
QGridLayout* mainlayout;
|
||||
KTreeWidgetSearchLine* objectssearchline;
|
||||
KPushButton* objectsrefreshbutton;
|
||||
QTreeWidget* objectswidget;
|
||||
KTabWidget* tabwidget;
|
||||
KTextEdit* eventsedit;
|
||||
QTableWidget* propertieswidget;
|
||||
|
||||
public Q_SLOTS:
|
||||
void slotUpdateObjects();
|
||||
void slotItemSelectionChanged();
|
||||
|
||||
protected:
|
||||
bool eventFilter(QObject *object, QEvent *event) final;
|
||||
|
||||
private:
|
||||
void addObject(QObject *object, QTreeWidgetItem *parentitem);
|
||||
|
||||
QPointer<QObject> m_object;
|
||||
};
|
||||
|
||||
KDebuggerPrivate::KDebuggerPrivate(QObject *parent)
|
||||
: QObject(parent),
|
||||
mainwidget(nullptr),
|
||||
mainlayout(nullptr),
|
||||
objectssearchline(nullptr),
|
||||
objectsrefreshbutton(nullptr),
|
||||
objectswidget(nullptr),
|
||||
tabwidget(nullptr),
|
||||
eventsedit(nullptr),
|
||||
propertieswidget(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
void KDebuggerPrivate::addObject(QObject *object, QTreeWidgetItem *parentitem)
|
||||
{
|
||||
QTreeWidgetItem* objectitem = new QTreeWidgetItem(parentitem);
|
||||
objectitem->setText(0, kObjectString(object));
|
||||
objectitem->setData(0, Qt::UserRole, QVariant::fromValue(object));
|
||||
objectitem->setExpanded(true);
|
||||
foreach (QObject *childobject, object->children()) {
|
||||
addObject(childobject, objectitem);
|
||||
}
|
||||
}
|
||||
|
||||
bool KDebuggerPrivate::eventFilter(QObject *object, QEvent *event)
|
||||
{
|
||||
switch (event->type()) {
|
||||
// TODO: option for what events to show
|
||||
case QEvent::Timer:
|
||||
case QEvent::MouseButtonPress:
|
||||
case QEvent::MouseButtonRelease:
|
||||
case QEvent::MouseButtonDblClick:
|
||||
case QEvent::MouseMove:
|
||||
case QEvent::KeyPress:
|
||||
case QEvent::KeyRelease:
|
||||
case QEvent::FocusIn:
|
||||
case QEvent::FocusOut:
|
||||
case QEvent::Enter:
|
||||
case QEvent::Leave:
|
||||
case QEvent::Paint:
|
||||
case QEvent::Move:
|
||||
case QEvent::Resize:
|
||||
case QEvent::Create:
|
||||
case QEvent::Destroy:
|
||||
case QEvent::Show:
|
||||
case QEvent::Hide:
|
||||
case QEvent::Close:
|
||||
case QEvent::Quit:
|
||||
case QEvent::ParentChange:
|
||||
case QEvent::ParentAboutToChange:
|
||||
case QEvent::ThreadChange:
|
||||
case QEvent::WindowActivate:
|
||||
case QEvent::WindowDeactivate:
|
||||
case QEvent::ShowToParent:
|
||||
case QEvent::HideToParent:
|
||||
case QEvent::Wheel:
|
||||
case QEvent::WindowTitleChange:
|
||||
case QEvent::WindowIconChange:
|
||||
case QEvent::ApplicationWindowIconChange:
|
||||
case QEvent::ApplicationFontChange:
|
||||
case QEvent::ApplicationLayoutDirectionChange:
|
||||
case QEvent::ApplicationPaletteChange:
|
||||
case QEvent::PaletteChange:
|
||||
case QEvent::Clipboard:
|
||||
case QEvent::MetaCall:
|
||||
case QEvent::SockAct:
|
||||
case QEvent::DeferredDelete:
|
||||
case QEvent::DragEnter:
|
||||
case QEvent::DragMove:
|
||||
case QEvent::DragLeave:
|
||||
case QEvent::Drop:
|
||||
case QEvent::ChildAdded:
|
||||
case QEvent::ChildPolished:
|
||||
case QEvent::ChildRemoved:
|
||||
case QEvent::ShowWindowRequest:
|
||||
case QEvent::PolishRequest:
|
||||
case QEvent::Polish:
|
||||
case QEvent::LayoutRequest:
|
||||
case QEvent::UpdateRequest:
|
||||
case QEvent::UpdateLater:
|
||||
case QEvent::ContextMenu:
|
||||
case QEvent::LocaleChange:
|
||||
case QEvent::LanguageChange:
|
||||
case QEvent::LayoutDirectionChange:
|
||||
case QEvent::Style:
|
||||
case QEvent::FontChange:
|
||||
case QEvent::EnabledChange:
|
||||
case QEvent::ActivationChange:
|
||||
case QEvent::StyleChange:
|
||||
case QEvent::IconTextChange:
|
||||
case QEvent::ModifiedChange:
|
||||
case QEvent::MouseTrackingChange:
|
||||
case QEvent::WindowBlocked:
|
||||
case QEvent::WindowUnblocked:
|
||||
case QEvent::WindowStateChange:
|
||||
case QEvent::ToolTip:
|
||||
case QEvent::WhatsThis:
|
||||
case QEvent::StatusTip:
|
||||
case QEvent::ActionChanged:
|
||||
case QEvent::ActionAdded:
|
||||
case QEvent::ActionRemoved:
|
||||
case QEvent::Shortcut:
|
||||
case QEvent::ShortcutOverride:
|
||||
case QEvent::WhatsThisClicked:
|
||||
case QEvent::ApplicationActivate:
|
||||
case QEvent::ApplicationDeactivate:
|
||||
case QEvent::QueryWhatsThis:
|
||||
case QEvent::EnterWhatsThisMode:
|
||||
case QEvent::LeaveWhatsThisMode:
|
||||
case QEvent::ZOrderChange:
|
||||
case QEvent::HoverEnter:
|
||||
case QEvent::HoverLeave:
|
||||
case QEvent::HoverMove:
|
||||
case QEvent::AcceptDropsChange:
|
||||
case QEvent::GraphicsSceneMouseMove:
|
||||
case QEvent::GraphicsSceneMousePress:
|
||||
case QEvent::GraphicsSceneMouseRelease:
|
||||
case QEvent::GraphicsSceneMouseDoubleClick:
|
||||
case QEvent::GraphicsSceneContextMenu:
|
||||
case QEvent::GraphicsSceneHoverEnter:
|
||||
case QEvent::GraphicsSceneHoverMove:
|
||||
case QEvent::GraphicsSceneHoverLeave:
|
||||
case QEvent::GraphicsSceneLeave:
|
||||
case QEvent::GraphicsSceneHelp:
|
||||
case QEvent::GraphicsSceneDragEnter:
|
||||
case QEvent::GraphicsSceneDragMove:
|
||||
case QEvent::GraphicsSceneDragLeave:
|
||||
case QEvent::GraphicsSceneDrop:
|
||||
case QEvent::GraphicsSceneWheel:
|
||||
case QEvent::KeyboardLayoutChange:
|
||||
case QEvent::DynamicPropertyChange:
|
||||
case QEvent::ContentsRectChange:
|
||||
case QEvent::GraphicsSceneResize:
|
||||
case QEvent::GraphicsSceneMove:
|
||||
case QEvent::CursorChange:
|
||||
case QEvent::ToolTipChange:
|
||||
case QEvent::GrabMouse:
|
||||
case QEvent::UngrabMouse:
|
||||
case QEvent::GrabKeyboard:
|
||||
case QEvent::UngrabKeyboard:
|
||||
case QEvent::RequestSoftwareInputPanel:
|
||||
case QEvent::CloseSoftwareInputPanel:
|
||||
case QEvent::WinIdChange: {
|
||||
QString eventline = kObjectString(object);
|
||||
eventline.append(QLatin1String(" - "));
|
||||
eventline.append(QString::number(event->type()));
|
||||
eventsedit->append(eventline);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void KDebuggerPrivate::slotUpdateObjects()
|
||||
{
|
||||
objectswidget->clear();
|
||||
addObject(qApp, objectswidget->invisibleRootItem());
|
||||
foreach (QWidget *widget, QApplication::allWidgets()) {
|
||||
addObject(widget, objectswidget->invisibleRootItem());
|
||||
}
|
||||
}
|
||||
|
||||
void KDebuggerPrivate::slotItemSelectionChanged()
|
||||
{
|
||||
QList<QTreeWidgetItem*> selectedobjects = objectswidget->selectedItems();
|
||||
if (selectedobjects.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
QTreeWidgetItem* objectitem = selectedobjects.first();
|
||||
QObject* object = qvariant_cast<QObject*>(objectitem->data(0, Qt::UserRole));
|
||||
if (!object) {
|
||||
return;
|
||||
}
|
||||
if (m_object) {
|
||||
m_object->removeEventFilter(this);
|
||||
}
|
||||
m_object = object;
|
||||
kDebug() << "watching" << m_object;
|
||||
eventsedit->clear();
|
||||
m_object->installEventFilter(this);
|
||||
|
||||
propertieswidget->clear();
|
||||
// this has to be done after every clear
|
||||
const QStringList tableheaders = QStringList()
|
||||
<< i18n("Property")
|
||||
<< i18n("Value");
|
||||
propertieswidget->setHorizontalHeaderLabels(tableheaders);
|
||||
int propertiesrowcount = 0;
|
||||
const QMetaObject* metaobject = m_object->metaObject();
|
||||
for (int i = 0; i < metaobject->propertyCount(); i++) {
|
||||
propertieswidget->setRowCount(propertiesrowcount + 1);
|
||||
const QMetaProperty metaproperty = metaobject->property(i);
|
||||
QTableWidgetItem* propertynameitem = new QTableWidgetItem(metaproperty.name());
|
||||
propertynameitem->setFlags(Qt::ItemIsEnabled);
|
||||
propertieswidget->setItem(propertiesrowcount, 0, propertynameitem);
|
||||
QTableWidgetItem* propertyvalueitem = new QTableWidgetItem(metaproperty.read(m_object).toString());
|
||||
// TODO: implement editing
|
||||
propertyvalueitem->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsEditable);
|
||||
propertieswidget->setItem(propertiesrowcount, 1, propertyvalueitem);
|
||||
propertiesrowcount++;
|
||||
}
|
||||
// TODO: dynamic properties
|
||||
// qDebug() << Q_FUNC_INFO << m_object->dynamicPropertyNames();
|
||||
}
|
||||
|
||||
|
||||
KDebugger::KDebugger(QWidget *parent)
|
||||
: KDialog(parent),
|
||||
d(new KDebuggerPrivate())
|
||||
{
|
||||
setCaption(i18nc("@title:window", "Debugger"));
|
||||
setButtons(KDialog::Close);
|
||||
|
||||
d->mainwidget = new QWidget(this);
|
||||
d->mainlayout = new QGridLayout(d->mainwidget);
|
||||
d->mainwidget->setLayout(d->mainlayout);
|
||||
setMainWidget(d->mainwidget);
|
||||
|
||||
d->objectssearchline = new KTreeWidgetSearchLine(d->mainwidget);
|
||||
d->mainlayout->addWidget(d->objectssearchline, 0, 0, 1, 1);
|
||||
d->objectsrefreshbutton = new KPushButton(d->mainwidget);
|
||||
d->objectsrefreshbutton->setIcon(KIcon("view-refresh"));
|
||||
connect(
|
||||
d->objectsrefreshbutton, SIGNAL(clicked()),
|
||||
d, SLOT(slotUpdateObjects())
|
||||
);
|
||||
d->mainlayout->addWidget(d->objectsrefreshbutton, 0, 1, 1, 1);
|
||||
|
||||
d->objectswidget = new QTreeWidget(d->mainwidget);
|
||||
d->objectssearchline->addTreeWidget(d->objectswidget);
|
||||
d->mainlayout->addWidget(d->objectswidget, 1, 0, 1, 2);
|
||||
|
||||
d->tabwidget = new KTabWidget(d->mainwidget);
|
||||
d->mainlayout->addWidget(d->tabwidget, 0, 2, 2, 1);
|
||||
|
||||
d->eventsedit = new KTextEdit(d->tabwidget);
|
||||
d->eventsedit->setReadOnly(false);
|
||||
d->tabwidget->addTab(d->eventsedit, KIcon("utilities-log-viewer"), i18n("Events"));
|
||||
|
||||
d->propertieswidget = new QTableWidget(d->tabwidget);
|
||||
d->propertieswidget->setSelectionMode(QAbstractItemView::SingleSelection);
|
||||
d->propertieswidget->setSelectionBehavior(QAbstractItemView::SelectItems);
|
||||
d->propertieswidget->setColumnCount(2);
|
||||
QHeaderView* verticalheader = d->propertieswidget->verticalHeader();
|
||||
verticalheader->setVisible(false);
|
||||
QHeaderView* horizontalheader = d->propertieswidget->horizontalHeader();
|
||||
horizontalheader->setMovable(false);
|
||||
horizontalheader->setStretchLastSection(false);
|
||||
horizontalheader->setResizeMode(0, QHeaderView::Stretch);
|
||||
horizontalheader->setResizeMode(1, QHeaderView::Stretch);
|
||||
d->tabwidget->addTab(d->propertieswidget, KIcon("document-properties"), i18n("Properties"));
|
||||
|
||||
KConfigGroup kconfiggroup(KGlobal::config(), "Debugger");
|
||||
restoreDialogSize(kconfiggroup);
|
||||
|
||||
d->slotUpdateObjects();
|
||||
|
||||
connect(
|
||||
d->objectswidget, SIGNAL(itemSelectionChanged()),
|
||||
d, SLOT(slotItemSelectionChanged())
|
||||
);
|
||||
}
|
||||
|
||||
KDebugger::~KDebugger()
|
||||
{
|
||||
KConfigGroup kconfiggroup(KGlobal::config(), "Debugger");
|
||||
saveDialogSize(kconfiggroup);
|
||||
KGlobal::config()->sync();
|
||||
|
||||
delete d;
|
||||
}
|
||||
|
||||
#include "moc_kdebugger.cpp"
|
||||
#include "kdebugger.moc"
|
47
kdeui/util/kdebugger.h
Normal file
47
kdeui/util/kdebugger.h
Normal file
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
This file is part of the KDE libraries
|
||||
Copyright (C) 2024 Ivailo Monev <xakepa10@gmail.com>
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public
|
||||
License version 2, as published by the Free Software Foundation.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public License
|
||||
along with this library; see the file COPYING.LIB. If not, write to
|
||||
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef KDEBUGGER_H
|
||||
#define KDEBUGGER_H
|
||||
|
||||
#include <kdeui_export.h>
|
||||
#include <kdialog.h>
|
||||
|
||||
class KDebuggerPrivate;
|
||||
|
||||
/*!
|
||||
Debugging class
|
||||
|
||||
@since 4.24
|
||||
@warning the API is subject to change
|
||||
*/
|
||||
class KDEUI_EXPORT KDebugger : public KDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
KDebugger(QWidget *parent = nullptr);
|
||||
~KDebugger();
|
||||
|
||||
private:
|
||||
Q_DISABLE_COPY(KDebugger);
|
||||
KDebuggerPrivate *const d;
|
||||
};
|
||||
|
||||
#endif // KDEBUGGER_H
|
Loading…
Add table
Reference in a new issue