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