swift
dbreducemodelduplicates.cpp
1 // SPDX-FileCopyrightText: Copyright (C) 2018 swift Project Community / Contributors
2 // SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-swift-pilot-client-1
3 
5 
6 #include <QCompleter>
7 #include <QPushButton>
8 
9 #include "ui_dbreducemodelduplicates.h"
10 
11 #include "core/webdataservices.h"
12 #include "gui/guiapplication.h"
13 #include "gui/uppercasevalidator.h"
14 #include "misc/statusmessage.h"
15 
16 using namespace swift::misc;
17 using namespace swift::misc::simulation;
18 using namespace swift::gui::models;
19 using namespace swift::gui::views;
20 
21 namespace swift::gui::components
22 {
23  CDbReduceModelDuplicates::CDbReduceModelDuplicates(QWidget *parent)
24  : QDialog(parent), ui(new Ui::CDbReduceModelDuplicates)
25  {
26  ui->setupUi(this);
27  this->clearProgressBar();
28 
29  this->setWindowFlags(this->windowFlags() & ~Qt::WindowContextHelpButtonHint);
30  ui->tvp_RemoveModels->menuAddItems(CAircraftModelView::MenuRemoveSelectedRows);
31  ui->tvp_RemoveModels->setAircraftModelMode(CAircraftModelListModel::OwnModelSet);
32  ui->le_Distributor->setValidator(new CUpperCaseValidator(ui->le_Distributor));
33  ui->bb_ReduceModelDuplicates->button(QDialogButtonBox::Ok)->setEnabled(false);
34 
35  connect(ui->pb_Run, &QPushButton::clicked, this, &CDbReduceModelDuplicates::process);
36  connect(ui->pb_Stop, &QPushButton::clicked, this, &CDbReduceModelDuplicates::stop);
37  connect(this, &QDialog::finished, this, &CDbReduceModelDuplicates::stop);
38  }
39 
41 
43  {
44  this->clearProgressBar();
45 
46  const bool changedSim = (m_simulator != simulator);
47  if (changedSim)
48  {
49  ui->le_Distributor->clear();
50  ui->tvp_RemoveModels->clear();
51  }
52 
53  m_models = models;
54  m_simulator = simulator;
55 
56  if (ui->le_Distributor->text().isEmpty())
57  {
58  const CDistributor distributor = m_distributorPreferences.get().getFirstOrDefaultDistributor(simulator);
59  ui->le_Distributor->setText(distributor.getDbKey());
60  }
61 
62  const QStringList distributors = models.getDistributors().getDbKeysAndAliases(true);
63  const int distributorCount = m_models.getDistributors().sizeInt();
64  QCompleter *c = new QCompleter(distributors, this);
65  c->setCaseSensitivity(Qt::CaseInsensitive);
66  ui->le_Distributor->setCompleter(c);
67  ui->le_Models->setText(QStringLiteral("%1 models for simulator '%2', distributors: %3")
68  .arg(models.size())
69  .arg(simulator.toQString(true))
70  .arg(distributorCount));
71  }
72 
74  {
75  using namespace std::chrono_literals;
76  if (!sGui || sGui->isShuttingDown()) { return; }
77 
78  this->clearProgressBar();
79  m_stop = false;
80 
81  if (m_models.isEmpty())
82  {
83  const CStatusMessage m = CStatusMessage(this).validationError(u"No models");
84  ui->fr_Overlay->showOverlayHTMLMessage(m, 5s);
85  return;
86  }
87 
88  if (ui->le_Distributor->text().isEmpty())
89  {
90  const CStatusMessage m = CStatusMessage(this).validationError(u"No distributor");
91  ui->fr_Overlay->showOverlayHTMLMessage(m, 5s);
92  return;
93  }
94 
95  const CAircraftModelList keyDuplicates = m_models.findDuplicateModelStrings();
96  if (!keyDuplicates.isEmpty())
97  {
98  const CStatusMessage m = CStatusMessage(this).validationError(u"Found %1 key duplicates")
99  << keyDuplicates.size();
100  ui->fr_Overlay->showOverlayHTMLMessage(m, 5s);
101  return;
102  }
103 
104  const CDistributorList distributors = m_models.getDistributors();
105  const CDistributor distributor = distributors.findByKeyOrAlias(ui->le_Distributor->text().trimmed().toUpper());
106  if (!distributor.hasValidDbKey())
107  {
108  const CStatusMessage m = CStatusMessage(this).validationError(u"Invalid distributor");
109  ui->fr_Overlay->showOverlayHTMLMessage(m, 5s);
110  return;
111  }
112 
113  const CAircraftModelList distributorModels = m_models.findByDistributor(distributor);
114  CAircraftModelList otherDistributorsModels = m_models;
115  otherDistributorsModels.removeByDistributor(distributor); // all models of other distrbutors
116  CAircraftModelList removeModels;
117 
118  ui->pb_Progress->setMaximum(distributorModels.sizeInt());
119  ui->pb_Progress->setValue(0);
120 
121  int mc = 0;
122  for (const CAircraftModel &distributorModel : distributorModels)
123  {
124  if (m_stop) { break; }
125  if (!distributorModel.getLivery().isAirlineLivery()) { continue; }
126  if (!distributorModel.getAircraftIcaoCode().hasValidDbKey()) { continue; }
127  if (ui->rb_SameLiveryAndAircraft->isChecked())
128  {
129  removeModels.replaceOrAddModelsWithString(
130  otherDistributorsModels.findByAircraftAndLivery(distributorModel.getAircraftIcaoCode(),
131  distributorModel.getLivery()),
132  Qt::CaseInsensitive);
133  }
134  else if (ui->rb_SameAirlineAndAircraft->isChecked())
135  {
136  removeModels.replaceOrAddModelsWithString(
137  otherDistributorsModels.findByAircraftAndAirline(distributorModel.getAircraftIcaoCode(),
138  distributorModel.getAirlineIcaoCode()),
139  Qt::CaseInsensitive);
140  }
141 
142  if (mc % 50 == 0) { ui->pb_Progress->setValue(mc); }
143  if (mc % 100 == 0) { CGuiApplication::processEventsFor(10); }
144  mc++;
145  }
146 
147  if (!m_stop) { ui->pb_Progress->setValue(distributorModels.sizeInt()); }
148  ui->tvp_RemoveModels->updateContainerMaybeAsync(removeModels);
149  m_removeCandidates = removeModels;
150  m_stop = false;
151 
152  const QString distKeys = removeModels.getDistributors().dbKeysAsString(", ");
153  const CStatusMessage msg =
154  removeModels.isEmpty() ?
155  CStatusMessage(this).info(u"No duplicates to be removed!") :
156  CStatusMessage(this).info(u"You can remove %1 models of the following distributors: '%2'.")
157  << removeModels.size() << distKeys;
158  ui->fr_Overlay->showOverlayHTMLMessage(msg, 5s);
159  ui->bb_ReduceModelDuplicates->button(QDialogButtonBox::Ok)->setEnabled(true);
160  }
161 
163  {
164  const int delta = ui->pb_Progress->maximum() - ui->pb_Progress->minimum();
165  const double p = percentage;
166  const int value = qRound(delta * 100.0 / p);
167  ui->pb_Progress->setValue(value);
168  }
169 
170  void CDbReduceModelDuplicates::clearProgressBar()
171  {
172  ui->pb_Progress->setMaximum(100); // otherwise undetermined
173  ui->pb_Progress->setMinimum(0);
174  ui->pb_Progress->setValue(0);
175  ui->pb_Progress->setFormat("%v/%m");
176  }
177 
178 } // namespace swift::gui::components
static void processEventsFor(int milliseconds)
Process all events for some time.
bool isShuttingDown() const
Is application shutting down?
virtual void updateProgressIndicator(int percentage)
Update the progress indicator 0..100.
void setModels(const swift::misc::simulation::CAircraftModelList &models, const swift::misc::simulation::CSimulatorInfo &simulator)
Set the models.
T get() const
Get a copy of the current value.
Definition: valuecache.h:408
Derived & validationError(const char16_t(&format)[N])
Set the severity to error, providing a format string, and adding the validation category.
Derived & info(const char16_t(&format)[N])
Set the severity to info, providing a format string.
size_type size() const
Returns number of elements in the sequence.
Definition: sequence.h:273
bool isEmpty() const
Synonym for empty.
Definition: sequence.h:285
int sizeInt() const
Avoid compiler warnings when using with int.
Definition: sequence.h:276
Streamable status message, e.g.
QString dbKeysAsString(const QString &separator) const
The DB keys as string.
bool hasValidDbKey() const
Has valid DB key.
Definition: datastore.h:195
const QString & getDbKey() const
Get DB key.
Definition: datastore.h:180
QString toQString(bool i18n=false) const
Cast as QString.
Definition: mixinstring.h:76
Aircraft model (used by another pilot, my models on disk)
Definition: aircraftmodel.h:71
Value object encapsulating a list of aircraft models.
int replaceOrAddModelsWithString(const CAircraftModelList &addOrReplaceList, Qt::CaseSensitivity sensitivity)
Replace or add based on model string.
CAircraftModelList findByAircraftAndAirline(const aviation::CAircraftIcaoCode &aircraftIcaoCode, const aviation::CAirlineIcaoCode &airlineIcaoCode) const
Find by ICAO of aircraft and airline.
int removeByDistributor(const CDistributor &distributor)
Remove by distributor.
CAircraftModelList findByAircraftAndLivery(const aviation::CAircraftIcaoCode &aircraftIcaoCode, const aviation::CLivery &livery) const
Find by aircraft and livery.
CAircraftModelList findDuplicateModelStrings() const
Find duplicate model strings and return those models with at least 1 duplicate model string.
CAircraftModelList findByDistributor(const CDistributor &distributor) const
All models from given distributors.
CDistributorList getDistributors(bool onlyDbDistributors=true) const
All distributors used with models of this list.
Value object encapsulating information of software distributor.
Definition: distributor.h:33
Value object encapsulating a list of distributors.
CDistributor findByKeyOrAlias(const QString &keyOrAlias) const
Find by id or alias.
QStringList getDbKeysAndAliases(bool sort) const
All DB keys and aliases.
Simple hardcoded info about the corresponding simulator.
Definition: simulatorinfo.h:41
SWIFT_GUI_EXPORT swift::gui::CGuiApplication * sGui
Single instance of GUI application object.
High level reusable GUI components.
Definition: aboutdialog.cpp:13
Models to be used with views, mainly QTableView.
Views, mainly QTableView.
Free functions in swift::misc.