swift
dbquickmappingwizard.cpp
1 // SPDX-FileCopyrightText: Copyright (C) 2016 swift Project Community / Contributors
2 // SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-swift-pilot-client-1
3 
4 #include "dbquickmappingwizard.h"
5 
6 #include <QStringBuilder>
7 
8 #include "ui_dbquickmappingwizard.h"
9 
10 #include "config/buildconfig.h"
12 #include "core/db/databasewriter.h"
13 #include "core/webdataservices.h"
16 #include "gui/guiapplication.h"
17 #include "gui/guiutility.h"
18 #include "gui/uppercasevalidator.h"
21 #include "gui/views/liveryview.h"
22 
23 using namespace swift::core;
24 using namespace swift::core::db;
25 using namespace swift::config;
26 using namespace swift::misc;
27 using namespace swift::misc::aviation;
28 using namespace swift::misc::simulation;
29 
30 namespace swift::gui::components
31 {
32  CDbQuickMappingWizard::CDbQuickMappingWizard(QWidget *parent) : QWizard(parent), ui(new Ui::CDbQuickMappingWizard)
33  {
34  Q_ASSERT_X(sGui, Q_FUNC_INFO, "Missing sGui");
35  Q_ASSERT_X(sGui->hasWebDataServices(), Q_FUNC_INFO, "Missing web services");
36  Q_ASSERT_X(sGui->getWebDataServices()->getDatabaseWriter(), Q_FUNC_INFO, "Missing writer");
37 
38  ui->setupUi(this);
39  ui->selector_AircraftIcaoCode->setFocus();
40  ui->selector_AircraftIcaoCode->displayWithIcaoDescription(false);
41  ui->selector_AircraftIcaoCode->displayMode(CDbAircraftIcaoSelectorComponent::DisplayCompleterString);
42  ui->selector_AirlineIcaoCode->displayWithIcaoDescription(false);
43  ui->selector_Simulator->setNoSelectionMeansAll(false);
44  ui->selector_Simulator->setRememberSelection(false);
45  ui->editor_AircraftModel->allowDrop(false);
46  ui->editor_AircraftModel->setReadOnly(true);
47  CGuiUtility::checkBoxReadOnly(ui->cb_Military, true);
48  CGuiUtility::checkBoxReadOnly(ui->cb_VirtualAirline, true);
49 
50  connect(sGui->getWebDataServices(), &CWebDataServices::swiftDbAllDataRead, this,
51  &CDbQuickMappingWizard::onWebDataRead, Qt::QueuedConnection);
52  connect(sGui->getWebDataServices()->getDatabaseWriter(), &CDatabaseWriter::publishedModels, this,
53  &CDbQuickMappingWizard::onPublishedModels, Qt::QueuedConnection);
54 
55  connect(this, &CDbQuickMappingWizard::currentIdChanged, this, &CDbQuickMappingWizard::currentWizardPageChanged);
56  connect(ui->selector_AircraftIcaoCode, &CDbAircraftIcaoSelectorComponent::changedAircraftIcao, this,
57  &CDbQuickMappingWizard::onAircraftSelected, Qt::QueuedConnection);
58  connect(ui->selector_AirlineIcaoCode, &CDbAirlineIcaoSelectorComponent::changedAirlineIcao, this,
59  &CDbQuickMappingWizard::onAirlineSelected, Qt::QueuedConnection);
60  connect(ui->selector_AirlineName, &CDbAirlineIcaoSelectorComponent::changedAirlineIcao, this,
61  &CDbQuickMappingWizard::onAirlineSelected, Qt::QueuedConnection);
62 
63  ui->comp_Log->showFilterDialog(); // filter for log normally not needed, so dialog (not bar)
65 
66  // init if data already available
67  this->onWebDataRead();
68  }
69 
71 
73  {
74  static const QStringList cats { CLogCategories::mapping(), CLogCategories::guiComponent() };
75  return cats;
76  }
77 
78  void CDbQuickMappingWizard::keyPressEvent(QKeyEvent *event)
79  {
80  Qt::Key key = static_cast<Qt::Key>(event->key());
81  if (key == Qt::Key_Enter || key == Qt::Key_Return)
82  {
83  // disable enter, interferes with filter returnPressed
84  event->accept();
85  }
86  else { QWizard::keyPressEvent(event); }
87  }
88 
90  {
91  this->clear();
92  ui->selector_AircraftIcaoCode->setAircraftIcao(aircraftIcao);
93  ui->selector_AircraftIcaoCode->setFocus();
94  }
95 
97  {
98  QString ms = model.getModelString();
99  if (!model.getDescription().isEmpty()) { ms += u" (" % model.getDescription() % u")"; }
100 
102  ui->selector_AirlineIcaoCode->setAirlineIcao(model.getAirlineIcaoCode());
103  ui->selector_AirlineName->setAirlineIcao(model.getAirlineIcaoCode());
104  ui->comp_Distributor->view()->selectDbKey(model.getDistributor().getDbKey());
105  ui->le_ModelString->setText(model.hasModelString() ? ms : "<no model string>");
106  ui->selector_AircraftIcaoCode->setFocus();
107 
108  const CLivery livery(model.getLivery());
109  if (livery.isColorLivery())
110  {
111  ui->comp_ColorSearch->presetColorLivery(livery);
112  ui->rb_ColorLivery->setChecked(true);
113  }
114 
115  m_model = model;
116  }
117 
119  {
120  m_lastId = 0;
121  ui->editor_AircraftModel->clear();
122  ui->comp_Log->clear();
123  this->restart();
124  }
125 
126  void CDbQuickMappingWizard::setAircraftIcaoFilter()
127  {
128  const CAircraftIcaoCode icao(ui->selector_AircraftIcaoCode->getAircraftIcao());
129  if (icao.isLoadedFromDb())
130  {
131  ui->comp_AircraftIcao->view()->sortByPropertyIndex(CAircraftIcaoCode::IndexRank);
132  ui->comp_AircraftIcao->filter(icao);
133  ui->comp_AircraftIcao->selectAircraftIcao(icao);
134  }
135  }
136 
137  void CDbQuickMappingWizard::setAirlineIcaoFilter()
138  {
139  const CAirlineIcaoCode icao(ui->selector_AirlineIcaoCode->getAirlineIcao());
140  if (icao.isLoadedFromDb())
141  {
142  ui->comp_Livery->view()->sortByPropertyIndex(CLivery::IndexDbIntegerKey);
143  ui->comp_Livery->filterByAirline(icao);
144  ui->comp_Livery->view()->selectRow(0);
145  }
146  }
147 
148  void CDbQuickMappingWizard::setColorFilter()
149  {
150  const CLivery colorLivery(ui->comp_ColorSearch->getLivery());
151  if (colorLivery.isLoadedFromDb())
152  {
153  ui->comp_Livery->filter(colorLivery);
154  ui->comp_Livery->view()->selectRow(0);
155  }
156  }
157 
158  void CDbQuickMappingWizard::setDistributorFilter()
159  {
160  const CSimulatorInfo sims = this->guessSimulator();
161  ui->comp_Distributor->filterBySimulator(sims);
162  if (m_model.getDistributor().isLoadedFromDb())
163  {
164  const bool s = ui->comp_Distributor->selectDistributor(m_model.getDistributor());
165  Q_UNUSED(s);
166  }
167  }
168 
169  CLivery CDbQuickMappingWizard::getFirstSelectedOrDefaultLivery() const
170  {
171  const CLivery l = ui->comp_Livery->view()->firstSelectedOrDefaultObject();
172  if (l.isLoadedFromDb()) { return l; }
173  if (m_model.getLivery().isLoadedFromDb()) { return m_model.getLivery(); }
174  return l;
175  }
176 
177  CAircraftIcaoCode CDbQuickMappingWizard::getFirstSelectedOrDefaultAircraftIcao() const
178  {
179  const CAircraftIcaoCode icao = ui->comp_AircraftIcao->view()->firstSelectedOrDefaultObject();
180  if (icao.isLoadedFromDb()) { return icao; }
181  if (m_model.getAircraftIcaoCode().isLoadedFromDb()) { return m_model.getAircraftIcaoCode(); }
182  return icao;
183  }
184 
185  swift::misc::simulation::CDistributor CDbQuickMappingWizard::getFirstSelectedOrDefaultDistributor() const
186  {
187  const CDistributor dist = ui->comp_Distributor->view()->firstSelectedOrDefaultObject();
188  if (dist.isLoadedFromDb()) { return dist; }
189  if (m_model.getDistributor().isLoadedFromDb()) { return m_model.getDistributor(); }
190  return dist;
191  }
192 
193  void CDbQuickMappingWizard::onWebDataRead()
194  {
195  if (!sGui || !sGui->hasWebDataServices()) { return; }
196  }
197 
198  void CDbQuickMappingWizard::onPublishedModels(const CAircraftModelList &modelsPublished,
199  const CAircraftModelList &modelsSkipped,
200  const CStatusMessageList &messages, bool requestSuccessful,
201  bool directWrite)
202  {
203  Q_UNUSED(modelsPublished);
204  Q_UNUSED(modelsSkipped);
205  Q_UNUSED(directWrite);
206  CStatusMessageList msgs;
207  if (requestSuccessful)
208  {
209  msgs.push_back(CStatusMessage(this, CStatusMessage::SeverityInfo, u"Publishing request sent"));
210  }
211  else { msgs.push_back(CStatusMessage(this, CStatusMessage::SeverityError, u"Publishing request failed")); }
212  msgs.push_back(messages);
213  ui->comp_Log->appendStatusMessagesToList(msgs);
214  }
215 
216  void CDbQuickMappingWizard::currentWizardPageChanged(int id)
217  {
218  const bool forward = id > m_lastId;
219  const bool colorMode = ui->rb_ColorLivery->isChecked();
220  m_lastId = id;
221 
222  const Pages page = static_cast<Pages>(id);
223  switch (page)
224  {
225  case PageAircraftSelect:
226  {
227  this->setAircraftIcaoFilter();
228  }
229  break;
230  case PageColor:
231  if (!colorMode) { forward ? this->next() : this->back(); }
232  break;
233  case PageLiverySelect:
234  {
235  if (colorMode) { this->setColorFilter(); }
236  else { this->setAirlineIcaoFilter(); }
237  }
238  break;
239  case PageDistributorSelect:
240  {
241  this->setDistributorFilter();
242  }
243  break;
244  case PageConfirmation:
245  {
246  const CSimulatorInfo sims = this->guessSimulator();
247  ui->selector_Simulator->setValue(sims);
248  ui->editor_AircraftModel->setLivery(this->getFirstSelectedOrDefaultLivery());
249  ui->editor_AircraftModel->setDistributor(this->getFirstSelectedOrDefaultDistributor());
250  ui->editor_AircraftModel->setAircraftIcao(this->getFirstSelectedOrDefaultAircraftIcao());
251  const CStatusMessageList msgs(this->validateData());
252  const bool errorFree = !msgs.hasWarningOrErrorMessages();
253  ui->fr_ConfirmationOk->setVisible(errorFree);
254  ui->fr_ConfirmationStillErrors->setVisible(!errorFree);
255  if (!errorFree) { ui->wp6_Confirmation->showOverlayMessages(msgs); }
256  }
257  break;
258  case PageCredentials:
259  {
260  ui->comp_Log->clear();
261  }
262  break;
264  {
265  // void
266  }
267  break;
268  case PageSendStatus:
269  {
270  this->writeModelToDb();
271  this->button(BackButton)->hide();
272  }
273  break;
274  default: break;
275  }
276  }
277 
279  {
280  const Pages page = static_cast<Pages>(this->currentId());
281  bool ok = false;
282  switch (page)
283  {
284  case PageConfirmation:
285  {
286  const CStatusMessageList msgs(this->validateData());
287  if (!msgs.isEmpty()) { ui->wp6_Confirmation->showOverlayMessages(msgs); }
288  ok = !msgs.hasWarningOrErrorMessages();
289  }
290  break;
291  case PageCredentials:
292  {
293  ok = ui->comp_DbLogin->isUserAuthenticated();
294  if (!ok)
295  {
296  ui->wp7_Credentials->showOverlayHTMLMessage("No user credentials, read login hints!", 10 * 1000);
297  }
298  }
299  break;
300  default:
301  {
302  ok = true;
303  }
304  break;
305  }
306 
307  return ok;
308  }
309 
310  CStatusMessageList CDbQuickMappingWizard::validateData() const
311  {
312  CStatusMessageList msgs(ui->editor_AircraftModel->validate(true));
313  if (ui->le_ModelString->text().isEmpty())
314  {
315  const CStatusMessage error(this, CStatusMessage::SeverityError, u"Missing model string", true);
316  msgs.push_back(error);
317  }
318 
319  const CStatusMessage vMsg = ui->selector_Simulator->getValue().validateSimulatorsForModel();
320  if (vMsg.isWarningOrAbove()) { msgs.push_back(vMsg); }
321 
322  return msgs;
323  }
324 
325  void CDbQuickMappingWizard::consolidateModelWithUIData()
326  {
327  CAircraftModel model = m_model;
328  model.setAircraftIcaoCode(ui->editor_AircraftModel->getAircraftIcao());
329  model.setDistributor(ui->editor_AircraftModel->getDistributor());
330  model.setLivery(ui->editor_AircraftModel->getLivery());
331  model.setSimulator(ui->selector_Simulator->getValue());
332  m_model = model;
333  }
334 
335  CSimulatorInfo CDbQuickMappingWizard::guessSimulator() const
336  {
337  CSimulatorInfo sims = m_model.getSimulator();
338  if (!sims.isAnySimulator() && m_model.hasModelString() && sGui && sGui->hasWebDataServices())
339  {
341  if (m.isLoadedFromDb()) { sims = m.getSimulator(); }
342  }
343 
344  if (sGui && !sGui->isShuttingDown() && sGui->getIContextSimulator() &&
346  {
348  }
349  return sims;
350  }
351 
352  void CDbQuickMappingWizard::writeModelToDb()
353  {
354  if (!sGui || sGui->isShuttingDown() || !sGui->getWebDataServices() ||
356  {
357  return;
358  }
359  this->consolidateModelWithUIData();
360 
361  // make sure the model is correctly excluded for XP etc.
362  static const QString qmw(u"[swift QMW " % CBuildConfig::getVersionString() % u"]");
363  if (m_model.getSimulator().isXPlane()) { m_model.setModelMode(CAircraftModel::Exclude); }
364  m_model.setVersion(CBuildConfig::getVersionString());
365  const QString extraInfo = QString(m_model.getDescription() % u" " % qmw).simplified().trimmed();
366 
367  const CStatusMessageList msgs =
368  sGui->getWebDataServices()->getDatabaseWriter()->asyncPublishModel(m_model, extraInfo);
369  ui->comp_Log->appendStatusMessagesToList(msgs);
370  }
371 
372  void CDbQuickMappingWizard::onAirlineSelected(const CAirlineIcaoCode &icao)
373  {
374  if (icao.isLoadedFromDb())
375  {
376  ui->cb_VirtualAirline->setChecked(icao.isVirtualAirline());
377  ui->cb_Military->setChecked(icao.isMilitary());
378  ui->selector_AirlineName->setAirlineIcao(icao);
379  ui->selector_AirlineIcaoCode->setAirlineIcao(icao);
380  // already trigger sorting, if sorting is already correct it does nothing
381  // avoids issue with later selection overridden by sorting/filtering
382  this->setAirlineIcaoFilter();
383  }
384  }
385 
386  void CDbQuickMappingWizard::onAircraftSelected(const CAircraftIcaoCode &icao)
387  {
388  if (icao.isLoadedFromDb())
389  {
390  ui->cb_Military->setChecked(icao.isMilitary());
391  // already trigger sorting, if sorting is already correct it does nothing
392  // avoids issue with later selection overidden by sorting/filtering
393  this->setAircraftIcaoFilter();
394  }
395  }
396 } // namespace swift::gui::components
bool hasWebDataServices() const
Web data services available?
bool isShuttingDown() const
Is application shutting down?
const context::IContextSimulator * getIContextSimulator() const
Direct access to contexts if a CCoreFacade has been initialized.
CWebDataServices * getWebDataServices() const
Get the web data services.
db::CDatabaseWriter * getDatabaseWriter() const
DB writer class.
swift::misc::simulation::CAircraftModel getModelForModelString(const QString &modelString) const
Model for model string if any.
virtual swift::misc::simulation::CSimulatorPluginInfo getSimulatorPluginInfo() const =0
Simulator info, currently loaded plugin.
bool isSimulatorAvailable() const
Simulator avialable (driver available)?
swift::misc::CStatusMessageList asyncPublishModel(const swift::misc::simulation::CAircraftModel &model, const QString &extraInfo)
Write model to DB.
static void checkBoxReadOnly(QCheckBox *checkBox, bool readOnly)
Pseudo readonly state for checkbox.
Definition: guiutility.cpp:450
static void setWizardButtonWidths(QWizard *wizard)
Set button widths for a wizard.
Definition: guiutility.cpp:944
void changedAircraftIcao(const swift::misc::aviation::CAircraftIcaoCode &icao)
ICAO was changed.
void changedAirlineIcao(const swift::misc::aviation::CAirlineIcaoCode &icao)
ICAO was changed.
Wizard to quickly provide a single mapping.
void presetAircraftIcao(const swift::misc::aviation::CAircraftIcaoCode &aircraftIcao)
Preset values.
void presetModel(const swift::misc::simulation::CAircraftModel &model)
Preset a model.
static const QStringList & getLogCategories()
Log categories.
@ PageLastConfirmation
just info to say data will be send
void push_back(const T &value)
Appends an element at the end of the sequence.
Definition: sequence.h:305
bool isEmpty() const
Synonym for empty.
Definition: sequence.h:285
Streamable status message, e.g.
bool isWarningOrAbove() const
Warning or above.
Status messages, e.g. from Core -> GUI.
bool hasWarningOrErrorMessages() const
Warning or error messages.
Value object for ICAO classification.
Value object for ICAO classification.
bool isVirtualAirline() const
Virtual airline.
bool isMilitary() const
Military, air force or such?
Value object encapsulating information about an airpot.
Definition: livery.h:29
bool isColorLivery() const
Color livery?
Definition: livery.cpp:180
void setVersion(const QString &version)
Version info.
Definition: datastore.h:57
bool isLoadedFromDb() const
Loaded from DB.
Definition: datastore.cpp:49
bool isLoadedFromDb() const
Loaded from DB.
Definition: datastore.h:204
const QString & getDbKey() const
Get DB key.
Definition: datastore.h:180
Aircraft model (used by another pilot, my models on disk)
Definition: aircraftmodel.h:71
const aviation::CAirlineIcaoCode & getAirlineIcaoCode() const
Airline ICAO code.
const aviation::CLivery & getLivery() const
Get livery.
CSimulatorInfo getSimulator() const
Simulator info.
const QString & getModelString() const
Model key, either queried or loaded from simulator model.
const QString & getDescription() const
Descriptive text.
void setSimulator(const CSimulatorInfo &simulator)
Set simulator info.
const CDistributor & getDistributor() const
Get distributor.
const aviation::CAircraftIcaoCode & getAircraftIcaoCode() const
Aircraft ICAO code.
void setModelMode(ModelMode mode)
Set model mode.
bool hasModelString() const
Non empty model string?
void setLivery(const aviation::CLivery &livery)
Livery.
void setDistributor(const CDistributor &distributor)
Set distributor.
bool setAircraftIcaoCode(const aviation::CAircraftIcaoCode &aircraftIcaoCode)
Set aircraft ICAO code.
Value object encapsulating a list of aircraft models.
Value object encapsulating information of software distributor.
Definition: distributor.h:33
Simple hardcoded info about the corresponding simulator.
Definition: simulatorinfo.h:41
CSimulatorInfo add(const CSimulatorInfo &other)
Add simulator.
bool isAnySimulator() const
Any simulator?
const QString & getSimulator() const
Simulator.
SWIFT_GUI_EXPORT swift::gui::CGuiApplication * sGui
Single instance of GUI application object.
Classes interacting with the swift database (aka "datastore").
Backend services of the swift project, like dealing with the network or the simulators.
Definition: actionbind.cpp:7
High level reusable GUI components.
Definition: aboutdialog.cpp:13
Free functions in swift::misc.