Skip to content

Commit 57dc9de

Browse files
authoredDec 4, 2017
Add API to ease saving and restoring widget geometry. (#5615)
Usage: - QgsGui::instance()->enableAutoGeometryRestore( this ); just after setupUi in your widgets to enable. - Remove any calls to saveGeometry() and restoreGeometry() in your widgets.
1 parent 21fe98d commit 57dc9de

10 files changed

+205
-11
lines changed
 

‎python/gui/qgsgui.sip

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,12 @@ class QgsGui
6868
:rtype: QgsLayoutItemGuiRegistry
6969
%End
7070

71+
static void enableAutoGeometryRestore( QWidget *widget, const QString &key = QString() );
72+
%Docstring
73+
Register the widget to allow its position to be automatically saved and restored when open and closed.
74+
Use this to avoid needing to call saveGeometry() and restoreGeometry() on your widget.
75+
%End
76+
7177
~QgsGui();
7278

7379
private:

‎src/gui/CMakeLists.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -364,6 +364,7 @@ SET(QGIS_GUI_SRCS
364364
qgsvscrollarea.cpp
365365
qgsdatasourcemanagerdialog.cpp
366366
qgsabstractdatasourcewidget.cpp
367+
qgswidgetstatehelper_p.cpp
367368
qgssourceselectprovider.cpp
368369
qgssourceselectproviderregistry.cpp
369370
)
@@ -528,6 +529,7 @@ SET(QGIS_GUI_MOC_HDRS
528529
qgsfiledownloaderdialog.h
529530
qgsdatasourcemanagerdialog.h
530531
qgsabstractdatasourcewidget.h
532+
qgswidgetstatehelper_p.h
531533

532534
ogr/qgsnewogrconnection.h
533535
ogr/qgsvectorlayersaveasdialog.h
@@ -741,6 +743,7 @@ SET(QGIS_GUI_HDRS
741743
qgsvertexmarker.h
742744
qgsdatasourcemanagerdialog.h
743745
qgsabstractdatasourcewidget.h
746+
qgswidgetstatehelper_p.h
744747
qgssourceselectprovider.h
745748
qgssourceselectproviderregistry.h
746749
qgsvscrollarea.h

‎src/gui/qgsexpressionbuilderdialog.cpp

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,15 @@
1515

1616
#include "qgsexpressionbuilderdialog.h"
1717
#include "qgssettings.h"
18+
#include "qgsguiutils.h"
19+
#include "qgsgui.h"
1820

1921
QgsExpressionBuilderDialog::QgsExpressionBuilderDialog( QgsVectorLayer *layer, const QString &startText, QWidget *parent, const QString &key, const QgsExpressionContext &context )
2022
: QDialog( parent )
2123
, mRecentKey( key )
2224
{
2325
setupUi( this );
26+
QgsGui::instance()->enableAutoGeometryRestore( this );
2427

2528
QPushButton *okButton = buttonBox->button( QDialogButtonBox::Ok );
2629
connect( builder, &QgsExpressionBuilderWidget::expressionParsed, okButton, &QWidget::setEnabled );
@@ -31,8 +34,6 @@ QgsExpressionBuilderDialog::QgsExpressionBuilderDialog( QgsVectorLayer *layer, c
3134
builder->loadFieldNames();
3235
builder->loadRecent( mRecentKey );
3336

34-
QgsSettings settings;
35-
restoreGeometry( settings.value( QStringLiteral( "Windows/ExpressionBuilderDialog/geometry" ) ).toByteArray() );
3637

3738
connect( buttonBox, &QDialogButtonBox::helpRequested, this, &QgsExpressionBuilderDialog::showHelp );
3839
}
@@ -65,9 +66,6 @@ void QgsExpressionBuilderDialog::setExpressionContext( const QgsExpressionContex
6566
void QgsExpressionBuilderDialog::done( int r )
6667
{
6768
QDialog::done( r );
68-
69-
QgsSettings settings;
70-
settings.setValue( QStringLiteral( "Windows/ExpressionBuilderDialog/geometry" ), saveGeometry() );
7169
}
7270

7371
void QgsExpressionBuilderDialog::accept()

‎src/gui/qgsexpressionselectiondialog.cpp

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#include "qgsmessagebar.h"
2222
#include "qgsvectorlayer.h"
2323
#include "qgssettings.h"
24+
#include "qgsgui.h"
2425

2526

2627
QgsExpressionSelectionDialog::QgsExpressionSelectionDialog( QgsVectorLayer *layer, const QString &startText, QWidget *parent )
@@ -29,6 +30,9 @@ QgsExpressionSelectionDialog::QgsExpressionSelectionDialog( QgsVectorLayer *laye
2930

3031
{
3132
setupUi( this );
33+
34+
QgsGui::instance()->enableAutoGeometryRestore( this );
35+
3236
connect( mActionSelect, &QAction::triggered, this, &QgsExpressionSelectionDialog::mActionSelect_triggered );
3337
connect( mActionAddToSelection, &QAction::triggered, this, &QgsExpressionSelectionDialog::mActionAddToSelection_triggered );
3438
connect( mActionRemoveFromSelection, &QAction::triggered, this, &QgsExpressionSelectionDialog::mActionRemoveFromSelection_triggered );
@@ -60,9 +64,6 @@ QgsExpressionSelectionDialog::QgsExpressionSelectionDialog( QgsVectorLayer *laye
6064
// by default, zoom to features is hidden, shown only if canvas is set
6165
mButtonZoomToFeatures->setVisible( false );
6266

63-
QgsSettings settings;
64-
restoreGeometry( settings.value( QStringLiteral( "Windows/ExpressionSelectionDialog/geometry" ) ).toByteArray() );
65-
6667
connect( buttonBox, &QDialogButtonBox::helpRequested, this, &QgsExpressionSelectionDialog::showHelp );
6768
}
6869

@@ -181,9 +182,6 @@ void QgsExpressionSelectionDialog::mButtonZoomToFeatures_clicked()
181182
void QgsExpressionSelectionDialog::closeEvent( QCloseEvent *closeEvent )
182183
{
183184
QDialog::closeEvent( closeEvent );
184-
185-
QgsSettings settings;
186-
settings.setValue( QStringLiteral( "Windows/ExpressionSelectionDialog/geometry" ), saveGeometry() );
187185
}
188186

189187
void QgsExpressionSelectionDialog::mPbnClose_clicked()

‎src/gui/qgsgui.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
#include "qgsnative.h"
3030
#endif
3131
#include "qgsshortcutsmanager.h"
32+
#include "qgswidgetstatehelper_p.h"
3233

3334
QgsGui *QgsGui::instance()
3435
{
@@ -71,6 +72,11 @@ QgsLayoutItemGuiRegistry *QgsGui::layoutItemGuiRegistry()
7172
return instance()->mLayoutItemGuiRegistry;
7273
}
7374

75+
void QgsGui::enableAutoGeometryRestore( QWidget *widget, const QString &key )
76+
{
77+
instance()->mWidgetStateHelper->registerWidget( widget, key );
78+
}
79+
7480
QgsGui::~QgsGui()
7581
{
7682
delete mLayoutItemGuiRegistry;
@@ -80,6 +86,7 @@ QgsGui::~QgsGui()
8086
delete mSourceSelectProviderRegistry;
8187
delete mShortcutsManager;
8288
delete mNative;
89+
delete mWidgetStateHelper;
8390
}
8491

8592
QgsGui::QgsGui()
@@ -96,4 +103,5 @@ QgsGui::QgsGui()
96103
mMapLayerActionRegistry = new QgsMapLayerActionRegistry();
97104
mSourceSelectProviderRegistry = new QgsSourceSelectProviderRegistry();
98105
mLayoutItemGuiRegistry = new QgsLayoutItemGuiRegistry();
106+
mWidgetStateHelper = new QgsWidgetStateHelper();
99107
}

‎src/gui/qgsgui.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020

2121
#include "qgis_gui.h"
2222
#include "qgis_sip.h"
23+
#include <QWidget>
2324

2425
class QgsEditorWidgetRegistry;
2526
class QgsShortcutsManager;
@@ -28,6 +29,7 @@ class QgsMapLayerActionRegistry;
2829
class QgsSourceSelectProviderRegistry;
2930
class QgsNative;
3031
class QgsLayoutItemGuiRegistry;
32+
class QgsWidgetStateHelper;
3133

3234
/**
3335
* \ingroup gui
@@ -87,12 +89,19 @@ class GUI_EXPORT QgsGui
8789
*/
8890
static QgsLayoutItemGuiRegistry *layoutItemGuiRegistry();
8991

92+
/**
93+
* Register the widget to allow its position to be automatically saved and restored when open and closed.
94+
* Use this to avoid needing to call saveGeometry() and restoreGeometry() on your widget.
95+
*/
96+
static void enableAutoGeometryRestore( QWidget *widget, const QString &key = QString() );
97+
9098
~QgsGui();
9199

92100
private:
93101

94102
QgsGui();
95103

104+
QgsWidgetStateHelper *mWidgetStateHelper = nullptr;
96105
QgsNative *mNative = nullptr;
97106
QgsEditorWidgetRegistry *mEditorWidgetRegistry = nullptr;
98107
QgsSourceSelectProviderRegistry *mSourceSelectProviderRegistry = nullptr;

‎src/gui/qgsguiutils.cpp

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -201,4 +201,37 @@ namespace QgsGuiUtils
201201
return QFontDialog::getFont( &ok, initial, nullptr, title );
202202
#endif
203203
}
204+
205+
void saveGeometry( QWidget *widget, const QString &keyName )
206+
{
207+
QgsSettings settings;
208+
QString key = createWidgetKey( widget, keyName );
209+
settings.setValue( key, widget->saveGeometry() );
210+
}
211+
212+
bool restoreGeometry( QWidget *widget, const QString &keyName )
213+
{
214+
QgsSettings settings;
215+
QString key = createWidgetKey( widget, keyName );
216+
return widget->restoreGeometry( settings.value( key ).toByteArray() );
217+
}
218+
219+
QString createWidgetKey( QWidget *widget, const QString &keyName )
220+
{
221+
QString subKey;
222+
if ( !keyName.isEmpty() )
223+
{
224+
subKey = keyName;
225+
}
226+
else if ( widget->objectName().isEmpty() )
227+
{
228+
subKey = QString( widget->metaObject()->className() );
229+
}
230+
else
231+
{
232+
subKey = widget->objectName();
233+
}
234+
QString key = QStringLiteral( "Windows/%1/geometry" ).arg( subKey );
235+
return key;
236+
}
204237
}

‎src/gui/qgsguiutils.h

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,32 @@ namespace QgsGuiUtils
136136
* \returns QFont the selected fon
137137
*/
138138
QFont GUI_EXPORT getFont( bool &ok, const QFont &initial, const QString &title = QString() );
139+
140+
/**
141+
* Restore the wigget geometry from settings. Will use the objetName() of the widget and if empty, or keyName is set, will
142+
* use keyName to save state into settings.
143+
* \param widget The widget to restore.
144+
* \param keyName Override for objectName() if needed.
145+
* \return True if the geometry was restored.
146+
*/
147+
bool GUI_EXPORT restoreGeometry( QWidget *widget, const QString &keyName = QString() );
148+
149+
/**
150+
* Save the wigget geometry into settings. Will use the objectName() of the widget and if empty, or keyName is set, will
151+
* use keyName to save state into settings.
152+
* \param widget The widget to save.
153+
* \param keyName Override for objectName() if needed.
154+
*/
155+
void GUI_EXPORT saveGeometry( QWidget *widget, const QString &keyName = QString() );
156+
157+
/**
158+
* Creates a key for the given widget that can be used to store related data in settings.
159+
* Will use objectName() or class name if objectName() is not set. Can be overridden using \param keyName.
160+
* \param widget The widget to make the key from.
161+
* \param keyName Override for objectName() if needed. If not set will use objectName()
162+
* \return A key name that can be used for the widget in settings.
163+
*/
164+
QString createWidgetKey( QWidget *widget, const QString &keyName = QString() );
139165
}
140166

141167
#endif // QGSGUIUTILS_H

‎src/gui/qgswidgetstatehelper_p.cpp

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
/***************************************************************************
2+
qgswidgetstatehelper_p.cpp - QgsWidgetStateHelper
3+
4+
---------------------
5+
begin : 3.12.2017
6+
copyright : (C) 2017 by Nathan Woodrow
7+
Email : woodrow.nathan at gmail dot com
8+
***************************************************************************
9+
* *
10+
* This program is free software; you can redistribute it and/or modify *
11+
* it under the terms of the GNU General Public License as published by *
12+
* the Free Software Foundation; either version 2 of the License, or *
13+
* (at your option) any later version. *
14+
* *
15+
***************************************************************************/
16+
#include "qgswidgetstatehelper_p.h"
17+
#include <QWidget>
18+
#include <QEvent>
19+
#include <QObject>
20+
#include "qgsguiutils.h"
21+
#include "qgslogger.h"
22+
23+
QgsWidgetStateHelper::QgsWidgetStateHelper( QObject *parent ) : QObject( parent )
24+
{
25+
26+
}
27+
28+
bool QgsWidgetStateHelper::eventFilter( QObject *object, QEvent *event )
29+
{
30+
if ( event->type() == QEvent::Close || event->type() == QEvent::Destroy )
31+
{
32+
QString key = mKeys[object->objectName()];
33+
QWidget *widget = qobject_cast<QWidget *>( object );
34+
QgsGuiUtils::saveGeometry( widget, key );
35+
}
36+
else if ( event->type() == QEvent::Show )
37+
{
38+
QString key = mKeys[object->objectName()];
39+
QWidget *widget = qobject_cast<QWidget *>( object );
40+
QgsGuiUtils::restoreGeometry( widget, key );
41+
}
42+
return QObject::eventFilter( object, event );
43+
}
44+
45+
void QgsWidgetStateHelper::registerWidget( QWidget *widget, const QString &key )
46+
{
47+
Q_ASSERT( !widget->objectName().isEmpty() );
48+
mKeys[widget->objectName()] = key;
49+
widget->installEventFilter( this );
50+
}

‎src/gui/qgswidgetstatehelper_p.h

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
/***************************************************************************
2+
qgswidgetstatehelper_p.h - QgsWidgetStateHelper
3+
4+
---------------------
5+
begin : 3.12.2017
6+
copyright : (C) 2017 by Nathan Woodrow
7+
Email : woodrow.nathan at gmail dot com
8+
***************************************************************************
9+
* *
10+
* This program is free software; you can redistribute it and/or modify *
11+
* it under the terms of the GNU General Public License as published by *
12+
* the Free Software Foundation; either version 2 of the License, or *
13+
* (at your option) any later version. *
14+
* *
15+
***************************************************************************/
16+
#ifndef QGSWIDGETSTATEHELPER_P_H
17+
#define QGSWIDGETSTATEHELPER_P_H
18+
19+
#include <QMap>
20+
#include <QObject>
21+
22+
#define SIP_NO_FILE
23+
24+
/**
25+
* \ingroup gui
26+
* QgsWidgetStateHelper is a helper class to save and restore the geometry of QWidgets in the application.
27+
* This removes the need for devs to remember to call saveGeometry() and restoreGeometry() when writing new widgets.
28+
*
29+
* This helper is internal and should only be called via QgsGui::enabledAutoGeometryRestore
30+
* \since QGIS 3.0
31+
*/
32+
class QgsWidgetStateHelper : public QObject
33+
{
34+
Q_OBJECT
35+
public:
36+
37+
/**
38+
* QgsWidgetStateHelper
39+
* @param parent Parent object
40+
*/
41+
explicit QgsWidgetStateHelper( QObject *parent = 0 );
42+
43+
/**
44+
* Event filter to catch events from registered widgets.
45+
* \param object Object getting the event.
46+
* \param event Event sent from Qt.
47+
* \return Always returns True so that widget still gets event.
48+
*/
49+
bool eventFilter( QObject *object, QEvent *event );
50+
51+
/**
52+
* Register a widget to have it geometry state automatically saved and restored.
53+
* \param widget The widget to save. Must have objectName() set.
54+
* \param key The override settings key name to use if objectName() isn't to be used.
55+
* objectName() is the default if not set.
56+
*/
57+
void registerWidget( QWidget *widget, const QString &key = QString() );
58+
59+
private:
60+
QMap<QString, QString> mKeys;
61+
};
62+
63+
#endif // QGSWIDGETSTATEHELPER_P_H

0 commit comments

Comments
 (0)
Please sign in to comment.