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

MerginMaps / input / 6572455714

19 Oct 2023 09:16AM UTC coverage: 62.301% (-0.009%) from 62.31%
6572455714

Pull #2852

github

iiLubos
Added MMMapLabel for labels on map
Pull Request #2852: Try to design map items

7688 of 12340 relevant lines covered (62.3%)

104.91 hits per line

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

65.37
/app/projectsmodel.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 "projectsmodel.h"
11
#include "localprojectsmanager.h"
12
#include "inpututils.h"
13
#include "merginuserauth.h"
14
#include "coreutils.h"
15

16

17
ProjectsModel::ProjectsModel( QObject *parent ) : QAbstractListModel( parent )
2✔
18
{
19
  connect( this, &ProjectsModel::merginApiChanged, this, &ProjectsModel::initializeProjectsModel );
2✔
20
  connect( this, &ProjectsModel::modelTypeChanged, this, &ProjectsModel::initializeProjectsModel );
2✔
21
  connect( this, &ProjectsModel::syncManagerChanged, this, &ProjectsModel::initializeProjectsModel );
2✔
22
  connect( this, &ProjectsModel::localProjectsManagerChanged, this, &ProjectsModel::initializeProjectsModel );
2✔
23
}
2✔
24

25
void ProjectsModel::initializeProjectsModel()
8✔
26
{
27
  if ( !mSyncManager || !mBackend || !mLocalProjectsManager || mModelType == EmptyProjectsModel ) // Model is not set up properly yet
8✔
28
    return;
6✔
29

30
  QObject::connect( mSyncManager, &SynchronizationManager::syncStarted, this, &ProjectsModel::onProjectSyncStarted );
2✔
31
  QObject::connect( mSyncManager, &SynchronizationManager::syncFinished, this, &ProjectsModel::onProjectSyncFinished );
2✔
32
  QObject::connect( mSyncManager, &SynchronizationManager::syncCancelled, this, &ProjectsModel::onProjectSyncCancelled );
2✔
33
  QObject::connect( mSyncManager, &SynchronizationManager::syncProgressChanged, this, &ProjectsModel::onProjectSyncProgressChanged );
2✔
34

35
  QObject::connect( mBackend, &MerginApi::projectDetached, this, &ProjectsModel::onProjectDetachedFromMergin );
2✔
36
  QObject::connect( mBackend, &MerginApi::projectAttachedToMergin, this, &ProjectsModel::onProjectAttachedToMergin );
2✔
37
  QObject::connect( mBackend, &MerginApi::authChanged, this, &ProjectsModel::onAuthChanged );
2✔
38

39
  if ( mModelType == ProjectModelTypes::LocalProjectsModel )
2✔
40
  {
41
    QObject::connect( mBackend, &MerginApi::listProjectsByNameFinished, this, &ProjectsModel::onListProjectsByNameFinished );
1✔
42
    loadLocalProjects();
1✔
43
  }
44
  else if ( mModelType != ProjectModelTypes::RecentProjectsModel )
1✔
45
  {
46
    QObject::connect( mBackend, &MerginApi::listProjectsFinished, this, &ProjectsModel::onListProjectsFinished );
1✔
47
  }
48
  else
49
  {
50
    // Implement RecentProjectsModel type
51
  }
52

53
  QObject::connect( mLocalProjectsManager, &LocalProjectsManager::localProjectAdded, this, &ProjectsModel::onProjectAdded );
2✔
54
  QObject::connect( mLocalProjectsManager, &LocalProjectsManager::aboutToRemoveLocalProject, this, &ProjectsModel::onAboutToRemoveProject );
2✔
55
  QObject::connect( mLocalProjectsManager, &LocalProjectsManager::localProjectDataChanged, this, &ProjectsModel::onProjectDataChanged );
2✔
56
  QObject::connect( mLocalProjectsManager, &LocalProjectsManager::dataDirReloaded, this, &ProjectsModel::loadLocalProjects );
2✔
57

58
  emit modelInitialized();
2✔
59
}
60

