QGIS API Documentation  2.99.0-Master (19b062c)
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"
25 #include "qgsproviderregistry.h"
26 #include "qgsexpression.h"
27 #include "qgsactionscoperegistry.h"
28 #include "qgsruntimeprofiler.h"
29 #include "qgstaskmanager.h"
31 #include "qgssvgcache.h"
32 #include "qgscolorschemeregistry.h"
33 #include "qgspainteffectregistry.h"
35 #include "qgsrendererregistry.h"
36 #include "qgssymbollayerregistry.h"
37 #include "qgspluginlayerregistry.h"
38 #include "qgsmessagelog.h"
39 #include "qgsannotationregistry.h"
40 #include "qgssettings.h"
41 #include "qgsunittypes.h"
42 #include "qgsuserprofile.h"
43 #include "qgsuserprofilemanager.h"
44 #include "qgsreferencedgeometry.h"
45 #include "qgs3drendererregistry.h"
46 #include "qgslayoutcontext.h"
47 #include "qgssqliteutils.h"
48 
51 
53 
54 #include <QDir>
55 #include <QFile>
56 #include <QFileInfo>
57 #include <QFileOpenEvent>
58 #include <QMessageBox>
59 #include <QPalette>
60 #include <QProcess>
61 #include <QIcon>
62 #include <QPixmap>
63 #include <QThreadPool>
64 #include <QLocale>
65 
66 #ifndef Q_OS_WIN
67 #include <netinet/in.h>
68 #include <pwd.h>
69 #else
70 #include <winsock.h>
71 #include <windows.h>
72 #include <Lmcons.h>
73 #define SECURITY_WIN32
74 #include <Security.h>
75 #pragma comment( lib, "Secur32.lib" )
76 #endif
77 
78 #include "qgsconfig.h"
79 
80 #include <gdal.h>
81 #include <ogr_api.h>
82 #include <cpl_conv.h> // for setting gdal options
83 #include <sqlite3.h>
84 
85 QObject *ABISYM( QgsApplication::mFileOpenEventReceiver );
86 QStringList ABISYM( QgsApplication::mFileOpenEventList );
87 QString ABISYM( QgsApplication::mPrefixPath );
88 QString ABISYM( QgsApplication::mPluginPath );
89 QString ABISYM( QgsApplication::mPkgDataPath );
90 QString ABISYM( QgsApplication::mLibraryPath );
91 QString ABISYM( QgsApplication::mLibexecPath );
92 QString ABISYM( QgsApplication::mThemeName );
93 QString ABISYM( QgsApplication::mUIThemeName );
94 QStringList ABISYM( QgsApplication::mDefaultSvgPaths );
95 QMap<QString, QString> ABISYM( QgsApplication::mSystemEnvVars );
96 QString ABISYM( QgsApplication::mConfigPath );
97 bool ABISYM( QgsApplication::mRunningFromBuildDir ) = false;
98 QString ABISYM( QgsApplication::mBuildSourcePath );
99 #ifdef _MSC_VER
100 QString ABISYM( QgsApplication::mCfgIntDir );
101 #endif
102 QString ABISYM( QgsApplication::mBuildOutputPath );
103 QStringList ABISYM( QgsApplication::mGdalSkipList );
104 int ABISYM( QgsApplication::mMaxThreads );
105 QString ABISYM( QgsApplication::mAuthDbDirPath );
106 
107 QString QgsApplication::sUserName;
108 QString QgsApplication::sUserFullName;
109 QString QgsApplication::sPlatformName = QStringLiteral( "desktop" );
110 
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 
115 QgsApplication::ApplicationMembers *QgsApplication::sApplicationMembers = nullptr;
116 
117 QgsApplication::QgsApplication( int &argc, char **argv, bool GUIenabled, const QString &profileFolder, const QString &platformName )
118  : QApplication( argc, argv, GUIenabled )
119 {
120  sPlatformName = platformName;
121 
122  mApplicationMembers = new ApplicationMembers();
123 
124  init( profileFolder ); // init can also be called directly by e.g. unit tests that don't inherit QApplication.
125 }
126 
127 void QgsApplication::init( QString profileFolder )
128 {
129  if ( profileFolder.isEmpty() )
130  {
131  if ( getenv( "QGIS_CUSTOM_CONFIG_PATH" ) )
132  {
133  QString envProfileFolder = getenv( "QGIS_CUSTOM_CONFIG_PATH" );
134  profileFolder = envProfileFolder + QDir::separator() + "profiles";
135  }
136  else
137  {
138  profileFolder = QStandardPaths::standardLocations( QStandardPaths::AppDataLocation ).value( 0 );
139  }
140  // This will normally get here for custom scripts that use QgsApplication.
141  // This doesn't get this hit for QGIS Desktop because we setup the profile via main
142  QString rootProfileFolder = QgsUserProfileManager::resolveProfilesFolder( profileFolder );
143  QgsUserProfileManager manager( rootProfileFolder );
144  QgsUserProfile *profile = manager.getProfile();
145  profileFolder = profile->folder();
146  delete profile;
147  }
148 
149  qRegisterMetaType<QgsGeometry::Error>( "QgsGeometry::Error" );
150  qRegisterMetaType<QgsProcessingFeatureSourceDefinition>( "QgsProcessingFeatureSourceDefinition" );
151  qRegisterMetaType<QgsProcessingOutputLayerDefinition>( "QgsProcessingOutputLayerDefinition" );
152  qRegisterMetaType<QgsUnitTypes::LayoutUnit>( "QgsUnitTypes::LayoutUnit" );
153  qRegisterMetaType<QgsFeatureIds>( "QgsFeatureIds" );
154  qRegisterMetaType<QgsMessageLog::MessageLevel>( "QgsMessageLog::MessageLevel" );
155  qRegisterMetaType<QgsReferencedRectangle>( "QgsReferencedRectangle" );
156  qRegisterMetaType<QgsReferencedPointXY>( "QgsReferencedPointXY" );
157  qRegisterMetaType<QgsLayoutContext::Flags>( "QgsLayoutContext::Flags" );
158 
159  QString prefixPath( getenv( "QGIS_PREFIX_PATH" ) ? getenv( "QGIS_PREFIX_PATH" ) : applicationDirPath() );
160  // QgsDebugMsg( QString( "prefixPath(): %1" ).arg( prefixPath ) );
161 
162  // check if QGIS is run from build directory (not the install directory)
163  QFile f;
164  // "/../../.." is for Mac bundled app in build directory
165  Q_FOREACH ( const QString &path, QStringList() << "" << "/.." << "/bin" << "/../../.." )
166  {
167  f.setFileName( prefixPath + path + "/qgisbuildpath.txt" );
168  if ( f.exists() )
169  break;
170  }
171  if ( f.exists() && f.open( QIODevice::ReadOnly ) )
172  {
173  ABISYM( mRunningFromBuildDir ) = true;
174  ABISYM( mBuildSourcePath ) = f.readLine().trimmed();
175  ABISYM( mBuildOutputPath ) = f.readLine().trimmed();
176  QgsDebugMsgLevel( QStringLiteral( "Running from build directory!" ), 4 );
177  QgsDebugMsgLevel( QStringLiteral( "- source directory: %1" ).arg( ABISYM( mBuildSourcePath ).toUtf8().data() ), 4 );
178  QgsDebugMsgLevel( QStringLiteral( "- output directory of the build: %1" ).arg( ABISYM( mBuildOutputPath ).toUtf8().data() ), 4 );
179 #ifdef _MSC_VER
180  ABISYM( mCfgIntDir ) = prefixPath.split( '/', QString::SkipEmptyParts ).last();
181  qDebug( "- cfg: %s", ABISYM( mCfgIntDir ).toUtf8().data() );
182 #endif
183  }
184 
185  if ( ABISYM( mRunningFromBuildDir ) )
186  {
187  // we run from source directory - not installed to destination (specified prefix)
188  ABISYM( mPrefixPath ) = QString(); // set invalid path
189 #if defined(_MSC_VER) && !defined(USING_NMAKE) && !defined(USING_NINJA)
190  setPluginPath( ABISYM( mBuildOutputPath ) + '/' + QString( QGIS_PLUGIN_SUBDIR ) + '/' + ABISYM( mCfgIntDir ) );
191 #else
192  setPluginPath( ABISYM( mBuildOutputPath ) + '/' + QStringLiteral( QGIS_PLUGIN_SUBDIR ) );
193 #endif
194  setPkgDataPath( ABISYM( mBuildSourcePath ) ); // directly source path - used for: doc, resources, svg
195  ABISYM( mLibraryPath ) = ABISYM( mBuildOutputPath ) + '/' + QGIS_LIB_SUBDIR + '/';
196 #if defined(_MSC_VER) && !defined(USING_NMAKE) && !defined(USING_NINJA)
197  ABISYM( mLibexecPath ) = ABISYM( mBuildOutputPath ) + '/' + QGIS_LIBEXEC_SUBDIR + '/' + ABISYM( mCfgIntDir ) + '/';
198 #else
199  ABISYM( mLibexecPath ) = ABISYM( mBuildOutputPath ) + '/' + QGIS_LIBEXEC_SUBDIR + '/';
200 #endif
201  }
202  else
203  {
204  char *prefixPath = getenv( "QGIS_PREFIX_PATH" );
205  if ( !prefixPath )
206  {
207 #if defined(Q_OS_MACX) || defined(Q_OS_WIN)
208  setPrefixPath( applicationDirPath(), true );
209 #elif defined(ANDROID)
210  // this is "/data/data/org.qgis.qgis" in android
211  QDir myDir( QDir::homePath() );
212  myDir.cdUp();
213  QString myPrefix = myDir.absolutePath();
214  setPrefixPath( myPrefix, true );
215 #else
216  QDir myDir( applicationDirPath() );
217  myDir.cdUp();
218  QString myPrefix = myDir.absolutePath();
219  setPrefixPath( myPrefix, true );
220 #endif
221  }
222  else
223  {
224  setPrefixPath( prefixPath, true );
225  }
226  }
227 
228  ABISYM( mConfigPath ) = profileFolder + '/'; // make sure trailing slash is included
229  ABISYM( mDefaultSvgPaths ) << qgisSettingsDirPath() + QStringLiteral( "svg/" );
230 
231  ABISYM( mAuthDbDirPath ) = qgisSettingsDirPath();
232  if ( getenv( "QGIS_AUTH_DB_DIR_PATH" ) )
233  {
234  setAuthDatabaseDirPath( getenv( "QGIS_AUTH_DB_DIR_PATH" ) );
235  }
236 
237 
238  // store system environment variables passed to application, before they are adjusted
239  QMap<QString, QString> systemEnvVarMap;
240  QString passfile( QStringLiteral( "QGIS_AUTH_PASSWORD_FILE" ) ); // QString, for comparison
241  Q_FOREACH ( const QString &varStr, QProcess::systemEnvironment() )
242  {
243  int pos = varStr.indexOf( QLatin1Char( '=' ) );
244  if ( pos == -1 )
245  continue;
246  QString varStrName = varStr.left( pos );
247  QString varStrValue = varStr.mid( pos + 1 );
248  if ( varStrName != passfile )
249  {
250  systemEnvVarMap.insert( varStrName, varStrValue );
251  }
252  }
253  ABISYM( mSystemEnvVars ) = systemEnvVarMap;
254 
255  // allow Qt to search for Qt plugins (e.g. sqldrivers) in our plugin directory
256  QCoreApplication::addLibraryPath( pluginPath() );
257 
258  // set max. thread count to -1
259  // this should be read from QgsSettings but we don't know where they are at this point
260  // so we read actual value in main.cpp
261  ABISYM( mMaxThreads ) = -1;
262 }
263 
265 {
266  delete mDataItemProviderRegistry;
267  delete mApplicationMembers;
268 }
269 
271 {
272  return qobject_cast<QgsApplication *>( QCoreApplication::instance() );
273 }
274 
276 {
277  bool done = false;
278  if ( event->type() == QEvent::FileOpen )
279  {
280  // handle FileOpen event (double clicking a file icon in Mac OS X Finder)
281  if ( ABISYM( mFileOpenEventReceiver ) )
282  {
283  // Forward event to main window.
284  done = notify( ABISYM( mFileOpenEventReceiver ), event );
285  }
286  else
287  {
288  // Store filename because receiver has not registered yet.
289  // If QGIS has been launched by double clicking a file icon, FileOpen will be
290  // the first event; the main window is not yet ready to handle the event.
291  ABISYM( mFileOpenEventList ).append( static_cast<QFileOpenEvent *>( event )->file() );
292  done = true;
293  }
294  }
295  else
296  {
297  // pass other events to base class
298  done = QApplication::event( event );
299  }
300  return done;
301 }
302 
303 bool QgsApplication::notify( QObject *receiver, QEvent *event )
304 {
305  bool done = false;
306  // Crashes in customization (especially on Mac), if we're not in the main/UI thread, see #5597
307  if ( thread() == receiver->thread() )
308  emit preNotify( receiver, event, &done );
309 
310  if ( done )
311  return true;
312 
313  // Send event to receiver and catch unhandled exceptions
314  done = true;
315  try
316  {
317  done = QApplication::notify( receiver, event );
318  }
319  catch ( QgsException &e )
320  {
321  QgsDebugMsg( "Caught unhandled QgsException: " + e.what() );
322  if ( qApp->thread() == QThread::currentThread() )
323  QMessageBox::critical( activeWindow(), tr( "Exception" ), e.what() );
324  }
325  catch ( std::exception &e )
326  {
327  QgsDebugMsg( "Caught unhandled std::exception: " + QString::fromLatin1( e.what() ) );
328  if ( qApp->thread() == QThread::currentThread() )
329  QMessageBox::critical( activeWindow(), tr( "Exception" ), e.what() );
330  }
331  catch ( ... )
332  {
333  QgsDebugMsg( "Caught unhandled unknown exception" );
334  if ( qApp->thread() == QThread::currentThread() )
335  QMessageBox::critical( activeWindow(), tr( "Exception" ), tr( "unknown exception" ) );
336  }
337 
338  return done;
339 }
340 
342 {
343  return members()->mProfiler;
344 }
345 
347 {
348  // Set receiver for FileOpen events
349  ABISYM( mFileOpenEventReceiver ) = receiver;
350  // Propagate any events collected before the receiver has registered.
351  if ( ABISYM( mFileOpenEventList ).count() > 0 )
352  {
353  QStringListIterator i( ABISYM( mFileOpenEventList ) );
354  while ( i.hasNext() )
355  {
356  QFileOpenEvent foe( i.next() );
357  QgsApplication::sendEvent( ABISYM( mFileOpenEventReceiver ), &foe );
358  }
359  ABISYM( mFileOpenEventList ).clear();
360  }
361 }
362 
363 void QgsApplication::setPrefixPath( const QString &prefixPath, bool useDefaultPaths )
364 {
365  ABISYM( mPrefixPath ) = prefixPath;
366 #if defined(_MSC_VER)
367  if ( ABISYM( mPrefixPath ).endsWith( "/bin" ) )
368  {
369  ABISYM( mPrefixPath ).chop( 4 );
370  }
371 #endif
372  if ( useDefaultPaths && !ABISYM( mRunningFromBuildDir ) )
373  {
374  setPluginPath( ABISYM( mPrefixPath ) + '/' + QStringLiteral( QGIS_PLUGIN_SUBDIR ) );
375  setPkgDataPath( ABISYM( mPrefixPath ) + '/' + QStringLiteral( QGIS_DATA_SUBDIR ) );
376  }
377  ABISYM( mLibraryPath ) = ABISYM( mPrefixPath ) + '/' + QGIS_LIB_SUBDIR + '/';
378  ABISYM( mLibexecPath ) = ABISYM( mPrefixPath ) + '/' + QGIS_LIBEXEC_SUBDIR + '/';
379 }
380 
382 {
383  ABISYM( mPluginPath ) = pluginPath;
384 }
385 
387 {
388  ABISYM( mPkgDataPath ) = pkgDataPath;
389  QString mySvgPath = pkgDataPath + ( ABISYM( mRunningFromBuildDir ) ? "/images/svg/" : "/svg/" );
390  // avoid duplicate entries
391  if ( !ABISYM( mDefaultSvgPaths ).contains( mySvgPath ) )
392  ABISYM( mDefaultSvgPaths ) << mySvgPath;
393 }
394 
395 void QgsApplication::setDefaultSvgPaths( const QStringList &pathList )
396 {
397  ABISYM( mDefaultSvgPaths ) = pathList;
398 }
399 
400 void QgsApplication::setAuthDatabaseDirPath( const QString &authDbDirPath )
401 {
402  QFileInfo fi( authDbDirPath );
403  if ( fi.exists() && fi.isDir() && fi.isWritable() )
404  {
405  ABISYM( mAuthDbDirPath ) = fi.canonicalFilePath() + QDir::separator();
406  }
407 }
408 
410 {
411  if ( ABISYM( mRunningFromBuildDir ) )
412  {
413  static bool sOnce = true;
414  if ( sOnce )
415  qWarning( "!!! prefix path was requested, but it is not valid - we do not run from installed path !!!" );
416  sOnce = false;
417  }
418 
419  return ABISYM( mPrefixPath );
420 }
422 {
423  return ABISYM( mPluginPath );
424 }
426 {
427  return ABISYM( mPkgDataPath );
428 }
430 {
431  return QStringLiteral( ":/images/themes/default/" );
432 }
434 {
435  return userThemesFolder() + QDir::separator() + themeName() + QDir::separator() + "icons/";
436 }
437 
439 {
440  return iconsPath() + QStringLiteral( "qgis-icon-60x60.png" );
441 }
442 
443 QString QgsApplication::iconPath( const QString &iconFile )
444 {
445  // try active theme
446  QString path = activeThemePath();
447  if ( QFile::exists( path + iconFile ) )
448  return path + iconFile;
449 
450  // use default theme
451  return defaultThemePath() + iconFile;
452 }
453 
454 QIcon QgsApplication::getThemeIcon( const QString &name )
455 {
456  QgsApplication *app = instance();
457  if ( app && app->mIconCache.contains( name ) )
458  return app->mIconCache.value( name );
459 
460  QIcon icon;
461 
462  QString myPreferredPath = activeThemePath() + QDir::separator() + name;
463  QString myDefaultPath = defaultThemePath() + QDir::separator() + name;
464  if ( QFile::exists( myPreferredPath ) )
465  {
466  icon = QIcon( myPreferredPath );
467  }
468  else if ( QFile::exists( myDefaultPath ) )
469  {
470  //could still return an empty icon if it
471  //doesn't exist in the default theme either!
472  icon = QIcon( myDefaultPath );
473  }
474  else
475  {
476  icon = QIcon();
477  }
478 
479  if ( app )
480  app->mIconCache.insert( name, icon );
481  return icon;
482 }
483 
484 QCursor QgsApplication::getThemeCursor( const Cursor &cursor )
485 {
486  QgsApplication *app = instance();
487  if ( app && app->mCursorCache.contains( cursor ) )
488  return app->mCursorCache.value( cursor );
489 
490  // All calculations are done on 32x32 icons
491  // Defaults to center, individual cursors may override
492  int activeX = 16;
493  int activeY = 16;
494 
495  QString name;
496  switch ( cursor )
497  {
498  case ZoomIn:
499  name = QStringLiteral( "mZoomIn.svg" );
500  activeX = 13;
501  activeY = 13;
502  break;
503  case ZoomOut:
504  name = QStringLiteral( "mZoomOut.svg" );
505  activeX = 13;
506  activeY = 13;
507  break;
508  case Identify:
509  activeX = 3;
510  activeY = 6;
511  name = QStringLiteral( "mIdentify.svg" );
512  break;
513  case CrossHair:
514  name = QStringLiteral( "mCrossHair.svg" );
515  break;
516  case CapturePoint:
517  name = QStringLiteral( "mCapturePoint.svg" );
518  break;
519  case Select:
520  name = QStringLiteral( "mSelect.svg" );
521  activeX = 6;
522  activeY = 6;
523  break;
524  case Sampler:
525  activeX = 5;
526  activeY = 5;
527  name = QStringLiteral( "mSampler.svg" );
528  break;
529  // No default
530  }
531  // It should never get here!
532  Q_ASSERT( ! name.isEmpty( ) );
533 
534  QIcon icon = getThemeIcon( QStringLiteral( "cursors" ) + QDir::separator() + name );
535  QCursor _cursor;
536  // Check if an icon exists for this cursor (the O.S. default cursor will be used if it does not)
537  if ( ! icon.isNull( ) )
538  {
539  // Apply scaling
540  float scale( ( float ) app->fontMetrics().height() / 32 * 1.5 ) ; // Make them bigger to match 24x24
541  _cursor = QCursor( icon.pixmap( std::ceil( scale * 32 ), std::ceil( scale * 32 ) ), std::ceil( scale * activeX ), std::ceil( scale * activeY ) );
542  }
543  if ( app )
544  app->mCursorCache.insert( cursor, _cursor );
545  return _cursor;
546 }
547 
548 // TODO: add some caching mechanism ?
549 QPixmap QgsApplication::getThemePixmap( const QString &name )
550 {
551  QString myPreferredPath = activeThemePath() + QDir::separator() + name;
552  QString myDefaultPath = defaultThemePath() + QDir::separator() + name;
553  if ( QFile::exists( myPreferredPath ) )
554  {
555  return QPixmap( myPreferredPath );
556  }
557  else
558  {
559  //could still return an empty icon if it
560  //doesn't exist in the default theme either!
561  return QPixmap( myDefaultPath );
562  }
563 }
564 
566 {
567  ABISYM( mThemeName ) = themeName;
568 }
569 
571 {
572  return ABISYM( mThemeName );
573 }
574 
575 void QgsApplication::setUITheme( const QString &themeName )
576 {
577  // Loop all style sheets, find matching name, load it.
578  QHash<QString, QString> themes = QgsApplication::uiThemes();
579  if ( themeName == QStringLiteral( "default" ) || !themes.contains( themeName ) )
580  {
581  setThemeName( QStringLiteral( "default" ) );
582  qApp->setStyleSheet( QString() );
583  return;
584  }
585 
586  QString path = themes.value( themeName );
587  QString stylesheetname = path + "/style.qss";
588  QString autostylesheet = stylesheetname + ".auto";
589 
590  QFile file( stylesheetname );
591  QFile variablesfile( path + "/variables.qss" );
592  QFile fileout( autostylesheet );
593 
594  QFileInfo variableInfo( variablesfile );
595 
596  if ( variableInfo.exists() && variablesfile.open( QIODevice::ReadOnly ) )
597  {
598  if ( !file.open( QIODevice::ReadOnly ) || !fileout.open( QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate ) )
599  {
600  return;
601  }
602 
603  QString styledata = file.readAll();
604  QTextStream in( &variablesfile );
605  while ( !in.atEnd() )
606  {
607  QString line = in.readLine();
608  // This is is a variable
609  if ( line.startsWith( '@' ) )
610  {
611  int index = line.indexOf( ':' );
612  QString name = line.mid( 0, index );
613  QString value = line.mid( index + 1, line.length() );
614  styledata.replace( name, value );
615  }
616  }
617  variablesfile.close();
618  QTextStream out( &fileout );
619  out << styledata;
620  fileout.close();
621  file.close();
622  stylesheetname = autostylesheet;
623  }
624 
625  QString styleSheet = QStringLiteral( "file:///" );
626  styleSheet.append( stylesheetname );
627  qApp->setStyleSheet( styleSheet );
628  setThemeName( themeName );
629 }
630 
631 QHash<QString, QString> QgsApplication::uiThemes()
632 {
633  QStringList paths = QStringList() << userThemesFolder();
634  QHash<QString, QString> mapping;
635  mapping.insert( QStringLiteral( "default" ), QLatin1String( "" ) );
636  Q_FOREACH ( const QString &path, paths )
637  {
638  QDir folder( path );
639  QFileInfoList styleFiles = folder.entryInfoList( QDir::Dirs | QDir::NoDotAndDotDot );
640  Q_FOREACH ( const QFileInfo &info, styleFiles )
641  {
642  QFileInfo styleFile( info.absoluteFilePath() + "/style.qss" );
643  if ( !styleFile.exists() )
644  continue;
645 
646  QString name = info.baseName();
647  QString path = info.absoluteFilePath();
648  mapping.insert( name, path );
649  }
650  }
651  return mapping;
652 }
653 
655 {
656  return ABISYM( mPkgDataPath ) + QStringLiteral( "/doc/AUTHORS" );
657 }
658 
660 {
661  return ABISYM( mPkgDataPath ) + QStringLiteral( "/doc/CONTRIBUTORS" );
662 }
664 {
665  return ABISYM( mPkgDataPath ) + QStringLiteral( "/doc/developersmap.html" );
666 }
667 
669 {
670  return ABISYM( mPkgDataPath ) + QStringLiteral( "/doc/SPONSORS" );
671 }
672 
674 {
675  return ABISYM( mPkgDataPath ) + QStringLiteral( "/doc/DONORS" );
676 }
677 
679 {
680  return ABISYM( mPkgDataPath ) + QStringLiteral( "/doc/TRANSLATORS" );
681 }
682 
684 {
685  return ABISYM( mPkgDataPath ) + QStringLiteral( "/doc/LICENSE" );
686 }
687 
689 {
690  if ( ABISYM( mRunningFromBuildDir ) )
691  return ABISYM( mBuildOutputPath ) + QStringLiteral( "/i18n" );
692  else
693  return ABISYM( mPkgDataPath ) + QStringLiteral( "/i18n/" );
694 }
695 
697 {
698  return ABISYM( mPkgDataPath ) + QStringLiteral( "/resources/metadata-ISO/" );
699 }
700 
702 {
703  return ABISYM( mPkgDataPath ) + QStringLiteral( "/resources/qgis.db" );
704 }
705 
707 {
708  return ABISYM( mConfigPath );
709 }
710 
712 {
713  return qgisSettingsDirPath() + QStringLiteral( "qgis.db" );
714 }
715 
717 {
718  return ABISYM( mAuthDbDirPath ) + QStringLiteral( "qgis-auth.db" );
719 }
720 
722 {
723  return QStringLiteral( ":/images/splash/" );
724 }
725 
727 {
728  return ABISYM( mPkgDataPath ) + QStringLiteral( "/images/icons/" );
729 }
730 
732 {
733  if ( ABISYM( mRunningFromBuildDir ) )
734  {
735  QString tempCopy = QDir::tempPath() + "/srs.db";
736 
737  if ( !QFile( tempCopy ).exists() )
738  {
739  QFile f( ABISYM( mPkgDataPath ) + "/resources/srs.db" );
740  if ( !f.copy( tempCopy ) )
741  {
742  qFatal( "Could not create temporary copy" );
743  }
744  }
745 
746  return tempCopy;
747  }
748  else
749  {
750  return ABISYM( mPkgDataPath ) + QStringLiteral( "/resources/srs.db" );
751  }
752 }
753 
755 {
756  //local directories to search when looking for an SVG with a given basename
757  //defined by user in options dialog
758  QgsSettings settings;
759  QStringList pathList = settings.value( QStringLiteral( "svg/searchPathsForSVG" ) ).toStringList();
760 
761  // maintain user set order while stripping duplicates
762  QStringList paths;
763  Q_FOREACH ( const QString &path, pathList )
764  {
765  if ( !paths.contains( path ) )
766  paths.append( path );
767  }
768  Q_FOREACH ( const QString &path, ABISYM( mDefaultSvgPaths ) )
769  {
770  if ( !paths.contains( path ) )
771  paths.append( path );
772  }
773 
774  return paths;
775 }
776 
778 {
779  //local directories to search when looking for an SVG with a given basename
780  //defined by user in options dialog
781  QgsSettings settings;
782  QStringList pathList = settings.value( QStringLiteral( "composer/searchPathsForTemplates" ) ).toStringList();
783 
784  return pathList;
785 }
786 
788 {
789  return qgisSettingsDirPath() + QStringLiteral( "symbology-style.db" );
790 }
791 
793 {
794  return QRegExp( "^[A-Za-z][A-Za-z0-9\\._-]*" );
795 }
796 
798 {
799  if ( !sUserName.isEmpty() )
800  return sUserName;
801 
802 #ifdef _MSC_VER
803  TCHAR name [ UNLEN + 1 ];
804  DWORD size = UNLEN + 1;
805 
806  if ( GetUserName( ( TCHAR * )name, &size ) )
807  {
808  sUserName = QString( name );
809  }
810 
811 #else
812  QProcess process;
813 
814  process.start( QStringLiteral( "whoami" ) );
815  process.waitForFinished();
816  sUserName = process.readAllStandardOutput().trimmed();
817 #endif
818 
819  if ( !sUserName.isEmpty() )
820  return sUserName;
821 
822  //backup plan - use environment variables
823  sUserName = qgetenv( "USER" );
824  if ( !sUserName.isEmpty() )
825  return sUserName;
826 
827  //last resort
828  sUserName = qgetenv( "USERNAME" );
829  return sUserName;
830 }
831 
833 {
834  if ( !sUserFullName.isEmpty() )
835  return sUserFullName;
836 
837 #ifdef _MSC_VER
838  TCHAR name [ UNLEN + 1 ];
839  DWORD size = UNLEN + 1;
840 
841  //note - this only works for accounts connected to domain
842  if ( GetUserNameEx( NameDisplay, ( TCHAR * )name, &size ) )
843  {
844  sUserFullName = QString( name );
845  }
846 
847  //fall back to login name
848  if ( sUserFullName.isEmpty() )
849  sUserFullName = userLoginName();
850 #elif defined(Q_OS_ANDROID)
851  sUserFullName = "Not available";
852 #else
853  struct passwd *p = getpwuid( getuid() );
854 
855  if ( p )
856  {
857  QString gecosName = QString( p->pw_gecos );
858  sUserFullName = gecosName.left( gecosName.indexOf( ',', 0 ) );
859  }
860 
861 #endif
862 
863  return sUserFullName;
864 }
865 
867 {
868 #if defined(Q_OS_ANDROID)
869  return QLatin1String( "android" );
870 #elif defined(Q_OS_MAC)
871  return QLatin1String( "osx" );
872 #elif defined(Q_OS_WIN)
873  return QLatin1String( "windows" );
874 #elif defined(Q_OS_LINUX)
875  return QStringLiteral( "linux" );
876 #else
877  return QLatin1String( "unknown" );
878 #endif
879 }
880 
882 {
883  return sPlatformName;
884 }
885 
887 {
888  QgsSettings settings;
889  bool overrideLocale = settings.value( QStringLiteral( "locale/overrideFlag" ), false ).toBool();
890  if ( overrideLocale )
891  {
892  QString locale = settings.value( QStringLiteral( "locale/userLocale" ), QString() ).toString();
893  // don't differentiate en_US and en_GB
894  if ( locale.startsWith( QStringLiteral( "en" ), Qt::CaseInsensitive ) )
895  {
896  return locale.left( 2 );
897  }
898 
899  return locale;
900  }
901  else
902  {
903  return QLocale::system().name().left( 2 );
904  }
905 }
906 
908 {
909  return qgisSettingsDirPath() + QStringLiteral( "/themes" );
910 }
911 
913 {
914  return ABISYM( mPkgDataPath ) + QStringLiteral( "/resources/symbology-style.xml" );
915 }
916 
918 {
919  return ABISYM( mPkgDataPath ) + QStringLiteral( "/resources/themes" );
920 }
921 
923 {
924  return ABISYM( mPkgDataPath ) + QStringLiteral( "/resources/server/" );
925 }
926 
928 {
929  return ABISYM( mLibraryPath );
930 }
931 
933 {
934  return ABISYM( mLibexecPath );
935 }
936 
938 {
939  return ( htonl( 1 ) == 1 ) ? XDR : NDR;
940 }
941 
943 {
944  // set the provider plugin path (this creates provider registry)
946 
947  // create data item provider registry
949 
950  // create project instance if doesn't exist
952 
953  // Initialize authentication manager and connect to database
955 
956  // Make sure we have a NAM created on the main thread.
957  // Note that this might call QgsApplication::authManager to
958  // setup the proxy configuration that's why it needs to be
959  // called after the QgsAuthManager instance has been created
961 
962 }
963 
964 
966 {
967  if ( instance() )
968  {
969  if ( !instance()->mAuthManager )
970  {
971  instance()->mAuthManager = QgsAuthManager::instance();
972  }
973  return instance()->mAuthManager;
974  }
975  else
976  {
977  // no QgsApplication instance
978  static QgsAuthManager *sAuthManager = nullptr;
979  if ( !sAuthManager )
980  sAuthManager = QgsAuthManager::instance();
981  return sAuthManager;
982  }
983 }
984 
985 
987 {
989 
990  //Ensure that all remaining deleteLater QObjects are actually deleted before we exit.
991  //This isn't strictly necessary (since we're exiting anyway) but doing so prevents a lot of
992  //LeakSanitiser noise which hides real issues
993  QgsApplication::sendPostedEvents( nullptr, QEvent::DeferredDelete );
994 
995  //delete all registered functions from expression engine (see above comment)
996  QgsExpression::cleanRegisteredFunctions();
997 
998  delete QgsProject::instance();
999 
1001 
1002  // tear-down GDAL/OGR
1003  OGRCleanupAll();
1004  GDALDestroyDriverManager();
1005 }
1006 
1008 {
1009  QString myEnvironmentVar( getenv( "QGIS_PREFIX_PATH" ) );
1010  QString myState = tr( "Application state:\n"
1011  "QGIS_PREFIX_PATH env var:\t\t%1\n"
1012  "Prefix:\t\t%2\n"
1013  "Plugin Path:\t\t%3\n"
1014  "Package Data Path:\t%4\n"
1015  "Active Theme Name:\t%5\n"
1016  "Active Theme Path:\t%6\n"
1017  "Default Theme Path:\t%7\n"
1018  "SVG Search Paths:\t%8\n"
1019  "User DB Path:\t%9\n"
1020  "Auth DB Path:\t%10\n" )
1021  .arg( myEnvironmentVar,
1022  prefixPath(),
1023  pluginPath(),
1024  pkgDataPath(),
1025  themeName(),
1026  activeThemePath(),
1027  defaultThemePath(),
1028  svgPaths().join( tr( "\n\t\t", "match indentation of application state" ) ),
1030  .arg( qgisAuthDatabaseFilePath() );
1031  return myState;
1032 }
1033 
1035 {
1036  //
1037  // Make the style sheet desktop preferences aware by using qappliation
1038  // palette as a basis for colors where appropriate
1039  //
1040 // QColor myColor1 = palette().highlight().color();
1041  QColor myColor1( Qt::lightGray );
1042  QColor myColor2 = myColor1;
1043  myColor2 = myColor2.lighter( 110 ); //10% lighter
1044  QString myStyle;
1045  myStyle = "p.glossy{ background-color: qlineargradient(x1:0, y1:0, x2:0, y2:1, "
1046  " stop: 0 " + myColor1.name() + ","
1047  " stop: 0.1 " + myColor2.name() + ","
1048  " stop: 0.5 " + myColor1.name() + ","
1049  " stop: 0.9 " + myColor2.name() + ","
1050  " stop: 1 " + myColor1.name() + ");"
1051  " color: black;"
1052  " padding-left: 4px;"
1053  " padding-top: 20px;"
1054  " padding-bottom: 8px;"
1055  " border: 1px solid #6c6c6c;"
1056  "}"
1057  "p.subheaderglossy{ background-color: qlineargradient(x1:0, y1:0, x2:0, y2:1, "
1058  " stop: 0 " + myColor1.name() + ","
1059  " stop: 0.1 " + myColor2.name() + ","
1060  " stop: 0.5 " + myColor1.name() + ","
1061  " stop: 0.9 " + myColor2.name() + ","
1062  " stop: 1 " + myColor1.name() + ");"
1063  " font-weight: bold;"
1064  " font-size: medium;"
1065  " line-height: 1.1em;"
1066  " width: 100%;"
1067  " color: black;"
1068  " padding-left: 4px;"
1069  " padding-right: 4px;"
1070  " padding-top: 20px;"
1071  " padding-bottom: 8px;"
1072  " border: 1px solid #6c6c6c;"
1073  "}"
1074  "th.glossy{ background-color: qlineargradient(x1:0, y1:0, x2:0, y2:1, "
1075  " stop: 0 " + myColor1.name() + ","
1076  " stop: 0.1 " + myColor2.name() + ","
1077  " stop: 0.5 " + myColor1.name() + ","
1078  " stop: 0.9 " + myColor2.name() + ","
1079  " stop: 1 " + myColor1.name() + ");"
1080  " color: black;"
1081  " border: 1px solid #6c6c6c;"
1082  "}"
1083  ".overview{"
1084  " font: 1.82em;"
1085  " font-weight: bold;"
1086  "}"
1087  "body{"
1088  " background: white;"
1089  " color: black;"
1090  " font-family: 'Lato', 'Ubuntu', 'Lucida Grande', 'Segoe UI', 'Arial', sans-serif;"
1091  " width: 100%;"
1092  "}"
1093  "h1{ background-color: #F6F6F6;"
1094  " color: #589632; " // from http://qgis.org/en/site/getinvolved/styleguide.html
1095  " font-size: x-large; "
1096  " font-weight: normal;"
1097  " background: none;"
1098  " padding: 0.75em 0 0;"
1099  " margin: 0;"
1100  " line-height: 3em;"
1101  "}"
1102  "h2{ background-color: #F6F6F6;"
1103  " color: #589632; " // from http://qgis.org/en/site/getinvolved/styleguide.html
1104  " font-size: medium; "
1105  " font-weight: normal;"
1106  " background: none;"
1107  " padding: 0.75em 0 0;"
1108  " margin: 0;"
1109  " line-height: 1.1em;"
1110  "}"
1111  "h3{ background-color: #F6F6F6;"
1112  " color: #93b023;" // from http://qgis.org/en/site/getinvolved/styleguide.html
1113  " font-weight: bold;"
1114  " font-size: large;"
1115  " text-align: right;"
1116  " border-bottom: 5px solid #DCEB5C;"
1117  "}"
1118  "h4{ background-color: #F6F6F6;"
1119  " color: #93b023;" // from http://qgis.org/en/site/getinvolved/styleguide.html
1120  " font-weight: bold;"
1121  " font-size: medium;"
1122  " text-align: right;"
1123  "}"
1124  "h5{ background-color: #F6F6F6;"
1125  " color: #93b023;" // from http://qgis.org/en/site/getinvolved/styleguide.html
1126  " font-weight: bold;"
1127  " font-size: small;"
1128  " text-align: right;"
1129  "}"
1130  "a{ color: #729FCF;"
1131  " font-family: arial,sans-serif;"
1132  " font-size: small;"
1133  "}"
1134  "label{ background-color: #FFFFCC;"
1135  " border: 1px solid black;"
1136  " margin: 1px;"
1137  " padding: 0px 3px; "
1138  " font-size: small;"
1139  "}"
1140  ".section {"
1141  " font-weight: bold;"
1142  " padding-top:25px;"
1143  "}"
1144  ".list-view .highlight {"
1145  " text-align: right;"
1146  " border: 0px;"
1147  " width: 20%;"
1148  " padding-right: 15px;"
1149  " padding-left: 20px;"
1150  " font-weight: bold;"
1151  "}"
1152  ".tabular-view{ "
1153  " border-collapse: collapse;"
1154  " width: 95%;"
1155  "}"
1156  ".tabular-view th, .tabular-view td { "
1157  " border:10px solid black;"
1158  "}"
1159  ".tabular-view .odd-row{"
1160  " background-color: #f9f9f9;"
1161  "}"
1162  "hr {"
1163  " border: 0;"
1164  " height: 0;"
1165  " border-top: 1px solid black;"
1166  "}";
1167  return myStyle;
1168 }
1169 
1171 {
1172  if ( 0 >= OGRGetDriverCount() )
1173  {
1174  OGRRegisterAll();
1175  }
1176 }
1177 
1178 QString QgsApplication::absolutePathToRelativePath( const QString &aPath, const QString &targetPath )
1179 {
1180  QString aPathUrl = aPath;
1181  QString tPathUrl = targetPath;
1182 #if defined( Q_OS_WIN )
1183  const Qt::CaseSensitivity cs = Qt::CaseInsensitive;
1184 
1185  aPathUrl.replace( '\\', '/' );
1186  if ( aPathUrl.startsWith( "//" ) )
1187  {
1188  // keep UNC prefix
1189  aPathUrl = "\\\\" + aPathUrl.mid( 2 );
1190  }
1191 
1192  tPathUrl.replace( '\\', '/' );
1193  if ( tPathUrl.startsWith( "//" ) )
1194  {
1195  // keep UNC prefix
1196  tPathUrl = "\\\\" + tPathUrl.mid( 2 );
1197  }
1198 #else
1199  const Qt::CaseSensitivity cs = Qt::CaseSensitive;
1200 #endif
1201 
1202  QStringList targetElems = tPathUrl.split( '/', QString::SkipEmptyParts );
1203  QStringList aPathElems = aPathUrl.split( '/', QString::SkipEmptyParts );
1204 
1205  targetElems.removeAll( QStringLiteral( "." ) );
1206  aPathElems.removeAll( QStringLiteral( "." ) );
1207 
1208  // remove common part
1209  int n = 0;
1210  while ( !aPathElems.isEmpty() &&
1211  !targetElems.isEmpty() &&
1212  aPathElems[0].compare( targetElems[0], cs ) == 0 )
1213  {
1214  aPathElems.removeFirst();
1215  targetElems.removeFirst();
1216  n++;
1217  }
1218 
1219  if ( n == 0 )
1220  {
1221  // no common parts; might not even be a file
1222  return aPathUrl;
1223  }
1224 
1225  if ( !targetElems.isEmpty() )
1226  {
1227  // go up to the common directory
1228  for ( int i = 0; i < targetElems.size(); i++ )
1229  {
1230  aPathElems.insert( 0, QStringLiteral( ".." ) );
1231  }
1232  }
1233  else
1234  {
1235  // let it start with . nevertheless,
1236  // so relative path always start with either ./ or ../
1237  aPathElems.insert( 0, QStringLiteral( "." ) );
1238  }
1239 
1240  return aPathElems.join( QStringLiteral( "/" ) );
1241 }
1242 
1243 QString QgsApplication::relativePathToAbsolutePath( const QString &rpath, const QString &targetPath )
1244 {
1245  // relative path should always start with ./ or ../
1246  if ( !rpath.startsWith( QLatin1String( "./" ) ) && !rpath.startsWith( QLatin1String( "../" ) ) )
1247  {
1248  return rpath;
1249  }
1250 
1251  QString rPathUrl = rpath;
1252  QString targetPathUrl = targetPath;
1253 
1254 #if defined(Q_OS_WIN)
1255  rPathUrl.replace( '\\', '/' );
1256  targetPathUrl.replace( '\\', '/' );
1257 
1258  bool uncPath = targetPathUrl.startsWith( "//" );
1259 #endif
1260 
1261  QStringList srcElems = rPathUrl.split( '/', QString::SkipEmptyParts );
1262  QStringList targetElems = targetPathUrl.split( '/', QString::SkipEmptyParts );
1263 
1264 #if defined(Q_OS_WIN)
1265  if ( uncPath )
1266  {
1267  targetElems.insert( 0, "" );
1268  targetElems.insert( 0, "" );
1269  }
1270 #endif
1271 
1272  // append source path elements
1273  targetElems << srcElems;
1274  targetElems.removeAll( QStringLiteral( "." ) );
1275 
1276  // resolve ..
1277  int pos;
1278  while ( ( pos = targetElems.indexOf( QStringLiteral( ".." ) ) ) > 0 )
1279  {
1280  // remove preceding element and ..
1281  targetElems.removeAt( pos - 1 );
1282  targetElems.removeAt( pos - 1 );
1283  }
1284 
1285 #if !defined(Q_OS_WIN)
1286  // make path absolute
1287  targetElems.prepend( QLatin1String( "" ) );
1288 #endif
1289 
1290  return targetElems.join( QStringLiteral( "/" ) );
1291 }
1292 
1293 void QgsApplication::skipGdalDriver( const QString &driver )
1294 {
1295  if ( ABISYM( mGdalSkipList ).contains( driver ) || driver.isEmpty() )
1296  {
1297  return;
1298  }
1299  ABISYM( mGdalSkipList ) << driver;
1301 }
1302 
1303 void QgsApplication::restoreGdalDriver( const QString &driver )
1304 {
1305  if ( !ABISYM( mGdalSkipList ).contains( driver ) )
1306  {
1307  return;
1308  }
1309  int myPos = ABISYM( mGdalSkipList ).indexOf( driver );
1310  if ( myPos >= 0 )
1311  {
1312  ABISYM( mGdalSkipList ).removeAt( myPos );
1313  }
1315 }
1316 
1318 {
1319  ABISYM( mGdalSkipList ).removeDuplicates();
1320  QString myDriverList = ABISYM( mGdalSkipList ).join( QStringLiteral( " " ) );
1321  QgsDebugMsg( "Gdal Skipped driver list set to:" );
1322  QgsDebugMsg( myDriverList );
1323  CPLSetConfigOption( "GDAL_SKIP", myDriverList.toUtf8() );
1324  GDALAllRegister(); //to update driver list and skip missing ones
1325 }
1326 
1328 {
1329  QString folder = userThemesFolder();
1330  QDir myDir( folder );
1331  if ( !myDir.exists() )
1332  {
1333  myDir.mkpath( folder );
1334  }
1335 
1336  copyPath( defaultThemesFolder(), userThemesFolder() );
1337  return true;
1338 }
1339 
1340 void QgsApplication::copyPath( const QString &src, const QString &dst )
1341 {
1342  QDir dir( src );
1343  if ( ! dir.exists() )
1344  return;
1345 
1346  Q_FOREACH ( const QString &d, dir.entryList( QDir::Dirs | QDir::NoDotAndDotDot ) )
1347  {
1348  QString dst_path = dst + QDir::separator() + d;
1349  dir.mkpath( dst_path );
1350  copyPath( src + QDir::separator() + d, dst_path );
1351  }
1352 
1353  Q_FOREACH ( const QString &f, dir.entryList( QDir::Files ) )
1354  {
1355  QFile::copy( src + QDir::separator() + f, dst + QDir::separator() + f );
1356  }
1357 }
1358 
1360 {
1361  //read values from QgsSettings
1362  QgsSettings settings;
1363 
1364  QVariantMap variables;
1365 
1366  //check if settings contains any variables
1367  if ( settings.contains( QStringLiteral( "/variables/values" ) ) )
1368  {
1369  QList< QVariant > customVariableVariants = settings.value( QStringLiteral( "variables/values" ) ).toList();
1370  QList< QVariant > customVariableNames = settings.value( QStringLiteral( "variables/names" ) ).toList();
1371  int variableIndex = 0;
1372  for ( QList< QVariant >::const_iterator it = customVariableVariants.constBegin();
1373  it != customVariableVariants.constEnd(); ++it )
1374  {
1375  if ( variableIndex >= customVariableNames.length() )
1376  {
1377  break;
1378  }
1379 
1380  QVariant value = ( *it );
1381  QString name = customVariableNames.at( variableIndex ).toString();
1382 
1383  variables.insert( name, value );
1384  variableIndex++;
1385  }
1386  }
1387 
1388  return variables;
1389 }
1390 
1391 void QgsApplication::setCustomVariables( const QVariantMap &variables )
1392 {
1393  QgsSettings settings;
1394 
1395  QList< QVariant > customVariableValues;
1396  QList< QVariant > customVariableNames;
1397 
1398  QVariantMap::const_iterator it = variables.constBegin();
1399  for ( ; it != variables.constEnd(); ++it )
1400  {
1401  customVariableNames << it.key();
1402  customVariableValues << it.value();
1403  }
1404 
1405  settings.setValue( QStringLiteral( "variables/names" ), customVariableNames );
1406  settings.setValue( QStringLiteral( "variables/values" ), customVariableValues );
1407 
1408  emit instance()->customVariablesChanged();
1409 }
1410 
1411 void QgsApplication::setCustomVariable( const QString &name, const QVariant &value )
1412 {
1413  // save variable to settings
1414  QgsSettings settings;
1415 
1416  QList< QVariant > customVariableVariants = settings.value( QStringLiteral( "variables/values" ) ).toList();
1417  QList< QVariant > customVariableNames = settings.value( QStringLiteral( "variables/names" ) ).toList();
1418 
1419  customVariableVariants << value;
1420  customVariableNames << name;
1421 
1422  settings.setValue( QStringLiteral( "variables/names" ), customVariableNames );
1423  settings.setValue( QStringLiteral( "variables/values" ), customVariableVariants );
1424 
1425  emit instance()->customVariablesChanged();
1426 }
1427 
1428 
1430 {
1431  ApplicationMembers *appMembers = members();
1432  if ( appMembers->mNullRepresentation.isNull() )
1433  {
1434  appMembers->mNullRepresentation = QgsSettings().value( QStringLiteral( "qgis/nullValue" ), QStringLiteral( "NULL" ) ).toString();
1435  }
1436  return appMembers->mNullRepresentation;
1437 }
1438 
1440 {
1441  ApplicationMembers *appMembers = members();
1442  if ( !appMembers || appMembers->mNullRepresentation == nullRepresentation )
1443  return;
1444 
1445  appMembers->mNullRepresentation = nullRepresentation;
1446  QgsSettings().setValue( QStringLiteral( "qgis/nullValue" ), nullRepresentation );
1447 
1448  QgsApplication *app = instance();
1449  if ( app )
1450  emit app->nullRepresentationChanged();
1451 }
1452 
1454 {
1455  return members()->mActionScopeRegistry;
1456 }
1457 
1458 bool QgsApplication::createDatabase( QString *errorMessage )
1459 {
1460  // set a working directory up for gdal to write .aux.xml files into
1461  // for cases where the raster dir is read only to the user
1462  // if the env var is already set it will be used preferentially
1463  QString myPamPath = qgisSettingsDirPath() + QStringLiteral( "gdal_pam/" );
1464  QDir myDir( myPamPath );
1465  if ( !myDir.exists() )
1466  {
1467  myDir.mkpath( myPamPath ); //fail silently
1468  }
1469 
1470 #if defined(Q_OS_WIN)
1471  CPLSetConfigOption( "GDAL_PAM_PROXY_DIR", myPamPath.toUtf8() );
1472 #else
1473  //under other OS's we use an environment var so the user can
1474  //override the path if he likes
1475  int myChangeFlag = 0; //whether we want to force the env var to change
1476  setenv( "GDAL_PAM_PROXY_DIR", myPamPath.toUtf8(), myChangeFlag );
1477 #endif
1478 
1479  // Check qgis.db and make private copy if necessary
1480  QFile qgisPrivateDbFile( QgsApplication::qgisUserDatabaseFilePath() );
1481 
1482  // first we look for ~/.qgis/qgis.db
1483  if ( !qgisPrivateDbFile.exists() )
1484  {
1485  // if it doesn't exist we copy it in from the global resources dir
1486  QString qgisMasterDbFileName = QgsApplication::qgisMasterDatabaseFilePath();
1487  QFile masterFile( qgisMasterDbFileName );
1488 
1489  // Must be sure there is destination directory ~/.qgis
1490  QDir().mkpath( QgsApplication::qgisSettingsDirPath() );
1491 
1492  //now copy the master file into the users .qgis dir
1493  bool isDbFileCopied = masterFile.copy( qgisPrivateDbFile.fileName() );
1494 
1495  if ( !isDbFileCopied )
1496  {
1497  if ( errorMessage )
1498  {
1499  *errorMessage = tr( "[ERROR] Can not make qgis.db private copy" );
1500  }
1501  return false;
1502  }
1503  }
1504  else
1505  {
1506  // migrate if necessary
1507  sqlite3_database_unique_ptr database;
1508  if ( database.open( QgsApplication::qgisUserDatabaseFilePath() ) != SQLITE_OK )
1509  {
1510  if ( errorMessage )
1511  {
1512  *errorMessage = tr( "Could not open qgis.db" );
1513  }
1514  return false;
1515  }
1516 
1517  char *errmsg = nullptr;
1518  int res = sqlite3_exec( database.get(), "SELECT epsg FROM tbl_srs LIMIT 0", nullptr, nullptr, &errmsg );
1519  if ( res == SQLITE_OK )
1520  {
1521  // epsg column exists => need migration
1522  if ( sqlite3_exec( database.get(),
1523  "ALTER TABLE tbl_srs RENAME TO tbl_srs_bak;"
1524  "CREATE TABLE tbl_srs ("
1525  "srs_id INTEGER PRIMARY KEY,"
1526  "description text NOT NULL,"
1527  "projection_acronym text NOT NULL,"
1528  "ellipsoid_acronym NOT NULL,"
1529  "parameters text NOT NULL,"
1530  "srid integer,"
1531  "auth_name varchar,"
1532  "auth_id varchar,"
1533  "is_geo integer NOT NULL,"
1534  "deprecated boolean);"
1535  "CREATE INDEX idx_srsauthid on tbl_srs(auth_name,auth_id);"
1536  "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;"
1537  "DROP TABLE tbl_srs_bak", nullptr, nullptr, &errmsg ) != SQLITE_OK
1538  )
1539  {
1540  if ( errorMessage )
1541  {
1542  *errorMessage = tr( "Migration of private qgis.db failed.\n%1" ).arg( QString::fromUtf8( errmsg ) );
1543  }
1544  sqlite3_free( errmsg );
1545  return false;
1546  }
1547  }
1548  else
1549  {
1550  sqlite3_free( errmsg );
1551  }
1552 
1553  if ( sqlite3_exec( database.get(), "DROP VIEW vw_srs", nullptr, nullptr, &errmsg ) != SQLITE_OK )
1554  {
1555  QgsDebugMsg( QString( "vw_srs didn't exists in private qgis.db: %1" ).arg( errmsg ) );
1556  }
1557 
1558  if ( sqlite3_exec( database.get(),
1559  "CREATE VIEW vw_srs AS"
1560  " SELECT"
1561  " a.description AS description"
1562  ",a.srs_id AS srs_id"
1563  ",a.is_geo AS is_geo"
1564  ",coalesce(b.name,a.projection_acronym) AS name"
1565  ",a.parameters AS parameters"
1566  ",a.auth_name AS auth_name"
1567  ",a.auth_id AS auth_id"
1568  ",a.deprecated AS deprecated"
1569  " FROM tbl_srs a"
1570  " LEFT OUTER JOIN tbl_projection b ON a.projection_acronym=b.acronym"
1571  " ORDER BY coalesce(b.name,a.projection_acronym),a.description", nullptr, nullptr, &errmsg ) != SQLITE_OK
1572  )
1573  {
1574  if ( errorMessage )
1575  {
1576  *errorMessage = tr( "Update of view in private qgis.db failed.\n%1" ).arg( QString::fromUtf8( errmsg ) );
1577  }
1578  sqlite3_free( errmsg );
1579  return false;
1580  }
1581  }
1582  return true;
1583 }
1584 
1586 {
1587  QgsDebugMsg( QString( "maxThreads: %1" ).arg( maxThreads ) );
1588 
1589  // make sure value is between 1 and #cores, if not set to -1 (use #cores)
1590  // 0 could be used to disable any parallel processing
1591  if ( maxThreads < 1 || maxThreads > QThread::idealThreadCount() )
1592  maxThreads = -1;
1593 
1594  // save value
1595  ABISYM( mMaxThreads ) = maxThreads;
1596 
1597  // if -1 use #cores
1598  if ( maxThreads == -1 )
1599  maxThreads = QThread::idealThreadCount();
1600 
1601  // set max thread count in QThreadPool
1602  QThreadPool::globalInstance()->setMaxThreadCount( maxThreads );
1603  QgsDebugMsg( QString( "set QThreadPool max thread count to %1" ).arg( QThreadPool::globalInstance()->maxThreadCount() ) );
1604 }
1605 
1607 {
1608  return members()->mTaskManager;
1609 }
1610 
1612 {
1613  return members()->mColorSchemeRegistry;
1614 }
1615 
1617 {
1618  return members()->mPaintEffectRegistry;
1619 }
1620 
1622 {
1623  return members()->mRendererRegistry;
1624 }
1625 
1627 {
1628  return members()->mRasterRendererRegistry;
1629 }
1630 
1632 {
1633  if ( instance() )
1634  {
1635  if ( !instance()->mDataItemProviderRegistry )
1636  {
1637  instance()->mDataItemProviderRegistry = new QgsDataItemProviderRegistry();
1638  }
1639  return instance()->mDataItemProviderRegistry;
1640  }
1641  else
1642  {
1643  // no QgsApplication instance
1644  static QgsDataItemProviderRegistry *sDataItemProviderRegistry = nullptr;
1645  if ( !sDataItemProviderRegistry )
1646  sDataItemProviderRegistry = new QgsDataItemProviderRegistry();
1647  return sDataItemProviderRegistry;
1648  }
1649 }
1650 
1652 {
1653  return members()->mSvgCache;
1654 }
1655 
1657 {
1658  return members()->mSymbolLayerRegistry;
1659 }
1660 
1662 {
1663  return members()->mLayoutItemRegistry;
1664 }
1665 
1667 {
1668  return members()->mGpsConnectionRegistry;
1669 }
1670 
1672 {
1673  return members()->mPluginLayerRegistry;
1674 }
1675 
1677 {
1678  return members()->mMessageLog;
1679 }
1680 
1682 {
1683  return members()->mProcessingRegistry;
1684 }
1685 
1687 {
1688  return members()->mPageSizeRegistry;
1689 }
1690 
1691 QgsAnnotationRegistry *QgsApplication::annotationRegistry()
1692 {
1693  return members()->mAnnotationRegistry;
1694 }
1695 
1697 {
1698  return members()->mFieldFormatterRegistry;
1699 }
1700 
1702 {
1703  return members()->m3DRendererRegistry;
1704 }
1705 
1706 QgsApplication::ApplicationMembers::ApplicationMembers()
1707 {
1708  // don't use initializer lists or scoped pointers - as more objects are added here we
1709  // will need to be careful with the order of creation/destruction
1710  mMessageLog = new QgsMessageLog();
1711  mProfiler = new QgsRuntimeProfiler();
1712  mTaskManager = new QgsTaskManager();
1713  mActionScopeRegistry = new QgsActionScopeRegistry();
1714  mFieldFormatterRegistry = new QgsFieldFormatterRegistry();
1715  mSvgCache = new QgsSvgCache();
1716  mColorSchemeRegistry = new QgsColorSchemeRegistry();
1717  mColorSchemeRegistry->addDefaultSchemes();
1718  mPaintEffectRegistry = new QgsPaintEffectRegistry();
1719  mSymbolLayerRegistry = new QgsSymbolLayerRegistry();
1720  mRendererRegistry = new QgsRendererRegistry();
1721  mRasterRendererRegistry = new QgsRasterRendererRegistry();
1722  mGpsConnectionRegistry = new QgsGPSConnectionRegistry();
1723  mPluginLayerRegistry = new QgsPluginLayerRegistry();
1724  mProcessingRegistry = new QgsProcessingRegistry();
1725  mPageSizeRegistry = new QgsPageSizeRegistry();
1726  mLayoutItemRegistry = new QgsLayoutItemRegistry();
1727  mLayoutItemRegistry->populate();
1728  mAnnotationRegistry = new QgsAnnotationRegistry();
1729  m3DRendererRegistry = new Qgs3DRendererRegistry();
1730 }
1731 
1732 QgsApplication::ApplicationMembers::~ApplicationMembers()
1733 {
1734  delete mActionScopeRegistry;
1735  delete m3DRendererRegistry;
1736  delete mAnnotationRegistry;
1737  delete mColorSchemeRegistry;
1738  delete mFieldFormatterRegistry;
1739  delete mGpsConnectionRegistry;
1740  delete mMessageLog;
1741  delete mPaintEffectRegistry;
1742  delete mPluginLayerRegistry;
1743  delete mProcessingRegistry;
1744  delete mPageSizeRegistry;
1745  delete mLayoutItemRegistry;
1746  delete mProfiler;
1747  delete mRasterRendererRegistry;
1748  delete mRendererRegistry;
1749  delete mSvgCache;
1750  delete mSymbolLayerRegistry;
1751  delete mTaskManager;
1752 }
1753 
1754 QgsApplication::ApplicationMembers *QgsApplication::members()
1755 {
1756  if ( instance() )
1757  {
1758  return instance()->mApplicationMembers;
1759  }
1760  else
1761  {
1762  static QMutex sMemberMutex( QMutex::Recursive );
1763  QMutexLocker lock( &sMemberMutex );
1764  if ( !sApplicationMembers )
1765  sApplicationMembers = new ApplicationMembers();
1766  return sApplicationMembers;
1767  }
1768 }
Singleton offering an interface to manage the authentication configuration database and to utilize co...
QgsApplication(int &argc, char **argv, bool GUIenabled, const QString &profileFolder=QString(), const QString &platformName="desktop")
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 void setThemeName(const QString &themeName)
Set the active theme to the specified theme.
static Qgs3DRendererRegistry * renderer3DRegistry()
Returns registry of available 3D renderers.
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.
Extends QApplication to provide access to QGIS specific resources such as theme paths, database paths etc.
static QgsFieldFormatterRegistry * fieldFormatterRegistry()
Get 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 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.
This class is a composition of two QSettings instances:
Definition: qgssettings.h:55
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.
virtual bool event(QEvent *event) override
Watch for QFileOpenEvent.
bool contains(const QString &key, const QgsSettings::Section section=QgsSettings::NoSection) const
Returns true if there exists a setting called key; returns false otherwise.
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.
#define QgsDebugMsg(str)
Definition: qgslogger.h:37
void nullRepresentationChanged()
This string is used to represent the value NULL throughout QGIS.
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).
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:128
Registry of renderers.
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 QVariantMap customVariables()
Custom expression variables for this application.
The QgsFieldFormatterRegistry manages registered classes of QgsFieldFormatter.
Color/Value picker.
static void setFileOpenEventReceiver(QObject *receiver)
Set the FileOpen event receiver.
static QString reportStyleSheet()
get a standard css style sheet for reports.
static int maxThreads()
Get maximum concurrent thread count.
static endian_t endian()
Returns whether this machine uses big or little endian.
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 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.
void setValue(const QString &key, const QVariant &value, const QgsSettings::Section section=QgsSettings::NoSection)
Sets the value of setting key to value.
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.
Keeps track of available 3D renderers.
#define QgsDebugMsgLevel(str, level)
Definition: qgslogger.h:38
Registry of available symbol layer classes.
static bool createThemeFolder()
Create the users theme folder.
static bool createDatabase(QString *errorMessage=nullptr)
initialize qgis.db
virtual ~QgsApplication()
static QString i18nPath()
Returns the path to the translation directory.
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.
A registry for known page sizes.
static const char * QGIS_ORGANIZATION_NAME
int open(const QString &path)
Opens the database at the specified file path.
Task manager for managing a set of long-running QgsTask tasks.
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.
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 QCursor getThemeCursor(const Cursor &cursor)
Helper to get a theme cursor.
static QgsAuthManager * authManager()
Returns the application&#39;s authentication manager instance.
static QRegExp shortNameRegExp()
Returns the short name regular expression for line edit validator.
Identify: obtain information about the object.
A class to register / unregister existing GPS connections such that the information is available to a...
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()
get application icon
static QgsColorSchemeRegistry * colorSchemeRegistry()
Returns the application&#39;s color scheme registry, used for managing color schemes. ...
static const char * QGIS_ORGANIZATION_DOMAIN
virtual 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 QString contributorsFilePath()
Returns the path to the contributors file.
static QString activeThemePath()
Returns the path to the currently active theme directory.
static QgsNetworkAccessManager * instance()
returns a pointer to the single instance
static void init(QString profileFolder=QString())
This method initializes paths etc for QGIS.
static void setPluginPath(const QString &pluginPath)
Alters plugin path - used by 3rd party apps.
QVariant value(const QString &key, const QVariant &defaultValue=QVariant(), const Section section=NoSection) const
Returns the value for setting key.
QgsUserProfile * getProfile(const QString &defaultProfile="default", bool createNew=true, bool initSettings=true)
Return the profile from the given root profile location.
static QgsProject * instance()
Returns the QgsProject singleton instance.
Definition: qgsproject.cpp:383
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 void exitQgis()
deletes provider registry and map layer registry
static QStringList svgPaths()
Returns the paths to svg directories.
static QString sponsorsFilePath()
Returns the path to the sponsors file.
static QStringList composerTemplatePaths()
Returns the paths to composer template directories.
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
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 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:37
static void setMaxThreads(int maxThreads)
Set maximum concurrent thread count.
static QgsGPSConnectionRegistry * gpsConnectionRegistry()
Returns the application&#39;s GPS connection registry, used for managing GPS connections.
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 QString licenceFilePath()
Returns the path to the licence file.
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.