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