61
QVariant ProjectsModel::data( const QModelIndex &index, int role ) const
×
62
{
63
  if ( !index.isValid() )
×
64
    return QVariant();
×
65

66
  if ( index.row() < 0 || index.row() >= mProjects.size() )
×
67
    return QVariant();
×
68

69
  const Project project = mProjects.at( index.row() );
×
70

71
  switch ( role )
×
72
  {
73
    case ProjectName: return QVariant( project.projectName() );
×
74
    case ProjectNamespace: return QVariant( project.projectNamespace() );
×
75
    case ProjectFullName: return QVariant( project.fullName() );
×
76
    case ProjectId: return QVariant( project.id() );
×
77
    case ProjectIsLocal: return QVariant( project.isLocal() );
×
78
    case ProjectIsMergin: return QVariant( project.isMergin() );
×
79
    case ProjectStatus: return QVariant( project.isMergin() ? project.mergin.status : ProjectStatus::NoVersion );
×
80
    case ProjectFilePath: return QVariant( project.isLocal() ? project.local.qgisProjectFilePath : QString() );
×
81
    case ProjectDirectory: return QVariant( project.isLocal() ? project.local.projectDir : QString() );
×
82
    case ProjectIsValid:
×
83
    {
84
      if ( !project.isLocal() )
×
85
        return true; // Mergin projects are by default valid, remote error only affects syncing, not opening of a project
×
86
      return project.local.projectError.isEmpty();
×
87
    }
88
    case ProjectDescription:
×
89
    {
90
      if ( project.isLocal() )
×
91
      {
92
        if ( !project.local.projectError.isEmpty() )
×
93
        {
94
          return QVariant( project.local.projectError );
×
95
        }
96
        QFileInfo fi( project.local.projectDir );
×
97
        // lastModified of projectDir is not reliable - gpkg file may have modified header after opening it. See more #1320
98
        return QVariant( tr( "Updated %1" ).arg( InputUtils::formatDateTimeDiff( fi.lastModified().toUTC() ) ) );
×
99
      }
×
100
      else if ( project.isMergin() )
×
101
      {
102
        return QVariant( tr( "Updated %1" ).arg( InputUtils::formatDateTimeDiff( project.mergin.serverUpdated.toUTC() ) ) );
×
103
      }
104

105
      // This should not happen
106
      CoreUtils::log( "Project error", "Found project that is not downloaded nor remote" );
×
107
      return QVariant();
×
108
    }
109
    default:
×
110
    {
111
      if ( !project.isMergin() ) return QVariant();
×
112

113
      // Roles only for projects that has mergin part
114
      if ( role == ProjectSyncPending ) return QVariant( mSyncManager->hasPendingSync( project.fullName() ) );
×
115
      else if ( role == ProjectSyncProgress ) return QVariant( mSyncManager->syncProgress( project.fullName() ) );
×
116
      else if ( role == ProjectRemoteError ) return QVariant( project.mergin.remoteError );
×
117
      return QVariant();
×
118
    }
119
  }
120
}
×
121

122
QModelIndex ProjectsModel::index( int row, int col, const QModelIndex &parent ) const
326✔
123
{
124
  Q_UNUSED( col )
125
  Q_UNUSED( parent )
126
  return createIndex( row, 0, nullptr );
326✔
127
}
128

129
QHash<int, QByteArray> ProjectsModel::roleNames() const
×
130
{
131
  QHash<int, QByteArray> roles;
×
132
  roles[Roles::ProjectName]         = QStringLiteral( "ProjectName" ).toLatin1();
×
133
  roles[Roles::ProjectNamespace]    = QStringLiteral( "ProjectNamespace" ).toLatin1();
×
134
  roles[Roles::ProjectFullName]     = QStringLiteral( "ProjectFullName" ).toLatin1();
×
135
  roles[Roles::ProjectId]           = QStringLiteral( "ProjectId" ).toLatin1();
×
136
  roles[Roles::ProjectDirectory]    = QStringLiteral( "ProjectDirectory" ).toLatin1();
×
137
  roles[Roles::ProjectIsLocal]      = QStringLiteral( "ProjectIsLocal" ).toLatin1();
×
138
  roles[Roles::ProjectIsMergin]     = QStringLiteral( "ProjectIsMergin" ).toLatin1();
×
139
  roles[Roles::ProjectStatus]       = QStringLiteral( "ProjectStatus" ).toLatin1();
×
140
  roles[Roles::ProjectIsValid]      = QStringLiteral( "ProjectIsValid" ).toLatin1();
×
141
  roles[Roles::ProjectFilePath]     = QStringLiteral( "ProjectFilePath" ).toLatin1();
×
142
  roles[Roles::ProjectDescription]  = QStringLiteral( "ProjectDescription" ).toLatin1();
×
143
  roles[Roles::ProjectSyncPending]  = QStringLiteral( "ProjectSyncPending" ).toLatin1();
×
144
  roles[Roles::ProjectSyncProgress] = QStringLiteral( "ProjectSyncProgress" ).toLatin1();
×
145
  roles[Roles::ProjectRemoteError]  = QStringLiteral( "ProjectRemoteError" ).toLatin1();
×
146
  return roles;
×
147
}
×
148

