swift
copymodelsfromotherswiftversionscomponent.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 <QFileInfo>
7 #include <QMessageBox>
8 #include <QPointer>
9 #include <QSet>
10 
11 #include "ui_copymodelsfromotherswiftversionscomponent.h"
12 
13 #include "core/application.h"
15 #include "misc/directoryutils.h"
16 #include "misc/fileutils.h"
17 #include "misc/stringutils.h"
18 #include "misc/swiftdirectories.h"
19 
20 using namespace swift::core;
21 using namespace swift::misc;
22 using namespace swift::misc::simulation;
23 using namespace swift::gui::models;
24 
25 namespace swift::gui::components
26 {
27  CCopyModelsFromOtherSwiftVersionsComponent::CCopyModelsFromOtherSwiftVersionsComponent(QWidget *parent)
29  {
30  ui->setupUi(this);
31  ui->comp_SimulatorSelector->setMode(CSimulatorSelector::CheckBoxes);
32  ui->comp_SimulatorSelector->clear();
33  ui->tvp_AircraftModels->setAircraftModelMode(CAircraftModelListModel::OwnModelSet);
34  connect(ui->pb_StartCopying, &QPushButton::clicked, this, &CCopyModelsFromOtherSwiftVersionsComponent::copy);
35  connect(ui->comp_OtherSwiftVersions, &COtherSwiftVersionsComponent::versionChanged, this,
36  &CCopyModelsFromOtherSwiftVersionsComponent::onVersionChanged);
37  }
38 
40 
41  void CCopyModelsFromOtherSwiftVersionsComponent::copy()
42  {
43  using namespace std::chrono_literals;
44 
45  const CSimulatorInfo selectedSimulators = ui->comp_SimulatorSelector->getValue();
46  const QSet<CSimulatorInfo> simulators = selectedSimulators.asSingleSimulatorSet();
47  if (simulators.isEmpty())
48  {
49  static const CStatusMessage m = CStatusMessage(this).validationError(u"No simulator(s) selected");
50  this->showOverlayMessage(m);
51  return;
52  }
53 
54  const bool set = ui->cb_ModelSet->isChecked();
55  const bool cache = ui->cb_ModelCache->isChecked();
56  if (!cache && !set)
57  {
58  static const CStatusMessage m =
59  CStatusMessage(this).validationError(u"No models selected (cache? model set?)");
60  this->showOverlayMessage(m);
61  return;
62  }
63 
64  if (!ui->comp_OtherSwiftVersions->hasSelection())
65  {
66  static const CStatusMessage m = CStatusMessage(this).validationError(u"No other version selected");
67  this->showOverlayMessage(m);
68  return;
69  }
70 
71  int sets = 0;
72  int caches = 0;
73  const CApplicationInfo otherVersion = ui->comp_OtherSwiftVersions->selectedOtherVersion();
74  for (const CSimulatorInfo &simulator : simulators)
75  {
76  if (set)
77  {
78  // inits current version cache
79  m_modelSetCaches.synchronizeCache(simulator);
80 
81  // get file name
82  CAircraftModelList otherSet;
83  const QString thisVersionModelSetFile = m_modelSetCaches.getFilename(simulator);
84  if (this->readDataFile(thisVersionModelSetFile, otherSet, otherVersion, simulator) &&
85  !otherSet.isEmpty())
86  {
87  CApplication::processEventsFor(250);
88  if (this->confirmOverride(QStringLiteral("Override model set for '%1'").arg(simulator.toQString())))
89  {
90  m_modelSetCaches.setModelsForSimulator(otherSet, simulator);
91  }
92  }
93  sets++;
94  } // set
95 
96  if (cache)
97  {
98  // inits current version cache
99  m_modelCaches.synchronizeCache(simulator);
100 
101  // get file name
102  CAircraftModelList otherCache;
103  const QString thisVersionModelCacheFile = m_modelCaches.getFilename(simulator);
104  if (this->readDataFile(thisVersionModelCacheFile, otherCache, otherVersion, simulator) &&
105  !otherCache.isEmpty())
106  {
107  CApplication::processEventsFor(250);
108  if (this->confirmOverride(
109  QStringLiteral("Override model cache for '%1'").arg(simulator.toQString())))
110  {
111  m_modelCaches.setModelsForSimulator(otherCache, simulator);
112  }
113  }
114  caches++;
115  }
116  } // all sims
117 
118  if (sets > 0 || caches > 0)
119  {
120  const CStatusMessage m = CStatusMessage(this).validationInfo(u"Copied %1 sets and %2 caches for '%3'")
121  << sets << caches << selectedSimulators.toQString(true);
122  this->showOverlayHTMLMessage(m, 7500ms);
123  }
124  }
125 
126  bool CCopyModelsFromOtherSwiftVersionsComponent::readDataFile(const QString &thisVersionModelFile,
127  CAircraftModelList &models,
128  const CApplicationInfo &otherVersion,
129  const CSimulatorInfo &sim)
130  {
131  // init
132  models.clear();
133 
134  // create relative file name
135  QString relativeModelFile = thisVersionModelFile;
136  relativeModelFile =
137  relativeModelFile.replace(CSwiftDirectories::applicationDataDirectory(), "", Qt::CaseInsensitive);
138  if (relativeModelFile.length() < 2) { return false; }
139  relativeModelFile = relativeModelFile.mid(relativeModelFile.indexOf('/', 1));
140 
141  const QString otherModelFile =
142  CFileUtils::appendFilePathsAndFixUnc(otherVersion.getApplicationDataDirectory(), relativeModelFile);
143  const QFileInfo fiOtherModelFile(otherModelFile);
144  if (!fiOtherModelFile.exists())
145  {
146  ui->le_Status->setText(QStringLiteral("No models here: '%1'").arg(fiOtherModelFile.absoluteFilePath()));
147  return false;
148  }
149 
150  // read other file
151  const QString jsonString = CFileUtils::readFileToString(fiOtherModelFile.absoluteFilePath());
152  if (jsonString.isEmpty()) { return false; }
153  try
154  {
155  models = CAircraftModelList::fromMultipleJsonFormats(jsonString);
156  ui->tvp_AircraftModels->updateContainerAsync(models);
157  ui->le_Status->setText(QStringLiteral("Imported models: '%1'").arg(fiOtherModelFile.absoluteFilePath()));
158  }
159  catch (const CJsonException &ex)
160  {
161  this->showOverlayMessage(CStatusMessage::fromJsonException(
162  ex, this, QStringLiteral("JSON format error. '%1'").arg(fiOtherModelFile.absoluteFilePath())));
163  return false;
164  }
165 
166  ui->le_Status->setText(QStringLiteral("Imported %1 models '%2' for %3")
167  .arg(models.size())
168  .arg(fiOtherModelFile.fileName(), sim.toQString()));
169  return true;
170  }
171 
172  bool CCopyModelsFromOtherSwiftVersionsComponent::confirmOverride(const QString &msg)
173  {
174  if (!sApp || sApp->isShuttingDown()) { return false; }
175  if (ui->cb_Silent->isChecked())
176  {
177  // allow UI updates
178  sApp->processEventsFor(50);
179  return true;
180  }
181  const QMessageBox::StandardButton reply = QMessageBox::question(
182  this, QStringLiteral("Confirm override"), withQuestionMark(msg), QMessageBox::Yes | QMessageBox::No);
183  return reply == QMessageBox::Yes;
184  }
185 
186  void CCopyModelsFromOtherSwiftVersionsComponent::onVersionChanged(const CApplicationInfo &otherVersion)
187  {
188  const CSimulatorInfo cacheSims = m_modelCaches.otherVersionSimulatorsWithFile(otherVersion);
189  const CSimulatorInfo setSims = m_modelSetCaches.otherVersionSimulatorsWithFile(otherVersion);
190 
191  ui->cb_ModelCache->setChecked(cacheSims.isAnySimulator());
192  ui->cb_ModelSet->setChecked(setSims.isAnySimulator());
193  ui->comp_SimulatorSelector->setValue(setSims);
194  }
195 
197  {
198  ui->comp_OtherSwiftVersions->reloadOtherVersionsDeferred(deferMs);
199  }
200 
202  {
203  // force reload as the other version could be changed
204  if (m_copyModels) { m_copyModels->reloadOtherVersions(1000); }
205  }
206 
208  {
209  Q_ASSERT_X(m_copyModels, Q_FUNC_INFO, "Missing widget");
210  return true;
211  }
212 } // namespace swift::gui::components
SWIFT_CORE_EXPORT swift::core::CApplication * sApp
Single instance of application object.
Definition: application.cpp:71
static void processEventsFor(int milliseconds)
Process all events for some time.
bool isShuttingDown() const
Is application shutting down?
bool showOverlayHTMLMessage(const QString &htmlMessage, std::chrono::milliseconds timeout=std::chrono::milliseconds(0))
HTML message.
bool showOverlayMessage(const swift::misc::CStatusMessage &message, std::chrono::milliseconds timeout=std::chrono::milliseconds(0))
Show single message.
Using this class provides a QFrame with the overlay functionality already integrated.
void versionChanged(const swift::misc::CApplicationInfo &info)
Selection changed.
Description of a swift application.
const QString & getApplicationDataDirectory() const
Set application data dir.
Thrown when a convertFromJson method encounters an unrecoverable error in JSON data.
Definition: jsonexception.h:24
Derived & validationError(const char16_t(&format)[N])
Set the severity to error, providing a format string, and adding the validation category.
Derived & validationInfo(const char16_t(&format)[N])
Set the severity to info, providing a format string, and adding the validation category.
size_type size() const
Returns number of elements in the sequence.
Definition: sequence.h:273
void clear()
Removes all elements in the sequence.
Definition: sequence.h:288
bool isEmpty() const
Synonym for empty.
Definition: sequence.h:285
Streamable status message, e.g.
QString toQString(bool i18n=false) const
Cast as QString.
Definition: mixinstring.h:76
Value object encapsulating a list of aircraft models.
Simple hardcoded info about the corresponding simulator.
Definition: simulatorinfo.h:41
QSet< CSimulatorInfo > asSingleSimulatorSet() const
As a set of single simulator info objects.
bool isAnySimulator() const
Any simulator?
CSimulatorInfo otherVersionSimulatorsWithFile(const swift::misc::CApplicationInfo &info) const
Simulators of given other versionwhich have a cache file.
Definition: modelcaches.cpp:98
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
Models to be used with views, mainly QTableView.
Free functions in swift::misc.
SWIFT_MISC_EXPORT QString withQuestionMark(const QString &question)
Add a question mark at the end if not existing.