QGIS API Documentation  3.0.2-Girona (307d082)
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 #ifdef Q_OS_MACX
560  if ( app->devicePixelRatio() >= 2 )
561  {
562  scale *= app->devicePixelRatio();
563  activeX = activeY = 5;
564  }
565 #endif
566  cursorIcon = QCursor( icon.pixmap( std::ceil( scale * 32 ), std::ceil( scale * 32 ) ), std::ceil( scale * activeX ), std::ceil( scale * activeY ) );
567  }
568  if ( app )
569  app->mCursorCache.insert( cursor, cursorIcon );
570  return cursorIcon;
571 }
572 
573 // TODO: add some caching mechanism ?
574 QPixmap QgsApplication::getThemePixmap( const QString &name )
575 {
576  QString myPreferredPath = activeThemePath() + QDir::separator() + name;
577  QString myDefaultPath = defaultThemePath() + QDir::separator() + name;
578  if ( QFile::exists( myPreferredPath ) )
579  {
580  return QPixmap( myPreferredPath );
581  }
582  else
583  {
584  //could still return an empty icon if it
585  //doesn't exist in the default theme either!
586  return QPixmap( myDefaultPath );
587  }
588 }
589 
591 {
592  ABISYM( mThemeName ) = themeName;
593 }
594 
596 {
597 #if defined(ANDROID)
598  QString prefixPath( getenv( "QGIS_PREFIX_PATH" ) ? getenv( "QGIS_PREFIX_PATH" ) : QDir::homePath() );
599 #else
600  QString prefixPath( getenv( "QGIS_PREFIX_PATH" ) ? getenv( "QGIS_PREFIX_PATH" ) : applicationDirPath() );
601 #endif
602  QFile f;
603  // "/../../.." is for Mac bundled app in build directory
604  const QStringList pathPrefixes = QStringList() << "" << "/.." << "/bin" << "/../../..";
605  for ( const QString &path : pathPrefixes )
606  {
607  f.setFileName( prefixPath + path + "/qgisbuildpath.txt" );
608  QgsDebugMsg( f.fileName() );
609  if ( f.exists() )
610  break;
611  }
612 
613  if ( f.exists() && f.open( QIODevice::ReadOnly ) )
614  {
615  QgsDebugMsg( "Running from build dir!" );
616  return f.readLine().trimmed();
617  }
618  else
619  {
620  return prefixPath + '/' + QStringLiteral( QGIS_DATA_SUBDIR );
621  }
622 
623 }
624 
626 {
627  return ABISYM( mThemeName );
628 }
629 
630 void QgsApplication::setUITheme( const QString &themeName )
631 {
632  // Loop all style sheets, find matching name, load it.
633  QHash<QString, QString> themes = QgsApplication::uiThemes();
634  if ( themeName == QStringLiteral( "default" ) || !themes.contains( themeName ) )
635  {
636  setThemeName( QStringLiteral( "default" ) );
637  qApp->setStyleSheet( QString() );
638  return;
639  }
640 
641  QString path = themes.value( themeName );
642  QString stylesheetname = path + "/style.qss";
643  QString autostylesheet = stylesheetname + ".auto";
644 
645  QFile file( stylesheetname );
646  QFile variablesfile( path + "/variables.qss" );
647  QFile fileout( autostylesheet );
648 
649  QFileInfo variableInfo( variablesfile );
650 
651  if ( variableInfo.exists() && variablesfile.open( QIODevice::ReadOnly ) )
652  {
653  if ( !file.open( QIODevice::ReadOnly ) || !fileout.open( QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate ) )
654  {
655  return;
656  }
657 
658  QString styledata = file.readAll();
659  QTextStream in( &variablesfile );
660  while ( !in.atEnd() )
661  {
662  QString line = in.readLine();
663  // This is a variable
664  if ( line.startsWith( '@' ) )
665  {
666  int index = line.indexOf( ':' );
667  QString name = line.mid( 0, index );
668  QString value = line.mid( index + 1, line.length() );
669  styledata.replace( name, value );
670  }
671  }
672  variablesfile.close();
673  QTextStream out( &fileout );
674  out << styledata;
675  fileout.close();
676  file.close();
677  stylesheetname = autostylesheet;
678  }
679 
680  QString styleSheet = QStringLiteral( "file:///" );
681  styleSheet.append( stylesheetname );
682  qApp->setStyleSheet( styleSheet );
683  setThemeName( themeName );
684 }
685 
686 QHash<QString, QString> QgsApplication::uiThemes()
687 {
688  QStringList paths = QStringList() << userThemesFolder() << defaultThemesFolder();
689  QHash<QString, QString> mapping;
690  mapping.insert( QStringLiteral( "default" ), QLatin1String( "" ) );
691  Q_FOREACH ( const QString &path, paths )
692  {
693  QDir folder( path );
694  QFileInfoList styleFiles = folder.entryInfoList( QDir::Dirs | QDir::NoDotAndDotDot );
695  Q_FOREACH ( const QFileInfo &info, styleFiles )
696  {
697  QFileInfo styleFile( info.absoluteFilePath() + "/style.qss" );
698  if ( !styleFile.exists() )
699  continue;
700 
701  QString name = info.baseName();
702  QString path = info.absoluteFilePath();
703  mapping.insert( name, path );
704  }
705  }
706  return mapping;
707 }
708 
710 {
711  return ABISYM( mPkgDataPath ) + QStringLiteral( "/doc/AUTHORS" );
712 }
713 
715 {
716  return ABISYM( mPkgDataPath ) + QStringLiteral( "/doc/CONTRIBUTORS" );
717 }
719 {
720  return ABISYM( mPkgDataPath ) + QStringLiteral( "/doc/developersmap.html" );
721 }
722 
724 {
725  return ABISYM( mPkgDataPath ) + QStringLiteral( "/doc/SPONSORS" );
726 }
727 
729 {
730  return ABISYM( mPkgDataPath ) + QStringLiteral( "/doc/DONORS" );
731 }
732 
734 {
735  return ABISYM( mPkgDataPath ) + QStringLiteral( "/doc/TRANSLATORS" );
736 }
737 
739 {
740  return ABISYM( mPkgDataPath ) + QStringLiteral( "/doc/LICENSE" );
741 }
742 
744 {
745  if ( ABISYM( mRunningFromBuildDir ) )
746  return ABISYM( mBuildOutputPath ) + QStringLiteral( "/i18n" );
747  else
748  return ABISYM( mPkgDataPath ) + QStringLiteral( "/i18n/" );
749 }
750 
752 {
753  return ABISYM( mPkgDataPath ) + QStringLiteral( "/resources/metadata-ISO/" );
754 }
755 
757 {
758  return ABISYM( mPkgDataPath ) + QStringLiteral( "/resources/qgis.db" );
759 }
760 
762 {
763  return ABISYM( mConfigPath );
764 }
765 
767 {
768  return qgisSettingsDirPath() + QStringLiteral( "qgis.db" );
769 }
770 
772 {
773  return ABISYM( mAuthDbDirPath ) + QStringLiteral( "qgis-auth.db" );
774 }
775 
777 {
778  return QStringLiteral( ":/images/splash/" );
779 }
780 
782 {
783  return ABISYM( mPkgDataPath ) + QStringLiteral( "/images/icons/" );
784 }
785 
787 {
788  if ( ABISYM( mRunningFromBuildDir ) )
789  {
790  QString tempCopy = QDir::tempPath() + "/srs.db";
791 
792  if ( !QFile( tempCopy ).exists() )
793  {
794  QFile f( ABISYM( mPkgDataPath ) + "/resources/srs.db" );
795  if ( !f.copy( tempCopy ) )
796  {
797  qFatal( "Could not create temporary copy" );
798  }
799  }
800 
801  return tempCopy;
802  }
803  else
804  {
805  return ABISYM( mPkgDataPath ) + QStringLiteral( "/resources/srs.db" );
806  }
807 }
808 
810 {
811  //local directories to search when looking for an SVG with a given basename
812  //defined by user in options dialog
813  QgsSettings settings;
814  QStringList pathList = settings.value( QStringLiteral( "svg/searchPathsForSVG" ) ).toStringList();
815 
816  // maintain user set order while stripping duplicates
817  QStringList paths;
818  Q_FOREACH ( const QString &path, pathList )
819  {
820  if ( !paths.contains( path ) )
821  paths.append( path );
822  }
823  Q_FOREACH ( const QString &path, ABISYM( mDefaultSvgPaths ) )
824  {
825  if ( !paths.contains( path ) )
826  paths.append( path );
827  }
828 
829  return paths;
830 }
831 
833 {
834  //local directories to search when looking for an template with a given basename
835  //defined by user in options dialog
836  QgsSettings settings;
837  QStringList pathList = settings.value( QStringLiteral( "Layout/searchPathsForTemplates" ), QVariant(), QgsSettings::Core ).toStringList();
838 
839  return pathList;
840 }
841 
843 {
844  return qgisSettingsDirPath() + QStringLiteral( "symbology-style.db" );
845 }
846 
848 {
849  return QRegExp( "^[A-Za-z_][A-Za-z0-9\\._-]*" );
850 }
851 
853 {
854  if ( !sUserName.isEmpty() )
855  return sUserName;
856 
857 #ifdef _MSC_VER
858  TCHAR name [ UNLEN + 1 ];
859  DWORD size = UNLEN + 1;
860 
861  if ( GetUserName( ( TCHAR * )name, &size ) )
862  {
863  sUserName = QString( name );
864  }
865 
866 #else
867  QProcess process;
868 
869  process.start( QStringLiteral( "whoami" ) );
870  process.waitForFinished();
871  sUserName = process.readAllStandardOutput().trimmed();
872 #endif
873 
874  if ( !sUserName.isEmpty() )
875  return sUserName;
876 
877  //backup plan - use environment variables
878  sUserName = qgetenv( "USER" );
879  if ( !sUserName.isEmpty() )
880  return sUserName;
881 
882  //last resort
883  sUserName = qgetenv( "USERNAME" );
884  return sUserName;
885 }
886 
888 {
889  if ( !sUserFullName.isEmpty() )
890  return sUserFullName;
891 
892 #ifdef _MSC_VER
893  TCHAR name [ UNLEN + 1 ];
894  DWORD size = UNLEN + 1;
895 
896  //note - this only works for accounts connected to domain
897  if ( GetUserNameEx( NameDisplay, ( TCHAR * )name, &size ) )
898  {
899  sUserFullName = QString( name );
900  }
901 
902  //fall back to login name
903  if ( sUserFullName.isEmpty() )
904  sUserFullName = userLoginName();
905 #elif defined(Q_OS_ANDROID) || defined(__MINGW32__)
906  sUserFullName = "Not available";
907 #else
908  struct passwd *p = getpwuid( getuid() );
909 
910  if ( p )
911  {
912  QString gecosName = QString( p->pw_gecos );
913  sUserFullName = gecosName.left( gecosName.indexOf( ',', 0 ) );
914  }
915 
916 #endif
917 
918  return sUserFullName;
919 }
920 
922 {
923 #if defined(Q_OS_ANDROID)
924  return QLatin1String( "android" );
925 #elif defined(Q_OS_MAC)
926  return QLatin1String( "osx" );
927 #elif defined(Q_OS_WIN)
928  return QLatin1String( "windows" );
929 #elif defined(Q_OS_LINUX)
930  return QStringLiteral( "linux" );
931 #else
932  return QLatin1String( "unknown" );
933 #endif
934 }
935 
937 {
938  return sPlatformName;
939 }
940 
942 {
943  QgsSettings settings;
944  bool overrideLocale = settings.value( QStringLiteral( "locale/overrideFlag" ), false ).toBool();
945  if ( overrideLocale )
946  {
947  QString locale = settings.value( QStringLiteral( "locale/userLocale" ), QString() ).toString();
948  // don't differentiate en_US and en_GB
949  if ( locale.startsWith( QStringLiteral( "en" ), Qt::CaseInsensitive ) )
950  {
951  return locale.left( 2 );
952  }
953 
954  return locale;
955  }
956  else
957  {
958  return QLocale::system().name().left( 2 );
959  }
960 }
961 
963 {
964  return qgisSettingsDirPath() + QStringLiteral( "/themes" );
965 }
966 
968 {
969  return ABISYM( mPkgDataPath ) + QStringLiteral( "/resources/symbology-style.xml" );
970 }
971 
973 {
974  return ABISYM( mPkgDataPath ) + QStringLiteral( "/resources/themes" );
975 }
976 
978 {
979  return ABISYM( mPkgDataPath ) + QStringLiteral( "/resources/server/" );
980 }
981 
983 {
984  return ABISYM( mLibraryPath );
985 }
986 
988 {
989  return ABISYM( mLibexecPath );
990 }
991 
993 {
994  return ( htonl( 1 ) == 1 ) ? XDR : NDR;
995 }
996 
998 {
999  if ( !ABISYM( mInitialized ) && QgsApplication::instance() )
1000  {
1001  init( ABISYM( mProfilePath ) );
1002  }
1003 
1004  // set the provider plugin path (this creates provider registry)
1006 
1007  // create data item provider registry
1009 
1010  // create project instance if doesn't exist
1012 
1013  // Initialize authentication manager and connect to database
1015 
1016  // Make sure we have a NAM created on the main thread.
1017  // Note that this might call QgsApplication::authManager to
1018  // setup the proxy configuration that's why it needs to be
1019  // called after the QgsAuthManager instance has been created
1021 
1022 }
1023 
1024 
1026 {
1027  if ( instance() )
1028  {
1029  if ( !instance()->mAuthManager )
1030  {
1031  instance()->mAuthManager = QgsAuthManager::instance();
1032  }
1033  return instance()->mAuthManager;
1034  }
1035  else
1036  {
1037  // no QgsApplication instance
1038  static QgsAuthManager *sAuthManager = nullptr;
1039  if ( !sAuthManager )
1040  sAuthManager = QgsAuthManager::instance();
1041  return sAuthManager;
1042  }
1043 }
1044 
1045 
1047 {
1048  delete QgsApplication::authManager();
1049 
1050  //Ensure that all remaining deleteLater QObjects are actually deleted before we exit.
1051  //This isn't strictly necessary (since we're exiting anyway) but doing so prevents a lot of
1052  //LeakSanitiser noise which hides real issues
1053  QgsApplication::sendPostedEvents( nullptr, QEvent::DeferredDelete );
1054 
1055  //delete all registered functions from expression engine (see above comment)
1056  QgsExpression::cleanRegisteredFunctions();
1057 
1058  delete QgsProject::instance();
1059 
1061 
1062  // tear-down GDAL/OGR
1063  OGRCleanupAll();
1064  GDALDestroyDriverManager();
1065 }
1066 
1068 {
1069  QString myEnvironmentVar( getenv( "QGIS_PREFIX_PATH" ) );
1070  QString myState = tr( "Application state:\n"
1071  "QGIS_PREFIX_PATH env var:\t\t%1\n"
1072  "Prefix:\t\t%2\n"
1073  "Plugin Path:\t\t%3\n"
1074  "Package Data Path:\t%4\n"
1075  "Active Theme Name:\t%5\n"
1076  "Active Theme Path:\t%6\n"
1077  "Default Theme Path:\t%7\n"
1078  "SVG Search Paths:\t%8\n"
1079  "User DB Path:\t%9\n"
1080  "Auth DB Path:\t%10\n" )
1081  .arg( myEnvironmentVar,
1082  prefixPath(),
1083  pluginPath(),
1084  pkgDataPath(),
1085  themeName(),
1086  activeThemePath(),
1087  defaultThemePath(),
1088  svgPaths().join( tr( "\n\t\t", "match indentation of application state" ) ),
1090  .arg( qgisAuthDatabaseFilePath() );
1091  return myState;
1092 }
1093 
1095 {
1096  //
1097  // Make the style sheet desktop preferences aware by using qappliation
1098  // palette as a basis for colors where appropriate
1099  //
1100 // QColor myColor1 = palette().highlight().color();
1101  QColor myColor1( Qt::lightGray );
1102  QColor myColor2 = myColor1;
1103  myColor2 = myColor2.lighter( 110 ); //10% lighter
1104  QString myStyle;
1105  myStyle = ".overview{"
1106  " font: 1.82em;"
1107  " font-weight: bold;"
1108  "}"
1109  "body{"
1110  " background: white;"
1111  " color: black;"
1112  " font-family: 'Lato', 'Ubuntu', 'Lucida Grande', 'Segoe UI', 'Arial', sans-serif;"
1113  " width: 100%;"
1114  "}"
1115  "h1{ background-color: #F6F6F6;"
1116  " color: #589632; " // from http://qgis.org/en/site/getinvolved/styleguide.html
1117  " font-size: x-large; "
1118  " font-weight: normal;"
1119  " background: none;"
1120  " padding: 0.75em 0 0;"
1121  " margin: 0;"
1122  " line-height: 3em;"
1123  "}"
1124  "h2{ background-color: #F6F6F6;"
1125  " color: #589632; " // from http://qgis.org/en/site/getinvolved/styleguide.html
1126  " font-size: medium; "
1127  " font-weight: normal;"
1128  " background: none;"
1129  " padding: 0.75em 0 0;"
1130  " margin: 0;"
1131  " line-height: 1.1em;"
1132  "}"
1133  "h3{ background-color: #F6F6F6;"
1134  " color: #93b023;" // from http://qgis.org/en/site/getinvolved/styleguide.html
1135  " font-weight: bold;"
1136  " font-size: large;"
1137  " text-align: right;"
1138  " border-bottom: 5px solid #DCEB5C;"
1139  "}"
1140  "h4{ background-color: #F6F6F6;"
1141  " color: #93b023;" // from http://qgis.org/en/site/getinvolved/styleguide.html
1142  " font-weight: bold;"
1143  " font-size: medium;"
1144  " text-align: right;"
1145  "}"
1146  "h5{ background-color: #F6F6F6;"
1147  " color: #93b023;" // from http://qgis.org/en/site/getinvolved/styleguide.html
1148  " font-weight: bold;"
1149  " font-size: small;"
1150  " text-align: right;"
1151  "}"
1152  "a{ color: #729FCF;"
1153  " font-family: arial,sans-serif;"
1154  " font-size: small;"
1155  "}"
1156  "label{ background-color: #FFFFCC;"
1157  " border: 1px solid black;"
1158  " margin: 1px;"
1159  " padding: 0px 3px; "
1160  " font-size: small;"
1161  "}"
1162  ".section {"
1163  " font-weight: bold;"
1164  " padding-top:25px;"
1165  "}"
1166  ".list-view .highlight {"
1167  " text-align: right;"
1168  " border: 0px;"
1169  " width: 20%;"
1170  " padding-right: 15px;"
1171  " padding-left: 20px;"
1172  " font-weight: bold;"
1173  "}"
1174  "th .strong {"
1175  " font-weight: bold;"
1176  "}"
1177  ".tabular-view{ "
1178  " border-collapse: collapse;"
1179  " width: 95%;"
1180  "}"
1181  ".tabular-view th, .tabular-view td { "
1182  " border:10px solid black;"
1183  "}"
1184  ".tabular-view .odd-row{"
1185  " background-color: #f9f9f9;"
1186  "}"
1187  "hr {"
1188  " border: 0;"
1189  " height: 0;"
1190  " border-top: 1px solid black;"
1191  "}";
1192  return myStyle;
1193 }
1194 
1196 {
1197  if ( 0 >= OGRGetDriverCount() )
1198  {
1199  OGRRegisterAll();
1200  }
1201 }
1202 
1203 QString QgsApplication::absolutePathToRelativePath( const QString &aPath, const QString &targetPath )
1204 {
1205  QString aPathUrl = aPath;
1206  QString tPathUrl = targetPath;
1207 #if defined( Q_OS_WIN )
1208  const Qt::CaseSensitivity cs = Qt::CaseInsensitive;
1209 
1210  aPathUrl.replace( '\\', '/' );
1211  if ( aPathUrl.startsWith( "//" ) )
1212  {
1213  // keep UNC prefix
1214  aPathUrl = "\\\\" + aPathUrl.mid( 2 );
1215  }
1216 
1217  tPathUrl.replace( '\\', '/' );
1218  if ( tPathUrl.startsWith( "//" ) )
1219  {
1220  // keep UNC prefix
1221  tPathUrl = "\\\\" + tPathUrl.mid( 2 );
1222  }
1223 #else
1224  const Qt::CaseSensitivity cs = Qt::CaseSensitive;
1225 #endif
1226 
1227  QStringList targetElems = tPathUrl.split( '/', QString::SkipEmptyParts );
1228  QStringList aPathElems = aPathUrl.split( '/', QString::SkipEmptyParts );
1229 
1230  targetElems.removeAll( QStringLiteral( "." ) );
1231  aPathElems.removeAll( QStringLiteral( "." ) );
1232 
1233  // remove common part
1234  int n = 0;
1235  while ( !aPathElems.isEmpty() &&
1236  !targetElems.isEmpty() &&
1237  aPathElems[0].compare( targetElems[0], cs ) == 0 )
1238  {
1239  aPathElems.removeFirst();
1240  targetElems.removeFirst();
1241  n++;
1242  }
1243 
1244  if ( n == 0 )
1245  {
1246  // no common parts; might not even be a file
1247  return aPathUrl;
1248  }
1249 
1250  if ( !targetElems.isEmpty() )
1251  {
1252  // go up to the common directory
1253  for ( int i = 0; i < targetElems.size(); i++ )
1254  {
1255  aPathElems.insert( 0, QStringLiteral( ".." ) );
1256  }
1257  }
1258  else
1259  {
1260  // let it start with . nevertheless,
1261  // so relative path always start with either ./ or ../
1262  aPathElems.insert( 0, QStringLiteral( "." ) );
1263  }
1264 
1265  return aPathElems.join( QStringLiteral( "/" ) );
1266 }
1267 
1268 QString QgsApplication::relativePathToAbsolutePath( const QString &rpath, const QString &targetPath )
1269 {
1270  // relative path should always start with ./ or ../
1271  if ( !rpath.startsWith( QLatin1String( "./" ) ) && !rpath.startsWith( QLatin1String( "../" ) ) )
1272  {
1273  return rpath;
1274  }
1275 
1276  QString rPathUrl = rpath;
1277  QString targetPathUrl = targetPath;
1278 
1279 #if defined(Q_OS_WIN)
1280  rPathUrl.replace( '\\', '/' );
1281  targetPathUrl.replace( '\\', '/' );
1282 
1283  bool uncPath = targetPathUrl.startsWith( "//" );
1284 #endif
1285 
1286  QStringList srcElems = rPathUrl.split( '/', QString::SkipEmptyParts );
1287  QStringList targetElems = targetPathUrl.split( '/', QString::SkipEmptyParts );
1288 
1289 #if defined(Q_OS_WIN)
1290  if ( uncPath )
1291  {
1292  targetElems.insert( 0, "" );
1293  targetElems.insert( 0, "" );
1294  }
1295 #endif
1296 
1297  // append source path elements
1298  targetElems << srcElems;
1299  targetElems.removeAll( QStringLiteral( "." ) );
1300 
1301  // resolve ..
1302  int pos;
1303  while ( ( pos = targetElems.indexOf( QStringLiteral( ".." ) ) ) > 0 )
1304  {
1305  // remove preceding element and ..
1306  targetElems.removeAt( pos - 1 );
1307  targetElems.removeAt( pos - 1 );
1308  }
1309 
1310 #if !defined(Q_OS_WIN)
1311  // make path absolute
1312  targetElems.prepend( QLatin1String( "" ) );
1313 #endif
1314 
1315  return targetElems.join( QStringLiteral( "/" ) );
1316 }
1317 
1318 void QgsApplication::skipGdalDriver( const QString &driver )
1319 {
1320  if ( ABISYM( mGdalSkipList ).contains( driver ) || driver.isEmpty() )
1321  {
1322  return;
1323  }
1324  ABISYM( mGdalSkipList ) << driver;
1326 }
1327 
1328 void QgsApplication::restoreGdalDriver( const QString &driver )
1329 {
1330  if ( !ABISYM( mGdalSkipList ).contains( driver ) )
1331  {
1332  return;
1333  }
1334  int myPos = ABISYM( mGdalSkipList ).indexOf( driver );
1335  if ( myPos >= 0 )
1336  {
1337  ABISYM( mGdalSkipList ).removeAt( myPos );
1338  }
1340 }
1341 
1343 {
1344  ABISYM( mGdalSkipList ).removeDuplicates();
1345  QString myDriverList = ABISYM( mGdalSkipList ).join( QStringLiteral( " " ) );
1346  QgsDebugMsg( "Gdal Skipped driver list set to:" );
1347  QgsDebugMsg( myDriverList );
1348  CPLSetConfigOption( "GDAL_SKIP", myDriverList.toUtf8() );
1349  GDALAllRegister(); //to update driver list and skip missing ones
1350 }
1351 
1353 {
1354  QString folder = userThemesFolder();
1355  QDir myDir( folder );
1356  if ( !myDir.exists() )
1357  {
1358  myDir.mkpath( folder );
1359  }
1360 
1361  return true;
1362 }
1363 
1364 void QgsApplication::copyPath( const QString &src, const QString &dst )
1365 {
1366  QDir dir( src );
1367  if ( ! dir.exists() )
1368  return;
1369 
1370  Q_FOREACH ( const QString &d, dir.entryList( QDir::Dirs | QDir::NoDotAndDotDot ) )
1371  {
1372  QString dst_path = dst + QDir::separator() + d;
1373  dir.mkpath( dst_path );
1374  copyPath( src + QDir::separator() + d, dst_path );
1375  }
1376 
1377  Q_FOREACH ( const QString &f, dir.entryList( QDir::Files ) )
1378  {
1379  QFile::copy( src + QDir::separator() + f, dst + QDir::separator() + f );
1380  }
1381 }
1382 
1384 {
1385  //read values from QgsSettings
1386  QgsSettings settings;
1387 
1388  QVariantMap variables;
1389 
1390  //check if settings contains any variables
1391  settings.beginGroup( "variables" );
1392  QStringList childKeys = settings.childKeys();
1393  for ( QStringList::const_iterator it = childKeys.constBegin(); it != childKeys.constEnd(); ++it )
1394  {
1395  QString name = *it;
1396  variables.insert( name, settings.value( name ) );
1397  }
1398 
1399  return variables;
1400 }
1401 
1402 void QgsApplication::setCustomVariables( const QVariantMap &variables )
1403 {
1404  QgsSettings settings;
1405 
1406  QVariantMap::const_iterator it = variables.constBegin();
1407  settings.beginGroup( "variables" );
1408  settings.remove( "" );
1409  for ( ; it != variables.constEnd(); ++it )
1410  {
1411  settings.setValue( it.key(), it.value() );
1412  }
1413 
1414  emit instance()->customVariablesChanged();
1415 }
1416 
1417 void QgsApplication::setCustomVariable( const QString &name, const QVariant &value )
1418 {
1419  // save variable to settings
1420  QgsSettings settings;
1421 
1422  settings.setValue( QStringLiteral( "variables/" ) + name, value );
1423 
1424  emit instance()->customVariablesChanged();
1425 }
1426 
1427 
1429 {
1430  ApplicationMembers *appMembers = members();
1431  if ( appMembers->mNullRepresentation.isNull() )
1432  {
1433  appMembers->mNullRepresentation = QgsSettings().value( QStringLiteral( "qgis/nullValue" ), QStringLiteral( "NULL" ) ).toString();
1434  }
1435  return appMembers->mNullRepresentation;
1436 }
1437 
1439 {
1440  ApplicationMembers *appMembers = members();
1441  if ( !appMembers || appMembers->mNullRepresentation == nullRepresentation )
1442  return;
1443 
1444  appMembers->mNullRepresentation = nullRepresentation;
1445  QgsSettings().setValue( QStringLiteral( "qgis/nullValue" ), nullRepresentation );
1446 
1447  QgsApplication *app = instance();
1448  if ( app )
1449  emit app->nullRepresentationChanged();
1450 }
1451 
1453 {
1454  return members()->mActionScopeRegistry;
1455 }
1456 
1457 bool QgsApplication::createDatabase( QString *errorMessage )
1458 {
1459  // set a working directory up for gdal to write .aux.xml files into
1460  // for cases where the raster dir is read only to the user
1461  // if the env var is already set it will be used preferentially
1462  QString myPamPath = qgisSettingsDirPath() + QStringLiteral( "gdal_pam/" );
1463  QDir myDir( myPamPath );
1464  if ( !myDir.exists() )
1465  {
1466  myDir.mkpath( myPamPath ); //fail silently
1467  }
1468 
1469 #if defined(Q_OS_WIN)
1470  CPLSetConfigOption( "GDAL_PAM_PROXY_DIR", myPamPath.toUtf8() );
1471 #else
1472  //under other OS's we use an environment var so the user can
1473  //override the path if he likes
1474  int myChangeFlag = 0; //whether we want to force the env var to change
1475  setenv( "GDAL_PAM_PROXY_DIR", myPamPath.toUtf8(), myChangeFlag );
1476 #endif
1477 
1478  // Check qgis.db and make private copy if necessary
1479  QFile qgisPrivateDbFile( QgsApplication::qgisUserDatabaseFilePath() );
1480 
1481  // first we look for ~/.qgis/qgis.db
1482  if ( !qgisPrivateDbFile.exists() )
1483  {
1484  // if it doesn't exist we copy it in from the global resources dir
1485  QString qgisMasterDbFileName = QgsApplication::qgisMasterDatabaseFilePath();
1486  QFile masterFile( qgisMasterDbFileName );
1487 
1488  // Must be sure there is destination directory ~/.qgis
1489  QDir().mkpath( QgsApplication::qgisSettingsDirPath() );
1490 
1491  //now copy the master file into the users .qgis dir
1492  bool isDbFileCopied = masterFile.copy( qgisPrivateDbFile.fileName() );
1493 
1494  if ( !isDbFileCopied )
1495  {
1496  if ( errorMessage )
1497  {
1498  *errorMessage = tr( "[ERROR] Can not make qgis.db private copy" );
1499  }
1500  return false;
1501  }
1502  }
1503  else
1504  {
1505  // migrate if necessary
1506  sqlite3_database_unique_ptr database;
1507  if ( database.open( QgsApplication::qgisUserDatabaseFilePath() ) != SQLITE_OK )
1508  {
1509  if ( errorMessage )
1510  {
1511  *errorMessage = tr( "Could not open qgis.db" );
1512  }
1513  return false;
1514  }
1515 
1516  char *errmsg = nullptr;
1517  int res = sqlite3_exec( database.get(), "SELECT epsg FROM tbl_srs LIMIT 0", nullptr, nullptr, &errmsg );
1518  if ( res == SQLITE_OK )
1519  {
1520  // epsg column exists => need migration
1521  if ( sqlite3_exec( database.get(),
1522  "ALTER TABLE tbl_srs RENAME TO tbl_srs_bak;"
1523  "CREATE TABLE tbl_srs ("
1524  "srs_id INTEGER PRIMARY KEY,"
1525  "description text NOT NULL,"
1526  "projection_acronym text NOT NULL,"
1527  "ellipsoid_acronym NOT NULL,"
1528  "parameters text NOT NULL,"
1529  "srid integer,"
1530  "auth_name varchar,"
1531  "auth_id varchar,"
1532  "is_geo integer NOT NULL,"
1533  "deprecated boolean);"
1534  "CREATE INDEX idx_srsauthid on tbl_srs(auth_name,auth_id);"
1535  "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;"
1536  "DROP TABLE tbl_srs_bak", nullptr, nullptr, &errmsg ) != SQLITE_OK
1537  )
1538  {
1539  if ( errorMessage )
1540  {
1541  *errorMessage = tr( "Migration of private qgis.db failed.\n%1" ).arg( QString::fromUtf8( errmsg ) );
1542  }
1543  sqlite3_free( errmsg );
1544  return false;
1545  }
1546  }
1547  else
1548  {
1549  sqlite3_free( errmsg );
1550  }
1551 
1552  if ( sqlite3_exec( database.get(), "DROP VIEW vw_srs", nullptr, nullptr, &errmsg ) != SQLITE_OK )
1553  {
1554  QgsDebugMsg( QString( "vw_srs didn't exists in private qgis.db: %1" ).arg( errmsg ) );
1555  }
1556 
1557  if ( sqlite3_exec( database.get(),
1558  "CREATE VIEW vw_srs AS"
1559  " SELECT"
1560  " a.description AS description"
1561  ",a.srs_id AS srs_id"
1562  ",a.is_geo AS is_geo"
1563  ",coalesce(b.name,a.projection_acronym) AS name"
1564  ",a.parameters AS parameters"
1565  ",a.auth_name AS auth_name"
1566  ",a.auth_id AS auth_id"
1567  ",a.deprecated AS deprecated"
1568  " FROM tbl_srs a"
1569  " LEFT OUTER JOIN tbl_projection b ON a.projection_acronym=b.acronym"
1570  " ORDER BY coalesce(b.name,a.projection_acronym),a.description", nullptr, nullptr, &errmsg ) != SQLITE_OK
1571  )
1572  {
1573  if ( errorMessage )
1574  {
1575  *errorMessage = tr( "Update of view in private qgis.db failed.\n%1" ).arg( QString::fromUtf8( errmsg ) );
1576  }
1577  sqlite3_free( errmsg );
1578  return false;
1579  }
1580  }
1581  return true;
1582 }
1583 
1585 {
1586  QgsDebugMsg( QString( "maxThreads: %1" ).arg( maxThreads ) );
1587 
1588  // make sure value is between 1 and #cores, if not set to -1 (use #cores)
1589  // 0 could be used to disable any parallel processing
1590  if ( maxThreads < 1 || maxThreads > QThread::idealThreadCount() )
1591  maxThreads = -1;
1592 
1593  // save value
1594  ABISYM( mMaxThreads ) = maxThreads;
1595 
1596  // if -1 use #cores
1597  if ( maxThreads == -1 )
1598  maxThreads = QThread::idealThreadCount();
1599 
1600  // set max thread count in QThreadPool
1601  QThreadPool::globalInstance()->setMaxThreadCount( maxThreads );
1602  QgsDebugMsg( QString( "set QThreadPool max thread count to %1" ).arg( QThreadPool::globalInstance()->maxThreadCount() ) );
1603 }
1604 
1606 {
1607  return members()->mTaskManager;
1608 }
1609 
1611 {
1612  return members()->mColorSchemeRegistry;
1613 }
1614 
1616 {
1617  return members()->mPaintEffectRegistry;
1618 }
1619 
1621 {
1622  return members()->mRendererRegistry;
1623 }
1624 
1626 {
1627  return members()->mRasterRendererRegistry;
1628 }
1629 
1631 {
1632  if ( instance() )
1633  {
1634  if ( !instance()->mDataItemProviderRegistry )
1635  {
1636  instance()->mDataItemProviderRegistry = new QgsDataItemProviderRegistry();
1637  }
1638  return instance()->mDataItemProviderRegistry;
1639  }
1640  else
1641  {
1642  // no QgsApplication instance
1643  static QgsDataItemProviderRegistry *sDataItemProviderRegistry = nullptr;
1644  if ( !sDataItemProviderRegistry )
1645  sDataItemProviderRegistry = new QgsDataItemProviderRegistry();
1646  return sDataItemProviderRegistry;
1647  }
1648 }
1649 
1651 {
1652  return members()->mSvgCache;
1653 }
1654 
1656 {
1657  return members()->mSymbolLayerRegistry;
1658 }
1659 
1661 {
1662  return members()->mLayoutItemRegistry;
1663 }
1664 
1666 {
1667  return members()->mGpsConnectionRegistry;
1668 }
1669 
1671 {
1672  return members()->mPluginLayerRegistry;
1673 }
1674 
1676 {
1677  return members()->mMessageLog;
1678 }
1679 
1681 {
1682  return members()->mProcessingRegistry;
1683 }
1684 
1686 {
1687  return members()->mPageSizeRegistry;
1688 }
1689 
1690 QgsAnnotationRegistry *QgsApplication::annotationRegistry()
1691 {
1692  return members()->mAnnotationRegistry;
1693 }
1694 
1696 {
1697  return members()->mFieldFormatterRegistry;
1698 }
1699 
1701 {
1702  return members()->m3DRendererRegistry;
1703 }
1704 
1705 QgsApplication::ApplicationMembers::ApplicationMembers()
1706 {
1707  // don't use initializer lists or scoped pointers - as more objects are added here we
1708  // will need to be careful with the order of creation/destruction
1709  mMessageLog = new QgsMessageLog();
1710  mProfiler = new QgsRuntimeProfiler();
1711  mTaskManager = new QgsTaskManager();
1712  mActionScopeRegistry = new QgsActionScopeRegistry();
1713  mFieldFormatterRegistry = new QgsFieldFormatterRegistry();
1714  mSvgCache = new QgsSvgCache();
1715  mColorSchemeRegistry = new QgsColorSchemeRegistry();
1716  mColorSchemeRegistry->addDefaultSchemes();
1717  mPaintEffectRegistry = new QgsPaintEffectRegistry();
1718  mSymbolLayerRegistry = new QgsSymbolLayerRegistry();
1719  mRendererRegistry = new QgsRendererRegistry();
1720  mRasterRendererRegistry = new QgsRasterRendererRegistry();
1721  mGpsConnectionRegistry = new QgsGpsConnectionRegistry();
1722  mPluginLayerRegistry = new QgsPluginLayerRegistry();
1723  mProcessingRegistry = new QgsProcessingRegistry();
1724  mPageSizeRegistry = new QgsPageSizeRegistry();
1725  mLayoutItemRegistry = new QgsLayoutItemRegistry();
1726  mLayoutItemRegistry->populate();
1727  mAnnotationRegistry = new QgsAnnotationRegistry();
1728  m3DRendererRegistry = new Qgs3DRendererRegistry();
1729 }
1730 
1731 QgsApplication::ApplicationMembers::~ApplicationMembers()
1732 {
1733  delete mActionScopeRegistry;
1734  delete m3DRendererRegistry;
1735  delete mAnnotationRegistry;
1736  delete mColorSchemeRegistry;
1737  delete mFieldFormatterRegistry;
1738  delete mGpsConnectionRegistry;
1739  delete mMessageLog;
1740  delete mPaintEffectRegistry;
1741  delete mPluginLayerRegistry;
1742  delete mProcessingRegistry;
1743  delete mPageSizeRegistry;
1744  delete mLayoutItemRegistry;
1745  delete mProfiler;
1746  delete mRasterRendererRegistry;
1747  delete mRendererRegistry;
1748  delete mSvgCache;
1749  delete mSymbolLayerRegistry;
1750  delete mTaskManager;
1751 }
1752 
1753 QgsApplication::ApplicationMembers *QgsApplication::members()
1754 {
1755  if ( instance() )
1756  {
1757  return instance()->mApplicationMembers;
1758  }
1759  else
1760  {
1761  static QMutex sMemberMutex( QMutex::Recursive );
1762  QMutexLocker lock( &sMemberMutex );
1763  if ( !sApplicationMembers )
1764  sApplicationMembers = new ApplicationMembers();
1765  return sApplicationMembers;
1766  }
1767 }
static QStringList layoutTemplatePaths()
Returns the paths to layout template directories.
Singleton offering an interface to manage the authentication configuration database and to utilize co...
void remove(const QString &key, const QgsSettings::Section section=QgsSettings::NoSection)
Removes the setting key and any sub-settings of key in a section.
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.
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).
QStringList childKeys() const
Returns a list of all top-level keys that can be read using the QSettings object. ...
static void restoreGdalDriver(const QString &driver)
Sets the GDAL_SKIP environment variable to exclude the specified driver and then calls GDALDriverMana...
static QString iconPath(const QString &iconFile)
Returns path to the desired icon file.
A cache for images / pictures derived from svg files.
Definition: qgssvgcache.h:130
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...
void beginGroup(const QString &prefix, const QgsSettings::Section section=QgsSettings::NoSection)
Appends prefix to the current group.
Definition: qgssettings.cpp:86
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.