149
int ProjectsModel::rowCount( const QModelIndex & ) const
47✔
150
{
151
  return mProjects.count();
47✔
152
}
153

154
void ProjectsModel::listProjects( const QString &searchExpression, int page )
15✔
155
{
156
  if ( mModelType == LocalProjectsModel )
15✔
157
  {
158
    listProjectsByName();
3✔
159
    return;
3✔
160
  }
161

162
  mLastRequestId = mBackend->listProjects( searchExpression, modelTypeToFlag(), page );
12✔
163

164
  if ( !mLastRequestId.isEmpty() )
12✔
165
  {
166
    setModelIsLoading( true );
12✔
167
    // clear only after requesting the very first page, otherwise we want to append results to the model
168
    if ( page == 1 )
12✔
169
      clearProjects();
12✔
170
  }
171
}
172

173
void ProjectsModel::listProjectsByName()
9✔
174
{
175
  if ( mModelType != LocalProjectsModel )
9✔
176
  {
177
    return;
3✔
178
  }
179

180
  mLastRequestId = mBackend->listProjectsByName( projectNames() );
6✔
181

182
  if ( !mLastRequestId.isEmpty() )
6✔
183
  {
184
    setModelIsLoading( true );
6✔
185
    clearProjects();
6✔
186
  }
187
}
188

189
bool ProjectsModel::hasMoreProjects() const
×
190
{
191
  return ( mProjects.size() < mServerProjectsCount );
×
192
}
193

194
void ProjectsModel::fetchAnotherPage( const QString &searchExpression )
×
195
{
196
  listProjects( searchExpression, mPaginatedPage + 1 );
×
197
}
×
198

199
void ProjectsModel::onListProjectsFinished( const MerginProjectsList &merginProjects, int projectsCount, int page, QString requestId )
22✔
200
{
201
  if ( mLastRequestId != requestId )
22✔
202
  {
203
    return;
10✔
204
  }
205

206
  if ( page == 1 )
12✔
207
  {
208
    // if we are populating first page, reset model and throw away previous projects
209
    beginResetModel();
12✔
210
    mergeProjects( merginProjects, MergeStrategy::DiscardPrevious );
12✔
211
    endResetModel();
12✔
212
  }
213
  else
214
  {
215
    // paginating next page, keep previous projects and emit model add items
216
    beginInsertRows( QModelIndex(), mProjects.size(), mProjects.size() + merginProjects.size() - 1 );
×
217
    mergeProjects( merginProjects, MergeStrategy::KeepPrevious );
×
218
    endInsertRows();
×
219
  }
220

221
  mServerProjectsCount = projectsCount;
12✔
222
  mPaginatedPage = page;
12✔
223
  emit hasMoreProjectsChanged();
12✔
224
  setModelIsLoading( false );
12✔
225
}
226

227
void ProjectsModel::onListProjectsByNameFinished( const MerginProjectsList &merginProjects, QString requestId )
7✔
228
{
229
  if ( mLastRequestId != requestId )
7✔
230
  {
231
    return;
1✔
232
  }
233

234
  beginResetModel();
6✔
235
  mergeProjects( merginProjects );
6✔
236
  endResetModel();
6✔
237

238
  setModelIsLoading( false );
6✔
239
}
240

