Skip to content

Commit

Permalink
Add API to ease saving and restoring widget geometry. (#5615)
Browse files Browse the repository at this point in the history
Usage:
 - QgsGui::instance()->enableAutoGeometryRestore( this ); just
after setupUi in your widgets to enable.
 - Remove any calls to saveGeometry() and restoreGeometry() in your
widgets.
  • Loading branch information
NathanW2 committed Dec 4, 2017
1 parent 21fe98d commit 57dc9de
Show file tree
Hide file tree
Showing 10 changed files with 205 additions and 11 deletions.
6 changes: 6 additions & 0 deletions python/gui/qgsgui.sip
Expand Up @@ -68,6 +68,12 @@ class QgsGui
:rtype: QgsLayoutItemGuiRegistry
%End

static void enableAutoGeometryRestore( QWidget *widget, const QString &key = QString() );
%Docstring
Register the widget to allow its position to be automatically saved and restored when open and closed.
Use this to avoid needing to call saveGeometry() and restoreGeometry() on your widget.
%End

~QgsGui();

private:
Expand Down
3 changes: 3 additions & 0 deletions src/gui/CMakeLists.txt
Expand Up @@ -364,6 +364,7 @@ SET(QGIS_GUI_SRCS
qgsvscrollarea.cpp
qgsdatasourcemanagerdialog.cpp
qgsabstractdatasourcewidget.cpp
qgswidgetstatehelper_p.cpp
qgssourceselectprovider.cpp
qgssourceselectproviderregistry.cpp
)
Expand Down Expand Up @@ -528,6 +529,7 @@ SET(QGIS_GUI_MOC_HDRS
qgsfiledownloaderdialog.h
qgsdatasourcemanagerdialog.h
qgsabstractdatasourcewidget.h
qgswidgetstatehelper_p.h

ogr/qgsnewogrconnection.h
ogr/qgsvectorlayersaveasdialog.h
Expand Down Expand Up @@ -741,6 +743,7 @@ SET(QGIS_GUI_HDRS
qgsvertexmarker.h
qgsdatasourcemanagerdialog.h
qgsabstractdatasourcewidget.h
qgswidgetstatehelper_p.h
qgssourceselectprovider.h
qgssourceselectproviderregistry.h
qgsvscrollarea.h
Expand Down
8 changes: 3 additions & 5 deletions src/gui/qgsexpressionbuilderdialog.cpp
Expand Up @@ -15,12 +15,15 @@

#include "qgsexpressionbuilderdialog.h"
#include "qgssettings.h"
#include "qgsguiutils.h"
#include "qgsgui.h"

QgsExpressionBuilderDialog::QgsExpressionBuilderDialog( QgsVectorLayer *layer, const QString &startText, QWidget *parent, const QString &key, const QgsExpressionContext &context )
: QDialog( parent )
, mRecentKey( key )
{
setupUi( this );
QgsGui::instance()->enableAutoGeometryRestore( this );

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

QgsSettings settings;
restoreGeometry( settings.value( QStringLiteral( "Windows/ExpressionBuilderDialog/geometry" ) ).toByteArray() );

connect( buttonBox, &QDialogButtonBox::helpRequested, this, &QgsExpressionBuilderDialog::showHelp );
}
Expand Down Expand Up @@ -65,9 +66,6 @@ void QgsExpressionBuilderDialog::setExpressionContext( const QgsExpressionContex
void QgsExpressionBuilderDialog::done( int r )
{
QDialog::done( r );

QgsSettings settings;
settings.setValue( QStringLiteral( "Windows/ExpressionBuilderDialog/geometry" ), saveGeometry() );
}

void QgsExpressionBuilderDialog::accept()
Expand Down
10 changes: 4 additions & 6 deletions src/gui/qgsexpressionselectiondialog.cpp
Expand Up @@ -21,6 +21,7 @@
#include "qgsmessagebar.h"
#include "qgsvectorlayer.h"
#include "qgssettings.h"
#include "qgsgui.h"


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

{
setupUi( this );

QgsGui::instance()->enableAutoGeometryRestore( this );

connect( mActionSelect, &QAction::triggered, this, &QgsExpressionSelectionDialog::mActionSelect_triggered );
connect( mActionAddToSelection, &QAction::triggered, this, &QgsExpressionSelectionDialog::mActionAddToSelection_triggered );
connect( mActionRemoveFromSelection, &QAction::triggered, this, &QgsExpressionSelectionDialog::mActionRemoveFromSelection_triggered );
Expand Down Expand Up @@ -60,9 +64,6 @@ QgsExpressionSelectionDialog::QgsExpressionSelectionDialog( QgsVectorLayer *laye
// by default, zoom to features is hidden, shown only if canvas is set
mButtonZoomToFeatures->setVisible( false );

QgsSettings settings;
restoreGeometry( settings.value( QStringLiteral( "Windows/ExpressionSelectionDialog/geometry" ) ).toByteArray() );

connect( buttonBox, &QDialogButtonBox::helpRequested, this, &QgsExpressionSelectionDialog::showHelp );
}

Expand Down Expand Up @@ -181,9 +182,6 @@ void QgsExpressionSelectionDialog::mButtonZoomToFeatures_clicked()
void QgsExpressionSelectionDialog::closeEvent( QCloseEvent *closeEvent )
{
QDialog::closeEvent( closeEvent );

QgsSettings settings;
settings.setValue( QStringLiteral( "Windows/ExpressionSelectionDialog/geometry" ), saveGeometry() );
}

void QgsExpressionSelectionDialog::mPbnClose_clicked()
Expand Down
8 changes: 8 additions & 0 deletions src/gui/qgsgui.cpp
Expand Up @@ -29,6 +29,7 @@
#include "qgsnative.h"
#endif
#include "qgsshortcutsmanager.h"
#include "qgswidgetstatehelper_p.h"

QgsGui *QgsGui::instance()
{
Expand Down Expand Up @@ -71,6 +72,11 @@ QgsLayoutItemGuiRegistry *QgsGui::layoutItemGuiRegistry()
return instance()->mLayoutItemGuiRegistry;
}

void QgsGui::enableAutoGeometryRestore( QWidget *widget, const QString &key )
{
instance()->mWidgetStateHelper->registerWidget( widget, key );
}

QgsGui::~QgsGui()
{
delete mLayoutItemGuiRegistry;
Expand All @@ -80,6 +86,7 @@ QgsGui::~QgsGui()
delete mSourceSelectProviderRegistry;
delete mShortcutsManager;
delete mNative;
delete mWidgetStateHelper;
}

QgsGui::QgsGui()
Expand All @@ -96,4 +103,5 @@ QgsGui::QgsGui()
mMapLayerActionRegistry = new QgsMapLayerActionRegistry();
mSourceSelectProviderRegistry = new QgsSourceSelectProviderRegistry();
mLayoutItemGuiRegistry = new QgsLayoutItemGuiRegistry();
mWidgetStateHelper = new QgsWidgetStateHelper();
}
9 changes: 9 additions & 0 deletions src/gui/qgsgui.h
Expand Up @@ -20,6 +20,7 @@

#include "qgis_gui.h"
#include "qgis_sip.h"
#include <QWidget>

class QgsEditorWidgetRegistry;
class QgsShortcutsManager;
Expand All @@ -28,6 +29,7 @@ class QgsMapLayerActionRegistry;
class QgsSourceSelectProviderRegistry;
class QgsNative;
class QgsLayoutItemGuiRegistry;
class QgsWidgetStateHelper;

/**
* \ingroup gui
Expand Down Expand Up @@ -87,12 +89,19 @@ class GUI_EXPORT QgsGui
*/
static QgsLayoutItemGuiRegistry *layoutItemGuiRegistry();

/**
* Register the widget to allow its position to be automatically saved and restored when open and closed.
* Use this to avoid needing to call saveGeometry() and restoreGeometry() on your widget.
*/
static void enableAutoGeometryRestore( QWidget *widget, const QString &key = QString() );

~QgsGui();

private:

QgsGui();

QgsWidgetStateHelper *mWidgetStateHelper = nullptr;
QgsNative *mNative = nullptr;
QgsEditorWidgetRegistry *mEditorWidgetRegistry = nullptr;
QgsSourceSelectProviderRegistry *mSourceSelectProviderRegistry = nullptr;
Expand Down
33 changes: 33 additions & 0 deletions src/gui/qgsguiutils.cpp
Expand Up @@ -201,4 +201,37 @@ namespace QgsGuiUtils
return QFontDialog::getFont( &ok, initial, nullptr, title );
#endif
}

void saveGeometry( QWidget *widget, const QString &keyName )
{
QgsSettings settings;
QString key = createWidgetKey( widget, keyName );
settings.setValue( key, widget->saveGeometry() );
}

bool restoreGeometry( QWidget *widget, const QString &keyName )
{
QgsSettings settings;
QString key = createWidgetKey( widget, keyName );
return widget->restoreGeometry( settings.value( key ).toByteArray() );
}

QString createWidgetKey( QWidget *widget, const QString &keyName )
{
QString subKey;
if ( !keyName.isEmpty() )
{
subKey = keyName;
}
else if ( widget->objectName().isEmpty() )
{
subKey = QString( widget->metaObject()->className() );
}
else
{
subKey = widget->objectName();
}
QString key = QStringLiteral( "Windows/%1/geometry" ).arg( subKey );
return key;
}
}
26 changes: 26 additions & 0 deletions src/gui/qgsguiutils.h
Expand Up @@ -136,6 +136,32 @@ namespace QgsGuiUtils
* \returns QFont the selected fon
*/
QFont GUI_EXPORT getFont( bool &ok, const QFont &initial, const QString &title = QString() );

/**
* Restore the wigget geometry from settings. Will use the objetName() of the widget and if empty, or keyName is set, will
* use keyName to save state into settings.
* \param widget The widget to restore.
* \param keyName Override for objectName() if needed.
* \return True if the geometry was restored.
*/
bool GUI_EXPORT restoreGeometry( QWidget *widget, const QString &keyName = QString() );

/**
* Save the wigget geometry into settings. Will use the objectName() of the widget and if empty, or keyName is set, will
* use keyName to save state into settings.
* \param widget The widget to save.
* \param keyName Override for objectName() if needed.
*/
void GUI_EXPORT saveGeometry( QWidget *widget, const QString &keyName = QString() );

/**
* Creates a key for the given widget that can be used to store related data in settings.
* Will use objectName() or class name if objectName() is not set. Can be overridden using \param keyName.
* \param widget The widget to make the key from.
* \param keyName Override for objectName() if needed. If not set will use objectName()
* \return A key name that can be used for the widget in settings.
*/
QString createWidgetKey( QWidget *widget, const QString &keyName = QString() );
}

#endif // QGSGUIUTILS_H
50 changes: 50 additions & 0 deletions src/gui/qgswidgetstatehelper_p.cpp
@@ -0,0 +1,50 @@
/***************************************************************************
qgswidgetstatehelper_p.cpp - QgsWidgetStateHelper
---------------------
begin : 3.12.2017
copyright : (C) 2017 by Nathan Woodrow
Email : woodrow.nathan at gmail dot com
***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
#include "qgswidgetstatehelper_p.h"
#include <QWidget>
#include <QEvent>
#include <QObject>
#include "qgsguiutils.h"
#include "qgslogger.h"

QgsWidgetStateHelper::QgsWidgetStateHelper( QObject *parent ) : QObject( parent )
{

}

bool QgsWidgetStateHelper::eventFilter( QObject *object, QEvent *event )
{
if ( event->type() == QEvent::Close || event->type() == QEvent::Destroy )
{
QString key = mKeys[object->objectName()];
QWidget *widget = qobject_cast<QWidget *>( object );
QgsGuiUtils::saveGeometry( widget, key );
}
else if ( event->type() == QEvent::Show )
{
QString key = mKeys[object->objectName()];
QWidget *widget = qobject_cast<QWidget *>( object );
QgsGuiUtils::restoreGeometry( widget, key );
}
return QObject::eventFilter( object, event );
}

void QgsWidgetStateHelper::registerWidget( QWidget *widget, const QString &key )
{
Q_ASSERT( !widget->objectName().isEmpty() );
mKeys[widget->objectName()] = key;
widget->installEventFilter( this );
}
63 changes: 63 additions & 0 deletions src/gui/qgswidgetstatehelper_p.h
@@ -0,0 +1,63 @@
/***************************************************************************
qgswidgetstatehelper_p.h - QgsWidgetStateHelper
---------------------
begin : 3.12.2017
copyright : (C) 2017 by Nathan Woodrow
Email : woodrow.nathan at gmail dot com
***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
#ifndef QGSWIDGETSTATEHELPER_P_H
#define QGSWIDGETSTATEHELPER_P_H

#include <QMap>
#include <QObject>

#define SIP_NO_FILE

/**
* \ingroup gui
* QgsWidgetStateHelper is a helper class to save and restore the geometry of QWidgets in the application.
* This removes the need for devs to remember to call saveGeometry() and restoreGeometry() when writing new widgets.
*
* This helper is internal and should only be called via QgsGui::enabledAutoGeometryRestore
* \since QGIS 3.0
*/
class QgsWidgetStateHelper : public QObject
{
Q_OBJECT
public:

/**
* QgsWidgetStateHelper
* @param parent Parent object
*/
explicit QgsWidgetStateHelper( QObject *parent = 0 );

/**
* Event filter to catch events from registered widgets.
* \param object Object getting the event.
* \param event Event sent from Qt.
* \return Always returns True so that widget still gets event.
*/
bool eventFilter( QObject *object, QEvent *event );

/**
* Register a widget to have it geometry state automatically saved and restored.
* \param widget The widget to save. Must have objectName() set.
* \param key The override settings key name to use if objectName() isn't to be used.
* objectName() is the default if not set.
*/
void registerWidget( QWidget *widget, const QString &key = QString() );

private:
QMap<QString, QString> mKeys;
};

#endif // QGSWIDGETSTATEHELPER_P_H

0 comments on commit 57dc9de

Please sign in to comment.