swift
swiftlauncher.cpp
1 // SPDX-FileCopyrightText: Copyright (C) 2015 swift Project Community / Contributors
2 // SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-swift-pilot-client-1
3 
4 #include "swiftlauncher.h"
5 
6 #include <qcompilerdetection.h>
7 
8 #include <QBitmap>
9 #include <QDesktopServices>
10 #include <QMessageBox>
11 #include <QPixmap>
12 #include <QPointer>
13 #include <QProcess>
14 #include <QPushButton>
15 #include <QShortcut>
16 #include <QStringBuilder>
17 #include <QTimer>
18 
19 #include "ui_swiftlauncher.h"
20 
21 #include "config/buildconfig.h"
24 #include "core/setupreader.h"
27 #include "gui/guiapplication.h"
29 #include "gui/stylesheetutility.h"
30 #include "misc/dbusserver.h"
31 #include "misc/directoryutils.h"
32 #include "misc/icons.h"
33 #include "misc/loghandler.h"
34 #include "misc/logmessage.h"
38 #include "misc/swiftdirectories.h"
39 #include "sound/audioutilities.h"
40 
41 using namespace swift::config;
42 using namespace swift::gui;
43 using namespace swift::gui::components;
44 using namespace swift::core;
45 using namespace swift::core::context;
46 using namespace swift::core::data;
47 using namespace swift::sound;
48 using namespace swift::misc;
49 using namespace swift::misc::db;
50 using namespace swift::misc::network;
51 using namespace swift::misc::simulation;
52 using namespace swift::misc::simulation::data;
53 using namespace swift::misc::simulation::fscommon;
54 
55 CSwiftLauncher::CSwiftLauncher(bool installerMode, QWidget *parent)
56  : QMainWindow(parent, CEnableForFramelessWindow::modeToWindowFlags(CEnableForFramelessWindow::WindowNormal)),
57  CEnableForFramelessWindow(CEnableForFramelessWindow::WindowFrameless, true, "framelessMainWindow", this),
59 {
60  Q_ASSERT_X(sGui, Q_FUNC_INFO, "Need sGui");
62  ui->setupUi(this);
63  this->init(); // reads also defaults from settings
64 
65  connect(ui->tb_SwiftCore, &QPushButton::pressed, this, &CSwiftLauncher::startButtonPressed);
66  connect(ui->tb_SwiftMappingTool, &QPushButton::pressed, this, &CSwiftLauncher::startButtonPressed);
67  connect(ui->tb_SwiftGui, &QPushButton::pressed, this, &CSwiftLauncher::startButtonPressed);
68  connect(ui->tb_Database, &QPushButton::pressed, this, &CSwiftLauncher::startButtonPressed);
69  connect(ui->tb_BackToMain, &QToolButton::pressed, this, &CSwiftLauncher::showMainPage);
70  connect(ui->tb_ConfigurationWizard, &QToolButton::pressed, this, &CSwiftLauncher::startWizard);
71  connect(ui->tb_Launcher, &QToolBox::currentChanged, this, &CSwiftLauncher::tabChanged);
72 
73  connect(ui->rb_SwiftDistributed, &QRadioButton::released, this, &CSwiftLauncher::onCoreModeReleased,
74  Qt::QueuedConnection);
75  connect(ui->rb_SwiftStandalone, &QRadioButton::released, this, &CSwiftLauncher::onCoreModeReleased,
76  Qt::QueuedConnection);
77 
78  connect(ui->comp_UpdateInfo, &CUpdateInfoComponent::updateInfoAvailable, this, &CSwiftLauncher::updateInfoAvailable,
79  Qt::QueuedConnection);
80  connect(ui->comp_UpdateInfo, &CUpdateInfoComponent::newerPilotClientAvailable, this, &CSwiftLauncher::setHeaderInfo,
81  Qt::QueuedConnection);
82  connect(ui->comp_DBusSelector, &CDBusServerAddressSelector::editingFinished, this,
83  &CSwiftLauncher::onDBusEditingFinished, Qt::QueuedConnection);
84  connect(sGui, &CGuiApplication::styleSheetsChanged, this, &CSwiftLauncher::onStyleSheetsChanged,
85  Qt::QueuedConnection);
86 
87  connect(ui->pb_LogDir, &QPushButton::released, sGui, &CGuiApplication::openStandardLogDirectory,
88  Qt::QueuedConnection);
89  connect(ui->pb_DumpDir, &QPushButton::released, sGui, &CGuiApplication::openStandardCrashDumpDirectory,
90  Qt::QueuedConnection);
91  connect(ui->pb_Log, &QPushButton::released, this, &CSwiftLauncher::showLogPage, Qt::QueuedConnection);
92  connect(ui->pb_Log, &QPushButton::released, this, &CSwiftLauncher::showLogPage, Qt::QueuedConnection);
93  connect(ui->pb_FSXConfigDirs, &QPushButton::released, this, &CSwiftLauncher::showSimulatorConfigDirs,
94  Qt::QueuedConnection);
95  connect(ui->pb_P3DConfigDirs, &QPushButton::released, this, &CSwiftLauncher::showSimulatorConfigDirs,
96  Qt::QueuedConnection);
97 
98  const QShortcut *logPageShortCut =
99  new QShortcut(QKeySequence(static_cast<Qt::Key>(Qt::CTRL) + Qt::Key_L), this, SLOT(showLogPage()));
100  Q_UNUSED(logPageShortCut)
101 
102  // periodically check
103  connect(&m_checkTimer, &QTimer::timeout, this, &CSwiftLauncher::checkRunningApplicationsAndCore);
104  m_checkTimer.setInterval(2500);
105  m_checkTimer.start();
106 
107  // platform specific tool
108  ui->gb_ToolsWindows->setEnabled(CBuildConfig::isRunningOnWindowsNtPlatform());
109  if (CBuildConfig::isRunningOnWindowsNtPlatform())
110  {
111  connect(ui->pb_ClearRegistry, &QPushButton::released, this, &CSwiftLauncher::clearWindowsRegistry);
112  }
113 
114  const QPointer<CSwiftLauncher> myself(this);
115  if (installerMode)
116  {
117  QTimer::singleShot(1000, this, [=] {
118  if (!sGui || sGui->isShuttingDown() || !myself) { return; }
119  ui->fr_SwiftLauncherMain->showOverlayHTMLMessage("Checking installation!<br>One moment please ....");
120  this->raise();
121  });
122  }
123 
124  // auto launch wizard and other init parts
125  QTimer::singleShot(2500, this, [=] {
126  if (!sGui || sGui->isShuttingDown() || !myself) { return; }
127  this->onCoreModeReleased();
128  this->requestMacMicrophoneAccess();
129  if (installerMode) this->installerMode();
130  });
131 
132  this->show();
133 }
134 
135 void CSwiftLauncher::installerMode()
136 {
137  if (!sGui || sGui->isShuttingDown()) { return; }
138 
139  bool runDialog = false;
140  do {
141  const QDir dir = CSwiftDirectories::logDirectory();
142  if (!dir.exists()) { break; }
143 
144  for (const CSimulatorInfo &sim : CSimulatorInfo::allSimulatorsSet())
145  {
146  this->synchronizeCache(sim);
147  const int c = this->getCachedModelsCount(sim);
148  if (c > 0)
149  {
150  // we already have data
151  runDialog = true;
152  break;
153  }
154  }
155  }
156  while (false);
157 
158  bool startWizard = true;
159  ui->fr_SwiftLauncherMain->closeOverlay();
160 
161  if (runDialog)
162  {
163  const QMessageBox::StandardButton ret =
164  QMessageBox::question(this, tr("swift configuration"),
165  tr("This installation directory already contains a swift configuration.\n"
166  "Do you want to use that one?"));
167  if (ret != QMessageBox::No) { startWizard = false; }
168  }
169 
170  if (startWizard) { this->startWizard(); }
171 }
172 
173 void CSwiftLauncher::clearWindowsRegistry()
174 {
175  if (!CBuildConfig::isRunningOnWindowsNtPlatform()) { return; }
176  const QMessageBox::StandardButton ret =
177  QMessageBox::warning(this, tr("Registry swift applications"),
178  tr("Do you really want to delete all entries?\nThis cannot be undone!"),
179  QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel, QMessageBox::No);
180  if (ret != QMessageBox::Yes) { return; }
181  CGuiApplication::removeAllWindowsSwiftRegistryEntries();
182 }
183 
185 
186 QString CSwiftLauncher::getCmdLine() const { return this->toCmdLine(m_executable, m_executableArgs); }
187 
189 {
190  if (m_executable.isEmpty()) { return false; }
191  const QString cmd = this->getCmdLine();
192  CLogMessage(this).info(cmd);
193  return QProcess::startDetached(m_executable, m_executableArgs);
194 }
195 
196 CEnableForFramelessWindow::WindowMode CSwiftLauncher::getWindowMode() const
197 {
198  if (ui->rb_WindowFrameless->isChecked()) { return CEnableForFramelessWindow::WindowFrameless; }
199  return CEnableForFramelessWindow::WindowNormal;
200 }
201 
202 CoreModes::CoreMode CSwiftLauncher::getCoreMode() const
203 {
204  if (ui->rb_SwiftStandalone->isChecked()) { return CoreModes::Standalone; }
205  if (ui->rb_SwiftDistributed->isChecked()) { return CoreModes::Distributed; }
206 
207  Q_ASSERT_X(false, Q_FUNC_INFO, "wrong mode");
208  return CoreModes::Standalone;
209 }
210 
211 void CSwiftLauncher::mousePressEvent(QMouseEvent *event)
212 {
213  if (!handleMousePressEvent(event)) { QMainWindow::mousePressEvent(event); }
214 }
215 
216 void CSwiftLauncher::mouseMoveEvent(QMouseEvent *event)
217 {
218  if (!handleMouseMoveEvent(event)) { QMainWindow::mouseMoveEvent(event); }
219 }
220 
221 void CSwiftLauncher::mouseReleaseEvent(QMouseEvent *event)
222 {
223  m_framelessDragPosition = QPoint();
224  QMainWindow::mouseReleaseEvent(event);
225 }
226 
227 void CSwiftLauncher::updateInfoAvailable()
228 {
229  this->setHeaderInfo(ui->comp_UpdateInfo->getLatestAvailablePilotClientArtifactForSelection());
230 }
231 
232 void CSwiftLauncher::init()
233 {
234  Q_ASSERT_X(sGui, Q_FUNC_INFO, "Need sGui");
236 
237  m_mwaOverlayFrame = ui->fr_SwiftLauncherMain;
238  m_mwaStatusBar = nullptr;
239  m_mwaLogComponent = ui->comp_SwiftLauncherLog;
240 
241  this->initStyleSheet();
242  this->initLogDisplay();
243  this->setDefaults();
244 
245  ui->lbl_HeaderInfo->setVisible(false);
246  ui->sw_SwiftLauncher->setCurrentWidget(ui->pg_SwiftLauncherMain);
247  ui->tb_Launcher->setCurrentWidget(ui->pg_CoreMode);
248 }
249 
250 void CSwiftLauncher::initStyleSheet()
251 {
252  if (!sGui || sGui->isShuttingDown()) { return; }
253  const QString s = sGui->getStyleSheetUtility().styles({ CStyleSheetUtility::fileNameFonts(),
254  CStyleSheetUtility::fileNameStandardWidget(),
255  CStyleSheetUtility::fileNameSwiftLauncher() });
256  this->setStyleSheet(""); // clear, otherwise launcher crashing
257  this->setStyleSheet(s);
258 }
259 
260 void CSwiftLauncher::initLogDisplay()
261 {
262  CLogHandler::instance()->install(true);
263  CLogHandler::instance()->enableConsoleOutput(false); // default disable
264 
265  ui->comp_SwiftLauncherLog->showFilterBar();
266  ui->comp_SwiftLauncherLog->filterUseRadioButtonDescriptiveIcons(false);
267 
268  m_logHistory.setFilter(CLogPattern().withSeverity(CStatusMessage::SeverityError));
269  connect(&m_logHistory, &CLogHistoryReplica::elementAdded, this,
270  qOverload<const CStatusMessage &>(&CSwiftLauncher::showStatusMessage));
271  m_logHistory.initialize(sApp->getDataLinkDBus());
272 }
273 
274 void CSwiftLauncher::setHeaderInfo(const CArtifact &latestArtifact)
275 {
276  const bool isNewer = latestArtifact.isNewerThanCurrentBuild();
277  ui->lbl_HeaderInfo->setVisible(isNewer);
278  if (isNewer)
279  {
280  static const QString t("New version '%1' ['%2'/'%3']");
281  ui->lbl_HeaderInfo->setText(t.arg(latestArtifact.getVersion(), latestArtifact.getPlatform().getPlatformName(),
282  latestArtifact.getMostStableDistribution().getChannel()));
283  ui->lbl_HeaderInfo->setStyleSheet("background: red; color: yellow;");
284  }
285 }
286 
287 bool CSwiftLauncher::setSwiftCoreExecutable()
288 {
289  if (!sGui || sGui->isShuttingDown()) { return false; }
290  this->saveSetup();
291  QStringList args = ui->comp_DBusSelector->getDBusCmdLineArgs();
292  if (ui->cb_ResetWindow->isChecked()) { args.append("--resetsize"); }
293  if (ui->cb_DisableCoreAudio->isChecked()) { args.append("--noaudio"); }
294 
295  m_executableArgs = sGui->argumentsJoined(args);
296  m_executable = CSwiftDirectories::executableFilePath(CBuildConfig::swiftCoreExecutableName());
297  return true;
298 }
299 
300 bool CSwiftLauncher::setSwiftDataExecutable()
301 {
302  m_executable = CSwiftDirectories::executableFilePath(CBuildConfig::swiftDataExecutableName());
303 
304  QStringList fsdArgs;
305 #ifdef SWIFT_VATSIM_SUPPORT
306  int id = 0;
307  QString key;
308  if (IContextNetwork::getCmdLineClientIdAndKey(id, key))
309  {
310  // from cmd. line
311  fsdArgs << "--idAndKey";
312  fsdArgs << sApp->getParserValue("clientIdAndKey"); // as typed in
313  }
314 #endif
315 
316  m_executableArgs = sGui->argumentsJoined({}, fsdArgs);
317  return true;
318 }
319 
320 bool CSwiftLauncher::setSwiftGuiExecutable()
321 {
322  if (!sGui || sGui->isShuttingDown()) { return false; }
323  m_executable = CSwiftDirectories::executableFilePath(CBuildConfig::swiftGuiExecutableName());
324  QStringList args { "--core", CoreModes::coreModeToString(getCoreMode()), "--window",
325  CEnableForFramelessWindow::windowModeToString(getWindowMode()) };
326 
327  if (ui->cb_ResetWindow->isChecked()) { args << "--resetsize"; }
328  if (this->isStandaloneGuiSelected())
329  {
330  if (ui->cb_DisableSaAfv->isChecked()) { args.append("--noaudio"); }
331  }
332  else
333  {
334  if (ui->cb_DisableGUIAfv->isChecked()) { args.append("--noaudio"); }
335 
336  const QString dBus(ui->comp_DBusSelector->getDBusAddress());
337  args.append(ui->comp_DBusSelector->getDBusCmdLineArgs());
338  this->saveSetup();
339 
340  QString msg;
341  if (!CSwiftLauncher::canConnectSwiftOnDBusServer(dBus, msg))
342  {
343  const CStatusMessage m(this, CStatusMessage::SeverityError,
344  "DBus server for '" + dBus + "' can not be connected.\n" +
345  "Likely the core is not running or is not reachable.\n" + "Details: " + msg,
346  true);
347  this->showStatusMessage(m);
348  return false;
349  }
350  }
351  this->saveSetup();
352  m_executableArgs = sGui->argumentsJoined(args);
353  return true;
354 }
355 
356 bool CSwiftLauncher::canConnectSwiftOnDBusServer(const QString &dBusAddress, QString &msg) const
357 {
358  if (this->isStandaloneGuiSelected()) { return true; } // do not mind here
359  return CContextApplicationProxy::isContextResponsive(dBusAddress, msg);
360 }
361 
362 bool CSwiftLauncher::isStandaloneGuiSelected() const { return ui->rb_SwiftStandalone->isChecked(); }
363 
364 void CSwiftLauncher::setDefaults()
365 {
366  const CLauncherSetup setup(m_setup.get());
367  const QString dbus(setup.getDBusAddress().toLower().trimmed());
368  ui->comp_DBusSelector->set(dbus);
369 
370  ui->rb_WindowFrameless->setChecked(setup.useFramelessWindow());
371  ui->rb_WindowNormal->setChecked(!setup.useFramelessWindow());
372 
373  const CLauncherSetup::CoreMode mode = setup.getCoreMode();
374  ui->rb_SwiftStandalone->setChecked(mode == CLauncherSetup::Standalone ? true : false);
375  ui->rb_SwiftDistributed->setChecked(mode == CLauncherSetup::Distributed ? true : false);
376 
377  const CLauncherSetup::AudioMode audio = setup.getAudioMode();
378  ui->cb_DisableCoreAudio->setChecked(audio.testFlag(CLauncherSetup::AudioDisableDistributedCoreAudio));
379  ui->cb_DisableGUIAfv->setChecked(audio.testFlag(CLauncherSetup::AudioDisableDistributedGuiAudio));
380  ui->cb_DisableSaAfv->setChecked(audio.testFlag(CLauncherSetup::AudioDisableStandaloneAudio));
381 }
382 
383 void CSwiftLauncher::saveSetup()
384 {
385  CLauncherSetup setup = m_setup.get();
386  const QString dBus(ui->comp_DBusSelector->getDBusAddress());
387  if (!dBus.isEmpty()) { setup.setDBusAddress(dBus); }
388  setup.setFramelessWindow(ui->rb_WindowFrameless->isChecked());
389  setup.setCoreMode(CLauncherSetup::Standalone);
390 
391  CLauncherSetup::AudioMode audio = CLauncherSetup::AudioNothingDisabled;
392  audio.setFlag(CLauncherSetup::AudioDisableDistributedCoreAudio, ui->cb_DisableCoreAudio->isChecked());
393  audio.setFlag(CLauncherSetup::AudioDisableDistributedGuiAudio, ui->cb_DisableGUIAfv->isChecked());
394  audio.setFlag(CLauncherSetup::AudioDisableStandaloneAudio, ui->cb_DisableSaAfv->isChecked());
395  setup.setAudioMode(audio);
396 
397  if (ui->rb_SwiftDistributed->isChecked()) { setup.setCoreMode(CLauncherSetup::Distributed); }
398 
399  const CStatusMessage msg = m_setup.set(setup);
400  Q_UNUSED(msg)
401 }
402 
403 bool CSwiftLauncher::warnAboutOtherSwiftApplications()
404 {
405  CApplicationInfoList running = CGuiApplication::getRunningApplications();
406  running.removeApplication(CApplicationInfo::Launcher);
407  if (running.isEmpty()) { return true; }
408 
409  // getting here means another application is running
410  const QString msg = u"While using the wizard no other application should run.\nClose applications and try "
411  u"again.\nCurrently running: " %
412  running.processNames().join(',');
413  QMessageBox::question(this, "Wizard", msg, QMessageBox::Close);
414  return false;
415 }
416 
417 QString CSwiftLauncher::toCmdLine(const QString &exe, const QStringList &exeArgs)
418 {
419  if (exeArgs.isEmpty()) { return exe; }
420  const QString exeArgsString = exeArgs.join(' ');
421  const QString cmd(exe + " " + exeArgsString);
422  return cmd;
423 }
424 
425 void CSwiftLauncher::startButtonPressed()
426 {
427  const QObject *sender = QObject::sender();
428  const qreal scaleFactor = ui->comp_Scale->getScaleFactor();
429  CGuiApplication::highDpiScreenSupport(QString::number(scaleFactor, 'f', 4));
430 
431  const Qt::KeyboardModifiers km = QGuiApplication::queryKeyboardModifiers();
432  const bool shift = km.testFlag(Qt::ShiftModifier);
433 
434  if (sender == ui->tb_SwiftGui)
435  {
436  if (this->setSwiftGuiExecutable())
437  {
438  if (shift) { this->popupExecutableArgs(); }
439  else { close(); }
440  }
441  }
442  else if (sender == ui->tb_SwiftMappingTool)
443  {
444  ui->tb_SwiftMappingTool->setEnabled(false);
445  m_startMappingToolWaitCycles = 2;
446  if (this->setSwiftDataExecutable())
447  {
448  if (shift) { this->popupExecutableArgs(); }
449  else { close(); }
450  }
451  }
452  else if (sender == ui->tb_SwiftCore)
453  {
454  if (this->isStandaloneGuiSelected()) { ui->rb_SwiftDistributed->setChecked(true); }
455  ui->tb_SwiftCore->setEnabled(false);
456  m_startCoreWaitCycles = 2;
457  if (this->setSwiftCoreExecutable())
458  {
459  if (shift) { this->popupExecutableArgs(); }
460  else { this->startDetached(); }
461  }
462  }
463  else if (sender == ui->tb_Database)
464  {
465  const CUrl homePage(sApp->getGlobalSetup().getDbHomePageUrl());
466  QDesktopServices::openUrl(homePage);
467  }
468 }
469 
470 void CSwiftLauncher::dbusServerModeSelected(bool selected)
471 {
472  if (!selected) { return; }
473  if (!this->isStandaloneGuiSelected()) { return; }
474  ui->rb_SwiftDistributed->setChecked(true);
475 }
476 
477 void CSwiftLauncher::showStatusMessage(const CStatusMessage &msg)
478 {
479  using namespace std::chrono_literals;
480  ui->fr_SwiftLauncherMain->showOverlayMessage(msg, 5s);
481 }
482 
483 void CSwiftLauncher::showStatusMessage(const QString &htmlMsg)
484 {
485  using namespace std::chrono_literals;
486  ui->fr_SwiftLauncherMain->showOverlayMessage(htmlMsg, 5s);
487 }
488 
489 void CSwiftLauncher::showMainPage() { ui->sw_SwiftLauncher->setCurrentWidget(ui->pg_SwiftLauncherMain); }
490 
491 void CSwiftLauncher::tabChanged(int current)
492 {
493  if (current == static_cast<int>(PageUpdates)) { ui->comp_DataUpdates->display(); }
494 }
495 
496 void CSwiftLauncher::showLogPage() { ui->sw_SwiftLauncher->setCurrentWidget(ui->pg_SwiftLauncherLog); }
497 
498 void CSwiftLauncher::checkRunningApplicationsAndCore()
499 {
500  // wait some time before buttons are enabled (allows startup)
501  if (m_startCoreWaitCycles > 0) { m_startCoreWaitCycles--; }
502  if (m_startMappingToolWaitCycles > 0) { m_startMappingToolWaitCycles--; }
503  if (m_startGuiWaitCycles > 0) { m_startGuiWaitCycles--; }
504 
505  const CApplicationInfoList runningApps = sGui->getRunningApplications();
506  const bool foundLocalCore = runningApps.containsApplication(CApplicationInfo::PilotClientCore);
507  const bool foundLocalMappingTool = runningApps.containsApplication(CApplicationInfo::MappingTool);
508  const bool foundLocalPilotClientGui = runningApps.containsApplication(CApplicationInfo::PilotClientGui);
509  const bool standalone = ui->rb_SwiftStandalone->isChecked();
510 
511  ui->tb_SwiftCore->setEnabled(!standalone && !foundLocalCore && m_startCoreWaitCycles < 1);
512  ui->tb_SwiftMappingTool->setEnabled(!foundLocalMappingTool && m_startMappingToolWaitCycles < 1);
513  ui->tb_SwiftGui->setEnabled(!foundLocalPilotClientGui && m_startGuiWaitCycles < 1);
514 }
515 
516 void CSwiftLauncher::startWizard()
517 {
518  const bool show = this->warnAboutOtherSwiftApplications();
519  if (!show) { return; }
520  if (!m_wizard) { m_wizard.reset(new CConfigurationWizard(this)); }
521  m_wizard->show();
522  CGuiUtility::centerWidget(m_wizard.data(), this);
523 }
524 
525 void CSwiftLauncher::onStyleSheetsChanged() { this->initStyleSheet(); }
526 
527 void CSwiftLauncher::onDBusEditingFinished() { ui->rb_SwiftDistributed->setChecked(true); }
528 
529 void CSwiftLauncher::onCoreModeReleased()
530 {
531  const bool sa = ui->rb_SwiftStandalone->isChecked();
532  ui->comp_DBusSelector->setEnabled(!sa);
533  ui->tb_SwiftCore->setEnabled(!sa);
534  ui->gb_AudioSa->setEnabled(sa);
535  ui->gb_AudioDistributed->setEnabled(!sa);
536  this->saveSetup();
537 }
538 
539 void CSwiftLauncher::popupExecutableArgs() { QMessageBox::information(this, "Command line", this->getCmdLine()); }
540 
541 void CSwiftLauncher::showSimulatorConfigDirs()
542 {
543  if (!m_textEditDialog) { m_textEditDialog.reset(new CTextEditDialog(this)); }
544 
545  const QObject *s = QObject::sender();
546  QStringList dirs;
547  QString simDir;
548  QString simObjDir;
549 
550  if (s == ui->pb_P3DConfigDirs)
551  {
552  simDir = CFsDirectories::p3dDir();
553  simObjDir = CFsDirectories::p3dSimObjectsDir();
554  const QString versionHint = CFsDirectories::guessP3DVersion(simDir);
555  dirs = CFsDirectories::p3dSimObjectsDirPlusAddOnXmlSimObjectsPaths(simObjDir, versionHint);
556  }
557  else if (s == ui->pb_FSXConfigDirs)
558  {
559  dirs = CFsDirectories::fsxSimObjectsDirPlusAddOnXmlSimObjectsPaths();
560  simDir = CFsDirectories::fsxDir();
561  simObjDir = CFsDirectories::fsxSimObjectsDir();
562  }
563 
564  const QString info = u"Sim.dir: " % simDir % "\n" % u"Sim.objects: " % simObjDir % "\n" %
565  (dirs.isEmpty() ? "No dirs" : dirs.join("\n"));
566 
567  m_textEditDialog->setReadOnly();
568  m_textEditDialog->textEdit()->setText(info);
569  m_textEditDialog->show();
570 }
571 
572 bool CSwiftLauncher::shouldStartAppDetached() const { return !m_executable.isEmpty(); }
573 
574 void CSwiftLauncher::requestMacMicrophoneAccess()
575 {
576  // needed to be able to start core/GUI which need MIC access
577  // https://discordapp.com/channels/539048679160676382/567983892791951374/634806582013591603
578 #ifdef Q_OS_MAC
579  const CMacOSMicrophoneAccess::AuthorizationStatus status = m_micAccess.getAuthorizationStatus();
580  if (status == CMacOSMicrophoneAccess::Authorized) { return; }
581  m_micAccess.requestAccess();
582  CLogMessage(this).info(u"MacOS requested input device");
583 #endif
584 }
SWIFT_CORE_EXPORT swift::core::CApplication * sApp
Single instance of application object.
Definition: application.cpp:71
swift launcher tool
Definition: swiftlauncher.h:51
virtual void mouseReleaseEvent(QMouseEvent *event)
Mouse events for frameless window.
virtual void mouseMoveEvent(QMouseEvent *event)
Mouse events for frameless window.
virtual ~CSwiftLauncher()
Destructor.
CSwiftLauncher(bool installerMode, QWidget *parent=nullptr)
Constructor.
bool shouldStartAppDetached() const
Check if an app is set that should be started detached.
bool startDetached()
Start currently set application detached.
virtual void mousePressEvent(QMouseEvent *event)
Mouse events for frameless window.
QString getCmdLine() const
Current command line.
QStringList argumentsJoined(const QStringList &newArguments={}, const QStringList &removeArguments={}) const
Current parameters replaced by new arguments without the cmd line argument.
swift::misc::shared_state::CDataLinkDBus * getDataLinkDBus()
Transport mechanism for sharing state between applications.
QString getParserValue(const QString &option) const
Delegates to QCommandLineParser::value.
data::CGlobalSetup getGlobalSetup() const
Global setup.
bool isShuttingDown() const
Is application shutting down?
static swift::misc::CApplicationInfoList getRunningApplications()
Information about all running apps (including this one only if exec() has already been called)
swift::misc::network::CUrl getDbHomePageUrl() const
Home page url.
Definition: globalsetup.cpp:42
void setAudioMode(AudioMode mode)
Audio mode.
Definition: launchersetup.h:71
void setCoreMode(CoreMode mode)
Core mode.
Definition: launchersetup.h:65
void setFramelessWindow(bool frameless)
Frameless window?
Definition: launchersetup.h:77
void setDBusAddress(const QString &dBusAddress)
DBus address.
Definition: launchersetup.h:59
Main window which can be frameless.
bool handleMousePressEvent(QMouseEvent *event)
Mouse press, required for frameless window.
QPoint m_framelessDragPosition
position, if moving is handled with frameless window
bool handleMouseMoveEvent(QMouseEvent *event)
Mouse moving, required for frameless window.
void registerMainApplicationWidget(QWidget *mainWidget)
Register main application window widget if this is known.
const CStyleSheetUtility & getStyleSheetUtility() const
Style sheet handling.
void initMainApplicationWidget(QWidget *mainWidget)
Init the main application window based on information in this application.
QString styles(const QStringList &fileNames) const
Multiple styles concatenated.
CManagedStatusBar * m_mwaStatusBar
status bar if any
components::CLogComponent * m_mwaLogComponent
the log component if any
COverlayMessagesFrame * m_mwaOverlayFrame
overlay messages if any
Configure the most important settings.
List of swift application descriptions.
QStringList processNames() const
Running application names.
bool containsApplication(CApplicationInfo::Application application) const
List containing entry for CApplicationInfo::Application ?
int removeApplication(CApplicationInfo::Application application)
Remove given application.
T get() const
Get a copy of the current value.
Definition: valuecache.h:408
CStatusMessage set(const typename Trait::type &value, qint64 timestamp=0)
Write a new value. Must be called from the thread in which the owner lives.
Definition: datacache.h:350
Base class with a member CIdentifier to be inherited by a class which has an identity in the environm...
Definition: identifiable.h:24
Class for emitting a log message.
Definition: logmessage.h:27
Value class for matching log messages based on their categories.
Definition: logpattern.h:49
AuthorizationStatus
Authorization status.
Derived & info(const char16_t(&format)[N])
Set the severity to info, providing a format string.
QString getPlatformName() const
Name of platform.
Definition: platform.cpp:53
bool isEmpty() const
Synonym for empty.
Definition: sequence.h:285
Streamable status message, e.g.
Artifacts ("our software" products)
Definition: artifact.h:23
const CPlatform & getPlatform() const
OS.
Definition: artifact.h:89
bool isNewerThanCurrentBuild() const
Newer than the current build.
Definition: artifact.cpp:72
CDistribution getMostStableDistribution() const
Most stable distribution if any.
Definition: artifact.h:101
const QString & getChannel() const
Version channel (Alpha, Beta, Stable ..)
Definition: distribution.h:45
const QString & getVersion() const
Version info.
Definition: datastore.h:48
Value object encapsulating information of a location, kind of simplified CValueObject compliant versi...
Definition: url.h:27
void setFilter(const U &filter)
Set filter to choose list elements.
Definition: listobserver.h:77
virtual void initialize(IDataLink *dataLink)
Subscribe using the given transport mechanism.
Definition: listobserver.h:70
Simple hardcoded info about the corresponding simulator.
Definition: simulatorinfo.h:41
Basically a QObject free (delegate based) version of CCentralMultiSimulatorModelSetCachesProvider.
Definition: modelcaches.h:640
int getCachedModelsCount(const CSimulatorInfo &simulator) const
Look like IMultiSimulatorModelCaches interface.
Definition: modelcaches.h:648
void synchronizeCache(const CSimulatorInfo &simulator)
Look like IMultiSimulatorModelCaches interface.
Definition: modelcaches.h:674
SWIFT_GUI_EXPORT swift::gui::CGuiApplication * sGui
Single instance of GUI application object.
Core data traits (aka cached values) and classes.
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
GUI related classes.
Free functions in swift::misc.
auto singleShot(int msec, QObject *target, F &&task)
Starts a single-shot timer which will call a task in the thread of the given object when it times out...
Definition: threadutils.h:30
CoreMode
Core runs how and where?
Definition: coremodeenums.h:18