241
void ProjectsModel::mergeProjects( const MerginProjectsList &merginProjects, MergeStrategy mergeStrategy )
22✔
242
{
243
  const LocalProjectsList localProjects = mLocalProjectsManager->projects();
22✔
244

245
  if ( mergeStrategy == DiscardPrevious )
22✔
246
  {
247
    mProjects.clear();
22✔
248
  }
249

250
  if ( mModelType == ProjectModelTypes::LocalProjectsModel )
22✔
251
  {
252
    // Keep all local projects and ignore all not downloaded remote projects
253
    for ( const LocalProject &localProject : localProjects )
198✔
254
    {
255
      Project project;
188✔
256
      project.local = localProject;
188✔
257

258
      const auto res = std::find_if( merginProjects.begin(), merginProjects.end(), [&project]( const MerginProject & me )
188✔
259
      {
260
        return ( project.id() == me.id() );
1,591✔
261
      } );
262

263
      if ( res != merginProjects.end() )
188✔
264
      {
265
        project.mergin = *res;
111✔
266
        project.mergin.status = ProjectStatus::projectStatus( project );
111✔
267
      }
268
      else if ( project.local.hasMerginMetadata() )
77✔
269
      {
270
        // App is starting - loads all local projects from a device
271
        // OR
272
        // We do not have server info because the project was ignored
273
        // (listProjectsByName API limits response to max 50 projects)
274
        project.mergin.projectName = project.local.projectName;
72✔
275
        project.mergin.projectNamespace = project.local.projectNamespace;
72✔
276
        project.mergin.status = ProjectStatus::projectStatus( project );
72✔
277
      }
278

279
      mProjects << project;
188✔
280
    }
188✔
281

282
    // lets check also for projects that are currently being downloaded and add them to local projects list
283
    QList<QString> pendingProjects = mSyncManager->pendingProjects();
10✔
284

285
    for ( const QString &pendingProjectName : pendingProjects )
11✔
286
    {
287
      const auto &match = std::find_if( mProjects.begin(), mProjects.end(), [&pendingProjectName]( const Project & mp )
1✔
288
      {
289
        return ( mp.id() == pendingProjectName );
12✔
290
      } );
1✔
291

292
      bool alreadyIncluded = match != mProjects.end();
1✔
293
      if ( !alreadyIncluded )
1✔
294
      {
295
        Project project;
×
296

297
        MerginApi::extractProjectName( pendingProjectName, project.mergin.projectNamespace, project.mergin.projectName );
×
298
        project.mergin.status = ProjectStatus::projectStatus( project );
×
299

300
        mProjects << project;
×
301
      }
×
302
    }
303
  }
10✔
304
  else if ( mModelType != ProjectModelTypes::RecentProjectsModel )
12✔
305
  {
306
    // Keep all remote projects and ignore all non mergin projects from local projects
307
    for ( const auto &remoteEntry : merginProjects )
141✔
308
    {
309
      Project project;
129✔
310
      project.mergin = remoteEntry;
129✔
311

312
      const auto match = std::find_if( localProjects.begin(), localProjects.end(), [&project]( const LocalProject & le )
129✔
313
      {
314
        return ( project.id() == le.id() );
720✔
315
      } );
316

317
      if ( match != localProjects.end() )
129✔
318
      {
319
        project.local = *match;
85✔
320
      }
321
      project.mergin.status = ProjectStatus::projectStatus( project );
129✔
322

323
      mProjects << project;
129✔
324
    }
129✔
325
  }
326
}
22✔
327

328
void ProjectsModel::syncProject( const QString &projectId )
×
329
{
330
  int ix = projectIndexFromId( projectId );
×
331

332
  if ( ix < 0 )
×
333
    return;
×
334

335
  if ( mSyncManager )
×
336
  {
337
    if ( mModelType == ProjectModelTypes::PublicProjectsModel )
×
338
    {
339
      mSyncManager->syncProject( mProjects[ix], SyncOptions::AuthOptional );
×
340
    }
341
    else
342
    {
343
      mSyncManager->syncProject( mProjects[ix] );
×
344
    }
345
  }
346
}
347

