swift
aircraftmodelmenus.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 "aircraftmodelmenus.h"
5 
6 #include <QDesktopServices>
7 
8 #include "config/buildconfig.h"
10 #include "core/webdataservices.h"
13 #include "gui/guiapplication.h"
14 #include "misc/icons.h"
15 #include "misc/logmessage.h"
17 
18 using namespace swift::config;
19 using namespace swift::misc;
20 using namespace swift::misc::simulation;
21 using namespace swift::gui;
22 using namespace swift::gui::views;
23 using namespace swift::gui::models;
24 using namespace swift::gui::components;
25 using namespace swift::core::db;
26 
27 namespace swift::gui::menus
28 {
29  void IAircraftModelViewMenu::anchor() {}
30 
31  const QStringList &IAircraftModelViewMenu::getLogCategories()
32  {
33  static const QStringList cats { CLogCategories::guiComponent() };
34  return cats;
35  }
36 
37  CAircraftModelView *IAircraftModelViewMenu::modelView() const
38  {
39  CAircraftModelView *mv = qobject_cast<CAircraftModelView *>(parent());
40  Q_ASSERT_X(mv, Q_FUNC_INFO, "no view");
41  return mv;
42  }
43 
44  const CAircraftModelList &IAircraftModelViewMenu::getAircraftModels() const
45  {
46  const CAircraftModelView *mv = modelView();
47  Q_ASSERT_X(mv, Q_FUNC_INFO, "no view");
48  return mv->container();
49  }
50 
51  const CAircraftModelList &IAircraftModelViewMenu::getAllOrAllFilteredAircraftModels(bool *filtered) const
52  {
53  const CAircraftModelView *mv = modelView();
54  Q_ASSERT_X(mv, Q_FUNC_INFO, "no view");
55  return mv->containerOrFilteredContainer(filtered);
56  }
57 
58  CAircraftModelList IAircraftModelViewMenu::getSelectedAircraftModels() const
59  {
60  const CAircraftModelView *mv = modelView();
61  Q_ASSERT_X(mv, Q_FUNC_INFO, "no view");
62  return mv->selectedObjects();
63  }
64 
65  CShowSimulatorFileMenu::CShowSimulatorFileMenu(CAircraftModelView *modelView, COverlayMessagesFrame *messageFrame)
66  : IAircraftModelViewMenu(modelView), m_messageFrame(messageFrame)
67  {}
68 
70  {
71  static const QStringList cats { CLogCategories::guiComponent() };
72  return cats;
73  }
74 
76  {
78  Q_ASSERT_X(mv, Q_FUNC_INFO, "no view");
79 
80  if (mv->hasSingleSelectedRow())
81  {
82  const CAircraftModel model(mv->selectedObject());
83  bool added = false;
84  if (model.hasFileName())
85  {
86  menuActions.addMenuSimulator();
87  m_fileAction = menuActions.addAction(m_fileAction, CIcons::text16(), "Open simulator file",
89  { this, &CShowSimulatorFileMenu::showSimulatorFile });
90  added = true;
91  if (CModelConverterX::supportsModelConverterX())
92  {
93  m_modelConverterX =
94  menuActions.addAction(m_modelConverterX, "ModelConverterX", CMenuAction::pathSimulator(),
95  { this, &CShowSimulatorFileMenu::startModelConverterX });
96  }
97  }
98 
99  if (added) { menuActions.addSeparator(CMenuAction::pathSimulator()); }
100  }
101  this->nestedCustomMenu(menuActions);
102  }
103 
104  void CShowSimulatorFileMenu::showSimulatorFile()
105  {
106  const CAircraftModelView *mv = modelView();
107  if (!mv->hasSingleSelectedRow()) { return; }
108  const CAircraftModel model(mv->selectedObject());
109  if (!model.hasFileName()) { return; }
110  if (QFile::exists(model.getFileName()))
111  {
112  const QUrl url = QUrl::fromLocalFile(model.getFileName());
113  QDesktopServices::openUrl(url);
114  }
115  else
116  {
117  const CStatusMessage m =
118  CStatusMessage(this, CStatusMessage::SeverityError,
119  QStringLiteral("No file for model '&1'").arg(model.getFileName()), true);
120  if (m_messageFrame) { m_messageFrame->showOverlayHTMLMessage(m); }
121  CLogMessage::preformatted(m);
122  }
123  }
124 
125  void CShowSimulatorFileMenu::startModelConverterX()
126  {
127  if (!CModelConverterX::supportsModelConverterX()) { return; }
128  const CAircraftModelView *mv = modelView();
129  if (!mv->hasSingleSelectedRow()) { return; }
130  const CAircraftModel model(mv->selectedObject());
131  CModelConverterX::startModelConverterX(model, sApp);
132  }
133 
134  // --------------------------------- with DB data ---------------------------------
135 
137  : IAircraftModelViewMenu(modelView), m_modelsTarget(modelsTarget)
138  {
139  // it can be the target is not yet known
140  if (modelsTarget)
141  {
142  const bool ok = modelsTargetSetable() || modelsTargetUpdatable();
143  Q_ASSERT_X(ok, Q_FUNC_INFO, "Neither setable nor updatable");
144  Q_UNUSED(ok)
145  }
146  }
147 
149  {
150  static const QStringList cats { CLogCategories::mapping(), CLogCategories::guiComponent() };
151  return cats;
152  }
153 
155  {
156  const CAircraftModelView *mv = modelView();
157  if (!mv || mv->isEmpty())
158  {
159  this->nestedCustomMenu(menuActions);
160  return;
161  }
162  if (!sGui->hasWebDataServices())
163  {
164  this->nestedCustomMenu(menuActions);
165  return;
166  }
167 
168  menuActions.addMenuConsolidateModels();
169 
170  m_consolidateAll = menuActions.addAction(m_consolidateAll, CIcons::databaseEdit16(), "All with DB data",
172  { this, &CConsolidateWithDbDataMenu::consolidateData });
173  if (mv->hasSelection())
174  {
175  m_consolidateSelected = menuActions.addAction(
176  m_consolidateSelected, CIcons::databaseEdit16(), "Selected with DB data",
177  CMenuAction::pathModelConsolidate(), { this, &CConsolidateWithDbDataMenu::consolidateSelectedData });
178  }
179  this->nestedCustomMenu(menuActions);
180  }
181 
182  void CConsolidateWithDbDataMenu::consolidateData()
183  {
184  if (!sGui || sGui->isShuttingDown() || !sGui->hasWebDataServices()) { return; }
185  const CAircraftModelList dbModels(sGui->getWebDataServices()->getModels());
186  if (dbModels.isEmpty())
187  {
188  CLogMessage(this).warning(u"No DB models to consolidate with");
189  return;
190  }
191  if (!this->modelsTargetSetable())
192  {
193  CLogMessage(this).warning(u"No setable target");
194  return;
195  }
196 
197  this->modelView()->showLoadIndicator();
198  bool filtered = false;
199  CAircraftModelList models(this->getAllOrAllFilteredAircraftModels(&filtered));
200 
201  const int c = CDatabaseUtils::consolidateModelsWithDbDataAllowsGuiRefresh(models, true, true);
202  if (c > 0 && this->modelsTargetSetable() && this->modelsTargetUpdatable())
203  {
204  if (filtered)
205  {
206  this->modelsTargetUpdatable()->updateModels(models);
207  CLogMessage(this).info(u"Consolidated %1/%2 filtered models with DB") << c << models.size();
208  }
209  else
210  {
211  this->modelsTargetSetable()->setModels(models);
212  CLogMessage(this).info(u"Consolidated %1/%2 models with DB") << c << models.size();
213  }
214  }
215  else
216  {
217  CLogMessage(this).info(u"No data consolidated with DB");
218  this->modelView()->hideLoadIndicator();
219  }
220  }
221 
222  void CConsolidateWithDbDataMenu::consolidateSelectedData()
223  {
224  Q_ASSERT_X(sGui, Q_FUNC_INFO, "Missing sGui");
225  if (!sGui->hasWebDataServices()) { return; }
226 
228  if (models.isEmpty()) { return; }
229  if (!this->modelsTargetUpdatable())
230  {
231  CLogMessage(this).warning(u"No updatable target");
232  return;
233  }
234  const int c = CDatabaseUtils::consolidateModelsWithDbDataAllowsGuiRefresh(models, true, true);
235  if (c > 0 && this->modelsTargetUpdatable()) { this->modelsTargetUpdatable()->updateModels(models); }
236  }
237 
238  IModelsSetable *CConsolidateWithDbDataMenu::modelsTargetSetable() const
239  {
240  return qobject_cast<IModelsSetable *>(m_modelsTarget);
241  }
242 
243  IModelsUpdatable *CConsolidateWithDbDataMenu::modelsTargetUpdatable() const
244  {
245  return qobject_cast<IModelsUpdatable *>(m_modelsTarget);
246  }
247 
248  // --------------------------------- with simulator models ---------------------------------
249 
251  QObject *modelsTarget)
252  : IAircraftModelViewMenu(modelView), m_modelsTarget(modelsTarget)
253  {
254  // it can be the target is not yet known
255  if (modelsTarget)
256  {
257  const bool ok = modelsTargetSetable() || modelsTargetUpdatable();
258  Q_ASSERT_X(ok, Q_FUNC_INFO, "Neither setable nor updatable");
259  Q_UNUSED(ok)
260  }
261  }
262 
264  {
265  static const QStringList cats { CLogCategories::mapping(), CLogCategories::guiComponent() };
266  return cats;
267  }
268 
270  {
271  const CAircraftModelView *mv = modelView();
272  if (mv->isEmpty())
273  {
274  this->nestedCustomMenu(menuActions);
275  return;
276  }
277  if (!sGui->hasWebDataServices())
278  {
279  this->nestedCustomMenu(menuActions);
280  return;
281  }
282 
283  menuActions.addMenuConsolidateModels();
284 
285  // consolidate
286  m_consolidateAll = menuActions.addAction(m_consolidateAll, CIcons::appModels16(), "All with simulator models",
288  { this, &CConsolidateWithSimulatorModels::consolidateData });
289  if (mv->hasSelection())
290  {
291  m_consolidateSelected =
292  menuActions.addAction(m_consolidateSelected, CIcons::appModels16(), "Selected with simulator models",
294  { this, &CConsolidateWithSimulatorModels::consolidateSelectedData });
295  }
296 
297  // update directories
298  m_updateDirsAll = menuActions.addAction(m_updateDirsAll, CIcons::disk16(), "Update all directories",
300  { this, &CConsolidateWithSimulatorModels::updateDirectoryData });
301  if (mv->hasSelection())
302  {
303  m_updateDirsSelected =
304  menuActions.addAction(m_updateDirsSelected, CIcons::disk16(), "Update directories for selected",
306  { this, &CConsolidateWithSimulatorModels::updateDirectorySelectedData });
307  }
308 
309  this->nestedCustomMenu(menuActions);
310  }
311 
312  void CConsolidateWithSimulatorModels::consolidateData()
313  {
314  using namespace std::chrono_literals;
315 
316  bool filtered = false;
317  const CAircraftModelList models(this->getAllOrAllFilteredAircraftModels(&filtered));
318  if (models.isEmpty()) { return; }
319  QStringList removedModelStrings;
320  const int i = this->modelView()->showLoadIndicator();
321  const CAircraftModelList consolidated = CDatabaseUtils::consolidateModelsWithSimulatorModelsAllowsGuiRefresh(
322  models, this->getSimulatorModels(), removedModelStrings, true);
323  const CSimulatorInfo sim(this->getSimulator());
324 
325  if (!filtered) { this->modelsTargetSetable()->setModelsForSimulator(consolidated, sim); }
326  else
327  {
328  if (!this->modelsTargetUpdatable()) { CLogMessage(this).warning(u"No updatable target"); }
329  else { this->modelsTargetUpdatable()->updateModelsForSimulator(consolidated, sim); }
330  }
331  this->modelView()->hideLoadIndicator(i);
332  if (!removedModelStrings.isEmpty() && this->getMappingComponent())
333  {
334  const CStatusMessage m = CStatusMessage(this).info(u"Removed %1 model(s)") << removedModelStrings.size();
335  this->getMappingComponent()->showOverlayMessage(m, 5s);
336  }
337  }
338 
339  void CConsolidateWithSimulatorModels::consolidateSelectedData()
340  {
341  using namespace std::chrono_literals;
342 
343  Q_ASSERT_X(sGui, Q_FUNC_INFO, "Missing sGui");
344  const CAircraftModelList models(this->getSelectedAircraftModels());
345  if (models.isEmpty()) { return; }
346  if (!this->modelsTargetUpdatable())
347  {
348  CLogMessage(this).warning(u"No updatable target");
349  return;
350  }
351 
352  QStringList removedModelStrings;
353  const int i = this->modelView()->showLoadIndicator();
354  const CAircraftModelList consolidated = CDatabaseUtils::consolidateModelsWithSimulatorModelsAllowsGuiRefresh(
355  models, this->getSimulatorModels(), removedModelStrings, true);
356  const CSimulatorInfo sim(this->getSimulator());
357 
358  this->modelsTargetUpdatable()->updateModelsForSimulator(consolidated, sim);
359  this->modelView()->hideLoadIndicator(i);
360  if (!removedModelStrings.isEmpty() && this->getMappingComponent())
361  {
362  const CStatusMessage m = CStatusMessage(this).info(u"Removed %1 model(s)") << removedModelStrings.size();
363  this->getMappingComponent()->showOverlayMessage(m, 5s);
364  }
365  }
366 
367  void CConsolidateWithSimulatorModels::updateDirectoryData()
368  {
369  using namespace std::chrono_literals;
370 
371  bool filtered = false;
372  const CAircraftModelList models(this->getAllOrAllFilteredAircraftModels(&filtered));
373  if (models.isEmpty()) { return; }
374  QStringList removedModelStrings;
375  const int i = this->modelView()->showLoadIndicator();
376  const CAircraftModelList consolidated = CDatabaseUtils::updateModelsDirectoriesAllowsGuiRefresh(
377  models, this->getSimulatorModels(), removedModelStrings, true);
378  const CSimulatorInfo sim(this->getSimulator());
379 
380  if (!filtered) { this->modelsTargetSetable()->setModelsForSimulator(consolidated, sim); }
381  else
382  {
383  if (!this->modelsTargetUpdatable()) { CLogMessage(this).warning(u"No updatable target"); }
384  else { this->modelsTargetUpdatable()->updateModelsForSimulator(consolidated, sim); }
385  }
386  this->modelView()->hideLoadIndicator(i);
387  if (!removedModelStrings.isEmpty() && this->getMappingComponent())
388  {
389  const CStatusMessage m = CStatusMessage(this).info(u"Removed %1 model(s)") << removedModelStrings.size();
390  this->getMappingComponent()->showOverlayMessage(m, 5s);
391  }
392  }
393 
394  void CConsolidateWithSimulatorModels::updateDirectorySelectedData()
395  {
396  using namespace std::chrono_literals;
397 
398  Q_ASSERT_X(sGui, Q_FUNC_INFO, "Missing sGui");
399  const CAircraftModelList models(this->getSelectedAircraftModels());
400  if (models.isEmpty()) { return; }
401  if (!this->modelsTargetUpdatable())
402  {
403  CLogMessage(this).warning(u"No updatable target");
404  return;
405  }
406 
407  QStringList removedModelStrings;
408  const int i = this->modelView()->showLoadIndicator();
409  const CAircraftModelList consolidated = CDatabaseUtils::updateModelsDirectoriesAllowsGuiRefresh(
410  models, this->getSimulatorModels(), removedModelStrings, true);
411  const CSimulatorInfo sim(this->getSimulator());
412 
413  this->modelsTargetUpdatable()->updateModelsForSimulator(consolidated, sim);
414  this->modelView()->hideLoadIndicator(i);
415  if (!removedModelStrings.isEmpty() && this->getMappingComponent())
416  {
417  const CStatusMessage m = CStatusMessage(this).info(u"Removed %1 model(s)") << removedModelStrings.size();
418  this->getMappingComponent()->showOverlayMessage(m, 5s);
419  }
420  }
421 
422  CAircraftModelList CConsolidateWithSimulatorModels::getSimulatorModels() const
423  {
424  CDbMappingComponent *mc = this->getMappingComponent();
425  Q_ASSERT_X(mc, Q_FUNC_INFO, "No mapping component");
426  const CSimulatorInfo sim = this->getSimulator();
427  mc->setOwnModelsSimulator(sim);
428  return mc->getOwnModels();
429  }
430 
431  CSimulatorInfo CConsolidateWithSimulatorModels::getSimulator() const
432  {
433  const ISimulatorSelectable *s = this->simulatorSelectable();
434  Q_ASSERT_X(s, Q_FUNC_INFO, "No ISimulatorSelectable");
435  const CSimulatorInfo sim = s->getSelectedSimulator();
436  Q_ASSERT_X(sim.isSingleSimulator(), Q_FUNC_INFO, "Need single simulator");
437  return sim;
438  }
439 
440  IModelsForSimulatorSetable *CConsolidateWithSimulatorModels::modelsTargetSetable() const
441  {
442  return qobject_cast<IModelsForSimulatorSetable *>(m_modelsTarget);
443  }
444 
445  IModelsForSimulatorUpdatable *CConsolidateWithSimulatorModels::modelsTargetUpdatable() const
446  {
447  return qobject_cast<IModelsForSimulatorUpdatable *>(m_modelsTarget);
448  }
449 
450  ISimulatorSelectable *CConsolidateWithSimulatorModels::simulatorSelectable() const
451  {
452  return qobject_cast<ISimulatorSelectable *>(m_modelsTarget);
453  }
454 
455  components::CDbMappingComponent *CConsolidateWithSimulatorModels::getMappingComponent() const
456  {
457  // try to cast target
458  CDbMappingComponent *mc = nullptr;
459  CDbMappingComponentAware *mca = qobject_cast<CDbMappingComponentAware *>(m_modelsTarget);
460  if (mca) { mc = mca->getMappingComponent(); }
461  if (!mc) { mc = qobject_cast<CDbMappingComponent *>(m_modelsTarget); }
462  return mc;
463  }
464 } // namespace swift::gui::menus
SWIFT_CORE_EXPORT swift::core::CApplication * sApp
Single instance of application object.
Definition: application.cpp:71
bool hasWebDataServices() const
Web data services available?
bool isShuttingDown() const
Is application shutting down?
CWebDataServices * getWebDataServices() const
Get the web data services.
swift::misc::simulation::CAircraftModelList getModels() const
Models.
bool showOverlayHTMLMessage(const QString &htmlMessage, std::chrono::milliseconds timeout=std::chrono::milliseconds(0))
HTML message.
Using this class provides a QFrame with the overlay functionality already integrated.
Allows subcomponents to gain access to model component.
CDbMappingComponent * getMappingComponent() const
Get the mapping component.
swift::misc::simulation::CAircraftModelList getOwnModels() const
Own cached models.
void setOwnModelsSimulator(const swift::misc::simulation::CSimulatorInfo &simulator)
Set simulator for own models.
CConsolidateWithDbDataMenu(swift::gui::views::CAircraftModelView *modelView, QObject *modelsTarget)
Constructor.
static const QStringList & getLogCategories()
Log.categories.
virtual void customMenu(CMenuActions &menuActions)
Display custom menu.
CConsolidateWithSimulatorModels(views::CAircraftModelView *modelView, QObject *modelsTarget)
Constructor.
static const QStringList & getLogCategories()
Log.categories.
virtual void customMenu(CMenuActions &menuActions)
Display custom menu.
static const QString & pathModelConsolidate()
Consolidate.
Definition: menuaction.h:164
static const QString & pathSimulator()
Simulator sub menu.
Definition: menuaction.h:122
Bunch of CMenuAction objects.
Definition: menuaction.h:384
CMenuAction addMenuSimulator()
Simulator menu.
Definition: menuaction.cpp:428
CMenuAction addMenuConsolidateModels()
Consolidate models menu.
Definition: menuaction.cpp:455
void addSeparator(const QString &path)
Add a separator.
Definition: menuaction.cpp:187
CMenuAction addAction(const CMenuAction &menuAction)
Add menu action.
Definition: menuaction.cpp:210
static const QStringList & getLogCategories()
Log.categories.
virtual void customMenu(CMenuActions &menuActions)
Display custom menu.
Menu base class for aircraft model view menus.
swift::misc::simulation::CAircraftModelList getSelectedAircraftModels() const
Selected aircraft models.
const swift::misc::simulation::CAircraftModelList & getAllOrAllFilteredAircraftModels(bool *filtered=nullptr) const
Get aircraft models (all, or all filtered)
swift::gui::views::CAircraftModelView * modelView() const
Model view.
void nestedCustomMenu(CMenuActions &menuActions) const
Delegate down one level.
Definition: menudelegate.h:49
virtual bool isEmpty() const
Empty?
Definition: viewbase.cpp:400
virtual ContainerType selectedObjects() const
Selected objects.
Definition: viewbase.cpp:240
ObjectType selectedObject() const
Selected object (or default)
Definition: viewbase.cpp:307
const ContainerType & container() const
Access to container.
Definition: viewbase.cpp:200
const ContainerType & containerOrFilteredContainer(bool *filtered=nullptr) const
Full container or cached filtered container as approproiate.
Definition: viewbase.cpp:233
void hideLoadIndicator(int loadingId=-1)
Hide loading indicator.
bool hasSingleSelectedRow() const
Single selected row.
int showLoadIndicator(int containerSizeDependent=-1, std::chrono::milliseconds timeout=std::chrono::milliseconds { 0 }, bool processEvents=true)
Show loading indicator.
bool hasSelection() const
Selection (selected rows)
Class for emitting a log message.
Definition: logmessage.h:27
Derived & warning(const char16_t(&format)[N])
Set the severity to warning, providing a format string.
Derived & info(const char16_t(&format)[N])
Set the severity to info, providing a format string.
Streamable status message, e.g.
Aircraft model (used by another pilot, my models on disk)
Definition: aircraftmodel.h:71
Value object encapsulating a list of aircraft models.
Simple hardcoded info about the corresponding simulator.
Definition: simulatorinfo.h:41
bool isSingleSimulator() const
Single simulator selected.
Interface to "something" backing models, which can be set.
Interface to "something" backing models, which can be modified (updated)
Interface to "something" backing models, which can be set.
virtual void setModels(const CAircraftModelList &models)=0
Set models.
Interface to "something" backing models, which can be modified (updated)
virtual int updateModels(const CAircraftModelList &models)=0
Update models.
Interface to "something" allowing a simulator selection.
virtual swift::misc::simulation::CSimulatorInfo getSelectedSimulator() const =0
Simulator.
SWIFT_GUI_EXPORT swift::gui::CGuiApplication * sGui
Single instance of GUI application object.
Classes interacting with the swift database (aka "datastore").
High level reusable GUI components.
Definition: aboutdialog.cpp:13
Models to be used with views, mainly QTableView.
Views, mainly QTableView.
GUI related classes.
Free functions in swift::misc.