QGIS/src/app/options/qgsoptions.cpp
2023-03-24 06:30:13 +10:00

2777 lines
125 KiB
C++

/***************************************************************************
qgsoptions.cpp
Set user options and preferences
-------------------
begin : May 28, 2004
copyright : (C) 2004 by Gary E.Sherman
email : sherman at mrcc.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 "qgsapplication.h"
#include "qgsoptions.h"
#include "qgis.h"
#include "qgisapp.h"
#include "qgisappstylesheet.h"
#include "qgsgdalutils.h"
#include "qgscoordinatereferencesystem.h"
#include "qgstolerance.h"
#include "qgsscaleutils.h"
#include "qgsnetworkaccessmanager.h"
#include "qgsproject.h"
#include "qgsdualview.h"
#include "qgsexpressioncontextutils.h"
#include "qgslocaldefaultsettings.h"
#include "qgsnumericformatwidget.h"
#include "qgslayertreemodellegendnode.h"
#include "qgsattributetablefiltermodel.h"
#include "qgslocalizeddatapathregistry.h"
#include "qgsrasterformatsaveoptionswidget.h"
#include "qgsrasterpyramidsoptionswidget.h"
#include "qgsdatumtransformtablewidget.h"
#include "qgsdialog.h"
#include "qgscolorschemeregistry.h"
#include "qgssymbollayerutils.h"
#include "qgscolordialog.h"
#include "qgsexpressioncontext.h"
#include "qgsunittypes.h"
#include "qgsclipboard.h"
#include "qgslayout.h"
#include "qgssettings.h"
#include "qgssettingsregistrycore.h"
#include "qgssettingsregistrygui.h"
#include "qgsoptionswidgetfactory.h"
#include "qgslocatorwidget.h"
#include "qgslocatoroptionswidget.h"
#include "qgsgui.h"
#include "qgswelcomepage.h"
#include "qgsnewsfeedparser.h"
#include "qgsbearingnumericformat.h"
#include "qgscoordinatenumericformat.h"
#include "options/qgsadvancedoptions.h"
#include "qgssettingsentryimpl.h"
#include "qgssettingsentryenumflag.h"
#ifdef HAVE_OPENCL
#include "qgsopenclutils.h"
#endif
#include <QInputDialog>
#include <QFileDialog>
#include <QColorDialog>
#include <QLocale>
#include <QProcess>
#include <QToolBar>
#include <QScrollBar>
#include <QSize>
#include <QStyleFactory>
#include <QMessageBox>
#include <QNetworkDiskCache>
#include <QStandardPaths>
#include <QRegularExpression>
#include <limits>
#include <sqlite3.h>
#include "qgslogger.h"
#define CPL_SUPRESS_CPLUSPLUS //#spellok
#include <gdal.h>
#include <geos_c.h>
#include <cpl_conv.h> // for setting gdal options
#include "qgsconfig.h"
/**
* \class QgsOptions - Set user options and preferences
* Constructor
*/
QgsOptions::QgsOptions( QWidget *parent, Qt::WindowFlags fl, const QList<QgsOptionsWidgetFactory *> &optionsFactories )
: QgsOptionsDialogBase( QStringLiteral( "Options" ), parent, fl )
{
setupUi( this );
mTreeModel = new QStandardItemModel( this );
mTreeModel->appendRow( createItem( QCoreApplication::translate( "QgsOptionsBase", "General" ), QCoreApplication::translate( "QgsOptionsBase", "General" ), QStringLiteral( "propertyicons/general.svg" ) ) );
mTreeModel->appendRow( createItem( QCoreApplication::translate( "QgsOptionsBase", "System" ), QCoreApplication::translate( "QgsOptionsBase", "System" ), QStringLiteral( "propertyicons/system.svg" ) ) );
QStandardItem *crsGroup = new QStandardItem( QCoreApplication::translate( "QgsOptionsBase", "CRS and Transforms" ) );
crsGroup->setData( QStringLiteral( "crs_and_transforms" ) );
crsGroup->setToolTip( tr( "CRS and Transforms" ) );
crsGroup->setSelectable( false );
crsGroup->appendRow( createItem( QCoreApplication::translate( "QgsOptionsBase", "CRS Handling" ), QCoreApplication::translate( "QgsOptionsBase", "General CRS handling" ), QStringLiteral( "propertyicons/CRS.svg" ) ) );
crsGroup->appendRow( createItem( QCoreApplication::translate( "QgsOptionsBase", "Coordinate Transforms" ), QCoreApplication::translate( "QgsOptionsBase", "Coordinate transformations and operations" ), QStringLiteral( "transformation.svg" ) ) );
mTreeModel->appendRow( crsGroup );
QStandardItem *dataSources = createItem( QCoreApplication::translate( "QgsOptionsBase", "Data Sources" ), QCoreApplication::translate( "QgsOptionsBase", "Data sources" ), QStringLiteral( "propertyicons/attributes.svg" ) );
mTreeModel->appendRow( dataSources );
dataSources->appendRow( createItem( QCoreApplication::translate( "QgsOptionsBase", "GDAL" ), QCoreApplication::translate( "QgsOptionsBase", "GDAL" ), QStringLiteral( "propertyicons/gdal.svg" ) ) );
mTreeModel->appendRow( createItem( QCoreApplication::translate( "QgsOptionsBase", "Canvas & Legend" ), QCoreApplication::translate( "QgsOptionsBase", "Canvas and legend" ), QStringLiteral( "propertyicons/overlay.svg" ) ) );
QStandardItem *mapTools = createItem( QCoreApplication::translate( "QgsOptionsBase", "Map Tools" ), QCoreApplication::translate( "QgsOptionsBase", "Map tools" ), QStringLiteral( "propertyicons/map_tools.svg" ) );
mTreeModel->appendRow( mapTools );
mapTools->appendRow( createItem( QCoreApplication::translate( "QgsOptionsBase", "Digitizing" ), QCoreApplication::translate( "QgsOptionsBase", "Digitizing" ), QStringLiteral( "propertyicons/digitizing.svg" ) ) );
mTreeModel->appendRow( createItem( QCoreApplication::translate( "QgsOptionsBase", "Colors" ), QCoreApplication::translate( "QgsOptionsBase", "Colors" ), QStringLiteral( "propertyicons/colors.svg" ) ) );
mTreeModel->appendRow( createItem( QCoreApplication::translate( "QgsOptionsBase", "Layouts" ), QCoreApplication::translate( "QgsOptionsBase", "Print layouts" ), QStringLiteral( "mIconLayout.svg" ) ) );
mTreeModel->appendRow( createItem( QCoreApplication::translate( "QgsOptionsBase", "Variables" ), QCoreApplication::translate( "QgsOptionsBase", "Variables" ), QStringLiteral( "mIconExpression.svg" ) ) );
mTreeModel->appendRow( createItem( QCoreApplication::translate( "QgsOptionsBase", "Authentication" ), QCoreApplication::translate( "QgsOptionsBase", "Authentication" ), QStringLiteral( "locked.svg" ) ) );
mTreeModel->appendRow( createItem( QCoreApplication::translate( "QgsOptionsBase", "Network" ), QCoreApplication::translate( "QgsOptionsBase", "Network" ), QStringLiteral( "propertyicons/network_and_proxy.svg" ) ) );
mTreeModel->appendRow( createItem( QCoreApplication::translate( "QgsOptionsBase", "Locator" ), tr( "Locator" ), QStringLiteral( "search.svg" ) ) );
mTreeModel->appendRow( createItem( QCoreApplication::translate( "QgsOptionsBase", "Acceleration" ), tr( "GPU acceleration" ), QStringLiteral( "mIconGPU.svg" ) ) );
QStandardItem *ideGroup = new QStandardItem( QCoreApplication::translate( "QgsOptionsBase", "IDE" ) );
ideGroup->setData( QStringLiteral( "ide" ) );
ideGroup->setToolTip( tr( "Development and Scripting Settings" ) );
ideGroup->setSelectable( false );
mTreeModel->appendRow( ideGroup );
mOptionsTreeView->setModel( mTreeModel );
connect( cbxProjectDefaultNew, &QCheckBox::toggled, this, &QgsOptions::cbxProjectDefaultNew_toggled );
connect( leLayerGlobalCrs, &QgsProjectionSelectionWidget::crsChanged, this, &QgsOptions::leLayerGlobalCrs_crsChanged );
connect( lstRasterDrivers, &QTreeWidget::itemDoubleClicked, this, &QgsOptions::lstRasterDrivers_itemDoubleClicked );
connect( mProjectOnLaunchCmbBx, static_cast<void ( QComboBox::* )( int )>( &QComboBox::currentIndexChanged ), this, &QgsOptions::mProjectOnLaunchCmbBx_currentIndexChanged );
connect( spinFontSize, static_cast < void ( QSpinBox::* )( int ) > ( &QSpinBox::valueChanged ), this, &QgsOptions::spinFontSize_valueChanged );
connect( mFontFamilyRadioQt, &QRadioButton::released, this, &QgsOptions::mFontFamilyRadioQt_released );
connect( mFontFamilyRadioCustom, &QRadioButton::released, this, &QgsOptions::mFontFamilyRadioCustom_released );
connect( mFontFamilyComboBox, &QFontComboBox::currentFontChanged, this, &QgsOptions::mFontFamilyComboBox_currentFontChanged );
connect( mProxyTypeComboBox, static_cast<void ( QComboBox::* )( int )>( &QComboBox::currentIndexChanged ), this, &QgsOptions::mProxyTypeComboBox_currentIndexChanged );
connect( mCustomVariablesChkBx, &QCheckBox::toggled, this, &QgsOptions::mCustomVariablesChkBx_toggled );
connect( mCurrentVariablesQGISChxBx, &QCheckBox::toggled, this, &QgsOptions::mCurrentVariablesQGISChxBx_toggled );
connect( buttonBox, &QDialogButtonBox::helpRequested, this, &QgsOptions::showHelp );
connect( cboGlobalLocale, qOverload< int >( &QComboBox::currentIndexChanged ), this, [ = ]( int ) { updateSampleLocaleText( ); } );
connect( cbShowGroupSeparator, &QCheckBox::toggled, this, [ = ]( bool ) { updateSampleLocaleText(); } );
// QgsOptionsDialogBase handles saving/restoring of geometry, splitter and current tab states,
// switching vertical tabs between icon/text to icon-only modes (splitter collapsed to left),
// and connecting QDialogButtonBox's accepted/rejected signals to dialog's accept/reject slots
initOptionsBase( false );
// disconnect default connection setup by initOptionsBase for accepting dialog, and insert logic
// to validate widgets before allowing dialog to be closed
disconnect( mOptButtonBox, &QDialogButtonBox::accepted, this, &QDialog::accept );
connect( mOptButtonBox, &QDialogButtonBox::accepted, this, [ = ]
{
for ( QgsOptionsPageWidget *widget : std::as_const( mAdditionalOptionWidgets ) )
{
if ( !widget->isValid() )
{
setCurrentPage( widget->objectName() );
return;
}
}
accept();
} );
// stylesheet setup
mStyleSheetBuilder = QgisApp::instance()->styleSheetBuilder();
mStyleSheetNewOpts = mStyleSheetBuilder->defaultOptions();
mStyleSheetOldOpts = QMap<QString, QVariant>( mStyleSheetNewOpts );
connect( mFontFamilyRadioCustom, &QAbstractButton::toggled, mFontFamilyComboBox, &QWidget::setEnabled );
connect( cmbIconSize, qOverload< int >( &QComboBox::activated ), this, &QgsOptions::iconSizeChanged );
connect( cmbIconSize, qOverload< int >( &QComboBox::highlighted ), this, &QgsOptions::iconSizeChanged );
connect( cmbIconSize, &QComboBox::editTextChanged, this, &QgsOptions::iconSizeChanged );
connect( this, &QDialog::accepted, this, &QgsOptions::saveOptions );
connect( this, &QDialog::rejected, this, &QgsOptions::rejectOptions );
QStringList styles = QStyleFactory::keys();
QStringList filteredStyles = styles;
for ( int i = filteredStyles.count() - 1; i >= 0; --i )
{
// filter out the broken adwaita styles - see note in main.cpp
if ( filteredStyles.at( i ).contains( QStringLiteral( "adwaita" ), Qt::CaseInsensitive ) )
{
filteredStyles.removeAt( i );
}
}
if ( filteredStyles.isEmpty() )
{
// oops - none left!.. have to let user use a broken style
filteredStyles = styles;
}
cmbStyle->addItems( filteredStyles );
QStringList themes = QgsApplication::uiThemes().keys();
cmbUITheme->addItems( themes );
// non-default themes are best rendered using the Fusion style, therefore changing themes must require a restart to
lblUITheme->setText( QStringLiteral( "%1 <i>(%2)</i>" ).arg( lblUITheme->text(), tr( "QGIS restart required" ) ) );
mEnableMacrosComboBox->addItem( tr( "Never" ), QVariant::fromValue( Qgis::PythonMacroMode::Never ) );
mEnableMacrosComboBox->addItem( tr( "Ask" ), QVariant::fromValue( Qgis::PythonMacroMode::Ask ) );
mEnableMacrosComboBox->addItem( tr( "For This Session Only" ), QVariant::fromValue( Qgis::PythonMacroMode::SessionOnly ) );
mEnableMacrosComboBox->addItem( tr( "Not During This Session" ), QVariant::fromValue( Qgis::PythonMacroMode::NotForThisSession ) );
mEnableMacrosComboBox->addItem( tr( "Always (Not Recommended)" ), QVariant::fromValue( Qgis::PythonMacroMode::Always ) );
mIdentifyHighlightColorButton->setColorDialogTitle( tr( "Identify Highlight Color" ) );
mIdentifyHighlightColorButton->setAllowOpacity( true );
mIdentifyHighlightColorButton->setContext( QStringLiteral( "gui" ) );
mIdentifyHighlightColorButton->setDefaultColor( Qgis::DEFAULT_HIGHLIGHT_COLOR );
mSettings = new QgsSettings();
double identifyValue = mSettings->value( QStringLiteral( "/Map/searchRadiusMM" ), Qgis::DEFAULT_SEARCH_RADIUS_MM ).toDouble();
QgsDebugMsgLevel( QStringLiteral( "Standard Identify radius setting read from settings file: %1" ).arg( identifyValue ), 3 );
if ( identifyValue <= 0.0 )
identifyValue = Qgis::DEFAULT_SEARCH_RADIUS_MM;
spinBoxIdentifyValue->setMinimum( 0.0 );
spinBoxIdentifyValue->setClearValue( Qgis::DEFAULT_SEARCH_RADIUS_MM );
spinBoxIdentifyValue->setValue( identifyValue );
QColor highlightColor = QColor( mSettings->value( QStringLiteral( "/Map/highlight/color" ), Qgis::DEFAULT_HIGHLIGHT_COLOR.name() ).toString() );
int highlightAlpha = mSettings->value( QStringLiteral( "/Map/highlight/colorAlpha" ), Qgis::DEFAULT_HIGHLIGHT_COLOR.alpha() ).toInt();
highlightColor.setAlpha( highlightAlpha );
mIdentifyHighlightColorButton->setColor( highlightColor );
double highlightBuffer = mSettings->value( QStringLiteral( "/Map/highlight/buffer" ), Qgis::DEFAULT_HIGHLIGHT_BUFFER_MM ).toDouble();
mIdentifyHighlightBufferSpinBox->setClearValue( Qgis::DEFAULT_HIGHLIGHT_BUFFER_MM );
mIdentifyHighlightBufferSpinBox->setValue( highlightBuffer );
double highlightMinWidth = mSettings->value( QStringLiteral( "/Map/highlight/minWidth" ), Qgis::DEFAULT_HIGHLIGHT_MIN_WIDTH_MM ).toDouble();
mIdentifyHighlightMinWidthSpinBox->setClearValue( Qgis::DEFAULT_HIGHLIGHT_MIN_WIDTH_MM );
mIdentifyHighlightMinWidthSpinBox->setValue( highlightMinWidth );
// custom environment variables
bool useCustomVars = mSettings->value( QStringLiteral( "qgis/customEnvVarsUse" ), QVariant( false ) ).toBool();
mCustomVariablesChkBx->setChecked( useCustomVars );
if ( !useCustomVars )
{
mAddCustomVarBtn->setEnabled( false );
mRemoveCustomVarBtn->setEnabled( false );
mCustomVariablesTable->setEnabled( false );
}
const QStringList customVarsList = mSettings->value( QStringLiteral( "qgis/customEnvVars" ) ).toStringList();
for ( const QString &varStr : customVarsList )
{
int pos = varStr.indexOf( QLatin1Char( '|' ) );
if ( pos == -1 )
continue;
QString varStrApply = varStr.left( pos );
QString varStrNameValue = varStr.mid( pos + 1 );
pos = varStrNameValue.indexOf( QLatin1Char( '=' ) );
if ( pos == -1 )
continue;
QString varStrName = varStrNameValue.left( pos );
QString varStrValue = varStrNameValue.mid( pos + 1 );
addCustomEnvVarRow( varStrName, varStrValue, varStrApply );
}
QFontMetrics fmCustomVar( mCustomVariablesTable->horizontalHeader()->font() );
int fmCustomVarH = fmCustomVar.height() + 8;
mCustomVariablesTable->horizontalHeader()->setFixedHeight( fmCustomVarH );
mCustomVariablesTable->setColumnWidth( 0, 120 );
if ( mCustomVariablesTable->rowCount() > 0 )
{
mCustomVariablesTable->resizeColumnToContents( 1 );
}
else
{
mCustomVariablesTable->setColumnWidth( 1, 120 );
}
// current environment variables
mCurrentVariablesTable->horizontalHeader()->setFixedHeight( fmCustomVarH );
QMap<QString, QString> sysVarsMap = QgsApplication::systemEnvVars();
const QStringList currentVarsList = QProcess::systemEnvironment();
for ( const QString &varStr : currentVarsList )
{
int pos = varStr.indexOf( QLatin1Char( '=' ) );
if ( pos == -1 )
continue;
QStringList varStrItms;
QString varStrName = varStr.left( pos );
QString varStrValue = varStr.mid( pos + 1 );
varStrItms << varStrName << varStrValue;
// check if different than system variable
QString sysVarVal;
bool sysVarMissing = !sysVarsMap.contains( varStrName );
if ( sysVarMissing )
sysVarVal = tr( "not present" );
if ( !sysVarMissing && sysVarsMap.value( varStrName ) != varStrValue )
sysVarVal = sysVarsMap.value( varStrName );
if ( !sysVarVal.isEmpty() )
sysVarVal = tr( "System value: %1" ).arg( sysVarVal );
int rowCnt = mCurrentVariablesTable->rowCount();
mCurrentVariablesTable->insertRow( rowCnt );
QFont fItm;
for ( int i = 0; i < varStrItms.size(); ++i )
{
QTableWidgetItem *varNameItm = new QTableWidgetItem( varStrItms.at( i ) );
varNameItm->setFlags( Qt::ItemIsEnabled | Qt::ItemIsSelectable );
fItm = varNameItm->font();
if ( !sysVarVal.isEmpty() )
{
fItm.setBold( true );
varNameItm->setFont( fItm );
varNameItm->setToolTip( sysVarVal );
}
mCurrentVariablesTable->setItem( rowCnt, i, varNameItm );
}
fItm.setBold( true );
QFontMetrics fmRow( fItm );
mCurrentVariablesTable->setRowHeight( rowCnt, fmRow.height() + 6 );
}
if ( mCurrentVariablesTable->rowCount() > 0 )
mCurrentVariablesTable->resizeColumnToContents( 0 );
//local directories to search when loading c++ plugins
const QStringList pluginsPathList = mSettings->value( QStringLiteral( "plugins/searchPathsForPlugins" ) ).toStringList();
for ( const QString &path : pluginsPathList )
{
QListWidgetItem *newItem = new QListWidgetItem( mListPluginPaths );
newItem->setText( path );
newItem->setFlags( Qt::ItemIsEditable | Qt::ItemIsEnabled | Qt::ItemIsSelectable );
mListPluginPaths->addItem( newItem );
}
connect( mBtnAddPluginPath, &QAbstractButton::clicked, this, &QgsOptions::addPluginPath );
connect( mBtnRemovePluginPath, &QAbstractButton::clicked, this, &QgsOptions::removePluginPath );
//local directories to search when looking for an SVG with a given basename
const QStringList svgPathList = QgsApplication::svgPaths();
for ( const QString &path : svgPathList )
{
QListWidgetItem *newItem = new QListWidgetItem( mListSVGPaths );
newItem->setText( path );
newItem->setFlags( Qt::ItemIsEditable | Qt::ItemIsEnabled | Qt::ItemIsSelectable );
mListSVGPaths->addItem( newItem );
}
connect( mBtnAddSVGPath, &QAbstractButton::clicked, this, &QgsOptions::addSVGPath );
connect( mBtnRemoveSVGPath, &QAbstractButton::clicked, this, &QgsOptions::removeSVGPath );
//local directories to search when looking for a composer templates
const QStringList composerTemplatePathList = QgsApplication::layoutTemplatePaths();
for ( const QString &path : composerTemplatePathList )
{
QListWidgetItem *newItem = new QListWidgetItem( mListComposerTemplatePaths );
newItem->setText( path );
newItem->setFlags( Qt::ItemIsEditable | Qt::ItemIsEnabled | Qt::ItemIsSelectable );
mListComposerTemplatePaths->addItem( newItem );
}
connect( mBtnAddTemplatePath, &QAbstractButton::clicked, this, &QgsOptions::addTemplatePath );
connect( mBtnRemoveTemplatePath, &QAbstractButton::clicked, this, &QgsOptions::removeTemplatePath );
// localized data paths
connect( mLocalizedDataPathAddButton, &QAbstractButton::clicked, this, &QgsOptions::addLocalizedDataPath );
connect( mLocalizedDataPathRemoveButton, &QAbstractButton::clicked, this, &QgsOptions::removeLocalizedDataPath );
connect( mLocalizedDataPathUpButton, &QAbstractButton::clicked, this, &QgsOptions::moveLocalizedDataPathUp );
connect( mLocalizedDataPathDownButton, &QAbstractButton::clicked, this, &QgsOptions::moveLocalizedDataPathDown );
const QStringList localizedPaths = QgsApplication::localizedDataPathRegistry()->paths();
for ( const QString &path : localizedPaths )
{
QListWidgetItem *newItem = new QListWidgetItem( mLocalizedDataPathListWidget );
newItem->setText( path );
newItem->setFlags( Qt::ItemIsEditable | Qt::ItemIsEnabled | Qt::ItemIsSelectable );
mLocalizedDataPathListWidget->addItem( newItem );
}
//paths hidden from browser
const QStringList hiddenPathList = mSettings->value( QStringLiteral( "/browser/hiddenPaths" ) ).toStringList();
for ( const QString &path : hiddenPathList )
{
QListWidgetItem *newItem = new QListWidgetItem( mListHiddenBrowserPaths );
newItem->setText( path );
mListHiddenBrowserPaths->addItem( newItem );
}
connect( mBtnRemoveHiddenPath, &QAbstractButton::clicked, this, &QgsOptions::removeHiddenPath );
//locations of the QGIS help
const QStringList helpPathList = mSettings->value( QStringLiteral( "help/helpSearchPath" ), "https://docs.qgis.org/$qgis_short_version/$qgis_locale/docs/user_manual/" ).toStringList();
for ( const QString &path : helpPathList )
{
QTreeWidgetItem *item = new QTreeWidgetItem();
item->setText( 0, path );
item->setFlags( Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsEditable );
mHelpPathTreeWidget->addTopLevelItem( item );
}
connect( mBtnAddHelpPath, &QAbstractButton::clicked, this, &QgsOptions::addHelpPath );
connect( mBtnRemoveHelpPath, &QAbstractButton::clicked, this, &QgsOptions::removeHelpPath );
connect( mBtnMoveHelpUp, &QAbstractButton::clicked, this, &QgsOptions::moveHelpPathUp );
connect( mBtnMoveHelpDown, &QAbstractButton::clicked, this, &QgsOptions::moveHelpPathDown );
//Network timeout
mNetworkTimeoutSpinBox->setValue( QgsNetworkAccessManager::timeout() );
mNetworkTimeoutSpinBox->setClearValue( QgsNetworkAccessManager::settingsNetworkTimeout->defaultValue() );
leUserAgent->setText( mSettings->value( QStringLiteral( "/qgis/networkAndProxy/userAgent" ), "Mozilla/5.0" ).toString() );
// WMS capabilities expiry time
mDefaultCapabilitiesExpirySpinBox->setValue( mSettings->value( QStringLiteral( "/qgis/defaultCapabilitiesExpiry" ), 24 ).toInt() );
mDefaultCapabilitiesExpirySpinBox->setClearValue( 24 );
// WMS/WMS-C tile expiry time
mDefaultTileExpirySpinBox->setValue( mSettings->value( QStringLiteral( "/qgis/defaultTileExpiry" ), 24 ).toInt() );
mDefaultTileExpirySpinBox->setClearValue( 24 );
// WMS/WMS-C default max retry in case of tile request errors
mDefaultTileMaxRetrySpinBox->setValue( mSettings->value( QStringLiteral( "/qgis/defaultTileMaxRetry" ), 3 ).toInt() );
mDefaultTileMaxRetrySpinBox->setClearValue( 3 );
// Proxy stored authentication configurations
mAuthSettings->setDataprovider( QStringLiteral( "proxy" ) );
QString authcfg = mSettings->value( QStringLiteral( "proxy/authcfg" ) ).toString();
mAuthSettings->setConfigId( authcfg );
mAuthSettings->setWarningText( QgsAuthSettingsWidget::formattedWarning( QgsAuthSettingsWidget::UserSettings ) );
//Web proxy settings
grpProxy->setChecked( mSettings->value( QStringLiteral( "proxy/proxyEnabled" ), false ).toBool() );
leProxyHost->setText( mSettings->value( QStringLiteral( "proxy/proxyHost" ), QString() ).toString() );
leProxyPort->setText( mSettings->value( QStringLiteral( "proxy/proxyPort" ), QString() ).toString() );
mAuthSettings->setPassword( mSettings->value( QStringLiteral( "proxy/proxyPassword" ), QString() ).toString() );
mAuthSettings->setUsername( mSettings->value( QStringLiteral( "proxy/proxyUser" ), QString() ).toString() );
//available proxy types
mProxyTypeComboBox->insertItem( 0, QStringLiteral( "DefaultProxy" ) );
mProxyTypeComboBox->insertItem( 1, QStringLiteral( "Socks5Proxy" ) );
mProxyTypeComboBox->insertItem( 2, QStringLiteral( "HttpProxy" ) );
mProxyTypeComboBox->insertItem( 3, QStringLiteral( "HttpCachingProxy" ) );
mProxyTypeComboBox->insertItem( 4, QStringLiteral( "FtpCachingProxy" ) );
QString settingProxyType = mSettings->value( QStringLiteral( "proxy/proxyType" ), QStringLiteral( "DefaultProxy" ) ).toString();
mProxyTypeComboBox->setCurrentIndex( mProxyTypeComboBox->findText( settingProxyType ) );
//url with no proxy at all
const QStringList noProxyUrlPathList = mSettings->value( QStringLiteral( "proxy/noProxyUrls" ) ).toStringList();
for ( const QString &path : noProxyUrlPathList )
{
if ( path.trimmed().isEmpty() )
continue;
QListWidgetItem *newItem = new QListWidgetItem( mNoProxyUrlListWidget );
newItem->setText( path );
newItem->setFlags( Qt::ItemIsEditable | Qt::ItemIsEnabled | Qt::ItemIsSelectable );
mNoProxyUrlListWidget->addItem( newItem );
}
connect( mAddUrlPushButton, &QAbstractButton::clicked, this, &QgsOptions::addNoProxyUrl );
connect( mRemoveUrlPushButton, &QAbstractButton::clicked, this, &QgsOptions::removeNoProxyUrl );
// cache settings
mCacheDirectory->setText( mSettings->value( QStringLiteral( "cache/directory" ) ).toString() );
mCacheDirectory->setPlaceholderText( QStandardPaths::writableLocation( QStandardPaths::CacheLocation ) );
mCacheSize->setMinimum( 0 );
mCacheSize->setMaximum( std::numeric_limits<int>::max() );
mCacheSize->setSingleStep( 1024 );
qint64 cacheSize = mSettings->value( QStringLiteral( "cache/size" ), 256 * 1024 * 1024 ).toLongLong();
mCacheSize->setValue( static_cast<int>( cacheSize / 1024 ) );
mCacheSize->setClearValue( 50 * 1024 );
connect( mBrowseCacheDirectory, &QAbstractButton::clicked, this, &QgsOptions::browseCacheDirectory );
connect( mClearCache, &QAbstractButton::clicked, this, &QgsOptions::clearCache );
// Access (auth) cache settings
mAutoClearAccessCache->setChecked( mSettings->value( QStringLiteral( "clear_auth_cache_on_errors" ), true, QgsSettings::Section::Auth ).toBool( ) );
connect( mClearAccessCache, &QAbstractButton::clicked, this, &QgsOptions::clearAccessCache );
connect( mAutoClearAccessCache, &QCheckBox::clicked, this, [ = ]( bool checked )
{
mSettings->setValue( QStringLiteral( "clear_auth_cache_on_errors" ), checked, QgsSettings::Section::Auth );
} );
// set the attribute table default filter
cmbAttrTableBehavior->clear();
cmbAttrTableBehavior->addItem( tr( "Show All Features" ), QgsAttributeTableFilterModel::ShowAll );
cmbAttrTableBehavior->addItem( tr( "Show Selected Features" ), QgsAttributeTableFilterModel::ShowSelected );
cmbAttrTableBehavior->addItem( tr( "Show Features Visible on Map" ), QgsAttributeTableFilterModel::ShowVisible );
cmbAttrTableBehavior->setCurrentIndex( cmbAttrTableBehavior->findData( mSettings->enumValue( QStringLiteral( "/qgis/attributeTableBehavior" ), QgsAttributeTableFilterModel::ShowAll ) ) );
mAttrTableViewComboBox->clear();
mAttrTableViewComboBox->addItem( tr( "Remember Last View" ), -1 );
mAttrTableViewComboBox->addItem( tr( "Table View" ), QgsDualView::AttributeTable );
mAttrTableViewComboBox->addItem( tr( "Form View" ), QgsDualView::AttributeEditor );
mAttrTableViewComboBox->setCurrentIndex( mAttrTableViewComboBox->findData( mSettings->value( QStringLiteral( "/qgis/attributeTableView" ), -1 ).toInt() ) );
spinBoxAttrTableRowCache->setValue( mSettings->value( QStringLiteral( "/qgis/attributeTableRowCache" ), 10000 ).toInt() );
spinBoxAttrTableRowCache->setClearValue( 10000 );
spinBoxAttrTableRowCache->setSpecialValueText( tr( "All" ) );
cmbPromptSublayers->clear();
cmbPromptSublayers->addItem( tr( "Always" ), static_cast< int >( Qgis::SublayerPromptMode::AlwaysAsk ) );
cmbPromptSublayers->addItem( tr( "If Needed" ), static_cast< int >( Qgis::SublayerPromptMode::AskExcludingRasterBands ) ); //this means, prompt if there are sublayers but no band in the main dataset
cmbPromptSublayers->addItem( tr( "Never" ), static_cast< int >( Qgis::SublayerPromptMode::NeverAskSkip ) );
cmbPromptSublayers->addItem( tr( "Load All" ), static_cast< int >( Qgis::SublayerPromptMode::NeverAskLoadAll ) );
cmbPromptSublayers->setCurrentIndex( cmbPromptSublayers->findData( static_cast< int >( mSettings->enumValue( QStringLiteral( "/qgis/promptForSublayers" ), Qgis::SublayerPromptMode::AlwaysAsk ) ) ) );
// Scan for valid items in the browser dock
cmbScanItemsInBrowser->clear();
cmbScanItemsInBrowser->addItem( tr( "Check File Contents" ), "contents" ); // 0
cmbScanItemsInBrowser->addItem( tr( "Check Extension" ), "extension" ); // 1
int index = cmbScanItemsInBrowser->findData( mSettings->value( QStringLiteral( "/qgis/scanItemsInBrowser2" ), QString() ) );
if ( index == -1 ) index = 1;
cmbScanItemsInBrowser->setCurrentIndex( index );
// Scan for contents of compressed files (.zip) in browser dock
cmbScanZipInBrowser->clear();
cmbScanZipInBrowser->addItem( tr( "No" ), QVariant( "no" ) );
// cmbScanZipInBrowser->addItem( tr( "Passthru" ) ); // 1 - removed
cmbScanZipInBrowser->addItem( tr( "Basic Scan" ), QVariant( "basic" ) );
cmbScanZipInBrowser->addItem( tr( "Full Scan" ), QVariant( "full" ) );
index = cmbScanZipInBrowser->findData( mSettings->value( QStringLiteral( "/qgis/scanZipInBrowser2" ), QString() ) );
if ( index == -1 ) index = 1;
cmbScanZipInBrowser->setCurrentIndex( index );
mCheckMonitorDirectories->setChecked( mSettings->value( QStringLiteral( "/qgis/monitorDirectoriesInBrowser" ), true ).toBool() );
//set the default projection behavior radio buttons
const QgsOptions::UnknownLayerCrsBehavior mode = QgsSettings().enumValue( QStringLiteral( "/projections/unknownCrsBehavior" ), QgsOptions::UnknownLayerCrsBehavior::NoAction, QgsSettings::App );
switch ( mode )
{
case NoAction:
radCrsNoAction->setChecked( true );
break;
case PromptUserForCrs:
radPromptForProjection->setChecked( true );
break;
case UseProjectCrs:
radUseProjectProjection->setChecked( true );
break;
case UseDefaultCrs:
radUseGlobalProjection->setChecked( true );
break;
}
QString myLayerDefaultCrs = mSettings->value( QStringLiteral( "/Projections/layerDefaultCrs" ), geoEpsgCrsAuthId() ).toString();
mLayerDefaultCrs = QgsCoordinateReferenceSystem::fromOgcWmsCrs( myLayerDefaultCrs );
leLayerGlobalCrs->setCrs( mLayerDefaultCrs );
const QString defaultProjectCrs = mSettings->value( QStringLiteral( "/projections/defaultProjectCrs" ), geoEpsgCrsAuthId(), QgsSettings::App ).toString();
leProjectGlobalCrs->setOptionVisible( QgsProjectionSelectionWidget::DefaultCrs, false );
leProjectGlobalCrs->setOptionVisible( QgsProjectionSelectionWidget::CrsNotSet, true );
leProjectGlobalCrs->setNotSetText( tr( "No projection (or unknown/non-Earth projection)" ) );
leProjectGlobalCrs->setCrs( QgsCoordinateReferenceSystem( defaultProjectCrs ) );
leProjectGlobalCrs->setMessage(
tr( "<h1>Default projection for new projects</h1>"
"Select a projection that should be used for new projects that are created in QGIS."
) );
const QgsGui::ProjectCrsBehavior projectCrsBehavior = mSettings->enumValue( QStringLiteral( "/projections/newProjectCrsBehavior" ), QgsGui::UseCrsOfFirstLayerAdded, QgsSettings::App );
switch ( projectCrsBehavior )
{
case QgsGui::UseCrsOfFirstLayerAdded:
radProjectUseCrsOfFirstLayer->setChecked( true );
break;
case QgsGui::UsePresetCrs:
radProjectUseDefaultCrs->setChecked( true );
break;
}
const double crsAccuracyWarningThreshold = mSettings->value( QStringLiteral( "/projections/crsAccuracyWarningThreshold" ), 0.0, QgsSettings::App ).toDouble();
mCrsAccuracySpin->setMinimumWidth( QFontMetrics( font() ).horizontalAdvance( '0' ) * 20 );
mCrsAccuracySpin->setClearValue( 0.0, tr( "Always show" ) );
mCrsAccuracySpin->setValue( crsAccuracyWarningThreshold );
const bool crsAccuracyIndicator = mSettings->value( QStringLiteral( "/projections/crsAccuracyIndicator" ), false, QgsSettings::App ).toBool();
mCrsAccuracyIndicatorCheck->setChecked( crsAccuracyIndicator );
mShowDatumTransformDialogCheckBox->setChecked( mSettings->value( QStringLiteral( "/projections/promptWhenMultipleTransformsExist" ), false, QgsSettings::App ).toBool() );
// Datum transforms
QgsCoordinateTransformContext context;
context.readSettings();
mDefaultDatumTransformTableWidget->setTransformContext( context );
// Set the units for measuring
mDistanceUnitsComboBox->addItem( tr( "Meters" ), static_cast< int >( Qgis::DistanceUnit::Meters ) );
mDistanceUnitsComboBox->addItem( tr( "Kilometers" ), static_cast< int >( Qgis::DistanceUnit::Kilometers ) );
mDistanceUnitsComboBox->addItem( tr( "Feet" ), static_cast< int >( Qgis::DistanceUnit::Feet ) );
mDistanceUnitsComboBox->addItem( tr( "Yards" ), static_cast< int >( Qgis::DistanceUnit::Yards ) );
mDistanceUnitsComboBox->addItem( tr( "Miles" ), static_cast< int >( Qgis::DistanceUnit::Miles ) );
mDistanceUnitsComboBox->addItem( tr( "Nautical Miles" ), static_cast< int >( Qgis::DistanceUnit::NauticalMiles ) );
mDistanceUnitsComboBox->addItem( tr( "Centimeters" ), static_cast< int >( Qgis::DistanceUnit::Centimeters ) );
mDistanceUnitsComboBox->addItem( tr( "Millimeters" ), static_cast< int >( Qgis::DistanceUnit::Millimeters ) );
mDistanceUnitsComboBox->addItem( tr( "Degrees" ), static_cast< int >( Qgis::DistanceUnit::Degrees ) );
mDistanceUnitsComboBox->addItem( tr( "Map Units" ), static_cast< int >( Qgis::DistanceUnit::Unknown ) );
bool ok = false;
Qgis::DistanceUnit distanceUnits = QgsUnitTypes::decodeDistanceUnit( mSettings->value( QStringLiteral( "/qgis/measure/displayunits" ) ).toString(), &ok );
if ( !ok )
distanceUnits = Qgis::DistanceUnit::Meters;
mDistanceUnitsComboBox->setCurrentIndex( mDistanceUnitsComboBox->findData( static_cast< int >( distanceUnits ) ) );
mAreaUnitsComboBox->addItem( tr( "Square Meters" ), static_cast< int >( Qgis::AreaUnit::SquareMeters ) );
mAreaUnitsComboBox->addItem( tr( "Square Kilometers" ), static_cast< int >( Qgis::AreaUnit::SquareKilometers ) );
mAreaUnitsComboBox->addItem( tr( "Square Feet" ), static_cast< int >( Qgis::AreaUnit::SquareFeet ) );
mAreaUnitsComboBox->addItem( tr( "Square Yards" ), static_cast< int >( Qgis::AreaUnit::SquareYards ) );
mAreaUnitsComboBox->addItem( tr( "Square Miles" ), static_cast< int >( Qgis::AreaUnit::SquareMiles ) );
mAreaUnitsComboBox->addItem( tr( "Hectares" ), static_cast< int >( Qgis::AreaUnit::Hectares ) );
mAreaUnitsComboBox->addItem( tr( "Acres" ), static_cast< int >( Qgis::AreaUnit::Acres ) );
mAreaUnitsComboBox->addItem( tr( "Square Nautical Miles" ), static_cast< int >( Qgis::AreaUnit::SquareNauticalMiles ) );
mAreaUnitsComboBox->addItem( tr( "Square Centimeters" ), static_cast< int >( Qgis::AreaUnit::SquareCentimeters ) );
mAreaUnitsComboBox->addItem( tr( "Square Millimeters" ), static_cast< int >( Qgis::AreaUnit::SquareMillimeters ) );
mAreaUnitsComboBox->addItem( tr( "Square Degrees" ), static_cast< int >( Qgis::AreaUnit::SquareDegrees ) );
mAreaUnitsComboBox->addItem( tr( "Map Units" ), static_cast< int >( Qgis::AreaUnit::Unknown ) );
Qgis::AreaUnit areaUnits = QgsUnitTypes::decodeAreaUnit( mSettings->value( QStringLiteral( "/qgis/measure/areaunits" ) ).toString(), &ok );
if ( !ok )
areaUnits = Qgis::AreaUnit::SquareMeters;
mAreaUnitsComboBox->setCurrentIndex( mAreaUnitsComboBox->findData( static_cast< int >( areaUnits ) ) );
mAngleUnitsComboBox->addItem( tr( "Degrees" ), static_cast< int >( Qgis::AngleUnit::Degrees ) );
mAngleUnitsComboBox->addItem( tr( "Radians" ), static_cast< int >( Qgis::AngleUnit::Radians ) );
mAngleUnitsComboBox->addItem( tr( "Gon/gradians" ), static_cast< int >( Qgis::AngleUnit::Gon ) );
mAngleUnitsComboBox->addItem( tr( "Minutes of Arc" ), static_cast< int >( Qgis::AngleUnit::MinutesOfArc ) );
mAngleUnitsComboBox->addItem( tr( "Seconds of Arc" ), static_cast< int >( Qgis::AngleUnit::SecondsOfArc ) );
mAngleUnitsComboBox->addItem( tr( "Turns/revolutions" ), static_cast< int >( Qgis::AngleUnit::Turn ) );
mAngleUnitsComboBox->addItem( tr( "Milliradians (SI Definition)" ), static_cast< int >( Qgis::AngleUnit::MilliradiansSI ) );
mAngleUnitsComboBox->addItem( tr( "Mil (NATO/military Definition)" ), static_cast< int >( Qgis::AngleUnit::MilNATO ) );
Qgis::AngleUnit unit = QgsUnitTypes::decodeAngleUnit( mSettings->value( QStringLiteral( "/qgis/measure/angleunits" ), QgsUnitTypes::encodeUnit( Qgis::AngleUnit::Degrees ) ).toString() );
mAngleUnitsComboBox->setCurrentIndex( mAngleUnitsComboBox->findData( static_cast<int>( unit ) ) );
// set decimal places of the measure tool
int decimalPlaces = mSettings->value( QStringLiteral( "/qgis/measure/decimalplaces" ), 3 ).toInt();
mDecimalPlacesSpinBox->setClearValue( 3 );
mDecimalPlacesSpinBox->setRange( 0, 12 );
mDecimalPlacesSpinBox->setValue( decimalPlaces );
// set if base unit of measure tool should be changed
bool baseUnit = mSettings->value( QStringLiteral( "qgis/measure/keepbaseunit" ), true ).toBool();
if ( baseUnit )
{
mKeepBaseUnitCheckBox->setChecked( true );
}
else
{
mKeepBaseUnitCheckBox->setChecked( false );
}
mPlanimetricMeasurementsComboBox->setChecked( mSettings->value( QStringLiteral( "measure/planimetric" ), false, QgsSettings::Core ).toBool() );
cmbIconSize->setCurrentIndex( cmbIconSize->findText( mSettings->value( QStringLiteral( "qgis/iconSize" ), QGIS_ICON_SIZE ).toString() ) );
// set font size and family
spinFontSize->blockSignals( true );
mFontFamilyRadioQt->blockSignals( true );
mFontFamilyRadioCustom->blockSignals( true );
mFontFamilyComboBox->blockSignals( true );
spinFontSize->setValue( mStyleSheetOldOpts.value( QStringLiteral( "fontPointSize" ) ).toInt() );
QString fontFamily = mStyleSheetOldOpts.value( QStringLiteral( "fontFamily" ) ).toString();
bool isQtDefault = ( fontFamily == mStyleSheetBuilder->defaultFont().family() );
mFontFamilyRadioQt->setChecked( isQtDefault );
mFontFamilyRadioCustom->setChecked( !isQtDefault );
mFontFamilyComboBox->setEnabled( !isQtDefault );
if ( !isQtDefault )
{
QFont *tempFont = new QFont( fontFamily );
// is exact family match returned from system?
if ( tempFont->family() == fontFamily )
{
mFontFamilyComboBox->setCurrentFont( *tempFont );
}
delete tempFont;
}
spinFontSize->blockSignals( false );
mFontFamilyRadioQt->blockSignals( false );
mFontFamilyRadioCustom->blockSignals( false );
mFontFamilyComboBox->blockSignals( false );
mMessageTimeoutSpnBx->setValue( mSettings->value( QStringLiteral( "/qgis/messageTimeout" ), 5 ).toInt() );
mMessageTimeoutSpnBx->setClearValue( 5 );
QString name = mSettings->value( QStringLiteral( "/qgis/style" ) ).toString();
whileBlocking( cmbStyle )->setCurrentIndex( cmbStyle->findText( name, Qt::MatchFixedString ) );
QString theme = mSettings->value( QStringLiteral( "UI/UITheme" ), QStringLiteral( "default" ) ).toString();
if ( !QgsApplication::uiThemes().contains( theme ) )
{
theme = QStringLiteral( "default" );
}
whileBlocking( cmbUITheme )->setCurrentIndex( cmbUITheme->findText( theme, Qt::MatchFixedString ) );
mNativeColorDialogsChkBx->setChecked( mSettings->value( QStringLiteral( "/qgis/native_color_dialogs" ), false ).toBool() );
cbxLegendClassifiers->setChecked( mSettings->value( QStringLiteral( "/qgis/showLegendClassifiers" ), false ).toBool() );
mShowFeatureCountByDefaultCheckBox->setChecked( QgsSettingsRegistryCore::settingsLayerTreeShowFeatureCountForNewLayers->value() );
cbxHideSplash->setChecked( mSettings->value( QStringLiteral( "/qgis/hideSplash" ), false ).toBool() );
cbxShowNews->setChecked( !mSettings->value( QStringLiteral( "%1/disabled" ).arg( QgsNewsFeedParser::keyForFeed( QgsWelcomePage::newsFeedUrl() ) ), false, QgsSettings::Core ).toBool() );
cbxCheckVersion->setChecked( mSettings->value( QStringLiteral( "/qgis/checkVersion" ), true ).toBool() );
cbxCheckVersion->setVisible( mSettings->value( QStringLiteral( "/qgis/allowVersionCheck" ), true ).toBool() );
cbxAttributeTableDocked->setChecked( mSettings->value( QStringLiteral( "/qgis/dockAttributeTable" ), false ).toBool() );
mComboCopyFeatureFormat->addItem( tr( "Plain Text, No Geometry" ), QgsClipboard::AttributesOnly );
mComboCopyFeatureFormat->addItem( tr( "Plain Text, WKT Geometry" ), QgsClipboard::AttributesWithWKT );
mComboCopyFeatureFormat->addItem( tr( "GeoJSON" ), QgsClipboard::GeoJSON );
mComboCopyFeatureFormat->setCurrentIndex( mComboCopyFeatureFormat->findData( mSettings->enumValue( QStringLiteral( "/qgis/copyFeatureFormat" ), QgsClipboard::AttributesWithWKT ) ) );
leNullValue->setText( QgsApplication::nullRepresentation() );
cmbLegendDoubleClickAction->setCurrentIndex( mSettings->value( QStringLiteral( "/qgis/legendDoubleClickAction" ), 0 ).toInt() );
mLayerTreeInsertionMethod->addItem( tr( "Above currently selected layer" ), QVariant::fromValue( Qgis::LayerTreeInsertionMethod::AboveInsertionPoint ) );
mLayerTreeInsertionMethod->addItem( tr( "Always on top of the layer tree" ), QVariant::fromValue( Qgis::LayerTreeInsertionMethod::TopOfTree ) );
mLayerTreeInsertionMethod->addItem( tr( "Optimal index within current layer tree group" ), QVariant::fromValue( Qgis::LayerTreeInsertionMethod::OptimalInInsertionGroup ) );
mLayerTreeInsertionMethod->setCurrentIndex( mLayerTreeInsertionMethod->findData( QVariant::fromValue( mSettings->enumValue( QStringLiteral( "/qgis/layerTreeInsertionMethod" ), Qgis::LayerTreeInsertionMethod::AboveInsertionPoint ) ) ) );
// Legend symbol minimum / maximum values
mLegendSymbolMinimumSizeSpinBox->setClearValue( 0.0, tr( "none" ) );
mLegendSymbolMaximumSizeSpinBox->setClearValue( 0.0, tr( "none" ) );
mLegendSymbolMinimumSizeSpinBox->setValue( mSettings->value( QStringLiteral( "/qgis/legendsymbolMinimumSize" ), 0.1 ).toDouble() );
mLegendSymbolMaximumSizeSpinBox->setValue( mSettings->value( QStringLiteral( "/qgis/legendsymbolMaximumSize" ), 20.0 ).toDouble() );
// WMS getLegendGraphic setting
mLegendGraphicResolutionSpinBox->setValue( mSettings->value( QStringLiteral( "/qgis/defaultLegendGraphicResolution" ), 0 ).toInt() );
// Map Tips delay
mMapTipsDelaySpinBox->setValue( mSettings->value( QStringLiteral( "qgis/mapTipsDelay" ), 850 ).toInt() );
mMapTipsDelaySpinBox->setClearValue( 850 );
mRespectScreenDpiCheckBox->setChecked( QgsSettingsRegistryGui::settingsRespectScreenDPI->value() );
//set the color for selections
int red = mSettings->value( QStringLiteral( "/qgis/default_selection_color_red" ), 255 ).toInt();
int green = mSettings->value( QStringLiteral( "/qgis/default_selection_color_green" ), 255 ).toInt();
int blue = mSettings->value( QStringLiteral( "/qgis/default_selection_color_blue" ), 0 ).toInt();
int alpha = mSettings->value( QStringLiteral( "/qgis/default_selection_color_alpha" ), 255 ).toInt();
pbnSelectionColor->setColor( QColor( red, green, blue, alpha ) );
pbnSelectionColor->setColorDialogTitle( tr( "Set Selection Color" ) );
pbnSelectionColor->setAllowOpacity( true );
pbnSelectionColor->setContext( QStringLiteral( "gui" ) );
pbnSelectionColor->setDefaultColor( QColor( 255, 255, 0, 255 ) );
//set the default color for canvas background
red = mSettings->value( QStringLiteral( "/qgis/default_canvas_color_red" ), 255 ).toInt();
green = mSettings->value( QStringLiteral( "/qgis/default_canvas_color_green" ), 255 ).toInt();
blue = mSettings->value( QStringLiteral( "/qgis/default_canvas_color_blue" ), 255 ).toInt();
pbnCanvasColor->setColor( QColor( red, green, blue ) );
pbnCanvasColor->setColorDialogTitle( tr( "Set Canvas Color" ) );
pbnCanvasColor->setContext( QStringLiteral( "gui" ) );
pbnCanvasColor->setDefaultColor( Qt::white );
// set the default color for the measure tool
red = mSettings->value( QStringLiteral( "/qgis/default_measure_color_red" ), 222 ).toInt();
green = mSettings->value( QStringLiteral( "/qgis/default_measure_color_green" ), 155 ).toInt();
blue = mSettings->value( QStringLiteral( "/qgis/default_measure_color_blue" ), 67 ).toInt();
pbnMeasureColor->setColor( QColor( red, green, blue ) );
pbnMeasureColor->setColorDialogTitle( tr( "Set Measuring Tool Color" ) );
pbnMeasureColor->setContext( QStringLiteral( "gui" ) );
pbnMeasureColor->setDefaultColor( QColor( 222, 155, 67 ) );
int projOpen = mSettings->value( QStringLiteral( "/qgis/projOpenAtLaunch" ), 0 ).toInt();
mProjectOnLaunchCmbBx->setCurrentIndex( projOpen );
mProjectOnLaunchLineEdit->setText( mSettings->value( QStringLiteral( "/qgis/projOpenAtLaunchPath" ) ).toString() );
mProjectOnLaunchLineEdit->setEnabled( projOpen == 2 );
mProjectOnLaunchPushBtn->setEnabled( projOpen == 2 );
connect( mProjectOnLaunchPushBtn, &QAbstractButton::pressed, this, &QgsOptions::selectProjectOnLaunch );
chbAskToSaveProjectChanges->setChecked( mSettings->value( QStringLiteral( "qgis/askToSaveProjectChanges" ), QVariant( true ) ).toBool() );
mLayerDeleteConfirmationChkBx->setChecked( mSettings->value( QStringLiteral( "qgis/askToDeleteLayers" ), true ).toBool() );
chbWarnOldProjectVersion->setChecked( mSettings->value( QStringLiteral( "/qgis/warnOldProjectVersion" ), QVariant( true ) ).toBool() );
Qgis::PythonMacroMode pyMacroMode = mSettings->enumValue( QStringLiteral( "/qgis/enableMacros" ), Qgis::PythonMacroMode::Ask );
mEnableMacrosComboBox->setCurrentIndex( mEnableMacrosComboBox->findData( QVariant::fromValue( pyMacroMode ) ) );
mDefaultPathsComboBox->addItem( tr( "Absolute" ), static_cast< int >( Qgis::FilePathType::Absolute ) );
mDefaultPathsComboBox->addItem( tr( "Relative" ), static_cast< int >( Qgis::FilePathType::Relative ) );
mDefaultPathsComboBox->setCurrentIndex(
mDefaultPathsComboBox->findData(
static_cast< int >(
mSettings->value( QStringLiteral( "/qgis/defaultProjectPathsRelative" ), QVariant( true ) ).toBool() ? Qgis::FilePathType::Relative : Qgis::FilePathType::Absolute )
)
);
Qgis::ProjectFileFormat defaultProjectFileFormat = mSettings->enumValue( QStringLiteral( "/qgis/defaultProjectFileFormat" ), Qgis::ProjectFileFormat::Qgz );
mFileFormatQgzButton->setChecked( defaultProjectFileFormat == Qgis::ProjectFileFormat::Qgz );
mFileFormatQgsButton->setChecked( defaultProjectFileFormat == Qgis::ProjectFileFormat::Qgs );
// templates
cbxProjectDefaultNew->setChecked( mSettings->value( QStringLiteral( "/qgis/newProjectDefault" ), QVariant( false ) ).toBool() );
QString templateDirName = mSettings->value( QStringLiteral( "/qgis/projectTemplateDir" ),
QString( QgsApplication::qgisSettingsDirPath() + "project_templates" ) ).toString();
// make dir if it doesn't exist - should just be called once
QDir templateDir;
if ( ! templateDir.exists( templateDirName ) )
{
templateDir.mkdir( templateDirName );
}
leTemplateFolder->setText( templateDirName );
connect( pbnProjectDefaultSetCurrent, &QAbstractButton::clicked, this, &QgsOptions::setCurrentProjectDefault );
connect( pbnProjectDefaultReset, &QAbstractButton::clicked, this, &QgsOptions::resetProjectDefault );
connect( pbnTemplateFolderBrowse, &QAbstractButton::pressed, this, &QgsOptions::browseTemplateFolder );
connect( pbnTemplateFolderReset, &QAbstractButton::pressed, this, &QgsOptions::resetTemplateFolder );
setZoomFactorValue();
spinZoomFactor->setClearValue( 200 );
reverseWheelZoom->setChecked( mSettings->value( QStringLiteral( "/qgis/reverse_wheel_zoom" ), false ).toBool() );
// predefined scales for scale combobox
const QStringList scalePaths = QgsSettingsRegistryCore::settingsMapScales->value();
for ( const QString &scale : scalePaths )
{
addScaleToScaleList( scale );
}
connect( mListGlobalScales, &QListWidget::itemChanged, this, &QgsOptions::scaleItemChanged );
connect( pbnAddScale, &QAbstractButton::clicked, this, &QgsOptions::addScale );
connect( pbnRemoveScale, &QAbstractButton::clicked, this, &QgsOptions::removeScale );
connect( pbnExportScales, &QAbstractButton::clicked, this, &QgsOptions::exportScales );
connect( pbnImportScales, &QAbstractButton::clicked, this, &QgsOptions::importScales );
connect( pbnDefaultScaleValues, &QAbstractButton::clicked, this, &QgsOptions::restoreDefaultScaleValues );
//
// Color palette
//
connect( mButtonAddColor, &QAbstractButton::clicked, this, &QgsOptions::addColor );
connect( mButtonRemoveColor, &QAbstractButton::clicked, mTreeCustomColors, &QgsColorSchemeList::removeSelection );
connect( mButtonCopyColors, &QAbstractButton::clicked, mTreeCustomColors, &QgsColorSchemeList::copyColors );
connect( mButtonPasteColors, &QAbstractButton::clicked, mTreeCustomColors, &QgsColorSchemeList::pasteColors );
connect( mButtonImportColors, &QAbstractButton::clicked, mTreeCustomColors, &QgsColorSchemeList::showImportColorsDialog );
connect( mButtonExportColors, &QAbstractButton::clicked, mTreeCustomColors, &QgsColorSchemeList::showExportColorsDialog );
connect( mActionImportPalette, &QAction::triggered, this, [ = ]
{
if ( QgsCompoundColorWidget::importUserPaletteFromFile( this ) )
{
//refresh combobox
refreshSchemeComboBox();
mColorSchemesComboBox->setCurrentIndex( mColorSchemesComboBox->count() - 1 );
}
} );
connect( mActionRemovePalette, &QAction::triggered, this, [ = ]
{
//get current scheme
QList<QgsColorScheme *> schemeList = QgsApplication::colorSchemeRegistry()->schemes();
int prevIndex = mColorSchemesComboBox->currentIndex();
if ( prevIndex >= schemeList.length() )
{
return;
}
//make user scheme is a user removable scheme
QgsUserColorScheme *userScheme = dynamic_cast<QgsUserColorScheme *>( schemeList.at( prevIndex ) );
if ( !userScheme )
{
return;
}
if ( QgsCompoundColorWidget::removeUserPalette( userScheme, this ) )
{
refreshSchemeComboBox();
prevIndex = std::max( std::min( prevIndex, mColorSchemesComboBox->count() - 1 ), 0 );
mColorSchemesComboBox->setCurrentIndex( prevIndex );
}
} );
connect( mActionNewPalette, &QAction::triggered, this, [ = ]
{
if ( QgsCompoundColorWidget::createNewUserPalette( this ) )
{
//refresh combobox
refreshSchemeComboBox();
mColorSchemesComboBox->setCurrentIndex( mColorSchemesComboBox->count() - 1 );
}
} );
connect( mActionShowInButtons, &QAction::toggled, this, [ = ]( bool state )
{
QgsUserColorScheme *scheme = dynamic_cast< QgsUserColorScheme * >( mTreeCustomColors->scheme() );
if ( scheme )
{
scheme->setShowSchemeInMenu( state );
}
} );
QMenu *schemeMenu = new QMenu( mSchemeToolButton );
schemeMenu->addAction( mActionNewPalette );
schemeMenu->addAction( mActionImportPalette );
schemeMenu->addAction( mActionRemovePalette );
schemeMenu->addSeparator();
schemeMenu->addAction( mActionShowInButtons );
mSchemeToolButton->setMenu( schemeMenu );
//find custom color scheme from registry
refreshSchemeComboBox();
QList<QgsCustomColorScheme *> customSchemes;
QgsApplication::colorSchemeRegistry()->schemes( customSchemes );
if ( customSchemes.length() > 0 )
{
mTreeCustomColors->setScheme( customSchemes.at( 0 ) );
mColorSchemesComboBox->setCurrentIndex( mColorSchemesComboBox->findText( customSchemes.at( 0 )->schemeName() ) );
updateActionsForCurrentColorScheme( customSchemes.at( 0 ) );
}
connect( mColorSchemesComboBox, static_cast<void ( QComboBox::* )( int )>( &QComboBox::currentIndexChanged ), this, [ = ]( int index )
{
//save changes to scheme
if ( mTreeCustomColors->isDirty() )
{
mTreeCustomColors->saveColorsToScheme();
}
QgsColorScheme *scheme = QgsApplication::colorSchemeRegistry()->schemes().value( index );
if ( scheme )
{
mTreeCustomColors->setScheme( scheme );
updateActionsForCurrentColorScheme( scheme );
}
} );
//
// Layout settings
//
//default layout font
mComposerFontComboBox->blockSignals( true );
QString layoutFontFamily = mSettings->value( QStringLiteral( "LayoutDesigner/defaultFont" ), QVariant(), QgsSettings::Gui ).toString();
QFont tempLayoutFont( layoutFontFamily );
// is exact family match returned from system?
if ( tempLayoutFont.family() == layoutFontFamily )
{
mComposerFontComboBox->setCurrentFont( tempLayoutFont );
}
mComposerFontComboBox->blockSignals( false );
//default layout grid color
int gridRed, gridGreen, gridBlue, gridAlpha;
gridRed = mSettings->value( QStringLiteral( "LayoutDesigner/gridRed" ), 190, QgsSettings::Gui ).toInt();
gridGreen = mSettings->value( QStringLiteral( "LayoutDesigner/gridGreen" ), 190, QgsSettings::Gui ).toInt();
gridBlue = mSettings->value( QStringLiteral( "LayoutDesigner/gridBlue" ), 190, QgsSettings::Gui ).toInt();
gridAlpha = mSettings->value( QStringLiteral( "LayoutDesigner/gridAlpha" ), 100, QgsSettings::Gui ).toInt();
QColor gridColor = QColor( gridRed, gridGreen, gridBlue, gridAlpha );
mGridColorButton->setColor( gridColor );
mGridColorButton->setColorDialogTitle( tr( "Select Grid Color" ) );
mGridColorButton->setAllowOpacity( true );
mGridColorButton->setContext( QStringLiteral( "gui" ) );
mGridColorButton->setDefaultColor( QColor( 190, 190, 190, 100 ) );
//default layout grid style
QString gridStyleString;
gridStyleString = mSettings->value( QStringLiteral( "LayoutDesigner/gridStyle" ), "Dots", QgsSettings::Gui ).toString();
mGridStyleComboBox->insertItem( 0, tr( "Solid" ) );
mGridStyleComboBox->insertItem( 1, tr( "Dots" ) );
mGridStyleComboBox->insertItem( 2, tr( "Crosses" ) );
if ( gridStyleString == QLatin1String( "Solid" ) )
{
mGridStyleComboBox->setCurrentIndex( 0 );
}
else if ( gridStyleString == QLatin1String( "Crosses" ) )
{
mGridStyleComboBox->setCurrentIndex( 2 );
}
else
{
//default grid is dots
mGridStyleComboBox->setCurrentIndex( 1 );
}
//grid and guide defaults
mGridResolutionSpinBox->setValue( mSettings->value( QStringLiteral( "LayoutDesigner/defaultSnapGridResolution" ), 10.0, QgsSettings::Gui ).toDouble() );
mGridResolutionSpinBox->setClearValue( 10.0 );
mSnapToleranceSpinBox->setValue( mSettings->value( QStringLiteral( "LayoutDesigner/defaultSnapTolerancePixels" ), 5, QgsSettings::Gui ).toInt() );
mSnapToleranceSpinBox->setClearValue( 5 );
mOffsetXSpinBox->setValue( mSettings->value( QStringLiteral( "LayoutDesigner/defaultSnapGridOffsetX" ), 0, QgsSettings::Gui ).toDouble() );
mOffsetYSpinBox->setValue( mSettings->value( QStringLiteral( "LayoutDesigner/defaultSnapGridOffsetY" ), 0, QgsSettings::Gui ).toDouble() );
//
// Translation and locale settings
//
QString currentLocale = QLocale().name();
lblSystemLocale->setText( tr( "Detected active locale on your system: %1" ).arg( currentLocale ) );
QString userLocale = QgsApplication::settingsLocaleUserLocale->value();
bool showGroupSeparator = QgsApplication::settingsLocaleShowGroupSeparator->value();
QString globalLocale = QgsApplication::settingsLocaleGlobalLocale->value();
const QStringList language18nList( i18nList() );
for ( const auto &l : language18nList )
{
// QTBUG-57802: eo locale is improperly handled
QString displayName = l.startsWith( QLatin1String( "eo" ) ) ? QLocale::languageToString( QLocale::Esperanto ) : l.startsWith( QLatin1String( "sc" ) ) ? QStringLiteral( "sardu" ) : QLocale( l ).nativeLanguageName();
cboTranslation->addItem( QIcon( QString( ":/images/flags/%1.svg" ).arg( l ) ), displayName, l );
}
const QList<QLocale> allLocales = QLocale::matchingLocales(
QLocale::AnyLanguage,
QLocale::AnyScript,
QLocale::AnyCountry );
QSet<QString> addedLocales;
for ( const auto &l : allLocales )
{
// Do not add duplicates (like en_US)
if ( ! addedLocales.contains( l.name() ) )
{
cboGlobalLocale->addItem( QStringLiteral( "%1 %2 (%3)" ).arg( QLocale::languageToString( l.language() ), QLocale::countryToString( l.country() ), l.name() ), l.name() );
addedLocales.insert( l.name() );
}
}
cboTranslation->setCurrentIndex( cboTranslation->findData( userLocale ) );
cboGlobalLocale->setCurrentIndex( cboGlobalLocale->findData( globalLocale ) );
grpLocale->setChecked( QgsApplication::settingsLocaleOverrideFlag->value() );
cbShowGroupSeparator->setChecked( showGroupSeparator );
//set elements in digitizing tab
mLineWidthSpinBox->setValue( QgsSettingsRegistryCore::settingsDigitizingLineWidth->value() );
mLineColorToolButton->setColor( QgsSettingsRegistryCore::settingsDigitizingLineColor->value() );
mLineColorToolButton->setAllowOpacity( true );
mLineColorToolButton->setContext( QStringLiteral( "gui" ) );
mLineColorToolButton->setDefaultColor( QColor( 255, 0, 0, 200 ) );
mFillColorToolButton->setColor( QgsSettingsRegistryCore::settingsDigitizingFillColor->value() );
mFillColorToolButton->setAllowOpacity( true );
mFillColorToolButton->setContext( QStringLiteral( "gui" ) );
mFillColorToolButton->setDefaultColor( QColor( 255, 0, 0, 30 ) );
mLineGhostCheckBox->setChecked( QgsSettingsRegistryCore::settingsDigitizingLineGhost->value() );
mDefaultZValueSpinBox->setValue( QgsSettingsRegistryCore::settingsDigitizingDefaultZValue->value() );
mDefaultZValueSpinBox->setClearValue( QgsSettingsRegistryCore::settingsDigitizingDefaultZValue->defaultValue() );
mDefaultMValueSpinBox->setValue( QgsSettingsRegistryCore::settingsDigitizingDefaultMValue->value() );
mDefaultMValueSpinBox->setClearValue( Qgis::DEFAULT_M_COORDINATE );
//default snap mode
mSnappingEnabledDefault->setChecked( QgsSettingsRegistryCore::settingsDigitizingDefaultSnapEnabled->value() );
for ( Qgis::SnappingType type : qgsEnumList<Qgis::SnappingType>() )
{
mDefaultSnapTypeComboBox->addItem( QgsSnappingConfig::snappingTypeToIcon( type ),
QgsSnappingConfig::snappingTypeToString( type ),
QVariant::fromValue( type ) );
}
Qgis::SnappingTypes defaultSnapType = QgsSettingsRegistryCore::settingsDigitizingDefaultSnapType->value();
mDefaultSnapTypeComboBox->setCurrentIndex( mDefaultSnapTypeComboBox->findData( static_cast<int>( defaultSnapType ) ) );
mDefaultSnappingToleranceSpinBox->setValue( QgsSettingsRegistryCore::settingsDigitizingDefaultSnappingTolerance->value() );
mDefaultSnappingToleranceSpinBox->setClearValue( QgsSettingsRegistryCore::settingsDigitizingDefaultSnappingTolerance->defaultValue() );
mSearchRadiusVertexEditSpinBox->setValue( QgsSettingsRegistryCore::settingsDigitizingSearchRadiusVertexEdit->value() );
mSearchRadiusVertexEditSpinBox->setClearValue( QgsSettingsRegistryCore::settingsDigitizingSearchRadiusVertexEdit->defaultValue() );
QgsTolerance::UnitType defSnapUnits = QgsSettingsRegistryCore::settingsDigitizingDefaultSnappingToleranceUnit->value();
if ( defSnapUnits == QgsTolerance::ProjectUnits || defSnapUnits == QgsTolerance::LayerUnits )
{
index = mDefaultSnappingToleranceComboBox->findText( tr( "map units" ) );
}
else
{
index = mDefaultSnappingToleranceComboBox->findText( tr( "pixels" ) );
}
mDefaultSnappingToleranceComboBox->setCurrentIndex( index );
QgsTolerance::UnitType defRadiusUnits = QgsSettingsRegistryCore::settingsDigitizingSearchRadiusVertexEditUnit->value();
if ( defRadiusUnits == QgsTolerance::ProjectUnits || defRadiusUnits == QgsTolerance::LayerUnits )
{
index = mSearchRadiusVertexEditComboBox->findText( tr( "map units" ) );
}
else
{
index = mSearchRadiusVertexEditComboBox->findText( tr( "pixels" ) );
}
mSearchRadiusVertexEditComboBox->setCurrentIndex( index );
mSnappingMarkerColorButton->setColor( QgsSettingsRegistryCore::settingsDigitizingSnapColor->value() );
mSnappingTooltipsCheckbox->setChecked( QgsSettingsRegistryCore::settingsDigitizingSnapTooltip->value() );
mEnableSnappingOnInvisibleFeatureCheckbox->setChecked( QgsSettingsRegistryCore::settingsDigitizingSnapInvisibleFeature->value() );
//vertex marker
mMarkersOnlyForSelectedCheckBox->setChecked( QgsSettingsRegistryCore::settingsDigitizingMarkerOnlyForSelected->value() );
mMarkerStyleComboBox->addItem( tr( "Semi Transparent Circle" ) );
mMarkerStyleComboBox->addItem( tr( "Cross" ) );
mMarkerStyleComboBox->addItem( tr( "None" ) );
mValidateGeometries->clear();
mValidateGeometries->addItem( tr( "Off" ) );
mValidateGeometries->addItem( tr( "QGIS" ) );
mValidateGeometries->addItem( tr( "GEOS" ) );
QString markerStyle = QgsSettingsRegistryCore::settingsDigitizingMarkerStyle->value();
if ( markerStyle == QLatin1String( "SemiTransparentCircle" ) )
{
mMarkerStyleComboBox->setCurrentIndex( mMarkerStyleComboBox->findText( tr( "Semi Transparent Circle" ) ) );
}
else if ( markerStyle == QLatin1String( "Cross" ) )
{
mMarkerStyleComboBox->setCurrentIndex( mMarkerStyleComboBox->findText( tr( "Cross" ) ) );
}
else if ( markerStyle == QLatin1String( "None" ) )
{
mMarkerStyleComboBox->setCurrentIndex( mMarkerStyleComboBox->findText( tr( "None" ) ) );
}
mMarkerSizeSpinBox->setValue( QgsSettingsRegistryCore::settingsDigitizingMarkerSizeMm->value() );
mMarkerSizeSpinBox->setClearValue( QgsSettingsRegistryCore::settingsDigitizingMarkerSizeMm->defaultValue() );
chkReuseLastValues->setChecked( QgsSettingsRegistryCore::settingsDigitizingReuseLastValues->value() );
chkDisableAttributeValuesDlg->setChecked( QgsSettingsRegistryCore::settingsDigitizingDisableEnterAttributeValuesDialog->value() );
mValidateGeometries->setCurrentIndex( QgsSettingsRegistryCore::settingsDigitizingValidateGeometries->value() );
mSnappingMainDialogComboBox->clear();
mSnappingMainDialogComboBox->addItem( tr( "Dialog" ), "dialog" );
mSnappingMainDialogComboBox->addItem( tr( "Dock" ), "dock" );
mSnappingMainDialogComboBox->setCurrentIndex( mSnappingMainDialogComboBox->findData( mSettings->value( QStringLiteral( "/qgis/mainSnappingWidgetMode" ), "dialog" ).toString() ) );
mOffsetJoinStyleComboBox->addItem( tr( "Round" ), static_cast< int >( Qgis::JoinStyle::Round ) );
mOffsetJoinStyleComboBox->addItem( tr( "Miter" ), static_cast< int >( Qgis::JoinStyle::Miter ) );
mOffsetJoinStyleComboBox->addItem( tr( "Bevel" ), static_cast< int >( Qgis::JoinStyle::Bevel ) );
Qgis::JoinStyle joinStyleSetting = QgsSettingsRegistryCore::settingsDigitizingOffsetJoinStyle->value();
mOffsetJoinStyleComboBox->setCurrentIndex( mOffsetJoinStyleComboBox->findData( static_cast< int >( joinStyleSetting ) ) );
mOffsetQuadSegSpinBox->setValue( QgsSettingsRegistryCore::settingsDigitizingOffsetQuadSeg->value() );
mOffsetQuadSegSpinBox->setClearValue( QgsSettingsRegistryCore::settingsDigitizingOffsetQuadSeg->defaultValue() );
mCurveOffsetMiterLimitComboBox->setValue( QgsSettingsRegistryCore::settingsDigitizingOffsetMiterLimit->value() );
mCurveOffsetMiterLimitComboBox->setClearValue( QgsSettingsRegistryCore::settingsDigitizingOffsetMiterLimit->defaultValue() );
mTracingConvertToCurveCheckBox->setChecked( QgsSettingsRegistryCore::settingsDigitizingConvertToCurve->value() );
mTracingCustomAngleToleranceSpinBox->setValue( QgsSettingsRegistryCore::settingsDigitizingConvertToCurveAngleTolerance->value() );
mTracingCustomAngleToleranceSpinBox->setClearValue( QgsSettingsRegistryCore::settingsDigitizingConvertToCurveAngleTolerance->defaultValue() );
mTracingCustomDistanceToleranceSpinBox->setValue( QgsSettingsRegistryCore::settingsDigitizingConvertToCurveDistanceTolerance->value() );
mTracingCustomDistanceToleranceSpinBox->setClearValue( QgsSettingsRegistryCore::settingsDigitizingConvertToCurveDistanceTolerance->defaultValue() );
// load gdal driver list only when gdal tab is first opened
mLoadedGdalDriverList = false;
mVariableEditor->context()->appendScope( QgsExpressionContextUtils::globalScope() );
mVariableEditor->reloadContext();
mVariableEditor->setEditableScopeIndex( 0 );
connect( mAddCustomVarBtn, &QAbstractButton::clicked, this, &QgsOptions::addCustomVariable );
connect( mRemoveCustomVarBtn, &QAbstractButton::clicked, this, &QgsOptions::removeCustomVariable );
// locator
mLocatorOptionsWidget = new QgsLocatorOptionsWidget( QgisApp::instance()->locatorWidget(), this );
QVBoxLayout *locatorLayout = new QVBoxLayout();
locatorLayout->addWidget( mLocatorOptionsWidget );
mOptionsLocatorGroupBox->setLayout( locatorLayout );
QList< QgsOptionsWidgetFactory *> factories = optionsFactories;
// ensure advanced factory is always last
QgsAdvancedSettingsOptionsFactory advancedFactory;
factories << &advancedFactory;
for ( QgsOptionsWidgetFactory *factory : std::as_const( factories ) )
{
QgsOptionsPageWidget *page = factory->createWidget( this );
if ( !page )
continue;
mAdditionalOptionWidgets << page;
const QString beforePage = factory->pagePositionHint();
if ( beforePage.isEmpty() )
addPage( factory->title(), factory->title(), factory->icon(), page, factory->path(), factory->key() );
else
insertPage( factory->title(), factory->title(), factory->icon(), page, beforePage, factory->path(), factory->key() );
if ( QgsAdvancedSettingsWidget *advancedPage = qobject_cast< QgsAdvancedSettingsWidget * >( page ) )
{
advancedPage->settingsTree()->setSettingsObject( mSettings );
}
}
if ( mOptTreeView )
mOptTreeView->expandAll();
#ifdef HAVE_OPENCL
// Setup OpenCL Acceleration widget
connect( mGPUEnableCheckBox, &QCheckBox::toggled, this, [ = ]( bool checked )
{
if ( checked )
{
// Since this may crash and lock users out of the settings, let's disable opencl setting before entering
// and restore after available was successfully called
const bool openClStatus { QgsOpenClUtils::enabled() };
QgsOpenClUtils::setEnabled( false );
if ( QgsOpenClUtils::available( ) )
{
QgsOpenClUtils::setEnabled( openClStatus );
mOpenClContainerWidget->setEnabled( true );
mOpenClDevicesCombo->clear();
for ( const auto &dev : QgsOpenClUtils::devices( ) )
{
mOpenClDevicesCombo->addItem( QgsOpenClUtils::deviceInfo( QgsOpenClUtils::Info::Name, dev ), QgsOpenClUtils::deviceId( dev ) );
}
// Info updater
std::function<void( int )> infoUpdater = [ = ]( int )
{
mGPUInfoTextBrowser->setText( QgsOpenClUtils::deviceDescription( mOpenClDevicesCombo->currentData().toString() ) );
};
connect( mOpenClDevicesCombo, qOverload< int >( &QComboBox::currentIndexChanged ), infoUpdater );
mOpenClDevicesCombo->setCurrentIndex( mOpenClDevicesCombo->findData( QgsOpenClUtils::deviceId( QgsOpenClUtils::activeDevice() ) ) );
infoUpdater( -1 );
mOpenClContainerWidget->show();
}
else
{
mGPUInfoTextBrowser->setText( tr( "No OpenCL compatible devices were found on your system.<br>"
"You may need to install additional libraries in order to enable OpenCL.<br>"
"Please check your logs for further details." ) );
mOpenClContainerWidget->setEnabled( false );
mGPUEnableCheckBox->setChecked( false );
}
}
else
{
mOpenClContainerWidget->setEnabled( false );
}
} );
mOpenClContainerWidget->setEnabled( false );
mGPUEnableCheckBox->setChecked( QgsOpenClUtils::enabled( ) );
#else
mGPUEnableCheckBox->setChecked( false );
for ( int idx = 0; idx < mOptionsPageAccelerationLayout->count(); ++idx )
{
QWidget *item = mOptionsPageAccelerationLayout->itemAt( idx )->widget();
if ( item )
{
item->setEnabled( false );
}
}
QLabel *noOpenCL = new QLabel( tr( "QGIS is compiled without OpenCL support. "
"GPU acceleration is not available." ), this );
mOptionsPageAccelerationLayout->insertWidget( 0, noOpenCL );
#endif
connect( pbnEditCreateOptions, &QAbstractButton::pressed, this, &QgsOptions::editCreateOptions );
connect( pbnEditPyramidsOptions, &QAbstractButton::pressed, this, &QgsOptions::editPyramidsOptions );
// restore window and widget geometry/state
connect( mRestoreDefaultWindowStateBtn, &QAbstractButton::clicked, this, &QgsOptions::restoreDefaultWindowState );
mBearingFormat.reset( QgsLocalDefaultSettings::bearingFormat() );
mCoordinateFormat.reset( QgsLocalDefaultSettings::geographicCoordinateFormat() );
connect( mCustomizeBearingFormatButton, &QPushButton::clicked, this, &QgsOptions::customizeBearingFormat );
connect( mCustomizeCoordinateFormatButton, &QPushButton::clicked, this, &QgsOptions::customizeCoordinateFormat );
restoreOptionsBaseUi();
#ifdef QGISDEBUG
checkPageWidgetNameMap();
#endif
}
QgsOptions::~QgsOptions()
{
delete mSettings;
}
void QgsOptions::checkPageWidgetNameMap()
{
const QMap< QString, QString > pageNames = QgisApp::instance()->optionsPagesMap();
std::function<void( const QModelIndex & )> traverseModel;
// traverse through the model, collecting all entries which correspond to pages
QStringList pageTitles;
traverseModel = [&]( const QModelIndex & parent )
{
for ( int row = 0; row < mTreeModel->rowCount( parent ); ++row )
{
const QModelIndex currentIndex = mTreeModel->index( row, 0, parent );
if ( mTreeModel->itemFromIndex( currentIndex )->isSelectable() )
pageTitles << currentIndex.data().toString();
traverseModel( currentIndex );
}
};
traverseModel( QModelIndex() );
Q_ASSERT_X( pageNames.count() == pageTitles.count(), "QgsOptions::checkPageWidgetNameMap()",
QStringLiteral( "QgisApp::optionsPagesMap() is outdated, contains too many entries, "
" this is often a problem with missing translations for the entries (extra entries: %1)" ).arg(
qgsSetJoin( QSet( pageNames.keyBegin(), pageNames.keyEnd() ) - QSet( pageTitles.constBegin(), pageTitles.constEnd() ),
QStringLiteral( "," ) ) ).toLocal8Bit().constData() );
int page = 0;
for ( const QString &pageTitle : std::as_const( pageTitles ) )
{
QWidget *currentPage = mOptionsStackedWidget->widget( page );
Q_ASSERT_X( pageNames.contains( pageTitle ), "QgsOptions::checkPageWidgetNameMap()", QStringLiteral( "QgisApp::optionsPagesMap() is outdated, please update. Missing %1" ).arg( pageTitle ).toLocal8Bit().constData() );
Q_ASSERT_X( pageNames.value( pageTitle ) == currentPage->objectName() || pageNames.value( pageTitle ) == pageTitle, "QgsOptions::checkPageWidgetNameMap()", QStringLiteral( "QgisApp::optionsPagesMap() is outdated, please update. %1 should be %2 or %1 not %3" ).arg( pageTitle ).arg( currentPage->objectName() ).arg( pageNames.value( pageTitle ) ).toLocal8Bit().constData() );
page++;
}
}
void QgsOptions::setCurrentPage( const QString &pageWidgetName )
{
//find the page with a matching widget name
for ( int page = 0; page < mOptionsStackedWidget->count(); ++page )
{
QWidget *currentPage = mOptionsStackedWidget->widget( page );
if ( currentPage->objectName() == pageWidgetName )
{
//found the page, set it as current
mOptionsStackedWidget->setCurrentIndex( page );
return;
}
else if ( mTreeProxyModel )
{
const QModelIndex sourceIndex = mTreeProxyModel->pageNumberToSourceIndex( page );
if ( sourceIndex.data().toString() == pageWidgetName || sourceIndex.data( Qt::UserRole + 1 ).toString() == pageWidgetName )
{
mOptionsStackedWidget->setCurrentIndex( page );
return;
}
}
}
}
void QgsOptions::setCurrentPage( const int pageNumber )
{
if ( pageNumber >= 0 && pageNumber < mOptionsStackedWidget->count() )
mOptionsStackedWidget->setCurrentIndex( pageNumber );
}
void QgsOptions::mProxyTypeComboBox_currentIndexChanged( int idx )
{
frameManualProxy->setEnabled( idx != 0 );
}
void QgsOptions::cbxProjectDefaultNew_toggled( bool checked )
{
if ( checked )
{
QString fileName = QgsApplication::qgisSettingsDirPath() + QStringLiteral( "project_default.qgs" );
if ( ! QFile::exists( fileName ) )
{
QMessageBox::information( nullptr, tr( "Save Default Project" ), tr( "You must set a default project" ) );
cbxProjectDefaultNew->setChecked( false );
}
}
}
void QgsOptions::setCurrentProjectDefault()
{
QString fileName = QgsApplication::qgisSettingsDirPath() + QStringLiteral( "project_default.qgs" );
if ( QgsProject::instance()->write( fileName ) )
{
QMessageBox::information( nullptr, tr( "Save Default Project" ), tr( "Current project saved as default" ) );
}
else
{
QMessageBox::critical( nullptr, tr( "Save Default Project" ), tr( "Error saving current project as default" ) );
}
}
void QgsOptions::resetProjectDefault()
{
QString fileName = QgsApplication::qgisSettingsDirPath() + QStringLiteral( "project_default.qgs" );
if ( QFile::exists( fileName ) )
{
QFile::remove( fileName );
}
cbxProjectDefaultNew->setChecked( false );
}
void QgsOptions::browseTemplateFolder()
{
QString newDir = QFileDialog::getExistingDirectory( nullptr, tr( "Choose a directory to store project template files" ),
leTemplateFolder->text() );
if ( ! newDir.isNull() )
{
leTemplateFolder->setText( newDir );
}
}
void QgsOptions::resetTemplateFolder()
{
leTemplateFolder->setText( QgsApplication::qgisSettingsDirPath() + QStringLiteral( "project_templates" ) );
}
void QgsOptions::iconSizeChanged()
{
QgisApp::instance()->setIconSizes( cmbIconSize->currentText().toInt() );
}
void QgsOptions::uiThemeChanged( const QString &theme )
{
if ( theme == QgsApplication::themeName() )
return;
QgisApp::instance()->setTheme( theme );
}
void QgsOptions::mProjectOnLaunchCmbBx_currentIndexChanged( int indx )
{
bool specific = ( indx == 2 );
mProjectOnLaunchLineEdit->setEnabled( specific );
mProjectOnLaunchPushBtn->setEnabled( specific );
}
void QgsOptions::selectProjectOnLaunch()
{
// Retrieve last used project dir from persistent settings
QgsSettings settings;
QString lastUsedDir = mSettings->value( QStringLiteral( "/UI/lastProjectDir" ), QDir::homePath() ).toString();
QString projPath = QFileDialog::getOpenFileName( this,
tr( "Choose project file to open at launch" ),
lastUsedDir,
tr( "QGIS files" ) + " (*.qgs *.qgz *.QGS *.QGZ)" );
if ( !projPath.isNull() )
{
mProjectOnLaunchLineEdit->setText( projPath );
}
}
void QgsOptions::saveOptions()
{
for ( QgsOptionsPageWidget *widget : std::as_const( mAdditionalOptionWidgets ) )
{
if ( !widget->isValid() )
{
setCurrentPage( widget->objectName() );
return;
}
}
QgsSettings settings;
mSettings->setValue( QStringLiteral( "UI/UITheme" ), cmbUITheme->currentText() );
// custom environment variables
mSettings->setValue( QStringLiteral( "qgis/customEnvVarsUse" ), QVariant( mCustomVariablesChkBx->isChecked() ) );
QStringList customVars;
for ( int i = 0; i < mCustomVariablesTable->rowCount(); ++i )
{
if ( mCustomVariablesTable->item( i, 1 )->text().isEmpty() )
continue;
QComboBox *varApplyCmbBx = qobject_cast<QComboBox *>( mCustomVariablesTable->cellWidget( i, 0 ) );
QString customVar = varApplyCmbBx->currentData().toString();
customVar += '|';
customVar += mCustomVariablesTable->item( i, 1 )->text();
customVar += '=';
customVar += mCustomVariablesTable->item( i, 2 )->text();
customVars << customVar;
}
mSettings->setValue( QStringLiteral( "qgis/customEnvVars" ), QVariant( customVars ) );
//search directories for user plugins
QStringList pathsList;
for ( int i = 0; i < mListPluginPaths->count(); ++i )
{
pathsList << mListPluginPaths->item( i )->text();
}
mSettings->setValue( QStringLiteral( "plugins/searchPathsForPlugins" ), pathsList );
//search directories for svgs
pathsList.clear();
for ( int i = 0; i < mListSVGPaths->count(); ++i )
{
pathsList << mListSVGPaths->item( i )->text();
}
QgsApplication::setSvgPaths( pathsList );
pathsList.clear();
for ( int i = 0; i < mListComposerTemplatePaths->count(); ++i )
{
pathsList << mListComposerTemplatePaths->item( i )->text();
}
QgsLayout::settingsSearchPathForTemplates->setValue( pathsList );
pathsList.clear();
for ( int r = 0; r < mLocalizedDataPathListWidget->count(); r++ )
pathsList << mLocalizedDataPathListWidget->item( r )->text();
QgsApplication::localizedDataPathRegistry()->setPaths( pathsList );
pathsList.clear();
for ( int i = 0; i < mListHiddenBrowserPaths->count(); ++i )
{
pathsList << mListHiddenBrowserPaths->item( i )->text();
}
mSettings->setValue( QStringLiteral( "/browser/hiddenPaths" ), pathsList );
//QGIS help locations
QStringList helpPaths;
for ( int i = 0; i < mHelpPathTreeWidget->topLevelItemCount(); ++i )
{
if ( QTreeWidgetItem *item = mHelpPathTreeWidget->topLevelItem( i ) )
{
helpPaths << item->text( 0 );
}
}
mSettings->setValue( QStringLiteral( "help/helpSearchPath" ), helpPaths );
//Network timeout
QgsNetworkAccessManager::setTimeout( mNetworkTimeoutSpinBox->value() );
mSettings->setValue( QStringLiteral( "/qgis/networkAndProxy/userAgent" ), leUserAgent->text() );
// WMS capabiltiies expiry time
mSettings->setValue( QStringLiteral( "/qgis/defaultCapabilitiesExpiry" ), mDefaultCapabilitiesExpirySpinBox->value() );
// WMS/WMS-C tile expiry time
mSettings->setValue( QStringLiteral( "/qgis/defaultTileExpiry" ), mDefaultTileExpirySpinBox->value() );
// WMS/WMS-C default max retry in case of tile request errors
mSettings->setValue( QStringLiteral( "/qgis/defaultTileMaxRetry" ), mDefaultTileMaxRetrySpinBox->value() );
// Proxy stored authentication configurations
mSettings->setValue( QStringLiteral( "proxy/authcfg" ), mAuthSettings->configId( ) );
//Web proxy settings
mSettings->setValue( QStringLiteral( "proxy/proxyEnabled" ), grpProxy->isChecked() );
mSettings->setValue( QStringLiteral( "proxy/proxyHost" ), leProxyHost->text() );
mSettings->setValue( QStringLiteral( "proxy/proxyPort" ), leProxyPort->text() );
mSettings->setValue( QStringLiteral( "proxy/proxyUser" ), mAuthSettings->username() );
mSettings->setValue( QStringLiteral( "proxy/proxyPassword" ), mAuthSettings->password() );
mSettings->setValue( QStringLiteral( "proxy/proxyType" ), mProxyTypeComboBox->currentText() );
if ( !mCacheDirectory->text().isEmpty() )
mSettings->setValue( QStringLiteral( "cache/directory" ), mCacheDirectory->text() );
else
mSettings->remove( QStringLiteral( "cache/directory" ) );
mSettings->setValue( QStringLiteral( "cache/size" ), QVariant::fromValue( mCacheSize->value() * 1024L ) );
//url with no proxy at all
QStringList noProxyUrls;
noProxyUrls.reserve( mNoProxyUrlListWidget->count() );
for ( int i = 0; i < mNoProxyUrlListWidget->count(); ++i )
{
const QString host = mNoProxyUrlListWidget->item( i )->text();
if ( !host.trimmed().isEmpty() )
noProxyUrls << host;
}
mSettings->setValue( QStringLiteral( "proxy/noProxyUrls" ), noProxyUrls );
QgisApp::instance()->namUpdate();
//general settings
mSettings->setValue( QStringLiteral( "/Map/searchRadiusMM" ), spinBoxIdentifyValue->value() );
mSettings->setValue( QStringLiteral( "/Map/highlight/color" ), mIdentifyHighlightColorButton->color().name() );
mSettings->setValue( QStringLiteral( "/Map/highlight/colorAlpha" ), mIdentifyHighlightColorButton->color().alpha() );
mSettings->setValue( QStringLiteral( "/Map/highlight/buffer" ), mIdentifyHighlightBufferSpinBox->value() );
mSettings->setValue( QStringLiteral( "/Map/highlight/minWidth" ), mIdentifyHighlightMinWidthSpinBox->value() );
bool showLegendClassifiers = mSettings->value( QStringLiteral( "/qgis/showLegendClassifiers" ), false ).toBool();
mSettings->setValue( QStringLiteral( "/qgis/showLegendClassifiers" ), cbxLegendClassifiers->isChecked() );
QgsSettingsRegistryCore::settingsLayerTreeShowFeatureCountForNewLayers->setValue( mShowFeatureCountByDefaultCheckBox->isChecked() );
mSettings->setValue( QStringLiteral( "/qgis/hideSplash" ), cbxHideSplash->isChecked() );
mSettings->setValue( QStringLiteral( "%1/disabled" ).arg( QgsNewsFeedParser::keyForFeed( QgsWelcomePage::newsFeedUrl() ) ), !cbxShowNews->isChecked(), QgsSettings::Core );
mSettings->setValue( QStringLiteral( "/qgis/checkVersion" ), cbxCheckVersion->isChecked() );
mSettings->setValue( QStringLiteral( "/qgis/dockAttributeTable" ), cbxAttributeTableDocked->isChecked() );
mSettings->setEnumValue( QStringLiteral( "/qgis/attributeTableBehavior" ), ( QgsAttributeTableFilterModel::FilterMode )cmbAttrTableBehavior->currentData().toInt() );
mSettings->setValue( QStringLiteral( "/qgis/attributeTableView" ), mAttrTableViewComboBox->currentData() );
mSettings->setValue( QStringLiteral( "/qgis/attributeTableRowCache" ), spinBoxAttrTableRowCache->value() );
mSettings->setEnumValue( QStringLiteral( "/qgis/promptForSublayers" ), static_cast< Qgis::SublayerPromptMode >( cmbPromptSublayers->currentData().toInt() ) );
mSettings->setValue( QStringLiteral( "/qgis/scanItemsInBrowser2" ),
cmbScanItemsInBrowser->currentData().toString() );
mSettings->setValue( QStringLiteral( "/qgis/scanZipInBrowser2" ),
cmbScanZipInBrowser->currentData().toString() );
mSettings->setValue( QStringLiteral( "/qgis/monitorDirectoriesInBrowser" ), mCheckMonitorDirectories->isChecked() );
mSettings->setValue( QStringLiteral( "/qgis/mainSnappingWidgetMode" ), mSnappingMainDialogComboBox->currentData() );
mSettings->setValue( QStringLiteral( "/qgis/legendsymbolMinimumSize" ), mLegendSymbolMinimumSizeSpinBox->value() );
mSettings->setValue( QStringLiteral( "/qgis/legendsymbolMaximumSize" ), mLegendSymbolMaximumSizeSpinBox->value() );
QgsSymbolLegendNode::MINIMUM_SIZE = mLegendSymbolMinimumSizeSpinBox->value();
QgsSymbolLegendNode::MAXIMUM_SIZE = mLegendSymbolMaximumSizeSpinBox->value();
mSettings->setValue( QStringLiteral( "/qgis/defaultLegendGraphicResolution" ), mLegendGraphicResolutionSpinBox->value() );
mSettings->setValue( QStringLiteral( "/qgis/mapTipsDelay" ), mMapTipsDelaySpinBox->value() );
QgsSettingsRegistryGui::settingsRespectScreenDPI->setValue( mRespectScreenDpiCheckBox->isChecked() );
mSettings->setEnumValue( QStringLiteral( "/qgis/copyFeatureFormat" ), ( QgsClipboard::CopyFormat )mComboCopyFeatureFormat->currentData().toInt() );
QgisApp::instance()->setMapTipsDelay( mMapTipsDelaySpinBox->value() );
mSettings->setValue( QStringLiteral( "/qgis/legendDoubleClickAction" ), cmbLegendDoubleClickAction->currentIndex() );
mSettings->setEnumValue( QStringLiteral( "/qgis/layerTreeInsertionMethod" ), mLayerTreeInsertionMethod->currentData().value<Qgis::LayerTreeInsertionMethod>() );
// project
mSettings->setValue( QStringLiteral( "/qgis/projOpenAtLaunch" ), mProjectOnLaunchCmbBx->currentIndex() );
mSettings->setValue( QStringLiteral( "/qgis/projOpenAtLaunchPath" ), mProjectOnLaunchLineEdit->text() );
mSettings->setValue( QStringLiteral( "/qgis/askToSaveProjectChanges" ), chbAskToSaveProjectChanges->isChecked() );
mSettings->setValue( QStringLiteral( "qgis/askToDeleteLayers" ), mLayerDeleteConfirmationChkBx->isChecked() );
mSettings->setValue( QStringLiteral( "/qgis/warnOldProjectVersion" ), chbWarnOldProjectVersion->isChecked() );
if ( ( mSettings->value( QStringLiteral( "/qgis/projectTemplateDir" ) ).toString() != leTemplateFolder->text() ) ||
( mSettings->value( QStringLiteral( "/qgis/newProjectDefault" ) ).toBool() != cbxProjectDefaultNew->isChecked() ) )
{
mSettings->setValue( QStringLiteral( "/qgis/newProjectDefault" ), cbxProjectDefaultNew->isChecked() );
mSettings->setValue( QStringLiteral( "/qgis/projectTemplateDir" ), leTemplateFolder->text() );
QgisApp::instance()->updateProjectFromTemplates();
}
mSettings->setEnumValue( QStringLiteral( "/qgis/enableMacros" ), mEnableMacrosComboBox->currentData().value<Qgis::PythonMacroMode>() );
mSettings->setValue( QStringLiteral( "/qgis/defaultProjectPathsRelative" ),
static_cast< Qgis::FilePathType >( mDefaultPathsComboBox->currentData().toInt() ) == Qgis::FilePathType::Relative );
mSettings->setEnumValue( QStringLiteral( "/qgis/defaultProjectFileFormat" ), mFileFormatQgsButton->isChecked() ? Qgis::ProjectFileFormat::Qgs : Qgis::ProjectFileFormat::Qgz );
QgsApplication::setNullRepresentation( leNullValue->text() );
mSettings->setValue( QStringLiteral( "/qgis/style" ), cmbStyle->currentText() );
mSettings->setValue( QStringLiteral( "/qgis/iconSize" ), cmbIconSize->currentText() );
mSettings->setValue( QStringLiteral( "/qgis/messageTimeout" ), mMessageTimeoutSpnBx->value() );
mSettings->setValue( QStringLiteral( "/qgis/native_color_dialogs" ), mNativeColorDialogsChkBx->isChecked() );
//check behavior so default projection when new layer is added with no
//projection defined...
if ( radPromptForProjection->isChecked() )
{
mSettings->setEnumValue( QStringLiteral( "/projections/unknownCrsBehavior" ), QgsOptions::UnknownLayerCrsBehavior::PromptUserForCrs, QgsSettings::App );
}
else if ( radUseProjectProjection->isChecked() )
{
mSettings->setEnumValue( QStringLiteral( "/projections/unknownCrsBehavior" ), QgsOptions::UnknownLayerCrsBehavior::UseProjectCrs, QgsSettings::App );
}
else if ( radCrsNoAction->isChecked() )
{
mSettings->setEnumValue( QStringLiteral( "/projections/unknownCrsBehavior" ), QgsOptions::UnknownLayerCrsBehavior::NoAction, QgsSettings::App );
}
else
{
mSettings->setEnumValue( QStringLiteral( "/projections/unknownCrsBehavior" ), QgsOptions::UnknownLayerCrsBehavior::UseDefaultCrs, QgsSettings::App );
}
mSettings->setValue( QStringLiteral( "/Projections/layerDefaultCrs" ), mLayerDefaultCrs.authid() );
mSettings->setValue( QStringLiteral( "/projections/defaultProjectCrs" ), leProjectGlobalCrs->crs().authid(), QgsSettings::App );
mSettings->setEnumValue( QStringLiteral( "/projections/newProjectCrsBehavior" ), radProjectUseCrsOfFirstLayer->isChecked() ? QgsGui::UseCrsOfFirstLayerAdded : QgsGui::UsePresetCrs, QgsSettings::App );
mSettings->setValue( QStringLiteral( "/projections/promptWhenMultipleTransformsExist" ), mShowDatumTransformDialogCheckBox->isChecked(), QgsSettings::App );
mSettings->setValue( QStringLiteral( "/projections/crsAccuracyWarningThreshold" ), mCrsAccuracySpin->value(), QgsSettings::App );
mSettings->setValue( QStringLiteral( "/projections/crsAccuracyIndicator" ), mCrsAccuracyIndicatorCheck->isChecked(), QgsSettings::App );
//measurement settings
mSettings->setValue( QStringLiteral( "measure/planimetric" ), mPlanimetricMeasurementsComboBox->isChecked(), QgsSettings::Core );
Qgis::DistanceUnit distanceUnit = static_cast< Qgis::DistanceUnit >( mDistanceUnitsComboBox->currentData().toInt() );
mSettings->setValue( QStringLiteral( "/qgis/measure/displayunits" ), QgsUnitTypes::encodeUnit( distanceUnit ) );
Qgis::AreaUnit areaUnit = static_cast< Qgis::AreaUnit >( mAreaUnitsComboBox->currentData().toInt() );
mSettings->setValue( QStringLiteral( "/qgis/measure/areaunits" ), QgsUnitTypes::encodeUnit( areaUnit ) );
Qgis::AngleUnit angleUnit = static_cast< Qgis::AngleUnit >( mAngleUnitsComboBox->currentData().toInt() );
mSettings->setValue( QStringLiteral( "/qgis/measure/angleunits" ), QgsUnitTypes::encodeUnit( angleUnit ) );
int decimalPlaces = mDecimalPlacesSpinBox->value();
mSettings->setValue( QStringLiteral( "/qgis/measure/decimalplaces" ), decimalPlaces );
bool baseUnit = mKeepBaseUnitCheckBox->isChecked();
mSettings->setValue( QStringLiteral( "/qgis/measure/keepbaseunit" ), baseUnit );
//set the color for selections
QColor myColor = pbnSelectionColor->color();
mSettings->setValue( QStringLiteral( "/qgis/default_selection_color_red" ), myColor.red() );
mSettings->setValue( QStringLiteral( "/qgis/default_selection_color_green" ), myColor.green() );
mSettings->setValue( QStringLiteral( "/qgis/default_selection_color_blue" ), myColor.blue() );
mSettings->setValue( QStringLiteral( "/qgis/default_selection_color_alpha" ), myColor.alpha() );
//set the default color for canvas background
myColor = pbnCanvasColor->color();
mSettings->setValue( QStringLiteral( "/qgis/default_canvas_color_red" ), myColor.red() );
mSettings->setValue( QStringLiteral( "/qgis/default_canvas_color_green" ), myColor.green() );
mSettings->setValue( QStringLiteral( "/qgis/default_canvas_color_blue" ), myColor.blue() );
//set the default color for the measure tool
myColor = pbnMeasureColor->color();
mSettings->setValue( QStringLiteral( "/qgis/default_measure_color_red" ), myColor.red() );
mSettings->setValue( QStringLiteral( "/qgis/default_measure_color_green" ), myColor.green() );
mSettings->setValue( QStringLiteral( "/qgis/default_measure_color_blue" ), myColor.blue() );
mSettings->setValue( QStringLiteral( "/qgis/zoom_factor" ), zoomFactorValue() );
mSettings->setValue( QStringLiteral( "/qgis/reverse_wheel_zoom" ), reverseWheelZoom->isChecked() );
//digitizing
QgsSettingsRegistryCore::settingsDigitizingLineWidth->setValue( mLineWidthSpinBox->value() );
QColor digitizingColor = mLineColorToolButton->color();
QgsSettingsRegistryCore::settingsDigitizingLineColor->setValue( digitizingColor );
digitizingColor = mFillColorToolButton->color();
QgsSettingsRegistryCore::settingsDigitizingFillColor->setValue( digitizingColor );
QgsSettingsRegistryCore::settingsDigitizingLineGhost->setValue( mLineGhostCheckBox->isChecked() );
QgsSettingsRegistryCore::settingsDigitizingDefaultZValue->setValue( mDefaultZValueSpinBox->value() );
QgsSettingsRegistryCore::settingsDigitizingDefaultMValue->setValue( mDefaultMValueSpinBox->value() );
//default snap mode
QgsSettingsRegistryCore::settingsDigitizingDefaultSnapEnabled->setValue( mSnappingEnabledDefault->isChecked() );
QgsSettingsRegistryCore::settingsDigitizingDefaultSnapType->setValue( static_cast<Qgis::SnappingType>( mDefaultSnapTypeComboBox->currentData().toInt() ) );
QgsSettingsRegistryCore::settingsDigitizingDefaultSnappingTolerance->setValue( mDefaultSnappingToleranceSpinBox->value() );
QgsSettingsRegistryCore::settingsDigitizingSearchRadiusVertexEdit->setValue( mSearchRadiusVertexEditSpinBox->value() );
QgsSettingsRegistryCore::settingsDigitizingDefaultSnappingToleranceUnit->setValue(
( mDefaultSnappingToleranceComboBox->currentIndex() == 0 ? QgsTolerance::ProjectUnits : QgsTolerance::Pixels ) );
QgsSettingsRegistryCore::settingsDigitizingSearchRadiusVertexEditUnit->setValue(
( mSearchRadiusVertexEditComboBox->currentIndex() == 0 ? QgsTolerance::ProjectUnits : QgsTolerance::Pixels ) );
QgsSettingsRegistryCore::settingsDigitizingSnapColor->setValue( mSnappingMarkerColorButton->color() );
QgsSettingsRegistryCore::settingsDigitizingSnapTooltip->setValue( mSnappingTooltipsCheckbox->isChecked() );
QgsSettingsRegistryCore::settingsDigitizingSnapInvisibleFeature->setValue( mEnableSnappingOnInvisibleFeatureCheckbox->isChecked() );
QgsSettingsRegistryCore::settingsDigitizingMarkerOnlyForSelected->setValue( mMarkersOnlyForSelectedCheckBox->isChecked() );
QString markerComboText = mMarkerStyleComboBox->currentText();
if ( markerComboText == tr( "Semi Transparent Circle" ) )
{
QgsSettingsRegistryCore::settingsDigitizingMarkerStyle->setValue( QStringLiteral( "SemiTransparentCircle" ) );
}
else if ( markerComboText == tr( "Cross" ) )
{
QgsSettingsRegistryCore::settingsDigitizingMarkerStyle->setValue( QStringLiteral( "Cross" ) );
}
else if ( markerComboText == tr( "None" ) )
{
QgsSettingsRegistryCore::settingsDigitizingMarkerStyle->setValue( QStringLiteral( "None" ) );
}
QgsSettingsRegistryCore::settingsDigitizingMarkerSizeMm->setValue( mMarkerSizeSpinBox->value() );
QgsSettingsRegistryCore::settingsDigitizingReuseLastValues->setValue( chkReuseLastValues->isChecked() );
QgsSettingsRegistryCore::settingsDigitizingDisableEnterAttributeValuesDialog->setValue( chkDisableAttributeValuesDlg->isChecked() );
QgsSettingsRegistryCore::settingsDigitizingValidateGeometries->setValue( mValidateGeometries->currentIndex() );
QgsSettingsRegistryCore::settingsDigitizingOffsetJoinStyle->setValue( mOffsetJoinStyleComboBox->currentData().value<Qgis::JoinStyle>() );
QgsSettingsRegistryCore::settingsDigitizingOffsetQuadSeg->setValue( mOffsetQuadSegSpinBox->value() );
QgsSettingsRegistryCore::settingsDigitizingOffsetMiterLimit->setValue( mCurveOffsetMiterLimitComboBox->value() );
QgsSettingsRegistryCore::settingsDigitizingConvertToCurve->setValue( mTracingConvertToCurveCheckBox->isChecked() );
QgsSettingsRegistryCore::settingsDigitizingConvertToCurveAngleTolerance->setValue( mTracingCustomAngleToleranceSpinBox->value() );
QgsSettingsRegistryCore::settingsDigitizingConvertToCurveDistanceTolerance->setValue( mTracingCustomDistanceToleranceSpinBox->value() );
// default scale list
QStringList myPaths;
for ( int i = 0; i < mListGlobalScales->count(); ++i )
{
myPaths << mListGlobalScales->item( i )->text();
}
QgsSettingsRegistryCore::settingsMapScales->setValue( myPaths );
//
// Color palette
//
if ( mTreeCustomColors->isDirty() )
{
mTreeCustomColors->saveColorsToScheme();
}
//
// Layout settings
//
//default font
QString layoutFont = mComposerFontComboBox->currentFont().family();
mSettings->setValue( QStringLiteral( "LayoutDesigner/defaultFont" ), layoutFont, QgsSettings::Gui );
//grid color
mSettings->setValue( QStringLiteral( "LayoutDesigner/gridRed" ), mGridColorButton->color().red(), QgsSettings::Gui );
mSettings->setValue( QStringLiteral( "LayoutDesigner/gridGreen" ), mGridColorButton->color().green(), QgsSettings::Gui );
mSettings->setValue( QStringLiteral( "LayoutDesigner/gridBlue" ), mGridColorButton->color().blue(), QgsSettings::Gui );
mSettings->setValue( QStringLiteral( "LayoutDesigner/gridAlpha" ), mGridColorButton->color().alpha(), QgsSettings::Gui );
//grid style
if ( mGridStyleComboBox->currentText() == tr( "Solid" ) )
{
mSettings->setValue( QStringLiteral( "LayoutDesigner/gridStyle" ), "Solid", QgsSettings::Gui );
}
else if ( mGridStyleComboBox->currentText() == tr( "Dots" ) )
{
mSettings->setValue( QStringLiteral( "LayoutDesigner/gridStyle" ), "Dots", QgsSettings::Gui );
}
else if ( mGridStyleComboBox->currentText() == tr( "Crosses" ) )
{
mSettings->setValue( QStringLiteral( "LayoutDesigner/gridStyle" ), "Crosses", QgsSettings::Gui );
}
//grid and guide defaults
mSettings->setValue( QStringLiteral( "LayoutDesigner/defaultSnapGridResolution" ), mGridResolutionSpinBox->value(), QgsSettings::Gui );
mSettings->setValue( QStringLiteral( "LayoutDesigner/defaultSnapTolerancePixels" ), mSnapToleranceSpinBox->value(), QgsSettings::Gui );
mSettings->setValue( QStringLiteral( "LayoutDesigner/defaultSnapGridOffsetX" ), mOffsetXSpinBox->value(), QgsSettings::Gui );
mSettings->setValue( QStringLiteral( "LayoutDesigner/defaultSnapGridOffsetY" ), mOffsetYSpinBox->value(), QgsSettings::Gui );
//
// Locale settings
//
QgsApplication::settingsLocaleUserLocale->setValue( cboTranslation->currentData().toString() );
QgsApplication::settingsLocaleOverrideFlag->setValue( grpLocale->isChecked() );
QgsApplication::settingsLocaleGlobalLocale->setValue( cboGlobalLocale->currentData( ).toString() );
// Number settings
QgsApplication::settingsLocaleShowGroupSeparator->setValue( cbShowGroupSeparator->isChecked( ) );
QgsLocalDefaultSettings::setBearingFormat( mBearingFormat.get() );
QgsLocalDefaultSettings::setGeographicCoordinateFormat( mCoordinateFormat.get() );
#ifdef HAVE_OPENCL
// OpenCL settings
QgsOpenClUtils::setEnabled( mGPUEnableCheckBox->isChecked() );
QString preferredDevice( mOpenClDevicesCombo->currentData().toString() );
QgsOpenClUtils::storePreferredDevice( preferredDevice );
#endif
// Gdal skip driver list
if ( mLoadedGdalDriverList )
saveGdalDriverList();
// refresh symbology for any legend items, only if needed
if ( showLegendClassifiers != cbxLegendClassifiers->isChecked() )
{
// TODO[MD] QgisApp::instance()->legend()->updateLegendItemSymbologies();
}
//save variables
QgsExpressionContextUtils::setGlobalVariables( mVariableEditor->variablesInActiveScope() );
// save app stylesheet last (in case reset becomes necessary)
if ( mStyleSheetNewOpts != mStyleSheetOldOpts )
{
mStyleSheetBuilder->saveToSettings( mStyleSheetNewOpts );
// trigger an extra style sheet build to propagate saved settings
mStyleSheetBuilder->buildStyleSheet( mStyleSheetNewOpts );
}
mDefaultDatumTransformTableWidget->transformContext().writeSettings();
mLocatorOptionsWidget->commitChanges();
for ( QgsOptionsPageWidget *widget : std::as_const( mAdditionalOptionWidgets ) )
{
widget->apply();
}
QgsGui::instance()->emitOptionsChanged();
}
void QgsOptions::rejectOptions()
{
// don't reset stylesheet if we don't have to
if ( mStyleSheetNewOpts != mStyleSheetOldOpts )
{
mStyleSheetBuilder->buildStyleSheet( mStyleSheetOldOpts );
}
}
void QgsOptions::spinFontSize_valueChanged( int fontSize )
{
mStyleSheetNewOpts.insert( QStringLiteral( "fontPointSize" ), QVariant( fontSize ) );
mStyleSheetBuilder->buildStyleSheet( mStyleSheetNewOpts );
}
void QgsOptions::mFontFamilyRadioQt_released()
{
if ( mStyleSheetNewOpts.value( QStringLiteral( "fontFamily" ) ).toString() != mStyleSheetBuilder->defaultFont().family() )
{
mStyleSheetNewOpts.insert( QStringLiteral( "fontFamily" ), QVariant( mStyleSheetBuilder->defaultFont().family() ) );
mStyleSheetBuilder->buildStyleSheet( mStyleSheetNewOpts );
}
}
void QgsOptions::mFontFamilyRadioCustom_released()
{
if ( mFontFamilyComboBox->currentFont().family() != mStyleSheetBuilder->defaultFont().family() )
{
mStyleSheetNewOpts.insert( QStringLiteral( "fontFamily" ), QVariant( mFontFamilyComboBox->currentFont().family() ) );
mStyleSheetBuilder->buildStyleSheet( mStyleSheetNewOpts );
}
}
void QgsOptions::mFontFamilyComboBox_currentFontChanged( const QFont &font )
{
if ( mFontFamilyRadioCustom->isChecked()
&& mStyleSheetNewOpts.value( QStringLiteral( "fontFamily" ) ).toString() != font.family() )
{
mStyleSheetNewOpts.insert( QStringLiteral( "fontFamily" ), QVariant( font.family() ) );
mStyleSheetBuilder->buildStyleSheet( mStyleSheetNewOpts );
}
}
void QgsOptions::leLayerGlobalCrs_crsChanged( const QgsCoordinateReferenceSystem &crs )
{
mLayerDefaultCrs = crs;
}
void QgsOptions::lstRasterDrivers_itemDoubleClicked( QTreeWidgetItem *item, int column )
{
Q_UNUSED( column )
// edit driver if driver supports write
if ( item && ( cmbEditCreateOptions->findText( item->text( 0 ) ) != -1 ) )
{
editGdalDriver( item->text( 0 ) );
}
}
void QgsOptions::editCreateOptions()
{
editGdalDriver( cmbEditCreateOptions->currentText() );
}
void QgsOptions::editPyramidsOptions()
{
editGdalDriver( QStringLiteral( "_pyramids" ) );
}
void QgsOptions::editGdalDriver( const QString &driverName )
{
if ( driverName.isEmpty() )
return;
QgsDialog dlg( this, Qt::WindowFlags(), QDialogButtonBox::Ok | QDialogButtonBox::Cancel );
QVBoxLayout *layout = dlg.layout();
QString title = tr( "Create Options - %1 Driver" ).arg( driverName );
if ( driverName == QLatin1String( "_pyramids" ) )
title = tr( "Create Options - pyramids" );
dlg.setWindowTitle( title );
if ( driverName == QLatin1String( "_pyramids" ) )
{
QgsRasterPyramidsOptionsWidget *optionsWidget =
new QgsRasterPyramidsOptionsWidget( &dlg, QStringLiteral( "gdal" ) );
layout->addWidget( optionsWidget );
dlg.resize( 400, 400 );
if ( dlg.exec() == QDialog::Accepted )
optionsWidget->apply();
}
else
{
QgsRasterFormatSaveOptionsWidget *optionsWidget =
new QgsRasterFormatSaveOptionsWidget( &dlg, driverName,
QgsRasterFormatSaveOptionsWidget::Full, QStringLiteral( "gdal" ) );
layout->addWidget( optionsWidget );
if ( dlg.exec() == QDialog::Accepted )
optionsWidget->apply();
}
}
QStringList QgsOptions::i18nList()
{
QStringList myList;
myList << QStringLiteral( "en_US" ); //there is no qm file for this so we add it manually
QString myI18nPath = QgsApplication::i18nPath();
QDir myDir( myI18nPath, QStringLiteral( "qgis*.qm" ) );
QStringList myFileList = myDir.entryList();
QStringListIterator myIterator( myFileList );
while ( myIterator.hasNext() )
{
QString myFileName = myIterator.next();
// Ignore the 'en' translation file, already added as 'en_US'.
if ( myFileName.compare( QLatin1String( "qgis_en.qm" ) ) == 0 ) continue;
myList << myFileName.remove( QStringLiteral( "qgis_" ) ).remove( QStringLiteral( ".qm" ) );
}
return myList;
}
void QgsOptions::restoreDefaultWindowState()
{
// richard
if ( QMessageBox::warning( this, tr( "Restore UI Defaults" ), tr( "Are you sure to reset the UI to default (needs restart)?" ), QMessageBox::Ok | QMessageBox::Cancel ) == QMessageBox::Cancel )
return;
mSettings->setValue( QStringLiteral( "/qgis/restoreDefaultWindowState" ), true );
}
void QgsOptions::mCustomVariablesChkBx_toggled( bool chkd )
{
mAddCustomVarBtn->setEnabled( chkd );
mRemoveCustomVarBtn->setEnabled( chkd );
mCustomVariablesTable->setEnabled( chkd );
}
void QgsOptions::addCustomEnvVarRow( const QString &varName, const QString &varVal, const QString &varApply )
{
int rowCnt = mCustomVariablesTable->rowCount();
mCustomVariablesTable->insertRow( rowCnt );
QComboBox *varApplyCmbBx = new QComboBox( this );
varApplyCmbBx->addItem( tr( "Overwrite" ), QVariant( "overwrite" ) );
varApplyCmbBx->addItem( tr( "If Undefined" ), QVariant( "undefined" ) );
varApplyCmbBx->addItem( tr( "Unset" ), QVariant( "unset" ) );
varApplyCmbBx->addItem( tr( "Prepend" ), QVariant( "prepend" ) );
varApplyCmbBx->addItem( tr( "Append" ), QVariant( "append" ) );
varApplyCmbBx->addItem( tr( "Skip" ), QVariant( "skip" ) );
varApplyCmbBx->setCurrentIndex( varApply.isEmpty() ? 0 : varApplyCmbBx->findData( QVariant( varApply ) ) );
QFont cbf = varApplyCmbBx->font();
QFontMetrics cbfm = QFontMetrics( cbf );
cbf.setPointSize( cbf.pointSize() - 2 );
varApplyCmbBx->setFont( cbf );
mCustomVariablesTable->setCellWidget( rowCnt, 0, varApplyCmbBx );
Qt::ItemFlags itmFlags = Qt::ItemIsEnabled | Qt::ItemIsSelectable
| Qt::ItemIsEditable | Qt::ItemIsDropEnabled;
QTableWidgetItem *varNameItm = new QTableWidgetItem( varName );
varNameItm->setFlags( itmFlags );
mCustomVariablesTable->setItem( rowCnt, 1, varNameItm );
QTableWidgetItem *varValueItm = new QTableWidgetItem( varVal );
varNameItm->setFlags( itmFlags );
mCustomVariablesTable->setItem( rowCnt, 2, varValueItm );
mCustomVariablesTable->setRowHeight( rowCnt, cbfm.height() + 8 );
}
void QgsOptions::addCustomVariable()
{
addCustomEnvVarRow( QString(), QString() );
mCustomVariablesTable->setFocus();
mCustomVariablesTable->setCurrentCell( mCustomVariablesTable->rowCount() - 1, 1 );
mCustomVariablesTable->edit( mCustomVariablesTable->currentIndex() );
}
void QgsOptions::removeCustomVariable()
{
mCustomVariablesTable->removeRow( mCustomVariablesTable->currentRow() );
}
void QgsOptions::mCurrentVariablesQGISChxBx_toggled( bool qgisSpecific )
{
for ( int i = mCurrentVariablesTable->rowCount() - 1; i >= 0; --i )
{
if ( qgisSpecific )
{
QString itmTxt = mCurrentVariablesTable->item( i, 0 )->text();
if ( !itmTxt.startsWith( QLatin1String( "QGIS" ), Qt::CaseInsensitive ) )
mCurrentVariablesTable->hideRow( i );
}
else
{
mCurrentVariablesTable->showRow( i );
}
}
if ( mCurrentVariablesTable->rowCount() > 0 )
{
mCurrentVariablesTable->sortByColumn( 0, Qt::AscendingOrder );
mCurrentVariablesTable->resizeColumnToContents( 0 );
}
}
void QgsOptions::addPluginPath()
{
QString myDir = QFileDialog::getExistingDirectory(
this,
tr( "Choose a directory" ),
QDir::toNativeSeparators( QDir::homePath() ),
QFileDialog::Options()
);
if ( ! myDir.isEmpty() )
{
QListWidgetItem *newItem = new QListWidgetItem( mListPluginPaths );
newItem->setText( myDir );
newItem->setFlags( Qt::ItemIsEditable | Qt::ItemIsEnabled | Qt::ItemIsSelectable );
mListPluginPaths->addItem( newItem );
mListPluginPaths->setCurrentItem( newItem );
}
}
void QgsOptions::removePluginPath()
{
int currentRow = mListPluginPaths->currentRow();
QListWidgetItem *itemToRemove = mListPluginPaths->takeItem( currentRow );
delete itemToRemove;
}
void QgsOptions::addHelpPath()
{
QTreeWidgetItem *item = new QTreeWidgetItem();
item->setText( 0, QStringLiteral( "HELP_LOCATION" ) );
item->setFlags( Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsEditable );
mHelpPathTreeWidget->addTopLevelItem( item );
mHelpPathTreeWidget->setCurrentItem( item );
}
void QgsOptions::removeHelpPath()
{
QList<QTreeWidgetItem *> items = mHelpPathTreeWidget->selectedItems();
for ( int i = 0; i < items.size(); ++i )
{
int idx = mHelpPathTreeWidget->indexOfTopLevelItem( items.at( i ) );
if ( idx >= 0 )
{
delete mHelpPathTreeWidget->takeTopLevelItem( idx );
}
}
}
void QgsOptions::moveHelpPathUp()
{
QList<QTreeWidgetItem *> selectedItems = mHelpPathTreeWidget->selectedItems();
QList<QTreeWidgetItem *>::iterator itemIt = selectedItems.begin();
for ( ; itemIt != selectedItems.end(); ++itemIt )
{
int currentIndex = mHelpPathTreeWidget->indexOfTopLevelItem( *itemIt );
if ( currentIndex > 0 )
{
mHelpPathTreeWidget->takeTopLevelItem( currentIndex );
mHelpPathTreeWidget->insertTopLevelItem( currentIndex - 1, *itemIt );
mHelpPathTreeWidget->setCurrentItem( *itemIt );
}
}
}
void QgsOptions::moveHelpPathDown()
{
QList<QTreeWidgetItem *> selectedItems = mHelpPathTreeWidget->selectedItems();
QList<QTreeWidgetItem *>::iterator itemIt = selectedItems.begin();
for ( ; itemIt != selectedItems.end(); ++itemIt )
{
int currentIndex = mHelpPathTreeWidget->indexOfTopLevelItem( *itemIt );
if ( currentIndex < mHelpPathTreeWidget->topLevelItemCount() - 1 )
{
mHelpPathTreeWidget->takeTopLevelItem( currentIndex );
mHelpPathTreeWidget->insertTopLevelItem( currentIndex + 1, *itemIt );
mHelpPathTreeWidget->setCurrentItem( *itemIt );
}
}
}
void QgsOptions::addTemplatePath()
{
QString myDir = QFileDialog::getExistingDirectory(
this,
tr( "Choose a directory" ),
QDir::toNativeSeparators( QDir::homePath() ),
QFileDialog::Options()
);
if ( ! myDir.isEmpty() )
{
QListWidgetItem *newItem = new QListWidgetItem( mListComposerTemplatePaths );
newItem->setText( myDir );
newItem->setFlags( Qt::ItemIsEditable | Qt::ItemIsEnabled | Qt::ItemIsSelectable );
mListComposerTemplatePaths->addItem( newItem );
mListComposerTemplatePaths->setCurrentItem( newItem );
}
}
void QgsOptions::removeTemplatePath()
{
int currentRow = mListComposerTemplatePaths->currentRow();
QListWidgetItem *itemToRemove = mListComposerTemplatePaths->takeItem( currentRow );
delete itemToRemove;
}
void QgsOptions::addSVGPath()
{
QString myDir = QFileDialog::getExistingDirectory(
this,
tr( "Choose a directory" ),
QDir::toNativeSeparators( QDir::homePath() ),
QFileDialog::Options()
);
if ( ! myDir.isEmpty() )
{
QListWidgetItem *newItem = new QListWidgetItem( mListSVGPaths );
newItem->setText( myDir );
newItem->setFlags( Qt::ItemIsEditable | Qt::ItemIsEnabled | Qt::ItemIsSelectable );
mListSVGPaths->addItem( newItem );
mListSVGPaths->setCurrentItem( newItem );
}
}
void QgsOptions::removeHiddenPath()
{
int currentRow = mListHiddenBrowserPaths->currentRow();
QListWidgetItem *itemToRemove = mListHiddenBrowserPaths->takeItem( currentRow );
delete itemToRemove;
}
void QgsOptions::removeSVGPath()
{
int currentRow = mListSVGPaths->currentRow();
QListWidgetItem *itemToRemove = mListSVGPaths->takeItem( currentRow );
delete itemToRemove;
}
void QgsOptions::addNoProxyUrl()
{
QListWidgetItem *newItem = new QListWidgetItem( mNoProxyUrlListWidget );
newItem->setText( QStringLiteral( "URL" ) );
newItem->setFlags( Qt::ItemIsEditable | Qt::ItemIsEnabled | Qt::ItemIsSelectable );
mNoProxyUrlListWidget->addItem( newItem );
mNoProxyUrlListWidget->setCurrentItem( newItem );
}
void QgsOptions::removeNoProxyUrl()
{
int currentRow = mNoProxyUrlListWidget->currentRow();
QListWidgetItem *itemToRemove = mNoProxyUrlListWidget->takeItem( currentRow );
delete itemToRemove;
}
void QgsOptions::browseCacheDirectory()
{
QString myDir = QFileDialog::getExistingDirectory(
this,
tr( "Choose a directory" ),
QDir::toNativeSeparators( mCacheDirectory->text() ),
QFileDialog::Options()
);
if ( !myDir.isEmpty() )
{
mCacheDirectory->setText( QDir::toNativeSeparators( myDir ) );
}
}
void QgsOptions::clearCache()
{
QgsNetworkAccessManager::instance()->cache()->clear();
QMessageBox::information( this, tr( "Clear Cache" ), tr( "Content cache has been cleared." ) );
}
void QgsOptions::clearAccessCache()
{
QgsNetworkAccessManager::instance()->clearAccessCache();
QMessageBox::information( this, tr( "Clear Cache" ), tr( "Connection authentication cache has been cleared." ) );
}
void QgsOptions::optionsStackedWidget_CurrentChanged( int index )
{
QgsOptionsDialogBase::optionsStackedWidget_CurrentChanged( index );
Q_UNUSED( index )
// load gdal driver list when gdal tab is first opened
if ( mOptionsStackedWidget->currentWidget()->objectName() == QLatin1String( "mOptionsPageGDAL" )
&& ! mLoadedGdalDriverList )
{
loadGdalDriverList();
}
}
void QgsOptions::loadGdalDriverList()
{
QgsApplication::registerGdalDriversFromSettings();
const QStringList mySkippedDrivers = QgsApplication::skippedGdalDrivers();
GDALDriverH myGdalDriver; // current driver
QString myGdalDriverDescription;
QStringList myDrivers;
QStringList myGdalWriteDrivers;
QMap<QString, QString> myDriversFlags, myDriversExt, myDriversLongName;
QMap<QString, Qgis::LayerType> driversType;
// make sure we save list when accept()
mLoadedGdalDriverList = true;
// allow retrieving metadata from all drivers, they will be skipped again when saving
CPLSetConfigOption( "GDAL_SKIP", "" );
GDALAllRegister();
int myGdalDriverCount = GDALGetDriverCount();
for ( int i = 0; i < myGdalDriverCount; ++i )
{
myGdalDriver = GDALGetDriver( i );
Q_CHECK_PTR( myGdalDriver );
if ( !myGdalDriver )
{
QgsLogger::warning( "unable to get driver " + QString::number( i ) );
continue;
}
// in GDAL 2.0 both vector and raster drivers are returned by GDALGetDriver
myGdalDriverDescription = GDALGetDescription( myGdalDriver );
myDrivers << myGdalDriverDescription;
if ( QString( GDALGetMetadataItem( myGdalDriver, GDAL_DCAP_RASTER, nullptr ) ) == QLatin1String( "YES" ) )
{
driversType[myGdalDriverDescription] = Qgis::LayerType::Raster;
}
else if ( QString( GDALGetMetadataItem( myGdalDriver, GDAL_DCAP_VECTOR, nullptr ) ) == QLatin1String( "YES" ) )
{
driversType[myGdalDriverDescription] = Qgis::LayerType::Vector;
}
QgsDebugMsgLevel( QStringLiteral( "driver #%1 - %2" ).arg( i ).arg( myGdalDriverDescription ), 2 );
// get driver R/W flags, adopted from GDALGeneralCmdLineProcessor()
QString driverFlags = "";
if ( driversType[myGdalDriverDescription] == Qgis::LayerType::Raster )
{
if ( QgsGdalUtils::supportsRasterCreate( myGdalDriver ) )
{
myGdalWriteDrivers << myGdalDriverDescription;
driverFlags = "rw+";
}
else if ( GDALGetMetadataItem( myGdalDriver, GDAL_DCAP_CREATECOPY,
nullptr ) )
driverFlags = "rw";
else
driverFlags = "ro";
}
else
{
if ( GDALGetMetadataItem( myGdalDriver, GDAL_DCAP_OPEN, nullptr ) )
driverFlags = "r";
if ( GDALGetMetadataItem( myGdalDriver, GDAL_DCAP_CREATE, nullptr ) )
driverFlags += "w+";
else if ( GDALGetMetadataItem( myGdalDriver, GDAL_DCAP_CREATECOPY, nullptr ) )
driverFlags += "w";
else
driverFlags += "o";
}
if ( GDALGetMetadataItem( myGdalDriver, GDAL_DCAP_VIRTUALIO, nullptr ) )
driverFlags += "v";
myDriversFlags[myGdalDriverDescription] = driverFlags;
// get driver extensions and long name
// the gdal provider can override/add extensions but there is no interface to query this
// aside from parsing QgsRasterLayer::buildSupportedRasterFileFilter()
myDriversExt[myGdalDriverDescription] = QString( GDALGetMetadataItem( myGdalDriver, "DMD_EXTENSION", "" ) ).toLower();
myDriversLongName[myGdalDriverDescription] = QString( GDALGetMetadataItem( myGdalDriver, "DMD_LONGNAME", "" ) );
}
// restore active drivers
QgsApplication::applyGdalSkippedDrivers();
myDrivers.removeDuplicates();
// myDrivers.sort();
// sort list case insensitive - no existing function for this!
QMap<QString, QString> strMap;
for ( const QString &str : std::as_const( myDrivers ) )
strMap.insert( str.toLower(), str );
myDrivers = strMap.values();
for ( const QString &myName : std::as_const( myDrivers ) )
{
QTreeWidgetItem *mypItem = new QTreeWidgetItem( QStringList( myName ) );
if ( mySkippedDrivers.contains( myName ) )
{
mypItem->setCheckState( 0, Qt::Unchecked );
}
else
{
mypItem->setCheckState( 0, Qt::Checked );
}
// add driver metadata
mypItem->setText( 1, myDriversExt[myName] );
QString myFlags = myDriversFlags[myName];
mypItem->setText( 2, myFlags );
mypItem->setText( 3, myDriversLongName[myName] );
if ( driversType[myName] == Qgis::LayerType::Raster )
{
lstRasterDrivers->addTopLevelItem( mypItem );
}
else
{
lstVectorDrivers->addTopLevelItem( mypItem );
}
}
// adjust column width
for ( int i = 0; i < 4; i++ )
{
lstRasterDrivers->resizeColumnToContents( i );
lstRasterDrivers->setColumnWidth( i, lstRasterDrivers->columnWidth( i ) + 5 );
lstVectorDrivers->resizeColumnToContents( i );
lstVectorDrivers->setColumnWidth( i, lstVectorDrivers->columnWidth( i ) + 5 );
}
// populate cmbEditCreateOptions with gdal write drivers - sorted, GTiff first
strMap.clear();
for ( const QString &str : std::as_const( myGdalWriteDrivers ) )
strMap.insert( str.toLower(), str );
myGdalWriteDrivers = strMap.values();
myGdalWriteDrivers.removeAll( QStringLiteral( "Gtiff" ) );
myGdalWriteDrivers.prepend( QStringLiteral( "GTiff" ) );
cmbEditCreateOptions->clear();
for ( const QString &myName : std::as_const( myGdalWriteDrivers ) )
{
cmbEditCreateOptions->addItem( myName );
}
}
void QgsOptions::saveGdalDriverList()
{
bool driverUnregisterNeeded = false;
const auto oldSkippedGdalDrivers = QgsApplication::skippedGdalDrivers();
auto deferredSkippedGdalDrivers = QgsApplication::deferredSkippedGdalDrivers();
QStringList skippedGdalDrivers;
auto checkDriver = [ & ]( QTreeWidgetItem * item )
{
const auto &driverName( item->text( 0 ) );
if ( item->checkState( 0 ) == Qt::Unchecked )
{
skippedGdalDrivers << driverName;
if ( !deferredSkippedGdalDrivers.contains( driverName ) &&
!oldSkippedGdalDrivers.contains( driverName ) )
{
deferredSkippedGdalDrivers << driverName;
driverUnregisterNeeded = true;
}
}
else
{
if ( deferredSkippedGdalDrivers.contains( driverName ) )
{
deferredSkippedGdalDrivers.removeAll( driverName );
}
}
};
// raster drivers
for ( int i = 0; i < lstRasterDrivers->topLevelItemCount(); i++ )
{
checkDriver( lstRasterDrivers->topLevelItem( i ) );
}
// vector drivers
for ( int i = 0; i < lstVectorDrivers->topLevelItemCount(); i++ )
{
checkDriver( lstVectorDrivers->topLevelItem( i ) );
}
if ( driverUnregisterNeeded )
{
QMessageBox::information( this, tr( "Drivers Disabled" ),
tr( "One or more drivers have been disabled. This will only take effect after QGIS is restarted." ) );
}
QgsApplication::setSkippedGdalDrivers( skippedGdalDrivers, deferredSkippedGdalDrivers );
}
void QgsOptions::addScale()
{
int myScale = QInputDialog::getInt(
this,
tr( "Enter scale" ),
tr( "Scale denominator" ),
-1,
1
);
if ( myScale != -1 )
{
QListWidgetItem *newItem = addScaleToScaleList( QStringLiteral( "1:%1" ).arg( myScale ) );
mListGlobalScales->setCurrentItem( newItem );
}
}
void QgsOptions::removeScale()
{
int currentRow = mListGlobalScales->currentRow();
QListWidgetItem *itemToRemove = mListGlobalScales->takeItem( currentRow );
delete itemToRemove;
}
void QgsOptions::restoreDefaultScaleValues()
{
mListGlobalScales->clear();
QStringList myScalesList = Qgis::defaultProjectScales().split( ',' );
const auto constMyScalesList = myScalesList;
for ( const QString &scale : constMyScalesList )
{
addScaleToScaleList( scale );
}
}
void QgsOptions::importScales()
{
QString fileName = QFileDialog::getOpenFileName( this, tr( "Load scales" ), QDir::homePath(),
tr( "XML files (*.xml *.XML)" ) );
if ( fileName.isEmpty() )
{
return;
}
QString msg;
QStringList myScales;
if ( !QgsScaleUtils::loadScaleList( fileName, myScales, msg ) )
{
QgsDebugMsg( msg );
}
const auto constMyScales = myScales;
for ( const QString &scale : constMyScales )
{
addScaleToScaleList( scale );
}
}
void QgsOptions::exportScales()
{
QString fileName = QFileDialog::getSaveFileName( this, tr( "Save scales" ), QDir::homePath(),
tr( "XML files (*.xml *.XML)" ) );
if ( fileName.isEmpty() )
{
return;
}
// ensure the user never omitted the extension from the file name
if ( !fileName.endsWith( QLatin1String( ".xml" ), Qt::CaseInsensitive ) )
{
fileName += QLatin1String( ".xml" );
}
QStringList myScales;
myScales.reserve( mListGlobalScales->count() );
for ( int i = 0; i < mListGlobalScales->count(); ++i )
{
myScales.append( mListGlobalScales->item( i )->text() );
}
QString msg;
if ( !QgsScaleUtils::saveScaleList( fileName, myScales, msg ) )
{
QgsDebugMsg( msg );
}
}
void QgsOptions::addColor()
{
QColor newColor = QgsColorDialog::getColor( QColor(), this->parentWidget(), tr( "Select color" ), true );
if ( !newColor.isValid() )
{
return;
}
activateWindow();
mTreeCustomColors->addColor( newColor, QgsSymbolLayerUtils::colorToName( newColor ) );
}
void QgsOptions::removeLocalizedDataPath()
{
qDeleteAll( mLocalizedDataPathListWidget->selectedItems() );
}
void QgsOptions::addLocalizedDataPath()
{
QString myDir = QFileDialog::getExistingDirectory(
this,
tr( "Choose a Directory" ),
QDir::homePath(),
QFileDialog::Options()
);
if ( ! myDir.isEmpty() )
{
QListWidgetItem *newItem = new QListWidgetItem( mLocalizedDataPathListWidget );
newItem->setText( myDir );
newItem->setFlags( Qt::ItemIsEditable | Qt::ItemIsEnabled | Qt::ItemIsSelectable );
mLocalizedDataPathListWidget->addItem( newItem );
mLocalizedDataPathListWidget->setCurrentItem( newItem );
}
}
void QgsOptions::moveLocalizedDataPathUp()
{
QList<QListWidgetItem *> selectedItems = mLocalizedDataPathListWidget->selectedItems();
QList<QListWidgetItem *>::iterator itemIt = selectedItems.begin();
for ( ; itemIt != selectedItems.end(); ++itemIt )
{
int row = mLocalizedDataPathListWidget->row( *itemIt );
mLocalizedDataPathListWidget->takeItem( row );
mLocalizedDataPathListWidget->insertItem( row - 1, *itemIt );
}
}
void QgsOptions::moveLocalizedDataPathDown()
{
QList<QListWidgetItem *> selectedItems = mLocalizedDataPathListWidget->selectedItems();
QList<QListWidgetItem *>::iterator itemIt = selectedItems.begin();
for ( ; itemIt != selectedItems.end(); ++itemIt )
{
int row = mLocalizedDataPathListWidget->row( *itemIt );
mLocalizedDataPathListWidget->takeItem( row );
mLocalizedDataPathListWidget->insertItem( row + 1, *itemIt );
}
}
QListWidgetItem *QgsOptions::addScaleToScaleList( const QString &newScale )
{
QListWidgetItem *newItem = new QListWidgetItem( newScale );
addScaleToScaleList( newItem );
return newItem;
}
void QgsOptions::addScaleToScaleList( QListWidgetItem *newItem )
{
// If the new scale already exists, delete it.
QListWidgetItem *duplicateItem = mListGlobalScales->findItems( newItem->text(), Qt::MatchExactly ).value( 0 );
delete duplicateItem;
int newDenominator = newItem->text().split( ':' ).value( 1 ).toInt();
int i;
for ( i = 0; i < mListGlobalScales->count(); i++ )
{
int denominator = mListGlobalScales->item( i )->text().split( ':' ).value( 1 ).toInt();
if ( newDenominator > denominator )
break;
}
newItem->setData( Qt::UserRole, newItem->text() );
newItem->setFlags( Qt::ItemIsEditable | Qt::ItemIsEnabled | Qt::ItemIsSelectable );
mListGlobalScales->insertItem( i, newItem );
}
void QgsOptions::refreshSchemeComboBox()
{
mColorSchemesComboBox->blockSignals( true );
mColorSchemesComboBox->clear();
QList<QgsColorScheme *> schemeList = QgsApplication::colorSchemeRegistry()->schemes();
QList<QgsColorScheme *>::const_iterator schemeIt = schemeList.constBegin();
for ( ; schemeIt != schemeList.constEnd(); ++schemeIt )
{
mColorSchemesComboBox->addItem( ( *schemeIt )->schemeName() );
}
mColorSchemesComboBox->blockSignals( false );
}
void QgsOptions::updateSampleLocaleText()
{
QLocale locale( cboGlobalLocale->currentData( ).toString() );
if ( cbShowGroupSeparator->isChecked( ) )
{
locale.setNumberOptions( locale.numberOptions() &= ~QLocale::NumberOption::OmitGroupSeparator );
}
else
{
locale.setNumberOptions( locale.numberOptions() |= QLocale::NumberOption::OmitGroupSeparator );
}
lblLocaleSample->setText( tr( "Sample date: %1 money: %2 int: %3 float: %4" ).arg(
QDate::currentDate().toString( locale.dateFormat( QLocale::FormatType::ShortFormat ) ),
locale.toCurrencyString( 1000.00 ),
locale.toString( 1000 ),
locale.toString( 1000.00, 'f', 2 ) ) );
}
void QgsOptions::updateActionsForCurrentColorScheme( QgsColorScheme *scheme )
{
if ( !scheme )
return;
mButtonImportColors->setEnabled( scheme->isEditable() );
mButtonPasteColors->setEnabled( scheme->isEditable() );
mButtonAddColor->setEnabled( scheme->isEditable() );
mButtonRemoveColor->setEnabled( scheme->isEditable() );
QgsUserColorScheme *userScheme = dynamic_cast<QgsUserColorScheme *>( scheme );
mActionRemovePalette->setEnabled( static_cast< bool >( userScheme ) && userScheme->isEditable() );
if ( userScheme )
{
mActionShowInButtons->setEnabled( true );
whileBlocking( mActionShowInButtons )->setChecked( userScheme->flags() & QgsColorScheme::ShowInColorButtonMenu );
}
else
{
whileBlocking( mActionShowInButtons )->setChecked( false );
mActionShowInButtons->setEnabled( false );
}
}
void QgsOptions::scaleItemChanged( QListWidgetItem *changedScaleItem )
{
// Check if the new value is valid, restore the old value if not.
const thread_local QRegularExpression sRegExp( QStringLiteral( "^1:0*[1-9]\\d*$" ) );
if ( sRegExp.match( changedScaleItem->text() ).hasMatch() )
{
//Remove leading zeroes from the denominator
const thread_local QRegularExpression sRemoveLeadingZeroesRegEx( QStringLiteral( "^1:0*" ) );
changedScaleItem->setText( changedScaleItem->text().replace( sRemoveLeadingZeroesRegEx, QStringLiteral( "1:" ) ) );
}
else
{
QMessageBox::warning( this, tr( "Set Scale" ), tr( "The text you entered is not a valid scale." ) );
changedScaleItem->setText( changedScaleItem->data( Qt::UserRole ).toString() );
}
// Take the changed item out of the list and re-add it. This keeps things ordered and creates correct meta-data for the changed item.
int row = mListGlobalScales->row( changedScaleItem );
mListGlobalScales->takeItem( row );
addScaleToScaleList( changedScaleItem );
mListGlobalScales->setCurrentItem( changedScaleItem );
}
double QgsOptions::zoomFactorValue()
{
// Get the decimal value for zoom factor. This function is needed because the zoom factor spin box is shown as a percent value.
// The minimum zoom factor value is 1.01
if ( spinZoomFactor->value() == spinZoomFactor->minimum() )
return 1.01;
else
return spinZoomFactor->value() / 100.0;
}
void QgsOptions::setZoomFactorValue()
{
// Set the percent value for zoom factor spin box. This function is for converting the decimal zoom factor value in the qgis setting to the percent zoom factor value.
if ( mSettings->value( QStringLiteral( "/qgis/zoom_factor" ), 2 ).toDouble() <= 1.01 )
{
spinZoomFactor->setValue( spinZoomFactor->minimum() );
}
else
{
int percentValue = mSettings->value( QStringLiteral( "/qgis/zoom_factor" ), 2 ).toDouble() * 100;
spinZoomFactor->setValue( percentValue );
}
}
void QgsOptions::showHelp()
{
QWidget *activeTab = mOptionsStackedWidget->currentWidget();
QString link;
// give first priority to created pages which have specified a help key
for ( const QgsOptionsPageWidget *widget : std::as_const( mAdditionalOptionWidgets ) )
{
if ( widget == activeTab )
{
link = widget->helpKey();
break;
}
}
if ( link.isEmpty() )
{
link = QStringLiteral( "introduction/qgis_configuration.html" );
if ( activeTab == mOptionsPageAuth )
{
link = QStringLiteral( "auth_system/index.html" );
}
else if ( activeTab == mOptionsPageVariables )
{
link = QStringLiteral( "introduction/general_tools.html#variables" );
}
else if ( activeTab == mOptionsPageCRS )
{
link = QStringLiteral( "working_with_projections/working_with_projections.html" );
}
}
QgsHelp::openHelp( link );
}
void QgsOptions::customizeBearingFormat()
{
QgsBearingNumericFormatDialog dlg( mBearingFormat.get(), this );
dlg.setWindowTitle( tr( "Bearing Format" ) );
if ( dlg.exec() )
{
mBearingFormat.reset( dlg.format() );
}
}
void QgsOptions::customizeCoordinateFormat()
{
QgsGeographicCoordinateNumericFormatDialog dlg( mCoordinateFormat.get(), false, this );
dlg.setWindowTitle( tr( "Coordinate Format" ) );
if ( dlg.exec() )
{
mCoordinateFormat.reset( dlg.format() );
}
}