Skip to content
Permalink
Browse files

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.
  • Loading branch information
NathanW2 committed Dec 4, 2017
1 parent 21fe98d commit 57dc9deb06a8f4474429b2956008188292588a1b
@@ -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:
@@ -364,6 +364,7 @@ SET(QGIS_GUI_SRCS
qgsvscrollarea.cpp
qgsdatasourcemanagerdialog.cpp
qgsabstractdatasourcewidget.cpp
qgswidgetstatehelper_p.cpp
qgssourceselectprovider.cpp
qgssourceselectproviderregistry.cpp
)
@@ -528,6 +529,7 @@ SET(QGIS_GUI_MOC_HDRS
qgsfiledownloaderdialog.h
qgsdatasourcemanagerdialog.h
qgsabstractdatasourcewidget.h
qgswidgetstatehelper_p.h

ogr/qgsnewogrconnection.h
ogr/qgsvectorlayersaveasdialog.h
@@ -741,6 +743,7 @@ SET(QGIS_GUI_HDRS
qgsvertexmarker.h
qgsdatasourcemanagerdialog.h
qgsabstractdatasourcewidget.h
qgswidgetstatehelper_p.h
qgssourceselectprovider.h
qgssourceselectproviderregistry.h
qgsvscrollarea.h
@@ -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 );
@@ -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 );
}
@@ -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()
@@ -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 )
@@ -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 );
@@ -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 );
}

@@ -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()
@@ -29,6 +29,7 @@
#include "qgsnative.h"
#endif
#include "qgsshortcutsmanager.h"
#include "qgswidgetstatehelper_p.h"

QgsGui *QgsGui::instance()
{
@@ -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;
@@ -80,6 +86,7 @@ QgsGui::~QgsGui()
delete mSourceSelectProviderRegistry;
delete mShortcutsManager;
delete mNative;
delete mWidgetStateHelper;
}

QgsGui::QgsGui()
@@ -96,4 +103,5 @@ QgsGui::QgsGui()
mMapLayerActionRegistry = new QgsMapLayerActionRegistry();
mSourceSelectProviderRegistry = new QgsSourceSelectProviderRegistry();
mLayoutItemGuiRegistry = new QgsLayoutItemGuiRegistry();
mWidgetStateHelper = new QgsWidgetStateHelper();
}
@@ -20,6 +20,7 @@

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

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

/**
* \ingroup gui
@@ -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;
@@ -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;
}
}
@@ -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
@@ -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 );
}
@@ -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.
You can’t perform that action at this time.