QGIS API Documentation 3.30.0-'s-Hertogenbosch (f186b8efe0)
qgsapplication.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgsapplication.cpp - Accessors for application-wide data
3 --------------------------------------
4 Date : 02-Jan-2006
5 Copyright : (C) 2006 by Tom Elwertowski
6 Email : telwertowski at users dot sourceforge dot net
7 ***************************************************************************
8 * *
9 * This program is free software; you can redistribute it and/or modify *
10 * it under the terms of the GNU General Public License as published by *
11 * the Free Software Foundation; either version 2 of the License, or *
12 * (at your option) any later version. *
13 * *
14 ***************************************************************************/
15
16#include "qgsapplication.h"
17#include "qgsauthmanager.h"
20#include "qgsexception.h"
21#include "qgsgeometry.h"
24#include "qgslayout.h"
26#include "qgslogger.h"
27#include "qgsproject.h"
30#include "qgsnetworkreply.h"
31#include "qgsproviderregistry.h"
32#include "qgsexpression.h"
34#include "qgsruntimeprofiler.h"
35#include "qgstaskmanager.h"
39#include "qgssvgcache.h"
40#include "qgsimagecache.h"
41#include "qgssourcecache.h"
47#include "qgsrendererregistry.h"
51#include "qgssymbollayerutils.h"
52#include "qgscalloutsregistry.h"
55#include "qgsmessagelog.h"
57#include "qgssettings.h"
60#include "qgsunittypes.h"
61#include "qgsuserprofile.h"
65#include "qgs3dsymbolregistry.h"
67#include "qgssqliteutils.h"
68#include "qgsstyle.h"
69#include "qgsprojutils.h"
71#include "qgsnewsfeedparser.h"
72#include "qgsbookmarkmanager.h"
73#include "qgsstylemodel.h"
76#include "qgsmeshlayer.h"
77#include "qgsfeaturestore.h"
78#include "qgslocator.h"
79#include "qgsreadwritelocker.h"
81#include "qgsdbquerylog.h"
82#include "qgsfontmanager.h"
84#include "qgscolorrampimpl.h"
85#include "qgsinterval.h"
86#include "qgsgpsconnection.h"
87
92
96
97#include <QDir>
98#include <QFile>
99#include <QFileInfo>
100#include <QFileOpenEvent>
101#include <QMessageBox>
102#include <QPalette>
103#include <QProcess>
104#include <QProcessEnvironment>
105#include <QIcon>
106#include <QPixmap>
107#include <QThreadPool>
108#include <QLocale>
109#include <QStyle>
110#include <QLibraryInfo>
111#include <QStandardPaths>
112#include <QRegularExpression>
113#include <QTextStream>
114#include <QScreen>
115#include <QAuthenticator>
116#include <QRecursiveMutex>
117
119
121
123
125
127
128#ifndef Q_OS_WIN
129#include <netinet/in.h>
130#include <pwd.h>
131#else
132#include <winsock.h>
133#include <windows.h>
134#include <lmcons.h>
135#define SECURITY_WIN32
136#include <security.h>
137#ifdef _MSC_VER
138#pragma comment( lib, "Secur32.lib" )
139#endif
140#endif
141
142#include "qgsconfig.h"
143
144#include <gdal.h>
145#include <ogr_api.h>
146#include <cpl_conv.h> // for setting gdal options
147#include <sqlite3.h>
148#include <mutex>
149
150#include <proj.h>
151
152#if defined(Q_OS_LINUX)
153#include <sys/sysinfo.h>
154#endif
155
156#define CONN_POOL_MAX_CONCURRENT_CONNS 4
157
158QObject *ABISYM( QgsApplication::mFileOpenEventReceiver ) = nullptr;
159bool ABISYM( QgsApplication::mInitialized ) = false;
160bool ABISYM( QgsApplication::mRunningFromBuildDir ) = false;
161const char *QgsApplication::QGIS_ORGANIZATION_NAME = "QGIS";
162const char *QgsApplication::QGIS_ORGANIZATION_DOMAIN = "qgis.org";
163const char *QgsApplication::QGIS_APPLICATION_NAME = "QGIS3";
164QgsApplication::ApplicationMembers *QgsApplication::sApplicationMembers = nullptr;
165QgsAuthManager *QgsApplication::sAuthManager = nullptr;
166int ABISYM( QgsApplication::sMaxThreads ) = -1;
167
168Q_GLOBAL_STATIC( QStringList, sFileOpenEventList )
169Q_GLOBAL_STATIC( QString, sPrefixPath )
170Q_GLOBAL_STATIC( QString, sPluginPath )
171Q_GLOBAL_STATIC( QString, sPkgDataPath )
172Q_GLOBAL_STATIC( QString, sLibraryPath )
173Q_GLOBAL_STATIC( QString, sLibexecPath )
174Q_GLOBAL_STATIC( QString, sQmlImportPath )
175Q_GLOBAL_STATIC( QString, sThemeName )
176Q_GLOBAL_STATIC( QString, sProfilePath )
177
178Q_GLOBAL_STATIC( QStringList, sDefaultSvgPaths )
179Q_GLOBAL_STATIC( QgsStringMap, sSystemEnvVars )
180Q_GLOBAL_STATIC( QString, sConfigPath )
181
182Q_GLOBAL_STATIC( QString, sBuildSourcePath )
183#if defined(_MSC_VER) && !defined(USING_NMAKE) && !defined(USING_NINJA)
184Q_GLOBAL_STATIC( QString, sCfgIntDir )
185#endif
186Q_GLOBAL_STATIC( QString, sBuildOutputPath )
187Q_GLOBAL_STATIC( QStringList, sGdalSkipList )
188Q_GLOBAL_STATIC( QStringList, sDeferredSkippedGdalDrivers )
189Q_GLOBAL_STATIC( QString, sAuthDbDirPath )
190
191Q_GLOBAL_STATIC( QString, sUserName )
192Q_GLOBAL_STATIC( QString, sUserFullName )
193Q_GLOBAL_STATIC_WITH_ARGS( QString, sPlatformName, ( "external" ) )
194Q_GLOBAL_STATIC( QString, sApplicationFullName )
195Q_GLOBAL_STATIC( QString, sTranslation )
196
197Q_GLOBAL_STATIC( QTemporaryDir, sIconCacheDir )
198
199QgsApplication::QgsApplication( int &argc, char **argv, bool GUIenabled, const QString &profileFolder, const QString &platformName )
200 : QApplication( argc, argv, GUIenabled )
201{
202 *sPlatformName() = platformName;
203
204 if ( *sTranslation() != QLatin1String( "C" ) )
205 {
206 mQgisTranslator = new QTranslator();
207 if ( mQgisTranslator->load( QStringLiteral( "qgis_" ) + *sTranslation(), i18nPath() ) )
208 {
209 installTranslator( mQgisTranslator );
210 }
211 else
212 {
213 QgsDebugMsgLevel( QStringLiteral( "loading of qgis translation failed %1/qgis_%2" ).arg( i18nPath(), *sTranslation() ), 2 );
214 }
215
216 /* Translation file for Qt.
217 * The strings from the QMenuBar context section are used by Qt/Mac to shift
218 * the About, Preferences and Quit items to the Mac Application menu.
219 * These items must be translated identically in both qt_ and qgis_ files.
220 */
221 QString qtTranslationsPath = QLibraryInfo::location( QLibraryInfo::TranslationsPath );
222#ifdef __MINGW32__
223 QString prefix = QDir( QString( "%1/../" ).arg( QApplication::applicationDirPath() ) ).absolutePath();
224 qtTranslationsPath = prefix + qtTranslationsPath.mid( QLibraryInfo::location( QLibraryInfo::PrefixPath ).length() );
225#endif
226
227 mQtTranslator = new QTranslator();
228 if ( mQtTranslator->load( QStringLiteral( "qt_" ) + *sTranslation(), qtTranslationsPath ) )
229 {
230 installTranslator( mQtTranslator );
231 }
232 else
233 {
234 QgsDebugMsgLevel( QStringLiteral( "loading of qt translation failed %1/qt_%2" ).arg( qtTranslationsPath, *sTranslation() ), 2 );
235 }
236
237 mQtBaseTranslator = new QTranslator();
238 if ( mQtBaseTranslator->load( QStringLiteral( "qtbase_" ) + *sTranslation(), qtTranslationsPath ) )
239 {
240 installTranslator( mQtBaseTranslator );
241 }
242 else
243 {
244 QgsDebugMsgLevel( QStringLiteral( "loading of qtbase translation failed %1/qt_%2" ).arg( qtTranslationsPath, *sTranslation() ), 2 );
245 }
246 }
247
248 mApplicationMembers = new ApplicationMembers();
249
250 *sProfilePath() = profileFolder;
251
253
254 mApplicationMembers->mSettingsRegistryCore->migrateOldSettings();
255}
256
257void QgsApplication::init( QString profileFolder )
258{
259 if ( profileFolder.isEmpty() )
260 {
261 if ( getenv( "QGIS_CUSTOM_CONFIG_PATH" ) )
262 {
263 profileFolder = getenv( "QGIS_CUSTOM_CONFIG_PATH" );
264 }
265 else
266 {
267 profileFolder = QStandardPaths::standardLocations( QStandardPaths::AppDataLocation ).value( 0 );
268 }
269 // This will normally get here for custom scripts that use QgsApplication.
270 // This doesn't get this hit for QGIS Desktop because we setup the profile via main
271 QString rootProfileFolder = QgsUserProfileManager::resolveProfilesFolder( profileFolder );
272 QgsUserProfileManager manager( rootProfileFolder );
273 QgsUserProfile *profile = manager.getProfile();
274 profileFolder = profile->folder();
275 delete profile;
276 }
277
278 *sProfilePath() = profileFolder;
279
280 static std::once_flag sMetaTypesRegistered;
281 std::call_once( sMetaTypesRegistered, []
282 {
283 qRegisterMetaType<QgsGeometry::Error>( "QgsGeometry::Error" );
284 qRegisterMetaType<QgsDatabaseQueryLogEntry>( "QgsDatabaseQueryLogEntry" );
285 qRegisterMetaType<QgsProcessingFeatureSourceDefinition>( "QgsProcessingFeatureSourceDefinition" );
286 qRegisterMetaType<QgsProcessingOutputLayerDefinition>( "QgsProcessingOutputLayerDefinition" );
287 qRegisterMetaType<Qgis::LayoutUnit>( "Qgis::LayoutUnit" );
288 qRegisterMetaType<QgsUnsetAttributeValue>( "QgsUnsetAttributeValue" );
289 qRegisterMetaType<QgsFeatureId>( "QgsFeatureId" );
290 qRegisterMetaType<QgsFields>( "QgsFields" );
291 qRegisterMetaType<QgsFeatureIds>( "QgsFeatureIds" );
292 qRegisterMetaType<QgsProperty>( "QgsProperty" );
293 qRegisterMetaType<QgsFeatureStoreList>( "QgsFeatureStoreList" );
294 qRegisterMetaType<Qgis::MessageLevel>( "Qgis::MessageLevel" );
295 qRegisterMetaType<Qgis::BrowserItemState>( "Qgis::BrowserItemState" );
296 qRegisterMetaType<Qgis::GpsFixStatus>( "Qgis::GpsFixStatus" );
297 qRegisterMetaType<QgsReferencedRectangle>( "QgsReferencedRectangle" );
298 qRegisterMetaType<QgsReferencedPointXY>( "QgsReferencedPointXY" );
299 qRegisterMetaType<QgsReferencedGeometry>( "QgsReferencedGeometry" );
300 qRegisterMetaType<QgsLayoutRenderContext::Flags>( "QgsLayoutRenderContext::Flags" );
301 qRegisterMetaType<QgsStyle::StyleEntity>( "QgsStyle::StyleEntity" );
302 qRegisterMetaType<QgsCoordinateReferenceSystem>( "QgsCoordinateReferenceSystem" );
303 qRegisterMetaType<QgsAuthManager::MessageLevel>( "QgsAuthManager::MessageLevel" );
304 qRegisterMetaType<QgsNetworkRequestParameters>( "QgsNetworkRequestParameters" );
305 qRegisterMetaType<QgsNetworkReplyContent>( "QgsNetworkReplyContent" );
306 qRegisterMetaType<QgsFeature>( "QgsFeature" );
307 qRegisterMetaType<QgsGeometry>( "QgsGeometry" );
308 qRegisterMetaType<QgsInterval>( "QgsInterval" );
309 qRegisterMetaType<QgsRectangle>( "QgsRectangle" );
310 qRegisterMetaType<QgsPointXY>( "QgsPointXY" );
311 qRegisterMetaType<QgsPoint>( "QgsPoint" );
312 qRegisterMetaType<QgsDatumTransform::GridDetails>( "QgsDatumTransform::GridDetails" );
313 qRegisterMetaType<QgsDatumTransform::TransformDetails>( "QgsDatumTransform::TransformDetails" );
314 qRegisterMetaType<QgsNewsFeedParser::Entry>( "QgsNewsFeedParser::Entry" );
315 qRegisterMetaType<QgsRectangle>( "QgsRectangle" );
316 qRegisterMetaType<QgsLocatorResult>( "QgsLocatorResult" );
317 qRegisterMetaType<QgsGradientColorRamp>( "QgsGradientColorRamp" );
318 qRegisterMetaType<QgsProcessingModelChildParameterSource>( "QgsProcessingModelChildParameterSource" );
319#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
320 // Qt6 documentation says these are not needed anymore (https://www.qt.io/blog/whats-new-in-qmetatype-qvariant) #spellok
321 // TODO: when tests can run against Qt6 builds, check for any regressions
322 qRegisterMetaTypeStreamOperators<QgsProcessingModelChildParameterSource>( "QgsProcessingModelChildParameterSource" );
323#endif
324 qRegisterMetaType<QgsRemappingSinkDefinition>( "QgsRemappingSinkDefinition" );
325 qRegisterMetaType<QgsProcessingModelChildDependency>( "QgsProcessingModelChildDependency" );
326 qRegisterMetaType<QgsTextFormat>( "QgsTextFormat" );
327#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
328 QMetaType::registerComparators<QgsProcessingModelChildDependency>();
329 QMetaType::registerEqualsComparator<QgsProcessingFeatureSourceDefinition>();
330 QMetaType::registerEqualsComparator<QgsProperty>();
331 QMetaType::registerEqualsComparator<QgsDateTimeRange>();
332 QMetaType::registerEqualsComparator<QgsDateRange>();
333 QMetaType::registerEqualsComparator<QgsUnsetAttributeValue>();
334#endif
335 qRegisterMetaType<QPainter::CompositionMode>( "QPainter::CompositionMode" );
336 qRegisterMetaType<QgsDateTimeRange>( "QgsDateTimeRange" );
337 qRegisterMetaType<QList<QgsMapLayer *>>( "QList<QgsMapLayer*>" );
338 qRegisterMetaType<QMap<QNetworkRequest::Attribute, QVariant>>( "QMap<QNetworkRequest::Attribute,QVariant>" );
339 qRegisterMetaType<QMap<QNetworkRequest::KnownHeaders, QVariant>>( "QMap<QNetworkRequest::KnownHeaders,QVariant>" );
340 qRegisterMetaType<QList<QNetworkReply::RawHeaderPair>>( "QList<QNetworkReply::RawHeaderPair>" );
341 qRegisterMetaType< QAuthenticator * >( "QAuthenticator*" );
342 qRegisterMetaType< QgsGpsInformation >( "QgsGpsInformation" );
343 } );
344
345 ( void ) resolvePkgPath();
346
347 if ( ABISYM( mRunningFromBuildDir ) )
348 {
349 // we run from source directory - not installed to destination (specified prefix)
350 *sPrefixPath() = QString(); // set invalid path
351#if defined(_MSC_VER) && !defined(USING_NMAKE) && !defined(USING_NINJA)
352 setPluginPath( *sBuildOutputPath() + '/' + QString( QGIS_PLUGIN_SUBDIR ) + '/' + *sCfgIntDir() );
353#else
354 setPluginPath( *sBuildOutputPath() + '/' + QStringLiteral( QGIS_PLUGIN_SUBDIR ) );
355#endif
356 setPkgDataPath( *sBuildOutputPath() + QStringLiteral( "/data" ) ); // in buildDir/data - used for: doc, resources, svg
357 *sLibraryPath() = *sBuildOutputPath() + '/' + QGIS_LIB_SUBDIR + '/';
358#if defined(_MSC_VER) && !defined(USING_NMAKE) && !defined(USING_NINJA)
359 *sLibexecPath() = *sBuildOutputPath() + '/' + QGIS_LIBEXEC_SUBDIR + '/' + *sCfgIntDir() + '/';
360#else
361 *sLibexecPath() = *sBuildOutputPath() + '/' + QGIS_LIBEXEC_SUBDIR + '/';
362#endif
363#if defined( HAVE_QUICK )
364 *sQmlImportPath() = *sBuildOutputPath() + '/' + QGIS_QML_SUBDIR + '/';
365#endif
366 }
367 else
368 {
369 char *prefixPath = getenv( "QGIS_PREFIX_PATH" );
370 if ( !prefixPath )
371 {
372 if ( sPrefixPath()->isNull() )
373 {
374#if defined(Q_OS_MACX) || defined(Q_OS_WIN)
375 setPrefixPath( applicationDirPath(), true );
376#elif defined(ANDROID)
377 // this is "/data/data/org.qgis.qgis" in android
378 QDir myDir( QDir::homePath() );
379 myDir.cdUp();
380 QString myPrefix = myDir.absolutePath();
381 setPrefixPath( myPrefix, true );
382#else
383 QDir myDir( applicationDirPath() );
384 // Fix for server which is one level deeper in /usr/lib/cgi-bin
385 if ( applicationDirPath().contains( QStringLiteral( "cgi-bin" ) ) )
386 {
387 myDir.cdUp();
388 }
389 myDir.cdUp(); // Go from /usr/bin or /usr/lib (for server) to /usr
390 QString myPrefix = myDir.absolutePath();
391 setPrefixPath( myPrefix, true );
392#endif
393 }
394 }
395 else
396 {
397 setPrefixPath( prefixPath, true );
398 }
399 }
400
401 *sConfigPath() = profileFolder + '/'; // make sure trailing slash is included
402 *sDefaultSvgPaths() << qgisSettingsDirPath() + QStringLiteral( "svg/" );
403
404 *sAuthDbDirPath() = qgisSettingsDirPath();
405 if ( getenv( "QGIS_AUTH_DB_DIR_PATH" ) )
406 {
407 setAuthDatabaseDirPath( getenv( "QGIS_AUTH_DB_DIR_PATH" ) );
408 }
409
410 // force use of OpenGL renderer for Qt3d.
411 qputenv( "QT3D_RENDERER", "opengl" );
412
413 // store system environment variables passed to application, before they are adjusted
414 QMap<QString, QString> systemEnvVarMap;
415 QString passfile( QStringLiteral( "QGIS_AUTH_PASSWORD_FILE" ) ); // QString, for comparison
416
417 const auto systemEnvironment = QProcessEnvironment::systemEnvironment().toStringList();
418 for ( const QString &varStr : systemEnvironment )
419 {
420 int pos = varStr.indexOf( QLatin1Char( '=' ) );
421 if ( pos == -1 )
422 continue;
423 QString varStrName = varStr.left( pos );
424 QString varStrValue = varStr.mid( pos + 1 );
425 if ( varStrName != passfile )
426 {
427 systemEnvVarMap.insert( varStrName, varStrValue );
428 }
429 }
430 *sSystemEnvVars() = systemEnvVarMap;
431
432 // append local user-writable folder as a proj search path
433 QStringList currentProjSearchPaths = QgsProjUtils::searchPaths();
434 currentProjSearchPaths.append( qgisSettingsDirPath() + QStringLiteral( "proj" ) );
435#ifdef Q_OS_MACX
436 // append bundled proj lib for MacOS
437 QString projLib( QDir::cleanPath( pkgDataPath().append( "/proj" ) ) );
438 if ( QFile::exists( projLib ) )
439 {
440 currentProjSearchPaths.append( projLib );
441 }
442#endif // Q_OS_MACX
443
444 char **newPaths = new char *[currentProjSearchPaths.length()];
445 for ( int i = 0; i < currentProjSearchPaths.count(); ++i )
446 {
447 newPaths[i] = CPLStrdup( currentProjSearchPaths.at( i ).toUtf8().constData() );
448 }
449 proj_context_set_search_paths( nullptr, currentProjSearchPaths.count(), newPaths );
450 for ( int i = 0; i < currentProjSearchPaths.count(); ++i )
451 {
452 CPLFree( newPaths[i] );
453 }
454 delete [] newPaths;
455
456 // allow Qt to search for Qt plugins (e.g. sqldrivers) in our plugin directory
457 QCoreApplication::addLibraryPath( pluginPath() );
458
459 {
460 QgsScopedRuntimeProfile profile( tr( "Load user fonts" ) );
462 }
463
464 // set max. thread count to -1
465 // this should be read from QgsSettings but we don't know where they are at this point
466 // so we read actual value in main.cpp
467 ABISYM( sMaxThreads ) = -1;
468
469 {
470 QgsScopedRuntimeProfile profile( tr( "Load color schemes" ) );
473 }
474
475 {
476 QgsScopedRuntimeProfile profile( tr( "Load bookmarks" ) );
478 }
479
480 // trigger creation of default style
481 QgsStyle *defaultStyle = QgsStyle::defaultStyle();
482 if ( !members()->mStyleModel )
483 members()->mStyleModel = new QgsStyleModel( defaultStyle );
484
485 ABISYM( mInitialized ) = true;
486}
487
489{
490 mApplicationMembers->mSettingsRegistryCore->backwardCompatibility();
491
492 delete mDataItemProviderRegistry;
493 delete mApplicationMembers;
494 delete mQgisTranslator;
495 delete mQtTranslator;
496 delete mQtBaseTranslator;
497
498 // we do this here as well as in exitQgis() -- it's safe to call as often as we want,
499 // and there's just a *chance* that someone hasn't properly called exitQgis prior to
500 // this destructor...
501 invalidateCaches();
502}
503
504void QgsApplication::invalidateCaches()
505{
506 // invalidate coordinate cache while the PROJ context held by the thread-locale
507 // QgsProjContextStore object is still alive. Otherwise if this later object
508 // is destroyed before the static variables of the cache, we might use freed memory.
512}
513
515{
516 return qobject_cast<QgsApplication *>( QCoreApplication::instance() );
517}
518
519bool QgsApplication::event( QEvent *event )
520{
521 bool done = false;
522 if ( event->type() == QEvent::FileOpen )
523 {
524 // handle FileOpen event (double clicking a file icon in Mac OS X Finder)
525 if ( ABISYM( mFileOpenEventReceiver ) )
526 {
527 // Forward event to main window.
528 done = notify( ABISYM( mFileOpenEventReceiver ), event );
529 }
530 else
531 {
532 // Store filename because receiver has not registered yet.
533 // If QGIS has been launched by double clicking a file icon, FileOpen will be
534 // the first event; the main window is not yet ready to handle the event.
535 sFileOpenEventList()->append( static_cast<QFileOpenEvent *>( event )->file() );
536 done = true;
537 }
538 }
539 else
540 {
541 // pass other events to base class
542 done = QApplication::event( event );
543 }
544 return done;
545}
546
547bool QgsApplication::notify( QObject *receiver, QEvent *event )
548{
549 bool done = false;
550 // Crashes in customization (especially on Mac), if we're not in the main/UI thread, see #5597
551 if ( thread() == receiver->thread() )
552 emit preNotify( receiver, event, &done );
553
554 if ( done )
555 return true;
556
557 // Send event to receiver and catch unhandled exceptions
558 done = true;
559 try
560 {
561 done = QApplication::notify( receiver, event );
562 }
563 catch ( QgsException &e )
564 {
565 qCritical() << "Caught unhandled QgsException: " << e.what();
566 if ( qApp->thread() == QThread::currentThread() )
567 QMessageBox::critical( activeWindow(), tr( "Exception" ), e.what() );
568 }
569 catch ( std::exception &e )
570 {
571 qCritical() << "Caught unhandled std::exception: " << e.what();
572 if ( qApp->thread() == QThread::currentThread() )
573 QMessageBox::critical( activeWindow(), tr( "Exception" ), e.what() );
574 }
575 catch ( ... )
576 {
577 qCritical() << "Caught unhandled unknown exception";
578 if ( qApp->thread() == QThread::currentThread() )
579 QMessageBox::critical( activeWindow(), tr( "Exception" ), tr( "unknown exception" ) );
580 }
581
582 return done;
583}
584
586{
587 return QgsRuntimeProfiler::threadLocalInstance();
588}
589
591{
592 // Set receiver for FileOpen events
593 ABISYM( mFileOpenEventReceiver ) = receiver;
594 // Propagate any events collected before the receiver has registered.
595 if ( sFileOpenEventList()->count() > 0 )
596 {
597 const QStringList fileOpenEventList = *sFileOpenEventList();
598 for ( const QString &file : fileOpenEventList )
599 {
600 QFileOpenEvent foe( file );
601 QgsApplication::sendEvent( ABISYM( mFileOpenEventReceiver ), &foe );
602 }
603 sFileOpenEventList()->clear();
604 }
605}
606
607void QgsApplication::setPrefixPath( const QString &prefixPath, bool useDefaultPaths )
608{
609 *sPrefixPath() = prefixPath;
610#if defined(Q_OS_WIN)
611 if ( sPrefixPath()->endsWith( "/bin" ) )
612 {
613 sPrefixPath()->chop( 4 );
614 }
615#endif
616 if ( useDefaultPaths && !ABISYM( mRunningFromBuildDir ) )
617 {
618 setPluginPath( *sPrefixPath() + '/' + QStringLiteral( QGIS_PLUGIN_SUBDIR ) );
619 setPkgDataPath( *sPrefixPath() + '/' + QStringLiteral( QGIS_DATA_SUBDIR ) );
620 }
621 *sLibraryPath() = *sPrefixPath() + '/' + QGIS_LIB_SUBDIR + '/';
622 *sLibexecPath() = *sPrefixPath() + '/' + QGIS_LIBEXEC_SUBDIR + '/';
623#if defined( HAVE_QUICK )
624 *sQmlImportPath() = *sPrefixPath() + '/' + QGIS_QML_SUBDIR + '/';
625#endif
626}
627
628void QgsApplication::setPluginPath( const QString &pluginPath )
629{
630 *sPluginPath() = pluginPath;
631}
632
633void QgsApplication::setPkgDataPath( const QString &pkgDataPath )
634{
635 *sPkgDataPath() = pkgDataPath;
636
637 QString mySvgPath = pkgDataPath + QStringLiteral( "/svg/" );
638
639 // avoid duplicate entries
640 if ( !sDefaultSvgPaths()->contains( mySvgPath ) )
641 *sDefaultSvgPaths() << mySvgPath;
642}
643
644void QgsApplication::setDefaultSvgPaths( const QStringList &pathList )
645{
646 *sDefaultSvgPaths() = pathList;
647}
648
649void QgsApplication::setAuthDatabaseDirPath( const QString &authDbDirPath )
650{
651 QFileInfo fi( authDbDirPath );
652 if ( fi.exists() && fi.isDir() && fi.isWritable() )
653 {
654 *sAuthDbDirPath() = fi.canonicalFilePath() + QDir::separator();
655 }
656}
657
659{
660#if 0
661 if ( ABISYM( mRunningFromBuildDir ) )
662 {
663 static bool sOnce = true;
664 if ( sOnce )
665 {
666 QgsMessageLogNotifyBlocker blockNotifications;
667 ( void ) blockNotifications;
668 qWarning( "!!! prefix path was requested, but it is not valid - we do not run from installed path !!!" );
669 }
670 sOnce = false;
671 }
672#endif
673
674 return *sPrefixPath();
675}
677{
678 return *sPluginPath();
679}
680
682{
683 if ( sPkgDataPath()->isNull() )
684 return resolvePkgPath();
685 else
686 return *sPkgDataPath();
687}
688
690{
691 return QStringLiteral( ":/images/themes/default/" );
692}
694{
695 QString usersThemes = userThemesFolder() + QDir::separator() + themeName() + QDir::separator() + "icons/";
696 QDir dir( usersThemes );
697 if ( dir.exists() )
698 {
699 return usersThemes;
700 }
701 else
702 {
703 QString defaultThemes = defaultThemesFolder() + QDir::separator() + themeName() + QDir::separator() + "icons/";
704 return defaultThemes;
705 }
706}
707
709{
710 return iconsPath() + QStringLiteral( "qgis-icon-60x60.png" );
711}
712
714{
715 return ABISYM( sMaxThreads );
716}
717
718QString QgsApplication::iconPath( const QString &iconFile )
719{
720 // try active theme
721 QString path = activeThemePath();
722 if ( QFile::exists( path + iconFile ) )
723 return path + iconFile;
724
725 // use default theme
726 return defaultThemePath() + iconFile;
727}
728
729QIcon QgsApplication::getThemeIcon( const QString &name, const QColor &fillColor, const QColor &strokeColor )
730{
731 const QString cacheKey = ( name.startsWith( '/' ) ? name.mid( 1 ) : name )
732 + ( fillColor.isValid() ? QStringLiteral( "_%1" ).arg( fillColor.name( QColor::HexArgb ).mid( 1 ) ) : QString() )
733 + ( strokeColor.isValid() ? QStringLiteral( "_%1" ).arg( strokeColor.name( QColor::HexArgb ).mid( 1 ) ) : QString() );
734 QgsApplication *app = instance();
735 if ( app && app->mIconCache.contains( cacheKey ) )
736 return app->mIconCache.value( cacheKey );
737
738 QIcon icon;
739 const bool colorBased = fillColor.isValid() || strokeColor.isValid();
740
741 auto iconFromColoredSvg = [ = ]( const QString & path ) -> QIcon
742 {
743 // sizes are unused here!
744 const QByteArray svgContent = QgsApplication::svgCache()->svgContent( path, 16, fillColor, strokeColor, 1, 1 );
745
746 const QString iconPath = sIconCacheDir()->filePath( cacheKey + QStringLiteral( ".svg" ) );
747 QFile f( iconPath );
748 if ( f.open( QFile::WriteOnly | QFile::Truncate ) )
749 {
750 f.write( svgContent );
751 f.close();
752 }
753 else
754 {
755 QgsDebugMsg( QStringLiteral( "Could not create colorized icon svg at %1" ).arg( iconPath ) );
756 return QIcon();
757 }
758
759 return QIcon( f.fileName() );
760 };
761
762 QString preferredPath = activeThemePath() + QDir::separator() + name;
763 QString defaultPath = defaultThemePath() + QDir::separator() + name;
764 if ( QFile::exists( preferredPath ) )
765 {
766 if ( colorBased )
767 {
768 icon = iconFromColoredSvg( preferredPath );
769 }
770 else
771 {
772 icon = QIcon( preferredPath );
773 }
774 }
775 else if ( QFile::exists( defaultPath ) )
776 {
777 //could still return an empty icon if it
778 //doesn't exist in the default theme either!
779 if ( colorBased )
780 {
781 icon = iconFromColoredSvg( defaultPath );
782 }
783 else
784 {
785 icon = QIcon( defaultPath );
786 }
787 }
788 else
789 {
790 icon = QIcon();
791 }
792
793 if ( app )
794 app->mIconCache.insert( cacheKey, icon );
795 return icon;
796}
797
799{
800 QgsApplication *app = instance();
801 if ( app && app->mCursorCache.contains( cursor ) )
802 return app->mCursorCache.value( cursor );
803
804 // All calculations are done on 32x32 icons
805 // Defaults to center, individual cursors may override
806 int activeX = 16;
807 int activeY = 16;
808
809 QString name;
810 switch ( cursor )
811 {
812 case ZoomIn:
813 name = QStringLiteral( "mZoomIn.svg" );
814 activeX = 13;
815 activeY = 13;
816 break;
817 case ZoomOut:
818 name = QStringLiteral( "mZoomOut.svg" );
819 activeX = 13;
820 activeY = 13;
821 break;
822 case Identify:
823 activeX = 3;
824 activeY = 6;
825 name = QStringLiteral( "mIdentify.svg" );
826 break;
827 case CrossHair:
828 name = QStringLiteral( "mCrossHair.svg" );
829 break;
830 case CapturePoint:
831 name = QStringLiteral( "mCapturePoint.svg" );
832 break;
833 case Select:
834 name = QStringLiteral( "mSelect.svg" );
835 activeX = 6;
836 activeY = 6;
837 break;
838 case Sampler:
839 activeX = 5;
840 activeY = 5;
841 name = QStringLiteral( "mSampler.svg" );
842 break;
843 // No default
844 }
845 // It should never get here!
846 Q_ASSERT( ! name.isEmpty( ) );
847
848 QIcon icon = getThemeIcon( QStringLiteral( "cursors" ) + QDir::separator() + name );
849 QCursor cursorIcon;
850 // Check if an icon exists for this cursor (the O.S. default cursor will be used if it does not)
851 if ( ! icon.isNull( ) )
852 {
853 // Apply scaling
854 float scale = Qgis::UI_SCALE_FACTOR * QgsApplication::fontMetrics().height() / 32.0;
855 cursorIcon = QCursor( icon.pixmap( std::ceil( scale * 32 ), std::ceil( scale * 32 ) ), std::ceil( scale * activeX ), std::ceil( scale * activeY ) );
856 }
857 if ( app )
858 app->mCursorCache.insert( cursor, cursorIcon );
859 return cursorIcon;
860}
861
862// TODO: add some caching mechanism ?
863QPixmap QgsApplication::getThemePixmap( const QString &name, const QColor &foreColor, const QColor &backColor, const int size )
864{
865 const QString preferredPath = activeThemePath() + QDir::separator() + name;
866 const QString defaultPath = defaultThemePath() + QDir::separator() + name;
867 const QString path = QFile::exists( preferredPath ) ? preferredPath : defaultPath;
868 if ( foreColor.isValid() || backColor.isValid() )
869 {
870 bool fitsInCache = false;
871 const QImage image = svgCache()->svgAsImage( path, size, backColor, foreColor, 1, 1, fitsInCache );
872 return QPixmap::fromImage( image );
873 }
874
875 return QPixmap( path );
876}
877
878void QgsApplication::setThemeName( const QString &themeName )
879{
880 *sThemeName() = themeName;
881}
882
884{
885 static QString appPath;
886 if ( appPath.isNull() )
887 {
888 if ( QCoreApplication::instance() )
889 {
890 appPath = applicationDirPath();
891 }
892 else
893 {
894 qWarning( "Application path not initialized" );
895 }
896 }
897
898 if ( !appPath.isNull() || getenv( "QGIS_PREFIX_PATH" ) )
899 {
900 QString prefix = getenv( "QGIS_PREFIX_PATH" ) ? getenv( "QGIS_PREFIX_PATH" ) : appPath;
901
902 // check if QGIS is run from build directory (not the install directory)
903 QFile f;
904 // "/../../.." is for Mac bundled app in build directory
905 static const QStringList paths { QStringList() << QString() << QStringLiteral( "/.." ) << QStringLiteral( "/bin" ) << QStringLiteral( "/../../.." ) };
906 for ( const QString &path : paths )
907 {
908 f.setFileName( prefix + path + "/qgisbuildpath.txt" );
909 if ( f.exists() )
910 break;
911 }
912 if ( f.exists() && f.open( QIODevice::ReadOnly ) )
913 {
914 ABISYM( mRunningFromBuildDir ) = true;
915 *sBuildSourcePath() = f.readLine().trimmed();
916 *sBuildOutputPath() = f.readLine().trimmed();
917 QgsDebugMsgLevel( QStringLiteral( "Running from build directory!" ), 4 );
918 QgsDebugMsgLevel( QStringLiteral( "- source directory: %1" ).arg( sBuildSourcePath()->toUtf8().constData() ), 4 );
919 QgsDebugMsgLevel( QStringLiteral( "- output directory of the build: %1" ).arg( sBuildOutputPath()->toUtf8().constData() ), 4 );
920#if defined(_MSC_VER) && !defined(USING_NMAKE) && !defined(USING_NINJA)
921#if QT_VERSION < QT_VERSION_CHECK(5, 15, 0)
922 *sCfgIntDir() = prefix.split( '/', QString::SkipEmptyParts ).last();
923#else
924 *sCfgIntDir() = prefix.split( '/', Qt::SkipEmptyParts ).last();
925#endif
926 qDebug( "- cfg: %s", sCfgIntDir()->toUtf8().constData() );
927#endif
928 }
929 }
930
931 QString prefixPath;
932 if ( getenv( "QGIS_PREFIX_PATH" ) )
933 prefixPath = getenv( "QGIS_PREFIX_PATH" );
934 else
935 {
936#if defined(ANDROID)
937 // this is "/data/data/org.qgis.qgis" in android
938 QDir dir( QDir::homePath() );
939 dir.cdUp();
940 prefixPath = dir.absolutePath();
941#else
942
943#if defined(Q_OS_MACX)
944 prefixPath = appPath;
945#elif defined(Q_OS_WIN)
946 prefixPath = appPath;
947 if ( prefixPath.endsWith( "/bin" ) )
948 prefixPath.chop( 4 );
949#else
950 QDir dir( appPath );
951 // Fix for server which is one level deeper in /usr/lib/cgi-bin
952 if ( appPath.contains( QStringLiteral( "cgi-bin" ) ) )
953 {
954 dir.cdUp();
955 }
956 dir.cdUp(); // Go from /usr/bin or /usr/lib (for server) to /usr
957 prefixPath = dir.absolutePath();
958#endif
959#endif
960 }
961
962 if ( ABISYM( mRunningFromBuildDir ) )
963 return *sBuildOutputPath() + QStringLiteral( "/data" );
964 else
965 return prefixPath + '/' + QStringLiteral( QGIS_DATA_SUBDIR );
966}
967
969{
970 return *sThemeName();
971}
972
973void QgsApplication::setUITheme( const QString &themeName )
974{
975 // Loop all style sheets, find matching name, load it.
976 QHash<QString, QString> themes = QgsApplication::uiThemes();
977 if ( themeName == QLatin1String( "default" ) || !themes.contains( themeName ) )
978 {
979 setThemeName( QStringLiteral( "default" ) );
980 qApp->setStyleSheet( QString() );
981 return;
982 }
983
984 QString path = themes.value( themeName );
985 QString stylesheetname = path + "/style.qss";
986
987 QFile file( stylesheetname );
988 QFile variablesfile( path + "/variables.qss" );
989
990 QFileInfo variableInfo( variablesfile );
991
992 if ( !file.open( QIODevice::ReadOnly ) || ( variableInfo.exists() && !variablesfile.open( QIODevice::ReadOnly ) ) )
993 {
994 return;
995 }
996
997 QString styledata = file.readAll();
998 styledata.replace( QLatin1String( "@theme_path" ), path );
999
1000 if ( variableInfo.exists() )
1001 {
1002 QTextStream in( &variablesfile );
1003 while ( !in.atEnd() )
1004 {
1005 QString line = in.readLine();
1006 // This is a variable
1007 if ( line.startsWith( '@' ) )
1008 {
1009 int index = line.indexOf( ':' );
1010 QString name = line.mid( 0, index );
1011 QString value = line.mid( index + 1, line.length() );
1012 styledata.replace( name, value );
1013 }
1014 }
1015 variablesfile.close();
1016 }
1017 file.close();
1018
1019 if ( Qgis::UI_SCALE_FACTOR != 1.0 )
1020 {
1021 // apply OS-specific UI scale factor to stylesheet's em values
1022 int index = 0;
1023 const static QRegularExpression regex( QStringLiteral( "(?<=[\\s:])([0-9\\.]+)(?=em)" ) );
1024 QRegularExpressionMatch match = regex.match( styledata, index );
1025 while ( match.hasMatch() )
1026 {
1027 index = match.capturedStart();
1028 styledata.remove( index, match.captured( 0 ).length() );
1029 QString number = QString::number( match.captured( 0 ).toDouble() * Qgis::UI_SCALE_FACTOR );
1030 styledata.insert( index, number );
1031 index += number.length();
1032 match = regex.match( styledata, index );
1033 }
1034 }
1035
1036 qApp->setStyleSheet( styledata );
1037
1038 QFile palettefile( path + "/palette.txt" );
1039 QFileInfo paletteInfo( palettefile );
1040 if ( paletteInfo.exists() && palettefile.open( QIODevice::ReadOnly ) )
1041 {
1042 QPalette pal = qApp->palette();
1043 QTextStream in( &palettefile );
1044 while ( !in.atEnd() )
1045 {
1046 QString line = in.readLine();
1047 QStringList parts = line.split( ':' );
1048 if ( parts.count() == 2 )
1049 {
1050 int role = parts.at( 0 ).trimmed().toInt();
1051 QColor color = QgsSymbolLayerUtils::decodeColor( parts.at( 1 ).trimmed() );
1052 pal.setColor( static_cast< QPalette::ColorRole >( role ), color );
1053 }
1054 }
1055 palettefile.close();
1056 qApp->setPalette( pal );
1057 }
1058
1060}
1061
1062QHash<QString, QString> QgsApplication::uiThemes()
1063{
1064 QStringList paths = QStringList() << userThemesFolder() << defaultThemesFolder();
1065 QHash<QString, QString> mapping;
1066 mapping.insert( QStringLiteral( "default" ), QString() );
1067 const auto constPaths = paths;
1068 for ( const QString &path : constPaths )
1069 {
1070 QDir folder( path );
1071 QFileInfoList styleFiles = folder.entryInfoList( QDir::Dirs | QDir::NoDotAndDotDot );
1072 const auto constStyleFiles = styleFiles;
1073 for ( const QFileInfo &info : constStyleFiles )
1074 {
1075 QFileInfo styleFile( info.absoluteFilePath() + "/style.qss" );
1076 if ( !styleFile.exists() )
1077 continue;
1078
1079 QString name = info.baseName();
1080 QString path = info.absoluteFilePath();
1081 mapping.insert( name, path );
1082 }
1083 }
1084 return mapping;
1085}
1086
1088{
1089 return pkgDataPath() + QStringLiteral( "/doc/AUTHORS" );
1090}
1091
1093{
1094 return pkgDataPath() + QStringLiteral( "/doc/CONTRIBUTORS" );
1095}
1097{
1098 return pkgDataPath() + QStringLiteral( "/doc/developersmap.html" );
1099}
1100
1102{
1103 return pkgDataPath() + QStringLiteral( "/doc/SPONSORS" );
1104}
1105
1107{
1108 return pkgDataPath() + QStringLiteral( "/doc/DONORS" );
1109}
1110
1112{
1113 return pkgDataPath() + QStringLiteral( "/doc/TRANSLATORS" );
1114}
1115
1117{
1118 return pkgDataPath() + QStringLiteral( "/doc/LICENSE" );
1119}
1120
1122{
1123 if ( ABISYM( mRunningFromBuildDir ) )
1124 return *sBuildOutputPath() + QStringLiteral( "/i18n/" );
1125 else
1126 return pkgDataPath() + QStringLiteral( "/i18n/" );
1127}
1128
1130{
1131 return pkgDataPath() + QStringLiteral( "/resources/metadata-ISO/" );
1132}
1133
1135{
1136 return pkgDataPath() + QStringLiteral( "/resources/qgis.db" );
1137}
1138
1140{
1141 return *sConfigPath();
1142}
1143
1145{
1146 return qgisSettingsDirPath() + QStringLiteral( "qgis.db" );
1147}
1148
1150{
1151 return *sAuthDbDirPath() + QStringLiteral( "qgis-auth.db" );
1152}
1153
1155{
1156 return QStringLiteral( ":/images/splash/" );
1157}
1158
1160{
1161 return pkgDataPath() + QStringLiteral( "/images/icons/" );
1162}
1163
1165{
1166 if ( ABISYM( mRunningFromBuildDir ) )
1167 {
1168 QString tempCopy = QDir::tempPath() + "/srs6.db";
1169
1170 if ( !QFile( tempCopy ).exists() )
1171 {
1172 QFile f( buildSourcePath() + "/resources/srs6.db" );
1173 if ( !f.copy( tempCopy ) )
1174 {
1175 qFatal( "Could not create temporary copy" );
1176 }
1177 }
1178
1179 return tempCopy;
1180 }
1181 else
1182 {
1183 return pkgDataPath() + QStringLiteral( "/resources/srs.db" );
1184 }
1185}
1186
1187void QgsApplication::setSvgPaths( const QStringList &svgPaths )
1188{
1190 members()->mSvgPathCacheValid = false;
1191}
1192
1194{
1195 static QReadWriteLock lock;
1196
1198
1199 if ( members()->mSvgPathCacheValid )
1200 {
1201 return members()->mSvgPathCache;
1202 }
1203 else
1204 {
1206 //local directories to search when looking for an SVG with a given basename
1207 //defined by user in options dialog
1208 const QStringList pathList = settingsSearchPathsForSVG->value();
1209
1210 // maintain user set order while stripping duplicates
1211 QStringList paths;
1212 for ( const QString &path : pathList )
1213 {
1214 if ( !paths.contains( path ) )
1215 paths.append( path );
1216 }
1217 for ( const QString &path : std::as_const( *sDefaultSvgPaths() ) )
1218 {
1219 if ( !paths.contains( path ) )
1220 paths.append( path );
1221 }
1222 members()->mSvgPathCache = paths;
1223
1224 return paths;
1225 }
1226}
1227
1229{
1230 //local directories to search when looking for an template with a given basename
1231 //defined by user in options dialog
1233}
1234
1235QMap<QString, QString> QgsApplication::systemEnvVars()
1236{
1237 return *sSystemEnvVars();
1238}
1239
1241{
1242 return qgisSettingsDirPath() + QStringLiteral( "symbology-style.db" );
1243}
1244
1246{
1247 const thread_local QRegularExpression regexp( QRegularExpression::anchoredPattern( QStringLiteral( "^[A-Za-z][A-Za-z0-9\\._-]*" ) ) );
1248 return regexp;
1249}
1250
1252{
1253 if ( !sUserName()->isEmpty() )
1254 return *sUserName();
1255
1256#ifdef _MSC_VER
1257 TCHAR name [ UNLEN + 1 ];
1258 DWORD size = UNLEN + 1;
1259
1260 if ( GetUserName( ( TCHAR * )name, &size ) )
1261 {
1262#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
1263 *sUserName() = QString::fromLocal8Bit( name );
1264#else
1265 *sUserName() = QString::fromWCharArray( name );
1266#endif
1267 }
1268
1269
1270#elif QT_CONFIG(process)
1271 QProcess process;
1272
1273 process.start( QStringLiteral( "whoami" ), QStringList() );
1274 process.waitForFinished();
1275 *sUserName() = process.readAllStandardOutput().trimmed();
1276#endif
1277
1278 if ( !sUserName()->isEmpty() )
1279 return *sUserName();
1280
1281 //backup plan - use environment variables
1282 *sUserName() = qgetenv( "USER" );
1283 if ( !sUserName()->isEmpty() )
1284 return *sUserName();
1285
1286 //last resort
1287 *sUserName() = qgetenv( "USERNAME" );
1288 return *sUserName();
1289}
1290
1292{
1293 if ( !sUserFullName()->isEmpty() )
1294 return *sUserFullName();
1295
1296#ifdef _MSC_VER
1297 TCHAR name [ UNLEN + 1 ];
1298 DWORD size = UNLEN + 1;
1299
1300 //note - this only works for accounts connected to domain
1301 if ( GetUserNameEx( NameDisplay, ( TCHAR * )name, &size ) )
1302 {
1303#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
1304 *sUserFullName() = QString::fromLocal8Bit( name );
1305#else
1306 *sUserFullName() = QString::fromWCharArray( name );
1307#endif
1308 }
1309
1310 //fall back to login name
1311 if ( sUserFullName()->isEmpty() )
1312 *sUserFullName() = userLoginName();
1313#elif defined(Q_OS_ANDROID) || defined(__MINGW32__)
1314 *sUserFullName() = QStringLiteral( "Not available" );
1315#else
1316 struct passwd *p = getpwuid( getuid() );
1317
1318 if ( p )
1319 {
1320 QString gecosName = QString( p->pw_gecos );
1321 *sUserFullName() = gecosName.left( gecosName.indexOf( ',', 0 ) );
1322 }
1323
1324#endif
1325
1326 return *sUserFullName();
1327}
1328
1330{
1331#if defined(Q_OS_ANDROID)
1332 return QLatin1String( "android" );
1333#elif defined(Q_OS_MAC)
1334 return QLatin1String( "osx" );
1335#elif defined(Q_OS_WIN)
1336 return QLatin1String( "windows" );
1337#elif defined(Q_OS_LINUX)
1338 return QStringLiteral( "linux" );
1339#elif defined(Q_OS_FREEBSD)
1340 return QStringLiteral( "freebsd" );
1341#elif defined(Q_OS_OPENBSD)
1342 return QStringLiteral( "openbsd" );
1343#elif defined(Q_OS_NETBSD)
1344 return QStringLiteral( "netbsd" );
1345#elif defined(Q_OS_UNIX)
1346 return QLatin1String( "unix" );
1347#else
1348 return QLatin1String( "unknown" );
1349#endif
1350}
1351
1353{
1354#if defined(Q_OS_ANDROID)
1355 return -1;
1356#elif defined(Q_OS_MAC)
1357 return -1;
1358#elif defined(Q_OS_WIN)
1359 MEMORYSTATUSEX memoryStatus;
1360 ZeroMemory( &memoryStatus, sizeof( MEMORYSTATUSEX ) );
1361 memoryStatus.dwLength = sizeof( MEMORYSTATUSEX );
1362 if ( GlobalMemoryStatusEx( &memoryStatus ) )
1363 {
1364 return memoryStatus.ullTotalPhys / ( 1024 * 1024 );
1365 }
1366 else
1367 {
1368 return -1;
1369 }
1370#elif defined(Q_OS_LINUX)
1371 constexpr int megabyte = 1024 * 1024;
1372 struct sysinfo si;
1373 sysinfo( &si );
1374 return si.totalram / megabyte;
1375#elif defined(Q_OS_FREEBSD)
1376 return -1;
1377#elif defined(Q_OS_OPENBSD)
1378 return -1;
1379#elif defined(Q_OS_NETBSD)
1380 return -1;
1381#elif defined(Q_OS_UNIX)
1382 return -1;
1383#else
1384 return -1;
1385#endif
1386}
1387
1389{
1390 return *sPlatformName();
1391}
1392
1394{
1395 if ( !sApplicationFullName()->isEmpty() )
1396 return *sApplicationFullName();
1397
1398 //use environment variables
1399 *sApplicationFullName() = qgetenv( "QGIS_APPLICATION_FULL_NAME" );
1400 if ( !sApplicationFullName()->isEmpty() )
1401 return *sApplicationFullName();
1402
1403 //last resort
1404 QgsSettings settings;
1405 *sApplicationFullName() = settings.value(
1406 QStringLiteral( "/qgis/application_full_name" ),
1407 QStringLiteral( "%1 %2" ).arg( applicationName(), platform() )
1408 ).toString();
1409 return *sApplicationFullName();
1410}
1411
1413{
1415 {
1417 // don't differentiate en_US and en_GB
1418 if ( locale.startsWith( QLatin1String( "en" ), Qt::CaseInsensitive ) )
1419 {
1420 return locale.left( 2 );
1421 }
1422
1423 return locale;
1424 }
1425 else
1426 {
1427 return QLocale().name().left( 2 );
1428 }
1429}
1430
1431void QgsApplication::setLocale( const QLocale &locale )
1432{
1433 QLocale::setDefault( locale );
1434 emit instance()->localeChanged();
1435}
1436
1438{
1439 return qgisSettingsDirPath() + QStringLiteral( "/themes" );
1440}
1441
1443{
1444 return pkgDataPath() + QStringLiteral( "/resources/symbology-style.xml" );
1445}
1446
1448{
1449 return pkgDataPath() + QStringLiteral( "/resources/themes" );
1450}
1451
1453{
1454 return pkgDataPath() + QStringLiteral( "/resources/server/" );
1455}
1456
1458{
1459 return *sLibraryPath();
1460}
1461
1463{
1464 return *sLibexecPath();
1465}
1466
1468{
1469 return *sQmlImportPath();
1470}
1471
1473{
1474 return ( htonl( 1 ) == 1 ) ? XDR : NDR;
1475}
1476
1478{
1479 if ( !ABISYM( mInitialized ) && QgsApplication::instance() )
1480 {
1481 init( *sProfilePath() );
1482 }
1483
1484 // set the provider plugin path (this creates provider registry)
1486
1487 // create data item provider registry
1489
1490 // create project instance if doesn't exist
1492
1493 // Initialize authentication manager and connect to database
1495
1496 // Make sure we have a NAM created on the main thread.
1497 // Note that this might call QgsApplication::authManager to
1498 // setup the proxy configuration that's why it needs to be
1499 // called after the QgsAuthManager instance has been created
1501
1502}
1503
1505{
1506 if ( auto *lInstance = instance() )
1507 {
1508 if ( !lInstance->mAuthManager )
1509 {
1510 lInstance->mAuthManager = QgsAuthManager::instance();
1511 }
1512 return lInstance->mAuthManager;
1513 }
1514 else
1515 {
1516 // no QgsApplication instance
1517 if ( !sAuthManager )
1518 sAuthManager = QgsAuthManager::instance();
1519 return sAuthManager;
1520 }
1521}
1522
1523
1525{
1526 // make sure all threads are done before exiting
1527 QThreadPool::globalInstance()->waitForDone();
1528
1529 // don't create to delete
1530 if ( auto *lInstance = instance() )
1531 delete lInstance->mAuthManager;
1532 else
1533 delete sAuthManager;
1534
1535 //Ensure that all remaining deleteLater QObjects are actually deleted before we exit.
1536 QgsApplication::sendPostedEvents( nullptr, QEvent::DeferredDelete );
1537
1538 //delete all registered functions from expression engine (see above comment)
1540
1541 // avoid creating instance just to delete it!
1542 if ( QgsProject::sProject )
1543 delete QgsProject::instance();
1544
1545 //Ensure that providers/layers which called deleteLater on objects as part of their cleanup
1546 //result in fully deleted objects before we do the provider registry cleanup.
1547 //E.g. the QgsOgrConnPool instance has deleteLater calls when unrefing layers, so clearing
1548 //the project above has not yet fully cleaned up OGR objects, which we MUST do before
1549 //cleaning up the provider
1550 QgsApplication::sendPostedEvents( nullptr, QEvent::DeferredDelete );
1551
1552 // avoid creating instance just to delete it!
1553 if ( QgsProviderRegistry::exists() )
1555
1556 invalidateCaches();
1557
1559
1560 // tear-down GDAL/OGR
1561 OGRCleanupAll();
1562 GDALDestroyDriverManager();
1563}
1564
1566{
1567 QString myEnvironmentVar( getenv( "QGIS_PREFIX_PATH" ) );
1568 QString myState = tr( "Application state:\n"
1569 "QGIS_PREFIX_PATH env var:\t\t%1\n"
1570 "Prefix:\t\t%2\n"
1571 "Plugin Path:\t\t%3\n"
1572 "Package Data Path:\t%4\n"
1573 "Active Theme Name:\t%5\n"
1574 "Active Theme Path:\t%6\n"
1575 "Default Theme Path:\t%7\n"
1576 "SVG Search Paths:\t%8\n"
1577 "User DB Path:\t%9\n"
1578 "Auth DB Path:\t%10\n" )
1579 .arg( myEnvironmentVar,
1580 prefixPath(),
1581 pluginPath(),
1582 pkgDataPath(),
1583 themeName(),
1586 svgPaths().join( tr( "\n\t\t", "match indentation of application state" ) ),
1588 .arg( qgisAuthDatabaseFilePath() );
1589 return myState;
1590}
1591
1593{
1594 //
1595 // Make the style sheet desktop preferences aware by using qapplication
1596 // palette as a basis for colors where appropriate
1597 //
1598 // QColor myColor1 = palette().highlight().color();
1599 QColor myColor1( Qt::lightGray );
1600 QColor myColor2 = myColor1;
1601 myColor2 = myColor2.lighter( 110 ); //10% lighter
1602 QString myStyle;
1603 myStyle = QStringLiteral( ".overview{"
1604 " font: 1.82em;"
1605 " font-weight: bold;"
1606 "}"
1607 "body{"
1608 " background: white;"
1609 " color: black;"
1610 " font-family: 'Lato', 'Open Sans', 'Lucida Grande', 'Segoe UI', 'Arial', sans-serif;"
1611 " width: 100%;"
1612 "}"
1613 "h1{ background-color: #F6F6F6;"
1614 " color: #589632; " // from http://qgis.org/en/site/getinvolved/styleguide.html
1615 " font-size: x-large; "
1616 " font-weight: normal;"
1617 " background: none;"
1618 " padding: 0.75em 0 0;"
1619 " margin: 0;"
1620 " line-height: 3em;"
1621 "}"
1622 "h2{ background-color: #F6F6F6;"
1623 " color: #589632; " // from http://qgis.org/en/site/getinvolved/styleguide.html
1624 " font-size: medium; "
1625 " font-weight: normal;"
1626 " background: none;"
1627 " padding: 0.75em 0 0;"
1628 " margin: 0;"
1629 " line-height: 1.1em;"
1630 "}"
1631 "h3{ background-color: #F6F6F6;"
1632 " color: #93b023;" // from http://qgis.org/en/site/getinvolved/styleguide.html
1633 " font-weight: bold;"
1634 " font-size: large;"
1635 " text-align: left;"
1636 " border-bottom: 5px solid #DCEB5C;"
1637 "}"
1638 "h4{ background-color: #F6F6F6;"
1639 " color: #93b023;" // from http://qgis.org/en/site/getinvolved/styleguide.html
1640 " font-weight: bold;"
1641 " font-size: medium;"
1642 " text-align: left;"
1643 "}"
1644 "h5{ background-color: #F6F6F6;"
1645 " color: #93b023;" // from http://qgis.org/en/site/getinvolved/styleguide.html
1646 " font-weight: bold;"
1647 " font-size: small;"
1648 " text-align: left;"
1649 "}"
1650 "a{ color: #729FCF;"
1651 " font-family: arial,sans-serif;"
1652 "}"
1653 "label{ background-color: #FFFFCC;"
1654 " border: 1px solid black;"
1655 " margin: 1px;"
1656 " padding: 0px 3px; "
1657 " font-size: small;"
1658 "}"
1659 "th .strong {"
1660 " font-weight: bold;"
1661 "}"
1662 "hr {"
1663 " border: 0;"
1664 " height: 0;"
1665 " border-top: 1px solid black;"
1666 "}"
1667 ".list-view .highlight {"
1668 " text-align: left;"
1669 " border: 0px;"
1670 " width: 20%;"
1671 " padding-right: 15px;"
1672 " padding-left: 20px;"
1673 " font-weight: bold;"
1674 "}"
1675 ".tabular-view .odd-row {"
1676 " background-color: #f9f9f9;"
1677 "}"
1678 ".section {"
1679 " font-weight: bold;"
1680 " padding-top:25px;"
1681 "}" );
1682
1683 // We have some subtle differences between Qt based style and QWebKit style
1684 switch ( styleSheetType )
1685 {
1686 case StyleSheetType::Qt:
1687 myStyle += QStringLiteral(
1688 ".tabular-view{ "
1689 " border-collapse: collapse;"
1690 " width: 95%;"
1691 "}"
1692 ".tabular-view th, .tabular-view td { "
1693 " border:1px solid black;"
1694 "}" );
1695 break;
1696
1697 case StyleSheetType::WebBrowser:
1698 myStyle += QStringLiteral(
1699 "body { "
1700 " margin: auto;"
1701 " width: 97%;"
1702 "}"
1703 "table.tabular-view, table.list-view { "
1704 " border-collapse: collapse;"
1705 " table-layout:fixed;"
1706 " width: 100% !important;"
1707 " font-size: 90%;"
1708 "}"
1709 // Override
1710 "h1 { "
1711 " line-height: inherit;"
1712 "}"
1713 "td, th {"
1714 " word-wrap: break-word; "
1715 " vertical-align: top;"
1716 "}"
1717 // Set first column width
1718 ".list-view th:first-child, .list-view td:first-child {"
1719 " width: 20%;"
1720 "}"
1721 ".list-view.highlight { "
1722 " padding-left: inherit; "
1723 "}"
1724 // Set first column width for inner tables
1725 ".tabular-view th:first-child, .tabular-view td:first-child { "
1726 " width: 20%; "
1727 "}"
1728 // Makes titles bg stand up
1729 ".tabular-view th.strong { "
1730 " background-color: #eee; "
1731 "}"
1732 // Give some visual appearance to those ugly nested tables
1733 ".tabular-view th, .tabular-view td { "
1734 " border: 1px solid #eee;"
1735 "}"
1736 );
1737 break;
1738 }
1739
1740 return myStyle;
1741}
1742
1744{
1745 if ( 0 >= OGRGetDriverCount() )
1746 {
1747 OGRRegisterAll();
1748 }
1749}
1750
1751QString QgsApplication::absolutePathToRelativePath( const QString &aPath, const QString &targetPath )
1752{
1753 QString aPathUrl = aPath;
1754 QString tPathUrl = targetPath;
1755#if defined( Q_OS_WIN )
1756 const Qt::CaseSensitivity cs = Qt::CaseInsensitive;
1757
1758 aPathUrl.replace( '\\', '/' );
1759 if ( aPathUrl.startsWith( "//" ) )
1760 {
1761 // keep UNC prefix
1762 aPathUrl = "\\\\" + aPathUrl.mid( 2 );
1763 }
1764
1765 tPathUrl.replace( '\\', '/' );
1766 if ( tPathUrl.startsWith( "//" ) )
1767 {
1768 // keep UNC prefix
1769 tPathUrl = "\\\\" + tPathUrl.mid( 2 );
1770 }
1771#else
1772 const Qt::CaseSensitivity cs = Qt::CaseSensitive;
1773#endif
1774
1775#if QT_VERSION < QT_VERSION_CHECK(5, 15, 0)
1776 QStringList targetElems = tPathUrl.split( '/', QString::SkipEmptyParts );
1777 QStringList aPathElems = aPathUrl.split( '/', QString::SkipEmptyParts );
1778#else
1779 QStringList targetElems = tPathUrl.split( '/', Qt::SkipEmptyParts );
1780 QStringList aPathElems = aPathUrl.split( '/', Qt::SkipEmptyParts );
1781#endif
1782
1783 targetElems.removeAll( QStringLiteral( "." ) );
1784 aPathElems.removeAll( QStringLiteral( "." ) );
1785
1786 // remove common part
1787 int n = 0;
1788 while ( !aPathElems.isEmpty() &&
1789 !targetElems.isEmpty() &&
1790 aPathElems[0].compare( targetElems[0], cs ) == 0 )
1791 {
1792 aPathElems.removeFirst();
1793 targetElems.removeFirst();
1794 n++;
1795 }
1796
1797 if ( n == 0 )
1798 {
1799 // no common parts; might not even be a file
1800 return aPathUrl;
1801 }
1802
1803 if ( !targetElems.isEmpty() )
1804 {
1805 // go up to the common directory
1806 for ( int i = 0; i < targetElems.size(); i++ )
1807 {
1808 aPathElems.insert( 0, QStringLiteral( ".." ) );
1809 }
1810 }
1811 else
1812 {
1813 // let it start with . nevertheless,
1814 // so relative path always start with either ./ or ../
1815 aPathElems.insert( 0, QStringLiteral( "." ) );
1816 }
1817
1818 return aPathElems.join( QLatin1Char( '/' ) );
1819}
1820
1821QString QgsApplication::relativePathToAbsolutePath( const QString &rpath, const QString &targetPath )
1822{
1823 // relative path should always start with ./ or ../
1824 if ( !rpath.startsWith( QLatin1String( "./" ) ) && !rpath.startsWith( QLatin1String( "../" ) ) )
1825 {
1826 return rpath;
1827 }
1828
1829 QString rPathUrl = rpath;
1830 QString targetPathUrl = targetPath;
1831
1832#if defined(Q_OS_WIN)
1833 rPathUrl.replace( '\\', '/' );
1834 targetPathUrl.replace( '\\', '/' );
1835
1836 bool uncPath = targetPathUrl.startsWith( "//" );
1837#endif
1838
1839#if QT_VERSION < QT_VERSION_CHECK(5, 15, 0)
1840 QStringList srcElems = rPathUrl.split( '/', QString::SkipEmptyParts );
1841 QStringList targetElems = targetPathUrl.split( '/', QString::SkipEmptyParts );
1842#else
1843 QStringList srcElems = rPathUrl.split( '/', Qt::SkipEmptyParts );
1844 QStringList targetElems = targetPathUrl.split( '/', Qt::SkipEmptyParts );
1845#endif
1846
1847#if defined(Q_OS_WIN)
1848 if ( uncPath )
1849 {
1850 targetElems.insert( 0, "" );
1851 targetElems.insert( 0, "" );
1852 }
1853#endif
1854
1855 // append source path elements
1856 targetElems << srcElems;
1857 targetElems.removeAll( QStringLiteral( "." ) );
1858
1859 // resolve ..
1860 int pos;
1861 while ( ( pos = targetElems.indexOf( QLatin1String( ".." ) ) ) > 0 )
1862 {
1863 // remove preceding element and ..
1864 targetElems.removeAt( pos - 1 );
1865 targetElems.removeAt( pos - 1 );
1866 }
1867
1868#if !defined(Q_OS_WIN)
1869 // make path absolute
1870 targetElems.prepend( QString() );
1871#endif
1872
1873 return targetElems.join( QLatin1Char( '/' ) );
1874}
1875
1877{
1878 return *sBuildSourcePath();
1879}
1880
1882{
1883 return *sBuildOutputPath();
1884}
1885
1886#if defined(_MSC_VER) && !defined(USING_NMAKE) && !defined(USING_NINJA)
1887QString QgsApplication::cfgIntDir()
1888{
1889 return *sCfgIntDir();
1890}
1891#endif
1892
1893void QgsApplication::skipGdalDriver( const QString &driver )
1894{
1895 if ( sGdalSkipList()->contains( driver ) || driver.isEmpty() )
1896 {
1897 return;
1898 }
1899 *sGdalSkipList() << driver;
1901}
1902
1903void QgsApplication::restoreGdalDriver( const QString &driver )
1904{
1905 if ( !sGdalSkipList()->contains( driver ) )
1906 {
1907 return;
1908 }
1909 int myPos = sGdalSkipList()->indexOf( driver );
1910 if ( myPos >= 0 )
1911 {
1912 sGdalSkipList()->removeAt( myPos );
1913 }
1915}
1916
1918{
1919 return *sGdalSkipList();
1920}
1921
1922void QgsApplication::setSkippedGdalDrivers( const QStringList &skippedGdalDrivers,
1923 const QStringList &deferredSkippedGdalDrivers )
1924{
1925 *sGdalSkipList() = skippedGdalDrivers;
1926 *sDeferredSkippedGdalDrivers() = deferredSkippedGdalDrivers;
1927
1928 QgsSettings settings;
1929 settings.setValue( QStringLiteral( "gdal/skipDrivers" ), skippedGdalDrivers.join( QLatin1Char( ',' ) ) );
1930
1932}
1933
1935{
1936 QgsSettings settings;
1937 QString joinedList, delimiter;
1938 if ( settings.contains( QStringLiteral( "gdal/skipDrivers" ) ) )
1939 {
1940 joinedList = settings.value( QStringLiteral( "gdal/skipDrivers" ), QString() ).toString();
1941 delimiter = QStringLiteral( "," );
1942 }
1943 else
1944 {
1945 joinedList = settings.value( QStringLiteral( "gdal/skipList" ), QString() ).toString();
1946 delimiter = QStringLiteral( " " );
1947 }
1948 QStringList myList;
1949 if ( !joinedList.isEmpty() )
1950 {
1951 myList = joinedList.split( delimiter );
1952 }
1953 *sGdalSkipList() = myList;
1955}
1956
1958{
1959 return *sDeferredSkippedGdalDrivers();
1960}
1961
1963{
1964 sGdalSkipList()->removeDuplicates();
1965 QStringList realDisabledDriverList;
1966 for ( const auto &driverName : *sGdalSkipList() )
1967 {
1968 if ( !sDeferredSkippedGdalDrivers()->contains( driverName ) )
1969 realDisabledDriverList << driverName;
1970 }
1971 QString myDriverList = realDisabledDriverList.join( ',' );
1972 QgsDebugMsgLevel( QStringLiteral( "Gdal Skipped driver list set to:" ), 2 );
1973 QgsDebugMsgLevel( myDriverList, 2 );
1974 CPLSetConfigOption( "GDAL_SKIP", myDriverList.toUtf8() );
1975 GDALAllRegister(); //to update driver list and skip missing ones
1976}
1977
1979{
1980 QString folder = userThemesFolder();
1981 QDir myDir( folder );
1982 if ( !myDir.exists() )
1983 {
1984 myDir.mkpath( folder );
1985 }
1986
1987 return true;
1988}
1989
1990void QgsApplication::copyPath( const QString &src, const QString &dst )
1991{
1992 QDir dir( src );
1993 if ( ! dir.exists() )
1994 return;
1995
1996 const auto subDirectories = dir.entryList( QDir::Dirs | QDir::NoDotAndDotDot );
1997 for ( const QString &d : subDirectories )
1998 {
1999 QString dst_path = dst + QDir::separator() + d;
2000 dir.mkpath( dst_path );
2001 copyPath( src + QDir::separator() + d, dst_path );
2002 }
2003
2004 const auto files = dir.entryList( QDir::Files );
2005 for ( const QString &f : files )
2006 {
2007 QFile::copy( src + QDir::separator() + f, dst + QDir::separator() + f );
2008 }
2009}
2010
2012{
2013 //read values from QgsSettings
2014 QgsSettings settings;
2015
2016 QVariantMap variables;
2017
2018 //check if settings contains any variables
2019 settings.beginGroup( "variables" );
2020 QStringList childKeys = settings.childKeys();
2021 for ( QStringList::const_iterator it = childKeys.constBegin(); it != childKeys.constEnd(); ++it )
2022 {
2023 QString name = *it;
2024 variables.insert( name, settings.value( name ) );
2025 }
2026
2027 return variables;
2028}
2029
2030void QgsApplication::setCustomVariables( const QVariantMap &variables )
2031{
2032 QgsSettings settings;
2033
2034 QVariantMap::const_iterator it = variables.constBegin();
2035 settings.beginGroup( "variables" );
2036 settings.remove( "" );
2037 for ( ; it != variables.constEnd(); ++it )
2038 {
2039 settings.setValue( it.key(), it.value() );
2040 }
2041
2043}
2044
2045void QgsApplication::setCustomVariable( const QString &name, const QVariant &value )
2046{
2047 // save variable to settings
2048 QgsSettings settings;
2049
2050 settings.setValue( QStringLiteral( "variables/" ) + name, value );
2051
2053}
2054
2055int QgsApplication::scaleIconSize( int standardSize, bool applyDevicePixelRatio )
2056{
2057 QFontMetrics fm( ( QFont() ) );
2058 const double scale = 1.1 * standardSize / 24;
2059 int scaledIconSize = static_cast< int >( std::floor( std::max( Qgis::UI_SCALE_FACTOR * fm.height() * scale, static_cast< double >( standardSize ) ) ) );
2060 if ( applyDevicePixelRatio )
2061 {
2062 if ( QWidget *activeWindow = QApplication::activeWindow() )
2063 scaledIconSize *= ( activeWindow->screen() ? QApplication::activeWindow()->screen()->devicePixelRatio() : 1 );
2064 }
2065 return scaledIconSize;
2066}
2067
2069{
2071}
2072
2073void QgsApplication::setTranslation( const QString &translation )
2074{
2075 *sTranslation() = translation;
2076}
2077
2079{
2080 return *sTranslation();
2081}
2082
2084{
2085 emit requestForTranslatableObjects( translationContext );
2086}
2087
2089{
2090 ApplicationMembers *appMembers = members();
2091 if ( appMembers->mNullRepresentation.isNull() )
2092 {
2093 appMembers->mNullRepresentation = QgsSettings().value( QStringLiteral( "qgis/nullValue" ), QStringLiteral( "NULL" ) ).toString();
2094 }
2095 return appMembers->mNullRepresentation;
2096}
2097
2098void QgsApplication::setNullRepresentation( const QString &nullRepresentation )
2099{
2100 ApplicationMembers *appMembers = members();
2101 if ( !appMembers || appMembers->mNullRepresentation == nullRepresentation )
2102 return;
2103
2104 appMembers->mNullRepresentation = nullRepresentation;
2105 QgsSettings().setValue( QStringLiteral( "qgis/nullValue" ), nullRepresentation );
2106
2107 QgsApplication *app = instance();
2108 if ( app )
2109 emit app->nullRepresentationChanged();
2110}
2111
2113{
2114 return members()->mActionScopeRegistry;
2115}
2116
2117bool QgsApplication::createDatabase( QString *errorMessage )
2118{
2119 // set a working directory up for gdal to write .aux.xml files into
2120 // for cases where the raster dir is read only to the user
2121 // if the env var is already set it will be used preferentially
2122 QString myPamPath = qgisSettingsDirPath() + QStringLiteral( "gdal_pam/" );
2123 QDir myDir( myPamPath );
2124 if ( !myDir.exists() )
2125 {
2126 myDir.mkpath( myPamPath ); //fail silently
2127 }
2128
2129#if defined(Q_OS_WIN)
2130 CPLSetConfigOption( "GDAL_PAM_PROXY_DIR", myPamPath.toUtf8() );
2131#else
2132 //under other OS's we use an environment var so the user can
2133 //override the path if he likes
2134 int myChangeFlag = 0; //whether we want to force the env var to change
2135 setenv( "GDAL_PAM_PROXY_DIR", myPamPath.toUtf8(), myChangeFlag );
2136#endif
2137
2138 // Check qgis.db and make private copy if necessary
2139 QFile qgisPrivateDbFile( QgsApplication::qgisUserDatabaseFilePath() );
2140
2141 // first we look for ~/.qgis/qgis.db
2142 if ( !qgisPrivateDbFile.exists() )
2143 {
2144 // if it doesn't exist we copy it in from the global resources dir
2145 QString qgisMasterDbFileName = QgsApplication::qgisMasterDatabaseFilePath();
2146 QFile masterFile( qgisMasterDbFileName );
2147
2148 // Must be sure there is destination directory ~/.qgis
2149 QDir().mkpath( QgsApplication::qgisSettingsDirPath() );
2150
2151 //now copy the master file into the users .qgis dir
2152 bool isDbFileCopied = masterFile.copy( qgisPrivateDbFile.fileName() );
2153
2154 if ( !isDbFileCopied )
2155 {
2156 if ( errorMessage )
2157 {
2158 *errorMessage = tr( "[ERROR] Can not make qgis.db private copy" );
2159 }
2160 return false;
2161 }
2162
2163 QFile::Permissions perms = QFile( qgisPrivateDbFile.fileName() ).permissions();
2164 if ( !( perms & QFile::WriteOwner ) )
2165 {
2166 if ( !qgisPrivateDbFile.setPermissions( perms | QFile::WriteOwner ) )
2167 {
2168 if ( errorMessage )
2169 {
2170 *errorMessage = tr( "Can not make '%1' user writable" ).arg( qgisPrivateDbFile.fileName() );
2171 }
2172 return false;
2173 }
2174 }
2175 }
2176 else
2177 {
2178 // migrate if necessary
2180 if ( database.open( QgsApplication::qgisUserDatabaseFilePath() ) != SQLITE_OK )
2181 {
2182 if ( errorMessage )
2183 {
2184 *errorMessage = tr( "Could not open qgis.db" );
2185 }
2186 return false;
2187 }
2188
2189 char *errmsg = nullptr;
2190 int res = sqlite3_exec( database.get(), "SELECT srs_id FROM tbl_srs LIMIT 0", nullptr, nullptr, &errmsg );
2191 if ( res != SQLITE_OK )
2192 {
2193 sqlite3_free( errmsg );
2194
2195 // qgis.db is missing tbl_srs, create it
2196 if ( sqlite3_exec( database.get(),
2197 "DROP INDEX IF EXISTS idx_srsauthid;"
2198 "CREATE TABLE tbl_srs ("
2199 "srs_id INTEGER PRIMARY KEY,"
2200 "description text NOT NULL,"
2201 "projection_acronym text NOT NULL,"
2202 "ellipsoid_acronym NOT NULL,"
2203 "parameters text NOT NULL,"
2204 "srid integer,"
2205 "auth_name varchar,"
2206 "auth_id varchar,"
2207 "is_geo integer NOT NULL,"
2208 "deprecated boolean,"
2209 "wkt text);"
2210 "CREATE INDEX idx_srsauthid on tbl_srs(auth_name,auth_id);", nullptr, nullptr, &errmsg ) != SQLITE_OK )
2211 {
2212 if ( errorMessage )
2213 {
2214 *errorMessage = tr( "Creation of missing tbl_srs in the private qgis.db failed.\n%1" ).arg( QString::fromUtf8( errmsg ) );
2215 }
2216 sqlite3_free( errmsg );
2217 return false;
2218 }
2219 }
2220 else
2221 {
2222 // test if wkt column exists in database
2223 res = sqlite3_exec( database.get(), "SELECT wkt FROM tbl_srs LIMIT 0", nullptr, nullptr, &errmsg );
2224 if ( res != SQLITE_OK )
2225 {
2226 // need to add wkt column
2227 sqlite3_free( errmsg );
2228 if ( sqlite3_exec( database.get(),
2229 "DROP INDEX IF EXISTS idx_srsauthid;"
2230 "DROP TABLE IF EXISTS tbl_srs_bak;"
2231 "ALTER TABLE tbl_srs RENAME TO tbl_srs_bak;"
2232 "CREATE TABLE tbl_srs ("
2233 "srs_id INTEGER PRIMARY KEY,"
2234 "description text NOT NULL,"
2235 "projection_acronym text NOT NULL,"
2236 "ellipsoid_acronym NOT NULL,"
2237 "parameters text NOT NULL,"
2238 "srid integer,"
2239 "auth_name varchar,"
2240 "auth_id varchar,"
2241 "is_geo integer NOT NULL,"
2242 "deprecated boolean,"
2243 "wkt text);"
2244 "CREATE INDEX idx_srsauthid on tbl_srs(auth_name,auth_id);"
2245 "INSERT INTO tbl_srs(srs_id,description,projection_acronym,ellipsoid_acronym,parameters,srid,auth_name,auth_id,is_geo,deprecated) SELECT srs_id,description,projection_acronym,ellipsoid_acronym,parameters,srid,'','',is_geo,0 FROM tbl_srs_bak;"
2246 "DROP TABLE tbl_srs_bak", nullptr, nullptr, &errmsg ) != SQLITE_OK )
2247 {
2248 if ( errorMessage )
2249 {
2250 *errorMessage = tr( "Migration of private qgis.db failed.\n%1" ).arg( QString::fromUtf8( errmsg ) );
2251 }
2252 sqlite3_free( errmsg );
2253 return false;
2254 }
2255 }
2256 }
2257
2258 res = sqlite3_exec( database.get(), "SELECT acronym FROM tbl_projection LIMIT 0", nullptr, nullptr, &errmsg );
2259 if ( res != SQLITE_OK )
2260 {
2261 sqlite3_free( errmsg );
2262
2263 // qgis.db is missing tbl_projection, create it
2264 if ( sqlite3_exec( database.get(),
2265 "CREATE TABLE tbl_projection ("
2266 "acronym varchar(20) NOT NULL PRIMARY KEY,"
2267 "name varchar(255) NOT NULL default '',"
2268 "notes varchar(255) NOT NULL default '',"
2269 "parameters varchar(255) NOT NULL default ''"
2270 ")", nullptr, nullptr, &errmsg ) != SQLITE_OK )
2271 {
2272 if ( errorMessage )
2273 {
2274 *errorMessage = tr( "Creation of missing tbl_projection in the private qgis.db failed.\n%1" ).arg( QString::fromUtf8( errmsg ) );
2275 }
2276 sqlite3_free( errmsg );
2277 return false;
2278 }
2279 }
2280
2281 res = sqlite3_exec( database.get(), "SELECT epsg FROM tbl_srs LIMIT 0", nullptr, nullptr, &errmsg );
2282 if ( res == SQLITE_OK )
2283 {
2284 // epsg column exists => need migration
2285 if ( sqlite3_exec( database.get(),
2286 "DROP INDEX IF EXISTS idx_srsauthid;"
2287 "DROP TABLE IF EXISTS tbl_srs_bak;"
2288 "ALTER TABLE tbl_srs RENAME TO tbl_srs_bak;"
2289 "CREATE TABLE tbl_srs ("
2290 "srs_id INTEGER PRIMARY KEY,"
2291 "description text NOT NULL,"
2292 "projection_acronym text NOT NULL,"
2293 "ellipsoid_acronym NOT NULL,"
2294 "parameters text NOT NULL,"
2295 "srid integer,"
2296 "auth_name varchar,"
2297 "auth_id varchar,"
2298 "is_geo integer NOT NULL,"
2299 "deprecated boolean,"
2300 "wkt text);"
2301 "CREATE INDEX idx_srsauthid on tbl_srs(auth_name,auth_id);"
2302 "INSERT INTO tbl_srs(srs_id,description,projection_acronym,ellipsoid_acronym,parameters,srid,auth_name,auth_id,is_geo,deprecated) SELECT srs_id,description,projection_acronym,ellipsoid_acronym,parameters,srid,'','',is_geo,0 FROM tbl_srs_bak;"
2303 "DROP TABLE tbl_srs_bak", nullptr, nullptr, &errmsg ) != SQLITE_OK )
2304 {
2305 if ( errorMessage )
2306 {
2307 *errorMessage = tr( "Migration of private qgis.db failed.\n%1" ).arg( QString::fromUtf8( errmsg ) );
2308 }
2309 sqlite3_free( errmsg );
2310 return false;
2311 }
2312 }
2313 else
2314 {
2315 sqlite3_free( errmsg );
2316 }
2317
2318 if ( sqlite3_exec( database.get(), "DROP VIEW vw_srs", nullptr, nullptr, &errmsg ) != SQLITE_OK )
2319 {
2320 QgsDebugMsg( QStringLiteral( "vw_srs didn't exists in private qgis.db: %1" ).arg( errmsg ) );
2321 }
2322
2323 if ( sqlite3_exec( database.get(),
2324 "CREATE VIEW vw_srs AS"
2325 " SELECT"
2326 " a.description AS description"
2327 ",a.srs_id AS srs_id"
2328 ",a.is_geo AS is_geo"
2329 ",coalesce(b.name,a.projection_acronym) AS name"
2330 ",a.parameters AS parameters"
2331 ",a.auth_name AS auth_name"
2332 ",a.auth_id AS auth_id"
2333 ",a.deprecated AS deprecated"
2334 " FROM tbl_srs a"
2335 " LEFT OUTER JOIN tbl_projection b ON a.projection_acronym=b.acronym"
2336 " ORDER BY coalesce(b.name,a.projection_acronym),a.description", nullptr, nullptr, &errmsg ) != SQLITE_OK )
2337 {
2338 if ( errorMessage )
2339 {
2340 *errorMessage = tr( "Update of view in private qgis.db failed.\n%1" ).arg( QString::fromUtf8( errmsg ) );
2341 }
2342 sqlite3_free( errmsg );
2343 return false;
2344 }
2345 }
2346 return true;
2347}
2348
2349void QgsApplication::setMaxThreads( int maxThreads )
2350{
2351 QgsDebugMsgLevel( QStringLiteral( "maxThreads: %1" ).arg( maxThreads ), 2 );
2352
2353 // make sure value is between 1 and #cores, if not set to -1 (use #cores)
2354 if ( maxThreads < 1 || maxThreads > QThread::idealThreadCount() )
2355 maxThreads = -1;
2356
2357 // force at least 2 threads -- anything less risks deadlocks within Qt itself (e.g in QImage internal mutexes)
2358 if ( maxThreads > 0 && maxThreads < 2 )
2359 maxThreads = 2;
2360
2361 // save value
2362 ABISYM( sMaxThreads ) = maxThreads;
2363
2364 // if -1 use #cores
2365 if ( maxThreads == -1 )
2366 maxThreads = QThread::idealThreadCount();
2367
2368 // set max thread count in QThreadPool
2369 QThreadPool::globalInstance()->setMaxThreadCount( maxThreads );
2370 QgsDebugMsgLevel( QStringLiteral( "set QThreadPool max thread count to %1" ).arg( QThreadPool::globalInstance()->maxThreadCount() ), 2 );
2371}
2372
2374{
2375 return members()->mTaskManager;
2376}
2377
2379{
2380 return members()->mSettingsRegistryCore;
2381}
2382
2384{
2385 return members()->mColorSchemeRegistry;
2386}
2387
2389{
2390 return members()->mPaintEffectRegistry;
2391}
2392
2394{
2395 return members()->mRendererRegistry;
2396}
2397
2399{
2400 return members()->mRasterRendererRegistry;
2401}
2402
2404{
2405 return members()->mPointCloudRendererRegistry;
2406}
2407
2409{
2410 if ( auto *lInstance = instance() )
2411 {
2412 if ( !instance()->mDataItemProviderRegistry )
2413 {
2414 lInstance->mDataItemProviderRegistry = new QgsDataItemProviderRegistry();
2415 }
2416 return lInstance->mDataItemProviderRegistry;
2417 }
2418 else
2419 {
2420 // no QgsApplication instance
2421 static QgsDataItemProviderRegistry *sDataItemProviderRegistry = nullptr;
2422 if ( !sDataItemProviderRegistry )
2423 sDataItemProviderRegistry = new QgsDataItemProviderRegistry();
2424 return sDataItemProviderRegistry;
2425 }
2426}
2427
2429{
2430 return members()->mCrsRegistry;
2431}
2432
2434{
2435 return members()->mSvgCache;
2436}
2437
2439{
2440 return members()->mImageCache;
2441}
2442
2444{
2445 return members()->mSourceCache;
2446}
2447
2449{
2450 return members()->mNetworkContentFetcherRegistry;
2451}
2452
2454{
2455 return members()->mValidityCheckRegistry;
2456}
2457
2459{
2460 return members()->mSymbolLayerRegistry;
2461}
2462
2464{
2465 return members()->mCalloutRegistry;
2466}
2467
2469{
2470 return members()->mLayoutItemRegistry;
2471}
2472
2474{
2475 return members()->mAnnotationItemRegistry;
2476}
2477
2479{
2480 return members()->mGpsConnectionRegistry;
2481}
2482
2484{
2485 return members()->mGpsBabelFormatRegistry;
2486}
2487
2489{
2490 return members()->mPluginLayerRegistry;
2491}
2492
2494{
2495 return members()->mClassificationMethodRegistry;
2496}
2497
2499{
2500 return members()->mBookmarkManager;
2501}
2502
2504{
2505 return members()->mTileDownloadManager;
2506}
2507
2509{
2510 return members()->mRecentStyleHandler;
2511}
2512
2514{
2515 return members()->mQueryLogger;
2516}
2517
2519{
2520 return members()->mStyleModel;
2521}
2522
2524{
2525 return members()->mFontManager;
2526}
2527
2529{
2530 return members()->mMessageLog;
2531}
2532
2534{
2535 return members()->mProcessingRegistry;
2536}
2537
2539{
2540 return members()->mConnectionRegistry;
2541}
2542
2544{
2545 return members()->mLayerMetadataProviderRegistry;
2546}
2547
2549{
2550 return members()->mPageSizeRegistry;
2551}
2552
2554{
2555 return members()->mAnnotationRegistry;
2556}
2557
2559{
2560 return members()->mNumericFormatRegistry;
2561}
2562
2564{
2565 return members()->mFieldFormatterRegistry;
2566}
2567
2569{
2570 return members()->m3DRendererRegistry;
2571}
2572
2574{
2575 return members()->m3DSymbolRegistry;
2576}
2577
2579{
2580 return members()->mScaleBarRendererRegistry;
2581}
2582
2584{
2585 return members()->mProjectStorageRegistry;
2586}
2587
2589{
2590 return members()->mExternalStorageRegistry;
2591}
2592
2594{
2595 return members()->mLocalizedDataPathRegistry;
2596}
2597
2598QgsApplication::ApplicationMembers::ApplicationMembers()
2599{
2600 // don't use initializer lists or scoped pointers - as more objects are added here we
2601 // will need to be careful with the order of creation/destruction
2602 mSettingsRegistryCore = new QgsSettingsRegistryCore();
2603 mLocalizedDataPathRegistry = new QgsLocalizedDataPathRegistry();
2604 mMessageLog = new QgsMessageLog();
2605 QgsRuntimeProfiler *profiler = QgsRuntimeProfiler::threadLocalInstance();
2606
2607 {
2608 profiler->start( tr( "Create query logger" ) );
2609 mQueryLogger = new QgsDatabaseQueryLog();
2610 profiler->end();
2611 }
2612 {
2613 profiler->start( tr( "Setup coordinate reference system registry" ) );
2614 mCrsRegistry = new QgsCoordinateReferenceSystemRegistry();
2615 profiler->end();
2616 }
2617 {
2618 profiler->start( tr( "Create connection registry" ) );
2619 mConnectionRegistry = new QgsConnectionRegistry();
2620 profiler->end();
2621 }
2622 {
2623 profiler->start( tr( "Create project storage registry" ) );
2624 mProjectStorageRegistry = new QgsProjectStorageRegistry();
2625 profiler->end();
2626 }
2627 {
2628 profiler->start( tr( "Create metadata provider registry" ) );
2629 mLayerMetadataProviderRegistry = new QgsLayerMetadataProviderRegistry();
2630 profiler->end();
2631 }
2632 {
2633 profiler->start( tr( "Create font manager" ) );
2634 mFontManager = new QgsFontManager();
2635 profiler->end();
2636 }
2637 {
2638 profiler->start( tr( "Setup task manager" ) );
2639 mTaskManager = new QgsTaskManager();
2640 profiler->end();
2641 }
2642 {
2643 profiler->start( tr( "Setup action scope registry" ) );
2644 mActionScopeRegistry = new QgsActionScopeRegistry();
2645 profiler->end();
2646 }
2647 {
2648 profiler->start( tr( "Setup numeric formats" ) );
2649 mNumericFormatRegistry = new QgsNumericFormatRegistry();
2650 profiler->end();
2651 }
2652 {
2653 profiler->start( tr( "Setup field formats" ) );
2654 mFieldFormatterRegistry = new QgsFieldFormatterRegistry();
2655 profiler->end();
2656 }
2657 {
2658 profiler->start( tr( "Setup SVG cache" ) );
2659 mSvgCache = new QgsSvgCache();
2660 profiler->end();
2661 }
2662 {
2663 profiler->start( tr( "Setup image cache" ) );
2664 mImageCache = new QgsImageCache();
2665 profiler->end();
2666 }
2667 {
2668 profiler->start( tr( "Setup source cache" ) );
2669 mSourceCache = new QgsSourceCache();
2670 profiler->end();
2671 }
2672 {
2673 profiler->start( tr( "Setup color scheme registry" ) );
2674 mColorSchemeRegistry = new QgsColorSchemeRegistry();
2675 profiler->end();
2676 }
2677 {
2678 profiler->start( tr( "Setup paint effect" ) );
2679 mPaintEffectRegistry = new QgsPaintEffectRegistry();
2680 profiler->end();
2681 }
2682 {
2683 profiler->start( tr( "Setup symbol layer registry" ) );
2684 mSymbolLayerRegistry = new QgsSymbolLayerRegistry();
2685 profiler->end();
2686 }
2687 {
2688 profiler->start( tr( "Recent style handler" ) );
2689 mRecentStyleHandler = new QgsRecentStyleHandler();
2690 profiler->end();
2691 }
2692 {
2693 profiler->start( tr( "Setup callout registry" ) );
2694 mCalloutRegistry = new QgsCalloutRegistry();
2695 profiler->end();
2696 }
2697 {
2698 profiler->start( tr( "Setup renderer registry" ) );
2699 mRendererRegistry = new QgsRendererRegistry();
2700 profiler->end();
2701 }
2702 {
2703 profiler->start( tr( "Setup raster renderer registry" ) );
2704 mRasterRendererRegistry = new QgsRasterRendererRegistry();
2705 profiler->end();
2706 }
2707 {
2708 profiler->start( tr( "Setup point cloud renderer registry" ) );
2709 mPointCloudRendererRegistry = new QgsPointCloudRendererRegistry();
2710 profiler->end();
2711 }
2712 {
2713 profiler->start( tr( "Setup GPS registry" ) );
2714 mGpsConnectionRegistry = new QgsGpsConnectionRegistry();
2715 profiler->end();
2716 }
2717 {
2718 profiler->start( tr( "Setup GPSBabel format registry" ) );
2719 mGpsBabelFormatRegistry = new QgsBabelFormatRegistry();
2720 profiler->end();
2721 }
2722 {
2723 profiler->start( tr( "Setup plugin layer registry" ) );
2724 mPluginLayerRegistry = new QgsPluginLayerRegistry();
2725 profiler->end();
2726 }
2727 {
2728 profiler->start( tr( "Setup Processing registry" ) );
2729 mProcessingRegistry = new QgsProcessingRegistry();
2730 profiler->end();
2731 }
2732 mPageSizeRegistry = new QgsPageSizeRegistry();
2733 {
2734 profiler->start( tr( "Setup layout item registry" ) );
2735 mLayoutItemRegistry = new QgsLayoutItemRegistry();
2736 mLayoutItemRegistry->populate();
2737 profiler->end();
2738 }
2739 {
2740 profiler->start( tr( "Setup annotation registry" ) );
2741 mAnnotationRegistry = new QgsAnnotationRegistry();
2742 profiler->end();
2743 }
2744 {
2745 profiler->start( tr( "Setup annotation item registry" ) );
2746 mAnnotationItemRegistry = new QgsAnnotationItemRegistry();
2747 mAnnotationItemRegistry->populate();
2748 profiler->end();
2749 }
2750 {
2751 profiler->start( tr( "Setup 3D symbol registry" ) );
2752 m3DSymbolRegistry = new Qgs3DSymbolRegistry();
2753 profiler->end();
2754 }
2755 {
2756 profiler->start( tr( "Setup 3D renderer registry" ) );
2757 m3DRendererRegistry = new Qgs3DRendererRegistry();
2758 profiler->end();
2759 }
2760 {
2761 profiler->start( tr( "Setup project storage registry" ) );
2762 mProjectStorageRegistry = new QgsProjectStorageRegistry();
2763 profiler->end();
2764 }
2765 {
2766 profiler->start( tr( "Setup layer metadata provider registry" ) );
2767 mLayerMetadataProviderRegistry = new QgsLayerMetadataProviderRegistry();
2768 profiler->end();
2769 }
2770 {
2771 profiler->start( tr( "Setup external storage registry" ) );
2772 mExternalStorageRegistry = new QgsExternalStorageRegistry();
2773 profiler->end();
2774 }
2775 {
2776 profiler->start( tr( "Setup network content cache" ) );
2777 mNetworkContentFetcherRegistry = new QgsNetworkContentFetcherRegistry();
2778 profiler->end();
2779 }
2780 {
2781 profiler->start( tr( "Setup layout check registry" ) );
2782 mValidityCheckRegistry = new QgsValidityCheckRegistry();
2783 profiler->end();
2784 }
2785 {
2786 profiler->start( tr( "Setup classification registry" ) );
2787 mClassificationMethodRegistry = new QgsClassificationMethodRegistry();
2788 profiler->end();
2789 }
2790 {
2791 profiler->start( tr( "Setup bookmark manager" ) );
2792 mBookmarkManager = new QgsBookmarkManager( nullptr );
2793 profiler->end();
2794 }
2795 {
2796 profiler->start( tr( "Setup tile download manager" ) );
2797 mTileDownloadManager = new QgsTileDownloadManager();
2798 profiler->end();
2799 }
2800 {
2801 profiler->start( tr( "Setup scalebar registry" ) );
2802 mScaleBarRendererRegistry = new QgsScaleBarRendererRegistry();
2803 profiler->end();
2804 }
2805}
2806
2807QgsApplication::ApplicationMembers::~ApplicationMembers()
2808{
2809 delete mStyleModel;
2810 delete mTileDownloadManager;
2811 delete mScaleBarRendererRegistry;
2812 delete mValidityCheckRegistry;
2813 delete mActionScopeRegistry;
2814 delete m3DRendererRegistry;
2815 delete m3DSymbolRegistry;
2816 delete mAnnotationRegistry;
2817 delete mColorSchemeRegistry;
2818 delete mFieldFormatterRegistry;
2819 delete mGpsConnectionRegistry;
2820 delete mGpsBabelFormatRegistry;
2821 delete mMessageLog;
2822 delete mPaintEffectRegistry;
2823 delete mPluginLayerRegistry;
2824 delete mProcessingRegistry;
2825 delete mPageSizeRegistry;
2826 delete mAnnotationItemRegistry;
2827 delete mLayoutItemRegistry;
2828 delete mPointCloudRendererRegistry;
2829 delete mRasterRendererRegistry;
2830 delete mRendererRegistry;
2831 delete mSvgCache;
2832 delete mImageCache;
2833 delete mSourceCache;
2834 delete mCalloutRegistry;
2835 delete mRecentStyleHandler;
2836 delete mSymbolLayerRegistry;
2837 delete mExternalStorageRegistry;
2838 delete mTaskManager;
2839 delete mNetworkContentFetcherRegistry;
2840 delete mClassificationMethodRegistry;
2841 delete mNumericFormatRegistry;
2842 delete mBookmarkManager;
2843 delete mConnectionRegistry;
2844 delete mProjectStorageRegistry;
2845 delete mLayerMetadataProviderRegistry;
2846 delete mFontManager;
2847 delete mLocalizedDataPathRegistry;
2848 delete mCrsRegistry;
2849 delete mQueryLogger;
2850 delete mSettingsRegistryCore;
2851}
2852
2853QgsApplication::ApplicationMembers *QgsApplication::members()
2854{
2855 if ( auto *lInstance = instance() )
2856 {
2857 return lInstance->mApplicationMembers;
2858 }
2859 else
2860 {
2861 static QRecursiveMutex sMemberMutex;
2862 QMutexLocker lock( &sMemberMutex );
2863 if ( !sApplicationMembers )
2864 sApplicationMembers = new ApplicationMembers();
2865 return sApplicationMembers;
2866 }
2867}
static const double UI_SCALE_FACTOR
UI scaling factor.
Definition: qgis.h:3278
Keeps track of available 3D renderers.
Registry of available 3D symbol classes.
The action scope registry is an application wide registry that contains a list of available action sc...
Registry of available annotation item types.
Extends QApplication to provide access to QGIS specific resources such as theme paths,...
static QString resolvePkgPath()
Calculate the application pkg path.
static int scaleIconSize(int standardSize, bool applyDevicePixelRatio=false)
Scales an icon size to compensate for display pixel density, making the icon size hi-dpi friendly,...
static void restoreGdalDriver(const QString &driver)
Sets the GDAL_SKIP environment variable to exclude the specified driver and then calls GDALDriverMana...
static void setCustomVariables(const QVariantMap &customVariables)
Custom expression variables for this application.
QString translation() const
Returns the current application translation locale code.
static QString i18nPath()
Returns the path to the translation directory.
static QgsAnnotationItemRegistry * annotationItemRegistry()
Returns the application's annotation item registry, used for annotation item types.
static QString osName()
Returns a string name of the operating system QGIS is running on.
static void registerOgrDrivers()
Register OGR drivers ensuring this only happens once.
static QString sponsorsFilePath()
Returns the path to the sponsors file.
static QgsRecentStyleHandler * recentStyleHandler()
Returns the handler for recently used style items.
endian_t
Constants for endian-ness.
static QString qgisMasterDatabaseFilePath()
Returns the path to the master qgis.db file.
static void skipGdalDriver(const QString &driver)
Sets the GDAL_SKIP environment variable to include the specified driver and then calls GDALDriverMana...
static QString defaultThemePath()
Returns the path to the default theme directory.
static QgsPageSizeRegistry * pageSizeRegistry()
Returns the application's page size registry, used for managing layout page sizes.
static QgsValidityCheckRegistry * validityCheckRegistry()
Returns the application's validity check registry, used for managing validity checks.
static QgsDataItemProviderRegistry * dataItemProviderRegistry()
Returns the application's data item provider registry, which keeps a list of data item providers that...
static QString userStylePath()
Returns the path to user's style.
static QString platform()
Returns the QGIS platform name, e.g., "desktop", "server", "qgis_process" or "external" (for external...
static QgsProcessingRegistry * processingRegistry()
Returns the application's processing registry, used for managing processing providers,...
static QgsLayerMetadataProviderRegistry * layerMetadataProviderRegistry()
Returns registry of available layer metadata provider implementations.
static QgsConnectionRegistry * connectionRegistry()
Returns the application's connection registry, used for managing saved data provider connections.
static void exitQgis()
deletes provider registry and map layer registry
static void setPluginPath(const QString &pluginPath)
Alters plugin path - used by 3rd party apps.
static const QgsSettingsEntryStringList * settingsSearchPathsForSVG
Settings entry search path for SVG.
static QPixmap getThemePixmap(const QString &name, const QColor &foreColor=QColor(), const QColor &backColor=QColor(), int size=16)
Helper to get a theme icon as a pixmap.
static QString nullRepresentation()
This string is used to represent the value NULL throughout QGIS.
static QVariantMap customVariables()
Custom expression variables for this application.
static QgsPointCloudRendererRegistry * pointCloudRendererRegistry()
Returns the application's point cloud renderer registry, used for managing point cloud layer 2D rende...
static QgsPaintEffectRegistry * paintEffectRegistry()
Returns the application's paint effect registry, used for managing paint effects.
static QString pluginPath()
Returns the path to the application plugin directory.
static void setUITheme(const QString &themeName)
Set the current UI theme used to style the interface.
static bool createDatabase(QString *errorMessage=nullptr)
initialize qgis.db
static const QgsSettingsEntryBool * settingsLocaleOverrideFlag
Settings entry locale override flag.
static QCursor getThemeCursor(Cursor cursor)
Helper to get a theme cursor.
static int systemMemorySizeMb()
Returns the size of the system memory (RAM) in megabytes.
static void setLocale(const QLocale &locale)
Sets the QGIS locale - used mainly by 3rd party apps and tests.
static void init(QString profileFolder=QString())
This method initializes paths etc for QGIS.
static void setThemeName(const QString &themeName)
Set the active theme to the specified theme.
void customVariablesChanged()
Emitted whenever a custom global variable changes.
static QString buildSourcePath()
Returns path to the source directory. Valid only when running from build directory.
static QString buildOutputPath()
Returns path to the build output directory. Valid only when running from build directory.
bool notify(QObject *receiver, QEvent *event) override
Catch exceptions when sending event to receiver.
static int maxThreads()
Gets maximum concurrent thread count.
static QgsColorSchemeRegistry * colorSchemeRegistry()
Returns the application's color scheme registry, used for managing color schemes.
static QgsApplication * instance()
Returns the singleton instance of the QgsApplication.
static QString reportStyleSheet(QgsApplication::StyleSheetType styleSheetType=QgsApplication::StyleSheetType::Qt)
Returns a css style sheet for reports, the styleSheetType argument determines what type of stylesheet...
static QString pkgDataPath()
Returns the common root path of all application data directories.
static QgsScaleBarRendererRegistry * scaleBarRendererRegistry()
Gets the registry of available scalebar renderers.
static QgsLayoutItemRegistry * layoutItemRegistry()
Returns the application's layout item registry, used for layout item types.
static void setFileOpenEventReceiver(QObject *receiver)
Sets the FileOpen event receiver.
static QgsSymbolLayerRegistry * symbolLayerRegistry()
Returns the application's symbol layer registry, used for managing symbol layers.
static QgsRasterRendererRegistry * rasterRendererRegistry()
Returns the application's raster renderer registry, used for managing raster layer renderers.
static void applyGdalSkippedDrivers()
Apply the skipped drivers list to gdal.
static void setMaxThreads(int maxThreads)
Set maximum concurrent thread count.
static QgsNumericFormatRegistry * numericFormatRegistry()
Gets the registry of available numeric formats.
static QgsNetworkContentFetcherRegistry * networkContentFetcherRegistry()
Returns the application's network content registry used for fetching temporary files during QGIS sess...
static QgsProjectStorageRegistry * projectStorageRegistry()
Returns registry of available project storage implementations.
static QString licenceFilePath()
Returns the path to the licence file.
static QString libexecPath()
Returns the path with utility executables (help viewer, crssync, ...)
static QStringList skippedGdalDrivers()
Returns the list of gdal drivers that should be skipped (based on GDAL_SKIP environment variable)
StyleSheetType
The StyleSheetType enum represents the stylesheet type that a widget supports.
static QString translatorsFilePath()
Returns the path to the sponsors file.
static const QgsSettingsEntryString * settingsLocaleGlobalLocale
Settings entry locale global locale.
static QIcon getThemeIcon(const QString &name, const QColor &fillColor=QColor(), const QColor &strokeColor=QColor())
Helper to get a theme icon.
static void setNullRepresentation(const QString &nullRepresentation)
This string is used to represent the value NULL throughout QGIS.
static QString applicationFullName()
Returns the QGIS application full name.
static QgsGpsConnectionRegistry * gpsConnectionRegistry()
Returns the application's GPS connection registry, used for managing GPS connections.
static QString locale()
Returns the QGIS locale.
static QgsImageCache * imageCache()
Returns the application's image cache, used for caching resampled versions of raster images.
static QStringList svgPaths()
Returns the paths to svg directories.
static void initQgis()
loads providers
static QString showSettings()
Convenience function to get a summary of the paths used in this application instance useful for debug...
bool event(QEvent *event) override
Watch for QFileOpenEvent.
static void setPkgDataPath(const QString &pkgDataPath)
Alters pkg data path - used by 3rd party apps.
static QString absolutePathToRelativePath(const QString &apath, const QString &targetPath)
Converts absolute path to path relative to target.
static const QgsSettingsEntryString * settingsLocaleUserLocale
Settings entry locale user locale.
static QgsRuntimeProfiler * profiler()
Returns the application runtime profiler.
~QgsApplication() override
static QgsLocalizedDataPathRegistry * localizedDataPathRegistry()
Returns the registry of data repositories These are used as paths for basemaps, logos,...
static const char * QGIS_APPLICATION_NAME
static QgsTileDownloadManager * tileDownloadManager()
Returns the application's tile download manager, used for download of map tiles when rendering.
static const char * QGIS_ORGANIZATION_DOMAIN
static QMap< QString, QString > systemEnvVars()
Returns the system environment variables passed to application.
static void setAuthDatabaseDirPath(const QString &authDbDirPath)
Alters authentication data base directory path - used by 3rd party apps.
static QString prefixPath()
Returns the path to the application prefix directory.
static QgsSvgCache * svgCache()
Returns the application's SVG cache, used for caching SVG images and handling parameter replacement w...
static QgsFontManager * fontManager()
Returns the application font manager, which manages available fonts and font installation for the QGI...
static QString qgisSettingsDirPath()
Returns the path to the settings directory in user's home dir.
static QgsDatabaseQueryLog * databaseQueryLog()
Returns the database query log.
static QgsMessageLog * messageLog()
Returns the application's message log.
void preNotify(QObject *receiver, QEvent *event, bool *done)
static bool createThemeFolder()
Create the users theme folder.
static QString metadataPath()
Returns the path to the metadata directory.
void localeChanged()
Emitted when project locale has been changed.
static QgsActionScopeRegistry * actionScopeRegistry()
Returns the action scope registry.
static QgsCoordinateReferenceSystemRegistry * coordinateReferenceSystemRegistry()
Returns the application's coordinate reference system (CRS) registry, which handles known CRS definit...
static const char * QGIS_ORGANIZATION_NAME
static QString contributorsFilePath()
Returns the path to the contributors file.
void collectTranslatableObjects(QgsTranslationContext *translationContext)
Emits the signal to collect all the strings of .qgs to be included in ts file.
static QgsSourceCache * sourceCache()
Returns the application's source cache, used for caching embedded and remote source strings as local ...
static QRegularExpression shortNameRegularExpression()
Returns the short name regular expression for line edit validator.
static QgsTaskManager * taskManager()
Returns the application's task manager, used for managing application wide background task handling.
static QgsAnnotationRegistry * annotationRegistry()
Returns the application's annotation registry, used for managing annotation types.
static QgsPluginLayerRegistry * pluginLayerRegistry()
Returns the application's plugin layer registry, used for managing plugin layer types.
static QgsClassificationMethodRegistry * classificationMethodRegistry()
Returns the application's classification methods registry, used in graduated renderer.
static QStringList deferredSkippedGdalDrivers()
Returns the list of gdal drivers that have been disabled in the current session, and thus,...
static QString defaultStylePath()
Returns the path to default style (works as a starting point).
static QgsAuthManager * authManager()
Returns the application's authentication manager instance.
static QString qmlImportPath()
Returns the path where QML components are installed for QGIS Quick library.
Cursor
The Cursor enum defines constants for QGIS custom cursors.
@ ZoomOut
Zoom out.
@ CrossHair
Precisely identify a point on the canvas.
@ Identify
Identify: obtain information about the object.
@ Select
Select a rectangle.
@ CapturePoint
Select and capture a point or a feature.
@ Sampler
Color/Value picker.
@ ZoomIn
Zoom in.
static QString qgisAuthDatabaseFilePath()
Returns the path to the user authentication database file: qgis-auth.db.
static QString authorsFilePath()
Returns the path to the authors file.
static QgsBookmarkManager * bookmarkManager()
Returns the application's bookmark manager, used for storing installation-wide bookmarks.
static QString qgisUserDatabaseFilePath()
Returns the path to the user qgis.db file.
static QgsFieldFormatterRegistry * fieldFormatterRegistry()
Gets the registry of available field formatters.
static QString activeThemePath()
Returns the path to the currently active theme directory.
static QString defaultThemesFolder()
Returns the path to default themes folder from install (works as a starting point).
static void setSkippedGdalDrivers(const QStringList &skippedGdalDrivers, const QStringList &deferredSkippedGdalDrivers)
Sets the list of gdal drivers that should be disabled (skippedGdalDrivers), but excludes for now the ...
static QgsRendererRegistry * rendererRegistry()
Returns the application's renderer registry, used for managing vector layer renderers.
static void setTranslation(const QString &translation)
Set translation locale code.
static QgsCalloutRegistry * calloutRegistry()
Returns the application's callout registry, used for managing callout types.
static void setPrefixPath(const QString &prefixPath, bool useDefaultPaths=false)
Alters prefix path - used by 3rd party apps.
static QgsStyleModel * defaultStyleModel()
Returns a shared QgsStyleModel containing the default style library (see QgsStyle::defaultStyle()).
static QString relativePathToAbsolutePath(const QString &rpath, const QString &targetPath)
Converts path relative to target to an absolute path.
static void setSvgPaths(const QStringList &svgPaths)
Sets the paths to svg directories and invalidates the svg path list cache.
static QString developersMapFilePath()
Returns the path to the developers map file.
static QgsBabelFormatRegistry * gpsBabelFormatRegistry()
Returns the application's GPSBabel format registry, used for managing GPSBabel formats.
static endian_t endian()
Returns whether this machine uses big or little endian.
int maxConcurrentConnectionsPerPool() const
The maximum number of concurrent connections per connections pool.
static void setCustomVariable(const QString &name, const QVariant &value)
Set a single custom expression variable.
void requestForTranslatableObjects(QgsTranslationContext *translationContext)
Emitted when project strings which require translation are being collected for inclusion in a ....
static QString iconsPath()
Returns the path to the icons image directory.
static Qgs3DSymbolRegistry * symbol3DRegistry()
Returns registry of available 3D symbols.
static QgsExternalStorageRegistry * externalStorageRegistry()
Returns registry of available external storage implementations.
static QHash< QString, QString > uiThemes()
All themes found in ~/.qgis3/themes folder.
static QString splashPath()
Returns the path to the splash screen image directory.
static QString donorsFilePath()
Returns the path to the donors file.
static QString themeName()
Set the active theme to the specified theme.
void nullRepresentationChanged()
This string is used to represent the value NULL throughout QGIS.
static QString srsDatabaseFilePath()
Returns the path to the srs.db file.
static QString userThemesFolder()
Returns the path to user's themes folder.
static void registerGdalDriversFromSettings()
Register gdal drivers, excluding the ones mentioned in "gdal/skipList" setting.
static Qgs3DRendererRegistry * renderer3DRegistry()
Returns registry of available 3D renderers.
static QString iconPath(const QString &iconFile)
Returns path to the desired icon file.
static void setDefaultSvgPaths(const QStringList &pathList)
Alters default svg paths - used by 3rd party apps.
static QString libraryPath()
Returns the path containing qgis_core, qgis_gui, qgispython (and other) libraries.
static QStringList layoutTemplatePaths()
Returns the paths to layout template directories.
static const QgsSettingsEntryBool * settingsLocaleShowGroupSeparator
Settings entry locale show group separator.
static QString userFullName()
Returns the user's operating system login account full display name.
static Q_DECL_DEPRECATED QgsSettingsRegistryCore * settingsRegistryCore()
Returns the application's settings registry, used for managing application settings.
static QString serverResourcesPath()
Returns the path to the server resources directory.
static QString appIconPath()
Gets application icon.
static QString userLoginName()
Returns the user's operating system login account name.
Singleton offering an interface to manage the authentication configuration database and to utilize co...
bool init(const QString &pluginPath=QString(), const QString &authDatabasePath=QString())
init initialize QCA, prioritize qca-ossl plugin and optionally set up the authentication database
static QgsAuthManager * instance()
Enforce singleton pattern.
A registry for QgsAbstractBabelFormat GPSBabel formats.
Manages storage of a set of bookmarks.
void initialize(const QString &filePath)
Initializes the bookmark manager.
Registry of available callout classes.
This class manages all known classification methods.
Registry of color schemes.
void addDefaultSchemes()
Adds all default color schemes to this color scheme.
void initStyleScheme()
Initializes the default random style color scheme for the user.
A registry for saved data provider connections, allowing retrieval of saved connections by name and p...
A registry for known coordinate reference system (CRS) definitions, including any user-defined CRSes.
static void invalidateCache(bool disableCache=false)
Clears the internal cache used to initialize QgsCoordinateReferenceSystem objects.
static void invalidateCache(bool disableCache=false)
Clears the internal cache used to initialize QgsCoordinateTransform objects.
This class keeps a list of data item providers that may add items to the browser tree.
Handles logging of database queries.
static void applyLocaleChange()
Adjusts the date time display formats according to locale.
static void invalidateCache(bool disableCache=false)
Clears the internal cache used.
Defines a QGIS exception class.
Definition: qgsexception.h:35
QString what() const
Definition: qgsexception.h:48
static void cleanRegisteredFunctions()
Deletes all registered functions whose ownership have been transferred to the expression engine.
Registry of external storage backends used by QgsExternalResourceWidget.
The QgsFieldFormatterRegistry manages registered classes of QgsFieldFormatter.
Manages available fonts and font installation for a QGIS instance.
void installUserFonts()
Installs user fonts from the profile/fonts directory as application fonts.
A class to register / unregister existing GPS connections such that the information is available to a...
A cache for images derived from raster files.
Registry of layer metadata provider backends.
Registry of available layout item types.
static const QgsSettingsEntryStringList * settingsSearchPathForTemplates
Settings entry search path for templates.
Definition: qgslayout.h:662
A registry class to hold localized data paths which can be used for basemaps, logos,...
Temporarily blocks the application QgsMessageLog (see QgsApplication::messageLog()) from emitting the...
Interface for logging messages from QGIS in GUI independent way.
Definition: qgsmessagelog.h:40
static QgsNetworkAccessManager * instance(Qt::ConnectionType connectionType=Qt::BlockingQueuedConnection)
Returns a pointer to the active QgsNetworkAccessManager for the current thread.
Registry for temporary fetched files.
The QgsNumericFormatRegistry manages registered classes of QgsNumericFormat.
A registry for known page sizes.
Registry of available paint effects.
A registry of plugin layers types.
Registry of 2D renderers for point clouds.
Registry for various processing components, including providers, algorithms and various parameters an...
static QStringList searchPaths()
Returns the current list of Proj file search paths.
Registry of storage backends that QgsProject may use.
static QgsProject * instance()
Returns the QgsProject singleton instance.
Definition: qgsproject.cpp:477
static QgsProviderRegistry * instance(const QString &pluginPath=QString())
Means of accessing canonical single instance.
Registry for raster renderers.
The QgsReadWriteLocker class is a convenience class that simplifies locking and unlocking QReadWriteL...
@ Write
Lock for write.
@ Read
Lock for read.
void changeMode(Mode mode)
Change the mode of the lock to mode.
Handles and tracks style items recently used in the QGIS GUI.
Registry of renderers.
Provides a method of recording run time profiles of operations, allowing easy recording of their over...
void end(const QString &group="startup")
End the current profile event.
void start(const QString &name, const QString &group="startup")
Start a profile event with the given name.
The QgsScaleBarRendererRegistry manages registered scalebar renderers.
Scoped object for logging of the runtime for a single operation or group of operations.
A boolean settings entry.
bool setValue(const T &value, const QString &dynamicKeyPart=QString()) const
Set settings value.
T value(const QString &dynamicKeyPart=QString()) const
Returns settings value.
T value(const QString &dynamicKeyPart=QString()) const
Returns settings value.
A string list settings entry.
A string settings entry.
QgsSettingsRegistryCore is used for settings introspection and collects all QgsSettingsEntry instance...
static QgsSettingsTreeNode * sTreeLocale
static QgsSettingsTreeNode * sTreeSvg
This class is a composition of two QSettings instances:
Definition: qgssettings.h:63
QVariant value(const QString &key, const QVariant &defaultValue=QVariant(), Section section=NoSection) const
Returns the value for setting key.
bool contains(const QString &key, QgsSettings::Section section=QgsSettings::NoSection) const
Returns true if there exists a setting called key; returns false otherwise.
void beginGroup(const QString &prefix, QgsSettings::Section section=QgsSettings::NoSection)
Appends prefix to the current group.
Definition: qgssettings.cpp:89
QStringList childKeys() const
Returns a list of all top-level keys that can be read using the QSettings object.
void remove(const QString &key, QgsSettings::Section section=QgsSettings::NoSection)
Removes the setting key and any sub-settings of key in a section.
void setValue(const QString &key, const QVariant &value, QgsSettings::Section section=QgsSettings::NoSection)
Sets the value of setting key to value.
A cache for source strings that returns a local file path containing the source content.
A QAbstractItemModel subclass for showing symbol and color ramp entities contained within a QgsStyle ...
static void cleanDefaultStyle()
Deletes the default style. Only to be used by QgsApplication::exitQgis()
Definition: qgsstyle.cpp:176
static QgsStyle * defaultStyle()
Returns default application-wide style.
Definition: qgsstyle.cpp:145
A cache for images / pictures derived from SVG files.
Definition: qgssvgcache.h:123
QImage svgAsImage(const QString &path, double size, const QColor &fill, const QColor &stroke, double strokeWidth, double widthScaleFactor, bool &fitsInCache, double fixedAspectRatio=0, bool blocking=false, const QMap< QString, QString > &parameters=QMap< QString, QString >())
Returns an SVG drawing as a QImage.
QByteArray svgContent(const QString &path, double size, const QColor &fill, const QColor &stroke, double strokeWidth, double widthScaleFactor, double fixedAspectRatio=0, bool blocking=false, const QMap< QString, QString > &parameters=QMap< QString, QString >(), bool *isMissingImage=nullptr)
Gets the SVG content corresponding to the given path.
Registry of available symbol layer classes.
static QColor decodeColor(const QString &str)
Task manager for managing a set of long-running QgsTask tasks.
Tile download manager handles downloads of map tiles for the purpose of map rendering.
Used for the collecting of strings from projects for translation and creation of ts files.
User profile manager is used to manager list, and manage user profiles on the users machine.
QgsUserProfile * getProfile(const QString &defaultProfile="default", bool createNew=true, bool initSettings=true)
Returns the profile from the given root profile location.
static QString resolveProfilesFolder(const QString &basePath=QString())
Resolves the profiles folder for the given path.
User profile contains information about the user profile folders on the machine.
const QString folder() const
The base folder for the user profile.
This class keeps a list of QgsAbstractValidityCheck checks which can be used when performing validity...
Unique pointer for sqlite3 databases, which automatically closes the database when the pointer goes o...
int open(const QString &path)
Opens the database at the specified file path.
QMap< QString, QString > QgsStringMap
Definition: qgis.h:4054
QObject * ABISYM(QgsApplication::mFileOpenEventReceiver)
#define CONN_POOL_MAX_CONCURRENT_CONNS
Q_GLOBAL_STATIC_WITH_ARGS(PalPropertyList, palHiddenProperties,({ QgsPalLayerSettings::PositionX, QgsPalLayerSettings::PositionY, QgsPalLayerSettings::Show, QgsPalLayerSettings::LabelRotation, QgsPalLayerSettings::Family, QgsPalLayerSettings::FontStyle, QgsPalLayerSettings::Size, QgsPalLayerSettings::Bold, QgsPalLayerSettings::Italic, QgsPalLayerSettings::Underline, QgsPalLayerSettings::Color, QgsPalLayerSettings::Strikeout, QgsPalLayerSettings::MultiLineAlignment, QgsPalLayerSettings::BufferSize, QgsPalLayerSettings::BufferDraw, QgsPalLayerSettings::BufferColor, QgsPalLayerSettings::LabelDistance, QgsPalLayerSettings::Hali, QgsPalLayerSettings::Vali, QgsPalLayerSettings::ScaleVisibility, QgsPalLayerSettings::MinScale, QgsPalLayerSettings::MaxScale, QgsPalLayerSettings::AlwaysShow, QgsPalLayerSettings::CalloutDraw, QgsPalLayerSettings::LabelAllParts })) Q_GLOBAL_STATIC_WITH_ARGS(SymbolPropertyList
Q_GLOBAL_STATIC(QReadWriteLock, sDefinitionCacheLock)
#define QgsDebugMsgLevel(str, level)
Definition: qgslogger.h:39
#define QgsDebugMsg(str)
Definition: qgslogger.h:38