KDDockWidgets API Documentation  1.6
ObjectViewer.cpp
Go to the documentation of this file.
1 /*
2  This file is part of KDDockWidgets.
3 
4  SPDX-FileCopyrightText: 2019-2022 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 
39 using namespace KDDockWidgets::Debug;
40 
41 enum Role {
43 };
44 
45 
46 ObjectViewer::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 
80 void 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 
94 void 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 
104 void ObjectViewer::updateSelectedWidget()
105 {
106  if (auto w = selectedWidget())
107  w->update();
108 }
109 
110 void ObjectViewer::toggleVisible()
111 {
112  if (auto w = selectedWidget())
113  w->setVisible(!w->isVisible());
114 }
115 
116 #ifdef Q_OS_WIN
117 void 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 
126 void 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 
144 QString 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 
162 void 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 
188 void ObjectViewer::remove(QObject *obj)
189 {
190  Q_ASSERT(obj);
191  obj->removeEventFilter(this);
192  m_itemMap.remove(obj);
193 }
194 
195 void 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 
219 void 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 
238 QObject *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 
248 QWidget *ObjectViewer::selectedWidget() const
249 {
250  return qobject_cast<QWidget *>(selectedObject());
251 }
252 
253 void ObjectViewer::updateItemAppearence(QStandardItem *item)
254 {
255  Q_ASSERT(item);
256  QWidget *widget = widgetForItem(item);
257  if (!widget)
258  return;
259 
260  if (widget->isVisible()) {
261  item->setForeground(Qt::black);
262  } else {
263  item->setForeground(Qt::gray);
264  }
265 }
266 
267 QObject *ObjectViewer::objectForItem(QStandardItem *item) const
268 {
269  return item->data(ObjRole).value<QObject *>();
270 }
271 
272 QWidget *ObjectViewer::widgetForItem(QStandardItem *item) const
273 {
274  return qobject_cast<QWidget *>(objectForItem(item));
275 }
276 
277 void ObjectViewer::contextMenuEvent(QContextMenuEvent *ev)
278 {
279  m_menu.exec(ev->globalPos());
280 }
281 
282 bool 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 }
QObject::removeEventFilter
void removeEventFilter(QObject *obj)
QColor
QItemSelectionModel::selectionChanged
void selectionChanged(const QItemSelection &selected, const QItemSelection &deselected)
Qt::UserRole
UserRole
QEvent::Show
Show
QContextMenuEvent::globalPos
const QPoint & globalPos() const const
ObjRole
@ ObjRole
Definition: ObjectViewer.cpp:42
QVariant::fromValue
QVariant fromValue(const T &value)
QMetaProperty
QWidget::rect
rect
QVariant::value
T value() const const
QWindow
QWidget
QStandardItem::setForeground
void setForeground(const QBrush &brush)
QPainter
QObject::destroyed
void destroyed(QObject *obj)
QWidget::isVisible
bool isVisible() const const
QModelIndex::data
QVariant data(int role) const const
QPixmap
QObject
QString
QDir::currentPath
QString currentPath()
QContextMenuEvent
QObject::installEventFilter
void installEventFilter(QObject *filterObj)
QStandardItem
QMetaObject::propertyCount
int propertyCount() const const
QMetaProperty::read
QVariant read(const QObject *object) const const
QBrush
QObject::metaObject
virtual const QMetaObject * metaObject() const const
QMetaObject::className
const char * className() const const
Role
Role
Definition: ObjectViewer.cpp:41
QAction::triggered
void triggered(bool checked)
QMetaProperty::name
const char * name() const const
QString::arg
QString arg(qlonglong a, int fieldWidth, int base, QChar fillChar) const const
QString::fromLatin1
QString fromLatin1(const char *str, int size)
QEvent::type
QEvent::Type type() const const
QEvent
QObject::objectName
objectName
QHBoxLayout
QStandardItem::data
virtual QVariant data(int role) const const
QStandardItem::appendRow
void appendRow(const QList< QStandardItem * > &items)
QAction
QModelIndex
Qt::black
black
QObject::children
const QObjectList & children() const const

© 2019-2022 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 Thu Sep 15 2022 00:16:29 for KDDockWidgets API Documentation by doxygen 1.8.20