QGIS API Documentation  3.12.1-BucureČ™ti (121cc00ff0)
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"
19 #include "qgsexception.h"
20 #include "qgsgeometry.h"
21 #include "qgslayoutitemregistry.h"
22 #include "qgslogger.h"
23 #include "qgsproject.h"
26 #include "qgsnetworkreply.h"
27 #include "qgsproviderregistry.h"
28 #include "qgsexpression.h"
29 #include "qgsactionscoperegistry.h"
30 #include "qgsruntimeprofiler.h"
31 #include "qgstaskmanager.h"
34 #include "qgssvgcache.h"
35 #include "qgsimagecache.h"
36 #include "qgscolorschemeregistry.h"
37 #include "qgspainteffectregistry.h"
40 #include "qgsrendererregistry.h"
41 #include "qgssymbollayerregistry.h"
42 #include "qgssymbollayerutils.h"
44 #include "qgspluginlayerregistry.h"
46 #include "qgsmessagelog.h"
47 #include "qgsannotationregistry.h"
48 #include "qgssettings.h"
49 #include "qgsunittypes.h"
50 #include "qgsuserprofile.h"
51 #include "qgsuserprofilemanager.h"
52 #include "qgsreferencedgeometry.h"
53 #include "qgs3drendererregistry.h"
54 #include "qgslayoutrendercontext.h"
55 #include "qgssqliteutils.h"
56 #include "qgsstyle.h"
57 #include "qgsprojutils.h"
59 #include "qgsnewsfeedparser.h"
60 #include "qgsbookmarkmanager.h"
61 #include "qgsstylemodel.h"
62 
65 
67 
68 #include <QDir>
69 #include <QFile>
70 #include <QFileInfo>
71 #include <QFileOpenEvent>
72 #include <QMessageBox>
73 #include <QPalette>
74 #include <QProcess>
75 #include <QProcessEnvironment>
76 #include <QIcon>
77 #include <QPixmap>
78 #include <QThreadPool>
79 #include <QLocale>
80 #include <QStyle>
81 
82 #ifndef Q_OS_WIN
83 #include <netinet/in.h>
84 #include <pwd.h>
85 #else
86 #include <winsock.h>
87 #include <windows.h>
88 #include <lmcons.h>
89 #define SECURITY_WIN32
90 #include <security.h>
91 #pragma comment( lib, "Secur32.lib" )
92 #endif
93 
94 #include "qgsconfig.h"
95 
96 #include <gdal.h>
97 #include <ogr_api.h>
98 #include <cpl_conv.h> // for setting gdal options
99 #include <sqlite3.h>
100 
101 #if PROJ_VERSION_MAJOR>=6
102 #include <proj.h>
103 #endif
104 
105 
106 #define CONN_POOL_MAX_CONCURRENT_CONNS 4
107 
108 QObject *ABISYM( QgsApplication::mFileOpenEventReceiver ) = nullptr;
109 bool ABISYM( QgsApplication::mInitialized ) = false;
110 bool ABISYM( QgsApplication::mRunningFromBuildDir ) = false;
111 const char *QgsApplication::QGIS_ORGANIZATION_NAME = "QGIS";
112 const char *QgsApplication::QGIS_ORGANIZATION_DOMAIN = "qgis.org";
113 const char *QgsApplication::QGIS_APPLICATION_NAME = "QGIS3";
114 QgsApplication::ApplicationMembers *QgsApplication::sApplicationMembers = nullptr;
115 QgsAuthManager *QgsApplication::sAuthManager = nullptr;
116 int ABISYM( QgsApplication::sMaxThreads ) = -1;
117 
118 Q_GLOBAL_STATIC( QStringList, sFileOpenEventList )
119 Q_GLOBAL_STATIC( QString, sPrefixPath )
120 Q_GLOBAL_STATIC( QString, sPluginPath )
121 Q_GLOBAL_STATIC( QString, sPkgDataPath )
122 Q_GLOBAL_STATIC( QString, sLibraryPath )
123 Q_GLOBAL_STATIC( QString, sLibexecPath )
124 Q_GLOBAL_STATIC( QString, sQmlImportPath )
125 Q_GLOBAL_STATIC( QString, sThemeName )
126 Q_GLOBAL_STATIC( QString, sProfilePath )
127 
128 Q_GLOBAL_STATIC( QStringList, sDefaultSvgPaths )
129 Q_GLOBAL_STATIC( QgsStringMap, sSystemEnvVars )
130 Q_GLOBAL_STATIC( QString, sConfigPath )
131 
132 Q_GLOBAL_STATIC( QString, sBuildSourcePath )
133 #if defined(_MSC_VER) && !defined(USING_NMAKE) && !defined(USING_NINJA)
134 Q_GLOBAL_STATIC( QString, sCfgIntDir )
135 #endif
136 Q_GLOBAL_STATIC( QString, sBuildOutputPath )
137 Q_GLOBAL_STATIC( QStringList, sGdalSkipList )
138 Q_GLOBAL_STATIC( QStringList, sDeferredSkippedGdalDrivers )
139 Q_GLOBAL_STATIC( QString, sAuthDbDirPath )
140 
141 Q_GLOBAL_STATIC( QString, sUserName )
142 Q_GLOBAL_STATIC( QString, sUserFullName )
143 Q_GLOBAL_STATIC_WITH_ARGS( QString, sPlatformName, ( "desktop" ) )
144 Q_GLOBAL_STATIC( QString, sTranslation )
145 
146 QgsApplication::QgsApplication( int &argc, char **argv, bool GUIenabled, const QString &profileFolder, const QString &platformName )
147  : QApplication( argc, argv, GUIenabled )
148 {
149  *sPlatformName() = platformName;
150 
151  if ( *sTranslation() != QLatin1String( "C" ) )
152  {
153  mQgisTranslator = new QTranslator();
154  if ( mQgisTranslator->load( QStringLiteral( "qgis_" ) + *sTranslation(), i18nPath() ) )
155  {
156  installTranslator( mQgisTranslator );
157  }
158  else
159  {
160  QgsDebugMsg( QStringLiteral( "loading of qgis translation failed %1/qgis_%2" ).arg( i18nPath(), *sTranslation() ) );
161  }
162 
163  /* Translation file for Qt.
164  * The strings from the QMenuBar context section are used by Qt/Mac to shift
165  * the About, Preferences and Quit items to the Mac Application menu.
166  * These items must be translated identically in both qt_ and qgis_ files.
167  */
168  mQtTranslator = new QTranslator();
169  if ( mQtTranslator->load( QStringLiteral( "qt_" ) + *sTranslation(), QLibraryInfo::location( QLibraryInfo::TranslationsPath ) ) )
170  {
171  installTranslator( mQtTranslator );
172  }
173  else
174  {
175  QgsDebugMsg( QStringLiteral( "loading of qt translation failed %1/qt_%2" ).arg( QLibraryInfo::location( QLibraryInfo::TranslationsPath ), *sTranslation() ) );
176  }
177  }
178 
179  mApplicationMembers = new ApplicationMembers();
180 
181  *sProfilePath() = profileFolder;
182 }
183 
184 void QgsApplication::init( QString profileFolder )
185 {
186  if ( profileFolder.isEmpty() )
187  {
188  if ( getenv( "QGIS_CUSTOM_CONFIG_PATH" ) )
189  {
190  profileFolder = getenv( "QGIS_CUSTOM_CONFIG_PATH" );
191  }
192  else
193  {
194  profileFolder = QStandardPaths::standardLocations( QStandardPaths::AppDataLocation ).value( 0 );
195  }
196  // This will normally get here for custom scripts that use QgsApplication.
197  // This doesn't get this hit for QGIS Desktop because we setup the profile via main
198  QString rootProfileFolder = QgsUserProfileManager::resolveProfilesFolder( profileFolder );
199  QgsUserProfileManager manager( rootProfileFolder );
200  QgsUserProfile *profile = manager.getProfile();
201  profileFolder = profile->folder();
202  delete profile;
203  }
204 
205  *sProfilePath() = profileFolder;
206 
207  qRegisterMetaType<QgsGeometry::Error>( "QgsGeometry::Error" );
208  qRegisterMetaType<QgsProcessingFeatureSourceDefinition>( "QgsProcessingFeatureSourceDefinition" );
209  qRegisterMetaType<QgsProcessingOutputLayerDefinition>( "QgsProcessingOutputLayerDefinition" );
210  qRegisterMetaType<QgsUnitTypes::LayoutUnit>( "QgsUnitTypes::LayoutUnit" );
211  qRegisterMetaType<QgsFeatureId>( "QgsFeatureId" );
212  qRegisterMetaType<QgsFeatureIds>( "QgsFeatureIds" );
213  qRegisterMetaType<QgsProperty>( "QgsProperty" );
214  qRegisterMetaType<Qgis::MessageLevel>( "Qgis::MessageLevel" );
215  qRegisterMetaType<QgsReferencedRectangle>( "QgsReferencedRectangle" );
216  qRegisterMetaType<QgsReferencedPointXY>( "QgsReferencedPointXY" );
217  qRegisterMetaType<QgsLayoutRenderContext::Flags>( "QgsLayoutRenderContext::Flags" );
218  qRegisterMetaType<QgsStyle::StyleEntity>( "QgsStyle::StyleEntity" );
219  qRegisterMetaType<QgsCoordinateReferenceSystem>( "QgsCoordinateReferenceSystem" );
220  qRegisterMetaType<QgsAuthManager::MessageLevel>( "QgsAuthManager::MessageLevel" );
221  qRegisterMetaType<QgsNetworkRequestParameters>( "QgsNetworkRequestParameters" );
222  qRegisterMetaType<QgsNetworkReplyContent>( "QgsNetworkReplyContent" );
223  qRegisterMetaType<QgsGeometry>( "QgsGeometry" );
224  qRegisterMetaType<QgsDatumTransform::GridDetails>( "QgsDatumTransform::GridDetails" );
225  qRegisterMetaType<QgsDatumTransform::TransformDetails>( "QgsDatumTransform::TransformDetails" );
226  qRegisterMetaType<QgsNewsFeedParser::Entry>( "QgsNewsFeedParser::Entry" );
227 
228  ( void ) resolvePkgPath();
229 
230  if ( ABISYM( mRunningFromBuildDir ) )
231  {
232  // we run from source directory - not installed to destination (specified prefix)
233  *sPrefixPath() = QString(); // set invalid path
234 #if defined(_MSC_VER) && !defined(USING_NMAKE) && !defined(USING_NINJA)
235  setPluginPath( *sBuildOutputPath() + '/' + QString( QGIS_PLUGIN_SUBDIR ) + '/' + *sCfgIntDir() );
236 #else
237  setPluginPath( *sBuildOutputPath() + '/' + QStringLiteral( QGIS_PLUGIN_SUBDIR ) );
238 #endif
239  setPkgDataPath( *sBuildOutputPath() + QStringLiteral( "/data" ) ); // in buildDir/data - used for: doc, resources, svg
240  *sLibraryPath() = *sBuildOutputPath() + '/' + QGIS_LIB_SUBDIR + '/';
241 #if defined(_MSC_VER) && !defined(USING_NMAKE) && !defined(USING_NINJA)
242  *sLibexecPath() = *sBuildOutputPath() + '/' + QGIS_LIBEXEC_SUBDIR + '/' + *sCfgIntDir() + '/';
243 #else
244  *sLibexecPath() = *sBuildOutputPath() + '/' + QGIS_LIBEXEC_SUBDIR + '/';
245 #endif
246 #if defined( HAVE_QUICK )
247  *sQmlImportPath() = *sBuildOutputPath() + '/' + QGIS_QML_SUBDIR + '/';
248 #endif
249  }
250  else
251  {
252  char *prefixPath = getenv( "QGIS_PREFIX_PATH" );
253  if ( !prefixPath )
254  {
255  if ( sPrefixPath()->isNull() )
256  {
257 #if defined(Q_OS_MACX) || defined(Q_OS_WIN)
258  setPrefixPath( applicationDirPath(), true );
259 #elif defined(ANDROID)
260  // this is "/data/data/org.qgis.qgis" in android
261  QDir myDir( QDir::homePath() );
262  myDir.cdUp();
263  QString myPrefix = myDir.absolutePath();
264  setPrefixPath( myPrefix, true );
265 #else
266  QDir myDir( applicationDirPath() );
267  // Fix for server which is one level deeper in /usr/lib/cgi-bin
268  if ( applicationDirPath().contains( QStringLiteral( "cgi-bin" ) ) )
269  {
270  myDir.cdUp();
271  }
272  myDir.cdUp(); // Go from /usr/bin or /usr/lib (for server) to /usr
273  QString myPrefix = myDir.absolutePath();
274  setPrefixPath( myPrefix, true );
275 #endif
276  }
277  }
278  else
279  {
280  setPrefixPath( prefixPath, true );
281  }
282  }
283 
284  *sConfigPath() = profileFolder + '/'; // make sure trailing slash is included
285  *sDefaultSvgPaths() << qgisSettingsDirPath() + QStringLiteral( "svg/" );
286 
287  *sAuthDbDirPath() = qgisSettingsDirPath();
288  if ( getenv( "QGIS_AUTH_DB_DIR_PATH" ) )
289  {
290  setAuthDatabaseDirPath( getenv( "QGIS_AUTH_DB_DIR_PATH" ) );
291  }
292 
293  // store system environment variables passed to application, before they are adjusted
294  QMap<QString, QString> systemEnvVarMap;
295  QString passfile( QStringLiteral( "QGIS_AUTH_PASSWORD_FILE" ) ); // QString, for comparison
296 
297  const auto systemEnvironment = QProcessEnvironment::systemEnvironment().toStringList();
298  for ( const QString &varStr : systemEnvironment )
299  {
300  int pos = varStr.indexOf( QLatin1Char( '=' ) );
301  if ( pos == -1 )
302  continue;
303  QString varStrName = varStr.left( pos );
304  QString varStrValue = varStr.mid( pos + 1 );
305  if ( varStrName != passfile )
306  {
307  systemEnvVarMap.insert( varStrName, varStrValue );
308  }
309  }
310  *sSystemEnvVars() = systemEnvVarMap;
311 
312 #if PROJ_VERSION_MAJOR>=6
313  // append local user-writable folder as a proj search path
314  QStringList currentProjSearchPaths = QgsProjUtils::searchPaths();
315  currentProjSearchPaths.append( qgisSettingsDirPath() + QStringLiteral( "proj" ) );
316  char **newPaths = new char *[currentProjSearchPaths.length()];
317  for ( int i = 0; i < currentProjSearchPaths.count(); ++i )
318  {
319  newPaths[i] = CPLStrdup( currentProjSearchPaths.at( i ).toUtf8().constData() );
320  }
321  proj_context_set_search_paths( nullptr, currentProjSearchPaths.count(), newPaths );
322  for ( int i = 0; i < currentProjSearchPaths.count(); ++i )
323  {
324  CPLFree( newPaths[i] );
325  }
326  delete [] newPaths;
327 #endif
328 
329 
330  // allow Qt to search for Qt plugins (e.g. sqldrivers) in our plugin directory
331  QCoreApplication::addLibraryPath( pluginPath() );
332 
333  // set max. thread count to -1
334  // this should be read from QgsSettings but we don't know where they are at this point
335  // so we read actual value in main.cpp
336  ABISYM( sMaxThreads ) = -1;
337 
340 
342  if ( !members()->mStyleModel )
343  members()->mStyleModel = new QgsStyleModel( QgsStyle::defaultStyle() );
344 
345  ABISYM( mInitialized ) = true;
346 }
347 
349 {
350  delete mDataItemProviderRegistry;
351  delete mApplicationMembers;
352  delete mQgisTranslator;
353  delete mQtTranslator;
354 
355  // we do this here as well as in exitQgis() -- it's safe to call as often as we want,
356  // and there's just a *chance* that someone hasn't properly called exitQgis prior to
357  // this destructor...
358  invalidateCaches();
359 }
360 
361 void QgsApplication::invalidateCaches()
362 {
363  // invalidate coordinate cache while the PROJ context held by the thread-locale
364  // QgsProjContextStore object is still alive. Otherwise if this later object
365  // is destroyed before the static variables of the cache, we might use freed memory.
369 }
370 
372 {
373  return qobject_cast<QgsApplication *>( QCoreApplication::instance() );
374 }
375 
377 {
378  bool done = false;
379  if ( event->type() == QEvent::FileOpen )
380  {
381  // handle FileOpen event (double clicking a file icon in Mac OS X Finder)
382  if ( ABISYM( mFileOpenEventReceiver ) )
383  {
384  // Forward event to main window.
385  done = notify( ABISYM( mFileOpenEventReceiver ), event );
386  }
387  else
388  {
389  // Store filename because receiver has not registered yet.
390  // If QGIS has been launched by double clicking a file icon, FileOpen will be
391  // the first event; the main window is not yet ready to handle the event.
392  sFileOpenEventList()->append( static_cast<QFileOpenEvent *>( event )->file() );
393  done = true;
394  }
395  }
396  else
397  {
398  // pass other events to base class
399  done = QApplication::event( event );
400  }
401  return done;
402 }
403 
404 bool QgsApplication::notify( QObject *receiver, QEvent *event )
405 {
406  bool done = false;
407  // Crashes in customization (especially on Mac), if we're not in the main/UI thread, see #5597
408  if ( thread() == receiver->thread() )
409  emit preNotify( receiver, event, &done );
410 
411  if ( done )
412  return true;
413 
414  // Send event to receiver and catch unhandled exceptions
415  done = true;
416  try
417  {
418  done = QApplication::notify( receiver, event );
419  }
420  catch ( QgsException &e )
421  {
422  QgsDebugMsg( "Caught unhandled QgsException: " + e.what() );
423  if ( qApp->thread() == QThread::currentThread() )
424  QMessageBox::critical( activeWindow(), tr( "Exception" ), e.what() );
425  }
426  catch ( std::exception &e )
427  {
428  QgsDebugMsg( "Caught unhandled std::exception: " + QString::fromLatin1( e.what() ) );
429  if ( qApp->thread() == QThread::currentThread() )
430  QMessageBox::critical( activeWindow(), tr( "Exception" ), e.what() );
431  }
432  catch ( ... )
433  {
434  QgsDebugMsg( QStringLiteral( "Caught unhandled unknown exception" ) );
435  if ( qApp->thread() == QThread::currentThread() )
436  QMessageBox::critical( activeWindow(), tr( "Exception" ), tr( "unknown exception" ) );
437  }
438 
439  return done;
440 }
441 
443 {
444  return members()->mProfiler;
445 }
446 
448 {
449  // Set receiver for FileOpen events
450  ABISYM( mFileOpenEventReceiver ) = receiver;
451  // Propagate any events collected before the receiver has registered.
452  if ( sFileOpenEventList()->count() > 0 )
453  {
454  const QStringList fileOpenEventList = *sFileOpenEventList();
455  for ( const QString &file : fileOpenEventList )
456  {
457  QFileOpenEvent foe( file );
458  QgsApplication::sendEvent( ABISYM( mFileOpenEventReceiver ), &foe );
459  }
460  sFileOpenEventList()->clear();
461  }
462 }
463 
464 void QgsApplication::setPrefixPath( const QString &prefixPath, bool useDefaultPaths )
465 {
466  *sPrefixPath() = prefixPath;
467 #if defined(Q_OS_WIN)
468  if ( sPrefixPath()->endsWith( "/bin" ) )
469  {
470  sPrefixPath()->chop( 4 );
471  }
472 #endif
473  if ( useDefaultPaths && !ABISYM( mRunningFromBuildDir ) )
474  {
475  setPluginPath( *sPrefixPath() + '/' + QStringLiteral( QGIS_PLUGIN_SUBDIR ) );
476  setPkgDataPath( *sPrefixPath() + '/' + QStringLiteral( QGIS_DATA_SUBDIR ) );
477  }
478  *sLibraryPath() = *sPrefixPath() + '/' + QGIS_LIB_SUBDIR + '/';
479  *sLibexecPath() = *sPrefixPath() + '/' + QGIS_LIBEXEC_SUBDIR + '/';
480 #if defined( HAVE_QUICK )
481  *sQmlImportPath() = *sPrefixPath() + '/' + QGIS_QML_SUBDIR + '/';
482 #endif
483 }
484 
486 {
487  *sPluginPath() = pluginPath;
488 }
489 
491 {
492  *sPkgDataPath() = pkgDataPath;
493 
494  QString mySvgPath = pkgDataPath + QStringLiteral( "/svg/" );
495 
496  // avoid duplicate entries
497  if ( !sDefaultSvgPaths()->contains( mySvgPath ) )
498  *sDefaultSvgPaths() << mySvgPath;
499 }
500 
501 void QgsApplication::setDefaultSvgPaths( const QStringList &pathList )
502 {
503  *sDefaultSvgPaths() = pathList;
504 }
505 
506 void QgsApplication::setAuthDatabaseDirPath( const QString &authDbDirPath )
507 {
508  QFileInfo fi( authDbDirPath );
509  if ( fi.exists() && fi.isDir() && fi.isWritable() )
510  {
511  *sAuthDbDirPath() = fi.canonicalFilePath() + QDir::separator();
512  }
513 }
514 
516 {
517 #if 0
518  if ( ABISYM( mRunningFromBuildDir ) )
519  {
520  static bool sOnce = true;
521  if ( sOnce )
522  {
523  QgsMessageLogNotifyBlocker blockNotifications;
524  ( void ) blockNotifications;
525  qWarning( "!!! prefix path was requested, but it is not valid - we do not run from installed path !!!" );
526  }
527  sOnce = false;
528  }
529 #endif
530 
531  return *sPrefixPath();
532 }
534 {
535  return *sPluginPath();
536 }
537 
539 {
540  if ( sPkgDataPath()->isNull() )
541  return resolvePkgPath();
542  else
543  return *sPkgDataPath();
544 }
545 
547 {
548  return QStringLiteral( ":/images/themes/default/" );
549 }
551 {
552  QString usersThemes = userThemesFolder() + QDir::separator() + themeName() + QDir::separator() + "icons/";
553  QDir dir( usersThemes );
554  if ( dir.exists() )
555  {
556  return usersThemes;
557  }
558  else
559  {
560  QString defaultThemes = defaultThemesFolder() + QDir::separator() + themeName() + QDir::separator() + "icons/";
561  return defaultThemes;
562  }
563 }
564 
566 {
567  return iconsPath() + QStringLiteral( "qgis-icon-60x60.png" );
568 }
569 
571 {
572  return ABISYM( sMaxThreads );
573 }
574 
575 QString QgsApplication::iconPath( const QString &iconFile )
576 {
577  // try active theme
578  QString path = activeThemePath();
579  if ( QFile::exists( path + iconFile ) )
580  return path + iconFile;
581 
582  // use default theme
583  return defaultThemePath() + iconFile;
584 }
585 
586 QIcon QgsApplication::getThemeIcon( const QString &name )
587 {
588  QgsApplication *app = instance();
589  if ( app && app->mIconCache.contains( name ) )
590  return app->mIconCache.value( name );
591 
592  QIcon icon;
593 
594  QString myPreferredPath = activeThemePath() + QDir::separator() + name;
595  QString myDefaultPath = defaultThemePath() + QDir::separator() + name;
596  if ( QFile::exists( myPreferredPath ) )
597  {
598  icon = QIcon( myPreferredPath );
599  }
600  else if ( QFile::exists( myDefaultPath ) )
601  {
602  //could still return an empty icon if it
603  //doesn't exist in the default theme either!
604  icon = QIcon( myDefaultPath );
605  }
606  else
607  {
608  icon = QIcon();
609  }
610 
611  if ( app )
612  app->mIconCache.insert( name, icon );
613  return icon;
614 }
615 
617 {
618  QgsApplication *app = instance();
619  if ( app && app->mCursorCache.contains( cursor ) )
620  return app->mCursorCache.value( cursor );
621 
622  // All calculations are done on 32x32 icons
623  // Defaults to center, individual cursors may override
624  int activeX = 16;
625  int activeY = 16;
626 
627  QString name;
628  switch ( cursor )
629  {
630  case ZoomIn:
631  name = QStringLiteral( "mZoomIn.svg" );
632  activeX = 13;
633  activeY = 13;
634  break;
635  case ZoomOut:
636  name = QStringLiteral( "mZoomOut.svg" );
637  activeX = 13;
638  activeY = 13;
639  break;
640  case Identify:
641  activeX = 3;
642  activeY = 6;
643  name = QStringLiteral( "mIdentify.svg" );
644  break;
645  case CrossHair:
646  name = QStringLiteral( "mCrossHair.svg" );
647  break;
648  case CapturePoint:
649  name = QStringLiteral( "mCapturePoint.svg" );
650  break;
651  case Select:
652  name = QStringLiteral( "mSelect.svg" );
653  activeX = 6;
654  activeY = 6;
655  break;
656  case Sampler:
657  activeX = 5;
658  activeY = 5;
659  name = QStringLiteral( "mSampler.svg" );
660  break;
661  // No default
662  }
663  // It should never get here!
664  Q_ASSERT( ! name.isEmpty( ) );
665 
666  QIcon icon = getThemeIcon( QStringLiteral( "cursors" ) + QDir::separator() + name );
667  QCursor cursorIcon;
668  // Check if an icon exists for this cursor (the O.S. default cursor will be used if it does not)
669  if ( ! icon.isNull( ) )
670  {
671  // Apply scaling
672  float scale = Qgis::UI_SCALE_FACTOR * app->fontMetrics().height() / 32.0;
673  cursorIcon = QCursor( icon.pixmap( std::ceil( scale * 32 ), std::ceil( scale * 32 ) ), std::ceil( scale * activeX ), std::ceil( scale * activeY ) );
674  }
675  if ( app )
676  app->mCursorCache.insert( cursor, cursorIcon );
677  return cursorIcon;
678 }
679 
680 // TODO: add some caching mechanism ?
681 QPixmap QgsApplication::getThemePixmap( const QString &name )
682 {
683  QString myPreferredPath = activeThemePath() + QDir::separator() + name;
684  QString myDefaultPath = defaultThemePath() + QDir::separator() + name;
685  if ( QFile::exists( myPreferredPath ) )
686  {
687  return QPixmap( myPreferredPath );
688  }
689  else
690  {
691  //could still return an empty icon if it
692  //doesn't exist in the default theme either!
693  return QPixmap( myDefaultPath );
694  }
695 }
696 
698 {
699  *sThemeName() = themeName;
700 }
701 
703 {
704  static QString appPath;
705  if ( appPath.isNull() )
706  {
707  if ( QCoreApplication::instance() )
708  {
709  appPath = applicationDirPath();
710  }
711  else
712  {
713  qWarning( "Application path not initialized" );
714  }
715  }
716 
717  if ( !appPath.isNull() || getenv( "QGIS_PREFIX_PATH" ) )
718  {
719  QString prefix = getenv( "QGIS_PREFIX_PATH" ) ? getenv( "QGIS_PREFIX_PATH" ) : appPath;
720 
721  // check if QGIS is run from build directory (not the install directory)
722  QFile f;
723  // "/../../.." is for Mac bundled app in build directory
724  static const QStringList paths { QStringList() << QString() << QStringLiteral( "/.." ) << QStringLiteral( "/bin" ) << QStringLiteral( "/../../.." ) };
725  for ( const QString &path : paths )
726  {
727  f.setFileName( prefix + path + "/qgisbuildpath.txt" );
728  if ( f.exists() )
729  break;
730  }
731  if ( f.exists() && f.open( QIODevice::ReadOnly ) )
732  {
733  ABISYM( mRunningFromBuildDir ) = true;
734  *sBuildSourcePath() = f.readLine().trimmed();
735  *sBuildOutputPath() = f.readLine().trimmed();
736  QgsDebugMsgLevel( QStringLiteral( "Running from build directory!" ), 4 );
737  QgsDebugMsgLevel( QStringLiteral( "- source directory: %1" ).arg( sBuildSourcePath()->toUtf8().constData() ), 4 );
738  QgsDebugMsgLevel( QStringLiteral( "- output directory of the build: %1" ).arg( sBuildOutputPath()->toUtf8().constData() ), 4 );
739 #if defined(_MSC_VER) && !defined(USING_NMAKE) && !defined(USING_NINJA)
740  *sCfgIntDir() = appPath.split( '/', QString::SkipEmptyParts ).last();
741  qDebug( "- cfg: %s", sCfgIntDir()->toUtf8().constData() );
742 #endif
743  }
744  }
745 
746  QString prefixPath;
747  if ( getenv( "QGIS_PREFIX_PATH" ) )
748  prefixPath = getenv( "QGIS_PREFIX_PATH" );
749  else
750  {
751 #if defined(ANDROID)
752  // this is "/data/data/org.qgis.qgis" in android
753  QDir dir( QDir::homePath() );
754  dir.cdUp();
755  prefixPath = dir.absolutePath();
756 #else
757 
758 #if defined(Q_OS_MACX)
759  prefixPath = appPath;
760 #elif defined(Q_OS_WIN)
761  prefixPath = appPath;
762  if ( prefixPath.endsWith( "/bin" ) )
763  prefixPath.chop( 4 );
764 #else
765  QDir dir( appPath );
766  // Fix for server which is one level deeper in /usr/lib/cgi-bin
767  if ( appPath.contains( QStringLiteral( "cgi-bin" ) ) )
768  {
769  dir.cdUp();
770  }
771  dir.cdUp(); // Go from /usr/bin or /usr/lib (for server) to /usr
772  prefixPath = dir.absolutePath();
773 #endif
774 #endif
775  }
776 
777  if ( ABISYM( mRunningFromBuildDir ) )
778  return *sBuildOutputPath() + QStringLiteral( "/data" );
779  else
780  return prefixPath + '/' + QStringLiteral( QGIS_DATA_SUBDIR );
781 }
782 
784 {
785  return *sThemeName();
786 }
787 
788 void QgsApplication::setUITheme( const QString &themeName )
789 {
790  // Loop all style sheets, find matching name, load it.
791  QHash<QString, QString> themes = QgsApplication::uiThemes();
792  if ( themeName == QStringLiteral( "default" ) || !themes.contains( themeName ) )
793  {
794  setThemeName( QStringLiteral( "default" ) );
795  qApp->setStyleSheet( QString() );
796  return;
797  }
798 
799  QString path = themes.value( themeName );
800  QString stylesheetname = path + "/style.qss";
801 
802  QFile file( stylesheetname );
803  QFile variablesfile( path + "/variables.qss" );
804 
805  QFileInfo variableInfo( variablesfile );
806 
807  if ( !file.open( QIODevice::ReadOnly ) || ( variableInfo.exists() && !variablesfile.open( QIODevice::ReadOnly ) ) )
808  {
809  return;
810  }
811 
812  QString styledata = file.readAll();
813  styledata.replace( QStringLiteral( "@theme_path" ), path );
814 
815  if ( variableInfo.exists() )
816  {
817  QTextStream in( &variablesfile );
818  while ( !in.atEnd() )
819  {
820  QString line = in.readLine();
821  // This is a variable
822  if ( line.startsWith( '@' ) )
823  {
824  int index = line.indexOf( ':' );
825  QString name = line.mid( 0, index );
826  QString value = line.mid( index + 1, line.length() );
827  styledata.replace( name, value );
828  }
829  }
830  variablesfile.close();
831  }
832  file.close();
833 
834  if ( Qgis::UI_SCALE_FACTOR != 1.0 )
835  {
836  // apply OS-specific UI scale factor to stylesheet's em values
837  int index = 0;
838  QRegularExpression regex( QStringLiteral( "(?<=[\\s:])([0-9\\.]+)(?=em)" ) );
839  QRegularExpressionMatch match = regex.match( styledata, index );
840  while ( match.hasMatch() )
841  {
842  index = match.capturedStart();
843  styledata.remove( index, match.captured( 0 ).length() );
844  QString number = QString::number( match.captured( 0 ).toDouble() * Qgis::UI_SCALE_FACTOR );
845  styledata.insert( index, number );
846  index += number.length();
847  match = regex.match( styledata, index );
848  }
849  }
850 
851  qApp->setStyleSheet( styledata );
852 
853  QFile palettefile( path + "/palette.txt" );
854  QFileInfo paletteInfo( palettefile );
855  if ( paletteInfo.exists() && palettefile.open( QIODevice::ReadOnly ) )
856  {
857  QPalette pal = qApp->palette();
858  QTextStream in( &palettefile );
859  while ( !in.atEnd() )
860  {
861  QString line = in.readLine();
862  QStringList parts = line.split( ':' );
863  if ( parts.count() == 2 )
864  {
865  int role = parts.at( 0 ).trimmed().toInt();
866  QColor color = QgsSymbolLayerUtils::decodeColor( parts.at( 1 ).trimmed() );
867  pal.setColor( static_cast< QPalette::ColorRole >( role ), color );
868  }
869  }
870  palettefile.close();
871  qApp->setPalette( pal );
872  }
873 
874  setThemeName( themeName );
875 }
876 
877 QHash<QString, QString> QgsApplication::uiThemes()
878 {
879  QStringList paths = QStringList() << userThemesFolder() << defaultThemesFolder();
880  QHash<QString, QString> mapping;
881  mapping.insert( QStringLiteral( "default" ), QString() );
882  const auto constPaths = paths;
883  for ( const QString &path : constPaths )
884  {
885  QDir folder( path );
886  QFileInfoList styleFiles = folder.entryInfoList( QDir::Dirs | QDir::NoDotAndDotDot );
887  const auto constStyleFiles = styleFiles;
888  for ( const QFileInfo &info : constStyleFiles )
889  {
890  QFileInfo styleFile( info.absoluteFilePath() + "/style.qss" );
891  if ( !styleFile.exists() )
892  continue;
893 
894  QString name = info.baseName();
895  QString path = info.absoluteFilePath();
896  mapping.insert( name, path );
897  }
898  }
899  return mapping;
900 }
901 
903 {
904  return pkgDataPath() + QStringLiteral( "/doc/AUTHORS" );
905 }
906 
908 {
909  return pkgDataPath() + QStringLiteral( "/doc/CONTRIBUTORS" );
910 }
912 {
913  return pkgDataPath() + QStringLiteral( "/doc/developersmap.html" );
914 }
915 
917 {
918  return pkgDataPath() + QStringLiteral( "/doc/SPONSORS" );
919 }
920 
922 {
923  return pkgDataPath() + QStringLiteral( "/doc/DONORS" );
924 }
925 
927 {
928  return pkgDataPath() + QStringLiteral( "/doc/TRANSLATORS" );
929 }
930 
932 {
933  return pkgDataPath() + QStringLiteral( "/doc/LICENSE" );
934 }
935 
937 {
938  if ( ABISYM( mRunningFromBuildDir ) )
939  return *sBuildOutputPath() + QStringLiteral( "/i18n/" );
940  else
941  return pkgDataPath() + QStringLiteral( "/i18n/" );
942 }
943 
945 {
946  return pkgDataPath() + QStringLiteral( "/resources/metadata-ISO/" );
947 }
948 
950 {
951  return pkgDataPath() + QStringLiteral( "/resources/qgis.db" );
952 }
953 
955 {
956  return *sConfigPath();
957 }
958 
960 {
961  return qgisSettingsDirPath() + QStringLiteral( "qgis.db" );
962 }
963 
965 {
966  return *sAuthDbDirPath() + QStringLiteral( "qgis-auth.db" );
967 }
968 
970 {
971  return QStringLiteral( ":/images/splash/" );
972 }
973 
975 {
976  return pkgDataPath() + QStringLiteral( "/images/icons/" );
977 }
978 
980 {
981  if ( ABISYM( mRunningFromBuildDir ) )
982  {
983 #if PROJ_VERSION_MAJOR>=6
984  QString tempCopy = QDir::tempPath() + "/srs6.db";
985 #else
986  QString tempCopy = QDir::tempPath() + "/srs.db";
987 #endif
988 
989  if ( !QFile( tempCopy ).exists() )
990  {
991 #if PROJ_VERSION_MAJOR>=6
992  QFile f( buildSourcePath() + "/resources/srs6.db" );
993 #else
994  QFile f( buildSourcePath() + "/resources/srs.db" );
995 #endif
996  if ( !f.copy( tempCopy ) )
997  {
998  qFatal( "Could not create temporary copy" );
999  }
1000  }
1001 
1002  return tempCopy;
1003  }
1004  else
1005  {
1006  return pkgDataPath() + QStringLiteral( "/resources/srs.db" );
1007  }
1008 }
1009 
1011 {
1012  //local directories to search when looking for an SVG with a given basename
1013  //defined by user in options dialog
1014  QgsSettings settings;
1015  const QStringList pathList = settings.value( QStringLiteral( "svg/searchPathsForSVG" ) ).toStringList();
1016 
1017  // maintain user set order while stripping duplicates
1018  QStringList paths;
1019  for ( const QString &path : pathList )
1020  {
1021  if ( !paths.contains( path ) )
1022  paths.append( path );
1023  }
1024  for ( const QString &path : qgis::as_const( *sDefaultSvgPaths() ) )
1025  {
1026  if ( !paths.contains( path ) )
1027  paths.append( path );
1028  }
1029 
1030  return paths;
1031 }
1032 
1034 {
1035  //local directories to search when looking for an template with a given basename
1036  //defined by user in options dialog
1037  QgsSettings settings;
1038  QStringList pathList = settings.value( QStringLiteral( "Layout/searchPathsForTemplates" ), QVariant(), QgsSettings::Core ).toStringList();
1039 
1040  return pathList;
1041 }
1042 
1043 QMap<QString, QString> QgsApplication::systemEnvVars()
1044 {
1045  return *sSystemEnvVars();
1046 }
1047 
1049 {
1050  return qgisSettingsDirPath() + QStringLiteral( "symbology-style.db" );
1051 }
1052 
1054 {
1055  return QRegExp( "^[A-Za-z][A-Za-z0-9\\._-]*" );
1056 }
1057 
1059 {
1060  if ( !sUserName()->isEmpty() )
1061  return *sUserName();
1062 
1063 #ifdef _MSC_VER
1064  TCHAR name [ UNLEN + 1 ];
1065  DWORD size = UNLEN + 1;
1066 
1067  if ( GetUserName( ( TCHAR * )name, &size ) )
1068  {
1069  *sUserName() = QString::fromLocal8Bit( name );
1070  }
1071 
1072 #elif QT_CONFIG(process)
1073  QProcess process;
1074 
1075  process.start( QStringLiteral( "whoami" ) );
1076  process.waitForFinished();
1077  *sUserName() = process.readAllStandardOutput().trimmed();
1078 #endif
1079 
1080  if ( !sUserName()->isEmpty() )
1081  return *sUserName();
1082 
1083  //backup plan - use environment variables
1084  *sUserName() = qgetenv( "USER" );
1085  if ( !sUserName()->isEmpty() )
1086  return *sUserName();
1087 
1088  //last resort
1089  *sUserName() = qgetenv( "USERNAME" );
1090  return *sUserName();
1091 }
1092 
1094 {
1095  if ( !sUserFullName()->isEmpty() )
1096  return *sUserFullName();
1097 
1098 #ifdef _MSC_VER
1099  TCHAR name [ UNLEN + 1 ];
1100  DWORD size = UNLEN + 1;
1101 
1102  //note - this only works for accounts connected to domain
1103  if ( GetUserNameEx( NameDisplay, ( TCHAR * )name, &size ) )
1104  {
1105  *sUserFullName() = QString::fromLocal8Bit( name );
1106  }
1107 
1108  //fall back to login name
1109  if ( sUserFullName()->isEmpty() )
1110  *sUserFullName() = userLoginName();
1111 #elif defined(Q_OS_ANDROID) || defined(__MINGW32__)
1112  *sUserFullName() = QStringLiteral( "Not available" );
1113 #else
1114  struct passwd *p = getpwuid( getuid() );
1115 
1116  if ( p )
1117  {
1118  QString gecosName = QString( p->pw_gecos );
1119  *sUserFullName() = gecosName.left( gecosName.indexOf( ',', 0 ) );
1120  }
1121 
1122 #endif
1123 
1124  return *sUserFullName();
1125 }
1126 
1128 {
1129 #if defined(Q_OS_ANDROID)
1130  return QLatin1String( "android" );
1131 #elif defined(Q_OS_MAC)
1132  return QLatin1String( "osx" );
1133 #elif defined(Q_OS_WIN)
1134  return QLatin1String( "windows" );
1135 #elif defined(Q_OS_LINUX)
1136  return QStringLiteral( "linux" );
1137 #elif defined(Q_OS_FREEBSD)
1138  return QStringLiteral( "freebsd" );
1139 #elif defined(Q_OS_OPENBSD)
1140  return QStringLiteral( "openbsd" );
1141 #elif defined(Q_OS_NETBSD)
1142  return QStringLiteral( "netbsd" );
1143 #elif defined(Q_OS_UNIX)
1144  return QLatin1String( "unix" );
1145 #else
1146  return QLatin1String( "unknown" );
1147 #endif
1148 }
1149 
1151 {
1152  return *sPlatformName();
1153 }
1154 
1156 {
1157  QgsSettings settings;
1158  bool overrideLocale = settings.value( QStringLiteral( "locale/overrideFlag" ), false ).toBool();
1159  if ( overrideLocale )
1160  {
1161  QString locale = settings.value( QStringLiteral( "locale/userLocale" ), QString() ).toString();
1162  // don't differentiate en_US and en_GB
1163  if ( locale.startsWith( QLatin1String( "en" ), Qt::CaseInsensitive ) )
1164  {
1165  return locale.left( 2 );
1166  }
1167 
1168  return locale;
1169  }
1170  else
1171  {
1172  return QLocale().name().left( 2 );
1173  }
1174 }
1175 
1177 {
1178  return qgisSettingsDirPath() + QStringLiteral( "/themes" );
1179 }
1180 
1182 {
1183  return pkgDataPath() + QStringLiteral( "/resources/symbology-style.xml" );
1184 }
1185 
1187 {
1188  return pkgDataPath() + QStringLiteral( "/resources/themes" );
1189 }
1190 
1192 {
1193  return pkgDataPath() + QStringLiteral( "/resources/server/" );
1194 }
1195 
1197 {
1198  return *sLibraryPath();
1199 }
1200 
1202 {
1203  return *sLibexecPath();
1204 }
1205 
1207 {
1208  return *sQmlImportPath();
1209 }
1210 
1212 {
1213  return ( htonl( 1 ) == 1 ) ? XDR : NDR;
1214 }
1215 
1217 {
1218  if ( !ABISYM( mInitialized ) && QgsApplication::instance() )
1219  {
1220  init( *sProfilePath() );
1221  }
1222 
1223  // set the provider plugin path (this creates provider registry)
1225 
1226  // create data item provider registry
1228 
1229  // create project instance if doesn't exist
1231 
1232  // Initialize authentication manager and connect to database
1234 
1235  // Make sure we have a NAM created on the main thread.
1236  // Note that this might call QgsApplication::authManager to
1237  // setup the proxy configuration that's why it needs to be
1238  // called after the QgsAuthManager instance has been created
1240 
1241 }
1242 
1243 
1245 {
1246  if ( instance() )
1247  {
1248  if ( !instance()->mAuthManager )
1249  {
1250  instance()->mAuthManager = QgsAuthManager::instance();
1251  }
1252  return instance()->mAuthManager;
1253  }
1254  else
1255  {
1256  // no QgsApplication instance
1257  if ( !sAuthManager )
1258  sAuthManager = QgsAuthManager::instance();
1259  return sAuthManager;
1260  }
1261 }
1262 
1263 
1265 {
1266  // make sure all threads are done before exiting
1267  QThreadPool::globalInstance()->waitForDone();
1268 
1269  // don't create to delete
1270  if ( instance() )
1271  delete instance()->mAuthManager;
1272  else
1273  delete sAuthManager;
1274 
1275  //Ensure that all remaining deleteLater QObjects are actually deleted before we exit.
1276  //This isn't strictly necessary (since we're exiting anyway) but doing so prevents a lot of
1277  //LeakSanitiser noise which hides real issues
1278  QgsApplication::sendPostedEvents( nullptr, QEvent::DeferredDelete );
1279 
1280  //delete all registered functions from expression engine (see above comment)
1282 
1283  delete QgsProject::instance();
1284 
1285  // avoid creating instance just to delete it!
1286  if ( QgsProviderRegistry::exists() )
1288 
1289  invalidateCaches();
1290 
1292 
1293  // tear-down GDAL/OGR
1294  OGRCleanupAll();
1295  GDALDestroyDriverManager();
1296 }
1297 
1299 {
1300  QString myEnvironmentVar( getenv( "QGIS_PREFIX_PATH" ) );
1301  QString myState = tr( "Application state:\n"
1302  "QGIS_PREFIX_PATH env var:\t\t%1\n"
1303  "Prefix:\t\t%2\n"
1304  "Plugin Path:\t\t%3\n"
1305  "Package Data Path:\t%4\n"
1306  "Active Theme Name:\t%5\n"
1307  "Active Theme Path:\t%6\n"
1308  "Default Theme Path:\t%7\n"
1309  "SVG Search Paths:\t%8\n"
1310  "User DB Path:\t%9\n"
1311  "Auth DB Path:\t%10\n" )
1312  .arg( myEnvironmentVar,
1313  prefixPath(),
1314  pluginPath(),
1315  pkgDataPath(),
1316  themeName(),
1317  activeThemePath(),
1318  defaultThemePath(),
1319  svgPaths().join( tr( "\n\t\t", "match indentation of application state" ) ),
1321  .arg( qgisAuthDatabaseFilePath() );
1322  return myState;
1323 }
1324 
1326 {
1327  //
1328  // Make the style sheet desktop preferences aware by using qapplication
1329  // palette as a basis for colors where appropriate
1330  //
1331  // QColor myColor1 = palette().highlight().color();
1332  QColor myColor1( Qt::lightGray );
1333  QColor myColor2 = myColor1;
1334  myColor2 = myColor2.lighter( 110 ); //10% lighter
1335  QString myStyle;
1336  myStyle = QStringLiteral( ".overview{"
1337  " font: 1.82em;"
1338  " font-weight: bold;"
1339  "}"
1340  "body{"
1341  " background: white;"
1342  " color: black;"
1343  " font-family: 'Lato', 'Ubuntu', 'Lucida Grande', 'Segoe UI', 'Arial', sans-serif;"
1344  " width: 100%;"
1345  "}"
1346  "h1{ background-color: #F6F6F6;"
1347  " color: #589632; " // from http://qgis.org/en/site/getinvolved/styleguide.html
1348  " font-size: x-large; "
1349  " font-weight: normal;"
1350  " background: none;"
1351  " padding: 0.75em 0 0;"
1352  " margin: 0;"
1353  " line-height: 3em;"
1354  "}"
1355  "h2{ background-color: #F6F6F6;"
1356  " color: #589632; " // from http://qgis.org/en/site/getinvolved/styleguide.html
1357  " font-size: medium; "
1358  " font-weight: normal;"
1359  " background: none;"
1360  " padding: 0.75em 0 0;"
1361  " margin: 0;"
1362  " line-height: 1.1em;"
1363  "}"
1364  "h3{ background-color: #F6F6F6;"
1365  " color: #93b023;" // from http://qgis.org/en/site/getinvolved/styleguide.html
1366  " font-weight: bold;"
1367  " font-size: large;"
1368  " text-align: left;"
1369  " border-bottom: 5px solid #DCEB5C;"
1370  "}"
1371  "h4{ background-color: #F6F6F6;"
1372  " color: #93b023;" // from http://qgis.org/en/site/getinvolved/styleguide.html
1373  " font-weight: bold;"
1374  " font-size: medium;"
1375  " text-align: left;"
1376  "}"
1377  "h5{ background-color: #F6F6F6;"
1378  " color: #93b023;" // from http://qgis.org/en/site/getinvolved/styleguide.html
1379  " font-weight: bold;"
1380  " font-size: small;"
1381  " text-align: left;"
1382  "}"
1383  "a{ color: #729FCF;"
1384  " font-family: arial,sans-serif;"
1385  "}"
1386  "label{ background-color: #FFFFCC;"
1387  " border: 1px solid black;"
1388  " margin: 1px;"
1389  " padding: 0px 3px; "
1390  " font-size: small;"
1391  "}"
1392  "th .strong {"
1393  " font-weight: bold;"
1394  "}"
1395  "hr {"
1396  " border: 0;"
1397  " height: 0;"
1398  " border-top: 1px solid black;"
1399  "}"
1400  ".list-view .highlight {"
1401  " text-align: left;"
1402  " border: 0px;"
1403  " width: 20%;"
1404  " padding-right: 15px;"
1405  " padding-left: 20px;"
1406  " font-weight: bold;"
1407  "}"
1408  ".tabular-view .odd-row {"
1409  " background-color: #f9f9f9;"
1410  "}"
1411  ".section {"
1412  " font-weight: bold;"
1413  " padding-top:25px;"
1414  "}" );
1415 
1416  // We have some subtle differences between Qt based style and QWebKit style
1417  switch ( styleSheetType )
1418  {
1419  case StyleSheetType::Qt:
1420  myStyle += QStringLiteral(
1421  ".tabular-view{ "
1422  " border-collapse: collapse;"
1423  " width: 95%;"
1424  "}"
1425  ".tabular-view th, .tabular-view td { "
1426  " border:10px solid black;"
1427  "}" );
1428  break;
1429 
1430  case StyleSheetType::WebBrowser:
1431  myStyle += QStringLiteral(
1432  "body { "
1433  " margin: auto;"
1434  " width: 97%;"
1435  "}"
1436  "table.tabular-view, table.list-view { "
1437  " border-collapse: collapse;"
1438  " table-layout:fixed;"
1439  " width: 100% !important;"
1440  " font-size: 90%;"
1441  "}"
1442  // Override
1443  "h1 { "
1444  " line-height: inherit;"
1445  "}"
1446  "td, th {"
1447  " word-wrap: break-word; "
1448  " vertical-align: top;"
1449  "}"
1450  // Set first column width
1451  ".list-view th:first-child, .list-view td:first-child {"
1452  " width: 20%;"
1453  "}"
1454  ".list-view.highlight { "
1455  " padding-left: inherit; "
1456  "}"
1457  // Set first column width for inner tables
1458  ".tabular-view th:first-child, .tabular-view td:first-child { "
1459  " width: 20%; "
1460  "}"
1461  // Makes titles bg stand up
1462  ".tabular-view th.strong { "
1463  " background-color: #eee; "
1464  "}"
1465  // Give some visual appearance to those ugly nested tables
1466  ".tabular-view th, .tabular-view td { "
1467  " border: solid 1px #eee;"
1468  "}"
1469  );
1470  break;
1471  }
1472 
1473  return myStyle;
1474 }
1475 
1477 {
1478  if ( 0 >= OGRGetDriverCount() )
1479  {
1480  OGRRegisterAll();
1481  }
1482 }
1483 
1484 QString QgsApplication::absolutePathToRelativePath( const QString &aPath, const QString &targetPath )
1485 {
1486  QString aPathUrl = aPath;
1487  QString tPathUrl = targetPath;
1488 #if defined( Q_OS_WIN )
1489  const Qt::CaseSensitivity cs = Qt::CaseInsensitive;
1490 
1491  aPathUrl.replace( '\\', '/' );
1492  if ( aPathUrl.startsWith( "//" ) )
1493  {
1494  // keep UNC prefix
1495  aPathUrl = "\\\\" + aPathUrl.mid( 2 );
1496  }
1497 
1498  tPathUrl.replace( '\\', '/' );
1499  if ( tPathUrl.startsWith( "//" ) )
1500  {
1501  // keep UNC prefix
1502  tPathUrl = "\\\\" + tPathUrl.mid( 2 );
1503  }
1504 #else
1505  const Qt::CaseSensitivity cs = Qt::CaseSensitive;
1506 #endif
1507 
1508  QStringList targetElems = tPathUrl.split( '/', QString::SkipEmptyParts );
1509  QStringList aPathElems = aPathUrl.split( '/', QString::SkipEmptyParts );
1510 
1511  targetElems.removeAll( QStringLiteral( "." ) );
1512  aPathElems.removeAll( QStringLiteral( "." ) );
1513 
1514  // remove common part
1515  int n = 0;
1516  while ( !aPathElems.isEmpty() &&
1517  !targetElems.isEmpty() &&
1518  aPathElems[0].compare( targetElems[0], cs ) == 0 )
1519  {
1520  aPathElems.removeFirst();
1521  targetElems.removeFirst();
1522  n++;
1523  }
1524 
1525  if ( n == 0 )
1526  {
1527  // no common parts; might not even be a file
1528  return aPathUrl;
1529  }
1530 
1531  if ( !targetElems.isEmpty() )
1532  {
1533  // go up to the common directory
1534  for ( int i = 0; i < targetElems.size(); i++ )
1535  {
1536  aPathElems.insert( 0, QStringLiteral( ".." ) );
1537  }
1538  }
1539  else
1540  {
1541  // let it start with . nevertheless,
1542  // so relative path always start with either ./ or ../
1543  aPathElems.insert( 0, QStringLiteral( "." ) );
1544  }
1545 
1546  return aPathElems.join( QStringLiteral( "/" ) );
1547 }
1548 
1549 QString QgsApplication::relativePathToAbsolutePath( const QString &rpath, const QString &targetPath )
1550 {
1551  // relative path should always start with ./ or ../
1552  if ( !rpath.startsWith( QLatin1String( "./" ) ) && !rpath.startsWith( QLatin1String( "../" ) ) )
1553  {
1554  return rpath;
1555  }
1556 
1557  QString rPathUrl = rpath;
1558  QString targetPathUrl = targetPath;
1559 
1560 #if defined(Q_OS_WIN)
1561  rPathUrl.replace( '\\', '/' );
1562  targetPathUrl.replace( '\\', '/' );
1563 
1564  bool uncPath = targetPathUrl.startsWith( "//" );
1565 #endif
1566 
1567  QStringList srcElems = rPathUrl.split( '/', QString::SkipEmptyParts );
1568  QStringList targetElems = targetPathUrl.split( '/', QString::SkipEmptyParts );
1569 
1570 #if defined(Q_OS_WIN)
1571  if ( uncPath )
1572  {
1573  targetElems.insert( 0, "" );
1574  targetElems.insert( 0, "" );
1575  }
1576 #endif
1577 
1578  // append source path elements
1579  targetElems << srcElems;
1580  targetElems.removeAll( QStringLiteral( "." ) );
1581 
1582  // resolve ..
1583  int pos;
1584  while ( ( pos = targetElems.indexOf( QStringLiteral( ".." ) ) ) > 0 )
1585  {
1586  // remove preceding element and ..
1587  targetElems.removeAt( pos - 1 );
1588  targetElems.removeAt( pos - 1 );
1589  }
1590 
1591 #if !defined(Q_OS_WIN)
1592  // make path absolute
1593  targetElems.prepend( QString() );
1594 #endif
1595 
1596  return targetElems.join( QStringLiteral( "/" ) );
1597 }
1598 
1600 {
1601  return *sBuildSourcePath();
1602 }
1603 
1605 {
1606  return *sBuildOutputPath();
1607 }
1608 
1609 #if defined(_MSC_VER) && !defined(USING_NMAKE) && !defined(USING_NINJA)
1610 QString QgsApplication::cfgIntDir()
1611 {
1612  return *sCfgIntDir();
1613 }
1614 #endif
1615 
1616 void QgsApplication::skipGdalDriver( const QString &driver )
1617 {
1618  if ( sGdalSkipList()->contains( driver ) || driver.isEmpty() )
1619  {
1620  return;
1621  }
1622  *sGdalSkipList() << driver;
1624 }
1625 
1626 void QgsApplication::restoreGdalDriver( const QString &driver )
1627 {
1628  if ( !sGdalSkipList()->contains( driver ) )
1629  {
1630  return;
1631  }
1632  int myPos = sGdalSkipList()->indexOf( driver );
1633  if ( myPos >= 0 )
1634  {
1635  sGdalSkipList()->removeAt( myPos );
1636  }
1638 }
1639 
1641 {
1642  return *sGdalSkipList();
1643 }
1644 
1646  const QStringList &deferredSkippedGdalDrivers )
1647 {
1648  *sGdalSkipList() = skippedGdalDrivers;
1649  *sDeferredSkippedGdalDrivers() = deferredSkippedGdalDrivers;
1650 
1651  QgsSettings settings;
1652  settings.setValue( QStringLiteral( "gdal/skipList" ), skippedGdalDrivers.join( QStringLiteral( " " ) ) );
1653 
1655 }
1656 
1658 {
1659  QgsSettings settings;
1660  QString joinedList = settings.value( QStringLiteral( "gdal/skipList" ), QString() ).toString();
1661  QStringList myList;
1662  if ( !joinedList.isEmpty() )
1663  {
1664  myList = joinedList.split( ' ' );
1665  }
1666  *sGdalSkipList() = myList;
1668 }
1669 
1671 {
1672  return *sDeferredSkippedGdalDrivers();
1673 }
1674 
1676 {
1677  sGdalSkipList()->removeDuplicates();
1678  QStringList realDisabledDriverList;
1679  for ( const auto &driverName : *sGdalSkipList() )
1680  {
1681  if ( !sDeferredSkippedGdalDrivers()->contains( driverName ) )
1682  realDisabledDriverList << driverName;
1683  }
1684  QString myDriverList = realDisabledDriverList.join( ' ' );
1685  QgsDebugMsgLevel( QStringLiteral( "Gdal Skipped driver list set to:" ), 1 );
1686  QgsDebugMsgLevel( myDriverList, 1 );
1687  CPLSetConfigOption( "GDAL_SKIP", myDriverList.toUtf8() );
1688  GDALAllRegister(); //to update driver list and skip missing ones
1689 }
1690 
1692 {
1693  QString folder = userThemesFolder();
1694  QDir myDir( folder );
1695  if ( !myDir.exists() )
1696  {
1697  myDir.mkpath( folder );
1698  }
1699 
1700  return true;
1701 }
1702 
1703 void QgsApplication::copyPath( const QString &src, const QString &dst )
1704 {
1705  QDir dir( src );
1706  if ( ! dir.exists() )
1707  return;
1708 
1709  const auto subDirectories = dir.entryList( QDir::Dirs | QDir::NoDotAndDotDot );
1710  for ( const QString &d : subDirectories )
1711  {
1712  QString dst_path = dst + QDir::separator() + d;
1713  dir.mkpath( dst_path );
1714  copyPath( src + QDir::separator() + d, dst_path );
1715  }
1716 
1717  const auto files = dir.entryList( QDir::Files );
1718  for ( const QString &f : files )
1719  {
1720  QFile::copy( src + QDir::separator() + f, dst + QDir::separator() + f );
1721  }
1722 }
1723 
1725 {
1726  //read values from QgsSettings
1727  QgsSettings settings;
1728 
1729  QVariantMap variables;
1730 
1731  //check if settings contains any variables
1732  settings.beginGroup( "variables" );
1733  QStringList childKeys = settings.childKeys();
1734  for ( QStringList::const_iterator it = childKeys.constBegin(); it != childKeys.constEnd(); ++it )
1735  {
1736  QString name = *it;
1737  variables.insert( name, settings.value( name ) );
1738  }
1739 
1740  return variables;
1741 }
1742 
1743 void QgsApplication::setCustomVariables( const QVariantMap &variables )
1744 {
1745  QgsSettings settings;
1746 
1747  QVariantMap::const_iterator it = variables.constBegin();
1748  settings.beginGroup( "variables" );
1749  settings.remove( "" );
1750  for ( ; it != variables.constEnd(); ++it )
1751  {
1752  settings.setValue( it.key(), it.value() );
1753  }
1754 
1755  emit instance()->customVariablesChanged();
1756 }
1757 
1758 void QgsApplication::setCustomVariable( const QString &name, const QVariant &value )
1759 {
1760  // save variable to settings
1761  QgsSettings settings;
1762 
1763  settings.setValue( QStringLiteral( "variables/" ) + name, value );
1764 
1765  emit instance()->customVariablesChanged();
1766 }
1767 
1769 {
1771 }
1772 
1773 void QgsApplication::setTranslation( const QString &translation )
1774 {
1775  *sTranslation() = translation;
1776 }
1777 
1779 {
1780  emit requestForTranslatableObjects( translationContext );
1781 }
1782 
1784 {
1785  ApplicationMembers *appMembers = members();
1786  if ( appMembers->mNullRepresentation.isNull() )
1787  {
1788  appMembers->mNullRepresentation = QgsSettings().value( QStringLiteral( "qgis/nullValue" ), QStringLiteral( "NULL" ) ).toString();
1789  }
1790  return appMembers->mNullRepresentation;
1791 }
1792 
1794 {
1795  ApplicationMembers *appMembers = members();
1796  if ( !appMembers || appMembers->mNullRepresentation == nullRepresentation )
1797  return;
1798 
1799  appMembers->mNullRepresentation = nullRepresentation;
1800  QgsSettings().setValue( QStringLiteral( "qgis/nullValue" ), nullRepresentation );
1801 
1802  QgsApplication *app = instance();
1803  if ( app )
1804  emit app->nullRepresentationChanged();
1805 }
1806 
1808 {
1809  return members()->mActionScopeRegistry;
1810 }
1811 
1812 bool QgsApplication::createDatabase( QString *errorMessage )
1813 {
1814  // set a working directory up for gdal to write .aux.xml files into
1815  // for cases where the raster dir is read only to the user
1816  // if the env var is already set it will be used preferentially
1817  QString myPamPath = qgisSettingsDirPath() + QStringLiteral( "gdal_pam/" );
1818  QDir myDir( myPamPath );
1819  if ( !myDir.exists() )
1820  {
1821  myDir.mkpath( myPamPath ); //fail silently
1822  }
1823 
1824 #if defined(Q_OS_WIN)
1825  CPLSetConfigOption( "GDAL_PAM_PROXY_DIR", myPamPath.toUtf8() );
1826 #else
1827  //under other OS's we use an environment var so the user can
1828  //override the path if he likes
1829  int myChangeFlag = 0; //whether we want to force the env var to change
1830  setenv( "GDAL_PAM_PROXY_DIR", myPamPath.toUtf8(), myChangeFlag );
1831 #endif
1832 
1833  // Check qgis.db and make private copy if necessary
1834  QFile qgisPrivateDbFile( QgsApplication::qgisUserDatabaseFilePath() );
1835 
1836  // first we look for ~/.qgis/qgis.db
1837  if ( !qgisPrivateDbFile.exists() )
1838  {
1839  // if it doesn't exist we copy it in from the global resources dir
1840  QString qgisMasterDbFileName = QgsApplication::qgisMasterDatabaseFilePath();
1841  QFile masterFile( qgisMasterDbFileName );
1842 
1843  // Must be sure there is destination directory ~/.qgis
1844  QDir().mkpath( QgsApplication::qgisSettingsDirPath() );
1845 
1846  //now copy the master file into the users .qgis dir
1847  bool isDbFileCopied = masterFile.copy( qgisPrivateDbFile.fileName() );
1848 
1849  if ( !isDbFileCopied )
1850  {
1851  if ( errorMessage )
1852  {
1853  *errorMessage = tr( "[ERROR] Can not make qgis.db private copy" );
1854  }
1855  return false;
1856  }
1857 
1858  QFile::Permissions perms = QFile( qgisPrivateDbFile.fileName() ).permissions();
1859  if ( !( perms & QFile::WriteOwner ) )
1860  {
1861  if ( !qgisPrivateDbFile.setPermissions( perms | QFile::WriteOwner ) )
1862  {
1863  if ( errorMessage )
1864  {
1865  *errorMessage = tr( "Can not make '%1' user writable" ).arg( qgisPrivateDbFile.fileName() );
1866  }
1867  return false;
1868  }
1869  }
1870  }
1871  else
1872  {
1873  // migrate if necessary
1874  sqlite3_database_unique_ptr database;
1875  if ( database.open( QgsApplication::qgisUserDatabaseFilePath() ) != SQLITE_OK )
1876  {
1877  if ( errorMessage )
1878  {
1879  *errorMessage = tr( "Could not open qgis.db" );
1880  }
1881  return false;
1882  }
1883 
1884  char *errmsg = nullptr;
1885  int res = sqlite3_exec( database.get(), "SELECT srs_id FROM tbl_srs LIMIT 0", nullptr, nullptr, &errmsg );
1886  if ( res != SQLITE_OK )
1887  {
1888  sqlite3_free( errmsg );
1889 
1890  // qgis.db is missing tbl_srs, create it
1891  if ( sqlite3_exec( database.get(),
1892  "DROP INDEX IF EXISTS idx_srsauthid;"
1893  "CREATE TABLE tbl_srs ("
1894  "srs_id INTEGER PRIMARY KEY,"
1895  "description text NOT NULL,"
1896  "projection_acronym text NOT NULL,"
1897  "ellipsoid_acronym NOT NULL,"
1898  "parameters text NOT NULL,"
1899  "srid integer,"
1900  "auth_name varchar,"
1901  "auth_id varchar,"
1902  "is_geo integer NOT NULL,"
1903  "deprecated boolean,"
1904  "wkt text);"
1905  "CREATE INDEX idx_srsauthid on tbl_srs(auth_name,auth_id);", nullptr, nullptr, &errmsg ) != SQLITE_OK )
1906  {
1907  if ( errorMessage )
1908  {
1909  *errorMessage = tr( "Creation of missing tbl_srs in the private qgis.db failed.\n%1" ).arg( QString::fromUtf8( errmsg ) );
1910  }
1911  sqlite3_free( errmsg );
1912  return false;
1913  }
1914  }
1915  else
1916  {
1917  // test if wkt column exists in database
1918  res = sqlite3_exec( database.get(), "SELECT wkt FROM tbl_srs LIMIT 0", nullptr, nullptr, &errmsg );
1919  if ( res != SQLITE_OK )
1920  {
1921  // need to add wkt column
1922  sqlite3_free( errmsg );
1923  if ( sqlite3_exec( database.get(),
1924  "DROP INDEX IF EXISTS idx_srsauthid;"
1925  "DROP TABLE IF EXISTS tbl_srs_bak;"
1926  "ALTER TABLE tbl_srs RENAME TO tbl_srs_bak;"
1927  "CREATE TABLE tbl_srs ("
1928  "srs_id INTEGER PRIMARY KEY,"
1929  "description text NOT NULL,"
1930  "projection_acronym text NOT NULL,"
1931  "ellipsoid_acronym NOT NULL,"
1932  "parameters text NOT NULL,"
1933  "srid integer,"
1934  "auth_name varchar,"
1935  "auth_id varchar,"
1936  "is_geo integer NOT NULL,"
1937  "deprecated boolean,"
1938  "wkt text);"
1939  "CREATE INDEX idx_srsauthid on tbl_srs(auth_name,auth_id);"
1940  "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;"
1941  "DROP TABLE tbl_srs_bak", nullptr, nullptr, &errmsg ) != SQLITE_OK )
1942  {
1943  if ( errorMessage )
1944  {
1945  *errorMessage = tr( "Migration of private qgis.db failed.\n%1" ).arg( QString::fromUtf8( errmsg ) );
1946  }
1947  sqlite3_free( errmsg );
1948  return false;
1949  }
1950  }
1951  }
1952 
1953  res = sqlite3_exec( database.get(), "SELECT acronym FROM tbl_projection LIMIT 0", nullptr, nullptr, &errmsg );
1954  if ( res != SQLITE_OK )
1955  {
1956  sqlite3_free( errmsg );
1957 
1958  // qgis.db is missing tbl_projection, create it
1959  if ( sqlite3_exec( database.get(),
1960  "CREATE TABLE tbl_projection ("
1961  "acronym varchar(20) NOT NULL PRIMARY KEY,"
1962  "name varchar(255) NOT NULL default '',"
1963  "notes varchar(255) NOT NULL default '',"
1964  "parameters varchar(255) NOT NULL default ''"
1965  ")", nullptr, nullptr, &errmsg ) != SQLITE_OK )
1966  {
1967  if ( errorMessage )
1968  {
1969  *errorMessage = tr( "Creation of missing tbl_projection in the private qgis.db failed.\n%1" ).arg( QString::fromUtf8( errmsg ) );
1970  }
1971  sqlite3_free( errmsg );
1972  return false;
1973  }
1974  }
1975 
1976  res = sqlite3_exec( database.get(), "SELECT epsg FROM tbl_srs LIMIT 0", nullptr, nullptr, &errmsg );
1977  if ( res == SQLITE_OK )
1978  {
1979  // epsg column exists => need migration
1980  if ( sqlite3_exec( database.get(),
1981  "DROP INDEX IF EXISTS idx_srsauthid;"
1982  "DROP TABLE IF EXISTS tbl_srs_bak;"
1983  "ALTER TABLE tbl_srs RENAME TO tbl_srs_bak;"
1984  "CREATE TABLE tbl_srs ("
1985  "srs_id INTEGER PRIMARY KEY,"
1986  "description text NOT NULL,"
1987  "projection_acronym text NOT NULL,"
1988  "ellipsoid_acronym NOT NULL,"
1989  "parameters text NOT NULL,"
1990  "srid integer,"
1991  "auth_name varchar,"
1992  "auth_id varchar,"
1993  "is_geo integer NOT NULL,"
1994  "deprecated boolean,"
1995  "wkt text);"
1996  "CREATE INDEX idx_srsauthid on tbl_srs(auth_name,auth_id);"
1997  "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;"
1998  "DROP TABLE tbl_srs_bak", nullptr, nullptr, &errmsg ) != SQLITE_OK )
1999  {
2000  if ( errorMessage )
2001  {
2002  *errorMessage = tr( "Migration of private qgis.db failed.\n%1" ).arg( QString::fromUtf8( errmsg ) );
2003  }
2004  sqlite3_free( errmsg );
2005  return false;
2006  }
2007  }
2008  else
2009  {
2010  sqlite3_free( errmsg );
2011  }
2012 
2013  if ( sqlite3_exec( database.get(), "DROP VIEW vw_srs", nullptr, nullptr, &errmsg ) != SQLITE_OK )
2014  {
2015  QgsDebugMsg( QStringLiteral( "vw_srs didn't exists in private qgis.db: %1" ).arg( errmsg ) );
2016  }
2017 
2018  if ( sqlite3_exec( database.get(),
2019  "CREATE VIEW vw_srs AS"
2020  " SELECT"
2021  " a.description AS description"
2022  ",a.srs_id AS srs_id"
2023  ",a.is_geo AS is_geo"
2024  ",coalesce(b.name,a.projection_acronym) AS name"
2025  ",a.parameters AS parameters"
2026  ",a.auth_name AS auth_name"
2027  ",a.auth_id AS auth_id"
2028  ",a.deprecated AS deprecated"
2029  " FROM tbl_srs a"
2030  " LEFT OUTER JOIN tbl_projection b ON a.projection_acronym=b.acronym"
2031  " ORDER BY coalesce(b.name,a.projection_acronym),a.description", nullptr, nullptr, &errmsg ) != SQLITE_OK )
2032  {
2033  if ( errorMessage )
2034  {
2035  *errorMessage = tr( "Update of view in private qgis.db failed.\n%1" ).arg( QString::fromUtf8( errmsg ) );
2036  }
2037  sqlite3_free( errmsg );
2038  return false;
2039  }
2040  }
2041  return true;
2042 }
2043 
2045 {
2046  QgsDebugMsgLevel( QStringLiteral( "maxThreads: %1" ).arg( maxThreads ), 1 );
2047 
2048  // make sure value is between 1 and #cores, if not set to -1 (use #cores)
2049  // 0 could be used to disable any parallel processing
2050  if ( maxThreads < 1 || maxThreads > QThread::idealThreadCount() )
2051  maxThreads = -1;
2052 
2053  // save value
2054  ABISYM( sMaxThreads ) = maxThreads;
2055 
2056  // if -1 use #cores
2057  if ( maxThreads == -1 )
2058  maxThreads = QThread::idealThreadCount();
2059 
2060  // set max thread count in QThreadPool
2061  QThreadPool::globalInstance()->setMaxThreadCount( maxThreads );
2062  QgsDebugMsgLevel( QStringLiteral( "set QThreadPool max thread count to %1" ).arg( QThreadPool::globalInstance()->maxThreadCount() ), 1 );
2063 }
2064 
2066 {
2067  return members()->mTaskManager;
2068 }
2069 
2071 {
2072  return members()->mColorSchemeRegistry;
2073 }
2074 
2076 {
2077  return members()->mPaintEffectRegistry;
2078 }
2079 
2081 {
2082  return members()->mRendererRegistry;
2083 }
2084 
2086 {
2087  return members()->mRasterRendererRegistry;
2088 }
2089 
2091 {
2092  if ( instance() )
2093  {
2094  if ( !instance()->mDataItemProviderRegistry )
2095  {
2096  instance()->mDataItemProviderRegistry = new QgsDataItemProviderRegistry();
2097  }
2098  return instance()->mDataItemProviderRegistry;
2099  }
2100  else
2101  {
2102  // no QgsApplication instance
2103  static QgsDataItemProviderRegistry *sDataItemProviderRegistry = nullptr;
2104  if ( !sDataItemProviderRegistry )
2105  sDataItemProviderRegistry = new QgsDataItemProviderRegistry();
2106  return sDataItemProviderRegistry;
2107  }
2108 }
2109 
2111 {
2112  return members()->mSvgCache;
2113 }
2114 
2116 {
2117  return members()->mImageCache;
2118 }
2119 
2121 {
2122  return members()->mNetworkContentFetcherRegistry;
2123 }
2124 
2126 {
2127  return members()->mValidityCheckRegistry;
2128 }
2129 
2131 {
2132  return members()->mSymbolLayerRegistry;
2133 }
2134 
2136 {
2137  return members()->mCalloutRegistry;
2138 }
2139 
2141 {
2142  return members()->mLayoutItemRegistry;
2143 }
2144 
2146 {
2147  return members()->mGpsConnectionRegistry;
2148 }
2149 
2151 {
2152  return members()->mPluginLayerRegistry;
2153 }
2154 
2156 {
2157  return members()->mClassificationMethodRegistry;
2158 }
2159 
2161 {
2162  return members()->mBookmarkManager;
2163 }
2164 
2166 {
2167  return members()->mStyleModel;
2168 }
2169 
2171 {
2172  return members()->mMessageLog;
2173 }
2174 
2176 {
2177  return members()->mProcessingRegistry;
2178 }
2179 
2181 {
2182  return members()->mPageSizeRegistry;
2183 }
2184 
2185 QgsAnnotationRegistry *QgsApplication::annotationRegistry()
2186 {
2187  return members()->mAnnotationRegistry;
2188 }
2189 
2191 {
2192  return members()->mNumericFormatRegistry;
2193 }
2194 
2196 {
2197  return members()->mFieldFormatterRegistry;
2198 }
2199 
2201 {
2202  return members()->m3DRendererRegistry;
2203 }
2204 
2206 {
2207  return members()->mProjectStorageRegistry;
2208 }
2209 
2210 QgsApplication::ApplicationMembers::ApplicationMembers()
2211 {
2212  // don't use initializer lists or scoped pointers - as more objects are added here we
2213  // will need to be careful with the order of creation/destruction
2214  mMessageLog = new QgsMessageLog();
2215  mProfiler = new QgsRuntimeProfiler();
2216  mTaskManager = new QgsTaskManager();
2217  mActionScopeRegistry = new QgsActionScopeRegistry();
2218  mNumericFormatRegistry = new QgsNumericFormatRegistry();
2219  mFieldFormatterRegistry = new QgsFieldFormatterRegistry();
2220  mSvgCache = new QgsSvgCache();
2221  mImageCache = new QgsImageCache();
2222  mColorSchemeRegistry = new QgsColorSchemeRegistry();
2223  mPaintEffectRegistry = new QgsPaintEffectRegistry();
2224  mSymbolLayerRegistry = new QgsSymbolLayerRegistry();
2225  mCalloutRegistry = new QgsCalloutRegistry();
2226  mRendererRegistry = new QgsRendererRegistry();
2227  mRasterRendererRegistry = new QgsRasterRendererRegistry();
2228  mGpsConnectionRegistry = new QgsGpsConnectionRegistry();
2229  mPluginLayerRegistry = new QgsPluginLayerRegistry();
2230  mProcessingRegistry = new QgsProcessingRegistry();
2231  mPageSizeRegistry = new QgsPageSizeRegistry();
2232  mLayoutItemRegistry = new QgsLayoutItemRegistry();
2233  mLayoutItemRegistry->populate();
2234  mAnnotationRegistry = new QgsAnnotationRegistry();
2235  m3DRendererRegistry = new Qgs3DRendererRegistry();
2236  mProjectStorageRegistry = new QgsProjectStorageRegistry();
2237  mNetworkContentFetcherRegistry = new QgsNetworkContentFetcherRegistry();
2238  mValidityCheckRegistry = new QgsValidityCheckRegistry();
2239  mClassificationMethodRegistry = new QgsClassificationMethodRegistry();
2240  mBookmarkManager = new QgsBookmarkManager( nullptr );
2241 }
2242 
2243 QgsApplication::ApplicationMembers::~ApplicationMembers()
2244 {
2245  delete mStyleModel;
2246  delete mValidityCheckRegistry;
2247  delete mActionScopeRegistry;
2248  delete m3DRendererRegistry;
2249  delete mAnnotationRegistry;
2250  delete mColorSchemeRegistry;
2251  delete mFieldFormatterRegistry;
2252  delete mGpsConnectionRegistry;
2253  delete mMessageLog;
2254  delete mPaintEffectRegistry;
2255  delete mPluginLayerRegistry;
2256  delete mProcessingRegistry;
2257  delete mProjectStorageRegistry;
2258  delete mPageSizeRegistry;
2259  delete mLayoutItemRegistry;
2260  delete mProfiler;
2261  delete mRasterRendererRegistry;
2262  delete mRendererRegistry;
2263  delete mSvgCache;
2264  delete mImageCache;
2265  delete mCalloutRegistry;
2266  delete mSymbolLayerRegistry;
2267  delete mTaskManager;
2268  delete mNetworkContentFetcherRegistry;
2269  delete mClassificationMethodRegistry;
2270  delete mNumericFormatRegistry;
2271  delete mBookmarkManager;
2272 }
2273 
2274 QgsApplication::ApplicationMembers *QgsApplication::members()
2275 {
2276  if ( instance() )
2277  {
2278  return instance()->mApplicationMembers;
2279  }
2280  else
2281  {
2282  static QMutex sMemberMutex( QMutex::Recursive );
2283  QMutexLocker lock( &sMemberMutex );
2284  if ( !sApplicationMembers )
2285  sApplicationMembers = new ApplicationMembers();
2286  return sApplicationMembers;
2287  }
2288 }
static QStringList layoutTemplatePaths()
Returns the paths to layout template directories.
A QAbstractItemModel subclass for showing symbol and color ramp entities contained within a QgsStyle ...
Definition: qgsstylemodel.h:45
Singleton offering an interface to manage the authentication configuration database and to utilize co...
static QString locale()
Returns the QGIS locale.
static QgsSymbolLayerRegistry * symbolLayerRegistry()
Returns the application&#39;s symbol layer registry, used for managing symbol layers. ...
static QgsSvgCache * svgCache()
Returns the application&#39;s SVG cache, used for caching SVG images and handling parameter replacement w...
This class keeps a list of data item providers that may add items to the browser tree.
static QString buildSourcePath()
Returns path to the source directory. Valid only when running from build directory.
static void setThemeName(const QString &themeName)
Set the active theme to the specified theme.
void addDefaultSchemes()
Adds all default color schemes to this color scheme.
static Qgs3DRendererRegistry * renderer3DRegistry()
Returns registry of available 3D renderers.
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
static QgsCalloutRegistry * calloutRegistry()
Returns the application&#39;s callout registry, used for managing callout types.
static QString resolveProfilesFolder(const QString &basePath=QString())
Resolves the profiles folder for the given path.
static QgsAnnotationRegistry * annotationRegistry()
Returns the application&#39;s annotation registry, used for managing annotation types.
static void invalidateCache(bool disableCache=false)
Clears the internal cache used.
Extends QApplication to provide access to QGIS specific resources such as theme paths, database paths etc.
static QgsFieldFormatterRegistry * fieldFormatterRegistry()
Gets the registry of available field formatters.
Cursor
The Cursor enum defines constants for QGIS custom cursors.
static QString userStylePath()
Returns the path to user&#39;s style.
Registry of color schemes.
static QgsAuthManager * instance()
Enforce singleton pattern.
static QgsApplication * instance()
Returns the singleton instance of the QgsApplication.
static QString authorsFilePath()
Returns the path to the authors file.
static void setPrefixPath(const QString &prefixPath, bool useDefaultPaths=false)
Alters prefix path - used by 3rd party apps.
A registry of plugin layers types.
static QString qgisSettingsDirPath()
Returns the path to the settings directory in user&#39;s home dir.
static void invalidateCache(bool disableCache=false)
Clears the internal cache used to initialize QgsCoordinateReferenceSystem objects.
static void setCustomVariables(const QVariantMap &customVariables)
Custom expression variables for this application.
static QString libraryPath()
Returns the path containing qgis_core, qgis_gui, qgispython (and other) libraries.
static QgsRuntimeProfiler * profiler()
Returns the application runtime profiler.
static QString defaultThemePath()
Returns the path to the default theme directory.
static const double UI_SCALE_FACTOR
UI scaling factor.
Definition: qgis.h:182
This class is a composition of two QSettings instances:
Definition: qgssettings.h:58
static QString qgisMasterDatabaseFilePath()
Returns the path to the master qgis.db file.
void customVariablesChanged()
Emitted whenever a custom global variable changes.
static QString qgisUserDatabaseFilePath()
Returns the path to the user qgis.db file.
bool event(QEvent *event) override
Watch for QFileOpenEvent.
void requestForTranslatableObjects(QgsTranslationContext *translationContext)
Emitted when project strings which require translation are being collected for inclusion in a ...
static QString donorsFilePath()
Returns the path to the donors file.
static QString relativePathToAbsolutePath(const QString &rpath, const QString &targetPath)
Converts path relative to target to an absolute path.
QVariant value(const QString &key, const QVariant &defaultValue=QVariant(), Section section=NoSection) const
Returns the value for setting key.
#define QgsDebugMsg(str)
Definition: qgslogger.h:38
int maxConcurrentConnectionsPerPool() const
The maximum number of concurrent connections per connections pool.
void nullRepresentationChanged()
This string is used to represent the value NULL throughout QGIS.
static QgsImageCache * imageCache()
Returns the application&#39;s image cache, used for caching resampled versions of raster images...
static QgsValidityCheckRegistry * validityCheckRegistry()
Returns the application&#39;s validity check registry, used for managing validity checks.
static QString themeName()
Set the active theme to the specified theme.
static QString defaultThemesFolder()
Returns the path to default themes folder from install (works as a starting point).
void initStyleScheme()
Initializes the default random style color scheme for the user.
QStringList childKeys() const
Returns a list of all top-level keys that can be read using the QSettings object. ...
static void restoreGdalDriver(const QString &driver)
Sets the GDAL_SKIP environment variable to exclude the specified driver and then calls GDALDriverMana...
static QString iconPath(const QString &iconFile)
Returns path to the desired icon file.
A cache for images / pictures derived from svg files.
Definition: qgssvgcache.h:100
static void invalidateCache(bool disableCache=false)
Clears the internal cache used to initialize QgsCoordinateTransform objects.
void remove(const QString &key, QgsSettings::Section section=QgsSettings::NoSection)
Removes the setting key and any sub-settings of key in a section.
Registry of renderers.
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 resolvePkgPath()
Calculate the application pkg path.
Registry for raster renderers.
static void registerOgrDrivers()
Register OGR drivers ensuring this only happens once.
static QIcon getThemeIcon(const QString &name)
Helper to get a theme icon.
User profile contains information about the user profile folders on the machine.
Precisely identify a point on the canvas.
static QgsPluginLayerRegistry * pluginLayerRegistry()
Returns the application&#39;s plugin layer registry, used for managing plugin layer types.
static QgsNumericFormatRegistry * numericFormatRegistry()
Gets the registry of available numeric formats.
static QVariantMap customVariables()
Custom expression variables for this application.
Manages storage of a set of bookmarks.
The QgsFieldFormatterRegistry manages registered classes of QgsFieldFormatter.
This class keeps a list of QgsAbstractValidityCheck checks which can be used when performing validity...
Color/Value picker.
static void setFileOpenEventReceiver(QObject *receiver)
Sets the FileOpen event receiver.
static endian_t endian()
Returns whether this machine uses big or little endian.
QMap< QString, QString > QgsStringMap
Definition: qgis.h:694
static QStringList deferredSkippedGdalDrivers()
Returns the list of gdal drivers that have been disabled in the current session, and thus...
static QPixmap getThemePixmap(const QString &name)
Helper to get a theme icon as a pixmap.
static QString userFullName()
Returns the user&#39;s operating system login account full display name.
static QgsPaintEffectRegistry * paintEffectRegistry()
Returns the application&#39;s paint effect registry, used for managing paint effects. ...
static QgsStyle * defaultStyle()
Returns default application-wide style.
Definition: qgsstyle.cpp:74
static QString developersMapFilePath()
Returns the path to the developers map file.
static QString absolutePathToRelativePath(const QString &apath, const QString &targetPath)
Converts absolute path to path relative to target.
QString what() const
Definition: qgsexception.h:48
static QString defaultStylePath()
Returns the path to default style (works as a starting point).
static QgsTaskManager * taskManager()
Returns the application&#39;s task manager, used for managing application wide background task handling...
static QgsMessageLog * messageLog()
Returns the application&#39;s message log.
static void applyGdalSkippedDrivers()
Apply the skipped drivers list to gdal.
#define CONN_POOL_MAX_CONCURRENT_CONNS
endian_t
Constants for endian-ness.
static QgsProviderRegistry * instance(const QString &pluginPath=QString())
Means of accessing canonical single instance.
static QgsLayoutItemRegistry * layoutItemRegistry()
Returns the application&#39;s layout item registry, used for layout item types.
static void setNullRepresentation(const QString &nullRepresentation)
This string is used to represent the value NULL throughout QGIS.
static QString pluginPath()
Returns the path to the application plugin directory.
Q_GLOBAL_STATIC(QReadWriteLock, sDefinitionCacheLock)
Keeps track of available 3D renderers.
#define QgsDebugMsgLevel(str, level)
Definition: qgslogger.h:39
Registry of available symbol layer classes.
Registry for temporary fetched files.
static bool createThemeFolder()
Create the users theme folder.
static bool createDatabase(QString *errorMessage=nullptr)
initialize qgis.db
static void setTranslation(const QString &translation)
Set translation.
static void cleanRegisteredFunctions()
Deletes all registered functions whose ownership have been transferred to the expression engine...
static QString i18nPath()
Returns the path to the translation directory.
static void cleanDefaultStyle()
Deletes the default style. Only to be used by QgsApplication::exitQgis()
Definition: qgsstyle.cpp:99
static QString nullRepresentation()
This string is used to represent the value NULL throughout QGIS.
static QString splashPath()
Returns the path to the splash screen image directory.
static void setCustomVariable(const QString &name, const QVariant &value)
Set a single custom expression variable.
static int maxThreads()
Gets maximum concurrent thread count.
static QgsGpsConnectionRegistry * gpsConnectionRegistry()
Returns the application&#39;s GPS connection registry, used for managing GPS connections.
A registry for known page sizes.
static const char * QGIS_ORGANIZATION_NAME
This class manages all known classification methods.
int open(const QString &path)
Opens the database at the specified file path.
static QgsProjectStorageRegistry * projectStorageRegistry()
Returns registry of available project storage implementations.
Task manager for managing a set of long-running QgsTask tasks.
Used for the collecting of strings from projects for translation and creation of ts files...
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 QString userLoginName()
Returns the user&#39;s operating system login account name.
static QString pkgDataPath()
Returns the common root path of all application data directories.
static QString osName()
Returns a string name of the operating system QGIS is running on.
static void initQgis()
loads providers
Select a rectangle.
static void setDefaultSvgPaths(const QStringList &pathList)
Alters default svg paths - used by 3rd party apps.
StyleSheetType
The StyleSheetType enum represents the stylesheet type that a widget supports.
static QStringList searchPaths()
Returns the current list of Proj file search paths.
Unique pointer for sqlite3 databases, which automatically closes the database when the pointer goes o...
static void skipGdalDriver(const QString &driver)
Sets the GDAL_SKIP environment variable to include the specified driver and then calls GDALDriverMana...
static QgsStyleModel * defaultStyleModel()
Returns a shared QgsStyleModel containing the default style library (see QgsStyle::defaultStyle()).
void beginGroup(const QString &prefix, QgsSettings::Section section=QgsSettings::NoSection)
Appends prefix to the current group.
Definition: qgssettings.cpp:87
static QgsAuthManager * authManager()
Returns the application&#39;s authentication manager instance.
static QRegExp shortNameRegExp()
Returns the short name regular expression for line edit validator.
static QgsNetworkAccessManager * instance(Qt::ConnectionType connectionType=Qt::BlockingQueuedConnection)
Returns a pointer to the active QgsNetworkAccessManager for the current thread.
Identify: obtain information about the object.
Registry for various processing components, including providers, algorithms and various parameters an...
static QString showSettings()
Convenience function to get a summary of the paths used in this application instance useful for debug...
static QString appIconPath()
Gets application icon.
static QgsColorSchemeRegistry * colorSchemeRegistry()
Returns the application&#39;s color scheme registry, used for managing color schemes. ...
static const char * QGIS_ORGANIZATION_DOMAIN
bool notify(QObject *receiver, QEvent *event) override
Catch exceptions when sending event to receiver.
Registry of available layout item types.
static void setPkgDataPath(const QString &pkgDataPath)
Alters pkg data path - used by 3rd party apps.
static QgsPageSizeRegistry * pageSizeRegistry()
Returns the application&#39;s page size registry, used for managing layout page sizes.
static QStringList skippedGdalDrivers()
Returns the list of gdal drivers that should be skipped (based on GDAL_SKIP environment variable) ...
static QString contributorsFilePath()
Returns the path to the contributors file.
static QString activeThemePath()
Returns the path to the currently active theme directory.
static QString buildOutputPath()
Returns path to the build output directory. Valid only when running from build directory.
void setValue(const QString &key, const QVariant &value, QgsSettings::Section section=QgsSettings::NoSection)
Sets the value of setting key to value.
static void init(QString profileFolder=QString())
This method initializes paths etc for QGIS.
The QgsNumericFormatRegistry manages registered classes of QgsNumericFormat.
static void setPluginPath(const QString &pluginPath)
Alters plugin path - used by 3rd party apps.
QgsUserProfile * getProfile(const QString &defaultProfile="default", bool createNew=true, bool initSettings=true)
Returns the profile from the given root profile location.
static QgsClassificationMethodRegistry * classificationMethodRegistry()
Returns the application&#39;s classification methods registry, used in graduated renderer.
static QgsProject * instance()
Returns the QgsProject singleton instance.
Definition: qgsproject.cpp:450
A class to register / unregister existing GPS connections such that the information is available to a...
static QgsNetworkContentFetcherRegistry * networkContentFetcherRegistry()
Returns the application&#39;s network content registry used for fetching temporary files during QGIS sess...
Registry of available callout classes.
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 QString platform()
Returns the QGIS platform name, e.g., "desktop" or "server".
static QString srsDatabaseFilePath()
Returns the path to the srs.db file.
QObject * ABISYM(QgsApplication::mFileOpenEventReceiver)
static QgsBookmarkManager * bookmarkManager()
Returns the application&#39;s bookmark manager, used for storing installation-wide bookmarks.
static void exitQgis()
deletes provider registry and map layer registry
Temporarily blocks the application QgsMessageLog (see QgsApplication::messageLog()) from emitting the...
A cache for images derived from raster files.
Definition: qgsimagecache.h:89
static QStringList svgPaths()
Returns the paths to svg directories.
static QString sponsorsFilePath()
Returns the path to the sponsors file.
Registry of storage backends that QgsProject may use.
static QCursor getThemeCursor(Cursor cursor)
Helper to get a theme cursor.
static QString qgisAuthDatabaseFilePath()
Returns the path to the user authentication database file: qgis-auth.db.
const QString folder() const
The base folder for the user profile.
The action scope registry is an application wide registry that contains a list of available action sc...
static QHash< QString, QString > uiThemes()
All themes found in ~/.qgis3/themes folder.
static QString libexecPath()
Returns the path with utility executables (help viewer, crssync, ...)
static QString prefixPath()
Returns the path to the application prefix directory.
static QString iconsPath()
Returns the path to the icons image directory.
static QString translatorsFilePath()
Returns the path to the sponsors file.
static const char * QGIS_APPLICATION_NAME
void collectTranslatableObjects(QgsTranslationContext *translationContext)
Emits the signal to collect all the strings of .qgs to be included in ts file.
~QgsApplication() override
static QString serverResourcesPath()
Returns the path to the server resources directory.
static QgsActionScopeRegistry * actionScopeRegistry()
Returns the action scope registry.
User profile manager is used to manager list, and manage user profiles on the users machine...
static QString metadataPath()
Returns the path to the metadata directory.
Defines a QGIS exception class.
Definition: qgsexception.h:34
static QgsRasterRendererRegistry * rasterRendererRegistry()
Returns the application&#39;s raster renderer registry, used for managing raster layer renderers...
static QgsDataItemProviderRegistry * dataItemProviderRegistry()
Returns the application&#39;s data item provider registry, which keeps a list of data item providers that...
static void registerGdalDriversFromSettings()
Register gdal drivers, excluding the ones mentioned in "gdal/skipList" setting.
static QgsRendererRegistry * rendererRegistry()
Returns the application&#39;s renderer registry, used for managing vector layer renderers.
Interface for logging messages from QGIS in GUI independent way.
Definition: qgsmessagelog.h:38
static QString qmlImportPath()
Returns the path where QML components are installed for QGIS Quick library.
void initialize(const QString &filePath)
initialize
static void setMaxThreads(int maxThreads)
Set maximum concurrent thread count.
Select and capture a point or a feature.
static void setUITheme(const QString &themeName)
Set the current UI theme used to style the interface.
static QColor decodeColor(const QString &str)
static QString licenceFilePath()
Returns the path to the licence file.
static QMap< QString, QString > systemEnvVars()
Returns the system environment variables passed to application.
Registry of available paint effects.
static QgsProcessingRegistry * processingRegistry()
Returns the application&#39;s processing registry, used for managing processing providers, algorithms, and various parameters and outputs.
static QString userThemesFolder()
Returns the path to user&#39;s themes folder.
void preNotify(QObject *receiver, QEvent *event, bool *done)
static void setAuthDatabaseDirPath(const QString &authDbDirPath)
Alters authentication data base directory path - used by 3rd party apps.