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