aboutsummaryrefslogtreecommitdiff
path: root/src/gui/kwindowstatesaver.h
diff options
context:
space:
mode:
authorVolker Krause <vkrause@kde.org>2022-02-14 18:12:24 +0100
committerVolker Krause <vkrause@kde.org>2022-02-24 16:43:05 +0000
commitf446af2aa592997f6bc4aa3b5559cf477f9259f8 (patch)
tree884ce1c859da42351fd9b286680d5d15e916b6d8 /src/gui/kwindowstatesaver.h
parent1067eed52a8a1a93581744a5c9d4fc9f8a7d3661 (diff)
downloadkconfig-f446af2aa592997f6bc4aa3b5559cf477f9259f8.tar.gz
kconfig-f446af2aa592997f6bc4aa3b5559cf477f9259f8.tar.bz2
Add KWindowStateSaver
This is basically the C++ counter-part to https://invent.kde.org/frameworks/kconfig/-/merge_requests/94 and allows to easily retrofit window size persistence on existing windows/ dialogs, replacing e.g. code like https://invent.kde.org/pim/pimcommon/-/blob/master/src/pimcommon/widgets/kpimprintpreviewdialog.cpp. This is a bit more complicated than one might expect, as KWindowConfig works with QWindows, but that's something freshly created QWidget windows/ dialogs don't have yet. Additionally, we are in a library here that doesn't depend on Qt::Widgets. To overcome this we move the widget-dependent code (basically just a call to QWidget::windowHandle()) to inline template code (and thus into the consumer), use std::function's type erasure to pass it into the library code, and an event filter on the widget to wait for the QWindow to become available.
Diffstat (limited to 'src/gui/kwindowstatesaver.h')
-rw-r--r--src/gui/kwindowstatesaver.h144
1 files changed, 144 insertions, 0 deletions
diff --git a/src/gui/kwindowstatesaver.h b/src/gui/kwindowstatesaver.h
new file mode 100644
index 00000000..47b6ae95
--- /dev/null
+++ b/src/gui/kwindowstatesaver.h
@@ -0,0 +1,144 @@
+/*
+ SPDX-FileCopyrightText: 2022 Volker Krause <vkrause@kde.org>
+ SPDX-License-Identifier: LGPL-2.0-or-later
+*/
+
+#ifndef KWINDOWSTATESAVER_H
+#define KWINDOWSTATESAVER_H
+
+#include <kconfiggroup.h>
+#include <kconfiggui_export.h>
+
+#include <QObject>
+
+class QWindow;
+class KWindowStateSaverPrivate;
+
+/**
+ * Saves and restores a window size and (when possible) position.
+ *
+ * This is useful for retrofitting persisting window geometry on existing windows or dialogs,
+ * without having to modify those classes themselves, or having to inherit from them.
+ * For this, create a new instance of KWindowStateSaver for every window that should have it's
+ * state persisted, and pass it the window or widget as well as the config group the state
+ * should be stored in. The KWindowStateSaver will restore an existing state and then monitor
+ * the window for subsequent changes to persist. It will delete itself once the window is
+ * deleted.
+ *
+ * @code
+ * QPrintPreviewDialog dlg = ...
+ * new KWindowStateSaver(&dlg, "printPreviewDialogState");
+ * ...
+ * dlg.exec();
+ * @endcode
+ *
+ * Note that freshly created top-level QWidgets (such as the dialog in the above example)
+ * do not have an associated QWindow yet (ie. windowHandle() return @c nullptr). KWindowStateSaver
+ * supports this with its QWidget constructors which will monitor the widget for having
+ * its associated QWindow created before continuing with that.
+ *
+ * When implementing your own windows/dialogs, using KWindowConfig directly can be an
+ * alternative.
+ *
+ * @see KWindowConfig
+ * @since 5.92
+ */
+class KCONFIGGUI_EXPORT KWindowStateSaver : public QObject
+{
+ Q_OBJECT
+public:
+ /**
+ * Create a new window state saver for @p window.
+ * @param configGroup A KConfigGroup that holds the window state.
+ */
+ explicit KWindowStateSaver(QWindow *window, const KConfigGroup &configGroup);
+ /**
+ * Create a new window state saver for @p window.
+ * @param configGroupName The name of a KConfigGroup in the default state
+ * configuration (see KSharedConfig::openStateConfig) that holds the window state.
+ */
+ explicit KWindowStateSaver(QWindow *window, const QString &configGroupName);
+ /**
+ * Create a new window state saver for @p window.
+ * @param configGroupName The name of a KConfigGroup in the default state
+ * configuration (see KSharedConfig::openStateConfig) that holds the window state.
+ */
+ explicit KWindowStateSaver(QWindow *window, const char *configGroupName);
+
+ /**
+ * Create a new window state saver for @p widget.
+ * Use this for widgets that aren't shown yet and would still return @c nullptr from windowHandle().
+ * @param configGroup A KConfigGroup that holds the window state.
+ */
+ template<typename Widget>
+ explicit inline KWindowStateSaver(Widget *widget, const KConfigGroup &configGroup);
+ /**
+ * Create a new window state saver for @p widget.
+ * Use this for widgets that aren't shown yet and would still return @c nullptr from windowHandle().
+ * @param configGroupName The name of a KConfigGroup in the default state
+ * configuration (see KSharedConfig::openStateConfig) that holds the window state.
+ */
+ template<typename Widget>
+ explicit inline KWindowStateSaver(Widget *widget, const QString &configGroupName);
+ /**
+ * Create a new window state saver for @p widget.
+ * Use this for widgets that aren't shown yet and would still return @c nullptr from windowHandle().
+ * @param configGroupName The name of a KConfigGroup in the default state
+ * configuration (see KSharedConfig::openStateConfig) that holds the window state.
+ */
+ template<typename Widget>
+ explicit inline KWindowStateSaver(Widget *widget, const char *configGroupName);
+
+ ~KWindowStateSaver();
+
+private:
+ void timerEvent(QTimerEvent *event) override;
+ bool eventFilter(QObject *watched, QEvent *event) override;
+
+ // API used by template code, so technically part of the ABI
+ void initWidget(QObject *widget, const std::function<QWindow *()> &windowHandleCallback, const KConfigGroup &configGroup);
+ void initWidget(QObject *widget, const std::function<QWindow *()> &windowHandleCallback, const QString &configGroupName);
+ void initWidget(QObject *widget, const std::function<QWindow *()> &windowHandleCallback, const char *configGroupName);
+
+ // cannot use std::unique_ptr due to the template ctors
+ // not seeing the full private class
+ KWindowStateSaverPrivate *d = nullptr;
+};
+
+template<typename Widget>
+KWindowStateSaver::KWindowStateSaver(Widget *widget, const KConfigGroup &configGroup)
+ : QObject(widget)
+{
+ initWidget(
+ widget,
+ [widget]() {
+ return widget->windowHandle();
+ },
+ configGroup);
+}
+
+template<typename Widget>
+KWindowStateSaver::KWindowStateSaver(Widget *widget, const QString &configGroupName)
+ : QObject(widget)
+{
+ initWidget(
+ widget,
+ [widget]() {
+ return widget->windowHandle();
+ },
+ configGroupName);
+}
+
+template<typename Widget>
+KWindowStateSaver::KWindowStateSaver(Widget *widget, const char *configGroupName)
+ : QObject(widget)
+{
+ initWidget(
+ widget,
+ [widget]() {
+ return widget->windowHandle();
+ },
+ configGroupName);
+}
+
+#endif // KWINDOWSTATESAVER_H