Skip to content

Commit

Permalink
[feature] QgsSettings QGIS QSettings replacement (#4160)
Browse files Browse the repository at this point in the history
* [feature] QgsSettings QGIS QSettings replacement

This is the new QgsSettings class that adds an (optional)
Global Settings additional ini file where a system administrator
can store default values for the settings and provide
pre-configuration.

If an ini file named qgis_global_settings.ini is found
in the pkgDataPath directory it is automatically loaded,
this path can be overriden by a command line argument
( --globalsettingsfile path ) and through an environment
variable (QGIS_GLOBAL_SETTINGS_FILE).
  • Loading branch information
elpaso authored and NathanW2 committed Feb 22, 2017
1 parent 49114ae commit e1ede70
Show file tree
Hide file tree
Showing 10 changed files with 913 additions and 12 deletions.
1 change: 1 addition & 0 deletions python/core/core.sip
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@

%Include qgsapplication.sip
%Include qgsaction.sip
%Include qgssettings.sip
%Include qgsactionmanager.sip
%Include qgsactionscope.sip
%Include qgsactionscoperegistry.sip
Expand Down
181 changes: 181 additions & 0 deletions python/core/qgssettings.sip
Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@
/***************************************************************************
qgssettings.sip
--------------------------------------
Date : January 2017
Copyright : (C) 2017 by Alessandro Pasotti
Email : apasotti at boundlessgeo 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. *
* *
***************************************************************************/

/** \ingroup core
* \class QgsSettings
*
* This class is a composition of two QSettings instances:
* - the main QSettings instance is the standard User Settings and
* - the second one (Global Settings) is meant to provide read-only
* pre-configuration and defaults to the first one.
*
* Unlike the original QSettings, the keys of QgsSettings are case insensitive.
*
* For a given settings key, the function call to value(key, default) will return
* the first existing setting in the order specified below:
* - User Settings
* - Global Settings
* - Default Value
*
* The path to the Global Settings storage can be set before constructing the QgsSettings
* objects, with a static call to:
* static bool setGlobalSettingsPath( QString path );
*
* QgsSettings provides some shortcuts to get/set namespaced settings from/to a specific section:
* - Core
* - Gui
* - Server
* - Plugins
* - Misc
*
* @note added in QGIS 3
*/
class QgsSettings : public QObject
{

%TypeHeaderCode
#include <qgssettings.h>
%End

public:

//! Sections for namespaced settings
enum Section
{
NoSection,
Core,
Gui,
Server,
Plugins,
Misc
};

/** Construct a QgsSettings object for accessing settings of the application
* called application from the organization called organization, and with parent parent.
*/
explicit QgsSettings( const QString &organization,
const QString &application = QString(), QObject *parent = 0 );

/** Construct a QgsSettings object for accessing settings of the application called application
* from the organization called organization, and with parent parent.
* If scope is QSettings::UserScope, the QSettings object searches user-specific settings first,
* before it searches system-wide settings as a fallback. If scope is QSettings::SystemScope,
* the QSettings object ignores user-specific settings and provides access to system-wide settings.
*
* The storage format is set to QSettings::NativeFormat (i.e. calling setDefaultFormat() before
* calling this constructor has no effect).
*
* If no application name is given, the QSettings object will only access the organization-wide
* locations.
*/
QgsSettings( QSettings::Scope scope, const QString &organization,
const QString &application = QString(), QObject *parent = 0 );

/** Construct a QgsSettings object for accessing settings of the application called application
* from the organization called organization, and with parent parent.
* If scope is QSettings::UserScope, the QSettings object searches user-specific settings first,
* before it searches system-wide settings as a fallback. If scope is QSettings::SystemScope,
* the QSettings object ignores user-specific settings and provides access to system-wide settings.
* If format is QSettings::NativeFormat, the native API is used for storing settings. If format
* is QSettings::IniFormat, the INI format is used.
*
* If no application name is given, the QSettings object will only access the organization-wide
* locations.
*/
QgsSettings( QSettings::Format format, QSettings::Scope scope, const QString &organization,
const QString &application = QString(), QObject *parent = 0 );

/** Construct a QgsSettings object for accessing the settings stored in the file called fileName,
* with parent parent. If the file doesn't already exist, it is created.
*
* If format is QSettings::NativeFormat, the meaning of fileName depends on the platform. On Unix,
* fileName is the name of an INI file. On macOS and iOS, fileName is the name of a .plist file.
* On Windows, fileName is a path in the system registry.
*
* If format is QSettings::IniFormat, fileName is the name of an INI file.
*
* Warning: This function is provided for convenience. It works well for accessing INI or .plist
* files generated by Qt, but might fail on some syntaxes found in such files originated by
* other programs. In particular, be aware of the following limitations:
* - QgsSettings provides no way of reading INI "path" entries, i.e., entries with unescaped slash characters.
* (This is because these entries are ambiguous and cannot be resolved automatically.)
* - In INI files, QSettings uses the @ character as a metacharacter in some contexts, to encode
* Qt-specific data types (e.g., \@Rect), and might therefore misinterpret it when it occurs
* in pure INI files.
*/
QgsSettings( const QString &fileName, QSettings::Format format, QObject *parent = 0 );

/** Constructs a QgsSettings object for accessing settings of the application and organization
* set previously with a call to QCoreApplication::setOrganizationName(),
* QCoreApplication::setOrganizationDomain(), and QCoreApplication::setApplicationName().
*
* The scope is QSettings::UserScope and the format is defaultFormat() (QSettings::NativeFormat
* by default). Use setDefaultFormat() before calling this constructor to change the default
* format used by this constructor.
*/
explicit QgsSettings( QObject *parent = 0 );
~QgsSettings();

/** Appends prefix to the current group.
* The current group is automatically prepended to all keys specified to QSettings.
* In addition, query functions such as childGroups(), childKeys(), and allKeys()
* are based on the group. By default, no group is set.
*/
void beginGroup( const QString &prefix );
//! Resets the group to what it was before the corresponding beginGroup() call.
void endGroup();
//! Returns a list of all keys, including subkeys, that can be read using the QSettings object.
QStringList allKeys() const;
//! Returns a list of all top-level keys that can be read using the QSettings object.
QStringList childKeys() const;
//! Returns a list of all key top-level groups that contain keys that can be read using the QSettings object.
QStringList childGroups() const;
//! Return the path to the Global Settings QSettings storage file
static QString globalSettingsPath();
//! Set the Global Settings QSettings storage file
static bool setGlobalSettingsPath( QString path );
//! Adds prefix to the current group and starts reading from an array. Returns the size of the array.
int beginReadArray( const QString &prefix );
//! Closes the array that was started using beginReadArray() or beginWriteArray().
void endArray();
//! Sets the current array index to i. Calls to functions such as setValue(), value(), remove(), and contains() will operate on the array entry at that index.
void setArrayIndex( int i );
//! Sets the value of setting key to value. If the key already exists, the previous value is overwritten.
//! An optional Section argument can be used to set a value to a specific Section.
//! @note keys are case insensitive
void setValue(const QString &key, const QVariant &value, const QgsSettings::Section section = QgsSettings::Section::NoSection );
/** Returns the value for setting key. If the setting doesn't exist, it will be
* searched in the Global Settings and if not found, returns defaultValue.
* If no default value is specified, a default QVariant is returned.
* An optional Section argument can be used to get a value from a specific Section.
*/
QVariant value( const QString &key, const QVariant &defaultValue = QVariant(),
const QgsSettings::Section section = QgsSettings::Section::NoSection ) const;
//! Removes the setting key and any sub-settings of key.
void remove(const QString &key);
//! Return the sanitized and prefixed key
QString prefixedKey( const QString &key, const Section section ) const;
//! Returns the path where settings written using this QSettings object are stored.
QString fileName() const;
//! Writes any unsaved changes to permanent storage, and reloads any settings that have been
//! changed in the meantime by another application.
//! This function is called automatically from QSettings's destructor and by the event
//! loop at regular intervals, so you normally don't need to call it yourself.
void sync();
//! Returns true if there exists a setting called key; returns false otherwise.
//! If a group is set using beginGroup(), key is taken to be relative to that group.
bool contains(const QString &key) const;

};
44 changes: 40 additions & 4 deletions src/app/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ typedef SInt32 SRefCon;
#endif

#include "qgscustomization.h"
#include "qgssettings.h"
#include "qgsfontutils.h"
#include "qgspluginregistry.h"
#include "qgsmessagelog.h"
Expand Down Expand Up @@ -119,7 +120,8 @@ void usage( const QString& appName )
<< QStringLiteral( "\t[--noversioncheck]\tdon't check for new version of QGIS at startup\n" )
<< QStringLiteral( "\t[--noplugins]\tdon't restore plugins on startup\n" )
<< QStringLiteral( "\t[--nocustomization]\tdon't apply GUI customization\n" )
<< QStringLiteral( "\t[--customizationfile]\tuse the given ini file as GUI customization\n" )
<< QStringLiteral( "\t[--customizationfile path]\tuse the given ini file as GUI customization\n" )
<< QStringLiteral( "\t[--globalsettingsfile path]\tuse the given ini file as Global Settings (defaults)\n" )
<< QStringLiteral( "\t[--optionspath path]\tuse the given QSettings path\n" )
<< QStringLiteral( "\t[--configpath path]\tuse the given path for all user configuration\n" )
<< QStringLiteral( "\t[--authdbdirectory path] use the given directory for authentication database\n" )
Expand Down Expand Up @@ -556,6 +558,7 @@ int main( int argc, char *argv[] )
QString pythonfile;

QString customizationfile;
QString globalsettingsfile;

#if defined(ANDROID)
QgsDebugMsg( QString( "Android: All params stripped" ) );// Param %1" ).arg( argv[0] ) );
Expand Down Expand Up @@ -642,6 +645,10 @@ int main( int argc, char *argv[] )
{
customizationfile = QDir::toNativeSeparators( QFileInfo( args[++i] ).absoluteFilePath() );
}
else if ( i + 1 < argc && ( arg == QLatin1String( "--globalsettingsfile" ) || arg == QLatin1String( "-g" ) ) )
{
globalsettingsfile = QDir::toNativeSeparators( QFileInfo( args[++i] ).absoluteFilePath() );
}
else if ( arg == QLatin1String( "--defaultui" ) || arg == QLatin1String( "-d" ) )
{
myRestoreDefaultWindowState = true;
Expand Down Expand Up @@ -813,6 +820,35 @@ int main( int argc, char *argv[] )
QCoreApplication::setApplicationName( QgsApplication::QGIS_APPLICATION_NAME );
QCoreApplication::setAttribute( Qt::AA_DontShowIconsInMenus, false );

// SetUp the QgsSettings Global Settings:
// - use the path specified with --globalsettings path,
// - use the environment if not found
// - use a default location as a fallback
if ( globalsettingsfile.isEmpty( ) )
{
globalsettingsfile = getenv( "QGIS_GLOBAL_SETTINGS_FILE" );
}
if ( globalsettingsfile.isEmpty( ) )
{
QString default_globalsettingsfile = QgsApplication::pkgDataPath( ) + "/qgis_global_settings.ini";
if ( QFile::exists( default_globalsettingsfile ) )
{
globalsettingsfile = default_globalsettingsfile;
}
}
if ( !globalsettingsfile.isEmpty() )
{
if ( ! QgsSettings::setGlobalSettingsPath( globalsettingsfile ) )
{
QgsMessageLog::logMessage( QString( "Invalid globalsettingsfile path: %1" ).arg( globalsettingsfile ), QStringLiteral( "QGIS" ) );
}
else
{
QgsMessageLog::logMessage( QString( "Successfully loaded globalsettingsfile path: %1" ).arg( globalsettingsfile ), QStringLiteral( "QGIS" ) );
}
}

// TODO: use QgsSettings
QSettings* customizationsettings = nullptr;
if ( !optionpath.isEmpty() || !configpath.isEmpty() )
{
Expand Down Expand Up @@ -866,7 +902,8 @@ int main( int argc, char *argv[] )
}
#endif

QSettings mySettings;

QgsSettings mySettings;

// update any saved setting for older themes to new default 'gis' theme (2013-04-15)
if ( mySettings.contains( QStringLiteral( "/Themes" ) ) )
Expand All @@ -880,7 +917,6 @@ int main( int argc, char *argv[] )
}
}


