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