KDDockWidgets API Documentation 2.1
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("Raise #0 (after 3s timeout)"));
246 layout->addWidget(button);
247 connect(button, &QPushButton::clicked, this, [this] {
248 QTimer::singleShot(3000, this, [] {
249 const auto docks = DockRegistry::self()->dockwidgets();
250 if (!docks.isEmpty())
251 docks.constFirst()->raise();
252 });
253 });
254
255#ifdef Q_OS_WIN
256 button = new QPushButton(this);
257 button->setText(QStringLiteral("Dump native windows"));
258 layout->addWidget(button);
259 connect(button, &QPushButton::clicked, this, &DebugWindow::dumpWindows);
260#endif
261
262 resize(800, 800);
263}
264
265#ifdef Q_OS_WIN
266void DebugWindow::dumpWindow(QWidget *w)
267{
268 if (w->window()) {
269 HWND hwnd = HWND(w->winId());
270
271 RECT clientRect;
272 RECT rect;
273 GetWindowRect(hwnd, &rect);
274 GetClientRect(hwnd, &clientRect);
275
276 qDebug() << w
277 << QStringLiteral(" ClientRect=%1,%2 %3x%4")
278 .arg(clientRect.left)
279 .arg(clientRect.top)
280 .arg(clientRect.right - clientRect.left + 1)
281 .arg(clientRect.bottom - clientRect.top + 1)
282 << QStringLiteral(" WindowRect=%1,%2 %3x%4")
283 .arg(rect.left)
284 .arg(rect.top)
285 .arg(rect.right - rect.left + 1)
286 .arg(rect.bottom - rect.top + 1)
287 << "; geo=" << w->geometry() << "; groupGeo=" << w->frameGeometry();
288 }
289
290 for (QObject *child : w->children()) {
291 if (auto childW = qobject_cast<QWidget *>(child)) {
292 dumpWindow(childW);
293 }
294 }
295}
296
297
298void DebugWindow::dumpWindows()
299{
300 for (QWidget *w : qApp->topLevelWidgets()) {
301 if (w != window())
302 dumpWindow(w);
303 }
304}
305
306#endif
307
308void DebugWindow::repaintWidgetRecursive(QWidget *w)
309{
310 w->repaint();
311 for (QObject *child : w->children()) {
312 if (auto childW = qobject_cast<QWidget *>(child)) {
313 repaintWidgetRecursive(childW);
314 }
315 }
316}
317
318void DebugWindow::dumpDockWidgetInfo()
319{
320 const QVector<Core::FloatingWindow *> floatingWindows =
322 const MainWindow::List mainWindows = DockRegistry::self()->mainwindows();
324
325 for (Core::FloatingWindow *fw : floatingWindows) {
326 qDebug() << fw << "; affinities=" << fw->affinities();
327 fw->layout()->dumpLayout();
328 }
329
330 for (MainWindow *mw : mainWindows) {
331 qDebug() << mw << "; affinities=" << mw->affinities();
332 mw->layout()->dumpLayout();
333 }
334
335 for (Core::DockWidget *dw : dockWidgets) {
336 qDebug() << dw << "; affinities=";
337 }
338}
339
341{
342 if (!m_isPickingWidget)
344
345 QWidget *w = qApp->widgetAt(Qt5Qt6Compat::eventGlobalPos(event));
346 qDebug() << "Widget at pos" << Qt5Qt6Compat::eventGlobalPos(event) << "is" << w
347 << "; parent=" << (w ? w->parentWidget() : nullptr)
348 << "; geometry=" << (w ? w->geometry() : QRect());
349
350 if (m_isPickingWidget)
351 m_isPickingWidget->quit();
352}
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::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