// custom environment variables
QMap<QString, QString> systemEnvVars = QgsApplication::systemEnvVars();
bool useCustomVars = mySettings.value( QStringLiteral( "qgis/customEnvVarsUse" ), QVariant( false ) ).toBool();
Expand Down Expand Up @@ -1072,7 +1108,7 @@ int main( int argc, char *argv[] )

// set max. thread count
// this should be done in QgsApplication::init() but it doesn't know the settings dir.
QgsApplication::setMaxThreads( QSettings().value( QStringLiteral( "/qgis/max_threads" ), -1 ).toInt() );
QgsApplication::setMaxThreads( mySettings.value( QStringLiteral( "/qgis/max_threads" ), -1 ).toInt() );

QgisApp *qgis = new QgisApp( mypSplash, myRestorePlugins, mySkipVersionCheck ); // "QgisApp" used to find canonical instance
qgis->setObjectName( QStringLiteral( "QgisApp" ) );
Expand Down
4 changes: 2 additions & 2 deletions src/app/qgisapp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,6 @@
#include <QProgressDialog>
#include <QRegExp>
#include <QRegExpValidator>
#include <QSettings>
#include <QShortcut>
#include <QSpinBox>
#include <QSplashScreen>
Expand All @@ -70,6 +69,7 @@
#include <QWhatsThis>
#include <QWidgetAction>