348
void ProjectsModel::stopProjectSync( const QString &projectId )
×
349
{
350
  if ( mSyncManager )
×
351
  {
352
    mSyncManager->stopProjectSync( projectId );
×
353
  }
354
}
×
355

356
void ProjectsModel::removeLocalProject( const QString &projectId )
×
357
{
358
  mLocalProjectsManager->removeLocalProject( projectId );
×
359
}
×
360

361
void ProjectsModel::migrateProject( const QString &projectId )
×
362
{
363
  int ix = projectIndexFromId( projectId );
×
364

365
  if ( ix < 0 )
×
366
    return;
×
367

368
  mSyncManager->migrateProjectToMergin( mProjects[ix].local.projectName );
×
369
}
370

371
void ProjectsModel::onProjectSyncStarted( const QString &projectFullName )
218✔
372
{
373
  int ix = projectIndexFromId( projectFullName );
218✔
374

375
  if ( ix < 0 )
218✔
376
    return;
134✔
377

378
  QModelIndex changeIndex = index( ix );
84✔
379
  emit dataChanged( changeIndex, changeIndex, { ProjectSyncPending, ProjectSyncProgress } );
84✔
380
}
381

382
void ProjectsModel::onProjectSyncCancelled( const QString &projectFullName )
×
383
{
384
  int ix = projectIndexFromId( projectFullName );
×
385

386
  if ( ix < 0 )
×
387
    return;
×
388

389
  QModelIndex changeIndex = index( ix );
×
390
  emit dataChanged( changeIndex, changeIndex, { ProjectSyncPending, ProjectSyncProgress, ProjectStatus } );
×
391
}
392

393
void ProjectsModel::onProjectSyncFinished( const QString &projectFullName, bool successfully, int newVersion )
218✔
394
{
395
  int ix = projectIndexFromId( projectFullName );
218✔
396

397
  if ( ix < 0 )
218✔
398
    return;
197✔
399

400
  if ( !mProjects[ix].isMergin() )
121✔
401
    return;
100✔
402

403
  Project &project = mProjects[ix];
21✔
404

405
  if ( successfully )
21✔
406
  {
407
    project.mergin.serverVersion = newVersion;
21✔
408
  }
409

410
  project.mergin.status = ProjectStatus::projectStatus( project );
21✔
411

412
  QModelIndex changeIndex = index( ix );
21✔
413
  emit dataChanged( changeIndex, changeIndex, { ProjectSyncPending, ProjectSyncProgress, ProjectStatus } );
21✔
414

415
  // remove project from list of projects if this was a first-time download of remote project in local projects list
416
  if ( !successfully && mModelType == LocalProjectsModel )
21✔
417
  {
418
    if ( !project.isLocal() )
×
419
    {
420
      beginRemoveRows( QModelIndex(), ix, ix );
×
421
      mProjects.removeAt( ix );
×
422
      endRemoveRows();
×
423
    }
424
  }
425
}
426

427
void ProjectsModel::onProjectSyncProgressChanged( const QString &projectFullName, qreal progress )
786✔
428
{
429
  Q_UNUSED( progress )
430

431
  int ix = projectIndexFromId( projectFullName );
786✔
432

433
  if ( ix < 0 )
786✔
434
    return;
711✔
435

436
  if ( !mProjects[ix].isMergin() )
338✔
437
    return;
263✔
438

439
  QModelIndex changeIndex = index( ix );
75✔
440
  emit dataChanged( changeIndex, changeIndex, { ProjectSyncPending, ProjectSyncProgress } );
75✔
441
}
442

443
void ProjectsModel::onProjectAdded( const LocalProject &localProject )
90✔
444
{
445
  // Check if such project is already in project list
446
  int ix = projectIndexFromId( localProject.id() );
90✔
447
  if ( ix >= 0 )
90✔
448
  {
449
    // add local information ~ project downloaded
450
    Project &project = mProjects[ix];
10✔
451

452
    project.local = localProject;
10✔
453
    if ( project.isMergin() )
10✔
454
    {
455
      project.mergin.status = ProjectStatus::projectStatus( project );
10✔
456
    }
457

458
    QModelIndex modelIx = index( ix );
10✔
459
    emit dataChanged( modelIx, modelIx );
10✔
460
  }
461
  else if ( mModelType == LocalProjectsModel )
80✔
462
  {
463
    // add project to project list ~ project created
464
    Project project;
45✔
465
    project.local = localProject;
45✔
466

467
    int insertIndex = mProjects.size();
45✔
468

469
    beginInsertRows( QModelIndex(), insertIndex, insertIndex );
45✔
470
    mProjects << project;
45✔
471
    endInsertRows();
45✔
472
  }
45✔
473
}
90✔
474

