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