#include <qgssettings.h>
#include <qgsnetworkaccessmanager.h>
#include <qgsapplication.h>
#include <qgscomposition.h>
Expand Down Expand Up @@ -673,7 +673,7 @@ QgisApp::QgisApp( QSplashScreen *splash, bool restorePlugins, bool skipVersionCh
mSplash->showMessage( tr( "Setting up the GUI" ), Qt::AlignHCenter | Qt::AlignBottom );
qApp->processEvents();

QSettings settings;
QgsSettings settings;

startProfile( QStringLiteral( "Building style sheet" ) );
// set up stylesheet builder and apply saved or default style options
Expand Down
2 changes: 2 additions & 0 deletions src/core/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,7 @@ SET(QGIS_CORE_SRCS
qgsvirtuallayerdefinitionutils.cpp
qgsmapthemecollection.cpp
qgsxmlutils.cpp
qgssettings.cpp

composer/qgsaddremoveitemcommand.cpp
composer/qgsaddremovemultiframecommand.cpp
Expand Down Expand Up @@ -539,6 +540,7 @@ SET(QGIS_CORE_MOC_HDRS
qgsmapthemecollection.h
qgswebpage.h
qgswebview.h
qgssettings.h

annotations/qgsannotation.h
annotations/qgsannotationmanager.h
Expand Down
Loading

0 comments on commit e1ede70

Please sign in to comment.