475
void ProjectsModel::onAboutToRemoveProject( const LocalProject &localProject )
96✔
476
{
477
  int ix = projectIndexFromId( localProject.id() );
96✔
478

479
  if ( ix >= 0 )
96✔
480
  {
481
    if ( mModelType == LocalProjectsModel )
52✔
482
    {
483
      beginRemoveRows( QModelIndex(), ix, ix );
48✔
484
      mProjects.removeAt( ix );
48✔
485
      endRemoveRows();
48✔
486
    }
487
    else
488
    {
489
      // just remove local part
490
      mProjects[ix].local = LocalProject();
4✔
491
      mProjects[ix].mergin.status = ProjectStatus::projectStatus( mProjects[ix] );
4✔
492

493
      QModelIndex modelIx = index( ix );
4✔
494
      emit dataChanged( modelIx, modelIx );
4✔
495
    }
496
  }
497
}
96✔
498

499
void ProjectsModel::onProjectDataChanged( const LocalProject &localProject )
244✔
500
{
501
  int ix = projectIndexFromId( localProject.id() );
244✔
502

503
  if ( ix < 0 )
244✔
504
    return;
112✔
505

506
  Project &project = mProjects[ix];
132✔
507

508
  project.local = localProject;
132✔
509

510
  if ( project.isMergin() )
132✔
511
  {
512
    project.mergin.status = ProjectStatus::projectStatus( project );
22✔
513
  }
514

515
  QModelIndex editIndex = index( ix );
132✔
516
  emit dataChanged( editIndex, editIndex );
132✔
517
}
518

519
void ProjectsModel::onProjectDetachedFromMergin( const QString &projectFullName )
2✔
520
{
521
  int ix = projectIndexFromId( projectFullName );
2✔
522

523
  if ( ix < 0 )
2✔
524
    return;
2✔
525

526
  Project &project = mProjects[ix];
×
527
  project.mergin = MerginProject();
×
528
  project.local.projectNamespace = QLatin1String();
×
529

530
  QModelIndex editIndex = index( ix );
×
531
  emit dataChanged( editIndex, editIndex );
×
532

533
  // This project should also be removed from project list for remote project model types,
534
  // however, currently one needs to click on "My projects/Shared/Explore" and that sends
535
  // another listProjects request. In new list this project will not be shown.
536
  // However, this option is not allowed in GUI anyways.
537

538
}
539

540
void ProjectsModel::onProjectAttachedToMergin( const QString & )
6✔
541
{
542
  // To ensure project will be in sync with server, send listProjectByName request.
543
  // In theory we could send that request only for this one project.
544
  listProjectsByName();
6✔
545
}
6✔
546

547
void ProjectsModel::onAuthChanged()
18✔
548
{
549
  if ( !mBackend->userAuth() || !mBackend->userAuth()->hasAuthData() ) // user logged out, clear created and shared lists
18✔
550
  {
551
    if ( mModelType == CreatedProjectsModel || mModelType == SharedProjectsModel )
6✔
552
    {
553
      clearProjects();
3✔
554
    }
555
  }
556
}
18✔
557

558
void ProjectsModel::setMerginApi( MerginApi *merginApi )
2✔
559
{
560
  if ( !merginApi || mBackend == merginApi )
2✔
561
    return;
×
562

563
  mBackend = merginApi;
2✔
564
  emit merginApiChanged( mBackend );
2✔
565
}
566

