KDDockWidgets API Documentation 2.0
Loading...
Searching...
No Matches
DebugWindow.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 "DebugWindow.h"
21#include "core/DockRegistry.h"
22#include "LayoutSaver.h"
23#include "Qt5Qt6Compat_p.h"
24
25#include "kddockwidgets/core/MainWindow.h"
26#include "kddockwidgets/core/FloatingWindow.h"
27#include "kddockwidgets/core/Layout.h"
28
30
31#include <QVBoxLayout>
32#include <QHBoxLayout>
33#include <QPushButton>
34#include <QLineEdit>
35#include <QSpinBox>
36#include <QMessageBox>
37#include <QApplication>
38#include <QMouseEvent>
39#include <QWindow>
40#include <QFileDialog>
41#include <QAbstractNativeEventFilter>
42#include <QTimer>
43
44#ifdef Q_OS_WIN
45#include <windows.h>
46#include <winuser.h>
47#endif
48
49// clazy:excludeall=range-loop
50
51using namespace KDDockWidgets;
52using namespace KDDockWidgets::Core;
53using namespace KDDockWidgets::Debug;
54
55class DebugAppEventFilter : public QAbstractNativeEventFilter
56{
57public:
58 DebugAppEventFilter() = default;
59 ~DebugAppEventFilter() override;
60#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
61 bool nativeEventFilter(const QByteArray &eventType, void *message, qintptr *) override
62#else
63 bool nativeEventFilter(const QByteArray &eventType, void *message, long *) override
64#endif
65 {
66#ifdef Q_OS_WIN
67 if (eventType != "windows_generic_MSG")
68 return false;
69 auto msg = static_cast<MSG *>(message);
70
71 if (msg->message == WM_NCCALCSIZE)
72 qDebug() << "Got WM_NCCALCSIZE!" << message;
73#else
74 Q_UNUSED(eventType);
75 Q_UNUSED(message);
76#endif
77
78 return false; // don't accept anything
79 }
80};
81
82DebugAppEventFilter::~DebugAppEventFilter()
83{
84}
85
87 : QWidget(parent)
88 , m_objectViewer(this)
89{
90 // qGuiApp->installNativeEventFilter(new DebugAppEventFilter());
91 auto layout = new QVBoxLayout(this);
92 layout->addWidget(&m_objectViewer);
93
94 auto button = new QPushButton(this);
95 button->setText(QStringLiteral("Dump Debug"));
96 layout->addWidget(button);
97 connect(button, &QPushButton::clicked, this, &DebugWindow::dumpDockWidgetInfo);
98
99 auto hlay = new QHBoxLayout();
100 layout->addLayout(hlay);
101
102 button = new QPushButton(this);
103 auto spin = new QSpinBox(this);
104 spin->setMinimum(0);
105 button->setText(QStringLiteral("Toggle float"));
106 hlay->addWidget(button);
107 hlay->addWidget(spin);
108
109 connect(button, &QPushButton::clicked, this, [spin] {
110 auto docks = DockRegistry::self()->dockwidgets();
111 const int index = spin->value();
112 if (index >= docks.size()) {
113 QMessageBox::warning(nullptr, QStringLiteral("Invalid index"),
114 QStringLiteral("Max index is %1").arg(docks.size() - 1));
115 } else {
116 auto dw = docks.at(index);
117 dw->setFloating(!dw->isFloating());
118 }
119 });
120
121 hlay = new QHBoxLayout();
122 layout->addLayout(hlay);
123 button = new QPushButton(this);
124 auto lineedit = new QLineEdit(this);
125 lineedit->setPlaceholderText(tr("DockWidget unique name"));
126 button->setText(QStringLiteral("Show"));
127 hlay->addWidget(button);
128 hlay->addWidget(lineedit);
129
130 connect(button, &QPushButton::clicked, this, [lineedit] {
131 auto dw = DockRegistry::self()->dockByName(lineedit->text());
132 if (dw) {
133 dw->open();
134 } else {
136 nullptr, QStringLiteral("Could not find"),
137 QStringLiteral("Could not find DockWidget with name %1").arg(lineedit->text()));
138 }
139 });
140
141 button = new QPushButton(this);
142 button->setText(QStringLiteral("Float all visible docks"));
143 layout->addWidget(button);
144 connect(button, &QPushButton::clicked, this, [] {
145 const auto docks = DockRegistry::self()->dockwidgets();
146 for (auto dw : docks) {
147 if (dw->isVisible() && !dw->isFloating()) {
148 dw->setFloating(true);
149 }
150 }
151 });
152
153 button = new QPushButton(this);
154 button->setText(QStringLiteral("Show All DockWidgets"));
155 layout->addWidget(button);
156 connect(button, &QPushButton::clicked, this, [this] {
157 QTimer::singleShot(3000, this, [] {
158 const auto docks = DockRegistry::self()->dockwidgets();
159 for (auto dw : docks) {
160 dw->open();
161 }
162 });
163 });
164
165 button = new QPushButton(this);
166 button->setText(QStringLiteral("Save layout"));
167 layout->addWidget(button);
168 connect(button, &QPushButton::clicked, this, [] {
169 LayoutSaver saver;
170 QString message = saver.saveToFile(QStringLiteral("layout.json"))
171 ? QStringLiteral("Saved!")
172 : QStringLiteral("Error!");
173 qDebug() << message;
174 });
175
176 button = new QPushButton(this);
177 button->setText(QStringLiteral("Restore layout"));
178 layout->addWidget(button);
179 connect(button, &QPushButton::clicked, this, [] {
180 LayoutSaver saver;
181 QString message = saver.restoreFromFile(QStringLiteral("layout.json"))
182 ? QStringLiteral("Restored!")
183 : QStringLiteral("Error!");
184 qDebug() << message;
185 });
186
187 button = new QPushButton(this);
188 button->setText(QStringLiteral("Pick Widget"));
189 layout->addWidget(button);
190 connect(button, &QPushButton::clicked, this, [this] {
191 qGuiApp->setOverrideCursor(Qt::CrossCursor);
192 grabMouse();
193
194 QEventLoop loop;
195 m_isPickingWidget = &loop;
196 loop.exec();
197
198 releaseMouse();
199 m_isPickingWidget = nullptr;
200 qGuiApp->restoreOverrideCursor();
201 });
202
203 button = new QPushButton(this);
204 button->setText(QStringLiteral("check sanity"));
205 layout->addWidget(button);
206 connect(button, &QPushButton::clicked, this, [] {
207 const auto mainWindows = DockRegistry::self()->mainwindows();
208 for (MainWindow *mainWindow : mainWindows) {
209 mainWindow->layout()->checkSanity();
210 }
211
212 const auto floatingWindows = DockRegistry::self()->floatingWindows();
213 for (auto floatingWindow : floatingWindows) {
214 floatingWindow->layout()->checkSanity();
215 }
216 });
217
218 button = new QPushButton(this);
219 button->setText(QStringLiteral("Detach central widget"));
220 layout->addWidget(button);
221 connect(button, &QPushButton::clicked, this, [] {
222 const auto mainWindows = DockRegistry::self()->mainwindows();
223 if (mainWindows.isEmpty())
224 return;
225 auto mainwindow = mainWindows.at(0);
226 auto centralWidget =
227 qobject_cast<QMainWindow *>(QtWidgets::MainWindow::asQWidget(mainwindow))
228 ->centralWidget();
229 centralWidget->setParent(nullptr, Qt::Window);
230 if (!centralWidget->isVisible()) {
231 centralWidget->show();
232 }
233 });
234
235 button = new QPushButton(this);
236 button->setText(QStringLiteral("Repaint all widgets"));
237 layout->addWidget(button);
238 connect(button, &QPushButton::clicked, this, [this] {
239 const auto topLevelWidgets = qApp->topLevelWidgets();
240 for (auto w : topLevelWidgets)
241 repaintWidgetRecursive(w);
242 });
243
244 button = new QPushButton(this);
245 button->setText(QStringLiteral("resize by 1x1"));
246 layout->addWidget(button);
247 connect(button, &QPushButton::clicked, this, [] {
248 const auto layouts = DockRegistry::self()->layouts();
249 for (auto l : layouts) {
250 auto tlw = l->view()->rootView();
251 tlw->resize(tlw->size() + QSize(1, 1));
252 }
253 });
254
255 button = new QPushButton(this);
256 button->setText(QStringLiteral("Raise #0 (after 3s timeout)"));
257 layout->addWidget(button);
258 connect(button, &QPushButton::clicked, this, [this] {
259 QTimer::singleShot(3000, this, [] {
260 const auto docks = DockRegistry::self()->dockwidgets();
261 if (!docks.isEmpty())
262 docks.constFirst()->raise();
263 });
264 });
265
266#ifdef Q_OS_WIN
267 button = new QPushButton(this);
268 button->setText(QStringLiteral("Dump native windows"));
269 layout->addWidget(button);
270 connect(button, &QPushButton::clicked, this, &DebugWindow::dumpWindows);
271#endif
272
273 resize(800, 800);
274}
275
276#ifdef Q_OS_WIN
277void DebugWindow::dumpWindow(QWidget *w)
278{
279 if (w->window()) {
280 HWND hwnd = HWND(w->winId());
281
282 RECT clientRect;
283 RECT rect;
284 GetWindowRect(hwnd, &rect);
285 GetClientRect(hwnd, &clientRect);
286
287 qDebug() << w
288 << QStringLiteral(" ClientRect=%1,%2 %3x%4")
289 .arg(clientRect.left)
290 .arg(clientRect.top)
291 .arg(clientRect.right - clientRect.left + 1)
292 .arg(clientRect.bottom - clientRect.top + 1)
293 << QStringLiteral(" WindowRect=%1,%2 %3x%4")
294 .arg(rect.left)
295 .arg(rect.top)
296 .arg(rect.right - rect.left + 1)
297 .arg(rect.bottom - rect.top + 1)
298 << "; geo=" << w->geometry() << "; groupGeo=" << w->frameGeometry();
299 }
300
301 for (QObject *child : w->children()) {
302 if (auto childW = qobject_cast<QWidget *>(child)) {
303 dumpWindow(childW);
304 }
305 }
306}
307
308
309void DebugWindow::dumpWindows()
310{
311 for (QWidget *w : qApp->topLevelWidgets()) {
312 if (w != window())
313 dumpWindow(w);
314 }
315}
316
317#endif
318
319void DebugWindow::repaintWidgetRecursive(QWidget *w)
320{
321 w->repaint();
322 for (QObject *child : w->children()) {
323 if (auto childW = qobject_cast<QWidget *>(child)) {
324 repaintWidgetRecursive(childW);
325 }
326 }
327}
328
329void DebugWindow::dumpDockWidgetInfo()
330{
331 const QVector<Core::FloatingWindow *> floatingWindows =
333 const MainWindow::List mainWindows = DockRegistry::self()->mainwindows();
335
336 for (Core::FloatingWindow *fw : floatingWindows) {
337 qDebug() << fw << "; affinities=" << fw->affinities();
338 fw->layout()->dumpLayout();
339 }
340
341 for (MainWindow *mw : mainWindows) {
342 qDebug() << mw << "; affinities=" << mw->affinities();
343 mw->layout()->dumpLayout();
344 }
345
346 for (Core::DockWidget *dw : dockWidgets) {
347 qDebug() << dw << "; affinities=";
348 }
349}
350
352{
353 if (!m_isPickingWidget)
355
356 QWidget *w = qApp->widgetAt(Qt5Qt6Compat::eventGlobalPos(event));
357 qDebug() << "Widget at pos" << Qt5Qt6Compat::eventGlobalPos(event) << "is" << w
358 << "; parent=" << (w ? w->parentWidget() : nullptr)
359 << "; geometry=" << (w ? w->geometry() : QRect());
360
361 if (m_isPickingWidget)
362 m_isPickingWidget->quit();
363}
Window to show debug information. Used for debugging only, for apps that don't support GammaRay.
Class to save and restore dockwidget layouts.
The DockWidget base-class. DockWidget and Core::DockWidget are only split in two so we can share some...
void open()
Opens this dock widget. Does nothing if already open. The dock widget will appear floating unless it ...
The MainWindow base-class. MainWindow and MainWindowBase are only split in two so we can share some c...
void mousePressEvent(QMouseEvent *event) override
DebugWindow(QWidget *parent=nullptr)
Q_INVOKABLE KDDockWidgets::Core::DockWidget * dockByName(const QString &, KDDockWidgets::DockRegistry::DockByNameFlags={}) const
Vector< Core::FloatingWindow * > floatingWindows(bool includeBeingDeleted=false, bool honourSkipped=false) const
returns all FloatingWindow instances. Not necessarily all floating dock widgets, As there might be Do...
static DockRegistry * self()
Vector< Core::Layout * > layouts() const
returns the list of Layout instances
Vector< Core::DockWidget * > dockwidgets() const
returns all DockWidget instances
Vector< Core::MainWindow * > mainwindows() const
returns all MainWindow instances
LayoutSaver allows to save or restore layouts.
Definition LayoutSaver.h:56
bool saveToFile(const QString &jsonFilename)
saves the layout to JSON file
bool restoreFromFile(const QString &jsonFilename)
restores the layout from a JSON file
Class to abstract QAction, so code still works with QtQuick and Flutter.
void clicked(bool checked)
virtual bool nativeEventFilter(const QByteArray &eventType, void *message, long *result)=0
int exec(QEventLoop::ProcessEventsFlags flags)
void quit()
void addWidget(QWidget *w)
QMessageBox::StandardButton warning(QWidget *parent, const QString &title, const QString &text, QMessageBox::StandardButtons buttons, QMessageBox::StandardButton defaultButton)
const QObjectList & children() const const
QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
QString tr(const char *sourceText, const char *disambiguation, int n)
CrossCursor
QMainWindow sub-class to enable KDDockWidgets support.
virtual bool event(QEvent *event) override
void grabMouse()
QLayout * layout() const const
virtual void mousePressEvent(QMouseEvent *event)
QWidget * parentWidget() const const
void releaseMouse()
void repaint()
void resize(int w, int h)
WId winId() const const
QWidget * window() const const

© 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