4 #include "ui_swiftguistd.h"
29 #if defined(Q_OS_MACOS)
36 #include <QMessageBox>
39 #include <QStackedWidget>
63 using namespace swift::core::context;
67 using namespace swift::misc::network;
68 using namespace swift::misc::aviation;
69 using namespace swift::misc::physical_quantities;
70 using namespace swift::misc::geo;
71 using namespace swift::misc::audio;
72 using namespace swift::misc::input;
73 using namespace swift::misc::simulation;
74 using namespace swift::config;
82 Q_ASSERT_X(
sGui, Q_FUNC_INFO,
"Need sGui");
104 QMainWindow::mouseReleaseEvent(event);
107 void SwiftGuiStd::performGracefulShutdown()
109 if (!m_init) {
return; }
112 Q_ASSERT_X(CThreadUtils::thisIsMainThread(), Q_FUNC_INFO,
"Should shutdown in main thread");
115 this->stopAllTimers(
true);
118 if (m_contextNetworkAvailable)
122 if (m_contextAudioAvailable)
132 ui->comp_MainInfoArea->dockAllWidgets();
135 const QPointer<SwiftGuiStd> myself(
this);
137 if (!
sGui || !myself) {
return; }
154 QPointer<SwiftGuiStd> myself(
this);
156 if (!myself) {
return; }
157 myself->loginRequested();
162 if (this->triggerAutoPublishDialog())
175 this->performGracefulShutdown();
180 if (!CEnableForFramelessWindow::handleChangeEvent(event)) { QMainWindow::changeEvent(event); }
185 const QIcon i(CIcons::changeIconBackgroundColor(this->style()->standardIcon(QStyle::SP_TitleBarMinButton),
186 Qt::white, QSize(16, 16)));
187 QAction *a =
new QAction(i,
"Window minimized", parent);
188 connect(a, &QAction::triggered,
this, &SwiftGuiStd::showMinimized);
194 const QIcon i(CIcons::changeIconBackgroundColor(this->style()->standardIcon(QStyle::SP_TitleBarNormalButton),
195 Qt::white, QSize(16, 16)));
196 QAction *a =
new QAction(i,
"Window normal", parent);
197 connect(a, &QAction::triggered,
this, &SwiftGuiStd::showNormal);
203 const QIcon i(CIcons::changeIconBackgroundColor(this->style()->standardIcon(QStyle::SP_TitleBarShadeButton),
204 Qt::white, QSize(16, 16)));
205 QAction *a =
new QAction(i,
"Toogle main window visibility", parent);
206 connect(a, &QAction::triggered,
this, &SwiftGuiStd::toggleWindowVisibility);
212 const QIcon i(CIcons::changeIconBackgroundColor(this->style()->standardIcon(QStyle::SP_TitleBarUnshadeButton),
213 Qt::white, QSize(16, 16)));
214 QAction *a =
new QAction(i,
"Toogle main window on top", parent);
215 connect(a, &QAction::triggered,
this, &SwiftGuiStd::toggleWindowStayOnTop);
223 this->setMainPageToInfoArea();
224 ui->comp_MainInfoArea->selectArea(infoArea);
227 void SwiftGuiStd::setSettingsPage(
int settingsTabIndex)
229 this->setMainPageInfoArea(CMainInfoAreaComponent::InfoAreaSettings);
230 if (settingsTabIndex < 0) {
return; }
231 ui->comp_MainInfoArea->getSettingsComponent()->setCurrentIndex(settingsTabIndex);
236 return ui->sw_MainMiddle->currentIndex() ==
static_cast<int>(mainPage);
239 void SwiftGuiStd::loginRequested()
243 const bool changed = MainPageLogin != ui->sw_MainMiddle->currentIndex();
244 this->setMainPage(MainPageLogin);
252 void SwiftGuiStd::onKickedFromNetwork(
const QString &kickMessage)
254 this->updateGuiStatusInformation();
256 const QString msgText = kickMessage.isEmpty() ? QStringLiteral(
"You have been kicked from the network") :
257 QStringLiteral(
"You have been kicked: '%1'").arg(kickMessage);
265 this->updateGuiStatusInformation();
270 case CConnectionStatus::Connected: this->playNotifcationSound(CNotificationSounds::NotificationLogin);
break;
271 case CConnectionStatus::Disconnected: this->playNotifcationSound(CNotificationSounds::NotificationLogoff);
break;
276 void SwiftGuiStd::handleTimerBasedUpdates()
278 this->setContextAvailability();
279 this->updateGuiStatusInformation();
282 this->reloadOwnAircraft();
285 void SwiftGuiStd::setContextAvailability()
287 const bool corePreviouslyAvailable = m_coreAvailable;
294 else { m_coreAvailable =
false; }
295 if (isShuttingDown) {
return; }
296 if (m_coreAvailable && m_coreFailures > 0) { m_coreFailures--; }
297 else if (!m_coreAvailable && m_coreFailures < MaxCoreFailures) { m_coreFailures++; }
298 else if (!m_coreAvailable && !m_displayingDBusReconnect) { this->displayDBusReconnectDialog(); }
299 m_contextNetworkAvailable =
304 if (m_coreAvailable != corePreviouslyAvailable)
315 void SwiftGuiStd::updateGuiStatusInformation()
319 static const QString dBusTimestamp(
"%1 %2");
320 static const QString local(
"local");
321 const QString now = QDateTime::currentDateTimeUtc().toString(
"yyyy-MM-dd HH:mm:ss");
323 ui->comp_InfoBarStatus->setDBusStatus(dBus && m_coreAvailable);
324 ui->comp_InfoBarStatus->setDBusTooltip(
329 static const QString unavailable(
"unavailable");
330 ui->comp_InfoBarStatus->setDBusStatus(
false);
331 ui->comp_InfoBarStatus->setDBusTooltip(unavailable);
335 void SwiftGuiStd::onChangedWindowOpacity(
int opacity)
337 qreal o = opacity / 100.0;
338 o = o < 0.3 ? 0.3 : o;
339 o = o > 1.0 ? 1.0 : o;
340 QWidget::setWindowOpacity(o);
341 ui->comp_MainInfoArea->getSettingsComponent()->setGuiOpacity(o * 100.0);
344 void SwiftGuiStd::toggleWindowStayOnTop()
349 void SwiftGuiStd::toggleWindowVisibility()
351 if (this->isVisible())
359 void SwiftGuiStd::onStyleSheetsChanged() { this->initStyleSheet(); }
361 void SwiftGuiStd::onToggledWindowsOnTop(
bool onTop)
367 ui->comp_MainInfoArea->allFloatingOnTop();
371 void SwiftGuiStd::onCurrentMainWidgetChanged(
int currentIndex)
374 Q_UNUSED(currentIndex)
377 void SwiftGuiStd::onChangedMainInfoAreaFloating(
bool floating)
388 ui->fr_CentralFrameInside->showOverlayHTMLMessage(msg);
391 void SwiftGuiStd::focusInMainEntryField() { ui->comp_MainKeypadArea->focusInEntryField(); }
393 void SwiftGuiStd::focusInTextMessageEntryField()
395 if (!ui->comp_MainInfoArea->getTextMessageComponent()) {
return; }
396 if (ui->comp_MainInfoArea->getTextMessageComponent()->isParentDockWidgetFloating())
398 ui->comp_MainInfoArea->getTextMessageComponent()->activateWindow();
399 ui->comp_MainInfoArea->getTextMessageComponent()->focusTextEntry();
401 else { this->focusInMainEntryField(); }
408 void SwiftGuiStd::onNavigatorClosed()
414 void SwiftGuiStd::verifyPrerequisites()
425 #if defined(Q_OS_MACOS)
432 CLogMessage(
this).error(u
"Cannot access the keyboard. Is \"Input Monitoring\" for swift enabled?"));
446 using namespace std::chrono_literals;
449 if (QApplication::activeModalWidget())
452 if (invalid.
isEmpty()) {
return; }
455 u
"Model set validation has found %1 invalid models for '%2', check the model validation")
461 this->displayValidationDialog();
462 m_validationDialog->validatedModelSet(simulator, valid, invalid, stopped, msgs);
465 void SwiftGuiStd::displayValidationDialog()
469 m_validationDialog->show();
472 void SwiftGuiStd::checkDbDataLoaded()
476 Q_ASSERT_X(CThreadUtils::thisIsMainThread(), Q_FUNC_INFO,
"Wrong thread, needs to run in main thread");
477 const CEntityFlags::Entity loadEntities =
479 if (loadEntities == CEntityFlags::NoEntity)
481 m_dbDataLoading =
false;
486 m_dbLoadDialog->newerOrEmptyEntitiesDetected(loadEntities);
491 if (!m_contextAudioAvailable) {
return; }
492 if (!m_audioSettings.
get().isNotificationFlagSet(notification)) {
return; }
497 void SwiftGuiStd::displayLog() { ui->comp_MainInfoArea->displayLog(); }
499 void SwiftGuiStd::displayNetworkSettings()
502 this->setMainPageInfoArea(CMainInfoAreaComponent::InfoAreaSettings);
503 ui->comp_MainInfoArea->getSettingsComponent()->setTab(CSettingsComponent::SettingTabServers);
506 void SwiftGuiStd::onPttChanged(
bool enabled)
513 enabled ? CNotificationSounds::PTTClickKeyDown : CNotificationSounds::PTTClickKeyUp,
true);
516 void SwiftGuiStd::displayDBusReconnectDialog()
518 if (m_displayingDBusReconnect) {
return; }
522 m_displayingDBusReconnect =
true;
524 static const QString informativeText(
"Do you want to try to reconnect? 'Abort' will close the GUI.\n\nDBus: '%1'");
525 QMessageBox msgBox(
this);
526 msgBox.setIcon(QMessageBox::Critical);
527 msgBox.setText(
"swift core not reachable!");
528 msgBox.setInformativeText(informativeText.arg(dBusAddress));
529 msgBox.setStandardButtons(QMessageBox::Retry | QMessageBox::Abort);
530 msgBox.setDefaultButton(QMessageBox::Retry);
531 const int ret = msgBox.exec();
532 if (ret == QMessageBox::Abort)
536 CGuiApplication::exit(EXIT_FAILURE);
540 m_displayingDBusReconnect =
false;
542 if (msg.
isSuccess()) { m_coreFailures = 0; }
544 CLogMessage::preformatted(msg);
547 void SwiftGuiStd::onShowOverlayVariant(
const CVariant &variant, std::chrono::milliseconds duration)
550 ui->fr_CentralFrameInside->showOverlayVariant(variant, duration);
556 ui->fr_CentralFrameInside->showOverlayInlineTextMessage(tab);
559 void SwiftGuiStd::onShowOverlayInlineTextMessageCallsign(
const CCallsign &callsign)
562 ui->fr_CentralFrameInside->showOverlayInlineTextMessage(callsign);
565 bool SwiftGuiStd::triggerAutoPublishDialog()
567 if (!CAutoPublishData::existAutoPublishFiles()) {
return false; }
569 constexpr qint64 deltaT = 48 * 60 * 60 * 1000;
570 const qint64 lastDialogTs = m_lastAutoPublish.
get();
571 bool showAutoPublish = lastDialogTs < 0 || (QDateTime::currentMSecsSinceEpoch() - lastDialogTs) > deltaT;
572 if (!showAutoPublish) {
return false; }
574 const QMessageBox::StandardButton reply =
575 QMessageBox::question(
this, QStringLiteral(
"Upload data?"),
576 QStringLiteral(
"Do you want to help improving swift by uploading anonymized data?"),
577 QMessageBox::Yes | QMessageBox::No);
579 if (reply != QMessageBox::Yes)
581 m_lastAutoPublish.
set(QDateTime::currentMSecsSinceEpoch());
585 this->autoPublishDialog();
589 bool SwiftGuiStd::startModelBrowser()
592 m_modelBrower->exec();
596 bool SwiftGuiStd::startAFVMap()
SWIFT_CORE_EXPORT swift::core::CApplication * sApp
Single instance of application object.
virtual void mousePressEvent(QMouseEvent *event)
virtual void mouseMoveEvent(QMouseEvent *event)
void currentMainInfoAreaChanged(const QWidget *currentWidget)
Main info area has changed.
QAction * getToggleStayOnTopAction(QObject *parent)
Get a minimize action which minimizes the window.
SwiftGuiStd(WindowMode windowMode, QWidget *parent=nullptr)
Constructor.
virtual ~SwiftGuiStd()
Destructor.
QAction * getToggleWindowVisibilityAction(QObject *parent)
Get a minimize action which minimizes the window.
virtual void closeEvent(QCloseEvent *event)
MainPageIndex
Main page indexes.
QAction * getWindowNormalAction(QObject *parent)
Get a minimize action which minimizes the window.
QAction * getWindowMinimizeAction(QObject *parent)
Get a minimize action which minimizes the window.
virtual void changeEvent(QEvent *event)
virtual void mouseReleaseEvent(QMouseEvent *event)
const context::IContextAudio * getIContextAudio() const
Direct access to contexts if a CCoreFacade has been initialized.
data::CGlobalSetup getGlobalSetup() const
Global setup.
const context::IContextApplication * getIContextApplication() const
Direct access to contexts if a CCoreFacade has been initialized.
CCoreFacade * getCoreFacade()
Get the facade.
bool hasWebDataServices() const
Web data services available?
const context::IContextNetwork * getIContextNetwork() const
Direct access to contexts if a CCoreFacade has been initialized.
bool isShuttingDown() const
Is application shutting down?
const context::IContextSimulator * getIContextSimulator() const
Direct access to contexts if a CCoreFacade has been initialized.
const CCoreFacadeConfig & getCoreFacadeConfig() const
The core facade config.
const context::CContextAudioBase * getCContextAudioBase() const
Direct access to contexts if a CCoreFacade has been initialized.
bool supportsContexts(bool ignoreShutdownTest=false) const
Supports contexts.
CWebDataServices * getWebDataServices() const
Get the web data services.
bool requiresDBusConnection() const
Requires DBus connection (at least one remote)?
QString getDBusAddress() const
DBus address.
QString getDBusAddress() const
DBus address if any.
swift::misc::CStatusMessage tryToReconnectWithDBus()
In case connection between DBus parties is lost, try to reconnect.
swift::misc::network::CEntityFlags::Entity getSynchronizedEntitiesWithNewerSharedFileOrEmpty(bool syncData=true, swift::misc::network::CEntityFlags::Entity entities=swift::misc::network::CEntityFlags::AllDbEntities)
Synchronized entities either empty or with newer shared file.
void playNotification(swift::misc::audio::CNotificationSounds::NotificationFlag notification, bool considerSettings, int volume=-1)
Notification sounds.
virtual void unregisterApplication(const misc::CIdentifier &application)=0
Unregister application.
virtual void synchronizeLocalSettings()=0
Update local settings with settings from core.
virtual misc::CIdentifier registerApplication(const misc::CIdentifier &application)=0
Register application, can also be used for ping.
bool isEmptyObject() const
Empty object?
virtual swift::misc::CStatusMessage disconnectFromNetwork()=0
Disconnect from network.
virtual bool isConnected() const =0
Network connected?
virtual swift::misc::CStatusMessageList verifyPrerequisites() const =0
Verify prerequisites for simulation like an existing model set.
swift::misc::network::CUrl getAfvMapUrl() const
AFV map URL.
Main window which can be frameless.
bool handleMousePressEvent(QMouseEvent *event)
Mouse press, required for frameless window.
void showMinimizedModeChecked()
Check mode and then show minimized.
QPoint m_framelessDragPosition
position, if moving is handled with frameless window
void showNormalModeChecked()
Check mode and then show normal.
bool handleMouseMoveEvent(QMouseEvent *event)
Mouse moving, required for frameless window.
void setDynamicProperties(bool frameless)
Set dynamic properties such as frameless.
void registerMainApplicationWidget(QWidget *mainWidget)
Register main application window widget if this is known.
void processEventsToRefreshGui() const
Allow the GUI to refresh by processing events, call the event loop.
QDialog::DialogCode showCloseDialog(QMainWindow *mainWindow, QCloseEvent *closeEvent)
Show close dialog.
void gracefulShutdown()
Graceful shutdown.
bool toggleStayOnTop()
Toggle stay on top.
void openUrl(const swift::misc::network::CUrl &url)
Open a given URL.
Direct acccess to main window`s status bar, info bar and such.
virtual bool displayInOverlayWindow(const swift::misc::CStatusMessage &message, std::chrono::milliseconds timeout=std::chrono::milliseconds(0))
Display in overlay window.
Dialog for CAircraftModelValidationComponent.
Load data from DB as dialog.
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...
bool isMyIdentifier(const CIdentifier &otherIdentifier) const
My identifier?
const CIdentifier & identifier() const
Get identifier.
Class for emitting a log message.
bool isEmpty() const
Message empty.
Derived & validationWarning(const char16_t(&format)[N])
Set the severity to warning, providing a format string, and adding the validation category.
Derived & error(const char16_t(&format)[N])
Set the severity to error, providing a format string.
size_type size() const
Returns number of elements in the sequence.
void push_back(const T &value)
Appends an element at the end of the sequence.
reference front()
Access the first element.
bool isEmpty() const
Synonym for empty.
Streamable status message, e.g.
bool isSuccess() const
Operation considered successful.
bool clampSeverity(StatusSeverity severity)
Clip/reduce severity if higher (more critical)
Status messages, e.g. from Core -> GUI.
bool hasWarningOrErrorMessages() const
Warning or error messages.
Wrapper around QVariant which provides transparent access to CValueObject methods of the contained ob...
Value object encapsulating information of a callsign.
QString toQString(bool i18n=false) const
Cast as QString.
Value object encapsulating information about a connection status.
ConnectionStatus getConnectionStatus() const
Get status.
Value object encapsulating a list of aircraft models.
Simple hardcoded info about the corresponding simulator.
SWIFT_GUI_EXPORT swift::gui::CGuiApplication * sGui
Single instance of GUI application object.
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...
NotificationFlag
Play notification.