567
void ProjectsModel::setLocalProjectsManager( LocalProjectsManager *localProjectsManager )
2✔
568
{
569
  if ( !localProjectsManager || mLocalProjectsManager == localProjectsManager )
2✔
570
    return;
×
571

572
  mLocalProjectsManager = localProjectsManager;
2✔
573
  emit localProjectsManagerChanged( mLocalProjectsManager );
2✔
574
}
575

576
void ProjectsModel::setModelType( ProjectsModel::ProjectModelTypes modelType )
2✔
577
{
578
  if ( mModelType == modelType )
2✔
579
    return;
×
580

581
  mModelType = modelType;
2✔
582
  emit modelTypeChanged( mModelType );
2✔
583
}
584

585
QString ProjectsModel::modelTypeToFlag() const
12✔
586
{
587
  switch ( mModelType )
12✔
588
  {
589
    case CreatedProjectsModel:
12✔
590
      return QStringLiteral( "created" );
12✔
591
    case SharedProjectsModel:
×
592
      return QStringLiteral( "shared" );
×
593
    case WorkspaceProjectsModel:
×
594
      return QStringLiteral( "workspace" );
×
595
    case PublicProjectsModel:
×
596
      return QStringLiteral( "public" );
×
597
    default:
×
598
      return QLatin1String();
×
599
  }
600
}
601

602
QStringList ProjectsModel::projectNames() const
6✔
603
{
604
  QStringList projectNames;
6✔
605
  const LocalProjectsList projects = mLocalProjectsManager->projects();
6✔
606

607
  for ( const auto &proj : projects )
119✔
608
  {
609
    if ( !proj.projectName.isEmpty() && !proj.projectNamespace.isEmpty() )
113✔
610
      projectNames << proj.id();
112✔
611
  }
612

613
  return projectNames;
12✔
614
}
6✔
615

616
void ProjectsModel::clearProjects()
21✔
617
{
618
  beginResetModel();
21✔
619
  mProjects.clear();
21✔
620
  mServerProjectsCount = -1;
21✔
621
  endResetModel();
21✔
622

623
  emit hasMoreProjectsChanged();
21✔
624
}
21✔
625

626
void ProjectsModel::loadLocalProjects()
7✔
627
{
628
  if ( mModelType == LocalProjectsModel )
7✔
629
  {
630
    beginResetModel();
4✔
631
    mergeProjects( MerginProjectsList() ); // Fills model with local projects
4✔
632
    endResetModel();
4✔
633
  }
634
}
7✔
635

636
int ProjectsModel::projectIndexFromId( const QString &projectId ) const
1,654✔
637
{
638
  for ( int i = 0; i < mProjects.count(); i++ )
28,643✔
639
  {
640
    if ( mProjects[i].id() == projectId )
27,726✔
641
      return i;
737✔
642
  }
643

644
  return -1;
917✔
645
}
646

647
Project ProjectsModel::projectFromId( const QString &projectId ) const
24✔
648
{
649
  for ( const Project &project : mProjects )
220✔
650
  {
651
    if ( project.id() == projectId )
220✔
652
    {
653
      return project;
24✔
654
    }
655
  }
656
  return Project();
×
657
}
658

659
bool ProjectsModel::isLoading() const
×
660
{
661
  return mModelIsLoading;
×
662
}
663

664
void ProjectsModel::setModelIsLoading( bool state )
36✔
665
{
666
  mModelIsLoading = state;
36✔
667
  emit isLoadingChanged( mModelIsLoading );
36✔
668
}
36✔
669

670
ProjectsModel::ProjectModelTypes ProjectsModel::modelType() const
×
671
{
672
  return mModelType;
×
673
}
674

675
MerginApi *ProjectsModel::merginApi() const { return mBackend; }
×
676

677
LocalProjectsManager *ProjectsModel::localProjectsManager() const { return mLocalProjectsManager; }
×
678

679
SynchronizationManager *ProjectsModel::syncManager() const
×
680
{
681
  return mSyncManager;
×
682
}
683

684
void ProjectsModel::setSyncManager( SynchronizationManager *newSyncManager )
2✔
685
{
686
  if ( mSyncManager == newSyncManager )
2✔
687
    return;
×
688

689
  mSyncManager = newSyncManager;
2✔
690
  emit syncManagerChanged( mSyncManager );
2✔
691
}
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