• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

MerginMaps / input / 5222002891

pending completion
5222002891

push

github

web-flow
fix autotests (#2710)

for testing API we need PRO subscription; still few purchasing tests are skipped

8109 of 13061 relevant lines covered (62.09%)

107.91 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

41.67
/app/main.cpp
1
/***************************************************************************
2
 *                                                                         *
3
 *   This program is free software; you can redistribute it and/or modify  *
4
 *   it under the terms of the GNU General Public License as published by  *
5
 *   the Free Software Foundation; either version 2 of the License, or     *
6
 *   (at your option) any later version.                                   *
7
 *                                                                         *
8
 ***************************************************************************/
9

10
#include "inputconfig.h"
11

12
#include <QFontDatabase>
13
#include <QGuiApplication>
14
#include <QQmlApplicationEngine>
15
#include <QQmlComponent>
16
#include <QtDebug>
17
#include <QQmlError>
18
#include <QScreen>
19
#include <QWindow>
20
#include <QtGlobal>
21
#include <QQmlContext>
22
#include <QQuickWindow>
23
#include <QLocale>
24
#include <QImageReader>
17✔
25
#include <QStandardPaths>
17✔
26
#ifdef INPUT_TEST
17✔
27
#include "test/inputtests.h"
28
#endif
29
#include <qqml.h>
30
#include <qgsmessagelog.h>
31
#include "qgsconfig.h"
32
#include "qgsproviderregistry.h"
33
#include "qgsmaplayerproxymodel.h"
34
#include "qgsnetworkaccessmanager.h"
35
#include "geodiffutils.h"
36

37
#include "androidutils.h"
38
#include "ios/iosutils.h"
39
#include "inpututils.h"
40
#include "coreutils.h"
41
#include "position/positiondirection.h"
42
#include "mapthemesmodel.h"
43
#include "merginapi.h"
44
#include "merginapistatus.h"
45
#include "merginservertype.h"
46
#include "merginsubscriptioninfo.h"
47
#include "merginsubscriptionstatus.h"
48
#include "merginsubscriptiontype.h"
49
#include "merginprojectstatusmodel.h"
50
#include "layersproxymodel.h"
51
#include "layersmodel.h"
52
#include "activelayer.h"
53
#include "purchasing.h"
54
#include "merginuserauth.h"
55
#include "merginuserinfo.h"
56
#include "variablesmanager.h"
57
#include "inputhelp.h"
58
#include "inputprojutils.h"
59
#include "fieldsmodel.h"
17✔
60
#include "projectwizard.h"
17✔
61
#include "codescanner.h"
17✔
62
#include "inputexpressionfunctions.h"
17✔
63
#include "compass.h"
17✔
64
#include "attributepreviewcontroller.h"
65
#include "qgsfeature.h"
17✔
66
#include "qgslogger.h"
67
#include "qgsmaplayer.h"
17✔
68
#include "qgsmessagelog.h"
17✔
69
#include "qgspointxy.h"
17✔
70
#include "qgsproject.h"
17✔
71
#include "qgsrelationmanager.h"
17✔
72
#include "qgscoordinatetransformcontext.h"
17✔
73
#include "qgsvectorlayer.h"
74
#include "qgsunittypes.h"
17✔
75

76
#include "rememberattributescontroller.h"
77
#include "attributecontroller.h"
78
#include "attributedata.h"
79
#include "attributeformmodel.h"
80
#include "attributeformproxymodel.h"
81
#include "attributetabmodel.h"
82
#include "attributetabproxymodel.h"
83
#include "inputcoordinatetransformer.h"
84
#include "identifykit.h"
85
#include "featurelayerpair.h"
86

87
#include "inputmapcanvasmap.h"
88
#include "inputmapsettings.h"
89
#include "inputmaptransform.h"
90

91
#include "position/positionkit.h"
92
#include "scalebarkit.h"
93
#include "featuresmodel.h"
94
#include "relationfeaturesmodel.h"
95
#include "relationreferencefeaturesmodel.h"
96
#include "fieldvalidator.h"
97
#include "valuerelationfeaturesmodel.h"
98
#include "snaputils.h"
99
#include "guidelinecontroller.h"
100

101
#include "projectsmodel.h"
102
#include "projectsproxymodel.h"
103
#include "project.h"
104
#include "qgsproject.h"
105
#include "bluetoothdiscoverymodel.h"
106
#include "position/mapposition.h"
107
#include "position/positionprovidersmodel.h"
108
#include "position/abstractpositionprovider.h"
109
#include "synchronizationmanager.h"
110
#include "synchronizationerror.h"
111

112
#include "maptools/abstractmaptool.h"
113
#include "maptools/recordingmaptool.h"
114
#include "maptools/splittingmaptool.h"
115

116
#include "layer/layertreemodel.h"
117
#include "layer/layertreemodelpixmapprovider.h"
118
#include "layer/layertreesortfiltermodel.h"
119
#include "layer/layertreeflatmodel.h"
120
#include "layer/layertreeflatmodelpixmapprovider.h"
121
#include "layer/layertreeflatsortfiltermodel.h"
122
#include "layer/layerdetaildata.h"
123
#include "layer/layerdetaillegendimageprovider.h"
124

125
#include "workspacesmodel.h"
126
#include "workspacesproxymodel.h"
127
#include "invitationsmodel.h"
128
#include "invitationsproxymodel.h"
129

130
#include "streamingintervaltype.h"
131

132
#include <QQuickStyle>
133

134
#ifndef NDEBUG
135
// #include <QQmlDebuggingEnabler>
136
#endif
137

138
#ifdef MOBILE_OS
139
#include <QFile>
140
#include <QDir>
141
#include <QStandardPaths>
142
#endif
143

144
#ifdef DESKTOP_OS
145
#include <QCommandLineParser>
146
#include <qgis.h>
147
#endif
148

149
#include "qgsapplication.h"
150
#include "activeproject.h"
151
#include "appsettings.h"
152

153
static QString getDataDir()
17✔
154
{
155
#ifdef QGIS_QUICK_DATA_PATH
156
  QString dataPathRaw( STR( QGIS_QUICK_DATA_PATH ) );
17✔
157

158
#ifdef ANDROID
159
  dataPathRaw = AndroidUtils::externalStorageAppFolder();
160
#endif
161

162
#ifdef Q_OS_IOS
163
  QString docsLocation = QStandardPaths::standardLocations( QStandardPaths::DocumentsLocation ).value( 0 );
164

165
  QDir myDir( docsLocation );
166
  if ( !myDir.exists() )
167
  {
168
    myDir.mkpath( docsLocation );
169
  }
170
  dataPathRaw = docsLocation + "/" + dataPathRaw;
171
#endif
172

173
#ifdef Q_OS_WIN32
174
  QString appLocation = QStandardPaths::writableLocation( QStandardPaths::AppDataLocation );
175

176
  QDir myDir( appLocation );
177
  if ( !myDir.exists() )
178
  {
179
    myDir.mkpath( appLocation );
180
  }
181
  dataPathRaw = appLocation + "/" + dataPathRaw;
182
#endif
183

184
  qputenv( "QGIS_QUICK_DATA_PATH", dataPathRaw.toUtf8().constData() );
17✔
185
#else
186
  qDebug( "== Must set QGIS_QUICK_DATA_PATH in order to get QGIS Quick running! ==" );
187
#endif
188
  QString dataDir = QString::fromLocal8Bit( qgetenv( "QGIS_QUICK_DATA_PATH" ) ) ;
17✔
189
  qDebug() << "QGIS_QUICK_DATA_PATH: " << dataDir;
17✔
190
  return dataDir;
17✔
191
}
17✔
192

193
static void setEnvironmentQgisPrefixPath()
17✔
194
{
195
#ifdef DESKTOP_OS
196
#ifdef QGIS_PREFIX_PATH
197
  qputenv( "QGIS_PREFIX_PATH", STR( QGIS_PREFIX_PATH ) );
198
#endif
199
  if ( QString::fromLocal8Bit( qgetenv( "QGIS_PREFIX_PATH" ) ).isEmpty() )
17✔
200
  {
201
    // if not on Android, QGIS_PREFIX_PATH env variable should have been set already or defined as C++ define
202
    qDebug( "== Must set QGIS_PREFIX_PATH in order to get QGIS Quick module running! ==" );
17✔
203
  }
17✔
204
#endif
205

206
#if defined (ANDROID) || defined (Q_OS_IOS)
207
  QDir myDir( QDir::homePath() );
208
  myDir.cdUp();
209
  QString prefixPath = myDir.absolutePath();  // something like: /data/data/org.qgis.quick
210
  qputenv( "QGIS_PREFIX_PATH", prefixPath.toUtf8().constData() );
211
#elif defined (Q_OS_WIN32)
212
  QString prefixPath = QCoreApplication::applicationDirPath();
213
  qputenv( "QGIS_PREFIX_PATH", prefixPath.toUtf8().constData() );
214
#endif
215

216
  qDebug() << "QGIS_PREFIX_PATH: " << QString::fromLocal8Bit( qgetenv( "QGIS_PREFIX_PATH" ) );
17✔
217
}
17✔
218

219

220
static void copy_demo_projects( const QString &demoDir, const QString &projectDir )
1✔
221
{
222
  if ( !demoDir.isEmpty() )
1✔
223
    InputUtils::cpDir( demoDir, projectDir );
×
224

225
  QFile demoFile( projectDir + "/Start here!/qgis-project.qgz" );
1✔
226
  if ( demoFile.exists() )
1✔
227
    qDebug() << "DEMO projects initialized";
×
228
  else
229
    CoreUtils::log( QStringLiteral( "DEMO" ), QStringLiteral( "The Input has failed to initialize demo projects" ) );
1✔
230
}
1✔
231

232
static void init_qgis( const QString &pkgPath )
17✔
233
{
234
  QgsApplication::init();
17✔
235

236
#ifdef MOBILE_OS
237
  // QGIS plugins on Android are in the same path as other libraries
238
  QgsApplication::setPluginPath( QApplication::applicationDirPath() );
239
  QgsApplication::setPkgDataPath( pkgPath );
240
#else
241
  Q_UNUSED( pkgPath )
17✔
242
#endif
243

244
  QgsApplication::initQgis();
17✔
245

246
  // make sure the DB exists - otherwise custom projections will be failing
247
  if ( !QgsApplication::createDatabase() )
17✔
248
    qDebug( "Can't create qgis user DB!!!" );
×
249

250
  qDebug( "qgis providers:\n%s", QgsProviderRegistry::instance()->pluginList().toLatin1().data() );
17✔
251
}
17✔
252

253
void initDeclarative()
×
254
{
255
  qmlRegisterUncreatableType<MerginUserAuth>( "lc", 1, 0, "MerginUserAuth", "" );
×
256
  qmlRegisterUncreatableType<MerginUserInfo>( "lc", 1, 0, "MerginUserInfo", "" );
×
257
  qmlRegisterUncreatableType<MerginSubscriptionInfo>( "lc", 1, 0, "MerginSubscriptionInfo", "" );
×
258
  qmlRegisterUncreatableType<PurchasingPlan>( "lc", 1, 0, "MerginPlan", "" );
×
259
  qmlRegisterUncreatableType<ActiveProject>( "lc", 1, 0, "ActiveProject", "" );
×
260
  qmlRegisterUncreatableType<SynchronizationManager>( "lc", 1, 0, "SynchronizationManager", "" );
×
261
  qmlRegisterUncreatableType<SynchronizationError>( "lc", 1, 0, "SyncError", "SyncError Enum" );
×
262
  qmlRegisterUncreatableType<AppSettings>( "lc", 1, 0, "AppSettings", "" );
×
263
  qmlRegisterUncreatableType<MerginApiStatus>( "lc", 1, 0, "MerginApiStatus", "MerginApiStatus Enum" );
×
264
  qmlRegisterUncreatableType<MerginServerType>( "lc", 1, 0, "MerginServerType", "MerginServerType Enum" );
×
265
  qmlRegisterUncreatableType<MerginSubscriptionStatus>( "lc", 1, 0, "MerginSubscriptionStatus", "MerginSubscriptionStatus Enum" );
×
266
  qmlRegisterUncreatableType<MerginSubscriptionType>( "lc", 1, 0, "MerginSubscriptionType", "MerginSubscriptionType Enum" );
×
267
  qmlRegisterUncreatableType<MerginProjectStatusModel>( "lc", 1, 0, "MerginProjectStatusModel", "Enum" );
×
268
  qmlRegisterUncreatableType<LayersModel>( "lc", 1, 0, "LayersModel", "" );
×
269
  qmlRegisterUncreatableType<LayersProxyModel>( "lc", 1, 0, "LayersProxyModel", "" );
×
270
  qmlRegisterUncreatableType<ActiveLayer>( "lc", 1, 0, "ActiveLayer", "" );
×
271
  qmlRegisterUncreatableType<StreamingIntervalType>( "lc", 1, 0, "StreamingIntervalType", "StreamingIntervalType Enum" );
×
272
  qmlRegisterType<PositionDirection>( "lc", 1, 0, "PositionDirection" );
×
273
  qmlRegisterType<Compass>( "lc", 1, 0, "Compass" );
×
274
  qmlRegisterType<FieldsModel>( "lc", 1, 0, "FieldsModel" );
×
275
  qmlRegisterType<CodeScanner>( "lc", 1, 0, "CodeScanner" );
×
276
  qmlRegisterType<ProjectsModel>( "lc", 1, 0, "ProjectsModel" );
×
277
  qmlRegisterType<ProjectsProxyModel>( "lc", 1, 0, "ProjectsProxyModel" );
×
278
  qmlRegisterType<AttributePreviewController>( "lc", 1, 0, "AttributePreviewController" );
×
279
  qmlRegisterType<WorkspacesModel>( "lc", 1, 0, "WorkspacesModel" );
×
280
  qmlRegisterType<WorkspacesProxyModel>( "lc", 1, 0, "WorkspacesProxyModel" );
×
281
  qmlRegisterType<InvitationsModel>( "lc", 1, 0, "InvitationsModel" );
×
282
  qmlRegisterType<InvitationsProxyModel>( "lc", 1, 0, "InvitationsProxyModel" );
×
283
  qmlRegisterUncreatableType<AttributePreviewModel>( "lc", 1, 0, "AttributePreviewModel", "" );
×
284
  qmlRegisterUncreatableMetaObject( ProjectStatus::staticMetaObject, "lc", 1, 0, "ProjectStatus", "ProjectStatus Enum" );
×
285
  qRegisterMetaType< FeatureLayerPair >( "FeatureLayerPair" );
×
286
  qRegisterMetaType< FeatureLayerPair * >( "FeatureLayerPair*" );
×
287
  qRegisterMetaType< AttributeController * >( "AttributeController*" );
×
288

289
  qRegisterMetaType< QList<QgsMapLayer *> >( "QList<QgsMapLayer*>" );
×
290
  qRegisterMetaType< QgsAttributes > ( "QgsAttributes" );
×
291
  qRegisterMetaType< QgsCoordinateReferenceSystem >( "QgsCoordinateReferenceSystem" );
×
292
  qRegisterMetaType< QgsCoordinateTransformContext >( "QgsCoordinateTransformContext" );
×
293
  qRegisterMetaType< QgsFeature > ( "QgsFeature" );
×
294
  qRegisterMetaType< QgsFeatureId > ( "QgsFeatureId" );
×
295
  qRegisterMetaType< QgsPoint >( "QgsPoint" );
×
296
  qRegisterMetaType< QgsLayerTreeNode * >( "QgsLayerTreeNode*" );
×
297
  qRegisterMetaType< QgsPointXY >( "QgsPointXY" );
×
298
  qRegisterMetaType< QgsRelation >( "QgsRelation" );
×
299
  qRegisterMetaType< QgsPolymorphicRelation >( "QgsPolymorphicRelation" );
×
300
  qRegisterMetaType< QgsUnitTypes::SystemOfMeasurement >( "QgsUnitTypes::SystemOfMeasurement" );
×
301
  qRegisterMetaType< QgsUnitTypes::DistanceUnit >( "QgsUnitTypes::DistanceUnit" );
×
302
  qRegisterMetaType< QgsCoordinateFormatter::FormatFlags >( "QgsCoordinateFormatter::FormatFlags" );
×
303
  qRegisterMetaType< QgsCoordinateFormatter::Format >( "QgsCoordinateFormatter::Format" );
×
304
  qRegisterMetaType< QVariant::Type >( "QVariant::Type" );
×
305
  qRegisterMetaType< QgsVertexId >( "QgsVertexId" );
×
306
  qmlRegisterAnonymousType<QAbstractItemModel>( "lc", 1 );
×
307

308
  qRegisterMetaType< Vertex >( "Vertex" );
×
309

310
  qmlRegisterUncreatableType< FormItem >( "lc", 1, 0, "FormItem", "Only enums from FormItem can be used" );
×
311
  qmlRegisterUncreatableType< AttributeFormModel >( "lc", 1, 0, "AttributeFormModel", "Created by AttributeController" );
×
312
  qmlRegisterUncreatableType< AttributeFormProxyModel >( "lc", 1, 0, "AttributeFormProxyModel", "Created by AttributeController" );
×
313
  qmlRegisterUncreatableType< AttributeTabModel >( "lc", 1, 0, "AttributeTabModel", "Created by AttributeController" );
×
314
  qmlRegisterUncreatableType< AttributeTabProxyModel >( "lc", 1, 0, "AttributeTabProxyModel", "Created by AttributeController" );
×
315
  qmlRegisterUncreatableType< FieldValidator >( "lc", 1, 0, "FieldValidator", "Only enums from FieldValidator can be used" );
×
316
  qmlRegisterType< AttributeController >( "lc", 1, 0, "AttributeController" );
×
317
  qmlRegisterType< RememberAttributesController >( "lc", 1, 0, "RememberAttributesController" );
×
318
  qmlRegisterType< IdentifyKit >( "lc", 1, 0, "IdentifyKit" );
×
319
  qmlRegisterType< PositionKit >( "lc", 1, 0, "PositionKit" );
×
320
  qmlRegisterType< MapPosition >( "lc", 1, 0, "MapPosition" );
×
321
  qmlRegisterType< ScaleBarKit >( "lc", 1, 0, "ScaleBarKit" );
×
322
  qmlRegisterType< SnapUtils >( "lc", 1, 0, "SnapUtils" );
×
323
  qmlRegisterType< LayerTreeModel >( "lc", 1, 0, "LayerTreeModel" );
×
324
  qmlRegisterType< LayerTreeSortFilterModel >( "lc", 1, 0, "LayerTreeSortFilterModel" );
×
325
  qmlRegisterType< LayerTreeFlatModel >( "lc", 1, 0, "LayerTreeFlatModel" );
×
326
  qmlRegisterType< LayerTreeFlatSortFilterModel >( "lc", 1, 0, "LayerTreeFlatSortFilterModel" );
×
327
  qmlRegisterType< LayerDetailData >( "lc", 1, 0, "LayerDetailData" );
×
328
  qmlRegisterType< MapThemesModel >( "lc", 1, 0, "MapThemesModel" );
×
329
  qmlRegisterType< GuidelineController >( "lc", 1, 0, "GuidelineController" );
×
330
  qmlRegisterType< FeaturesModel >( "lc", 1, 0, "FeaturesModel" );
×
331
  qmlRegisterType< RelationFeaturesModel >( "lc", 1, 0, "RelationFeaturesModel" );
×
332
  qmlRegisterType< ValueRelationFeaturesModel >( "lc", 1, 0, "ValueRelationFeaturesModel" );
×
333
  qmlRegisterType< RelationReferenceFeaturesModel >( "lc", 1, 0, "RelationReferenceFeaturesModel" );
×
334
  qmlRegisterType< BluetoothDiscoveryModel >( "lc", 1, 0, "BluetoothDiscoveryModel" );
×
335
  qmlRegisterType< PositionProvidersModel >( "lc", 1, 0, "PositionProvidersModel" );
×
336

337
  qmlRegisterUncreatableType< QgsUnitTypes >( "Input", 0, 1, "QgsUnitTypes", "Only enums from QgsUnitTypes can be used" );
×
338
  qmlRegisterType< QgsVectorLayer >( "Input", 0, 1, "VectorLayer" );
×
339
  qmlRegisterType< QgsProject >( "Input", 0, 1, "Project" );
×
340
  qmlRegisterType< InputMapCanvasMap >( "Input", 0, 1, "MapCanvasMap" );
×
341
  qmlRegisterType< InputMapSettings >( "Input", 0, 1, "MapSettings" );
×
342
  qmlRegisterType< InputMapTransform >( "Input", 0, 1, "MapTransform" );
×
343
  qmlRegisterType< InputCoordinateTransformer >( "Input", 0, 1, "CoordinateTransformer" );
×
344

345
  qmlRegisterUncreatableType< AbstractPositionProvider >( "lc", 1, 0, "PositionProvider", "Must be instantiated via its construct method" );
×
346

347
  // map tools
348
  qmlRegisterUncreatableType< AbstractMapTool >( "lc", 1, 0, "AbstractMapTool", "Instantiate one of child map tools instead" );
×
349
  qmlRegisterType< RecordingMapTool >( "lc", 1, 0, "RecordingMapTool" );
×
350
  qmlRegisterType< SplittingMapTool >( "lc", 1, 0, "SplittingMapTool" );
×
351
}
×
352

353
void addQmlImportPath( QQmlEngine &engine )
×
354
{
355
  // QML resources
356
  engine.addImportPath( ":/com.merginmaps/imports:" );
×
357

358
  // This adds a runtime qml directory containing Input plugin
359
  // when Input is installed (e.g. Android/Win32)
360
  engine.addImportPath( QgsApplication::qmlImportPath() );
×
361
  qDebug() << "adding QML import Path: " << QgsApplication::qmlImportPath();
×
362

363
#ifdef QML_BUILD_IMPORT_DIR
364
  // Adds a runtime qml directory containing Input plugin
365
  // if we are using the developer mode (not installed Input)
366
  // e.g. Linux/MacOS
367
  QString qmlBuildImportPath( STR( QML_BUILD_IMPORT_DIR ) );
368
  engine.addImportPath( qmlBuildImportPath );
369
  qDebug() << "adding QML import Path: " << qmlBuildImportPath;
370
#endif
371

372
#ifdef Q_OS_IOS
373
  // REQUIRED FOR IOS - to load Input/*.qml files defined in qmldir
374
  engine.addImportPath( "qrc:///" );
375
  qDebug() << "adding QML import Path: " << "qrc:///";
376
#endif
377
}
×
378

379
int main( int argc, char *argv[] )
17✔
380
{
381
  QgsApplication app( argc, argv, true );
17✔
382

383
  const QString version = CoreUtils::appVersion();
17✔
384

385
  // Set up the QSettings environment must be done after qapp is created
386
  QCoreApplication::setOrganizationName( "Lutra Consulting" );
17✔
387
  QCoreApplication::setOrganizationDomain( "lutraconsulting.co.uk" );
17✔
388
  QCoreApplication::setApplicationName( "Input" ); // used by QSettings
17✔
389
  QCoreApplication::setApplicationVersion( version );
17✔
390

391
#ifdef INPUT_TEST
392
  InputTests tests;
17✔
393
  tests.parseArgs( argc, argv );
17✔
394
#endif
395
  qDebug() << "Built with QGIS version " << VERSION_INT;
17✔
396

397
  // Set/Get enviroment
398
  QString dataDir = getDataDir();
17✔
399
  QString projectDir = dataDir + "/projects";
17✔
400

401
#ifdef INPUT_TEST
402
  if ( tests.testingRequested() )
17✔
403
  {
404
    projectDir = tests.initTestingDir();
17✔
405
  }
17✔
406
#endif
407

408
  QDir projectsDirectory( projectDir );
17✔
409
  if ( !projectsDirectory.exists() )
17✔
410
  {
411
    projectsDirectory.mkpath( projectDir );
×
412
  }
×
413

414
  CoreUtils::setLogFilename( projectDir + "/.logs" );
17✔
415
  setEnvironmentQgisPrefixPath();
17✔
416

417
  // Initialize translations
418
  QLocale locale;
17✔
419

420
  /*
421
   * We need to fix locale country code (capital letters after underscore)
422
   * in system locale, because QT tries to do exact match, for example:
423
   * system locale "en_GB" -> our provided locale "en" would not match and
424
   * QT would try to find translation for other system language.
425
   *
426
   * If it fails it goes through the same process again, but without country code.
427
   * We want to match "en_GB" with "en" immediately, thus we remove the country code.
428
   *
429
   * This fix can be removed from QT 5.15
430
   * See: https://github.com/MerginMaps/input/issues/1417
431
   * See: QTBUG-86179
432
   */
433
  locale = InputUtils::fixLocaleCountry( locale );
17✔
434

435
  QTranslator inputTranslator;
17✔
436
  if ( inputTranslator.load( locale, "input", "_", ":/" ) )
17✔
437
  {
438
    app.installTranslator( &inputTranslator );
17✔
439
    qDebug() <<  "Loaded input translation" << app.locale() << "for" << locale;
17✔
440
  }
17✔
441
  else
442
  {
443
    qDebug() <<  "Error in loading input translation for " << locale;
×
444
  }
445

446
  QString appBundleDir;
17✔
447
  QString demoDir;
17✔
448
#ifdef ANDROID
449
  appBundleDir = dataDir + "/qgis-data";
450
  demoDir = "assets:/demo-projects";
451
#endif
452
#ifdef Q_OS_IOS
453
  appBundleDir = QCoreApplication::applicationDirPath() + "/qgis-data";
454
  demoDir = QCoreApplication::applicationDirPath() + "/demo-projects";
455
#endif
456
#ifdef Q_OS_WIN32
457
  appBundleDir = QCoreApplication::applicationDirPath() + "\\qgis-data";
458
  //TODO win32 package demo projects
459
#endif
460
#ifdef Q_OS_LINUX
461
  appBundleDir = dataDir;
462
#endif
463
#ifdef Q_OS_MACOS
464
  appBundleDir = dataDir;
17✔
465
#endif
466
  InputProjUtils inputProjUtils;
17✔
467
  inputProjUtils.initProjLib( appBundleDir, dataDir, projectDir );
17✔
468
  init_qgis( appBundleDir );
17✔
469

470
  // AppSettings has to be initialized after QGIS app init (because of correct reading/writing QSettings).
471
  AppSettings as;
17✔
472
  bool hasLoadedDemoProjects = false;
17✔
473

474
  // copy demo projects when the app is launched for the first time
475
  if ( !as.demoProjectsCopied() )
17✔
476
  {
477
    copy_demo_projects( demoDir, projectDir );
1✔
478
    as.setDemoProjectsCopied( true );
1✔
479
    hasLoadedDemoProjects = true;
1✔
480
  }
1✔
481

482
  // there seem to be issues with HTTP/2 server support (QTBUG-111417)
483
  // so let's stick to HTTP/1 for the time being (Qt5 has HTTP/2 disabled by default)
484
  QgsNetworkAccessManager::instance()->setRequestPreprocessor( []( QNetworkRequest * r )
17✔
485
  {
486
    r->setAttribute( QNetworkRequest::Http2AllowedAttribute, false );
×
487
  } );
×
488

489
  // Create Input classes
490
  GeodiffUtils::init();
17✔
491
  AndroidUtils au;
17✔
492
  IosUtils iosUtils;
17✔
493
  LocalProjectsManager localProjectsManager( projectDir );
17✔
494
  std::unique_ptr<MerginApi> ma =  std::unique_ptr<MerginApi>( new MerginApi( localProjectsManager ) );
17✔
495
  InputUtils iu( &au );
17✔
496
  MerginProjectStatusModel mpsm( localProjectsManager );
17✔
497
  InputHelp help( ma.get(), &iu );
17✔
498
  ProjectWizard pw( projectDir );
17✔
499

500
  // layer models
501
  LayersModel lm;
17✔
502
  LayersProxyModel recordingLpm( &lm, LayerModelTypes::ActiveLayerSelection );
17✔
503

504
  ActiveLayer al;
17✔
505
  ActiveProject activeProject( as, al, recordingLpm, localProjectsManager );
17✔
506
  std::unique_ptr<Purchasing> purchasing( new Purchasing( ma.get() ) );
17✔
507
  std::unique_ptr<VariablesManager> vm( new VariablesManager( ma.get() ) );
17✔
508
  vm->registerInputExpressionFunctions();
17✔
509

510
  SynchronizationManager syncManager( ma.get() );
17✔
511

512
  LayerTreeModelPixmapProvider *layerTreeModelPixmapProvider( new LayerTreeModelPixmapProvider );
17✔
513
  LayerTreeFlatModelPixmapProvider *layerTreeFlatModelPixmapProvider( new LayerTreeFlatModelPixmapProvider );
17✔
514
  LayerDetailLegendImageProvider *layerDetailLegendImageProvider( new LayerDetailLegendImageProvider );
17✔
515

516
  // build position kit, save active provider to QSettings and load previously active provider
517
  PositionKit pk;
17✔
518
  QObject::connect( &pk, &PositionKit::positionProviderChanged, &as, [&as]( AbstractPositionProvider * provider )
51✔
519
  {
520
    as.setActivePositionProviderId( provider ? provider->id() : QLatin1String() );
34✔
521
  } );
34✔
522
  pk.setPositionProvider( pk.constructActiveProvider( &as ) );
17✔
523
  pk.setAppSettings( &as );
17✔
524

525
  // Lambda context object can be used in all lambda functions defined here,
526
  // it secures lambdas, so that they are destroyed when this object is destroyed to avoid crashes.
527
  QObject lambdaContext;
17✔
528

529
  QObject::connect( &app, &QGuiApplication::applicationStateChanged, &lambdaContext, []( Qt::ApplicationState state )
22✔
530
  {
531
    QString msg;
5✔
532

533
    // Instatiate QDebug with QString to redirect output to string
534
    // It is used to convert enum to string
535
    QDebug logHelper( &msg );
5✔
536

537
    logHelper << QStringLiteral( "Application changed state to:" ) << state;
5✔
538
    CoreUtils::log( QStringLiteral( "Input" ), msg );
5✔
539
  } );
5✔
540

541
  QObject::connect( &app, &QCoreApplication::aboutToQuit, &lambdaContext, []()
17✔
542
  {
543
    CoreUtils::log( QStringLiteral( "Input" ), QStringLiteral( "Application has quit" ) );
×
544
  } );
×
545

546
  QObject::connect( &activeProject, &ActiveProject::syncActiveProject, &syncManager, [&syncManager]( const LocalProject & project )
17✔
547
  {
548
    syncManager.syncProject( project, SyncOptions::Authorized, SyncOptions::Retry );
×
549
  } );
×
550

551
  // Direct connections
552
  QObject::connect( &app, &QGuiApplication::applicationStateChanged, &pk, &PositionKit::appStateChanged );
17✔
553
  QObject::connect( &pw, &ProjectWizard::projectCreated, &localProjectsManager, &LocalProjectsManager::addLocalProject );
17✔
554
  QObject::connect( &activeProject, &ActiveProject::projectReloaded, vm.get(), &VariablesManager::merginProjectChanged );
17✔
555
  QObject::connect( &activeProject, &ActiveProject::projectWillBeReloaded, &inputProjUtils, &InputProjUtils::resetHandlers );
17✔
556
  QObject::connect( &pw, &ProjectWizard::notify, &iu, &InputUtils::showNotificationRequested );
17✔
557
  QObject::connect( &iosUtils, &IosUtils::showToast, &iu, &InputUtils::showNotificationRequested );
17✔
558
  QObject::connect( &syncManager, &SynchronizationManager::syncFinished, &activeProject, [&activeProject]( const QString & projectFullName, bool successfully, int version, bool reloadNeeded )
126✔
559
  {
560
    Q_UNUSED( successfully );
561
    Q_UNUSED( version );
562
    if ( reloadNeeded && activeProject.projectFullName() == projectFullName )
109✔
563
    {
564
      activeProject.reloadProject( activeProject.qgsProject()->homePath() );
×
565
    }
×
566
  } );
109✔
567
  QObject::connect( QgsApplication::messageLog(),
17✔
568
                    static_cast<void ( QgsMessageLog::* )( const QString &message, const QString &tag, Qgis::MessageLevel level )>( &QgsMessageLog::messageReceived ),
569
                    &iu,
570
                    &InputUtils::onQgsLogMessageReceived );
571

572
  QFile projectLoadingFile( ActiveProject::LOADING_FLAG_FILE_PATH );
17✔
573
  if ( projectLoadingFile.exists() )
17✔
574
  {
575
    // Cleaning default project due to a project loading has crashed during the last run.
576
    as.setDefaultProject( QString() );
×
577
    projectLoadingFile.remove();
×
578
    CoreUtils::log( QStringLiteral( "Loading project error" ), QStringLiteral( "The Input has been unexpectedly finished during the last run." ) );
×
579
  }
×
580

581
#ifdef INPUT_TEST
582
  if ( tests.testingRequested() )
17✔
583
  {
584
    tests.initTestDeclarative();
17✔
585
    tests.init( ma.get(), purchasing.get(), &iu, vm.get(), &pk, &as );
17✔
586
    return tests.runTest();
17✔
587
  }
588
#endif
589

590
  // we ship our fonts because they do not need to be installed on the target platform
591
  QStringList fonts;
×
592
  fonts << ":/Lato-Regular.ttf"
×
593
        << ":/Lato-Bold.ttf";
×
594
  for ( QString font : fonts )
×
595
  {
596
    if ( QFontDatabase::addApplicationFont( font ) == -1 )
×
597
      qDebug() << "!! Failed to load font" << font;
×
598
    else
599
      qDebug() << "Loaded font" << font;
×
600
  }
×
601
  app.setFont( QFont( "Lato" ) );
×
602

603
  QQuickStyle::setStyle( "Basic" );
×
604
  QQmlEngine engine;
×
605
  addQmlImportPath( engine );
×
606

607
  initDeclarative();
×
608
  // QGIS environment variables to set
609
  // OGR_SQLITE_JOURNAL is set to DELETE to avoid working with WAL files
610
  // and properly close connection after writting changes to gpkg.
611
  qputenv( "OGR_SQLITE_JOURNAL", "DELETE" );
×
612

613
  // Register to QQmlEngine
614
  engine.rootContext()->setContextProperty( "__androidUtils", &au );
×
615
  engine.rootContext()->setContextProperty( "__iosUtils", &iosUtils );
×
616
  engine.rootContext()->setContextProperty( "__inputUtils", &iu );
×
617
  engine.rootContext()->setContextProperty( "__inputProjUtils", &inputProjUtils );
×
618
  engine.rootContext()->setContextProperty( "__inputHelp", &help );
×
619
  engine.rootContext()->setContextProperty( "__activeProject", &activeProject );
×
620
  engine.rootContext()->setContextProperty( "__syncManager", &syncManager );
×
621
  engine.rootContext()->setContextProperty( "__appSettings", &as );
×
622
  engine.rootContext()->setContextProperty( "__merginApi", ma.get() );
×
623
  engine.rootContext()->setContextProperty( "__merginProjectStatusModel", &mpsm );
×
624
  engine.rootContext()->setContextProperty( "__recordingLayersModel", &recordingLpm );
×
625
  engine.rootContext()->setContextProperty( "__activeLayer", &al );
×
626
  engine.rootContext()->setContextProperty( "__purchasing", purchasing.get() );
×
627
  engine.rootContext()->setContextProperty( "__projectWizard", &pw );
×
628
  engine.rootContext()->setContextProperty( "__localProjectsManager", &localProjectsManager );
×
629
  engine.rootContext()->setContextProperty( "__variablesManager", vm.get() );
×
630
  engine.rootContext()->setContextProperty( "__positionKit", &pk );
×
631

632
  // add image provider to pass QIcons/QImages from C++ to QML
633
  engine.rootContext()->setContextProperty( "__layerTreeModelPixmapProvider", layerTreeModelPixmapProvider );
×
634
  engine.addImageProvider( QLatin1String( "LayerTreeModelPixmapProvider" ), layerTreeModelPixmapProvider );
×
635
  engine.rootContext()->setContextProperty( "__layerTreeFlatModelPixmapProvider", layerTreeFlatModelPixmapProvider );
×
636
  engine.addImageProvider( QLatin1String( "LayerTreeFlatModelPixmapProvider" ), layerTreeFlatModelPixmapProvider );
×
637
  engine.rootContext()->setContextProperty( "__layerDetailLegendImageProvider", layerDetailLegendImageProvider );
×
638
  engine.addImageProvider( QLatin1String( "LayerDetailLegendImageProvider" ), layerDetailLegendImageProvider );
×
639

640
#ifdef HAVE_BLUETOOTH
641
  engine.rootContext()->setContextProperty( "__haveBluetooth", true );
×
642
#else
643
  engine.rootContext()->setContextProperty( "__haveBluetooth", false );
644
#endif
645

646
#ifdef MOBILE_OS
647
  engine.rootContext()->setContextProperty( "__appwindowvisibility", QWindow::Maximized );
648
  engine.rootContext()->setContextProperty( "__appwindowwidth", QVariant( 0 ) );
649
  engine.rootContext()->setContextProperty( "__appwindowheight", QVariant( 0 ) );
650
#else
651
  engine.rootContext()->setContextProperty( "__appwindowvisibility", QWindow::Windowed );
×
652
  engine.rootContext()->setContextProperty( "__appwindowwidth", 640 );
×
653
  engine.rootContext()->setContextProperty( "__appwindowheight", 1136 );
×
654
#endif
655
  engine.rootContext()->setContextProperty( "__version", version );
×
656

657
  // Even though enabling QT's HighDPI scaling removes the need to multiply pixel values with dp,
658
  // there are screens that need a "little help", because system DPR has different value than the
659
  // one we calculated. In these scenarios we use a ratio between real (our) DPR and DPR reported by QT.
660
  // Use `value * __dp` for each pixel value in QML
661
  engine.rootContext()->setContextProperty( "__dp", InputUtils::calculateDpRatio() );
×
662

663
// due to https://bugreports.qt.io/browse/QTBUG-113751, the right DPI is set when app is created (after this pool)
664
#if (defined ANDROID && QT_VERSION >= QT_VERSION_CHECK(6, 5, 0) )
665
  QTimer::singleShot( 100, [&engine]() { engine.rootContext()->setContextProperty( "__dp", InputUtils::calculateDpRatio() );} );
666
#endif
667

17✔
668
  // Set simulated position for desktop builds
669
#ifdef DESKTOP_OS
670
  bool use_simulated_position = true;
×
671
#else
672
  bool use_simulated_position = false;
673
#endif
674
  engine.rootContext()->setContextProperty( "__use_simulated_position", use_simulated_position );
×
675

676
  QQmlComponent component( &engine, QUrl( "qrc:/com.merginmaps/imports/MMInput/main.qml" ) );
×
677
  QObject *object = component.create();
×
678

679
  if ( !component.errors().isEmpty() )
×
680
  {
681
    qDebug( "%s", QgsApplication::showSettings().toLocal8Bit().data() );
×
682

683
    qDebug() << "****************************************";
×
684
    qDebug() << "*****        QML errors:           *****";
×
685
    qDebug() << "****************************************";
×
686
    for ( const QQmlError &error : component.errors() )
×
687
    {
688
      qDebug() << "  " << error;
×
689
    }
690
    qDebug() << "****************************************";
×
691
    qDebug() << "****************************************";
×
692
  }
×
693

694
  if ( object == nullptr )
×
695
  {
696
    qDebug() << "FATAL ERROR: unable to create main.qml";
×
697
    return EXIT_FAILURE;
×
698
  }
699

700
#ifdef Q_OS_IOS
701
  QString logoUrl = "qrc:logo.png";
702
#else
703
  QString logoUrl = ":/logo.png";
×
704
#endif
705
  if ( QQuickWindow *quickWindow = qobject_cast<QQuickWindow *>( object ) )
×
706
  {
707
    quickWindow->setIcon( QIcon( logoUrl ) );
×
708
  }
×
709

710
#ifdef DESKTOP_OS
711
  QCommandLineParser parser;
×
712
  parser.addVersionOption();
×
713
  parser.process( app );
×
714
#endif
715

716
  // Add some data for debugging
717
  qDebug() << iu.dumpScreenInfo();
×
718
  qDebug() << "data directory: " << dataDir;
×
719
  qDebug() <<  "All up and running";
×
720

721
#ifdef ANDROID
722
  QNativeInterface::QAndroidApplication::hideSplashScreen();
723
#endif
724

725
  // save app version to settings
726
  as.setAppVersion( version );
×
727

728
  // Photos bigger that 512 MB (when uncompressed) will not load
729
  QImageReader::setAllocationLimit( 512 );
×
730

731
  int ret = EXIT_FAILURE;
×
732
  try
733
  {
734
    ret = app.exec();
×
735
  }
×
736
  catch ( QgsException &e )
737
  {
738
    CoreUtils::log( "Error", QStringLiteral( "Caught unhandled QgsException %1" ).arg( e.what() ) );
×
739
  }
×
740
  catch ( std::exception &e )
741
  {
742
    CoreUtils::log( "Error", QStringLiteral( "Caught unhandled std::exception %1" ).arg( e.what() ) );
×
743
  }
×
744
  catch ( ... )
745
  {
746
    CoreUtils::log( "Error", QStringLiteral( "Caught unhandled unknown exception" ) );
×
747
  }
×
748
  return ret;
×
749
}
17✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc