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

© 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 by doxygen 1.9.8