6 #include <qcompilerdetection.h>
9 #include <QDesktopServices>
10 #include <QMessageBox>
14 #include <QPushButton>
16 #include <QStringBuilder>
19 #include "ui_swiftlauncher.h"
41 using namespace swift::config;
45 using namespace swift::core::context;
47 using namespace swift::sound;
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;
60 Q_ASSERT_X(
sGui, Q_FUNC_INFO,
"Need sGui");
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);
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);
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);
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);
98 const QShortcut *logPageShortCut =
99 new QShortcut(QKeySequence(
static_cast<Qt::Key
>(Qt::CTRL) + Qt::Key_L),
this, SLOT(showLogPage()));
100 Q_UNUSED(logPageShortCut)
103 connect(&m_checkTimer, &QTimer::timeout,
this, &CSwiftLauncher::checkRunningApplicationsAndCore);
104 m_checkTimer.setInterval(2500);
105 m_checkTimer.start();
108 ui->gb_ToolsWindows->setEnabled(CBuildConfig::isRunningOnWindowsNtPlatform());
109 if (CBuildConfig::isRunningOnWindowsNtPlatform())
111 connect(ui->pb_ClearRegistry, &QPushButton::released,
this, &CSwiftLauncher::clearWindowsRegistry);
114 const QPointer<CSwiftLauncher> myself(
this);
119 ui->fr_SwiftLauncherMain->showOverlayHTMLMessage(
"Checking installation!<br>One moment please ....");
127 this->onCoreModeReleased();
128 this->requestMacMicrophoneAccess();
129 if (installerMode) this->installerMode();
135 void CSwiftLauncher::installerMode()
139 bool runDialog =
false;
141 const QDir dir = CSwiftDirectories::logDirectory();
142 if (!dir.exists()) {
break; }
144 for (
const CSimulatorInfo &sim : CSimulatorInfo::allSimulatorsSet())
158 bool startWizard =
true;
159 ui->fr_SwiftLauncherMain->closeOverlay();
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; }
170 if (startWizard) { this->startWizard(); }
173 void CSwiftLauncher::clearWindowsRegistry()
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();
190 if (m_executable.isEmpty()) {
return false; }
193 return QProcess::startDetached(m_executable, m_executableArgs);
198 if (ui->rb_WindowFrameless->isChecked()) {
return CEnableForFramelessWindow::WindowFrameless; }
199 return CEnableForFramelessWindow::WindowNormal;
204 if (ui->rb_SwiftStandalone->isChecked()) {
return CoreModes::Standalone; }
205 if (ui->rb_SwiftDistributed->isChecked()) {
return CoreModes::Distributed; }
207 Q_ASSERT_X(
false, Q_FUNC_INFO,
"wrong mode");
208 return CoreModes::Standalone;
224 QMainWindow::mouseReleaseEvent(event);
227 void CSwiftLauncher::updateInfoAvailable()
229 this->setHeaderInfo(ui->comp_UpdateInfo->getLatestAvailablePilotClientArtifactForSelection());
232 void CSwiftLauncher::init()
234 Q_ASSERT_X(
sGui, Q_FUNC_INFO,
"Need sGui");
241 this->initStyleSheet();
242 this->initLogDisplay();
245 ui->lbl_HeaderInfo->setVisible(
false);
246 ui->sw_SwiftLauncher->setCurrentWidget(ui->pg_SwiftLauncherMain);
247 ui->tb_Launcher->setCurrentWidget(ui->pg_CoreMode);
250 void CSwiftLauncher::initStyleSheet()
254 CStyleSheetUtility::fileNameStandardWidget(),
255 CStyleSheetUtility::fileNameSwiftLauncher() });
256 this->setStyleSheet(
"");
257 this->setStyleSheet(s);
260 void CSwiftLauncher::initLogDisplay()
262 CLogHandler::instance()->install(
true);
263 CLogHandler::instance()->enableConsoleOutput(
false);
265 ui->comp_SwiftLauncherLog->showFilterBar();
266 ui->comp_SwiftLauncherLog->filterUseRadioButtonDescriptiveIcons(
false);
269 connect(&m_logHistory, &CLogHistoryReplica::elementAdded,
this,
270 qOverload<const CStatusMessage &>(&CSwiftLauncher::showStatusMessage));
274 void CSwiftLauncher::setHeaderInfo(
const CArtifact &latestArtifact)
277 ui->lbl_HeaderInfo->setVisible(isNewer);
280 static const QString t(
"New version '%1' ['%2'/'%3']");
283 ui->lbl_HeaderInfo->setStyleSheet(
"background: red; color: yellow;");
287 bool CSwiftLauncher::setSwiftCoreExecutable()
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"); }
296 m_executable = CSwiftDirectories::executableFilePath(CBuildConfig::swiftCoreExecutableName());
300 bool CSwiftLauncher::setSwiftDataExecutable()
302 m_executable = CSwiftDirectories::executableFilePath(CBuildConfig::swiftDataExecutableName());
305 #ifdef SWIFT_VATSIM_SUPPORT
308 if (IContextNetwork::getCmdLineClientIdAndKey(
id, key))
311 fsdArgs <<
"--idAndKey";
320 bool CSwiftLauncher::setSwiftGuiExecutable()
323 m_executable = CSwiftDirectories::executableFilePath(CBuildConfig::swiftGuiExecutableName());
324 QStringList args {
"--core", CoreModes::coreModeToString(getCoreMode()),
"--window",
325 CEnableForFramelessWindow::windowModeToString(getWindowMode()) };
327 if (ui->cb_ResetWindow->isChecked()) { args <<
"--resetsize"; }
328 if (this->isStandaloneGuiSelected())
330 if (ui->cb_DisableSaAfv->isChecked()) { args.append(
"--noaudio"); }
334 if (ui->cb_DisableGUIAfv->isChecked()) { args.append(
"--noaudio"); }
336 const QString dBus(ui->comp_DBusSelector->getDBusAddress());
337 args.append(ui->comp_DBusSelector->getDBusCmdLineArgs());
341 if (!CSwiftLauncher::canConnectSwiftOnDBusServer(dBus, msg))
344 "DBus server for '" + dBus +
"' can not be connected.\n" +
345 "Likely the core is not running or is not reachable.\n" +
"Details: " + msg,
347 this->showStatusMessage(m);
356 bool CSwiftLauncher::canConnectSwiftOnDBusServer(
const QString &dBusAddress, QString &msg)
const
358 if (this->isStandaloneGuiSelected()) {
return true; }
359 return CContextApplicationProxy::isContextResponsive(dBusAddress, msg);
362 bool CSwiftLauncher::isStandaloneGuiSelected()
const {
return ui->rb_SwiftStandalone->isChecked(); }
364 void CSwiftLauncher::setDefaults()
367 const QString dbus(setup.getDBusAddress().toLower().trimmed());
368 ui->comp_DBusSelector->set(dbus);
370 ui->rb_WindowFrameless->setChecked(setup.useFramelessWindow());
371 ui->rb_WindowNormal->setChecked(!setup.useFramelessWindow());
374 ui->rb_SwiftStandalone->setChecked(mode == CLauncherSetup::Standalone ?
true :
false);
375 ui->rb_SwiftDistributed->setChecked(mode == CLauncherSetup::Distributed ?
true :
false);
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));
383 void CSwiftLauncher::saveSetup()
386 const QString dBus(ui->comp_DBusSelector->getDBusAddress());
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());
397 if (ui->rb_SwiftDistributed->isChecked()) { setup.
setCoreMode(CLauncherSetup::Distributed); }
403 bool CSwiftLauncher::warnAboutOtherSwiftApplications()
407 if (running.
isEmpty()) {
return true; }
410 const QString msg = u
"While using the wizard no other application should run.\nClose applications and try "
411 u
"again.\nCurrently running: " %
413 QMessageBox::question(
this,
"Wizard", msg, QMessageBox::Close);
417 QString CSwiftLauncher::toCmdLine(
const QString &exe,
const QStringList &exeArgs)
419 if (exeArgs.isEmpty()) {
return exe; }
420 const QString exeArgsString = exeArgs.join(
' ');
421 const QString cmd(exe +
" " + exeArgsString);
425 void CSwiftLauncher::startButtonPressed()
427 const QObject *sender = QObject::sender();
428 const qreal scaleFactor = ui->comp_Scale->getScaleFactor();
429 CGuiApplication::highDpiScreenSupport(QString::number(scaleFactor,
'f', 4));
431 const Qt::KeyboardModifiers km = QGuiApplication::queryKeyboardModifiers();
432 const bool shift = km.testFlag(Qt::ShiftModifier);
434 if (sender == ui->tb_SwiftGui)
436 if (this->setSwiftGuiExecutable())
438 if (shift) { this->popupExecutableArgs(); }
442 else if (sender == ui->tb_SwiftMappingTool)
444 ui->tb_SwiftMappingTool->setEnabled(
false);
445 m_startMappingToolWaitCycles = 2;
446 if (this->setSwiftDataExecutable())
448 if (shift) { this->popupExecutableArgs(); }
452 else if (sender == ui->tb_SwiftCore)
454 if (this->isStandaloneGuiSelected()) { ui->rb_SwiftDistributed->setChecked(
true); }
455 ui->tb_SwiftCore->setEnabled(
false);
456 m_startCoreWaitCycles = 2;
457 if (this->setSwiftCoreExecutable())
459 if (shift) { this->popupExecutableArgs(); }
463 else if (sender == ui->tb_Database)
466 QDesktopServices::openUrl(homePage);
470 void CSwiftLauncher::dbusServerModeSelected(
bool selected)
472 if (!selected) {
return; }
473 if (!this->isStandaloneGuiSelected()) {
return; }
474 ui->rb_SwiftDistributed->setChecked(
true);
479 using namespace std::chrono_literals;
480 ui->fr_SwiftLauncherMain->showOverlayMessage(msg, 5s);
483 void CSwiftLauncher::showStatusMessage(
const QString &htmlMsg)
485 using namespace std::chrono_literals;
486 ui->fr_SwiftLauncherMain->showOverlayMessage(htmlMsg, 5s);
489 void CSwiftLauncher::showMainPage() { ui->sw_SwiftLauncher->setCurrentWidget(ui->pg_SwiftLauncherMain); }
491 void CSwiftLauncher::tabChanged(
int current)
493 if (current ==
static_cast<int>(PageUpdates)) { ui->comp_DataUpdates->display(); }
496 void CSwiftLauncher::showLogPage() { ui->sw_SwiftLauncher->setCurrentWidget(ui->pg_SwiftLauncherLog); }
498 void CSwiftLauncher::checkRunningApplicationsAndCore()
501 if (m_startCoreWaitCycles > 0) { m_startCoreWaitCycles--; }
502 if (m_startMappingToolWaitCycles > 0) { m_startMappingToolWaitCycles--; }
503 if (m_startGuiWaitCycles > 0) { m_startGuiWaitCycles--; }
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();
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);
516 void CSwiftLauncher::startWizard()
518 const bool show = this->warnAboutOtherSwiftApplications();
519 if (!show) {
return; }
522 CGuiUtility::centerWidget(m_wizard.data(),
this);
525 void CSwiftLauncher::onStyleSheetsChanged() { this->initStyleSheet(); }
527 void CSwiftLauncher::onDBusEditingFinished() { ui->rb_SwiftDistributed->setChecked(
true); }
529 void CSwiftLauncher::onCoreModeReleased()
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);
539 void CSwiftLauncher::popupExecutableArgs() { QMessageBox::information(
this,
"Command line", this->
getCmdLine()); }
541 void CSwiftLauncher::showSimulatorConfigDirs()
543 if (!m_textEditDialog) { m_textEditDialog.reset(
new CTextEditDialog(
this)); }
545 const QObject *s = QObject::sender();
550 if (s == ui->pb_P3DConfigDirs)
552 simDir = CFsDirectories::p3dDir();
553 simObjDir = CFsDirectories::p3dSimObjectsDir();
554 const QString versionHint = CFsDirectories::guessP3DVersion(simDir);
555 dirs = CFsDirectories::p3dSimObjectsDirPlusAddOnXmlSimObjectsPaths(simObjDir, versionHint);
557 else if (s == ui->pb_FSXConfigDirs)
559 dirs = CFsDirectories::fsxSimObjectsDirPlusAddOnXmlSimObjectsPaths();
560 simDir = CFsDirectories::fsxDir();
561 simObjDir = CFsDirectories::fsxSimObjectsDir();
564 const QString info = u
"Sim.dir: " % simDir %
"\n" % u
"Sim.objects: " % simObjDir %
"\n" %
565 (dirs.isEmpty() ?
"No dirs" : dirs.join(
"\n"));
567 m_textEditDialog->setReadOnly();
568 m_textEditDialog->textEdit()->setText(info);
569 m_textEditDialog->show();
574 void CSwiftLauncher::requestMacMicrophoneAccess()
580 if (status == CMacOSMicrophoneAccess::Authorized) {
return; }
581 m_micAccess.requestAccess();
SWIFT_CORE_EXPORT swift::core::CApplication * sApp
Single instance of application object.
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.
void setAudioMode(AudioMode mode)
Audio mode.
void setCoreMode(CoreMode mode)
Core mode.
void setFramelessWindow(bool frameless)
Frameless window?
void setDBusAddress(const QString &dBusAddress)
DBus address.
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.
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.
Base class with a member CIdentifier to be inherited by a class which has an identity in the environm...
Class for emitting a log message.
Value class for matching log messages based on their categories.
AuthorizationStatus
Authorization status.
Derived & info(const char16_t(&format)[N])
Set the severity to info, providing a format string.
bool isEmpty() const
Synonym for empty.
Streamable status message, e.g.
Artifacts ("our software" products)
const CPlatform & getPlatform() const
OS.
bool isNewerThanCurrentBuild() const
Newer than the current build.
CDistribution getMostStableDistribution() const
Most stable distribution if any.
const QString & getChannel() const
Version channel (Alpha, Beta, Stable ..)
const QString & getVersion() const
Version info.
Value object encapsulating information of a location, kind of simplified CValueObject compliant versi...
void setFilter(const U &filter)
Set filter to choose list elements.
virtual void initialize(IDataLink *dataLink)
Subscribe using the given transport mechanism.
Simple hardcoded info about the corresponding simulator.
Basically a QObject free (delegate based) version of CCentralMultiSimulatorModelSetCachesProvider.
int getCachedModelsCount(const CSimulatorInfo &simulator) const
Look like IMultiSimulatorModelCaches interface.
void synchronizeCache(const CSimulatorInfo &simulator)
Look like IMultiSimulatorModelCaches interface.
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.
High level reusable GUI components.
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...
CoreMode
Core runs how and where?