KDDockWidgets API Documentation 1.7
Loading...
Searching...
No Matches
ObjectViewer.cpp
Go to the documentation of this file.
1/*
2 This file is part of KDDockWidgets.
3
4 SPDX-FileCopyrightText: 2019-2023 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
5 Author: SĂ©rgio Martins <sergio.martins@kdab.com>
6
7 SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only
8
9 Contact KDAB at <info@kdab.com> for commercial licensing options.
10*/
11
19#include "ObjectViewer_p.h"
20
21#include <QStandardItem>
22#include <QApplication>
23#include <QHBoxLayout>
24#include <QMenu>
25#include <QContextMenuEvent>
26#include <QItemSelectionModel>
27#include <QPainter>
28#include <QDebug>
29#include <QMetaProperty>
30#include <QWindow>
31#include <QToolBar>
32#include <QShortcut>
33#include <QDir>
34
35#ifdef Q_OS_WIN
36#include <windows.h>
37#endif
38
39using namespace KDDockWidgets::Debug;
40
44
45
46ObjectViewer::ObjectViewer(QWidget *parent)
47 : QWidget(parent)
48{
49 resize(600, 600);
50
51 auto lay = new QHBoxLayout(this);
52 lay->addWidget(&m_treeView);
53 m_treeView.setModel(&m_model);
54 connect(m_treeView.selectionModel(), &QItemSelectionModel::selectionChanged,
55 this, &ObjectViewer::onSelectionChanged);
56
57 QAction *action = m_menu.addAction(QStringLiteral("Refresh"));
58 connect(action, &QAction::triggered, this, &ObjectViewer::refresh);
59 action = m_menu.addAction(QStringLiteral("Dump Windows"));
60 connect(action, &QAction::triggered, this, &ObjectViewer::dumpWindows);
61
62 action = m_menu.addAction(QStringLiteral("Update"));
63 connect(action, &QAction::triggered, this, &ObjectViewer::updateSelectedWidget);
64
65 action = m_menu.addAction(QStringLiteral("Print to png"));
66 connect(action, &QAction::triggered, this, &ObjectViewer::dumpSelectedWidgetToPng);
67
68 action = m_menu.addAction(QStringLiteral("Toggle Visible"));
69 connect(action, &QAction::triggered, this, &ObjectViewer::toggleVisible);
70
71#ifdef Q_OS_WIN
72 action = m_menu.addAction(QStringLiteral("Send WM_NCHITTEST"));
73 connect(action, &QAction::triggered, this, &ObjectViewer::sendHitTest);
74#endif
75
76 refresh();
77 setWindowTitle(QStringLiteral("ObjectViewer"));
78}
79
80void ObjectViewer::refresh()
81{
82 const auto hashCopy = m_itemMap;
83 for (auto it = hashCopy.cbegin(), e = hashCopy.cend(); it != e; ++it)
84 remove(it.key());
85
86 m_model.clear();
87
88 const auto &topLevelWidgets = qApp->topLevelWidgets();
89 for (QWidget *window : topLevelWidgets) {
90 add(window, m_model.invisibleRootItem());
91 }
92}
93
94void ObjectViewer::dumpSelectedWidgetToPng()
95{
96 if (auto w = selectedWidget()) {
97 QPixmap px(w->size());
98 w->render(&px);
99 px.save(QStringLiteral("px.png"));
100 qDebug() << QDir::currentPath();
101 }
102}
103
104void ObjectViewer::updateSelectedWidget()
105{
106 if (auto w = selectedWidget())
107 w->update();
108}
109
110void ObjectViewer::toggleVisible()
111{
112 if (auto w = selectedWidget())
113 w->setVisible(!w->isVisible());
114}
115
116#ifdef Q_OS_WIN
117void ObjectViewer::sendHitTest()
118{
119 if (auto w = selectedWidget()) {
120 qDebug() << "Sending hit test to" << w;
121 ::SendMessage(HWND(w->winId()), WM_NCHITTEST, 0, 0);
122 }
123}
124#endif
125
126void ObjectViewer::dumpWindows()
127{
128 qDebug() << "Top Level QWidgets:";
129 const auto &topLevelWidgets = qApp->topLevelWidgets();
130 for (QWidget *w : topLevelWidgets) {
131 if (qobject_cast<QMenu *>(w))
132 continue;
133
134 qDebug() << " QWidget=" << w;
135 }
136
137 qDebug() << "Top Level Windows:";
138 const auto &topLevelWindows = qApp->topLevelWindows();
139 for (QWindow *w : topLevelWindows) {
140 qDebug() << " QWindow=" << w << "; parent=" << w->parent() << "; transientParent=" << w->transientParent() << "; hwnd=" << w->winId();
141 }
142}
143
144QString ObjectViewer::nameForObj(QObject *o) const
145{
147 if (!o->objectName().isEmpty())
148 name += QStringLiteral("(%1)").arg(o->objectName());
149
150 if (auto w = qobject_cast<QWidget *>(o)) {
151 name += QStringLiteral(" - %1,%2 %3x%4").arg(w->x()).arg(w->y()).arg(w->width()).arg(w->height());
152
153 if (w->isWindow())
154 name += QStringLiteral(" ;W");
155 if (w->windowHandle() != nullptr)
156 name += QStringLiteral(" ;N");
157 }
158
159 return name;
160}
161
162void ObjectViewer::add(QObject *obj, QStandardItem *parent)
163{
164 if (obj == this || obj == &m_menu || obj == parentWidget() || !obj) // Ignore our stuff
165 return;
166
167 if (m_ignoreMenus && qobject_cast<QMenu *>(obj))
168 return;
169
170 if (m_ignoreShortcuts && qobject_cast<QShortcut *>(obj))
171 return;
172
173 if (m_ignoreToolBars && qobject_cast<QToolBar *>(obj))
174 return;
175
176 connect(obj, &QObject::destroyed, this, &ObjectViewer::remove);
177 obj->installEventFilter(this);
178 auto item = new QStandardItem(nameForObj(obj));
179 item->setData(QVariant::fromValue(obj), ObjRole);
180 m_itemMap.insert(obj, item);
181 parent->appendRow(item);
182 updateItemAppearence(item);
183
184 for (auto child : obj->children())
185 add(child, item);
186}
187
188void ObjectViewer::remove(QObject *obj)
189{
190 Q_ASSERT(obj);
191 obj->removeEventFilter(this);
192 m_itemMap.remove(obj);
193}
194
195void ObjectViewer::onSelectionChanged()
196{
197 QObject *o = selectedObject();
198 if (m_selectedObject == o)
199 return;
200
201 if (m_selectedObject) {
202 m_selectedObject->removeEventFilter(this);
203 if (auto w = qobject_cast<QWidget *>(m_selectedObject))
204 w->update();
205 }
206
207 m_selectedObject = o;
208
209 if (m_selectedObject) {
210 printProperties(o);
211 m_selectedObject->installEventFilter(this);
212 if (m_highlightsWidget) {
213 if (auto w = qobject_cast<QWidget *>(o))
214 w->update();
215 }
216 }
217}
218
219void ObjectViewer::printProperties(QObject *obj) const
220{
221 qDebug() << "Printing properties for" << obj;
222
223 auto mo = obj->metaObject();
224 const int count = mo->propertyCount();
225 for (int i = 0; i < count; ++i) {
226 QMetaProperty prop = mo->property(i);
227 qDebug() << " " << prop.name() << prop.read(obj);
228 }
229
230 if (auto w = qobject_cast<QWidget *>(obj)) {
231 qDebug() << "Is a widget!";
232 qDebug() << "Window=" << w->window();
233 qDebug() << "flags=" << w->windowFlags();
234 qDebug() << "is native?" << (w->windowHandle() != nullptr);
235 }
236}
237
238QObject *ObjectViewer::selectedObject() const
239{
240 auto indexes = m_treeView.selectionModel()->selectedIndexes();
241 if (indexes.isEmpty())
242 return nullptr;
243 QModelIndex index = indexes.first();
244 QObject *obj = index.data(ObjRole).value<QObject *>();
245 return obj;
246}
247
248QWidget *ObjectViewer::selectedWidget() const
249{
250 return qobject_cast<QWidget *>(selectedObject());
251}
252
253void ObjectViewer::updateItemAppearence(QStandardItem *item)
254{
255 Q_ASSERT(item);
256 QWidget *widget = widgetForItem(item);
257 if (!widget)
258 return;
259
260 if (widget->isVisible()) {
262 } else {
263 item->setForeground(Qt::gray);
264 }
265}
266
267QObject *ObjectViewer::objectForItem(QStandardItem *item) const
268{
269 return item->data(ObjRole).value<QObject *>();
270}
271
272QWidget *ObjectViewer::widgetForItem(QStandardItem *item) const
273{
274 return qobject_cast<QWidget *>(objectForItem(item));
275}
276
277void ObjectViewer::contextMenuEvent(QContextMenuEvent *ev)
278{
279 m_menu.exec(ev->globalPos());
280}
281
282bool ObjectViewer::eventFilter(QObject *watched, QEvent *event)
283{
284 auto widget = static_cast<QWidget *>(watched);
285 if (event->type() == QEvent::Show || event->type() == QEvent::Hide) {
286 updateItemAppearence(m_itemMap.value(watched));
287 return false;
288 }
289
290 if (m_selectedObject != watched)
291 return false;
292
293 if (event->type() != QEvent::Paint || !m_highlightsWidget)
294 return false;
295
296 QPainter p(widget);
297 p.fillRect(widget->rect(), QBrush(QColor(0, 0, 255, 128)));
298
299 return true;
300}
@ ObjRole
void triggered(bool checked)
const QPoint & globalPos() const const
QString currentPath()
QEvent::Type type() const const
void selectionChanged(const QItemSelection &selected, const QItemSelection &deselected)
const char * className() const const
int propertyCount() const const
const char * name() const const
QVariant read(const QObject *object) const const
QVariant data(int role) const const
void destroyed(QObject *obj)
void installEventFilter(QObject *filterObj)
virtual const QMetaObject * metaObject() const const
void removeEventFilter(QObject *obj)
void appendRow(const QList< QStandardItem * > &items)
virtual QVariant data(int role) const const
void setForeground(const QBrush &brush)
QString arg(qlonglong a, int fieldWidth, int base, QChar fillChar) const const
QString fromLatin1(const char *str, int size)
UserRole
QVariant fromValue(const T &value)
T value() const const
bool isVisible() const const

© 2019-2023 Klarälvdalens Datakonsult AB (KDAB)
"The Qt, C++ and OpenGL Experts"
https://www.kdab.com/
KDDockWidgets
Advanced Dock Widget Framework for Qt
https://www.kdab.com/development-resources/qt-tools/kddockwidgets/
Generated on Wed Nov 1 2023 00:02:31 for KDDockWidgets API Documentation by doxygen 1.9.8