diff --git a/src/blackgui/aircraftcomponent.cpp b/src/blackgui/aircraftcomponent.cpp deleted file mode 100644 index bacd8723f..000000000 --- a/src/blackgui/aircraftcomponent.cpp +++ /dev/null @@ -1,34 +0,0 @@ -#include "aircraftcomponent.h" -#include "ui_aircraftcomponent.h" - -namespace BlackGui -{ - - CAircraftComponent::CAircraftComponent(QWidget *parent) : - QTabWidget(parent), CRuntimeBasedComponent(nullptr, false), ui(new Ui::CAircraftComponent), m_timerComponent(nullptr) - { - ui->setupUi(this); - m_timerComponent = new CTimerBasedComponent(SLOT(update()), this); - } - - CAircraftComponent::~CAircraftComponent() - { - delete ui; - } - - void CAircraftComponent::update() - { - Q_ASSERT(this->ui->tvp_AircraftsInRange); - Q_ASSERT(this->getIContextNetwork()); - Q_ASSERT(this->getIContextSimulator()); - - if (this->getIContextNetwork()->isConnected()) - { - this->ui->tvp_AircraftsInRange->update(this->getIContextNetwork()->getAircraftsInRange()); - } - if (this->getIContextSimulator()->isConnected()) - { - this->ui->tvp_AirportsInRange->update(this->getIContextSimulator()->getAirportsInRange()); - } - } -} diff --git a/src/blackgui/aircraftcomponent.h b/src/blackgui/aircraftcomponent.h deleted file mode 100644 index 8ea93ee2d..000000000 --- a/src/blackgui/aircraftcomponent.h +++ /dev/null @@ -1,47 +0,0 @@ -#ifndef BLACKGUI_AIRCRAFTCOMPONENT_H -#define BLACKGUI_AIRCRAFTCOMPONENT_H - -#include "blackgui/runtimebasedcomponent.h" -#include "blackgui/timerbasedcomponent.h" -#include "blackmisc/avaircraft.h" - -#include - -namespace Ui { class CAircraftComponent; } -namespace BlackGui -{ - //! Aircraft widget - class CAircraftComponent : public QTabWidget, public CRuntimeBasedComponent - { - Q_OBJECT - - public: - //! Constructor - explicit CAircraftComponent(QWidget *parent = nullptr); - - //! Destructor - ~CAircraftComponent(); - - //! Timer for updating - CTimerBasedComponent *getTimerComponent() { return this->m_timerComponent; } - - public slots: - //! Update users - void update(); - - //! \copydoc CTimerBasedComponent::setUpdateIntervalSeconds - void setUpdateIntervalSeconds(int seconds) { Q_ASSERT(this->m_timerComponent); this->m_timerComponent->setUpdateIntervalSeconds(seconds); } - - //! \copydoc CTimerBasedComponent::setUpdateInterval - void setUpdateInterval(int milliSeconds) { Q_ASSERT(this->m_timerComponent); this->m_timerComponent->setUpdateInterval(milliSeconds); } - - //! \copydoc CTimerBasedComponent::stopTimer - void stopTimer() { Q_ASSERT(this->m_timerComponent); this->m_timerComponent->stopTimer(); } - - private: - Ui::CAircraftComponent *ui; - CTimerBasedComponent *m_timerComponent; - }; -} - -#endif // guard diff --git a/src/blackgui/atcstationcomponent.cpp b/src/blackgui/atcstationcomponent.cpp deleted file mode 100644 index 9763734eb..000000000 --- a/src/blackgui/atcstationcomponent.cpp +++ /dev/null @@ -1,176 +0,0 @@ -#include "blackmisc/avinformationmessage.h" -#include "atcstationcomponent.h" -#include "ui_atcstationcomponent.h" - -using namespace BlackMisc::Aviation; -using namespace BlackCore; - -namespace BlackGui -{ - - CAtcStationComponent::CAtcStationComponent(QWidget *parent) : - QTabWidget(parent), CRuntimeBasedComponent(nullptr, false), ui(new Ui::CAtcStationComponent), m_timerComponent(nullptr) - { - ui->setupUi(this); - this->m_timerComponent = new CTimerBasedComponent(SLOT(update()), this); - this->ui->tvp_AtcStationsBooked->setStationMode(CAtcStationListModel::StationsBooked); - - // Signal / Slots - bool connected = this->connect(this->ui->le_AtcStationsOnlineMetar, SIGNAL(returnPressed()), this, SLOT(getMetar())); - Q_ASSERT(connected); - connected = this->connect(this->ui->pb_AtcStationsLoadMetar, SIGNAL(clicked()), this, SLOT(getMetar())); - Q_ASSERT(connected); - this->connect(this, &QTabWidget::currentChanged, this, &CAtcStationComponent::atcStationsTabChanged); - this->connect(this->ui->tvp_AtcStationsOnline, &QTableView::clicked, this, &CAtcStationComponent::onlineAtcStationSelected); - this->connect(this->ui->pb_AtcStationsAtisReload, &QPushButton::clicked, this, &CAtcStationComponent::requestAtis); - this->connect(this->ui->pb_ReloadAtcStationsBooked, &QPushButton::clicked, this, &CAtcStationComponent::reloadAtcStationsBooked); - } - - CAtcStationComponent::~CAtcStationComponent() - { - delete ui; - } - - void CAtcStationComponent::runtimeHasBeenSet() - { - Q_ASSERT(this->getRuntime()); - Q_ASSERT(this->getIContextNetwork()); - if (this->getIContextNetwork()) - { - this->connect(this->getIContextNetwork(), &IContextNetwork::changedAtcStationsOnline, this, &CAtcStationComponent::changedAtcStationsOnline); - this->connect(this->getIContextNetwork(), &IContextNetwork::changedAtcStationsBooked, this, &CAtcStationComponent::changedAtcStationsBooked); - this->connect(this->getIContextNetwork(), &IContextNetwork::changedAtcStationOnlineConnectionStatus, this, &CAtcStationComponent::changedAtcStationOnlineConnectionStatus); - this->connect(this->getIContextNetwork(), &IContextNetwork::connectionStatusChanged, this, &CAtcStationComponent::connectionStatusChanged); - } - } - - void CAtcStationComponent::update() - { - Q_ASSERT(this->ui->tvp_AtcStationsBooked); - Q_ASSERT(this->ui->tvp_AtcStationsOnline); - Q_ASSERT(this->getIContextNetwork()); - - // initial read for bookings - if (this->ui->tvp_AtcStationsBooked->isEmpty()) this->reloadAtcStationsBooked(); - - if (this->getIContextNetwork()->isConnected()) - { - // update - if (this->m_timestampOnlineStationsChanged.isNull() || this->m_timestampLastReadOnlineStations.isNull() || - (this->m_timestampOnlineStationsChanged > this->m_timestampLastReadOnlineStations)) - { - this->ui->tvp_AtcStationsOnline->update(this->getIContextNetwork()->getAtcStationsOnline()); - this->m_timestampLastReadOnlineStations = QDateTime::currentDateTimeUtc(); - this->m_timestampOnlineStationsChanged = this->m_timestampLastReadOnlineStations; - } - } - else - { - this->ui->tvp_AtcStationsOnline->clear(); - this->ui->le_AtcStationsOnlineMetar->clear(); - } - } - - void CAtcStationComponent::reloadAtcStationsBooked() - { - Q_ASSERT(this->ui->tvp_AtcStationsBooked); - Q_ASSERT(this->getIContextNetwork()); - - QObject *sender = QObject::sender(); - if (sender == this->ui->pb_ReloadAtcStationsBooked && this->getIContextNetwork()) - { - this->getIContextNetwork()->readAtcBookingsFromSource(); // trigger new read - QTimer::singleShot(7500, this, SLOT(reloadAtcStationsBooked())); // deferred loading - } - else - { - this->ui->tvp_AtcStationsBooked->update(this->getIContextNetwork()->getAtcStationsBooked()); - this->m_timestampLastReadBookedStations = QDateTime::currentDateTimeUtc(); - } - } - - void CAtcStationComponent::changedAtcStationsOnline() - { - // just update timestamp, data will be pulled by time - // the timestamp will tell if there are any newer data - this->m_timestampOnlineStationsChanged = QDateTime::currentDateTimeUtc(); - } - - void CAtcStationComponent::connectionStatusChanged(uint from, uint to, const QString &message) - { - INetwork::ConnectionStatus fromStatus = static_cast(from); - INetwork::ConnectionStatus toStatus = static_cast(to); - Q_UNUSED(fromStatus); - Q_UNUSED(message); - if (INetwork::isDisconnectedStatus(toStatus)) - { - this->ui->tvp_AtcStationsOnline->clear(); - this->ui->le_AtcStationsOnlineMetar->clear(); - } - } - - void CAtcStationComponent::changedAtcStationOnlineConnectionStatus(const CAtcStation &station, bool added) - { - this->ui->tvp_AtcStationsOnline->changedAtcStationConnectionStatus(station, added); - } - - void CAtcStationComponent::changedAtcStationsBooked() - { - this->reloadAtcStationsBooked(); - } - - void CAtcStationComponent::getMetar(const QString &airportIcaoCode) - { - if (!this->getIContextNetwork()->isConnected()) - { - this->ui->te_AtcStationsOnlineInfo->clear(); - return; - } - QString icao = airportIcaoCode.isEmpty() ? this->ui->le_AtcStationsOnlineMetar->text().trimmed().toUpper() : airportIcaoCode.trimmed().toUpper(); - this->ui->le_AtcStationsOnlineMetar->setText(icao); - if (icao.length() != 4) return; - CInformationMessage metar = this->getIContextNetwork()->getMetar(icao); - if (metar.getType() != CInformationMessage::METAR) return; - if (metar.isEmpty()) - { - this->ui->te_AtcStationsOnlineInfo->clear(); - } - else - { - this->ui->te_AtcStationsOnlineInfo->setText(metar.getMessage()); - } - } - - void CAtcStationComponent::onlineAtcStationSelected(QModelIndex index) - { - this->ui->te_AtcStationsOnlineInfo->setText(""); // reset - const CAtcStation stationClicked = this->ui->tvp_AtcStationsOnline->derivedModel()->at(index); - QString infoMessage; - - if (stationClicked.hasAtis()) - { - infoMessage.append(stationClicked.getAtis().getMessage()); - } - if (stationClicked.hasMetar()) - { - if (!infoMessage.isEmpty()) infoMessage.append("\n\n"); - infoMessage.append(stationClicked.getMetar().getMessage()); - } - this->ui->te_AtcStationsOnlineInfo->setText(infoMessage); - } - - void CAtcStationComponent::atcStationsTabChanged() - { - if (this->currentWidget() == this->ui->tb_AtcStationsOnline) - { - if (this->m_timestampLastReadBookedStations.isNull()) - this->reloadAtcStationsBooked(); - } - } - - void CAtcStationComponent::requestAtis() - { - if (!this->getIContextNetwork()->isConnected()) return; - this->getIContextNetwork()->requestAtisUpdates(); - } -} diff --git a/src/blackgui/atcstationcomponent.h b/src/blackgui/atcstationcomponent.h deleted file mode 100644 index fd8c16ac8..000000000 --- a/src/blackgui/atcstationcomponent.h +++ /dev/null @@ -1,86 +0,0 @@ -#ifndef BLACKGUI_ATCSTATIONCOMPONENT_H -#define BLACKGUI_ATCSTATIONCOMPONENT_H - -#include "blackgui/runtimebasedcomponent.h" -#include "blackgui/timerbasedcomponent.h" -#include "blackmisc/avatcstation.h" - -#include -#include - -namespace Ui { class CAtcStationComponent; } - -namespace BlackGui -{ - /*! - * \brief ATC stations component - */ - class CAtcStationComponent : public QTabWidget, public CRuntimeBasedComponent - { - Q_OBJECT - - public: - //! Constructor - explicit CAtcStationComponent(QWidget *parent = nullptr); - - //! Destructor - ~CAtcStationComponent(); - - //! Timer for updating - CTimerBasedComponent *getTimerComponent() { return this->m_timerComponent; } - - public slots: - //! Update users - void update(); - - //! \copydoc CTimerBasedComponent::setUpdateIntervalSeconds - void setUpdateIntervalSeconds(int seconds) { Q_ASSERT(this->m_timerComponent); this->m_timerComponent->setUpdateIntervalSeconds(seconds); } - - //! \copydoc CTimerBasedComponent::setUpdateInterval - void setUpdateInterval(int milliSeconds) { Q_ASSERT(this->m_timerComponent); this->m_timerComponent->setUpdateInterval(milliSeconds); } - - //! \copydoc CTimerBasedComponent::stopTimer - void stopTimer() { Q_ASSERT(this->m_timerComponent); this->m_timerComponent->stopTimer(); } - - //! Get METAR for given ICAO airport code - void getMetar(const QString &airportIcaoCode = ""); - - //! \copydoc CAtcStationListModel::changedAtcStationConnectionStatus - void changedAtcStationOnlineConnectionStatus(const BlackMisc::Aviation::CAtcStation &station, bool added); - - protected: - //! \copydoc CRuntimeBasedComponent::runtimeHasBeenSet - void runtimeHasBeenSet() override; - - private slots: - - //! Request new ATIS - void requestAtis(); - - //! Online ATC station selected - void onlineAtcStationSelected(QModelIndex index); - - //! Tab changed - void atcStationsTabChanged(); - - //! Booked stations - void reloadAtcStationsBooked(); - - //! Booked stations changed - void changedAtcStationsBooked(); - - //! Online stations changed - void changedAtcStationsOnline(); - - //! Connection status has been changed - void connectionStatusChanged(uint from, uint to, const QString &message); - - private: - Ui::CAtcStationComponent *ui; - CTimerBasedComponent *m_timerComponent; - QDateTime m_timestampLastReadOnlineStations; - QDateTime m_timestampOnlineStationsChanged; - QDateTime m_timestampLastReadBookedStations; - }; -} -#endif // guard diff --git a/src/blackgui/cockpitv1component.cpp b/src/blackgui/cockpitv1component.cpp deleted file mode 100644 index 54a70290e..000000000 --- a/src/blackgui/cockpitv1component.cpp +++ /dev/null @@ -1,404 +0,0 @@ -#include "cockpitv1component.h" -#include "ui_cockpitv1component.h" - -#include "blackgui/atcstationlistmodel.h" -#include "blackcore/context_ownaircraft.h" -#include "blackcore/context_ownaircraft_impl.h" -#include "blackcore/context_network.h" -#include "blackmisc/voiceroom.h" - -using namespace BlackCore; -using namespace BlackMisc; -using namespace BlackGui; -using namespace BlackMisc::Network; -using namespace BlackMisc::Aviation; -using namespace BlackMisc::PhysicalQuantities; -using namespace BlackMisc::Geo; -using namespace BlackMisc::Settings; -using namespace BlackMisc::Math; -using namespace BlackMisc::Audio; -using namespace BlackSound; - -namespace BlackGui -{ - CCockpitV1Component::CCockpitV1Component(QWidget *parent) : - QWidget(parent), CRuntimeBasedComponent(nullptr, false), ui(new Ui::CCockpitV1Component), m_externalCockpitIdentButton(nullptr), m_voiceRoomMembersTimer(nullptr) - { - ui->setupUi(this); - - // init encapsulated table views / models - this->ui->tvp_CockpitVoiceRoom1->setUserMode(CUserListModel::UserShort); - this->ui->tvp_CockpitVoiceRoom2->setUserMode(CUserListModel::UserShort); - - // SELCAL pairs in cockpit - this->ui->cb_CockpitSelcal1->clear(); - this->ui->cb_CockpitSelcal2->clear(); - this->ui->cb_CockpitSelcal1->addItems(BlackMisc::Aviation::CSelcal::codePairs()); - this->ui->cb_CockpitSelcal2->addItems(BlackMisc::Aviation::CSelcal::codePairs()); - - // cockpit GUI events - this->connect(this->ui->ds_CockpitCom1Active, &QDoubleSpinBox::editingFinished, this, &CCockpitV1Component::cockpitValuesChanged); - this->connect(this->ui->ds_CockpitCom2Active, &QDoubleSpinBox::editingFinished, this, &CCockpitV1Component::cockpitValuesChanged); - this->connect(this->ui->ds_CockpitCom1Standby, &QDoubleSpinBox::editingFinished, this, &CCockpitV1Component::cockpitValuesChanged); - this->connect(this->ui->ds_CockpitCom2Standby, &QDoubleSpinBox::editingFinished, this, &CCockpitV1Component::cockpitValuesChanged); - this->connect(this->ui->ds_CockpitTransponder, &QDoubleSpinBox::editingFinished, this, &CCockpitV1Component::cockpitValuesChanged); - - this->connect(this->ui->cb_CockpitVoiceRoom1Override, &QCheckBox::clicked, this, &CCockpitV1Component::setAudioVoiceRoomUrls); - this->connect(this->ui->cb_CockpitVoiceRoom2Override, &QCheckBox::clicked, this, &CCockpitV1Component::setAudioVoiceRoomUrls); - this->connect(this->ui->le_CockpitVoiceRoomCom1, &QLineEdit::returnPressed, this, &CCockpitV1Component::setAudioVoiceRoomUrls); - this->connect(this->ui->le_CockpitVoiceRoomCom2, &QLineEdit::returnPressed, this, &CCockpitV1Component::setAudioVoiceRoomUrls); - this->connect(this->ui->pb_CockpitToggleCom1, &QPushButton::clicked, this, &CCockpitV1Component::cockpitValuesChanged); - this->connect(this->ui->pb_CockpitToggleCom2, &QPushButton::clicked, this, &CCockpitV1Component::cockpitValuesChanged); - this->connect(this->ui->pb_CockpitSelcalTest, &QPushButton::clicked, this, &CCockpitV1Component::testSelcal); - - this->connect(this->ui->cbp_CockpitTransponderMode, &CTransponderModeSelector::valueChanged, this, &CCockpitV1Component::cockpitValuesChanged); - - this->connect(this->ui->di_CockpitCom1Volume, &QDial::valueChanged, this, &CCockpitV1Component::setCom1Volume); - this->connect(this->ui->di_CockpitCom2Volume, &QDial::valueChanged, this, &CCockpitV1Component::setCom2Volume); - - // timer - this->m_voiceRoomMembersTimer = new QTimer(this); - this->connect(this->m_voiceRoomMembersTimer, &QTimer::timeout, this, &CCockpitV1Component::updateVoiceRoomMembers); - this->m_voiceRoomMembersTimer->start(10 * 1000); - } - - void CCockpitV1Component::runtimeHasBeenSet() - { - // hook up with changes from own aircraft context - Q_ASSERT(this->getIContextOwnAircraft()); - this->connect(this->getIContextOwnAircraft(), &IContextOwnAircraft::changedAircraftCockpit, this, &CCockpitV1Component::updateCockpitFromContext); - - // Audio is optional - if (this->getIContextAudio()) - { - this->connect(this->getIContextAudio(), &IContextAudio::changedVoiceRooms, this, &CCockpitV1Component::updateAudioVoiceRoomsFromObjects); - } - } - - CCockpitV1Component::~CCockpitV1Component() - { - delete ui; - } - - void CCockpitV1Component::setExternalIdentButton(QPushButton *cockpitIdent) - { - if (this->m_externalCockpitIdentButton) disconnect(this->m_externalCockpitIdentButton); - this->m_externalCockpitIdentButton = cockpitIdent; - if (this->m_externalCockpitIdentButton) this->connect(this->m_externalCockpitIdentButton, &QPushButton::clicked, this, &CCockpitV1Component::cockpitValuesChanged); - } - - void CCockpitV1Component::setCom1Volume(int volume) - { - if (volume > 100) volume = 100; - if (volume < 0) volume = 0; - if (QObject::sender() != ui->di_CockpitCom1Volume) - this->ui->di_CockpitCom1Volume->setValue(volume); - this->getIContextOwnAircraft()->setAudioOutputVolumes(volume, this->ui->di_CockpitCom2Volume->value()); - emit this->audioVolumeChanged(); - } - - void CCockpitV1Component::setCom2Volume(int volume) - { - if (volume > 100) volume = 100; - if (volume < 0) volume = 0; - if (QObject::sender() != ui->di_CockpitCom2Volume) - this->ui->di_CockpitCom2Volume->setValue(volume); - this->getIContextOwnAircraft()->setAudioOutputVolumes(this->ui->di_CockpitCom1Volume->value(), volume); - emit this->audioVolumeChanged(); - } - - int CCockpitV1Component::getCom1Volume() const - { - return this->ui->di_CockpitCom1Volume->value(); - } - - int CCockpitV1Component::getCom2Volume() const - { - return this->ui->di_CockpitCom2Volume->value(); - } - - void CCockpitV1Component::setCockpitVoiceStatusPixmap(const QPixmap &pixmap) - { - this->ui->lbl_CockpitVoiceStatus->setPixmap(pixmap); - } - - bool CCockpitV1Component::isCockpitVolumeWidget(const QObject *sender) const - { - return - sender == this->ui->di_CockpitCom1Volume || - sender == this->ui->di_CockpitCom2Volume; - } - - const QString &CCockpitV1Component::cockpitOriginator() - { - static const QString o = QString("COCKPITV1:").append(QString::number(QDateTime::currentMSecsSinceEpoch())); - return o; - } - - CAircraft CCockpitV1Component::getOwnAircraft() const - { - Q_ASSERT(this->getIContextOwnAircraft()); - // direct object from local context - if (this->getIContextOwnAircraft()->usingLocalObjects()) return this->getRuntime()->getCContextOwnAircraft()->ownAircraft(); - - // non local - if (this->canPingApplicationContext()) return this->getIContextOwnAircraft()->getOwnAircraft(); - return CAircraft(); // anything better here, or status? - } - - void CCockpitV1Component::cockpitValuesChanged() - { - QObject *sender = QObject::sender(); - if (sender == this->ui->pb_CockpitToggleCom1) - { - if (this->ui->ds_CockpitCom1Standby->value() == this->ui->ds_CockpitCom1Active->value()) return; - double f = this->ui->ds_CockpitCom1Active->value(); - this->ui->ds_CockpitCom1Active->setValue(this->ui->ds_CockpitCom1Standby->value()); - this->ui->ds_CockpitCom1Standby->setValue(f); - } - else if (sender == this->ui->pb_CockpitToggleCom2) - { - if (this->ui->ds_CockpitCom2Standby->value() == this->ui->ds_CockpitCom2Active->value()) return; - double f = this->ui->ds_CockpitCom2Active->value(); - this->ui->ds_CockpitCom2Active->setValue(this->ui->ds_CockpitCom2Standby->value()); - this->ui->ds_CockpitCom2Standby->setValue(f); - } - else if (sender == this->ui->cbp_CockpitTransponderMode) - { - // toggle the external button - if (this->ui->cbp_CockpitTransponderMode->isIdentSelected()) - { - if (this->m_externalCockpitIdentButton) this->m_externalCockpitIdentButton->setStyleSheet("background: red"); - } - else - { - if (this->m_externalCockpitIdentButton) this->m_externalCockpitIdentButton->setStyleSheet(""); - } - } - else if (sender == this->m_externalCockpitIdentButton) - { - // toggle the combo box - if (this->ui->cbp_CockpitTransponderMode->isIdentSelected()) - { - this->ui->cbp_CockpitTransponderMode->resetTransponderMode(); - } - else - { - this->ui->cbp_CockpitTransponderMode->setSelectedTransponderModeStateIdent(); // trigger real button and whole process - } - } - - CAircraft ownAircraft = this->cockpitValuesToObject(); - this->sendCockpitUpdates(ownAircraft); - } - - CAircraft CCockpitV1Component::cockpitValuesToObject() - { - CAircraft ownAircraft = this->getOwnAircraft(); - CTransponder transponder = ownAircraft.getTransponder(); - CComSystem com1 = ownAircraft.getCom1System(); - CComSystem com2 = ownAircraft.getCom2System(); - - // - // Transponder - // - QString transponderCode = QString::number(qRound(this->ui->ds_CockpitTransponder->value())); - if (CTransponder::isValidTransponderCode(transponderCode)) - { - transponder.setTransponderCode(transponderCode); - } - else - { - this->sendStatusMessage(CStatusMessage::getValidationError("Wrong transponder code, reset")); - this->ui->ds_CockpitTransponder->setValue(transponder.getTransponderCode()); - } - transponder.setTransponderMode(this->ui->cbp_CockpitTransponderMode->getSelectedTransponderMode()); - - // - // COM units - // - com1.setFrequencyActiveMHz(this->ui->ds_CockpitCom1Active->value()); - com1.setFrequencyStandbyMHz(this->ui->ds_CockpitCom1Standby->value()); - com2.setFrequencyActiveMHz(this->ui->ds_CockpitCom2Active->value()); - com2.setFrequencyStandbyMHz(this->ui->ds_CockpitCom2Standby->value()); - this->updateComFrequencyDisplaysFromObjects(com1, com2); // back annotation after rounding - - ownAircraft.setCom1System(com1); - ownAircraft.setCom2System(com2); - ownAircraft.setTransponder(transponder); - return ownAircraft; - } - - void CCockpitV1Component::updateComFrequencyDisplaysFromObjects(const CComSystem &com1, const CComSystem &com2) - { - double freq = com1.getFrequencyActive().valueRounded(CFrequencyUnit::MHz(), 3); - if (freq != this->ui->ds_CockpitCom1Active->value()) - this->ui->ds_CockpitCom1Active->setValue(freq); - - freq = com2.getFrequencyActive().valueRounded(CFrequencyUnit::MHz(), 3); - if (freq != this->ui->ds_CockpitCom2Active->value()) - this->ui->ds_CockpitCom2Active->setValue(freq); - - freq = com1.getFrequencyStandby().valueRounded(CFrequencyUnit::MHz(), 3); - if (freq != this->ui->ds_CockpitCom1Standby->value()) - this->ui->ds_CockpitCom1Standby->setValue(freq); - - freq = com2.getFrequencyStandby().valueRounded(CFrequencyUnit::MHz(), 3); - if (freq != this->ui->ds_CockpitCom2Standby->value()) - this->ui->ds_CockpitCom2Standby->setValue(freq); - } - - void CCockpitV1Component::updateCockpitFromContext(const CAircraft &ownAircraft, const QString &originator) - { - if (originator == CCockpitV1Component::cockpitOriginator()) return; // comes from myself - - // update GUI elements - // avoid unnecessary change events as far as possible - const CComSystem com1 = ownAircraft.getCom1System(); // aircraft just updated or set from context - const CComSystem com2 = ownAircraft.getCom2System(); - const CTransponder transponder = ownAircraft.getTransponder(); - - // update the frequencies - this->updateComFrequencyDisplaysFromObjects(com1, com2); - - // update transponder - qint32 tc = transponder.getTransponderCode(); - if (tc != static_cast(this->ui->ds_CockpitTransponder->value())) - this->ui->ds_CockpitTransponder->setValue(tc); - - this->ui->cbp_CockpitTransponderMode->setSelectedTransponderMode(transponder.getTransponderMode()); - - if (this->getIContextNetwork()) - { - CAtcStationList selectedStations = this->getIContextNetwork()->getSelectedAtcStations(); - CAtcStation com1Station = selectedStations[0]; - CAtcStation com2Station = selectedStations[1]; - if (com1Station.getCallsign().isEmpty()) - this->ui->lbl_CockpitCom1->setToolTip(""); - else - this->ui->lbl_CockpitCom1->setToolTip(com1Station.getCallsign().getStringAsSet()); - if (com2Station.getCallsign().isEmpty()) - this->ui->lbl_CockpitCom2->setToolTip(""); - else - this->ui->lbl_CockpitCom2->setToolTip(com2Station.getCallsign().getStringAsSet()); - } - } - - bool CCockpitV1Component::sendCockpitUpdates(const CAircraft &ownAircraft) - { - // - // Send to context - // - bool changedCockpit = false; - if (this->getIContextOwnAircraft()) - { - changedCockpit = this->getIContextOwnAircraft()->updateOwnCockpit(ownAircraft.getCom1System(), ownAircraft.getCom2System(), ownAircraft.getTransponder(), CCockpitV1Component::cockpitOriginator()); - } - return changedCockpit; - } - - void CCockpitV1Component::setAudioVoiceRoomUrls() - { - Q_ASSERT(this->getIContextOwnAircraft()); - - // make fields readonly if not overriding - this->ui->le_CockpitVoiceRoomCom1->setReadOnly(!this->ui->cb_CockpitVoiceRoom1Override->isChecked()); - this->ui->le_CockpitVoiceRoomCom2->setReadOnly(!this->ui->cb_CockpitVoiceRoom2Override->isChecked()); - - QString room1; - QString room2; - if (this->ui->cb_CockpitVoiceRoom1Override->isChecked()) room1 = ui->le_CockpitVoiceRoomCom1->text(); - if (this->ui->cb_CockpitVoiceRoom2Override->isChecked()) room2 = ui->le_CockpitVoiceRoomCom2->text(); - this->getIContextOwnAircraft()->setAudioVoiceRoomOverrideUrls(room1, room2); - } - - void CCockpitV1Component::updateAudioVoiceRoomsFromObjects(const CVoiceRoomList &selectedVoiceRooms, bool connected) - { - Q_ASSERT(selectedVoiceRooms.size() == 2); - CVoiceRoom room1 = selectedVoiceRooms[0]; - CVoiceRoom room2 = selectedVoiceRooms[1]; - - // KB_REMOVE - qDebug() << "selected rooms" << room1.isConnected() << room1.getVoiceRoomUrl() << room2.isConnected() << room2.getVoiceRoomUrl(); - - // remark - // isAudioPlaying() is not set, as this is only a temporary value when really "something is playing" - - bool changedUrl1 = (room1.getVoiceRoomUrl() == this->ui->le_CockpitVoiceRoomCom1->text()); - this->ui->le_CockpitVoiceRoomCom1->setText(room1.getVoiceRoomUrl()); - if (room1.isConnected()) - { - this->ui->le_CockpitVoiceRoomCom1->setStyleSheet("background: green"); - if (this->getIContextAudio()) this->ui->tvp_CockpitVoiceRoom1->update(this->getIContextAudio()->getCom1RoomUsers()); - } - else - { - this->ui->le_CockpitVoiceRoomCom1->setStyleSheet(""); - this->ui->tvp_CockpitVoiceRoom1->clear(); - } - - bool changedUrl2 = (room2.getVoiceRoomUrl() == this->ui->le_CockpitVoiceRoomCom2->text()); - this->ui->le_CockpitVoiceRoomCom2->setText(room2.getVoiceRoomUrl()); - if (room2.isConnected()) - { - this->ui->le_CockpitVoiceRoomCom2->setStyleSheet("background: green"); - } - else - { - this->ui->le_CockpitVoiceRoomCom2->setStyleSheet(""); - this->ui->tvp_CockpitVoiceRoom2->clear(); - } - if (changedUrl1 || changedUrl2) - { - this->updateVoiceRoomMembers(); - - // notify - if (this->getIContextAudio()) - { - CNotificationSounds::Notification sound = connected ? - CNotificationSounds::NotificationVoiceRoomJoined : - CNotificationSounds::NotificationVoiceRoomLeft; - this->getIContextAudio()->playNotification(static_cast(sound), true); - } - } - } - - void CCockpitV1Component::updateVoiceRoomMembers() - { - if (!this->getIContextAudio()) return; - if (!this->ui->le_CockpitVoiceRoomCom1->text().trimmed().isEmpty()) - this->ui->tvp_CockpitVoiceRoom1->update(this->getIContextAudio()->getCom1RoomUsers()); - else - this->ui->tvp_CockpitVoiceRoom1->clear(); - - if (!this->ui->le_CockpitVoiceRoomCom2->text().trimmed().isEmpty()) - this->ui->tvp_CockpitVoiceRoom2->update(this->getIContextAudio()->getCom2RoomUsers()); - else - this->ui->tvp_CockpitVoiceRoom2->clear(); - } - - void CCockpitV1Component::testSelcal() - { - QString selcalCode = this->getSelcalCode(); - if (!CSelcal::isValidCode(selcalCode)) - { - this->sendStatusMessage(CStatusMessage(CStatusMessage::TypeValidation, CStatusMessage::SeverityWarning, "Invalid SELCAL codde")); - } - else if (this->getIContextAudio()) - { - CSelcal selcal(selcalCode); - this->getIContextAudio()->playSelcalTone(selcal); - } - else - { - this->sendStatusMessage(CStatusMessage(CStatusMessage::TypeAudio, CStatusMessage::SeverityError, "No audio available")); - } - } - - QString CCockpitV1Component::getSelcalCode() const - { - QString selcal = this->ui->cb_CockpitSelcal1->currentText().append(this->ui->cb_CockpitSelcal2->currentText()); - return selcal; - } - -} // guard diff --git a/src/blackgui/cockpitv1component.h b/src/blackgui/cockpitv1component.h deleted file mode 100644 index 3d3561a50..000000000 --- a/src/blackgui/cockpitv1component.h +++ /dev/null @@ -1,103 +0,0 @@ -#ifndef BLACKGUI_COCKPITV1COMPONENT_H -#define BLACKGUI_COCKPITV1COMPONENT_H - -#include "blackgui/runtimebasedcomponent.h" -#include -#include - -namespace Ui { class CCockpitV1Component; } - - -namespace BlackGui -{ - - /*! - * User componenet (users, clients) - */ - class CCockpitV1Component : public QWidget, public CRuntimeBasedComponent - { - Q_OBJECT - - public: - //! Constructor - explicit CCockpitV1Component(QWidget *parent = nullptr); - - //! Destructor - ~CCockpitV1Component(); - - //! Set external push buttons - void setExternalIdentButton(QPushButton *cockpitIdent); - - //! Volume 0..100 for COM1 - int getCom1Volume() const; - - //! Volume 0..100 for COM1 - int getCom2Volume() const; - - //! Pixmap for voice status - void setCockpitVoiceStatusPixmap(const QPixmap &pixmap); - - //! Object one of the volume widgets? - bool isCockpitVolumeWidget(const QObject *sender) const; - - //! Originator for signals - static const QString &cockpitOriginator(); - - public slots: - //! Update cockpit from context - void updateCockpitFromContext(const BlackMisc::Aviation::CAircraft &ownAircraft, const QString &originator); - - //! set SELCAL code - QString getSelcalCode() const; - - //! Volume 0..100 for COM1 - void setCom1Volume(int volume); - - //! Volume 0..100 for COM2 - void setCom2Volume(int volume); - - signals: - //! Audio volume changed - void audioVolumeChanged(); - - protected: - //! \copydoc CRuntimeBasedComponent::runtimeHasBeenSet - virtual void runtimeHasBeenSet() override; - - private slots: - //! Test SELCAL - void testSelcal(); - - //! Cockpit values changed from GUI - void cockpitValuesChanged(); - - //! Update voice rooms from list - void updateAudioVoiceRoomsFromObjects(const BlackMisc::Audio::CVoiceRoomList &selectedVoiceRooms, bool connected); - - //! Update the voice room members - void updateVoiceRoomMembers(); - - private: - Ui::CCockpitV1Component *ui; - QPushButton *m_externalCockpitIdentButton; //!< External ident button - QTimer *m_voiceRoomMembersTimer; - - //! Own aircraft object - BlackMisc::Aviation::CAircraft getOwnAircraft() const; - - //! COM frequencies displays - void updateComFrequencyDisplaysFromObjects(const BlackMisc::Aviation::CComSystem &com1, const BlackMisc::Aviation::CComSystem &com2); - - //! Cockpit updates - bool sendCockpitUpdates(const BlackMisc::Aviation::CAircraft &ownAircraft); - - //! Set audio voice rooms - void setAudioVoiceRoomUrls(); - - //! cockpit values to object, including back annotation - BlackMisc::Aviation::CAircraft cockpitValuesToObject(); - - }; -} - -#endif // guard diff --git a/src/blackgui/components/aircraftcomponent.cpp b/src/blackgui/components/aircraftcomponent.cpp new file mode 100644 index 000000000..91fbdb823 --- /dev/null +++ b/src/blackgui/components/aircraftcomponent.cpp @@ -0,0 +1,46 @@ +/* Copyright (C) 2013 + * Swift Project Community / Contributors + * + * This file is part of swift Project. It is subject to the license terms in the LICENSE file found in the top-level + * directory of this distribution and at http://www.swift-project.org/license.html. No part of Swift Project, + * including this file, may be copied, modified, propagated, or distributed except according to the terms + * contained in the LICENSE file. + */ + +#include "aircraftcomponent.h" +#include "ui_aircraftcomponent.h" + +namespace BlackGui +{ + namespace Components + { + + CAircraftComponent::CAircraftComponent(QWidget *parent) : + QTabWidget(parent), CRuntimeBasedComponent(nullptr, false), ui(new Ui::CAircraftComponent), m_timerComponent(nullptr) + { + ui->setupUi(this); + m_timerComponent = new CTimerBasedComponent(SLOT(update()), this); + } + + CAircraftComponent::~CAircraftComponent() + { + delete ui; + } + + void CAircraftComponent::update() + { + Q_ASSERT(this->ui->tvp_AircraftsInRange); + Q_ASSERT(this->getIContextNetwork()); + Q_ASSERT(this->getIContextSimulator()); + + if (this->getIContextNetwork()->isConnected()) + { + this->ui->tvp_AircraftsInRange->update(this->getIContextNetwork()->getAircraftsInRange()); + } + if (this->getIContextSimulator()->isConnected()) + { + this->ui->tvp_AirportsInRange->update(this->getIContextSimulator()->getAirportsInRange()); + } + } + } +} diff --git a/src/blackgui/components/aircraftcomponent.h b/src/blackgui/components/aircraftcomponent.h new file mode 100644 index 000000000..d3584e40f --- /dev/null +++ b/src/blackgui/components/aircraftcomponent.h @@ -0,0 +1,62 @@ +/* Copyright (C) 2013 + * swift Project Community / Contributors + * + * This file is part of swift Project. It is subject to the license terms in the LICENSE file found in the top-level + * directory of this distribution and at http://www.swift-project.org/license.html. No part of Swift Project, + * including this file, may be copied, modified, propagated, or distributed except according to the terms + * contained in the LICENSE file. + */ + +#ifndef BLACKGUI_AIRCRAFTCOMPONENT_H +#define BLACKGUI_AIRCRAFTCOMPONENT_H + +//! \file + +#include "blackgui/components/runtimebasedcomponent.h" +#include "blackgui/components/timerbasedcomponent.h" +#include "blackmisc/avaircraft.h" + +#include + +namespace Ui { class CAircraftComponent; } +namespace BlackGui +{ + namespace Components + { + + //! Aircraft widget + class CAircraftComponent : public QTabWidget, public CRuntimeBasedComponent + { + Q_OBJECT + + public: + //! Constructor + explicit CAircraftComponent(QWidget *parent = nullptr); + + //! Destructor + ~CAircraftComponent(); + + //! Timer for updating + CTimerBasedComponent *getTimerComponent() { return this->m_timerComponent; } + + public slots: + //! Update users + void update(); + + //! \copydoc CTimerBasedComponent::setUpdateIntervalSeconds + void setUpdateIntervalSeconds(int seconds) { Q_ASSERT(this->m_timerComponent); this->m_timerComponent->setUpdateIntervalSeconds(seconds); } + + //! \copydoc CTimerBasedComponent::setUpdateInterval + void setUpdateInterval(int milliSeconds) { Q_ASSERT(this->m_timerComponent); this->m_timerComponent->setUpdateInterval(milliSeconds); } + + //! \copydoc CTimerBasedComponent::stopTimer + void stopTimer() { Q_ASSERT(this->m_timerComponent); this->m_timerComponent->stopTimer(); } + + private: + Ui::CAircraftComponent *ui; + CTimerBasedComponent *m_timerComponent; + }; + } +} + +#endif // guard diff --git a/src/blackgui/aircraftcomponent.ui b/src/blackgui/components/aircraftcomponent.ui similarity index 79% rename from src/blackgui/aircraftcomponent.ui rename to src/blackgui/components/aircraftcomponent.ui index 51fed7cbf..35dfe346e 100644 --- a/src/blackgui/aircraftcomponent.ui +++ b/src/blackgui/components/aircraftcomponent.ui @@ -10,6 +10,12 @@ 300 + + + 0 + 0 + + Airports in range @@ -37,7 +43,7 @@ 0 - + false @@ -66,7 +72,7 @@ 0 - + false @@ -77,14 +83,14 @@ - BlackGui::CAircraftView + BlackGui::Views::CAircraftView QTableView -
blackgui/aircraftview.h
+
blackgui/views/aircraftview.h
- BlackGui::CAirportView + BlackGui::Views::CAirportView QTableView -
blackgui/airportview.h
+
blackgui/views/airportview.h
diff --git a/src/blackgui/components/atcstationcomponent.cpp b/src/blackgui/components/atcstationcomponent.cpp new file mode 100644 index 000000000..8d6662f6a --- /dev/null +++ b/src/blackgui/components/atcstationcomponent.cpp @@ -0,0 +1,190 @@ +/* Copyright (C) 2013 + * swift Project Community / Contributors + * + * This file is part of swift Project. It is subject to the license terms in the LICENSE file found in the top-level + * directory of this distribution and at http://www.swift-project.org/license.html. No part of Swift Project, + * including this file, may be copied, modified, propagated, or distributed except according to the terms + * contained in the LICENSE file. + */ + +#include "blackmisc/avinformationmessage.h" +#include "atcstationcomponent.h" +#include "ui_atcstationcomponent.h" + +//! \file + +using namespace BlackGui::Models; +using namespace BlackMisc::Aviation; +using namespace BlackCore; + +namespace BlackGui +{ + namespace Components + { + CAtcStationComponent::CAtcStationComponent(QWidget *parent) : + QTabWidget(parent), CRuntimeBasedComponent(nullptr, false), ui(new Ui::CAtcStationComponent), m_timerComponent(nullptr) + { + ui->setupUi(this); + this->m_timerComponent = new CTimerBasedComponent(SLOT(update()), this); + this->ui->tvp_AtcStationsBooked->setStationMode(CAtcStationListModel::StationsBooked); + + // Signal / Slots + bool connected = this->connect(this->ui->le_AtcStationsOnlineMetar, SIGNAL(returnPressed()), this, SLOT(getMetar())); + Q_ASSERT(connected); + connected = this->connect(this->ui->pb_AtcStationsLoadMetar, SIGNAL(clicked()), this, SLOT(getMetar())); + Q_ASSERT(connected); + this->connect(this, &QTabWidget::currentChanged, this, &CAtcStationComponent::atcStationsTabChanged); + this->connect(this->ui->tvp_AtcStationsOnline, &QTableView::clicked, this, &CAtcStationComponent::onlineAtcStationSelected); + this->connect(this->ui->pb_AtcStationsAtisReload, &QPushButton::clicked, this, &CAtcStationComponent::requestAtis); + this->connect(this->ui->pb_ReloadAtcStationsBooked, &QPushButton::clicked, this, &CAtcStationComponent::reloadAtcStationsBooked); + } + + CAtcStationComponent::~CAtcStationComponent() + { + delete ui; + } + + void CAtcStationComponent::runtimeHasBeenSet() + { + Q_ASSERT(this->getRuntime()); + Q_ASSERT(this->getIContextNetwork()); + if (this->getIContextNetwork()) + { + this->connect(this->getIContextNetwork(), &IContextNetwork::changedAtcStationsOnline, this, &CAtcStationComponent::changedAtcStationsOnline); + this->connect(this->getIContextNetwork(), &IContextNetwork::changedAtcStationsBooked, this, &CAtcStationComponent::changedAtcStationsBooked); + this->connect(this->getIContextNetwork(), &IContextNetwork::changedAtcStationOnlineConnectionStatus, this, &CAtcStationComponent::changedAtcStationOnlineConnectionStatus); + this->connect(this->getIContextNetwork(), &IContextNetwork::connectionStatusChanged, this, &CAtcStationComponent::connectionStatusChanged); + } + } + + void CAtcStationComponent::update() + { + Q_ASSERT(this->ui->tvp_AtcStationsBooked); + Q_ASSERT(this->ui->tvp_AtcStationsOnline); + Q_ASSERT(this->getIContextNetwork()); + + // initial read for bookings + if (this->ui->tvp_AtcStationsBooked->isEmpty()) this->reloadAtcStationsBooked(); + + if (this->getIContextNetwork()->isConnected()) + { + // update + if (this->m_timestampOnlineStationsChanged.isNull() || this->m_timestampLastReadOnlineStations.isNull() || + (this->m_timestampOnlineStationsChanged > this->m_timestampLastReadOnlineStations)) + { + this->ui->tvp_AtcStationsOnline->update(this->getIContextNetwork()->getAtcStationsOnline()); + this->m_timestampLastReadOnlineStations = QDateTime::currentDateTimeUtc(); + this->m_timestampOnlineStationsChanged = this->m_timestampLastReadOnlineStations; + } + } + else + { + this->ui->tvp_AtcStationsOnline->clear(); + this->ui->le_AtcStationsOnlineMetar->clear(); + } + } + + void CAtcStationComponent::reloadAtcStationsBooked() + { + Q_ASSERT(this->ui->tvp_AtcStationsBooked); + Q_ASSERT(this->getIContextNetwork()); + + QObject *sender = QObject::sender(); + if (sender == this->ui->pb_ReloadAtcStationsBooked && this->getIContextNetwork()) + { + this->getIContextNetwork()->readAtcBookingsFromSource(); // trigger new read + QTimer::singleShot(7500, this, SLOT(reloadAtcStationsBooked())); // deferred loading + } + else + { + this->ui->tvp_AtcStationsBooked->update(this->getIContextNetwork()->getAtcStationsBooked()); + this->m_timestampLastReadBookedStations = QDateTime::currentDateTimeUtc(); + } + } + + void CAtcStationComponent::changedAtcStationsOnline() + { + // just update timestamp, data will be pulled by time + // the timestamp will tell if there are any newer data + this->m_timestampOnlineStationsChanged = QDateTime::currentDateTimeUtc(); + } + + void CAtcStationComponent::connectionStatusChanged(uint from, uint to, const QString &message) + { + INetwork::ConnectionStatus fromStatus = static_cast(from); + INetwork::ConnectionStatus toStatus = static_cast(to); + Q_UNUSED(fromStatus); + Q_UNUSED(message); + if (INetwork::isDisconnectedStatus(toStatus)) + { + this->ui->tvp_AtcStationsOnline->clear(); + this->ui->le_AtcStationsOnlineMetar->clear(); + } + } + + void CAtcStationComponent::changedAtcStationOnlineConnectionStatus(const CAtcStation &station, bool added) + { + this->ui->tvp_AtcStationsOnline->changedAtcStationConnectionStatus(station, added); + } + + void CAtcStationComponent::changedAtcStationsBooked() + { + this->reloadAtcStationsBooked(); + } + + void CAtcStationComponent::getMetar(const QString &airportIcaoCode) + { + if (!this->getIContextNetwork()->isConnected()) + { + this->ui->te_AtcStationsOnlineInfo->clear(); + return; + } + QString icao = airportIcaoCode.isEmpty() ? this->ui->le_AtcStationsOnlineMetar->text().trimmed().toUpper() : airportIcaoCode.trimmed().toUpper(); + this->ui->le_AtcStationsOnlineMetar->setText(icao); + if (icao.length() != 4) return; + CInformationMessage metar = this->getIContextNetwork()->getMetar(icao); + if (metar.getType() != CInformationMessage::METAR) return; + if (metar.isEmpty()) + { + this->ui->te_AtcStationsOnlineInfo->clear(); + } + else + { + this->ui->te_AtcStationsOnlineInfo->setText(metar.getMessage()); + } + } + + void CAtcStationComponent::onlineAtcStationSelected(QModelIndex index) + { + this->ui->te_AtcStationsOnlineInfo->setText(""); // reset + const CAtcStation stationClicked = this->ui->tvp_AtcStationsOnline->derivedModel()->at(index); + QString infoMessage; + + if (stationClicked.hasAtis()) + { + infoMessage.append(stationClicked.getAtis().getMessage()); + } + if (stationClicked.hasMetar()) + { + if (!infoMessage.isEmpty()) infoMessage.append("\n\n"); + infoMessage.append(stationClicked.getMetar().getMessage()); + } + this->ui->te_AtcStationsOnlineInfo->setText(infoMessage); + } + + void CAtcStationComponent::atcStationsTabChanged() + { + if (this->currentWidget() == this->ui->tb_AtcStationsOnline) + { + if (this->m_timestampLastReadBookedStations.isNull()) + this->reloadAtcStationsBooked(); + } + } + + void CAtcStationComponent::requestAtis() + { + if (!this->getIContextNetwork()->isConnected()) return; + this->getIContextNetwork()->requestAtisUpdates(); + } + } +} diff --git a/src/blackgui/components/atcstationcomponent.h b/src/blackgui/components/atcstationcomponent.h new file mode 100644 index 000000000..1551a7de8 --- /dev/null +++ b/src/blackgui/components/atcstationcomponent.h @@ -0,0 +1,100 @@ +/* Copyright (C) 2013 + * swift Project Community / Contributors + * + * This file is part of swift Project. It is subject to the license terms in the LICENSE file found in the top-level + * directory of this distribution and at http://www.swift-project.org/license.html. No part of Swift Project, + * including this file, may be copied, modified, propagated, or distributed except according to the terms + * contained in the LICENSE file. + */ + +#ifndef BLACKGUI_ATCSTATIONCOMPONENT_H +#define BLACKGUI_ATCSTATIONCOMPONENT_H + +//! \file + +#include "blackgui/components/runtimebasedcomponent.h" +#include "blackgui/components/timerbasedcomponent.h" +#include "blackmisc/avatcstation.h" + +#include +#include + +namespace Ui { class CAtcStationComponent; } + +namespace BlackGui +{ + namespace Components + { + /*! + * ATC stations component + */ + class CAtcStationComponent : public QTabWidget, public CRuntimeBasedComponent + { + Q_OBJECT + + public: + //! Constructor + explicit CAtcStationComponent(QWidget *parent = nullptr); + + //! Destructor + ~CAtcStationComponent(); + + //! Timer for updating + CTimerBasedComponent *getTimerComponent() { return this->m_timerComponent; } + + public slots: + //! Update users + void update(); + + //! \copydoc CTimerBasedComponent::setUpdateIntervalSeconds + void setUpdateIntervalSeconds(int seconds) { Q_ASSERT(this->m_timerComponent); this->m_timerComponent->setUpdateIntervalSeconds(seconds); } + + //! \copydoc CTimerBasedComponent::setUpdateInterval + void setUpdateInterval(int milliSeconds) { Q_ASSERT(this->m_timerComponent); this->m_timerComponent->setUpdateInterval(milliSeconds); } + + //! \copydoc CTimerBasedComponent::stopTimer + void stopTimer() { Q_ASSERT(this->m_timerComponent); this->m_timerComponent->stopTimer(); } + + //! Get METAR for given ICAO airport code + void getMetar(const QString &airportIcaoCode = ""); + + //! \copydoc CAtcStationListModel::changedAtcStationConnectionStatus + void changedAtcStationOnlineConnectionStatus(const BlackMisc::Aviation::CAtcStation &station, bool added); + + protected: + //! \copydoc CRuntimeBasedComponent::runtimeHasBeenSet + void runtimeHasBeenSet() override; + + private slots: + + //! Request new ATIS + void requestAtis(); + + //! Online ATC station selected + void onlineAtcStationSelected(QModelIndex index); + + //! Tab changed + void atcStationsTabChanged(); + + //! Booked stations + void reloadAtcStationsBooked(); + + //! Booked stations changed + void changedAtcStationsBooked(); + + //! Online stations changed + void changedAtcStationsOnline(); + + //! Connection status has been changed + void connectionStatusChanged(uint from, uint to, const QString &message); + + private: + Ui::CAtcStationComponent *ui; + CTimerBasedComponent *m_timerComponent; + QDateTime m_timestampLastReadOnlineStations; + QDateTime m_timestampOnlineStationsChanged; + QDateTime m_timestampLastReadBookedStations; + }; + } +} +#endif // guard diff --git a/src/blackgui/atcstationcomponent.ui b/src/blackgui/components/atcstationcomponent.ui similarity index 96% rename from src/blackgui/atcstationcomponent.ui rename to src/blackgui/components/atcstationcomponent.ui index 2e4d2a747..5911e2338 100644 --- a/src/blackgui/atcstationcomponent.ui +++ b/src/blackgui/components/atcstationcomponent.ui @@ -37,7 +37,7 @@ 0 - + 0 @@ -247,7 +247,7 @@ 0 - + QFrame::StyledPanel @@ -289,9 +289,9 @@ - BlackGui::CAtcStationView + BlackGui::Views::CAtcStationView QTableView -
blackgui/atcstationview.h
+
blackgui/views/atcstationview.h
diff --git a/src/blackgui/components/cockpitv1component.cpp b/src/blackgui/components/cockpitv1component.cpp new file mode 100644 index 000000000..05ad7df56 --- /dev/null +++ b/src/blackgui/components/cockpitv1component.cpp @@ -0,0 +1,416 @@ +/* Copyright (C) 2013 + * swift Project Community / Contributors + * + * This file is part of swift project. It is subject to the license terms in the LICENSE file found in the top-level + * directory of this distribution and at http://www.swift-project.org/license.html. No part of Swift Project, + * including this file, may be copied, modified, propagated, or distributed except according to the terms + * contained in the LICENSE file. + */ + +#include "cockpitv1component.h" +#include "ui_cockpitv1component.h" + +#include "blackgui/models/atcstationlistmodel.h" +#include "blackcore/context_ownaircraft.h" +#include "blackcore/context_ownaircraft_impl.h" +#include "blackcore/context_network.h" +#include "blackmisc/voiceroom.h" + +using namespace BlackCore; +using namespace BlackMisc; +using namespace BlackGui; +using namespace BlackGui::Models; +using namespace BlackMisc::Network; +using namespace BlackMisc::Aviation; +using namespace BlackMisc::PhysicalQuantities; +using namespace BlackMisc::Geo; +using namespace BlackMisc::Settings; +using namespace BlackMisc::Math; +using namespace BlackMisc::Audio; +using namespace BlackSound; + +namespace BlackGui +{ + namespace Components + { + CCockpitV1Component::CCockpitV1Component(QWidget *parent) : + QWidget(parent), CRuntimeBasedComponent(nullptr, false), ui(new Ui::CCockpitV1Component), m_externalCockpitIdentButton(nullptr), m_voiceRoomMembersTimer(nullptr) + { + ui->setupUi(this); + + // init encapsulated table views / models + this->ui->tvp_CockpitVoiceRoom1->setUserMode(CUserListModel::UserShort); + this->ui->tvp_CockpitVoiceRoom2->setUserMode(CUserListModel::UserShort); + + // SELCAL pairs in cockpit + this->ui->cb_CockpitSelcal1->clear(); + this->ui->cb_CockpitSelcal2->clear(); + this->ui->cb_CockpitSelcal1->addItems(BlackMisc::Aviation::CSelcal::codePairs()); + this->ui->cb_CockpitSelcal2->addItems(BlackMisc::Aviation::CSelcal::codePairs()); + + // cockpit GUI events + this->connect(this->ui->ds_CockpitCom1Active, &QDoubleSpinBox::editingFinished, this, &CCockpitV1Component::cockpitValuesChanged); + this->connect(this->ui->ds_CockpitCom2Active, &QDoubleSpinBox::editingFinished, this, &CCockpitV1Component::cockpitValuesChanged); + this->connect(this->ui->ds_CockpitCom1Standby, &QDoubleSpinBox::editingFinished, this, &CCockpitV1Component::cockpitValuesChanged); + this->connect(this->ui->ds_CockpitCom2Standby, &QDoubleSpinBox::editingFinished, this, &CCockpitV1Component::cockpitValuesChanged); + this->connect(this->ui->ds_CockpitTransponder, &QDoubleSpinBox::editingFinished, this, &CCockpitV1Component::cockpitValuesChanged); + + this->connect(this->ui->cb_CockpitVoiceRoom1Override, &QCheckBox::clicked, this, &CCockpitV1Component::setAudioVoiceRoomUrls); + this->connect(this->ui->cb_CockpitVoiceRoom2Override, &QCheckBox::clicked, this, &CCockpitV1Component::setAudioVoiceRoomUrls); + this->connect(this->ui->le_CockpitVoiceRoomCom1, &QLineEdit::returnPressed, this, &CCockpitV1Component::setAudioVoiceRoomUrls); + this->connect(this->ui->le_CockpitVoiceRoomCom2, &QLineEdit::returnPressed, this, &CCockpitV1Component::setAudioVoiceRoomUrls); + this->connect(this->ui->pb_CockpitToggleCom1, &QPushButton::clicked, this, &CCockpitV1Component::cockpitValuesChanged); + this->connect(this->ui->pb_CockpitToggleCom2, &QPushButton::clicked, this, &CCockpitV1Component::cockpitValuesChanged); + this->connect(this->ui->pb_CockpitSelcalTest, &QPushButton::clicked, this, &CCockpitV1Component::testSelcal); + + this->connect(this->ui->cbp_CockpitTransponderMode, &CTransponderModeSelector::valueChanged, this, &CCockpitV1Component::cockpitValuesChanged); + + this->connect(this->ui->di_CockpitCom1Volume, &QDial::valueChanged, this, &CCockpitV1Component::setCom1Volume); + this->connect(this->ui->di_CockpitCom2Volume, &QDial::valueChanged, this, &CCockpitV1Component::setCom2Volume); + + // timer + this->m_voiceRoomMembersTimer = new QTimer(this); + this->connect(this->m_voiceRoomMembersTimer, &QTimer::timeout, this, &CCockpitV1Component::updateVoiceRoomMembers); + this->m_voiceRoomMembersTimer->start(10 * 1000); + } + + void CCockpitV1Component::runtimeHasBeenSet() + { + // hook up with changes from own aircraft context + Q_ASSERT(this->getIContextOwnAircraft()); + this->connect(this->getIContextOwnAircraft(), &IContextOwnAircraft::changedAircraftCockpit, this, &CCockpitV1Component::updateCockpitFromContext); + + // Audio is optional + if (this->getIContextAudio()) + { + this->connect(this->getIContextAudio(), &IContextAudio::changedVoiceRooms, this, &CCockpitV1Component::updateAudioVoiceRoomsFromObjects); + } + } + + CCockpitV1Component::~CCockpitV1Component() + { + delete ui; + } + + void CCockpitV1Component::setExternalIdentButton(QPushButton *cockpitIdent) + { + if (this->m_externalCockpitIdentButton) disconnect(this->m_externalCockpitIdentButton); + this->m_externalCockpitIdentButton = cockpitIdent; + if (this->m_externalCockpitIdentButton) this->connect(this->m_externalCockpitIdentButton, &QPushButton::clicked, this, &CCockpitV1Component::cockpitValuesChanged); + } + + void CCockpitV1Component::setCom1Volume(int volume) + { + if (volume > 100) volume = 100; + if (volume < 0) volume = 0; + if (QObject::sender() != ui->di_CockpitCom1Volume) + this->ui->di_CockpitCom1Volume->setValue(volume); + this->getIContextOwnAircraft()->setAudioOutputVolumes(volume, this->ui->di_CockpitCom2Volume->value()); + emit this->audioVolumeChanged(); + } + + void CCockpitV1Component::setCom2Volume(int volume) + { + if (volume > 100) volume = 100; + if (volume < 0) volume = 0; + if (QObject::sender() != ui->di_CockpitCom2Volume) + this->ui->di_CockpitCom2Volume->setValue(volume); + this->getIContextOwnAircraft()->setAudioOutputVolumes(this->ui->di_CockpitCom1Volume->value(), volume); + emit this->audioVolumeChanged(); + } + + int CCockpitV1Component::getCom1Volume() const + { + return this->ui->di_CockpitCom1Volume->value(); + } + + int CCockpitV1Component::getCom2Volume() const + { + return this->ui->di_CockpitCom2Volume->value(); + } + + void CCockpitV1Component::setCockpitVoiceStatusPixmap(const QPixmap &pixmap) + { + this->ui->lbl_CockpitVoiceStatus->setPixmap(pixmap); + } + + bool CCockpitV1Component::isCockpitVolumeWidget(const QObject *sender) const + { + return + sender == this->ui->di_CockpitCom1Volume || + sender == this->ui->di_CockpitCom2Volume; + } + + const QString &CCockpitV1Component::cockpitOriginator() + { + static const QString o = QString("COCKPITV1:").append(QString::number(QDateTime::currentMSecsSinceEpoch())); + return o; + } + + CAircraft CCockpitV1Component::getOwnAircraft() const + { + Q_ASSERT(this->getIContextOwnAircraft()); + // direct object from local context + if (this->getIContextOwnAircraft()->usingLocalObjects()) return this->getRuntime()->getCContextOwnAircraft()->ownAircraft(); + + // non local + if (this->canPingApplicationContext()) return this->getIContextOwnAircraft()->getOwnAircraft(); + return CAircraft(); // anything better here, or status? + } + + void CCockpitV1Component::cockpitValuesChanged() + { + QObject *sender = QObject::sender(); + if (sender == this->ui->pb_CockpitToggleCom1) + { + if (this->ui->ds_CockpitCom1Standby->value() == this->ui->ds_CockpitCom1Active->value()) return; + double f = this->ui->ds_CockpitCom1Active->value(); + this->ui->ds_CockpitCom1Active->setValue(this->ui->ds_CockpitCom1Standby->value()); + this->ui->ds_CockpitCom1Standby->setValue(f); + } + else if (sender == this->ui->pb_CockpitToggleCom2) + { + if (this->ui->ds_CockpitCom2Standby->value() == this->ui->ds_CockpitCom2Active->value()) return; + double f = this->ui->ds_CockpitCom2Active->value(); + this->ui->ds_CockpitCom2Active->setValue(this->ui->ds_CockpitCom2Standby->value()); + this->ui->ds_CockpitCom2Standby->setValue(f); + } + else if (sender == this->ui->cbp_CockpitTransponderMode) + { + // toggle the external button + if (this->ui->cbp_CockpitTransponderMode->isIdentSelected()) + { + if (this->m_externalCockpitIdentButton) this->m_externalCockpitIdentButton->setStyleSheet("background: red"); + } + else + { + if (this->m_externalCockpitIdentButton) this->m_externalCockpitIdentButton->setStyleSheet(""); + } + } + else if (sender == this->m_externalCockpitIdentButton) + { + // toggle the combo box + if (this->ui->cbp_CockpitTransponderMode->isIdentSelected()) + { + this->ui->cbp_CockpitTransponderMode->resetTransponderMode(); + } + else + { + this->ui->cbp_CockpitTransponderMode->setSelectedTransponderModeStateIdent(); // trigger real button and whole process + } + } + + CAircraft ownAircraft = this->cockpitValuesToObject(); + this->sendCockpitUpdates(ownAircraft); + } + + CAircraft CCockpitV1Component::cockpitValuesToObject() + { + CAircraft ownAircraft = this->getOwnAircraft(); + CTransponder transponder = ownAircraft.getTransponder(); + CComSystem com1 = ownAircraft.getCom1System(); + CComSystem com2 = ownAircraft.getCom2System(); + + // + // Transponder + // + QString transponderCode = QString::number(qRound(this->ui->ds_CockpitTransponder->value())); + if (CTransponder::isValidTransponderCode(transponderCode)) + { + transponder.setTransponderCode(transponderCode); + } + else + { + this->sendStatusMessage(CStatusMessage::getValidationError("Wrong transponder code, reset")); + this->ui->ds_CockpitTransponder->setValue(transponder.getTransponderCode()); + } + transponder.setTransponderMode(this->ui->cbp_CockpitTransponderMode->getSelectedTransponderMode()); + + // + // COM units + // + com1.setFrequencyActiveMHz(this->ui->ds_CockpitCom1Active->value()); + com1.setFrequencyStandbyMHz(this->ui->ds_CockpitCom1Standby->value()); + com2.setFrequencyActiveMHz(this->ui->ds_CockpitCom2Active->value()); + com2.setFrequencyStandbyMHz(this->ui->ds_CockpitCom2Standby->value()); + this->updateComFrequencyDisplaysFromObjects(com1, com2); // back annotation after rounding + + ownAircraft.setCom1System(com1); + ownAircraft.setCom2System(com2); + ownAircraft.setTransponder(transponder); + return ownAircraft; + } + + void CCockpitV1Component::updateComFrequencyDisplaysFromObjects(const CComSystem &com1, const CComSystem &com2) + { + double freq = com1.getFrequencyActive().valueRounded(CFrequencyUnit::MHz(), 3); + if (freq != this->ui->ds_CockpitCom1Active->value()) + this->ui->ds_CockpitCom1Active->setValue(freq); + + freq = com2.getFrequencyActive().valueRounded(CFrequencyUnit::MHz(), 3); + if (freq != this->ui->ds_CockpitCom2Active->value()) + this->ui->ds_CockpitCom2Active->setValue(freq); + + freq = com1.getFrequencyStandby().valueRounded(CFrequencyUnit::MHz(), 3); + if (freq != this->ui->ds_CockpitCom1Standby->value()) + this->ui->ds_CockpitCom1Standby->setValue(freq); + + freq = com2.getFrequencyStandby().valueRounded(CFrequencyUnit::MHz(), 3); + if (freq != this->ui->ds_CockpitCom2Standby->value()) + this->ui->ds_CockpitCom2Standby->setValue(freq); + } + + void CCockpitV1Component::updateCockpitFromContext(const CAircraft &ownAircraft, const QString &originator) + { + if (originator == CCockpitV1Component::cockpitOriginator()) return; // comes from myself + + // update GUI elements + // avoid unnecessary change events as far as possible + const CComSystem com1 = ownAircraft.getCom1System(); // aircraft just updated or set from context + const CComSystem com2 = ownAircraft.getCom2System(); + const CTransponder transponder = ownAircraft.getTransponder(); + + // update the frequencies + this->updateComFrequencyDisplaysFromObjects(com1, com2); + + // update transponder + qint32 tc = transponder.getTransponderCode(); + if (tc != static_cast(this->ui->ds_CockpitTransponder->value())) + this->ui->ds_CockpitTransponder->setValue(tc); + + this->ui->cbp_CockpitTransponderMode->setSelectedTransponderMode(transponder.getTransponderMode()); + + if (this->getIContextNetwork()) + { + CAtcStationList selectedStations = this->getIContextNetwork()->getSelectedAtcStations(); + CAtcStation com1Station = selectedStations[0]; + CAtcStation com2Station = selectedStations[1]; + if (com1Station.getCallsign().isEmpty()) + this->ui->lbl_CockpitCom1->setToolTip(""); + else + this->ui->lbl_CockpitCom1->setToolTip(com1Station.getCallsign().getStringAsSet()); + if (com2Station.getCallsign().isEmpty()) + this->ui->lbl_CockpitCom2->setToolTip(""); + else + this->ui->lbl_CockpitCom2->setToolTip(com2Station.getCallsign().getStringAsSet()); + } + } + + bool CCockpitV1Component::sendCockpitUpdates(const CAircraft &ownAircraft) + { + // + // Send to context + // + bool changedCockpit = false; + if (this->getIContextOwnAircraft()) + { + changedCockpit = this->getIContextOwnAircraft()->updateOwnCockpit(ownAircraft.getCom1System(), ownAircraft.getCom2System(), ownAircraft.getTransponder(), CCockpitV1Component::cockpitOriginator()); + } + return changedCockpit; + } + + void CCockpitV1Component::setAudioVoiceRoomUrls() + { + Q_ASSERT(this->getIContextOwnAircraft()); + + // make fields readonly if not overriding + this->ui->le_CockpitVoiceRoomCom1->setReadOnly(!this->ui->cb_CockpitVoiceRoom1Override->isChecked()); + this->ui->le_CockpitVoiceRoomCom2->setReadOnly(!this->ui->cb_CockpitVoiceRoom2Override->isChecked()); + + QString room1; + QString room2; + if (this->ui->cb_CockpitVoiceRoom1Override->isChecked()) room1 = ui->le_CockpitVoiceRoomCom1->text(); + if (this->ui->cb_CockpitVoiceRoom2Override->isChecked()) room2 = ui->le_CockpitVoiceRoomCom2->text(); + this->getIContextOwnAircraft()->setAudioVoiceRoomOverrideUrls(room1, room2); + } + + void CCockpitV1Component::updateAudioVoiceRoomsFromObjects(const CVoiceRoomList &selectedVoiceRooms, bool connected) + { + Q_ASSERT(selectedVoiceRooms.size() == 2); + CVoiceRoom room1 = selectedVoiceRooms[0]; + CVoiceRoom room2 = selectedVoiceRooms[1]; + + // KB_REMOVE + qDebug() << "selected rooms" << room1.isConnected() << room1.getVoiceRoomUrl() << room2.isConnected() << room2.getVoiceRoomUrl(); + + // remark + // isAudioPlaying() is not set, as this is only a temporary value when really "something is playing" + + bool changedUrl1 = (room1.getVoiceRoomUrl() == this->ui->le_CockpitVoiceRoomCom1->text()); + this->ui->le_CockpitVoiceRoomCom1->setText(room1.getVoiceRoomUrl()); + if (room1.isConnected()) + { + this->ui->le_CockpitVoiceRoomCom1->setStyleSheet("background: green"); + if (this->getIContextAudio()) this->ui->tvp_CockpitVoiceRoom1->update(this->getIContextAudio()->getCom1RoomUsers()); + } + else + { + this->ui->le_CockpitVoiceRoomCom1->setStyleSheet(""); + this->ui->tvp_CockpitVoiceRoom1->clear(); + } + + bool changedUrl2 = (room2.getVoiceRoomUrl() == this->ui->le_CockpitVoiceRoomCom2->text()); + this->ui->le_CockpitVoiceRoomCom2->setText(room2.getVoiceRoomUrl()); + if (room2.isConnected()) + { + this->ui->le_CockpitVoiceRoomCom2->setStyleSheet("background: green"); + } + else + { + this->ui->le_CockpitVoiceRoomCom2->setStyleSheet(""); + this->ui->tvp_CockpitVoiceRoom2->clear(); + } + if (changedUrl1 || changedUrl2) + { + this->updateVoiceRoomMembers(); + + // notify + if (this->getIContextAudio()) + { + CNotificationSounds::Notification sound = connected ? + CNotificationSounds::NotificationVoiceRoomJoined : + CNotificationSounds::NotificationVoiceRoomLeft; + this->getIContextAudio()->playNotification(static_cast(sound), true); + } + } + } + + void CCockpitV1Component::updateVoiceRoomMembers() + { + if (!this->getIContextAudio()) return; + if (!this->ui->le_CockpitVoiceRoomCom1->text().trimmed().isEmpty()) + this->ui->tvp_CockpitVoiceRoom1->update(this->getIContextAudio()->getCom1RoomUsers()); + else + this->ui->tvp_CockpitVoiceRoom1->clear(); + + if (!this->ui->le_CockpitVoiceRoomCom2->text().trimmed().isEmpty()) + this->ui->tvp_CockpitVoiceRoom2->update(this->getIContextAudio()->getCom2RoomUsers()); + else + this->ui->tvp_CockpitVoiceRoom2->clear(); + } + + void CCockpitV1Component::testSelcal() + { + QString selcalCode = this->getSelcalCode(); + if (!CSelcal::isValidCode(selcalCode)) + { + this->sendStatusMessage(CStatusMessage(CStatusMessage::TypeValidation, CStatusMessage::SeverityWarning, "Invalid SELCAL codde")); + } + else if (this->getIContextAudio()) + { + CSelcal selcal(selcalCode); + this->getIContextAudio()->playSelcalTone(selcal); + } + else + { + this->sendStatusMessage(CStatusMessage(CStatusMessage::TypeAudio, CStatusMessage::SeverityError, "No audio available")); + } + } + + QString CCockpitV1Component::getSelcalCode() const + { + QString selcal = this->ui->cb_CockpitSelcal1->currentText().append(this->ui->cb_CockpitSelcal2->currentText()); + return selcal; + } + } +} // guard diff --git a/src/blackgui/components/cockpitv1component.h b/src/blackgui/components/cockpitv1component.h new file mode 100644 index 000000000..ea8db7227 --- /dev/null +++ b/src/blackgui/components/cockpitv1component.h @@ -0,0 +1,113 @@ +/* Copyright (C) 2013 + * swift Project Community / Contributors + * + * This file is part of swift project. It is subject to the license terms in the LICENSE file found in the top-level + * directory of this distribution and at http://www.swift-project.org/license.html. No part of Swift Project, + * including this file, may be copied, modified, propagated, or distributed except according to the terms + * contained in the LICENSE file. + */ + +#ifndef BLACKGUI_COCKPITV1COMPONENT_H +#define BLACKGUI_COCKPITV1COMPONENT_H + +//! \file + +#include "blackgui/components/runtimebasedcomponent.h" +#include +#include + +namespace Ui { class CCockpitV1Component; } +namespace BlackGui +{ + namespace Components + { + + //! User componenet (users, clients) + class CCockpitV1Component : public QWidget, public CRuntimeBasedComponent + { + Q_OBJECT + + public: + //! Constructor + explicit CCockpitV1Component(QWidget *parent = nullptr); + + //! Destructor + ~CCockpitV1Component(); + + //! Set external push buttons + void setExternalIdentButton(QPushButton *cockpitIdent); + + //! Volume 0..100 for COM1 + int getCom1Volume() const; + + //! Volume 0..100 for COM1 + int getCom2Volume() const; + + //! Pixmap for voice status + void setCockpitVoiceStatusPixmap(const QPixmap &pixmap); + + //! Object one of the volume widgets? + bool isCockpitVolumeWidget(const QObject *sender) const; + + //! Originator for signals + static const QString &cockpitOriginator(); + + public slots: + //! Update cockpit from context + void updateCockpitFromContext(const BlackMisc::Aviation::CAircraft &ownAircraft, const QString &originator); + + //! set SELCAL code + QString getSelcalCode() const; + + //! Volume 0..100 for COM1 + void setCom1Volume(int volume); + + //! Volume 0..100 for COM2 + void setCom2Volume(int volume); + + signals: + //! Audio volume changed + void audioVolumeChanged(); + + protected: + //! \copydoc CRuntimeBasedComponent::runtimeHasBeenSet + virtual void runtimeHasBeenSet() override; + + private slots: + //! Test SELCAL + void testSelcal(); + + //! Cockpit values changed from GUI + void cockpitValuesChanged(); + + //! Update voice rooms from list + void updateAudioVoiceRoomsFromObjects(const BlackMisc::Audio::CVoiceRoomList &selectedVoiceRooms, bool connected); + + //! Update the voice room members + void updateVoiceRoomMembers(); + + private: + Ui::CCockpitV1Component *ui; + QPushButton *m_externalCockpitIdentButton; //!< External ident button + QTimer *m_voiceRoomMembersTimer; + + //! Own aircraft object + BlackMisc::Aviation::CAircraft getOwnAircraft() const; + + //! COM frequencies displays + void updateComFrequencyDisplaysFromObjects(const BlackMisc::Aviation::CComSystem &com1, const BlackMisc::Aviation::CComSystem &com2); + + //! Cockpit updates + bool sendCockpitUpdates(const BlackMisc::Aviation::CAircraft &ownAircraft); + + //! Set audio voice rooms + void setAudioVoiceRoomUrls(); + + //! cockpit values to object, including back annotation + BlackMisc::Aviation::CAircraft cockpitValuesToObject(); + + }; + } +} + +#endif // guard diff --git a/src/blackgui/cockpitv1component.ui b/src/blackgui/components/cockpitv1component.ui similarity index 97% rename from src/blackgui/cockpitv1component.ui rename to src/blackgui/components/cockpitv1component.ui index 0b0991bd5..25be35e8b 100644 --- a/src/blackgui/cockpitv1component.ui +++ b/src/blackgui/components/cockpitv1component.ui @@ -411,7 +411,7 @@ - :/blackgui/icons/audiovolumelow.png + :/blackgui/icons/audiovolumelow.png
@@ -520,7 +520,7 @@
- + QAbstractItemView::SingleSelection @@ -533,7 +533,7 @@ - + QAbstractItemView::SingleSelection @@ -551,9 +551,9 @@ - BlackGui::CUserView + BlackGui::Views::CUserView QTableView -
blackgui/userview.h
+
blackgui/views/userview.h
BlackGui::CTransponderModeSelector @@ -561,8 +561,6 @@
blackgui/transpondermodeselector.h
- - - + diff --git a/src/blackgui/components/flightplancomponent.cpp b/src/blackgui/components/flightplancomponent.cpp new file mode 100644 index 000000000..f86da63a5 --- /dev/null +++ b/src/blackgui/components/flightplancomponent.cpp @@ -0,0 +1,405 @@ +/* Copyright (C) 2013 + * swift Project Community / Contributors + * + * This file is part of swift Project. It is subject to the license terms in the LICENSE file found in the top-level + * directory of this distribution and at http://www.swift-project.org/license.html. No part of Swift Project, + * including this file, may be copied, modified, propagated, or distributed except according to the terms + * contained in the LICENSE file. + */ + +#include "flightplancomponent.h" +#include "ui_flightplancomponent.h" + +using namespace BlackMisc; +using namespace BlackMisc::Aviation; +using namespace BlackMisc::PhysicalQuantities; + +namespace BlackGui +{ + namespace Components + { + CFlightPlanComponent::CFlightPlanComponent(QWidget *parent) : + QTabWidget(parent), CRuntimeBasedComponent(nullptr, false), ui(new Ui::CFlightPlanComponent) + { + ui->setupUi(this); + connect(this->ui->pb_Send, &QPushButton::pressed, this, &CFlightPlanComponent::sendFlightPlan); + connect(this->ui->pb_Load, &QPushButton::pressed, this, &CFlightPlanComponent::loadFlightPlanFromNetwork); + connect(this->ui->pb_Reset, &QPushButton::pressed, this, &CFlightPlanComponent::resetFlightPlan); + connect(this->ui->pb_ValidateFlightPlan, &QPushButton::pressed, this, &CFlightPlanComponent::validateFlightPlan); + + bool c; + c = connect(this->ui->cb_VoiceCapabilities, SIGNAL(currentIndexChanged(int)), this, SLOT(buildRemarkString())); + Q_ASSERT(c); + c = connect(this->ui->cb_NavigationEquipment, SIGNAL(currentIndexChanged(int)), this, SLOT(buildRemarkString())); + Q_ASSERT(c); + c = connect(this->ui->cb_PerformanceCategory, SIGNAL(currentIndexChanged(int)), this, SLOT(buildRemarkString())); + Q_ASSERT(c); + c = connect(this->ui->cb_PilotRating, SIGNAL(currentIndexChanged(int)), this, SLOT(buildRemarkString())); + Q_ASSERT(c); + c = connect(this->ui->cb_RequiredNavigationPerformance, SIGNAL(currentIndexChanged(int)), this, SLOT(buildRemarkString())); + Q_ASSERT(c); + c = connect(this->ui->cb_NoSidsStarts, SIGNAL(toggled(bool)), this, SLOT(buildRemarkString())); + Q_ASSERT(c); + c = connect(this->ui->le_AircraftRegistration, SIGNAL(textChanged(QString)), this, SLOT(buildRemarkString())); + Q_ASSERT(c); + c = connect(this->ui->le_AirlineOperator, SIGNAL(textChanged(QString)), this, SLOT(buildRemarkString())); + Q_ASSERT(c); + Q_UNUSED(c); + + connect(this->ui->pte_AdditionalRemarks, &QPlainTextEdit::textChanged, this, &CFlightPlanComponent::buildRemarkString); + connect(this->ui->frp_SelcalCode, &CSelcalCodeSelector::valueChanged, this, &CFlightPlanComponent::buildRemarkString); + connect(this->ui->pb_CopyOver, &QPushButton::pressed, this, &CFlightPlanComponent::copyRemarks); + connect(this->ui->pb_RemarksGenerator, &QPushButton::clicked, this, &CFlightPlanComponent::currentTabGenerator); + + this->ui->frp_SelcalCode->resetSelcalCodes(true); + this->resetFlightPlan(); + this->buildRemarkString(); + } + + CFlightPlanComponent::~CFlightPlanComponent() + { + delete ui; + } + + void CFlightPlanComponent::prefillWithAircraftData(const BlackMisc::Aviation::CAircraft &ownAircraft) + { + this->ui->le_Callsign->setText(ownAircraft.getCallsign().asString()); + this->ui->le_AircraftType->setText(ownAircraft.getIcaoInfo().getAircraftDesignator()); + this->ui->le_PilotsName->setText(ownAircraft.getPilot().getRealName()); + } + + void CFlightPlanComponent::fillWithFlightPlanData(const BlackMisc::Aviation::CFlightPlan &flightPlan) + { + this->ui->le_AlternateAirport->setText(flightPlan.getAlternateAirportIcao().asString()); + this->ui->le_DestinationAirport->setText(flightPlan.getAlternateAirportIcao().asString()); + this->ui->le_OriginAirport->setText(flightPlan.getAlternateAirportIcao().asString()); + this->ui->pte_Route->setPlainText(flightPlan.getRoute()); + this->ui->pte_Remarks->setPlainText(flightPlan.getRemarks()); + this->ui->le_TakeOffTimePlanned->setText(flightPlan.getTakeoffTimePlannedHourMin()); + this->ui->le_FuelOnBoard->setText(flightPlan.getFuelTimeHourMin()); + this->ui->le_EstimatedTimeEnroute->setText(flightPlan.getEnrouteTimeHourMin()); + this->ui->le_CruiseTrueAirspeed->setText(flightPlan.getCruiseTrueAirspeed().valueRoundedWithUnit(BlackMisc::PhysicalQuantities::CSpeedUnit::kts(), 0)); + + CAltitude cruiseAlt = flightPlan.getCruiseAltitude(); + if (cruiseAlt.isFlightLevel()) + this->ui->le_CrusingAltitude->setText(cruiseAlt.toQString()); + else + this->ui->le_CrusingAltitude->setText(cruiseAlt.valueRoundedWithUnit(BlackMisc::PhysicalQuantities::CLengthUnit::ft(), 0)); + } + + CFlightPlan CFlightPlanComponent::getFlightPlan() const + { + return this->m_flightPlan; + } + + BlackMisc::CStatusMessageList CFlightPlanComponent::validateAndInitializeFlightPlan(BlackMisc::Aviation::CFlightPlan &flightPlan) + { + BlackMisc::CStatusMessageList messages; + QString v; + + CFlightPlan::FlightRules rule = CFlightPlan::IFR; + if (this->ui->rb_TypeIfr->isChecked()) + rule = CFlightPlan::IFR; + else if (this->ui->rb_TypeVfr->isChecked()) + rule = CFlightPlan::VFR; + flightPlan.setFlightRule(rule); + + v = ui->le_Callsign->text().trimmed(); + if (v.isEmpty()) + { + QString m = QString("Missing %1").arg(this->ui->lbl_Callsign->text()); + messages.push_back(CStatusMessage::getValidationError(m)); + } + + v = ui->pte_Route->toPlainText().trimmed(); + if (v.isEmpty()) + { + QString m = QString("Missing flight plan route"); + messages.push_back(CStatusMessage::getValidationError(m)); + } + else if (v.length() > CFlightPlan::MaxRouteLength) + { + QString m = QString("Flight plan route length exceeded (%1 chars max.)").arg(CFlightPlan::MaxRouteLength); + messages.push_back(CStatusMessage::getValidationError(m)); + } + else + flightPlan.setRoute(v); + + v = ui->pte_Remarks->toPlainText().trimmed(); + if (v.isEmpty()) + { + QString m = QString("No remarks, voice capabilities are mandatory"); + messages.push_back(CStatusMessage::getValidationError(m)); + } + else if (v.length() > CFlightPlan::MaxRemarksLength) + { + QString m = QString("Flight plan remarks length exceeded (%1 chars max.)").arg(CFlightPlan::MaxRemarksLength); + messages.push_back(CStatusMessage::getValidationError(m)); + } + else + flightPlan.setRemarks(v); + + v = ui->le_EstimatedTimeEnroute->text(); + if (v.isEmpty() || v == defaultTime()) + { + QString m = QString("Missing %1").arg(this->ui->lbl_EstimatedTimeEnroute->text()); + messages.push_back(CStatusMessage::getValidationError(m)); + } + else + flightPlan.setEnrouteTime(v); + + v = ui->le_FuelOnBoard->text(); + if (v.isEmpty() || v == defaultTime()) + { + QString m = QString("Missing %1").arg(this->ui->lbl_FuelOnBorad->text()); + messages.push_back(CStatusMessage::getValidationError(m)); + } + else + flightPlan.setFuelTime(v); + + v = ui->le_TakeOffTimePlanned->text(); + if (v.isEmpty() || v == defaultTime()) + { + QString m = QString("Missing %1").arg(this->ui->lbl_TakeOffTimePlanned->text()); + messages.push_back(CStatusMessage::getValidationError(m)); + } + else + flightPlan.setTakeoffTimePlanned(v); + + static const QRegExp withUnit("\\D+"); + v = ui->le_CrusingAltitude->text().trimmed(); + if (!v.isEmpty() && withUnit.indexIn(v) < 0) + { + v += "ft"; + this->ui->le_CrusingAltitude->setText(v); + } + + CAltitude cruisingAltitude(v, CPqString::SeparatorsLocale); + if (v.isEmpty() || cruisingAltitude.isNull()) + { + QString m = QString("Wrong %1").arg(this->ui->lbl_CrusingAltitude->text()); + messages.push_back(CStatusMessage::getValidationError(m)); + } + else + flightPlan.setCruiseAltitude(cruisingAltitude); + + v = this->ui->le_AlternateAirport->text(); + if (v.isEmpty() || v.endsWith(defaultIcao(), Qt::CaseInsensitive)) + { + QString m = QString("Missing %1").arg(this->ui->lbl_AlternateAirport->text()); + messages.push_back(CStatusMessage::getValidationError(m)); + flightPlan.setAlternateAirportIcao(defaultIcao()); + } + else + flightPlan.setAlternateAirportIcao(v); + + v = this->ui->le_DestinationAirport->text(); + if (v.isEmpty() || v.endsWith(defaultIcao(), Qt::CaseInsensitive)) + { + QString m = QString("Missing %1").arg(this->ui->lbl_DestinationAirport->text()); + messages.push_back(CStatusMessage::getValidationError(m)); + flightPlan.setDestinationAirportIcao(defaultIcao()); + } + else + flightPlan.setDestinationAirportIcao(v); + + v = this->ui->le_CruiseTrueAirspeed->text(); + BlackMisc::PhysicalQuantities::CSpeed cruiseTAS; + cruiseTAS.parseFromString(v, CPqString::SeparatorsLocale); + if (cruiseTAS.isNull()) + { + QString m = QString("Wrong TAS, %1").arg(this->ui->lbl_CruiseTrueAirspeed->text()); + messages.push_back(CStatusMessage::getValidationError(m)); + flightPlan.setDestinationAirportIcao(defaultIcao()); + } + else + flightPlan.setCruiseTrueAirspeed(cruiseTAS); + + v = this->ui->le_OriginAirport->text(); + if (v.isEmpty() || v.endsWith(defaultIcao(), Qt::CaseInsensitive)) + { + QString m = QString("Missing %1").arg(this->ui->lbl_OriginAirport->text()); + messages.push_back(CStatusMessage::getValidationError(m)); + flightPlan.setOriginAirportIcao(defaultIcao()); + } + else + flightPlan.setOriginAirportIcao(v); + + return messages; + } + + void CFlightPlanComponent::sendFlightPlan() + { + CFlightPlan flightPlan; + CStatusMessageList messages = this->validateAndInitializeFlightPlan(flightPlan); + if (messages.isEmpty()) + { + // no error, send if possible + CStatusMessage m; + if (this->getIContextNetwork()->isConnected()) + { + flightPlan.setWhenLastSentOrLoaded(QDateTime::currentDateTimeUtc()); + this->getIContextNetwork()->sendFlightPlan(flightPlan); + this->ui->le_LastSent->setText(flightPlan.whenLastSentOrLoaded().toString()); + m = CStatusMessage::getInfoMessage("Sent flight plan", CStatusMessage::TypeTrafficNetwork); + } + else + { + flightPlan.setWhenLastSentOrLoaded(QDateTime()); // empty + this->ui->le_LastSent->clear(); + m = CStatusMessage::getErrorMessage("No errors, but not connected, cannot send flight plan", CStatusMessage::TypeTrafficNetwork); + } + this->sendStatusMessage(m); + this->m_flightPlan = flightPlan; // last valid FP + } + else + { + this->sendStatusMessages(messages); + } + } + + void CFlightPlanComponent::validateFlightPlan() + { + CFlightPlan flightPlan; + CStatusMessageList messages = this->validateAndInitializeFlightPlan(flightPlan); + if (messages.isEmpty()) + { + this->sendStatusMessage(CStatusMessage::getInfoMessage("No errors", CStatusMessage::TypeTrafficNetwork)); + } + else + { + this->sendStatusMessages(messages); + } + } + + void CFlightPlanComponent::resetFlightPlan() + { + if (this->getIContextNetwork()) + { + this->prefillWithAircraftData(this->getIContextOwnAircraft()->getOwnAircraft()); + } + this->ui->le_AircraftRegistration->clear(); + this->ui->le_AirlineOperator->clear(); + this->ui->le_CrusingAltitude->setText("FL70"); + this->ui->le_CruiseTrueAirspeed->setText("100 kts"); + this->ui->pte_Remarks->clear(); + this->ui->pte_Route->clear(); + this->ui->le_AlternateAirport->setText(defaultIcao()); + this->ui->le_DestinationAirport->setText(defaultIcao()); + this->ui->le_OriginAirport->setText(defaultIcao()); + this->ui->le_FuelOnBoard->setText(defaultTime()); + this->ui->le_EstimatedTimeEnroute->setText(defaultTime()); + this->ui->le_TakeOffTimePlanned->setText(QDateTime::currentDateTimeUtc().addSecs(30 * 60).toString("hh:mm")); + } + + void CFlightPlanComponent::loadFlightPlanFromNetwork() + { + if (!this->getIContextNetwork()) + { + this->sendStatusMessage(CStatusMessage::getInfoMessage("Cannot load flight plan, network not available", CStatusMessage::TypeTrafficNetwork)); + return; + } + if (!this->getIContextNetwork()->isConnected()) + { + this->sendStatusMessage(CStatusMessage::getWarningMessage("Cannot load flight plan, network not connected", CStatusMessage::TypeTrafficNetwork)); + return; + } + + CAircraft ownAircraft = this->getIContextOwnAircraft()->getOwnAircraft(); + CFlightPlan loadedPlan = this->getIContextNetwork()->loadFlightPlanFromNetwork(ownAircraft.getCallsign()); + if (loadedPlan.wasSentOrLoaded()) + { + this->fillWithFlightPlanData(loadedPlan); + this->sendStatusMessage(CStatusMessage::getInfoMessage("Updated with loaded flight plan", CStatusMessage::TypeTrafficNetwork)); + } + else + { + this->sendStatusMessage(CStatusMessage::getWarningMessage("No flight plan data", CStatusMessage::TypeTrafficNetwork)); + } + } + + void CFlightPlanComponent::buildRemarkString() + { + QString rem; + QString v = this->ui->cb_VoiceCapabilities->currentText().toUpper(); + if (v.contains("TEXT")) + rem.append("/T/ "); + else if (v.contains("VOICE")) + rem.append("/V/ "); + else if (v.contains("RECEIVE")) + rem.append("/R/ "); + + v = this->ui->le_AirlineOperator->text().trimmed(); + if (!v.isEmpty()) rem.append("OPR/").append(v).append(" "); + + v = this->ui->le_AircraftRegistration->text().trimmed(); + if (!v.isEmpty()) rem.append("REG/").append(v).append(" "); + + v = this->ui->cb_PilotRating->currentText().toUpper(); + if (v.contains("P1")) + rem.append("PR/P1 "); + else if (v.contains("P2")) + rem.append("PR/P2 "); + else if (v.contains("P3")) + rem.append("PR/P3 "); + else if (v.contains("P4")) + rem.append("PR/P4 "); + else if (v.contains("P5")) + rem.append("PR/P5 "); + + v = this->ui->cb_RequiredNavigationPerformance->currentText().toUpper(); + if (v.contains("10")) + rem.append("RNP10 "); + else if (v.contains("4")) + rem.append("RNP4 "); + + v = this->ui->cb_NavigationEquipment->currentText().toUpper(); + if (v.contains("VORS")) + rem.append("NAV/VORNDB "); + else if (v.contains("SIDS")) + rem.append("NAV/GPSRNAV "); + if (v.contains("DEFAULT")) + rem.append("NAV/GPS "); + else if (v.contains("OCEANIC")) + rem.append("NAV/GPSOCEANIC "); + + v = this->ui->cb_PerformanceCategory->currentText().toUpper(); + if (v.startsWith("A")) + rem.append("PER/A "); + else if (v.startsWith("B")) + rem.append("PER/B "); + else if (v.startsWith("C")) + rem.append("PER/C "); + else if (v.startsWith("D")) + rem.append("PER/D "); + else if (v.startsWith("E")) + rem.append("PER/E "); + + if (this->ui->frp_SelcalCode->hasValidCode()) + { + rem.append("SEL/").append(this->ui->frp_SelcalCode->getSelcalCode()); + rem.append(" "); + } + + if (this->ui->cb_NoSidsStarts->isChecked()) + rem.append("NO SID/STAR "); + + v = this->ui->pte_AdditionalRemarks->toPlainText().trimmed(); + if (!v.isEmpty()) rem.append(v); + + rem = rem.simplified().trimmed(); + this->ui->pte_RemarksGenerated->setPlainText(rem); + } + + void CFlightPlanComponent::copyRemarks() + { + this->ui->pte_Remarks->setPlainText(this->ui->pte_RemarksGenerated->toPlainText()); + this->sendStatusMessage(CStatusMessage::getInfoMessage("Copied remarks", CStatusMessage::TypeTrafficNetwork)); + } + + void CFlightPlanComponent::currentTabGenerator() + { + this->setCurrentWidget(this->ui->tb_RemarksGenerator); + } + } +} diff --git a/src/blackgui/components/flightplancomponent.h b/src/blackgui/components/flightplancomponent.h new file mode 100644 index 000000000..5d7d8347d --- /dev/null +++ b/src/blackgui/components/flightplancomponent.h @@ -0,0 +1,89 @@ +/* Copyright (C) 2013 + * swift Project Community / Contributors + * + * This file is part of swift project. It is subject to the license terms in the LICENSE file found in the top-level + * directory of this distribution and at http://www.swift-project.org/license.html. No part of Swift Project, + * including this file, may be copied, modified, propagated, or distributed except according to the terms + * contained in the LICENSE file. + */ + +#ifndef BLACKGUI_FLIGHTPLANCOMPONENT_H +#define BLACKGUI_FLIGHTPLANCOMPONENT_H + +//! \file + +#include "blackgui/components/runtimebasedcomponent.h" +#include "blackmisc/avaircraft.h" +#include "blackmisc/avflightplan.h" + +#include + +namespace Ui { class CFlightPlanComponent; } +namespace BlackGui +{ + namespace Components + { + + //! Flight plan widget + class CFlightPlanComponent : public QTabWidget, public CRuntimeBasedComponent + { + Q_OBJECT + + public: + //! Constructor + explicit CFlightPlanComponent(QWidget *parent = nullptr); + + //! Destructor + ~CFlightPlanComponent(); + + public slots: + //! Prefill with aircraft data + void prefillWithAircraftData(const BlackMisc::Aviation::CAircraft &ownAircraft); + + //! Prefill with aircraft dara + void fillWithFlightPlanData(const BlackMisc::Aviation::CFlightPlan &flightPlan); + + //! Get this flight plan + BlackMisc::Aviation::CFlightPlan getFlightPlan() const; + + private: + Ui::CFlightPlanComponent *ui; + + //! My flight plan + BlackMisc::Aviation::CFlightPlan m_flightPlan; + + //! Validate, generates status messages + BlackMisc::CStatusMessageList validateAndInitializeFlightPlan(BlackMisc::Aviation::CFlightPlan &fligtPlan); + + //! Default value for airport ICAO airports + static const QString &defaultIcao() { static QString d("ICAO"); return d; } + + //! Default value for time + static const QString &defaultTime() { static QString t("00:00"); return t; } + + private slots: + //! Send flightplan + void sendFlightPlan(); + + //! Reset Flightplan + void resetFlightPlan(); + + //! Load Flightplan + void loadFlightPlanFromNetwork(); + + //! Validate Flightplan + void validateFlightPlan(); + + //! Remark + void buildRemarkString(); + + //! Copy over + void copyRemarks(); + + //! Show generator tab page + void currentTabGenerator(); + + }; + } +} +#endif // guard diff --git a/src/blackgui/flightplancomponent.ui b/src/blackgui/components/flightplancomponent.ui similarity index 100% rename from src/blackgui/flightplancomponent.ui rename to src/blackgui/components/flightplancomponent.ui diff --git a/src/blackgui/components/infowindowcomponent.cpp b/src/blackgui/components/infowindowcomponent.cpp new file mode 100644 index 000000000..fd13dc678 --- /dev/null +++ b/src/blackgui/components/infowindowcomponent.cpp @@ -0,0 +1,149 @@ +/* Copyright (C) 2013 + * swift Project Community / Contributors + * + * This file is part of swift project. It is subject to the license terms in the LICENSE file found in the top-level + * directory of this distribution and at http://www.swift-project.org/license.html. No part of Swift Project, + * including this file, may be copied, modified, propagated, or distributed except according to the terms + * contained in the LICENSE file. + */ + +#include "infowindowcomponent.h" +#include "ui_infowindowcomponent.h" + +#include +#include + +using namespace BlackMisc; +using namespace BlackMisc::Network; + +namespace BlackGui +{ + namespace Components + { + + /* + * Constructor + */ + CInfoWindowComponent::CInfoWindowComponent(QWidget *parent) : + QWizardPage(parent), ui(new Ui::InfoWindow), m_hideTimer(nullptr) + { + ui->setupUi(this); + this->hide(); + this->m_hideTimer = new QTimer(this); + this->m_hideTimer->setSingleShot(true); + connect(this->m_hideTimer, &QTimer::timeout, this, &CInfoWindowComponent::hide); + connect(this->ui->pb_Close, &QPushButton::pressed, this, &CInfoWindowComponent::hide); + } + + /* + * Destructor + */ + CInfoWindowComponent::~CInfoWindowComponent() { } + + /* + * Info message for some time + */ + void CInfoWindowComponent::displayStringMessage(const QString &message, int displayTimeMs) + { + if (message.isEmpty()) + { + this->hide(); + return; + } + + // message and display + this->ui->te_StringMessage->setText(message); + this->setCurrentPage(this->ui->pg_StringMessage); + this->showWindow(displayTimeMs); + } + + /* + * Info message for some time + */ + void CInfoWindowComponent::displayTextMessage(const CTextMessage &textMessage, int displayTimeMs) + { + if (textMessage.isEmpty()) + { + this->hide(); + return; + } + + // message and display + this->ui->le_TmFrom->setText(textMessage.getSenderCallsign().asString()); + this->ui->le_TmTo->setText(textMessage.getRecipientCallsign().asString()); + this->ui->le_TmReceived->setText(textMessage.receivedTime()); + this->ui->te_TmText->setText(textMessage.getMessage()); + + this->setCurrentPage(this->ui->pg_TextMessage); + this->showWindow(displayTimeMs); + } + + /* + * Display status message + */ + void CInfoWindowComponent::displayStatusMessage(const CStatusMessage &statusMessage, int displayTimeMs) + { + if (statusMessage.isEmpty()) + { + this->hide(); + return; + } + + this->ui->le_SmSeverity->setText(statusMessage.getSeverityAsString()); + this->ui->le_SmType->setText(statusMessage.getTypeAsString()); + this->ui->te_SmStatusMessage->setText(statusMessage.getMessage()); + this->ui->lbl_SmSeverityIcon->setPixmap(statusMessage.toIcon()); + + this->setCurrentPage(this->ui->pg_StatusMessage); + this->showWindow(displayTimeMs); + } + + /* + * Display + */ + void CInfoWindowComponent::display(const BlackMisc::CVariant &variant, int displayTimeMs) + { + if (variant.isNull()) return; + if (variant.canConvert()) + this->displayTextMessage(variant.value(), displayTimeMs); + else if (variant.canConvert()) + this->displayStatusMessage(variant.value(), displayTimeMs); + else + this->displayStringMessage(variant.toString(), displayTimeMs); + } + + /* + * Init this window + */ + void CInfoWindowComponent::initWindow() + { + // center + const QRect parent = this->parentWidget()->geometry(); + const QRect myself = this->rect(); + int dx = (parent.width() - myself.width()) / 2; + int dy = (parent.height() - myself.height()) / 2; + dy -= 80; // some offset, in order to display further on top + this->move(dx, dy); + this->show(); + } + + /* + * Show window + */ + void CInfoWindowComponent::showWindow(int displayTimeMs) + { + this->initWindow(); + + // hide after some time + this->m_hideTimer->start(displayTimeMs); + } + + /* + * Set current widget + */ + void CInfoWindowComponent::setCurrentPage(QWidget *widget) + { + this->ui->sw_DifferentModes->setCurrentWidget(widget); + } + } +} // namespace diff --git a/src/blackgui/components/infowindowcomponent.h b/src/blackgui/components/infowindowcomponent.h new file mode 100644 index 000000000..290dc01b0 --- /dev/null +++ b/src/blackgui/components/infowindowcomponent.h @@ -0,0 +1,74 @@ +/* Copyright (C) 2013 + * swift Project Community / Contributors + * + * This file is part of swift project. It is subject to the license terms in the LICENSE file found in the top-level + * directory of this distribution and at http://www.swift-project.org/license.html. No part of Swift Project, + * including this file, may be copied, modified, propagated, or distributed except according to the terms + * contained in the LICENSE file. + */ + +#ifndef BLACKGUI_INFOWINDOW_H +#define BLACKGUI_INFOWINDOW_H + +//! \file + +#include "blackmisc/nwtextmessage.h" +#include "blackmisc/statusmessage.h" +#include "blackmisc/variant.h" + +#include +#include + +namespace Ui { class InfoWindow; } + +namespace BlackGui +{ + namespace Components + { + + /*! + * Multi purpose info window (pop up window) + */ + class CInfoWindowComponent : public QWizardPage + { + Q_OBJECT + + public: + const static int DefaultDisplayTimeMs = 4000; //!< Display n milliseconds + + //! Constructor + explicit CInfoWindowComponent(QWidget *parent = nullptr); + + //! Destructor + ~CInfoWindowComponent(); + + public slots: + + //! Info message, pure string + void displayStringMessage(const QString &message, int displayTimeMs = DefaultDisplayTimeMs); + + //! Info message, based on text message + void displayTextMessage(const BlackMisc::Network::CTextMessage &textMessage, int displayTimeMs = DefaultDisplayTimeMs); + + //! Info message, based on status message + void displayStatusMessage(const BlackMisc::CStatusMessage &statusMessage, int displayTimeMs = DefaultDisplayTimeMs); + + //! Display any of the specialized types + void display(const BlackMisc::CVariant &variant, int displayTimeMs = DefaultDisplayTimeMs); + + private: + QScopedPointer ui; //!< user interface + QTimer *m_hideTimer; + + //! Init the window + void initWindow(); + + //! Show window, hide after some time + void showWindow(int displayTimeMs); + + //! Current page + void setCurrentPage(QWidget *widget); + }; + } +} +#endif // guard diff --git a/src/blackgui/infowindowcomponent.ui b/src/blackgui/components/infowindowcomponent.ui similarity index 98% rename from src/blackgui/infowindowcomponent.ui rename to src/blackgui/components/infowindowcomponent.ui index a2fbc3432..f48b82d62 100644 --- a/src/blackgui/infowindowcomponent.ui +++ b/src/blackgui/components/infowindowcomponent.ui @@ -107,7 +107,7 @@ QTextEdit { - + :/blackgui/icons/close.png:/blackgui/icons/close.png
@@ -240,8 +240,6 @@ QTextEdit {
- - - + diff --git a/src/blackgui/components/logcomponent.cpp b/src/blackgui/components/logcomponent.cpp new file mode 100644 index 000000000..e8e514fcb --- /dev/null +++ b/src/blackgui/components/logcomponent.cpp @@ -0,0 +1,29 @@ +/* Copyright (C) 2013 + * swift Project Community / Contributors + * + * This file is part of swift project. It is subject to the license terms in the LICENSE file found in the top-level + * directory of this distribution and at http://www.swift-project.org/license.html. No part of Swift Project, + * including this file, may be copied, modified, propagated, or distributed except according to the terms + * contained in the LICENSE file. + */ + +#include "logcomponent.h" +#include "ui_logcomponent.h" + +namespace BlackGui +{ + namespace Components + { + + CLogComponent::CLogComponent(QWidget *parent) : + QFrame(parent), ui(new Ui::CLogComponent) + { + ui->setupUi(this); + } + + CLogComponent::~CLogComponent() + { + delete ui; + } + } +} diff --git a/src/blackgui/components/logcomponent.h b/src/blackgui/components/logcomponent.h new file mode 100644 index 000000000..eabac2f6d --- /dev/null +++ b/src/blackgui/components/logcomponent.h @@ -0,0 +1,40 @@ +/* Copyright (C) 2013 + * swift Project Community / Contributors + * + * This file is part of swift project. It is subject to the license terms in the LICENSE file found in the top-level + * directory of this distribution and at http://www.swift-project.org/license.html. No part of Swift Project, + * including this file, may be copied, modified, propagated, or distributed except according to the terms + * contained in the LICENSE file. + */ + +#ifndef BLACKGUI_LOGCOMPONENT_H +#define BLACKGUI_LOGCOMPONENT_H + +#include "runtimebasedcomponent.h" +#include + +namespace Ui { class CLogComponent; } + +namespace BlackGui +{ + namespace Components + { + + //! GUI displaying log and status messages + class CLogComponent : public QFrame, public CRuntimeBasedComponent + { + Q_OBJECT + + public: + //! Constructor + explicit CLogComponent(QWidget *parent = nullptr); + + //! Destructor + ~CLogComponent(); + + private: + Ui::CLogComponent *ui; + }; + } +} +#endif // guard diff --git a/src/blackgui/components/logcomponent.ui b/src/blackgui/components/logcomponent.ui new file mode 100644 index 000000000..56ded9030 --- /dev/null +++ b/src/blackgui/components/logcomponent.ui @@ -0,0 +1,161 @@ + + + CLogComponent + + + + 0 + 0 + 400 + 300 + + + + + 0 + 0 + + + + Frame + + + QFrame::StyledPanel + + + QFrame::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + + 3 + + + + + 0 + + + 3 + + + + + 0 + 0 + 398 + 250 + + + + Messages + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + QAbstractItemView::SingleSelection + + + QAbstractItemView::SelectRows + + + false + + + + + + + + + 0 + 0 + 98 + 71 + + + + Console + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + 0 + + + + + 75 + false + true + + + + QPlainTextEdit::NoWrap + + + true + + + + + + + + + + + + BlackGui::Views::CStatusMessageView + QTableView +
blackgui/views/statusmessageview.h
+
+
+ + +
diff --git a/src/blackgui/components/runtimebasedcomponent.cpp b/src/blackgui/components/runtimebasedcomponent.cpp new file mode 100644 index 000000000..d85236440 --- /dev/null +++ b/src/blackgui/components/runtimebasedcomponent.cpp @@ -0,0 +1,135 @@ +/* Copyright (C) 2013 + * swift Project Community / Contributors + * + * This file is part of swift Project. It is subject to the license terms in the LICENSE file found in the top-level + * directory of this distribution and at http://www.swift-project.org/license.html. No part of Swift Project, + * including this file, may be copied, modified, propagated, or distributed except according to the terms + * contained in the LICENSE file. + */ + +#include "runtimebasedcomponent.h" +#include + +namespace BlackGui +{ + namespace Components + { + void CRuntimeBasedComponent::setRuntime(BlackCore::CRuntime *runtime, bool runtimeOwner) + { + Q_ASSERT(runtime); + this->m_runtime = runtime; + this->m_runtimeOwner = runtimeOwner; + this->runtimeHasBeenSet(); + } + + void CRuntimeBasedComponent::setRuntimeForComponents(BlackCore::CRuntime *runtime, QWidget *parent) + { + if (!parent) return; + + // tested for runtime, not too slow, only some ms + QList children = parent->findChildren(); + foreach(QWidget * widget, children) + { + if (widget->objectName().isEmpty()) continue; // rule out unamed widgets + CRuntimeBasedComponent *rbc = dynamic_cast(widget); + if (rbc) rbc->setRuntime(runtime, false); + } + } + + void CRuntimeBasedComponent::createRuntime(const BlackCore::CRuntimeConfig &config, QObject *parent) + { + this->m_runtime = new BlackCore::CRuntime(config, parent); + this->m_runtimeOwner = true; + } + + void CRuntimeBasedComponent::sendStatusMessage(const BlackMisc::CStatusMessage &statusMessage) + { + if (!this->getIContextApplication()) return; + this->getIContextApplication()->sendStatusMessage(statusMessage); + } + + void CRuntimeBasedComponent::sendStatusMessages(const BlackMisc::CStatusMessageList &statusMessages) + { + if (!this->getIContextApplication()) return; + this->getIContextApplication()->sendStatusMessages(statusMessages); + } + + const BlackCore::IContextApplication *CRuntimeBasedComponent::getIContextApplication() const + { + if (!this->m_runtime) return nullptr; + return this->m_runtime->getIContextApplication(); + } + + BlackCore::IContextApplication *CRuntimeBasedComponent::getIContextApplication() + { + if (!this->m_runtime) return nullptr; + return this->m_runtime->getIContextApplication(); + } + + BlackCore::IContextAudio *CRuntimeBasedComponent::getIContextAudio() + { + if (!this->m_runtime) return nullptr; + return this->m_runtime->getIContextAudio(); + } + + const BlackCore::IContextAudio *CRuntimeBasedComponent::getIContextAudio() const + { + if (!this->m_runtime) return nullptr; + return this->m_runtime->getIContextAudio(); + } + + BlackCore::IContextNetwork *CRuntimeBasedComponent::getIContextNetwork() + { + if (!this->m_runtime) return nullptr; + return this->m_runtime->getIContextNetwork(); + } + + const BlackCore::IContextNetwork *CRuntimeBasedComponent::getIContextNetwork() const + { + if (!this->m_runtime) return nullptr; + return this->m_runtime->getIContextNetwork(); + } + + BlackCore::IContextOwnAircraft *CRuntimeBasedComponent::getIContextOwnAircraft() + { + if (!this->m_runtime) return nullptr; + return this->m_runtime->getIContextOwnAircraft(); + } + + const BlackCore::IContextOwnAircraft *CRuntimeBasedComponent::getIContextOwnAircraft() const + { + if (!this->m_runtime) return nullptr; + return this->m_runtime->getIContextOwnAircraft(); + } + + BlackCore::IContextSettings *CRuntimeBasedComponent::getIContextSettings() + { + if (!this->m_runtime) return nullptr; + return this->m_runtime->getIContextSettings(); + } + + const BlackCore::IContextSettings *CRuntimeBasedComponent::getIContextSettings() const + { + if (!this->m_runtime) return nullptr; + return this->m_runtime->getIContextSettings(); + } + + const BlackCore::IContextSimulator *CRuntimeBasedComponent::getIContextSimulator() const + { + if (!this->m_runtime) return nullptr; + return this->m_runtime->getIContextSimulator(); + } + + BlackCore::IContextSimulator *CRuntimeBasedComponent::getIContextSimulator() + { + if (!this->m_runtime) return nullptr; + return this->m_runtime->getIContextSimulator(); + } + + void CRuntimeBasedComponent::playNotifcationSound(BlackSound::CNotificationSounds::Notification notification) const + { + if (!this->getIContextAudio()) return; + this->getIContextAudio()->playNotification(static_cast(notification), true); + } + } +} diff --git a/src/blackgui/components/runtimebasedcomponent.h b/src/blackgui/components/runtimebasedcomponent.h new file mode 100644 index 000000000..610e8f03b --- /dev/null +++ b/src/blackgui/components/runtimebasedcomponent.h @@ -0,0 +1,120 @@ +/* Copyright (C) 2013 + * swift Project Community / Contributors + * + * This file is part of swift Project. It is subject to the license terms in the LICENSE file found in the top-level + * directory of this distribution and at http://www.swift-project.org/license.html. No part of Swift Project, + * including this file, may be copied, modified, propagated, or distributed except according to the terms + * contained in the LICENSE file. + */ + +#ifndef BLACKGUI_RUNTIMEBASEDCOMPONENT_H +#define BLACKGUI_RUNTIMEBASEDCOMPONENT_H + +#include "blackcore/context_runtime.h" +#include "blackcore/context_all_interfaces.h" +#include "blackmisc/notificationsounds.h" +#include + +namespace BlackGui +{ + namespace Components + { + + /*! + * \brief Component, which provides reference to runtime object + * \details Access to runtime allows to encapsualate many aspects of data access and makes + * the component widely independent from a central data provideer + * \sa BlackCore::CRuntime + */ + class CRuntimeBasedComponent + { + public: + //! Set runtime, usually set by runtime owner (must only be one, usually main window) + void setRuntime(BlackCore::CRuntime *runtime, bool runtimeOwner = false); + + //! Set runtime for each CRuntimeBasedComponent + static void setRuntimeForComponents(BlackCore::CRuntime *runtime, QWidget *parent); + + protected: + //! Constructor + //! \remarks Usually runtime will be provided later, not at initialization time. + //! If runtime is provided right now, make sure to call runtimeHasBeenSet afterwards + CRuntimeBasedComponent(BlackCore::CRuntime *runtime = nullptr, bool runtimeOwner = false) : + m_runtime(runtime), m_runtimeOwner(runtimeOwner) + {} + + //! Runtime const + const BlackCore::CRuntime *getRuntime() const { return this->m_runtime;} + + //! Runtime non const + BlackCore::CRuntime *getRuntime() { return this->m_runtime;} + + //! Create a runtime (becomes owner). Only create one runtime. + void createRuntime(const BlackCore::CRuntimeConfig &config, QObject *parent); + + //! Context for application + const BlackCore::IContextApplication *getIContextApplication() const; + + //! Context for application + BlackCore::IContextApplication *getIContextApplication(); + + //! Context for audio + BlackCore::IContextAudio *getIContextAudio(); + + //! Context for audio + const BlackCore::IContextAudio *getIContextAudio() const; + + //! Context for network + BlackCore::IContextNetwork *getIContextNetwork(); + + //! Context for network + const BlackCore::IContextNetwork *getIContextNetwork() const; + + //! Context for own aircraft + const BlackCore::IContextOwnAircraft *getIContextOwnAircraft() const; + + //! Context for own aircraft + BlackCore::IContextOwnAircraft *getIContextOwnAircraft(); + + //! Context for settings + BlackCore::IContextSettings *getIContextSettings(); + + //! Context for settings + const BlackCore::IContextSettings *getIContextSettings() const; + + //! Context for simulator + const BlackCore::IContextSimulator *getIContextSimulator() const; + + //! Context for simulator + BlackCore::IContextSimulator *getIContextSimulator(); + + //! Send status message (via application context) + void sendStatusMessage(const BlackMisc::CStatusMessage &statusMessage); + + //! Send status message (via application context) + void sendStatusMessages(const BlackMisc::CStatusMessageList &statusMessages); + + //! Owner? + bool isRuntimeOwner() const { return this->m_runtimeOwner; } + + //! "Callback" when runtime is initialized, done this way as we do not have signals/slots here + //! \remarks use this methods to hook up signal/slots with runtime + virtual void runtimeHasBeenSet() {} + + //! \copydoc CRuntime::hasRemoteApplicationContext + bool hasRemoteApplicationContext() const { return this->m_runtime->hasRemoteApplicationContext(); } + + //! \copydoc CRuntime::canPingApplicationContext + bool canPingApplicationContext() const { return this->m_runtime->canPingApplicationContext(); } + + //! Play a given notification sound + void playNotifcationSound(BlackSound::CNotificationSounds::Notification notification) const; + + private: + BlackCore::CRuntime *m_runtime; + bool m_runtimeOwner; + }; + } +} // namespace + +#endif // guard diff --git a/src/blackgui/components/settingscomponent.cpp b/src/blackgui/components/settingscomponent.cpp new file mode 100644 index 000000000..45665f28f --- /dev/null +++ b/src/blackgui/components/settingscomponent.cpp @@ -0,0 +1,416 @@ +/* Copyright (C) 2013 + * swift Project Community / Contributors + * + * This file is part of swift project. It is subject to the license terms in the LICENSE file found in the top-level + * directory of this distribution and at http://www.swift-project.org/license.html. No part of Swift Project, + * including this file, may be copied, modified, propagated, or distributed except according to the terms + * contained in the LICENSE file. + */ + +#include "settingscomponent.h" +#include "ui_settingscomponent.h" +#include "blackgui/models/atcstationlistmodel.h" +#include "blackcore/dbus_server.h" +#include "blackcore/context_network.h" +#include "blackmisc/hwkeyboardkeylist.h" +#include "blackmisc/setaudio.h" + +using namespace BlackCore; +using namespace BlackMisc; +using namespace BlackGui; +using namespace BlackMisc::Network; +using namespace BlackMisc::Aviation; +using namespace BlackMisc::Audio; +using namespace BlackMisc::PhysicalQuantities; +using namespace BlackMisc::Geo; +using namespace BlackMisc::Settings; +using namespace BlackMisc::Hardware; + +namespace BlackGui +{ + namespace Components + { + + CSettingsComponent::CSettingsComponent(QWidget *parent) : + QTabWidget(parent), CRuntimeBasedComponent(nullptr, false), ui(new Ui::CSettingsComponent), + m_audioTestRunning(NoAudioTest) + { + ui->setupUi(this); + this->ui->prb_SettingsAudioTestProgress->setVisible(false); + this->m_timerAudioTests = new QTimer(this); + } + + CSettingsComponent::~CSettingsComponent() + { + delete ui; + } + + /* + * Update own ICAO data from GUI + */ + void CSettingsComponent::setOwnAircraftIcaoDataFromGui(CAircraftIcao &icao) const + { + icao.setAirlineDesignator(this->ui->le_SettingsIcaoAirlineDesignator->text()); + icao.setAircraftDesignator(this->ui->le_SettingsIcaoAircraftDesignator->text()); + icao.setAircraftCombinedType(this->ui->le_SettingsIcaoCombinedType->text()); + } + + void CSettingsComponent::setGuiOpacity(double value) + { + this->ui->hs_SettingsGuiOpacity->setValue(value); + } + + bool CSettingsComponent::loginAsObserver() const + { + return this->ui->rb_SettingsLoginStealthMode->isChecked(); + } + + bool CSettingsComponent::loginStealth() const + { + return this->ui->rb_SettingsLoginStealthMode->isChecked(); + } + + bool CSettingsComponent::playNotificationSounds() const + { + return this->ui->cb_SettingsAudioPlayNotificationSounds->isChecked(); + } + + int CSettingsComponent::getAtcUpdateIntervalSeconds() const + { + return this->ui->hs_SettingsGuiAtcRefreshTime->value(); + } + + int CSettingsComponent::getAircraftUpdateIntervalSeconds() const + { + return this->ui->hs_SettingsGuiAircraftRefreshTime->value(); + } + + int CSettingsComponent::getUsersUpdateIntervalSeconds() const + { + return this->ui->hs_SettingsGuiUserRefreshTime->value(); + } + + QString CSettingsComponent::getOwnCallsignFromGui() const + { + return this->ui->le_SettingsAircraftCallsign->text(); + } + + /* + * Reload settings + */ + void CSettingsComponent::reloadSettings() + { + // local copy + CSettingsNetwork nws = this->getIContextSettings()->getNetworkSettings(); + CSettingsAudio as = this->getIContextSettings()->getAudioSettings(); + + // update servers + this->ui->tvp_SettingsTnServers->setSelectedServer(nws.getCurrentTrafficNetworkServer()); + this->ui->tvp_SettingsTnServers->update(nws.getTrafficNetworkServers()); + + // update hot keys + this->ui->tvp_SettingsMiscHotkeys->update(this->getIContextSettings()->getHotkeys()); + + // fake setting for sound notifications + this->ui->cb_SettingsAudioPlayNotificationSounds->setChecked(true); + this->ui->cb_SettingsAudioNotificationTextMessage->setChecked(as.getNotificationFlag(BlackSound::CNotificationSounds::NotificationTextMessagePrivate)); + this->ui->cb_SettingsAudioNotificationVoiceRoom->setChecked(as.getNotificationFlag(BlackSound::CNotificationSounds::NotificationVoiceRoomJoined)); + } + + void CSettingsComponent::runtimeHasBeenSet() + { + if (!this->getIContextSettings()) qFatal("Settings missing"); + + this->connect(this->getIContextSettings(), &IContextSettings::changedSettings, this, &CSettingsComponent::changedSettings); + this->connect(this->m_timerAudioTests, &QTimer::timeout, this, &CSettingsComponent::audioTestUpdate); + + // based on audio context + Q_ASSERT(this->getIContextAudio()); + if (this->getIContextAudio()) + { + this->initAudioDeviceLists(); + bool connected = this->connect(this->getIContextAudio(), &IContextAudio::audioTestCompleted, this, &CSettingsComponent::audioTestUpdate); + Q_ASSERT(connected); + connected = this->connect(this->ui->cb_SettingsAudioInputDevice, SIGNAL(currentIndexChanged(int)), this, SLOT(audioDeviceSelected(int))); + Q_ASSERT(connected); + connected = this->connect(this->ui->cb_SettingsAudioOutputDevice, SIGNAL(currentIndexChanged(int)), this, SLOT(audioDeviceSelected(int))); + Q_ASSERT(connected); + this->connect(this->ui->pb_SettingsAudioMicrophoneTest, &QPushButton::clicked, this, &CSettingsComponent::startAudioTest); + this->connect(this->ui->pb_SettingsAudioSquelchTest, &QPushButton::clicked, this, &CSettingsComponent::startAudioTest); + } + + // Opacity, intervals + this->connect(this->ui->hs_SettingsGuiOpacity, &QSlider::valueChanged, this, &CSettingsComponent::changedWindowsOpacity); + this->connect(this->ui->hs_SettingsGuiAircraftRefreshTime, &QSlider::valueChanged, this, &CSettingsComponent::changedAircraftsUpdateInterval); + this->connect(this->ui->hs_SettingsGuiAtcRefreshTime, &QSlider::valueChanged, this, &CSettingsComponent::changedAtcStationsUpdateInterval); + this->connect(this->ui->hs_SettingsGuiUserRefreshTime, &QSlider::valueChanged, this, &CSettingsComponent::changedUsersUpdateInterval); + + // Settings server + this->connect(this->ui->pb_SettingsTnCurrentServer, &QPushButton::released, this, &CSettingsComponent::alterTrafficServer); + this->connect(this->ui->pb_SettingsTnRemoveServer, &QPushButton::released, this, &CSettingsComponent::alterTrafficServer); + this->connect(this->ui->pb_SettingsTnSaveServer, &QPushButton::released, this, &CSettingsComponent::alterTrafficServer); + this->connect(this->ui->tvp_SettingsTnServers, &QTableView::clicked, this, &CSettingsComponent::networkServerSelected); + + // Settings hotkeys + this->connect(this->ui->pb_SettingsMiscCancel, &QPushButton::clicked, this, &CSettingsComponent::reloadSettings); + this->connect(this->ui->pb_SettingsMiscSave, &QPushButton::clicked, this, &CSettingsComponent::saveHotkeys); + this->connect(this->ui->pb_SettingsMiscRemove, &QPushButton::clicked, this, &CSettingsComponent::clearHotkey); + } + + /* + * Network has been selected + */ + void CSettingsComponent::networkServerSelected(QModelIndex index) + { + const CServer clickedServer = this->ui->tvp_SettingsTnServers->at(index); + this->updateGuiSelectedServerTextboxes(clickedServer); + } + + /* + * Alter server + */ + void CSettingsComponent::alterTrafficServer() + { + CServer server = this->selectedServerFromTextboxes(); + if (!server.isValidForLogin()) + { + const CStatusMessage validation = CStatusMessage::getValidationError("Wrong settings for server"); + this->sendStatusMessage(validation); + return; + } + + const QString path = CSettingUtilities::appendPaths(IContextSettings::PathNetworkSettings(), CSettingsNetwork::ValueTrafficServers()); + QObject *sender = QObject::sender(); + CStatusMessageList msgs; + if (sender == this->ui->pb_SettingsTnCurrentServer) + { + msgs = this->getIContextSettings()->value(path, CSettingsNetwork::CmdSetCurrentServer(), server.toQVariant()); + } + else if (sender == this->ui->pb_SettingsTnRemoveServer) + { + msgs = this->getIContextSettings()->value(path, CSettingUtilities::CmdRemove(), server.toQVariant()); + } + else if (sender == this->ui->pb_SettingsTnSaveServer) + { + msgs = this->getIContextSettings()->value(path, CSettingUtilities::CmdUpdate(), server.toQVariant()); + } + + // status messages + this->sendStatusMessages(msgs); + } + + /* + * Settings did changed + */ + void CSettingsComponent::changedSettings(uint typeValue) + { + IContextSettings::SettingsType type = static_cast(typeValue); + this->reloadSettings(); + Q_UNUSED(type); + } + + /* + * Textboxes from server + */ + void CSettingsComponent::updateGuiSelectedServerTextboxes(const CServer &server) + { + this->ui->le_SettingsTnCsName->setText(server.getName()); + this->ui->le_SettingsTnCsDescription->setText(server.getDescription()); + this->ui->le_SettingsTnCsAddress->setText(server.getAddress()); + this->ui->le_SettingsTnCsPort->setText(QString::number(server.getPort())); + this->ui->le_SettingsTnCsRealName->setText(server.getUser().getRealName()); + this->ui->le_SettingsTnCsNetworkId->setText(server.getUser().getId()); + this->ui->le_SettingsTnCsPassword->setText(server.getUser().getPassword()); + } + + /* + * Server settings from textboxes + */ + CServer CSettingsComponent::selectedServerFromTextboxes() const + { + CServer server; + bool portOk = false; + server.setName(this->ui->le_SettingsTnCsName->text()); + server.setDescription(this->ui->le_SettingsTnCsDescription->text()); + server.setAddress(this->ui->le_SettingsTnCsAddress->text()); + server.setPort(this->ui->le_SettingsTnCsPort->text().toInt(&portOk)); + if (!portOk) server.setPort(-1); + + CUser user; + user.setRealName(this->ui->le_SettingsTnCsRealName->text()); + user.setId(this->ui->le_SettingsTnCsNetworkId->text()); + user.setPassword(this->ui->le_SettingsTnCsPassword->text()); + server.setUser(user); + + return server; + } + + /* + * Save the hotkeys + */ + void CSettingsComponent::saveHotkeys() + { + const QString path = CSettingUtilities::appendPaths(IContextSettings::PathRoot(), IContextSettings::PathHotkeys()); + CStatusMessageList msgs = this->getIContextSettings()->value(path, CSettingUtilities::CmdUpdate(), this->ui->tvp_SettingsMiscHotkeys->derivedModel()->getContainer().toQVariant()); + + // status messages + this->sendStatusMessages(msgs); + } + + /* + * Clear particular hotkey + */ + void CSettingsComponent::clearHotkey() + { + QModelIndex i = this->ui->tvp_SettingsMiscHotkeys->currentIndex(); + if (i.row() < 0 || i.row() >= this->ui->tvp_SettingsMiscHotkeys->rowCount()) return; + BlackMisc::Hardware::CKeyboardKey key = this->ui->tvp_SettingsMiscHotkeys->at(i); + BlackMisc::Hardware::CKeyboardKey defaultKey; + defaultKey.setFunction(key.getFunction()); + this->ui->tvp_SettingsMiscHotkeys->derivedModel()->update(i, defaultKey); + } + + /* + * Set audio device lists + */ + void CSettingsComponent::initAudioDeviceLists() + { + if (!this->getIContextAudio()) return; + this->ui->cb_SettingsAudioOutputDevice->clear(); + this->ui->cb_SettingsAudioInputDevice->clear(); + + foreach(CAudioDevice device, this->getIContextAudio()->getAudioDevices()) + { + if (device.getType() == CAudioDevice::InputDevice) + { + this->ui->cb_SettingsAudioInputDevice->addItem(device.toQString(true)); + } + else if (device.getType() == CAudioDevice::OutputDevice) + { + this->ui->cb_SettingsAudioOutputDevice->addItem(device.toQString(true)); + } + } + + foreach(CAudioDevice device, this->getIContextAudio()->getCurrentAudioDevices()) + { + if (device.getType() == CAudioDevice::InputDevice) + { + this->ui->cb_SettingsAudioInputDevice->setCurrentText(device.toQString(true)); + } + else if (device.getType() == CAudioDevice::OutputDevice) + { + this->ui->cb_SettingsAudioOutputDevice->setCurrentText(device.toQString(true)); + } + } + } + + /* + * Start the voice tests + */ + void CSettingsComponent::startAudioTest() + { + if (!this->getIContextAudio()) + { + CStatusMessage m(CStatusMessage::TypeAudio, CStatusMessage::SeverityError, "voice context not available"); + this->sendStatusMessage(m); + return; + } + if (this->m_timerAudioTests->isActive()) + { + CStatusMessage m(CStatusMessage::TypeAudio, CStatusMessage::SeverityError, "test running, wait until completed"); + this->sendStatusMessage(m); + return; + } + + QObject *sender = QObject::sender(); + this->m_timerAudioTests->start(600); // I let this run for ms, so there is enough overhead to really complete it + this->ui->prb_SettingsAudioTestProgress->setValue(0); + this->ui->pte_SettingsAudioTestActionAndResult->clear(); + if (sender == this->ui->pb_SettingsAudioMicrophoneTest) + { + this->m_audioTestRunning = MicrophoneTest; + this->getIContextAudio()->runMicrophoneTest(); + this->ui->pte_SettingsAudioTestActionAndResult->appendPlainText("Speak normally for 5 seconds"); + } + else if (sender == this->ui->pb_SettingsAudioSquelchTest) + { + this->m_audioTestRunning = SquelchTest; + this->getIContextAudio()->runSquelchTest(); + this->ui->pte_SettingsAudioTestActionAndResult->appendPlainText("Silence for 5 seconds"); + } + this->ui->prb_SettingsAudioTestProgress->setVisible(true); + this->ui->pb_SettingsAudioMicrophoneTest->setEnabled(false); + this->ui->pb_SettingsAudioSquelchTest->setEnabled(false); + } + + /* + * Start the voice tests + */ + void CSettingsComponent::audioTestUpdate() + { + Q_ASSERT(this->getIContextAudio()); + if (!this->getIContextAudio()) return; + int v = this->ui->prb_SettingsAudioTestProgress->value(); + QObject *sender = this->sender(); + + if (v < 100 && (sender == m_timerAudioTests)) + { + // timer update, increasing progress + this->ui->prb_SettingsAudioTestProgress->setValue(v + 10); + } + else + { + this->m_timerAudioTests->stop(); + this->ui->prb_SettingsAudioTestProgress->setValue(100); + if (sender == m_timerAudioTests) return; // just timer update + + // getting here we assume the audio test finished signal + // fetch results + this->ui->pte_SettingsAudioTestActionAndResult->clear(); + if (this->m_audioTestRunning == SquelchTest) + { + double s = this->getIContextAudio()->getSquelchValue(); + this->ui->pte_SettingsAudioTestActionAndResult->appendPlainText(QString::number(s)); + } + else if (this->m_audioTestRunning == MicrophoneTest) + { + QString m = this->getIContextAudio()->getMicrophoneTestResult(); + this->ui->pte_SettingsAudioTestActionAndResult->appendPlainText(m); + } + this->m_audioTestRunning = NoAudioTest; + this->m_timerAudioTests->stop(); + this->ui->pb_SettingsAudioMicrophoneTest->setEnabled(true); + this->ui->pb_SettingsAudioSquelchTest->setEnabled(true); + this->ui->prb_SettingsAudioTestProgress->setVisible(false); + } + } + + /* + * Select audio device + */ + void CSettingsComponent::audioDeviceSelected(int index) + { + if (!this->getIContextAudio()) return; + if (index < 0)return; + + CAudioDeviceList devices = this->getIContextAudio()->getAudioDevices(); + if (devices.isEmpty()) return; + CAudioDevice selectedDevice; + QObject *sender = QObject::sender(); + if (sender == this->ui->cb_SettingsAudioInputDevice) + { + CAudioDeviceList inputDevices = devices.getInputDevices(); + if (index >= inputDevices.size()) return; + selectedDevice = inputDevices[index]; + this->getIContextAudio()->setCurrentAudioDevice(selectedDevice); + } + else if (sender == this->ui->cb_SettingsAudioOutputDevice) + { + CAudioDeviceList outputDevices = devices.getOutputDevices(); + if (index >= outputDevices.size()) return; + selectedDevice = outputDevices[index]; + this->getIContextAudio()->setCurrentAudioDevice(selectedDevice); + } + } + } +} // namespace diff --git a/src/blackgui/components/settingscomponent.h b/src/blackgui/components/settingscomponent.h new file mode 100644 index 000000000..0f20d48bd --- /dev/null +++ b/src/blackgui/components/settingscomponent.h @@ -0,0 +1,145 @@ +/* Copyright (C) 2013 + * swift Project Community / Contributors + * + * This file is part of swift project. It is subject to the license terms in the LICENSE file found in the top-level + * directory of this distribution and at http://www.swift-project.org/license.html. No part of Swift Project, + * including this file, may be copied, modified, propagated, or distributed except according to the terms + * contained in the LICENSE file. + */ + +#ifndef BLACKGUI_SETTINGSCOMPONENT_H +#define BLACKGUI_SETTINGSCOMPONENT_H + +//! \file + +#include "blackgui/components/runtimebasedcomponent.h" +#include +#include +#include + + +namespace Ui { class CSettingsComponent; } + +namespace BlackGui +{ + namespace Components + { + + //! Settings component + class CSettingsComponent : public QTabWidget, public CRuntimeBasedComponent + { + Q_OBJECT + + public: + //! Constructor + explicit CSettingsComponent(QWidget *parent = nullptr); + + //! Destructor + ~CSettingsComponent(); + + //! ICAO data from GUI + void setOwnAircraftIcaoDataFromGui(BlackMisc::Aviation::CAircraftIcao &icao) const; + + //! GUI Opacity 0-100% + void setGuiOpacity(double value); + + //! Login as observer + bool loginAsObserver() const; + + //! Login as observer + bool loginStealth() const; + + //! Play notification sounds (at all) + bool playNotificationSounds() const; + + //! ATC refresh time + int getAtcUpdateIntervalSeconds() const; + + //! Aircraft refresh time + int getAircraftUpdateIntervalSeconds() const; + + //! Aircraft refresh time + int getUsersUpdateIntervalSeconds() const; + + //! Own callsign + QString getOwnCallsignFromGui() const; + + signals: + //! Change the windows opacity 0..100 + void changedWindowsOpacity(int opacity); + + //! Update interval changed (ATC) + void changedAtcStationsUpdateInterval(int seconds); + + //! Update interval changed (aircrafts) + void changedAircraftsUpdateInterval(int seconds); + + //! Update interval changed (users) + void changedUsersUpdateInterval(int seconds); + + public slots: + //! Reload settings + void reloadSettings(); + + protected: + //! \copydoc CRuntimeBasedComponent::runtimeHasBeenSet + virtual void runtimeHasBeenSet() override; + + private slots: + + //! Network server selected + void networkServerSelected(QModelIndex index); + + //! Alter traffic server + void alterTrafficServer(); + + /*! + * \brief Update the selected server textboxes + * \param server to be displayed + */ + void updateGuiSelectedServerTextboxes(const BlackMisc::Network::CServer &server); + + //! Selected server from textboxes + BlackMisc::Network::CServer selectedServerFromTextboxes() const; + + //! Settings have been changed + void changedSettings(uint typeValue); + + //! Save the Hotkeys + void saveHotkeys(); + + //! Clear single hotkey + void clearHotkey(); + + //! start the MIC tests (Squelch) + void startAudioTest(); + + //! Audio test updates (timer) for progressbar and fetching results + void audioTestUpdate(); + + /*! + * \brief Audio device selected + * \param index audio device index (COM1, COM2) + */ + void audioDeviceSelected(int index); + + private: + //! Audio test modes + enum AudioTest + { + NoAudioTest, + SquelchTest, + MicrophoneTest + }; + + Ui::CSettingsComponent *ui; + QTimer *m_timerAudioTests; //!< audio tests: progress bar, disable/enable buttons + AudioTest m_audioTestRunning; + + //! Audio device lists from settings + void initAudioDeviceLists(); + }; + } +} // namespace + +#endif // guard diff --git a/src/blackgui/settingscomponent.ui b/src/blackgui/components/settingscomponent.ui similarity index 97% rename from src/blackgui/settingscomponent.ui rename to src/blackgui/components/settingscomponent.ui index 159f3cfb1..2a3ffb2f4 100644 --- a/src/blackgui/settingscomponent.ui +++ b/src/blackgui/components/settingscomponent.ui @@ -37,7 +37,7 @@ 1 - + QAbstractItemView::AnyKeyPressed|QAbstractItemView::DoubleClicked|QAbstractItemView::EditKeyPressed @@ -527,7 +527,7 @@ - + QFrame::StyledPanel @@ -686,7 +686,7 @@ 2 - + true @@ -733,19 +733,19 @@ - BlackGui::CKeyboardKeyView + BlackGui::Views::CKeyboardKeyView QTableView -
blackgui/keyboardkeyview.h
+
blackgui/views/keyboardkeyview.h
- BlackGui::CServerView + BlackGui::Views::CServerView QTableView -
blackgui/serverview.h
+
blackgui/views/serverview.h
- BlackGui::CSettingsSimulatorComponent + BlackGui::Components::CSettingsSimulatorComponent QFrame -
blackgui/settingssimulatorcomponent.h
+
blackgui/components/settingssimulatorcomponent.h
1
diff --git a/src/blackgui/components/settingsfsxcomponent.cpp b/src/blackgui/components/settingsfsxcomponent.cpp new file mode 100644 index 000000000..cc15d4e2d --- /dev/null +++ b/src/blackgui/components/settingsfsxcomponent.cpp @@ -0,0 +1,187 @@ +/* Copyright (C) 2013 + * Swift Project Community / Contributors + * + * This file is part of swift Project. It is subject to the license terms in the LICENSE file found in the top-level + * directory of this distribution and at http://www.swift-project.org/license.html. No part of Swift Project, + * including this file, may be copied, modified, propagated, or distributed except according to the terms + * contained in the LICENSE file. + */ + +#include "settingsfsxcomponent.h" +#include "ui_settingsfsxcomponent.h" +#include +#include +#include +#include + +#include "blackmisc/networkutils.h" +#include "blackmisc/statusmessage.h" +#include "blacksim/fsx/fsxsimulatorsetup.h" +#include "blacksim/fsx/simconnectutilities.h" + +using namespace BlackMisc; +using namespace BlackSim::Fsx; +using namespace BlackMisc::Network; + +namespace BlackGui +{ + namespace Components + { + CSettingsFsxComponent::CSettingsFsxComponent(QWidget *parent) : + QFrame(parent), CRuntimeBasedComponent(nullptr, false), ui(new Ui::CSettingsFsxComponent) + { + ui->setupUi(this); + + this->connect(this->ui->pb_SettingsFsxTestConnection, &QPushButton::clicked, this, &CSettingsFsxComponent::testSimConnectConnection); + this->connect(this->ui->pb_SettingsFsxSaveSimconnectCfg, &QPushButton::clicked, this, &CSettingsFsxComponent::saveSimConnectCfg); + this->connect(this->ui->pb_SettingsFsxOpenSimconnectCfg, &QPushButton::clicked, this, &CSettingsFsxComponent::simConnectCfgFile); + this->connect(this->ui->pb_SettingsFsxDeleteSimconnectCfg, &QPushButton::clicked, this, &CSettingsFsxComponent::simConnectCfgFile); + this->connect(this->ui->pb_SettingsFsxExistsSimconncetCfg, &QPushButton::clicked, this, &CSettingsFsxComponent::simConnectCfgFile); + + } + + CSettingsFsxComponent::~CSettingsFsxComponent() + { + delete ui; + } + + /* + * SimConnect working? + */ + void CSettingsFsxComponent::testSimConnectConnection() + { + QString address = this->ui->le_SettingsFsxAddress->text().trimmed(); + QString port = this->ui->le_SettingsFsxPort->text().trimmed(); + + if (address.isEmpty() || port.isEmpty()) + { + this->sendStatusMessage(CStatusMessage(CStatusMessage::TypeTrafficNetwork, CStatusMessage::SeverityWarning, "no address or port")); + return; + } + if (!CNetworkUtils::isValidIPv4Address(address)) + { + this->sendStatusMessage(CStatusMessage(CStatusMessage::TypeTrafficNetwork, CStatusMessage::SeverityWarning, "IPv4 address invalid")); + return; + } + if (!CNetworkUtils::isValidPort(port)) + { + this->sendStatusMessage(CStatusMessage(CStatusMessage::TypeTrafficNetwork, CStatusMessage::SeverityWarning, "invalid port")); + return; + } + quint16 p = port.toUInt(); + QString msg; + if (!CNetworkUtils::canConnect(address, p, msg)) + { + this->sendStatusMessage(CStatusMessage(CStatusMessage::TypeTrafficNetwork, CStatusMessage::SeverityWarning, msg)); + return; + } + + msg = QString("Connected to %1:%2").arg(address).arg(port); + this->sendStatusMessage(CStatusMessage(CStatusMessage::TypeTrafficNetwork, CStatusMessage::SeverityInfo, msg)); + } + + /* + * Save simconnect.cfg + */ + void CSettingsFsxComponent::saveSimConnectCfg() + { + if (!this->getIContextSimulator() || !this->getIContextSimulator()->isSimulatorAvailable()) + { + this->sendStatusMessage(CStatusMessage::getErrorMessage("Simulator not available", CStatusMessage::TypeSimulator)); + return; + } + QString address = this->ui->le_SettingsFsxAddress->text().trimmed(); + QString port = this->ui->le_SettingsFsxPort->text().trimmed(); + + if (address.isEmpty() || port.isEmpty()) + { + this->sendStatusMessage(CStatusMessage(CStatusMessage::TypeTrafficNetwork, CStatusMessage::SeverityWarning, "no address or port")); + return; + } + if (!CNetworkUtils::isValidIPv4Address(address)) + { + this->sendStatusMessage(CStatusMessage(CStatusMessage::TypeTrafficNetwork, CStatusMessage::SeverityWarning, "IPv4 address invalid")); + return; + } + if (!CNetworkUtils::isValidPort(port)) + { + this->sendStatusMessage(CStatusMessage(CStatusMessage::TypeTrafficNetwork, CStatusMessage::SeverityWarning, "invalid port")); + return; + } + quint16 p = port.toUInt(); + QString fileName = this->getIContextSimulator()->getSimulatorInfo().getSimulatorSetupValueAsString(CFsxSimulatorSetup::SetupSimConnectCfgFile); + Q_ASSERT(!fileName.isEmpty()); + // write either local or remote file + bool local = this->getIContextSimulator()->usingLocalObjects(); + bool success = local ? + BlackSim::Fsx::CSimConnectUtilities::writeSimConnectCfg(fileName, address, p) : + this->getIContextApplication()->writeToFile(fileName, CSimConnectUtilities::simConnectCfg(address, p)); + if (success) + { + QString m = QString("Written ").append(local ? " local " : "remote ").append(fileName); + this->sendStatusMessage(CStatusMessage(CStatusMessage::TypeTrafficNetwork, CStatusMessage::SeverityInfo, m)); + } + else + { + QString m = QString("Cannot write ").append(fileName); + this->sendStatusMessage(CStatusMessage(CStatusMessage::TypeTrafficNetwork, CStatusMessage::SeverityError, m)); + } + this->ui->pb_SettingsFsxExistsSimconncetCfg->click(); // update status + } + + /* + * simconnect.cfg: open, delete, exists? + */ + void CSettingsFsxComponent::simConnectCfgFile() + { + if (!this->getIContextSimulator() || !this->getIContextSimulator()->isSimulatorAvailable()) + { + this->sendStatusMessage(CStatusMessage::getErrorMessage("Simulator not available", CStatusMessage::TypeSimulator)); + return; + } + + QObject *sender = QObject::sender(); + if (sender == this->ui->pb_SettingsFsxOpenSimconnectCfg) + { + QFileInfo fi(CSimConnectUtilities::getLocalSimConnectCfgFilename()); + QString path = QDir::toNativeSeparators(fi.absolutePath()); + QDesktopServices::openUrl(QUrl("file:///" + path)); + } + else if (sender == this->ui->pb_SettingsFsxDeleteSimconnectCfg) + { + if (!this->getIContextSimulator()) return; + QString fileName = BlackSim::Fsx::CSimConnectUtilities::getLocalSimConnectCfgFilename(); + QString m = QString("Deleted %1 ").append(fileName); + if (this->getIContextSimulator()->usingLocalObjects()) + { + QFile f(fileName); + f.remove(); + m = m.arg("locally"); + } + else + { + this->getIContextApplication()->removeFile(fileName); + m = m.arg("remotely"); + } + this->sendStatusMessage(CStatusMessage(CStatusMessage::TypeSimulator, CStatusMessage::SeverityInfo, m)); + this->ui->pb_SettingsFsxExistsSimconncetCfg->click(); // update status + } + else if (sender == this->ui->pb_SettingsFsxExistsSimconncetCfg) + { + if (!this->getIContextSimulator()) return; + QString fileName = BlackSim::Fsx::CSimConnectUtilities::getLocalSimConnectCfgFilename(); + bool exists = this->getIContextSimulator()->usingLocalObjects() ? + QFile::exists(fileName) : + this->getIContextApplication()->existsFile(fileName); + if (exists) + { + this->ui->le_SettingsFsxExistsSimconncetCfg->setText(fileName); + } + else + { + this->ui->le_SettingsFsxExistsSimconncetCfg->setText("no file"); + } + } + } + } +} diff --git a/src/blackgui/components/settingsfsxcomponent.h b/src/blackgui/components/settingsfsxcomponent.h new file mode 100644 index 000000000..e11033436 --- /dev/null +++ b/src/blackgui/components/settingsfsxcomponent.h @@ -0,0 +1,52 @@ +/* Copyright (C) 2013 + * swift Project Community / Contributors + * + * This file is part of swift Project. It is subject to the license terms in the LICENSE file found in the top-level + * directory of this distribution and at http://www.swift-project.org/license.html. No part of Swift Project, + * including this file, may be copied, modified, propagated, or distributed except according to the terms + * contained in the LICENSE file. + */ + +#ifndef BLACKGUI_SETTINGSFSXCOMPONENT_H +#define BLACKGUI_SETTINGSFSXCOMPONENT_H + +//! \file + +#include "blackgui/components/runtimebasedcomponent.h" +#include + +namespace Ui { class CSettingsFsxComponent; } + +namespace BlackGui +{ + namespace Components + { + //! Settings for FSX + class CSettingsFsxComponent : public QFrame, public CRuntimeBasedComponent + { + Q_OBJECT + + public: + //! Constructor + explicit CSettingsFsxComponent(QWidget *parent = nullptr); + + //! Destructor + ~CSettingsFsxComponent(); + + private slots: + //! Test the SIM connect connectivity + void testSimConnectConnection(); + + //! Save a simconnect.cfg file for FSX + void saveSimConnectCfg(); + + //! simConnect.cfg: open, exists? delete + void simConnectCfgFile(); + + private: + Ui::CSettingsFsxComponent *ui; + }; + } +} + +#endif // guard diff --git a/src/blackgui/settingsfsxcomponent.ui b/src/blackgui/components/settingsfsxcomponent.ui similarity index 100% rename from src/blackgui/settingsfsxcomponent.ui rename to src/blackgui/components/settingsfsxcomponent.ui diff --git a/src/blackgui/components/settingssimulatorcomponent.cpp b/src/blackgui/components/settingssimulatorcomponent.cpp new file mode 100644 index 000000000..2500cf4ed --- /dev/null +++ b/src/blackgui/components/settingssimulatorcomponent.cpp @@ -0,0 +1,163 @@ +#include "settingssimulatorcomponent.h" +#include "ui_settingssimulatorcomponent.h" + +#include "blackcore/context_settings.h" +#include "blacksim/simulatorinfolist.h" +#include "blacksim/setsimulator.h" +#include "blackmisc/settingutilities.h" + +#include + +using namespace BlackMisc; +using namespace BlackMisc::Settings; +using namespace BlackMisc::PhysicalQuantities; +using namespace BlackSim; +using namespace BlackSim::Settings; +using namespace BlackCore; + +namespace BlackGui +{ + namespace Components + { + CSettingsSimulatorComponent::CSettingsSimulatorComponent(QWidget *parent) : + QFrame(parent), CRuntimeBasedComponent(nullptr, false), + ui(new Ui::CSettingsSimulatorComponent) + { + ui->setupUi(this); + } + + CSettingsSimulatorComponent::~CSettingsSimulatorComponent() + { + delete ui; + } + + void CSettingsSimulatorComponent::runtimeHasBeenSet() + { + Q_ASSERT(this->getIContextSimulator()); + Q_ASSERT(this->getIContextSettings()); + if (this->getIContextSimulator()) + { + QStringList plugins = this->getIContextSimulator()->getAvailableSimulatorPlugins().toStringList(true); + CSimulatorInfo currentPlugin = this->getIContextSimulator()->getSimulatorInfo(); + this->ui->cb_Plugins->addItems(plugins); + this->setCurrentPlugin(currentPlugin); + + // disable / enable driver specific GUI parts + bool fsxDriver = + this->getIContextSimulator()->getAvailableSimulatorPlugins().supportsSimulator(CSimulatorInfo::FSX()); + this->ui->comp_SettingsSimulatorFsx->setVisible(fsxDriver); + + // time sync + bool timeSynced = this->getIContextSimulator()->isTimeSynchronized(); + this->ui->cb_TimeSync->setChecked(timeSynced); + CTime timeOffset = this->getIContextSimulator()->getTimeSynchronizationOffset(); + this->ui->le_TimeSyncOffset->setText(timeOffset.formattedHrsMin()); + + // only with simulator context set GUI values + bool connected = this->connect(this->ui->cb_Plugins, SIGNAL(currentIndexChanged(int)), this, SLOT(ps_pluginHasChanged(int))); + Q_ASSERT(connected); + Q_UNUSED(connected); + } + + if (this->getIContextSettings()) + { + connect(this->getIContextSettings(), &IContextSettings::changedSettings, this, &CSettingsSimulatorComponent::ps_settingsHaveChanged); + } + + connect(this->ui->cb_TimeSync, &QCheckBox::released, this, &CSettingsSimulatorComponent::ps_guiValueHasChanged); + connect(this->ui->le_TimeSyncOffset, &QLineEdit::returnPressed, this, &CSettingsSimulatorComponent::ps_guiValueHasChanged); + } + + void CSettingsSimulatorComponent::setCurrentPlugin(const CSimulatorInfo &plugin) + { + if (plugin.isUnspecified()) return; + const QString searchFor = plugin.getShortName(); + for (int i = 0; i < this->ui->cb_Plugins->count(); ++i) + { + const QString t = ui->cb_Plugins->itemText(i); + if (t.indexOf(searchFor, 0, Qt::CaseInsensitive) >= 0) + { + if (i == this->ui->cb_Plugins->currentIndex()) return; + this->ui->cb_Plugins->setCurrentIndex(i); + break; + } + } + } + + void CSettingsSimulatorComponent::ps_pluginHasChanged(int index) + { + Q_ASSERT(this->getIContextSimulator()); + Q_ASSERT(this->getIContextSettings()); + if (!this->getIContextSimulator() || !this->getIContextSettings()) return; + + CSimulatorInfoList simDrivers = this->getIContextSimulator()->getAvailableSimulatorPlugins(); + if (simDrivers.isEmpty()) + { + this->sendStatusMessage(CStatusMessage::getErrorMessage("No drivers available", CStatusMessage::TypeSimulator)); + return; + } + if (simDrivers.size() <= index) + { + this->sendStatusMessage(CStatusMessage::getErrorMessage("Wrong driver index", CStatusMessage::TypeSimulator)); + return; + } + + // update + CSimulatorInfo currentDriver = simDrivers[index]; + const QString path = CSettingUtilities::appendPaths(IContextSettings::PathSimulatorSettings(), CSettingsSimulator::ValueSelectedDriver()); + this->sendStatusMessages( + this->getIContextSettings()->value(path, CSettingUtilities::CmdUpdate(), currentDriver.toCVariant()) + ); + } + + void CSettingsSimulatorComponent::ps_settingsHaveChanged(uint settingsType) + { + Q_ASSERT(this->getIContextSettings()); + IContextSettings::SettingsType type = static_cast(settingsType); + if (type != IContextSettings::SettingsSimulator || !this->getIContextSettings()) return; + CSettingsSimulator simSettings = this->getIContextSettings()->getSimulatorSettings(); + + this->setCurrentPlugin(simSettings.getSelectedPlugin()); + this->ui->le_TimeSyncOffset->setText(simSettings.getSyncTimeOffset().formattedHrsMin()); + this->ui->cb_TimeSync->setChecked(simSettings.isTimeSyncEnabled()); + } + + void CSettingsSimulatorComponent::ps_guiValueHasChanged() + { + Q_ASSERT(this->getIContextSettings()); + if (!this->getIContextSettings()) return; + + QObject *sender = QObject::sender(); + if (!sender) return; + + const QString ps = IContextSettings::PathSimulatorSettings(); + CStatusMessageList msgs; + if (sender == this->ui->cb_TimeSync) + { + bool timeSync = this->ui->cb_TimeSync->isChecked(); + msgs = this->getIContextSettings()->value(CSettingUtilities::appendPaths(ps, CSettingsSimulator::ValueSyncTime()), CSettingUtilities::CmdUpdate(), QVariant(timeSync)); + } + else if (sender == this->ui->le_TimeSyncOffset) + { + const QString os = this->ui->le_TimeSyncOffset->text(); + CTime ost(0, CTimeUnit::hrmin()); + if (!os.isEmpty()) + { + ost.parseFromString(os); + } + if (ost.isNull()) + { + msgs.push_back(CStatusMessage::getValidationError("Invalid offset time")); + } + else + { + msgs = this->getIContextSettings()->value(CSettingUtilities::appendPaths(ps, CSettingsSimulator::ValueSyncTimeOffset()), CSettingUtilities::CmdUpdate(), ost.toQVariant()); + } + } + if (!msgs.isEmpty()) + { + this->getIContextApplication()->sendStatusMessages(msgs); + } + } + } +} // namespace diff --git a/src/blackgui/components/settingssimulatorcomponent.h b/src/blackgui/components/settingssimulatorcomponent.h new file mode 100644 index 000000000..15759f2a7 --- /dev/null +++ b/src/blackgui/components/settingssimulatorcomponent.h @@ -0,0 +1,50 @@ +#ifndef BLACKGUI_SETTINGSSIMULATORCOMPONENT_H +#define BLACKGUI_SETTINGSSIMULATORCOMPONENT_H + +#include "runtimebasedcomponent.h" +#include + +namespace Ui { class CSettingsSimulatorComponent; } + +namespace BlackGui +{ + namespace Components + { + /*! + * All simulator settings component (GUI) + */ + class CSettingsSimulatorComponent : public QFrame, public CRuntimeBasedComponent + { + Q_OBJECT + + public: + //! Constructor + explicit CSettingsSimulatorComponent(QWidget *parent = nullptr); + + //! Destructor + ~CSettingsSimulatorComponent(); + + protected: + //! \copydoc CRuntimeBasedComponent::runtimeHasBeenSet() + virtual void runtimeHasBeenSet() override; + + private slots: + //! Driver changed + void ps_pluginHasChanged(int index); + + //! Settings have been changed + void ps_settingsHaveChanged(uint settingsType); + + //! A GUI value has been changed + void ps_guiValueHasChanged(); + + private: + Ui::CSettingsSimulatorComponent *ui; //!< UI + + //! Smarter way to set current driver, avoids unnecessary signals and less formatting dependend + void setCurrentPlugin(const BlackSim::CSimulatorInfo &plugin); + + }; + } +} // namespace +#endif // guard diff --git a/src/blackgui/settingssimulatorcomponent.ui b/src/blackgui/components/settingssimulatorcomponent.ui similarity index 95% rename from src/blackgui/settingssimulatorcomponent.ui rename to src/blackgui/components/settingssimulatorcomponent.ui index af2c4a340..2582f987b 100644 --- a/src/blackgui/settingssimulatorcomponent.ui +++ b/src/blackgui/components/settingssimulatorcomponent.ui @@ -141,7 +141,7 @@ - + QFrame::StyledPanel @@ -156,9 +156,9 @@ - BlackGui::CSettingsFsxComponent + BlackGui::Components::CSettingsFsxComponent QFrame -
blackgui/settingsfsxcomponent.h
+
blackgui/components/settingsfsxcomponent.h
1
diff --git a/src/blackgui/components/simulatorcomponent.cpp b/src/blackgui/components/simulatorcomponent.cpp new file mode 100644 index 000000000..c394d0546 --- /dev/null +++ b/src/blackgui/components/simulatorcomponent.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2014 + * swift Project Community / Contributors + * + * This file is part of swift project. It is subject to the license terms in the LICENSE file found in the top-level + * directory of this distribution and at http://www.swift-project.org/license.html. No part of Swift Project, + * including this file, may be copied, modified, propagated, or distributed except according to the terms + * contained in the LICENSE file. + */ + +#include "simulatorcomponent.h" +#include "ui_simulatorcomponent.h" + +namespace BlackGui +{ + namespace Components + { + CSimulatorComponent::CSimulatorComponent(QWidget *parent) : + QTabWidget(parent), ui(new Ui::CSimulatorComponent) + { + ui->setupUi(this); + } + + CSimulatorComponent::~CSimulatorComponent() + { + delete ui; + } + } +} diff --git a/src/blackgui/components/simulatorcomponent.h b/src/blackgui/components/simulatorcomponent.h new file mode 100644 index 000000000..2ae20fe93 --- /dev/null +++ b/src/blackgui/components/simulatorcomponent.h @@ -0,0 +1,43 @@ +/* Copyright (C) 2014 + * swift Project Community / Contributors + * + * This file is part of swift project. It is subject to the license terms in the LICENSE file found in the top-level + * directory of this distribution and at http://www.swift-project.org/license.html. No part of Swift Project, + * including this file, may be copied, modified, propagated, or distributed except according to the terms + * contained in the LICENSE file. + */ + +#ifndef BLACKGUI_SIMULATORCOMPONENT_H +#define BLACKGUI_SIMULATORCOMPONENT_H + +//! \file + +#include "runtimebasedcomponent.h" +#include + +namespace Ui { class CSimulatorComponent; } +namespace BlackGui +{ + namespace Components + { + + //! Simulator component + class CSimulatorComponent : public QTabWidget, public CRuntimeBasedComponent + { + Q_OBJECT + + public: + + //! Constructor + explicit CSimulatorComponent(QWidget *parent = nullptr); + + //! Destructor + ~CSimulatorComponent(); + + private: + Ui::CSimulatorComponent *ui; + }; + } +} + +#endif // guard diff --git a/src/blackgui/components/simulatorcomponent.ui b/src/blackgui/components/simulatorcomponent.ui new file mode 100644 index 000000000..9d7c2c2b3 --- /dev/null +++ b/src/blackgui/components/simulatorcomponent.ui @@ -0,0 +1,59 @@ + + + CSimulatorComponent + + + + 0 + 0 + 400 + 300 + + + + TabWidget + + + 0 + + + + Live data + + + + 3 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + + + + Information + + + + + + BlackGui::Views::CNameVariantPairView + QTableView +
blackgui/views/namevariantpairview.h
+
+
+ + +
diff --git a/src/blackgui/components/textmessagecomponent.cpp b/src/blackgui/components/textmessagecomponent.cpp new file mode 100644 index 000000000..2684b4de8 --- /dev/null +++ b/src/blackgui/components/textmessagecomponent.cpp @@ -0,0 +1,473 @@ +/* Copyright (C) 2013 + * swift Project Community / Contributors + * + * This file is part of swift project. It is subject to the license terms in the LICENSE file found in the top-level + * directory of this distribution and at http://www.swift-project.org/license.html. No part of Swift Project, + * including this file, may be copied, modified, propagated, or distributed except according to the terms + * contained in the LICENSE file. + */ + +#include "textmessagecomponent.h" +#include "blackmisc/nwuser.h" +#include "blackmisc/notificationsounds.h" +#include "ui_textmessagecomponent.h" + +#include +#include + +using namespace BlackCore; +using namespace BlackMisc; +using namespace BlackGui; +using namespace BlackMisc::Network; +using namespace BlackMisc::Aviation; +using namespace BlackMisc::PhysicalQuantities; +using namespace BlackMisc::Settings; + +namespace BlackGui +{ + namespace Components + { + + CTextMessageComponent::CTextMessageComponent(QWidget *parent) : + QTabWidget(parent), CRuntimeBasedComponent(nullptr, false), ui(new Ui::CTextMessageComponent), m_selcalCallback(nullptr), m_clearTextEditAction(nullptr), m_currentTextEdit(nullptr) + { + ui->setupUi(this); + this->m_clearTextEditAction = new QAction("Clear", this); + connect(this->m_clearTextEditAction, &QAction::triggered, this, &CTextMessageComponent::clearTextEdit); + + ui->te_TextMessagesAll->setContextMenuPolicy(Qt::CustomContextMenu); + connect(ui->te_TextMessagesAll, &QTextEdit::customContextMenuRequested, this, &CTextMessageComponent::showContextMenuForTextEdit); + + ui->te_TextMessagesUnicom->setContextMenuPolicy(Qt::CustomContextMenu); + connect(ui->te_TextMessagesUnicom, &QTextEdit::customContextMenuRequested, this, &CTextMessageComponent::showContextMenuForTextEdit); + + ui->te_TextMessagesCOM1->setContextMenuPolicy(Qt::CustomContextMenu); + connect(ui->te_TextMessagesCOM1, &QTextEdit::customContextMenuRequested, this, &CTextMessageComponent::showContextMenuForTextEdit); + + ui->te_TextMessagesCOM2->setContextMenuPolicy(Qt::CustomContextMenu); + connect(ui->te_TextMessagesCOM2, &QTextEdit::customContextMenuRequested, this, &CTextMessageComponent::showContextMenuForTextEdit); + } + + CTextMessageComponent::~CTextMessageComponent() + { + delete ui; + } + + QWidget *CTextMessageComponent::getTab(CTextMessageComponent::Tab tab) + { + switch (tab) + { + case TextMessagesAll: + return this->ui->tb_TextMessagesAll; + case TextMessagesCom1: + return this->ui->tb_TextMessagesCOM1; + case TextMessagesCom2: + return this->ui->tb_TextMessagesCOM2; + case TextMessagesUnicom: + return this->ui->tb_TextMessagesUnicom; + default: + qFatal("Wrong index"); + break; + } + return nullptr; + } + + /* + * Text messages received or send, append to GUI + */ + void CTextMessageComponent::appendTextMessagesToGui(const CTextMessageList &messages, bool sending) + { + if (messages.isEmpty()) return; + foreach(CTextMessage message, messages) + { + const QString currentSelcal = this->m_selcalCallback ? this->m_selcalCallback() : ""; + if (CSelcal::isValidCode(currentSelcal) && message.isSelcalMessageFor(currentSelcal)) + { + if (this->getOwnAircraft().isActiveFrequencyWithin25kHzChannel(message.getFrequency())) + { + // this is SELCAL for me + if (this->getIContextAudio()) + { + this->getIContextAudio()->playSelcalTone(currentSelcal); + } + else + { + emit this->displayInInfoWindow(CStatusMessage::getInfoMessage("SELCAL received", CStatusMessage::TypeGui).toCVariant(), 3 * 1000); + } + } + continue; // not displayed + } + + bool relevantForMe = false; + QString m = message.asString(true, false, "\t"); + + if (message.isSendToUnicom()) + { + this->ui->te_TextMessagesUnicom->append(m); + relevantForMe = true; + } + + // check message + if (message.isRadioMessage()) + { + // check for own COM frequencies + if (message.isSendToFrequency(this->getOwnAircraft().getCom1System().getFrequencyActive())) + { + this->ui->te_TextMessagesCOM1->append(m); + relevantForMe = true; + } + if (message.isSendToFrequency(this->getOwnAircraft().getCom2System().getFrequencyActive())) + { + this->ui->te_TextMessagesCOM2->append(m); + relevantForMe = true; + } + } + else if (message.isPrivateMessage() && !message.isServerMessage()) + { + // private message + this->addPrivateChannelTextMessage(message, sending); + relevantForMe = true; + } + + // message for me? right frequency? otherwise quit + if (relevantForMe || message.isServerMessage()) this->ui->te_TextMessagesAll->append(m); + if (!relevantForMe) return; + + // overlay message if this channel is not selected + if (!sending && !message.isSendToUnicom() && !message.isServerMessage()) + { + // if the channel is selected, do nothing + if (!this->isCorrespondingTextMessageTabSelected(message)) + emit this->displayInInfoWindow(message.toCVariant(), 5 * 1000); + } + } + } + + void CTextMessageComponent::changedAircraftCockpit() + { + this->showCurrentFrequenciesFromCockpit(); + } + + void CTextMessageComponent::runtimeHasBeenSet() + { + connect(this->getIContextOwnAircraft(), &IContextOwnAircraft::changedAircraftCockpit, this, &CTextMessageComponent::changedAircraftCockpit); + } + + /* + * Is the tab of the message's receiver selected? + */ + bool CTextMessageComponent::isCorrespondingTextMessageTabSelected(CTextMessage textMessage) const + { + if (!this->isVisible()) return false; + if (!textMessage.hasValidRecipient()) return false; + if (textMessage.isEmpty()) return false; // ignore empty message + if (textMessage.isPrivateMessage()) + { + // private message + CCallsign cs = textMessage.getSenderCallsign(); + if (cs.isEmpty()) return false; + QWidget *tab = this->findTextMessageTabByName(cs.getStringAsSet()); + if (!tab) return false; + return this->currentWidget() == tab; + } + else + { + // frequency message + const CAircraft ownAircraft = this->getOwnAircraft(); + if (this->currentWidget() == this->ui->tb_TextMessagesAll) return true; + if (textMessage.isSendToFrequency(ownAircraft.getCom1System().getFrequencyActive())) + return this->currentWidget() == this->ui->tb_TextMessagesCOM1; + if (textMessage.isSendToFrequency(ownAircraft.getCom2System().getFrequencyActive())) + return this->currentWidget() == this->ui->tb_TextMessagesCOM2; + return false; + } + } + + void CTextMessageComponent::showCurrentFrequenciesFromCockpit() + { + const CAircraft ownAircraft = this->getOwnAircraft(); + QString f1n, f2n; + f1n.sprintf("%03.3f", ownAircraft.getCom1System().getFrequencyActive().valueRounded(CFrequencyUnit::MHz(), 3)); + f2n.sprintf("%03.3f", ownAircraft.getCom2System().getFrequencyActive().valueRounded(CFrequencyUnit::MHz(), 3)); + const QString f1 = QString("COM1: %1").arg(f1n); + const QString f2 = QString("COM2: %1").arg(f2n); + this->ui->tb_TextMessagesCOM1->setToolTip(f1); + this->ui->tb_TextMessagesCOM1->setToolTip(f2); + this->setTabText(this->indexOf(this->ui->tb_TextMessagesCOM1), f1); + this->setTabText(this->indexOf(this->ui->tb_TextMessagesCOM2), f2); + } + + /* + * Add new text message tab + */ + QWidget *CTextMessageComponent::addNewTextMessageTab(const QString &tabName) + { + QWidget *newTab = new QWidget(this); + QPushButton *closeButton = new QPushButton("Close", newTab); + QVBoxLayout *layout = new QVBoxLayout(newTab); + QTextEdit *textEdit = new QTextEdit(newTab); + int marginLeft, marginRight, marginTop, marginBottom; + this->ui->tb_TextMessagesAll->layout()->getContentsMargins(&marginLeft, &marginTop, &marginRight, &marginBottom); + newTab->layout()->setContentsMargins(marginLeft, marginTop, marginRight, 2); + textEdit->setReadOnly(true); + textEdit->setWordWrapMode(QTextOption::NoWrap); + layout->addWidget(textEdit); + layout->addWidget(closeButton); + newTab->setLayout(layout); + textEdit->setContextMenuPolicy(Qt::CustomContextMenu); + connect(textEdit, &QTextEdit::customContextMenuRequested, this, &CTextMessageComponent::showContextMenuForTextEdit); + int index = this->addTab(newTab, tabName); + this->connect(closeButton, &QPushButton::released, this, &CTextMessageComponent::closeTextMessageTab); + this->setCurrentIndex(index); + + if (this->getIContextNetwork()) + { + QString realName = this->getIContextNetwork()->getUserForCallsign(CCallsign(tabName)).getRealName(); + if (!realName.isEmpty()) this->setTabToolTip(index, realName); + } + return newTab; + } + + /* + * Add a private channel text message + */ + void CTextMessageComponent::addPrivateChannelTextMessage(const CTextMessage &textMessage, bool sending) + { + if (!textMessage.isPrivateMessage()) return; + CCallsign cs = sending ? textMessage.getRecipientCallsign() : textMessage.getSenderCallsign(); + if (cs.isEmpty()) return; + QWidget *tab = this->findTextMessageTabByName(cs.getStringAsSet()); + if (tab == nullptr) tab = this->findTextMessageTabByName(cs.asString()); + if (tab == nullptr) tab = this->addNewTextMessageTab(cs.getStringAsSet()); + Q_ASSERT(tab != nullptr); + QTextEdit *textEdit = tab->findChild(); + Q_ASSERT(textEdit != nullptr); + if (textEdit == nullptr) return; // do not crash, though this situation could not happen + textEdit->append(textMessage.asString(true, false, "\t")); + + // sound + if (this->getIContextAudio()) + this->getIContextAudio()->playNotification(BlackSound::CNotificationSounds::NotificationTextMessagePrivate, true); + } + + /* + * Message tab by name + */ + QWidget *CTextMessageComponent::findTextMessageTabByName(const QString &name) const + { + if (name.isEmpty()) return nullptr; + QString n = name.trimmed(); + for (int index = 0; index < this->count(); index++) + { + QString tabName = this->tabText(index); + if (tabName.indexOf(n, 0, Qt::CaseInsensitive) < 0) continue; + QWidget *tab = this->widget(index); + return tab; + } + return nullptr; + } + + /* + * Text message stub (sender/receiver) for current channel + */ + CTextMessage CTextMessageComponent::getTextMessageStubForChannel() + { + CTextMessage tm; + int index = this->currentIndex(); + if (index < 0) return tm; + if (index == this->indexOf(this->ui->tb_TextMessagesAll)) return tm; + + // from + tm.setSenderCallsign(this->getOwnAircraft().getCallsign()); + + // frequency text message? + if (index == this->indexOf(this->ui->tb_TextMessagesCOM1)) + { + tm.setFrequency(this->getOwnAircraft().getCom1System().getFrequencyActive()); + } + else if (index == this->indexOf(this->ui->tb_TextMessagesCOM2)) + { + tm.setFrequency(this->getOwnAircraft().getCom2System().getFrequencyActive()); + } + else if (index == this->indexOf(this->ui->tb_TextMessagesUnicom)) + { + tm.setFrequency(CPhysicalQuantitiesConstants::FrequencyUnicom()); + } + else + { + // not a standard channel + QString selectedTabText = this->tabText(index); + bool isNumber; + double frequency = selectedTabText.toDouble(&isNumber); + if (isNumber) + { + CFrequency radioFrequency = CFrequency(frequency, CFrequencyUnit::MHz()); + if (CComSystem::isValidCivilAviationFrequency(radioFrequency)) + { + tm.setFrequency(radioFrequency); + } + else + { + CCallsign toCallsign(selectedTabText); + tm.setRecipientCallsign(toCallsign); + } + } + else + { + CCallsign toCallsign(selectedTabText); + tm.setRecipientCallsign(toCallsign); + } + } + return tm; // now valid message stub with receiver + } + + /* + * Close message tab + */ + void CTextMessageComponent::closeTextMessageTab() + { + QObject *sender = QObject::sender(); + QWidget *parentWidget = qobject_cast(sender->parent()); + Q_ASSERT(parentWidget); + int index = -1; + + while (index < 0 && parentWidget) + { + index = this->indexOf(parentWidget); + parentWidget = parentWidget->parentWidget(); + } + if (index >= 0) this->removeTab(index); + } + + void CTextMessageComponent::showContextMenuForTextEdit(const QPoint &pt) + { + QObject *sender = QObject::sender(); + this->m_currentTextEdit = qobject_cast(sender); + Q_ASSERT(this->m_currentTextEdit); + + QMenu *menu = this->m_currentTextEdit->createStandardContextMenu(); + menu->setParent(this->m_currentTextEdit); + menu->setObjectName(this->m_currentTextEdit->objectName().append("_contextMenu")); + menu->addSeparator(); + menu->addAction(this->m_clearTextEditAction); + menu->exec(this->m_currentTextEdit->mapToGlobal(pt)); + delete menu; + } + + void CTextMessageComponent::clearTextEdit() + { + if (!this->m_currentTextEdit) return; + this->m_currentTextEdit->clear(); + this->m_currentTextEdit = nullptr; + } + + /* + * Command entered + */ + void CTextMessageComponent::commandEntered() + { + // TODO: just a first draft of the command line parser + // needs to be refactored, as soon as a first version works + + QLineEdit *lineEdit = qobject_cast(QObject::sender()); + Q_ASSERT(lineEdit); + + QString cmdLine = lineEdit->text().simplified(); + if (cmdLine.isEmpty()) return; + QList parts = cmdLine.toLower().split(' '); + if (parts.length() < 1) return; + QString cmd = parts[0].startsWith('.') ? parts[0].toLower() : ""; + if (cmd == ".m" || cmd == ".msg") + { + if (!this->getIContextNetwork() || !this->getIContextNetwork()->isConnected()) + { + this->sendStatusMessage(CStatusMessage(CStatusMessage::TypeTrafficNetwork, CStatusMessage::SeverityError, "network needs to be connected")); + return; + } + if (parts.length() < 3) + { + this->sendStatusMessage(CStatusMessage(CStatusMessage::TypeValidation, CStatusMessage::SeverityError, "incorrect message")); + return; + } + QString p = parts[1].trimmed(); // receiver + + // select current tab by command + this->setVisible(true); + if (p == "c1" || p == "com1") + { + this->setCurrentWidget(this->ui->tb_TextMessagesCOM1); + } + else if (p == "c2" || p == "com2") + { + this->setCurrentWidget(this->ui->tb_TextMessagesCOM2); + } + else if (p == "u" || p == "unicom" || p == "uni") + { + this->setCurrentWidget(this->ui->tb_TextMessagesUnicom); + } + else + { + QWidget *tab = this->findTextMessageTabByName(p.trimmed()); + if (tab == nullptr) tab = this->addNewTextMessageTab(p.trimmed().toUpper()); + this->setCurrentWidget(tab); + } + CTextMessage tm = this->getTextMessageStubForChannel(); + int index = cmdLine.indexOf(tm.getRecipientCallsign().getStringAsSet(), 0, Qt::CaseInsensitive); + if (index < 0) + { + this->sendStatusMessage( + CStatusMessage(CStatusMessage::TypeValidation, CStatusMessage::SeverityError, + "incomplete message") + ); + return; + } + QString msg(cmdLine.mid(index + tm.getRecipientCallsign().asString().length() + 1)); + tm.setMessage(msg); + if (tm.isEmpty()) return; + if (!this->isNetworkConnected()) return; + CTextMessageList tml(tm); + this->getIContextNetwork()->sendTextMessages(tml); + this->appendTextMessagesToGui(tml, true); + lineEdit->setText(""); + } + else if (cmd.startsWith(".")) + { + // dump CMDs + } + else + { + // single line, no command + // line is considered to be a message to the selected channel, send + if (!this->isNetworkConnected()) + { + this->sendStatusMessage(CStatusMessage(CStatusMessage::TypeTrafficNetwork, CStatusMessage::SeverityError, "network needs to be connected")); + return; + } + + if (!this->isVisible()) + { + this->sendStatusMessage(CStatusMessage(CStatusMessage::TypeTrafficNetwork, CStatusMessage::SeverityError, "text messages can only be sent from corresponding page")); + return; + } + + int index = this->currentIndex(); + if (index < 0 || index == this->indexOf(this->ui->tb_TextMessagesAll)) + { + this->sendStatusMessage(CStatusMessage(CStatusMessage::TypeValidation, CStatusMessage::SeverityError, "incorrect channel")); + } + else + { + CTextMessage tm = this->getTextMessageStubForChannel(); + tm.setMessage(cmdLine); + if (tm.isEmpty()) return; + if (!this->getIContextNetwork()) return; + CTextMessageList textMessageList(tm); + this->getIContextNetwork()->sendTextMessages(textMessageList); + this->appendTextMessagesToGui(textMessageList, true); + lineEdit->setText(""); + } + } + } + } +} + diff --git a/src/blackgui/components/textmessagecomponent.h b/src/blackgui/components/textmessagecomponent.h new file mode 100644 index 000000000..8d2c552d2 --- /dev/null +++ b/src/blackgui/components/textmessagecomponent.h @@ -0,0 +1,129 @@ +/* Copyright (C) 2013 + * swift Project Community / Contributors + * + * This file is part of swift project. It is subject to the license terms in the LICENSE file found in the top-level + * directory of this distribution and at http://www.swift-project.org/license.html. No part of Swift Project, + * including this file, may be copied, modified, propagated, or distributed except according to the terms + * contained in the LICENSE file. + */ + +#ifndef BLACKGUI_TEXTMESSAGECOMPONENT_H +#define BLACKGUI_TEXTMESSAGECOMPONENT_H + +//! \file + +#include "blackgui/components/runtimebasedcomponent.h" +#include "blackgui/components/timerbasedcomponent.h" +#include "blackmisc/nwtextmessage.h" +#include "blackmisc/avaircraft.h" + +#include +#include +#include + +namespace Ui { class CTextMessageComponent; } +namespace BlackGui +{ + namespace Components + { + //! Text message widget + class CTextMessageComponent : public QTabWidget, public CRuntimeBasedComponent + { + Q_OBJECT + + public: + //! Tabs + enum Tab + { + TextMessagesAll, + TextMessagesUnicom, + TextMessagesCom1, + TextMessagesCom2 + }; + + //! Constructor + explicit CTextMessageComponent(QWidget *parent = nullptr); + + //! Destructor + ~CTextMessageComponent(); + + //! SELCAL callback, SELCAL is obtained by that + void setSelcalCallback(const std::function &selcalCallback) { this->m_selcalCallback = selcalCallback; } + + signals: + //! Message to be displayed in info window + void displayInInfoWindow(const BlackMisc::CVariant &message, int displayDurationMs) const; + + public slots: + //! Command entered + void commandEntered(); + + /*! + * \brief Append text messages (received, to be sent) to GUI + * \param messages + * \param sending + */ + void appendTextMessagesToGui(const BlackMisc::Network::CTextMessageList &messages, bool sending = false); + + //! Cockpit values changed, used to updated some components + void changedAircraftCockpit(); + + protected: + //! \copydoc CRuntimeBasedComponent::runtimeHasBeenSet + void runtimeHasBeenSet() override; + + private: + Ui::CTextMessageComponent *ui; + QWidget *getTab(Tab tab); //!< enum to widget + std::function m_selcalCallback; //!< obtain SELCAL by that + QAction *m_clearTextEditAction; + QTextEdit *m_currentTextEdit; + + /*! + * \brief Add new text message tab + * \param tabName name of the new tab, usually the channel name + * \return + */ + QWidget *addNewTextMessageTab(const QString &tabName); + + //! Find text message tab by its name + QWidget *findTextMessageTabByName(const QString &name) const; + + /*! + * \brief Private channel text message + * \param textMessage + * \param sending sending or receiving + */ + void addPrivateChannelTextMessage(const BlackMisc::Network::CTextMessage &textMessage, bool sending = false); + + /*! + * Stub for sending a text message (eihter radio or private message). + * Sets sender / receiver depending on frequency / channel situation. + */ + BlackMisc::Network::CTextMessage getTextMessageStubForChannel(); + + //! own aircraft + const BlackMisc::Aviation::CAircraft getOwnAircraft() const { Q_ASSERT(this->getIContextOwnAircraft()); return this->getIContextOwnAircraft()->getOwnAircraft(); } + + //! For this text message's recepient, is the current tab selected? + bool isCorrespondingTextMessageTabSelected(BlackMisc::Network::CTextMessage textMessage) const; + + //! Network connected? + bool isNetworkConnected() const { return this->getIContextNetwork() && this->getIContextNetwork()->isConnected() ; } + + //! Show current frequencies + void showCurrentFrequenciesFromCockpit(); + + private slots: + //! Close text message tab + void closeTextMessageTab(); + + //! Context menu for text edit including clear + void showContextMenuForTextEdit(const QPoint &pt); + + //! Clear text edit + void clearTextEdit(); + }; + } +} +#endif // guard diff --git a/src/blackgui/textmessagecomponent.ui b/src/blackgui/components/textmessagecomponent.ui similarity index 100% rename from src/blackgui/textmessagecomponent.ui rename to src/blackgui/components/textmessagecomponent.ui diff --git a/src/blackgui/components/timerbasedcomponent.cpp b/src/blackgui/components/timerbasedcomponent.cpp new file mode 100644 index 000000000..417916a10 --- /dev/null +++ b/src/blackgui/components/timerbasedcomponent.cpp @@ -0,0 +1,42 @@ +/* Copyright (C) 2013 + * swift Project Community / Contributors + * + * This file is part of swift project. It is subject to the license terms in the LICENSE file found in the top-level + * directory of this distribution and at http://www.swift-project.org/license.html. No part of Swift Project, + * including this file, may be copied, modified, propagated, or distributed except according to the terms + * contained in the LICENSE file. + */ + +#include "timerbasedcomponent.h" + +namespace BlackGui +{ + namespace Components + { + CTimerBasedComponent::CTimerBasedComponent(const char *slot, QObject *parent) : + QObject(parent), m_timer(nullptr) + { + this->m_timer = new QTimer(this); + this->connect(this->m_timer, SIGNAL(timeout()), parent, slot); + } + + CTimerBasedComponent::~CTimerBasedComponent() + { + this->m_timer->stop(); + if (this->parent()) this->disconnect(this->parent()); + } + + void CTimerBasedComponent::setUpdateInterval(int milliSeconds) + { + if (milliSeconds < 100) + { + this->m_timer->stop(); + } + else + { + this->m_timer->setInterval(milliSeconds); + if (!this->m_timer->isActive()) this->m_timer->start(); + } + } + } +} // guard diff --git a/src/blackgui/components/timerbasedcomponent.h b/src/blackgui/components/timerbasedcomponent.h new file mode 100644 index 000000000..84b3b2268 --- /dev/null +++ b/src/blackgui/components/timerbasedcomponent.h @@ -0,0 +1,44 @@ +/* Copyright (C) 2013 + * swift Project Community / Contributors + * + * This file is part of swift project. It is subject to the license terms in the LICENSE file found in the top-level + * directory of this distribution and at http://www.swift-project.org/license.html. No part of Swift Project, + * including this file, may be copied, modified, propagated, or distributed except according to the terms + * contained in the LICENSE file. + */ + +#ifndef BLACKGUI_TIMERBASEDCOMPONENT_H +#define BLACKGUI_TIMERBASEDCOMPONENT_H + +#include + +namespace BlackGui +{ + namespace Components + { + //! Timer based componenet + class CTimerBasedComponent: public QObject + { + public: + //! Constructor + CTimerBasedComponent(const char *slot, QObject *parent); + + //! Destructor + ~CTimerBasedComponent(); + + public slots: + //! Update time, time < 100 stops updates + void setUpdateInterval(int milliSeconds); + + //! Update time + void setUpdateIntervalSeconds(int seconds) { this->setUpdateInterval(1000 * seconds); } + + //! Stop timer + void stopTimer() { this->setUpdateInterval(-1); } + + private: + QTimer *m_timer; + }; + } +} +#endif // guard diff --git a/src/blackgui/components/usercomponent.cpp b/src/blackgui/components/usercomponent.cpp new file mode 100644 index 000000000..0ef325eec --- /dev/null +++ b/src/blackgui/components/usercomponent.cpp @@ -0,0 +1,42 @@ +/* Copyright (C) 2013 + * swift Project Community / Contributors + * + * This file is part of swift project. It is subject to the license terms in the LICENSE file found in the top-level + * directory of this distribution and at http://www.swift-project.org/license.html. No part of Swift Project, + * including this file, may be copied, modified, propagated, or distributed except according to the terms + * contained in the LICENSE file. + */ + +#include "usercomponent.h" +#include "ui_usercomponent.h" + +namespace BlackGui +{ + namespace Components + { + CUserComponent::CUserComponent(QWidget *parent) : + QTabWidget(parent), CRuntimeBasedComponent(nullptr, false), ui(new Ui::CUserComponent), m_timerComponent(nullptr) + { + ui->setupUi(this); + this->m_timerComponent = new CTimerBasedComponent(SLOT(update()), this); + } + + CUserComponent::~CUserComponent() + { + delete ui; + } + + void CUserComponent::update() + { + Q_ASSERT(this->ui->tvp_AllUsers); + Q_ASSERT(this->ui->tvp_Clients); + Q_ASSERT(this->getIContextNetwork()); + + if (this->getIContextNetwork()->isConnected()) + { + this->ui->tvp_Clients->update(this->getIContextNetwork()->getOtherClients()); + this->ui->tvp_AllUsers->update(this->getIContextNetwork()->getUsers()); + } + } + } +} // guard diff --git a/src/blackgui/components/usercomponent.h b/src/blackgui/components/usercomponent.h new file mode 100644 index 000000000..73f26952a --- /dev/null +++ b/src/blackgui/components/usercomponent.h @@ -0,0 +1,60 @@ +/* Copyright (C) 2013 + * swift Project Community / Contributors + * + * This file is part of swift project. It is subject to the license terms in the LICENSE file found in the top-level + * directory of this distribution and at http://www.swift-project.org/license.html. No part of Swift Project, + * including this file, may be copied, modified, propagated, or distributed except according to the terms + * contained in the LICENSE file. + */ + +#ifndef BLACKGUI_USERCOMPONENT_H +#define BLACKGUI_USERCOMPONENT_H + +#include "blackgui/components/runtimebasedcomponent.h" +#include "blackgui/components/timerbasedcomponent.h" +#include "blackmisc/nwuserlist.h" + +#include +#include + +namespace Ui { class CUserComponent; } + +namespace BlackGui +{ + namespace Components + { + //! User componenet (users, clients) + class CUserComponent : public QTabWidget, public CRuntimeBasedComponent + { + Q_OBJECT + + public: + //! Constructor + explicit CUserComponent(QWidget *parent = nullptr); + + //! Destructor + ~CUserComponent(); + + //! Timer for updating + CTimerBasedComponent *getTimerComponent() { return this->m_timerComponent; } + + public slots: + //! Update users + void update(); + + //! \copydoc CTimerBasedComponent::setUpdateIntervalSeconds + void setUpdateIntervalSeconds(int seconds) { Q_ASSERT(this->m_timerComponent); this->m_timerComponent->setUpdateIntervalSeconds(seconds); } + + //! \copydoc CTimerBasedComponent::setUpdateInterval + void setUpdateInterval(int milliSeconds) { Q_ASSERT(this->m_timerComponent); this->m_timerComponent->setUpdateInterval(milliSeconds); } + + //! \copydoc CTimerBasedComponent::stopTimer + void stopTimer() { Q_ASSERT(this->m_timerComponent); this->m_timerComponent->stopTimer(); } + + private: + Ui::CUserComponent *ui; + CTimerBasedComponent *m_timerComponent; + }; + } +} +#endif // guard diff --git a/src/blackgui/usercomponent.ui b/src/blackgui/components/usercomponent.ui similarity index 86% rename from src/blackgui/usercomponent.ui rename to src/blackgui/components/usercomponent.ui index 35f08ba7f..0009f4417 100644 --- a/src/blackgui/usercomponent.ui +++ b/src/blackgui/components/usercomponent.ui @@ -37,7 +37,7 @@ 0 - + false @@ -66,7 +66,7 @@ 0 - + false @@ -77,14 +77,14 @@ - BlackGui::CUserView + BlackGui::Views::CUserView QTableView -
blackgui/userview.h
+
blackgui/views/userview.h
- BlackGui::CClientView + BlackGui::Views::CClientView QTableView -
blackgui/clientview.h
+
blackgui/views/clientview.h
diff --git a/src/blackgui/flightplancomponent.cpp b/src/blackgui/flightplancomponent.cpp deleted file mode 100644 index dd930e239..000000000 --- a/src/blackgui/flightplancomponent.cpp +++ /dev/null @@ -1,393 +0,0 @@ -#include "flightplancomponent.h" -#include "ui_flightplancomponent.h" - -using namespace BlackMisc; -using namespace BlackMisc::Aviation; -using namespace BlackMisc::PhysicalQuantities; - -namespace BlackGui -{ - CFlightPlanComponent::CFlightPlanComponent(QWidget *parent) : - QTabWidget(parent), CRuntimeBasedComponent(nullptr, false), ui(new Ui::CFlightPlanComponent) - { - ui->setupUi(this); - connect(this->ui->pb_Send, &QPushButton::pressed, this, &CFlightPlanComponent::sendFlightPlan); - connect(this->ui->pb_Load, &QPushButton::pressed, this, &CFlightPlanComponent::loadFlightPlanFromNetwork); - connect(this->ui->pb_Reset, &QPushButton::pressed, this, &CFlightPlanComponent::resetFlightPlan); - connect(this->ui->pb_ValidateFlightPlan, &QPushButton::pressed, this, &CFlightPlanComponent::validateFlightPlan); - - bool c; - c = connect(this->ui->cb_VoiceCapabilities, SIGNAL(currentIndexChanged(int)), this, SLOT(buildRemarkString())); - Q_ASSERT(c); - c = connect(this->ui->cb_NavigationEquipment, SIGNAL(currentIndexChanged(int)), this, SLOT(buildRemarkString())); - Q_ASSERT(c); - c = connect(this->ui->cb_PerformanceCategory, SIGNAL(currentIndexChanged(int)), this, SLOT(buildRemarkString())); - Q_ASSERT(c); - c = connect(this->ui->cb_PilotRating, SIGNAL(currentIndexChanged(int)), this, SLOT(buildRemarkString())); - Q_ASSERT(c); - c = connect(this->ui->cb_RequiredNavigationPerformance, SIGNAL(currentIndexChanged(int)), this, SLOT(buildRemarkString())); - Q_ASSERT(c); - c = connect(this->ui->cb_NoSidsStarts, SIGNAL(toggled(bool)), this, SLOT(buildRemarkString())); - Q_ASSERT(c); - c = connect(this->ui->le_AircraftRegistration, SIGNAL(textChanged(QString)), this, SLOT(buildRemarkString())); - Q_ASSERT(c); - c = connect(this->ui->le_AirlineOperator, SIGNAL(textChanged(QString)), this, SLOT(buildRemarkString())); - Q_ASSERT(c); - Q_UNUSED(c); - - connect(this->ui->pte_AdditionalRemarks, &QPlainTextEdit::textChanged, this, &CFlightPlanComponent::buildRemarkString); - connect(this->ui->frp_SelcalCode, &CSelcalCodeSelector::valueChanged, this, &CFlightPlanComponent::buildRemarkString); - connect(this->ui->pb_CopyOver, &QPushButton::pressed, this, &CFlightPlanComponent::copyRemarks); - connect(this->ui->pb_RemarksGenerator, &QPushButton::clicked, this, &CFlightPlanComponent::currentTabGenerator); - - this->ui->frp_SelcalCode->resetSelcalCodes(true); - this->resetFlightPlan(); - this->buildRemarkString(); - } - - CFlightPlanComponent::~CFlightPlanComponent() - { - delete ui; - } - - void CFlightPlanComponent::prefillWithAircraftData(const BlackMisc::Aviation::CAircraft &ownAircraft) - { - this->ui->le_Callsign->setText(ownAircraft.getCallsign().asString()); - this->ui->le_AircraftType->setText(ownAircraft.getIcaoInfo().getAircraftDesignator()); - this->ui->le_PilotsName->setText(ownAircraft.getPilot().getRealName()); - } - - void CFlightPlanComponent::fillWithFlightPlanData(const BlackMisc::Aviation::CFlightPlan &flightPlan) - { - this->ui->le_AlternateAirport->setText(flightPlan.getAlternateAirportIcao().asString()); - this->ui->le_DestinationAirport->setText(flightPlan.getAlternateAirportIcao().asString()); - this->ui->le_OriginAirport->setText(flightPlan.getAlternateAirportIcao().asString()); - this->ui->pte_Route->setPlainText(flightPlan.getRoute()); - this->ui->pte_Remarks->setPlainText(flightPlan.getRemarks()); - this->ui->le_TakeOffTimePlanned->setText(flightPlan.getTakeoffTimePlannedHourMin()); - this->ui->le_FuelOnBoard->setText(flightPlan.getFuelTimeHourMin()); - this->ui->le_EstimatedTimeEnroute->setText(flightPlan.getEnrouteTimeHourMin()); - this->ui->le_CruiseTrueAirspeed->setText(flightPlan.getCruiseTrueAirspeed().valueRoundedWithUnit(BlackMisc::PhysicalQuantities::CSpeedUnit::kts(), 0)); - - CAltitude cruiseAlt = flightPlan.getCruiseAltitude(); - if (cruiseAlt.isFlightLevel()) - this->ui->le_CrusingAltitude->setText(cruiseAlt.toQString()); - else - this->ui->le_CrusingAltitude->setText(cruiseAlt.valueRoundedWithUnit(BlackMisc::PhysicalQuantities::CLengthUnit::ft(), 0)); - } - - CFlightPlan CFlightPlanComponent::getFlightPlan() const - { - return this->m_flightPlan; - } - - BlackMisc::CStatusMessageList CFlightPlanComponent::validateAndInitializeFlightPlan(BlackMisc::Aviation::CFlightPlan &flightPlan) - { - BlackMisc::CStatusMessageList messages; - QString v; - - CFlightPlan::FlightRules rule = CFlightPlan::IFR; - if (this->ui->rb_TypeIfr->isChecked()) - rule = CFlightPlan::IFR; - else if (this->ui->rb_TypeVfr->isChecked()) - rule = CFlightPlan::VFR; - flightPlan.setFlightRule(rule); - - v = ui->le_Callsign->text().trimmed(); - if (v.isEmpty()) - { - QString m = QString("Missing %1").arg(this->ui->lbl_Callsign->text()); - messages.push_back(CStatusMessage::getValidationError(m)); - } - - v = ui->pte_Route->toPlainText().trimmed(); - if (v.isEmpty()) - { - QString m = QString("Missing flight plan route"); - messages.push_back(CStatusMessage::getValidationError(m)); - } - else if (v.length() > CFlightPlan::MaxRouteLength) - { - QString m = QString("Flight plan route length exceeded (%1 chars max.)").arg(CFlightPlan::MaxRouteLength); - messages.push_back(CStatusMessage::getValidationError(m)); - } - else - flightPlan.setRoute(v); - - v = ui->pte_Remarks->toPlainText().trimmed(); - if (v.isEmpty()) - { - QString m = QString("No remarks, voice capabilities are mandatory"); - messages.push_back(CStatusMessage::getValidationError(m)); - } - else if (v.length() > CFlightPlan::MaxRemarksLength) - { - QString m = QString("Flight plan remarks length exceeded (%1 chars max.)").arg(CFlightPlan::MaxRemarksLength); - messages.push_back(CStatusMessage::getValidationError(m)); - } - else - flightPlan.setRemarks(v); - - v = ui->le_EstimatedTimeEnroute->text(); - if (v.isEmpty() || v == defaultTime()) - { - QString m = QString("Missing %1").arg(this->ui->lbl_EstimatedTimeEnroute->text()); - messages.push_back(CStatusMessage::getValidationError(m)); - } - else - flightPlan.setEnrouteTime(v); - - v = ui->le_FuelOnBoard->text(); - if (v.isEmpty() || v == defaultTime()) - { - QString m = QString("Missing %1").arg(this->ui->lbl_FuelOnBorad->text()); - messages.push_back(CStatusMessage::getValidationError(m)); - } - else - flightPlan.setFuelTime(v); - - v = ui->le_TakeOffTimePlanned->text(); - if (v.isEmpty() || v == defaultTime()) - { - QString m = QString("Missing %1").arg(this->ui->lbl_TakeOffTimePlanned->text()); - messages.push_back(CStatusMessage::getValidationError(m)); - } - else - flightPlan.setTakeoffTimePlanned(v); - - static const QRegExp withUnit("\\D+"); - v = ui->le_CrusingAltitude->text().trimmed(); - if (!v.isEmpty() && withUnit.indexIn(v) < 0) - { - v += "ft"; - this->ui->le_CrusingAltitude->setText(v); - } - - CAltitude cruisingAltitude(v, CPqString::SeparatorsLocale); - if (v.isEmpty() || cruisingAltitude.isNull()) - { - QString m = QString("Wrong %1").arg(this->ui->lbl_CrusingAltitude->text()); - messages.push_back(CStatusMessage::getValidationError(m)); - } - else - flightPlan.setCruiseAltitude(cruisingAltitude); - - v = this->ui->le_AlternateAirport->text(); - if (v.isEmpty() || v.endsWith(defaultIcao(), Qt::CaseInsensitive)) - { - QString m = QString("Missing %1").arg(this->ui->lbl_AlternateAirport->text()); - messages.push_back(CStatusMessage::getValidationError(m)); - flightPlan.setAlternateAirportIcao(defaultIcao()); - } - else - flightPlan.setAlternateAirportIcao(v); - - v = this->ui->le_DestinationAirport->text(); - if (v.isEmpty() || v.endsWith(defaultIcao(), Qt::CaseInsensitive)) - { - QString m = QString("Missing %1").arg(this->ui->lbl_DestinationAirport->text()); - messages.push_back(CStatusMessage::getValidationError(m)); - flightPlan.setDestinationAirportIcao(defaultIcao()); - } - else - flightPlan.setDestinationAirportIcao(v); - - v = this->ui->le_CruiseTrueAirspeed->text(); - BlackMisc::PhysicalQuantities::CSpeed cruiseTAS; - cruiseTAS.parseFromString(v, CPqString::SeparatorsLocale); - if (cruiseTAS.isNull()) - { - QString m = QString("Wrong TAS, %1").arg(this->ui->lbl_CruiseTrueAirspeed->text()); - messages.push_back(CStatusMessage::getValidationError(m)); - flightPlan.setDestinationAirportIcao(defaultIcao()); - } - else - flightPlan.setCruiseTrueAirspeed(cruiseTAS); - - v = this->ui->le_OriginAirport->text(); - if (v.isEmpty() || v.endsWith(defaultIcao(), Qt::CaseInsensitive)) - { - QString m = QString("Missing %1").arg(this->ui->lbl_OriginAirport->text()); - messages.push_back(CStatusMessage::getValidationError(m)); - flightPlan.setOriginAirportIcao(defaultIcao()); - } - else - flightPlan.setOriginAirportIcao(v); - - return messages; - } - - void CFlightPlanComponent::sendFlightPlan() - { - CFlightPlan flightPlan; - CStatusMessageList messages = this->validateAndInitializeFlightPlan(flightPlan); - if (messages.isEmpty()) - { - // no error, send if possible - CStatusMessage m; - if (this->getIContextNetwork()->isConnected()) - { - flightPlan.setWhenLastSentOrLoaded(QDateTime::currentDateTimeUtc()); - this->getIContextNetwork()->sendFlightPlan(flightPlan); - this->ui->le_LastSent->setText(flightPlan.whenLastSentOrLoaded().toString()); - m = CStatusMessage::getInfoMessage("Sent flight plan", CStatusMessage::TypeTrafficNetwork); - } - else - { - flightPlan.setWhenLastSentOrLoaded(QDateTime()); // empty - this->ui->le_LastSent->clear(); - m = CStatusMessage::getErrorMessage("No errors, but not connected, cannot send flight plan", CStatusMessage::TypeTrafficNetwork); - } - this->sendStatusMessage(m); - this->m_flightPlan = flightPlan; // last valid FP - } - else - { - this->sendStatusMessages(messages); - } - } - - void CFlightPlanComponent::validateFlightPlan() - { - CFlightPlan flightPlan; - CStatusMessageList messages = this->validateAndInitializeFlightPlan(flightPlan); - if (messages.isEmpty()) - { - this->sendStatusMessage(CStatusMessage::getInfoMessage("No errors", CStatusMessage::TypeTrafficNetwork)); - } - else - { - this->sendStatusMessages(messages); - } - } - - void CFlightPlanComponent::resetFlightPlan() - { - if (this->getIContextNetwork()) - { - this->prefillWithAircraftData(this->getIContextOwnAircraft()->getOwnAircraft()); - } - this->ui->le_AircraftRegistration->clear(); - this->ui->le_AirlineOperator->clear(); - this->ui->le_CrusingAltitude->setText("FL70"); - this->ui->le_CruiseTrueAirspeed->setText("100 kts"); - this->ui->pte_Remarks->clear(); - this->ui->pte_Route->clear(); - this->ui->le_AlternateAirport->setText(defaultIcao()); - this->ui->le_DestinationAirport->setText(defaultIcao()); - this->ui->le_OriginAirport->setText(defaultIcao()); - this->ui->le_FuelOnBoard->setText(defaultTime()); - this->ui->le_EstimatedTimeEnroute->setText(defaultTime()); - this->ui->le_TakeOffTimePlanned->setText(QDateTime::currentDateTimeUtc().addSecs(30 * 60).toString("hh:mm")); - } - - void CFlightPlanComponent::loadFlightPlanFromNetwork() - { - if (!this->getIContextNetwork()) - { - this->sendStatusMessage(CStatusMessage::getInfoMessage("Cannot load flight plan, network not available", CStatusMessage::TypeTrafficNetwork)); - return; - } - if (!this->getIContextNetwork()->isConnected()) - { - this->sendStatusMessage(CStatusMessage::getWarningMessage("Cannot load flight plan, network not connected", CStatusMessage::TypeTrafficNetwork)); - return; - } - - CAircraft ownAircraft = this->getIContextOwnAircraft()->getOwnAircraft(); - CFlightPlan loadedPlan = this->getIContextNetwork()->loadFlightPlanFromNetwork(ownAircraft.getCallsign()); - if (loadedPlan.wasSentOrLoaded()) - { - this->fillWithFlightPlanData(loadedPlan); - this->sendStatusMessage(CStatusMessage::getInfoMessage("Updated with loaded flight plan", CStatusMessage::TypeTrafficNetwork)); - } - else - { - this->sendStatusMessage(CStatusMessage::getWarningMessage("No flight plan data", CStatusMessage::TypeTrafficNetwork)); - } - } - - void CFlightPlanComponent::buildRemarkString() - { - QString rem; - QString v = this->ui->cb_VoiceCapabilities->currentText().toUpper(); - if (v.contains("TEXT")) - rem.append("/T/ "); - else if (v.contains("VOICE")) - rem.append("/V/ "); - else if (v.contains("RECEIVE")) - rem.append("/R/ "); - - v = this->ui->le_AirlineOperator->text().trimmed(); - if (!v.isEmpty()) rem.append("OPR/").append(v).append(" "); - - v = this->ui->le_AircraftRegistration->text().trimmed(); - if (!v.isEmpty()) rem.append("REG/").append(v).append(" "); - - v = this->ui->cb_PilotRating->currentText().toUpper(); - if (v.contains("P1")) - rem.append("PR/P1 "); - else if (v.contains("P2")) - rem.append("PR/P2 "); - else if (v.contains("P3")) - rem.append("PR/P3 "); - else if (v.contains("P4")) - rem.append("PR/P4 "); - else if (v.contains("P5")) - rem.append("PR/P5 "); - - v = this->ui->cb_RequiredNavigationPerformance->currentText().toUpper(); - if (v.contains("10")) - rem.append("RNP10 "); - else if (v.contains("4")) - rem.append("RNP4 "); - - v = this->ui->cb_NavigationEquipment->currentText().toUpper(); - if (v.contains("VORS")) - rem.append("NAV/VORNDB "); - else if (v.contains("SIDS")) - rem.append("NAV/GPSRNAV "); - if (v.contains("DEFAULT")) - rem.append("NAV/GPS "); - else if (v.contains("OCEANIC")) - rem.append("NAV/GPSOCEANIC "); - - v = this->ui->cb_PerformanceCategory->currentText().toUpper(); - if (v.startsWith("A")) - rem.append("PER/A "); - else if (v.startsWith("B")) - rem.append("PER/B "); - else if (v.startsWith("C")) - rem.append("PER/C "); - else if (v.startsWith("D")) - rem.append("PER/D "); - else if (v.startsWith("E")) - rem.append("PER/E "); - - if (this->ui->frp_SelcalCode->hasValidCode()) - { - rem.append("SEL/").append(this->ui->frp_SelcalCode->getSelcalCode()); - rem.append(" "); - } - - if (this->ui->cb_NoSidsStarts->isChecked()) - rem.append("NO SID/STAR "); - - v = this->ui->pte_AdditionalRemarks->toPlainText().trimmed(); - if (!v.isEmpty()) rem.append(v); - - rem = rem.simplified().trimmed(); - this->ui->pte_RemarksGenerated->setPlainText(rem); - } - - void CFlightPlanComponent::copyRemarks() - { - this->ui->pte_Remarks->setPlainText(this->ui->pte_RemarksGenerated->toPlainText()); - this->sendStatusMessage(CStatusMessage::getInfoMessage("Copied remarks", CStatusMessage::TypeTrafficNetwork)); - } - - void CFlightPlanComponent::currentTabGenerator() - { - this->setCurrentWidget(this->ui->tb_RemarksGenerator); - } -} diff --git a/src/blackgui/flightplancomponent.h b/src/blackgui/flightplancomponent.h deleted file mode 100644 index be3966350..000000000 --- a/src/blackgui/flightplancomponent.h +++ /dev/null @@ -1,74 +0,0 @@ -#ifndef BLACKGUI_FLIGHTPLANCOMPONENT_H -#define BLACKGUI_FLIGHTPLANCOMPONENT_H - -#include "blackgui/runtimebasedcomponent.h" -#include "blackmisc/avaircraft.h" -#include "blackmisc/avflightplan.h" - -#include - -namespace Ui { class CFlightPlanComponent; } -namespace BlackGui -{ - //! Flight plan widget - class CFlightPlanComponent : public QTabWidget, public CRuntimeBasedComponent - { - Q_OBJECT - - public: - //! Constructor - explicit CFlightPlanComponent(QWidget *parent = nullptr); - - //! Destructor - ~CFlightPlanComponent(); - - public slots: - //! Prefill with aircraft data - void prefillWithAircraftData(const BlackMisc::Aviation::CAircraft &ownAircraft); - - //! Prefill with aircraft dara - void fillWithFlightPlanData(const BlackMisc::Aviation::CFlightPlan &flightPlan); - - //! Get this flight plan - BlackMisc::Aviation::CFlightPlan getFlightPlan() const; - - private: - Ui::CFlightPlanComponent *ui; - - //! My flight plan - BlackMisc::Aviation::CFlightPlan m_flightPlan; - - //! Validate, generates status messages - BlackMisc::CStatusMessageList validateAndInitializeFlightPlan(BlackMisc::Aviation::CFlightPlan &fligtPlan); - - //! Default value for airport ICAO airports - static const QString &defaultIcao() { static QString d("ICAO"); return d; } - - //! Default value for time - static const QString &defaultTime() { static QString t("00:00"); return t; } - - private slots: - //! Send flightplan - void sendFlightPlan(); - - //! Reset Flightplan - void resetFlightPlan(); - - //! Load Flightplan - void loadFlightPlanFromNetwork(); - - //! Validate Flightplan - void validateFlightPlan(); - - //! Remark - void buildRemarkString(); - - //! Copy over - void copyRemarks(); - - //! Show generator tab page - void currentTabGenerator(); - - }; -} -#endif // guard diff --git a/src/blackgui/infowindowcomponent.cpp b/src/blackgui/infowindowcomponent.cpp deleted file mode 100644 index a61baecb8..000000000 --- a/src/blackgui/infowindowcomponent.cpp +++ /dev/null @@ -1,138 +0,0 @@ -#include "infowindowcomponent.h" -#include "ui_infowindowcomponent.h" - -#include -#include - -using namespace BlackMisc; -using namespace BlackMisc::Network; - -namespace BlackGui -{ - - /* - * Constructor - */ - CInfoWindowComponent::CInfoWindowComponent(QWidget *parent) : - QWizardPage(parent), ui(new Ui::InfoWindow), m_hideTimer(nullptr) - { - ui->setupUi(this); - this->hide(); - this->m_hideTimer = new QTimer(this); - this->m_hideTimer->setSingleShot(true); - connect(this->m_hideTimer, &QTimer::timeout, this, &CInfoWindowComponent::hide); - connect(this->ui->pb_Close, &QPushButton::pressed, this, &CInfoWindowComponent::hide); - } - - /* - * Destructor - */ - CInfoWindowComponent::~CInfoWindowComponent() { } - - /* - * Info message for some time - */ - void CInfoWindowComponent::displayStringMessage(const QString &message, int displayTimeMs) - { - if (message.isEmpty()) - { - this->hide(); - return; - } - - // message and display - this->ui->te_StringMessage->setText(message); - this->setCurrentPage(this->ui->pg_StringMessage); - this->showWindow(displayTimeMs); - } - - /* - * Info message for some time - */ - void CInfoWindowComponent::displayTextMessage(const CTextMessage &textMessage, int displayTimeMs) - { - if (textMessage.isEmpty()) - { - this->hide(); - return; - } - - // message and display - this->ui->le_TmFrom->setText(textMessage.getSenderCallsign().asString()); - this->ui->le_TmTo->setText(textMessage.getRecipientCallsign().asString()); - this->ui->le_TmReceived->setText(textMessage.receivedTime()); - this->ui->te_TmText->setText(textMessage.getMessage()); - - this->setCurrentPage(this->ui->pg_TextMessage); - this->showWindow(displayTimeMs); - } - - /* - * Display status message - */ - void CInfoWindowComponent::displayStatusMessage(const CStatusMessage &statusMessage, int displayTimeMs) - { - if (statusMessage.isEmpty()) - { - this->hide(); - return; - } - - this->ui->le_SmSeverity->setText(statusMessage.getSeverityAsString()); - this->ui->le_SmType->setText(statusMessage.getTypeAsString()); - this->ui->te_SmStatusMessage->setText(statusMessage.getMessage()); - this->ui->lbl_SmSeverityIcon->setPixmap(statusMessage.toIcon()); - - this->setCurrentPage(this->ui->pg_StatusMessage); - this->showWindow(displayTimeMs); - } - - /* - * Display - */ - void CInfoWindowComponent::display(const BlackMisc::CVariant &variant, int displayTimeMs) - { - if (variant.isNull()) return; - if (variant.canConvert()) - this->displayTextMessage(variant.value(), displayTimeMs); - else if (variant.canConvert()) - this->displayStatusMessage(variant.value(), displayTimeMs); - else - this->displayStringMessage(variant.toString(), displayTimeMs); - } - - /* - * Init this window - */ - void CInfoWindowComponent::initWindow() - { - // center - const QRect parent = this->parentWidget()->geometry(); - const QRect myself = this->rect(); - int dx = (parent.width() - myself.width()) / 2; - int dy = (parent.height() - myself.height()) / 2; - dy -= 80; // some offset, in order to display further on top - this->move(dx, dy); - this->show(); - } - - /* - * Show window - */ - void CInfoWindowComponent::showWindow(int displayTimeMs) - { - this->initWindow(); - - // hide after some time - this->m_hideTimer->start(displayTimeMs); - } - - /* - * Set current widget - */ - void CInfoWindowComponent::setCurrentPage(QWidget *widget) - { - this->ui->sw_DifferentModes->setCurrentWidget(widget); - } - -} // namespace diff --git a/src/blackgui/infowindowcomponent.h b/src/blackgui/infowindowcomponent.h deleted file mode 100644 index cbeecca5d..000000000 --- a/src/blackgui/infowindowcomponent.h +++ /dev/null @@ -1,66 +0,0 @@ -/* Copyright (C) 2013 VATSIM Community / authors - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef BLACKGUI_INFOWINDOW_H -#define BLACKGUI_INFOWINDOW_H - -#include "blackmisc/nwtextmessage.h" -#include "blackmisc/statusmessage.h" -#include "blackmisc/variant.h" - -#include -#include - -namespace Ui { class InfoWindow; } - -namespace BlackGui -{ - - /*! - * Multi purpose info window (pop up window) - */ - class CInfoWindowComponent : public QWizardPage - { - Q_OBJECT - - public: - const static int DefaultDisplayTimeMs = 4000; //!< Display n milliseconds - - //! Constructor - explicit CInfoWindowComponent(QWidget *parent = nullptr); - - //! Destructor - ~CInfoWindowComponent(); - - public slots: - - //! Info message, pure string - void displayStringMessage(const QString &message, int displayTimeMs = DefaultDisplayTimeMs); - - //! Info message, based on text message - void displayTextMessage(const BlackMisc::Network::CTextMessage &textMessage, int displayTimeMs = DefaultDisplayTimeMs); - - //! Info message, based on status message - void displayStatusMessage(const BlackMisc::CStatusMessage &statusMessage, int displayTimeMs = DefaultDisplayTimeMs); - - //! Display any of the specialized types - void display(const BlackMisc::CVariant &variant, int displayTimeMs = DefaultDisplayTimeMs); - - private: - QScopedPointer ui; //!< user interface - QTimer *m_hideTimer; - - //! Init the window - void initWindow(); - - //! Show window, hide after some time - void showWindow(int displayTimeMs); - - //! Current page - void setCurrentPage(QWidget *widget); - }; -} - -#endif // guard diff --git a/src/blackgui/runtimebasedcomponent.cpp b/src/blackgui/runtimebasedcomponent.cpp deleted file mode 100644 index fbd32dad5..000000000 --- a/src/blackgui/runtimebasedcomponent.cpp +++ /dev/null @@ -1,124 +0,0 @@ -#include "runtimebasedcomponent.h" -#include - -namespace BlackGui -{ - - void CRuntimeBasedComponent::setRuntime(BlackCore::CRuntime *runtime, bool runtimeOwner) - { - Q_ASSERT(runtime); - this->m_runtime = runtime; - this->m_runtimeOwner = runtimeOwner; - this->runtimeHasBeenSet(); - } - - void CRuntimeBasedComponent::setRuntimeForComponents(BlackCore::CRuntime *runtime, QWidget *parent) - { - if (!parent) return; - - // tested for runtime, not too slow, only some ms - QList children = parent->findChildren(); - foreach(QWidget * widget, children) - { - if (widget->objectName().isEmpty()) continue; // rule out unamed widgets - CRuntimeBasedComponent *rbc = dynamic_cast(widget); - if (rbc) rbc->setRuntime(runtime, false); - } - } - - void CRuntimeBasedComponent::createRuntime(const BlackCore::CRuntimeConfig &config, QObject *parent) - { - this->m_runtime = new BlackCore::CRuntime(config, parent); - this->m_runtimeOwner = true; - } - - void CRuntimeBasedComponent::sendStatusMessage(const BlackMisc::CStatusMessage &statusMessage) - { - if (!this->getIContextApplication()) return; - this->getIContextApplication()->sendStatusMessage(statusMessage); - } - - void CRuntimeBasedComponent::sendStatusMessages(const BlackMisc::CStatusMessageList &statusMessages) - { - if (!this->getIContextApplication()) return; - this->getIContextApplication()->sendStatusMessages(statusMessages); - } - - const BlackCore::IContextApplication *CRuntimeBasedComponent::getIContextApplication() const - { - if (!this->m_runtime) return nullptr; - return this->m_runtime->getIContextApplication(); - } - - BlackCore::IContextApplication *CRuntimeBasedComponent::getIContextApplication() - { - if (!this->m_runtime) return nullptr; - return this->m_runtime->getIContextApplication(); - } - - BlackCore::IContextAudio *CRuntimeBasedComponent::getIContextAudio() - { - if (!this->m_runtime) return nullptr; - return this->m_runtime->getIContextAudio(); - } - - const BlackCore::IContextAudio *CRuntimeBasedComponent::getIContextAudio() const - { - if (!this->m_runtime) return nullptr; - return this->m_runtime->getIContextAudio(); - } - - BlackCore::IContextNetwork *CRuntimeBasedComponent::getIContextNetwork() - { - if (!this->m_runtime) return nullptr; - return this->m_runtime->getIContextNetwork(); - } - - const BlackCore::IContextNetwork *CRuntimeBasedComponent::getIContextNetwork() const - { - if (!this->m_runtime) return nullptr; - return this->m_runtime->getIContextNetwork(); - } - - BlackCore::IContextOwnAircraft *CRuntimeBasedComponent::getIContextOwnAircraft() - { - if (!this->m_runtime) return nullptr; - return this->m_runtime->getIContextOwnAircraft(); - } - - const BlackCore::IContextOwnAircraft *CRuntimeBasedComponent::getIContextOwnAircraft() const - { - if (!this->m_runtime) return nullptr; - return this->m_runtime->getIContextOwnAircraft(); - } - - BlackCore::IContextSettings *CRuntimeBasedComponent::getIContextSettings() - { - if (!this->m_runtime) return nullptr; - return this->m_runtime->getIContextSettings(); - } - - const BlackCore::IContextSettings *CRuntimeBasedComponent::getIContextSettings() const - { - if (!this->m_runtime) return nullptr; - return this->m_runtime->getIContextSettings(); - } - - const BlackCore::IContextSimulator *CRuntimeBasedComponent::getIContextSimulator() const - { - if (!this->m_runtime) return nullptr; - return this->m_runtime->getIContextSimulator(); - } - - BlackCore::IContextSimulator *CRuntimeBasedComponent::getIContextSimulator() - { - if (!this->m_runtime) return nullptr; - return this->m_runtime->getIContextSimulator(); - } - - void CRuntimeBasedComponent::playNotifcationSound(BlackSound::CNotificationSounds::Notification notification) const - { - if (!this->getIContextAudio()) return; - this->getIContextAudio()->playNotification(static_cast(notification), true); - } -} diff --git a/src/blackgui/runtimebasedcomponent.h b/src/blackgui/runtimebasedcomponent.h deleted file mode 100644 index 6bacf61e8..000000000 --- a/src/blackgui/runtimebasedcomponent.h +++ /dev/null @@ -1,108 +0,0 @@ -#ifndef BLACKGUI_RUNTIMEBASEDCOMPONENT_H -#define BLACKGUI_RUNTIMEBASEDCOMPONENT_H - -#include "blackcore/context_runtime.h" -#include "blackcore/context_all_interfaces.h" -#include "blackmisc/notificationsounds.h" -#include - -namespace BlackGui -{ - /*! - * \brief Component, which provides reference to runtime object - * \details Access to runtime allows to encapsualate many aspects of data access and makes - * the component widely independent from a central data provideer - * \sa BlackCore::CRuntime - */ - class CRuntimeBasedComponent - { - public: - //! Set runtime, usually set by runtime owner (must only be one, usually main window) - void setRuntime(BlackCore::CRuntime *runtime, bool runtimeOwner = false); - - //! Set runtime for each CRuntimeBasedComponent - static void setRuntimeForComponents(BlackCore::CRuntime *runtime, QWidget *parent); - - protected: - //! Constructor - //! \remarks Usually runtime will be provided later, not at initialization time. - //! If runtime is provided right now, make sure to call runtimeHasBeenSet afterwards - CRuntimeBasedComponent(BlackCore::CRuntime *runtime = nullptr, bool runtimeOwner = false) : - m_runtime(runtime), m_runtimeOwner(runtimeOwner) - {} - - //! Runtime const - const BlackCore::CRuntime *getRuntime() const { return this->m_runtime;} - - //! Runtime non const - BlackCore::CRuntime *getRuntime() { return this->m_runtime;} - - //! Create a runtime (becomes owner). Only create one runtime. - void createRuntime(const BlackCore::CRuntimeConfig &config, QObject *parent); - - //! Context for application - const BlackCore::IContextApplication *getIContextApplication() const; - - //! Context for application - BlackCore::IContextApplication *getIContextApplication(); - - //! Context for audio - BlackCore::IContextAudio *getIContextAudio(); - - //! Context for audio - const BlackCore::IContextAudio *getIContextAudio() const; - - //! Context for network - BlackCore::IContextNetwork *getIContextNetwork(); - - //! Context for network - const BlackCore::IContextNetwork *getIContextNetwork() const; - - //! Context for own aircraft - const BlackCore::IContextOwnAircraft *getIContextOwnAircraft() const; - - //! Context for own aircraft - BlackCore::IContextOwnAircraft *getIContextOwnAircraft(); - - //! Context for settings - BlackCore::IContextSettings *getIContextSettings(); - - //! Context for settings - const BlackCore::IContextSettings *getIContextSettings() const; - - //! Context for simulator - const BlackCore::IContextSimulator *getIContextSimulator() const; - - //! Context for simulator - BlackCore::IContextSimulator *getIContextSimulator(); - - //! Send status message (via application context) - void sendStatusMessage(const BlackMisc::CStatusMessage &statusMessage); - - //! Send status message (via application context) - void sendStatusMessages(const BlackMisc::CStatusMessageList &statusMessages); - - //! Owner? - bool isRuntimeOwner() const { return this->m_runtimeOwner; } - - //! "Callback" when runtime is initialized, done this way as we do not have signals/slots here - //! \remarks use this methods to hook up signal/slots with runtime - virtual void runtimeHasBeenSet() {} - - //! \copydoc CRuntime::hasRemoteApplicationContext - bool hasRemoteApplicationContext() const { return this->m_runtime->hasRemoteApplicationContext(); } - - //! \copydoc CRuntime::canPingApplicationContext - bool canPingApplicationContext() const { return this->m_runtime->canPingApplicationContext(); } - - //! Play a given notification sound - void playNotifcationSound(BlackSound::CNotificationSounds::Notification notification) const; - - private: - BlackCore::CRuntime *m_runtime; - bool m_runtimeOwner; - }; - -} // namespace - -#endif // guard diff --git a/src/blackgui/settingscomponent.cpp b/src/blackgui/settingscomponent.cpp deleted file mode 100644 index 921e00615..000000000 --- a/src/blackgui/settingscomponent.cpp +++ /dev/null @@ -1,405 +0,0 @@ -#include "settingscomponent.h" -#include "ui_settingscomponent.h" -#include "blackgui/atcstationlistmodel.h" -#include "blackcore/dbus_server.h" -#include "blackcore/context_network.h" -#include "blackmisc/hwkeyboardkeylist.h" -#include "blackmisc/setaudio.h" - -using namespace BlackCore; -using namespace BlackMisc; -using namespace BlackGui; -using namespace BlackMisc::Network; -using namespace BlackMisc::Aviation; -using namespace BlackMisc::Audio; -using namespace BlackMisc::PhysicalQuantities; -using namespace BlackMisc::Geo; -using namespace BlackMisc::Settings; -using namespace BlackMisc::Hardware; - -namespace BlackGui -{ - - CSettingsComponent::CSettingsComponent(QWidget *parent) : - QTabWidget(parent), CRuntimeBasedComponent(nullptr, false), ui(new Ui::CSettingsComponent), - m_audioTestRunning(NoAudioTest) - { - ui->setupUi(this); - this->ui->prb_SettingsAudioTestProgress->setVisible(false); - this->m_timerAudioTests = new QTimer(this); - } - - CSettingsComponent::~CSettingsComponent() - { - delete ui; - } - - /* - * Update own ICAO data from GUI - */ - void CSettingsComponent::setOwnAircraftIcaoDataFromGui(CAircraftIcao &icao) const - { - icao.setAirlineDesignator(this->ui->le_SettingsIcaoAirlineDesignator->text()); - icao.setAircraftDesignator(this->ui->le_SettingsIcaoAircraftDesignator->text()); - icao.setAircraftCombinedType(this->ui->le_SettingsIcaoCombinedType->text()); - } - - void CSettingsComponent::setGuiOpacity(double value) - { - this->ui->hs_SettingsGuiOpacity->setValue(value); - } - - bool CSettingsComponent::loginAsObserver() const - { - return this->ui->rb_SettingsLoginStealthMode->isChecked(); - } - - bool CSettingsComponent::loginStealth() const - { - return this->ui->rb_SettingsLoginStealthMode->isChecked(); - } - - bool CSettingsComponent::playNotificationSounds() const - { - return this->ui->cb_SettingsAudioPlayNotificationSounds->isChecked(); - } - - int CSettingsComponent::getAtcUpdateIntervalSeconds() const - { - return this->ui->hs_SettingsGuiAtcRefreshTime->value(); - } - - int CSettingsComponent::getAircraftUpdateIntervalSeconds() const - { - return this->ui->hs_SettingsGuiAircraftRefreshTime->value(); - } - - int CSettingsComponent::getUsersUpdateIntervalSeconds() const - { - return this->ui->hs_SettingsGuiUserRefreshTime->value(); - } - - QString CSettingsComponent::getOwnCallsignFromGui() const - { - return this->ui->le_SettingsAircraftCallsign->text(); - } - - /* - * Reload settings - */ - void CSettingsComponent::reloadSettings() - { - // local copy - CSettingsNetwork nws = this->getIContextSettings()->getNetworkSettings(); - CSettingsAudio as = this->getIContextSettings()->getAudioSettings(); - - // update servers - this->ui->tvp_SettingsTnServers->setSelectedServer(nws.getCurrentTrafficNetworkServer()); - this->ui->tvp_SettingsTnServers->update(nws.getTrafficNetworkServers()); - - // update hot keys - this->ui->tvp_SettingsMiscHotkeys->update(this->getIContextSettings()->getHotkeys()); - - // fake setting for sound notifications - this->ui->cb_SettingsAudioPlayNotificationSounds->setChecked(true); - this->ui->cb_SettingsAudioNotificationTextMessage->setChecked(as.getNotificationFlag(BlackSound::CNotificationSounds::NotificationTextMessagePrivate)); - this->ui->cb_SettingsAudioNotificationVoiceRoom->setChecked(as.getNotificationFlag(BlackSound::CNotificationSounds::NotificationVoiceRoomJoined)); - } - - void CSettingsComponent::runtimeHasBeenSet() - { - if (!this->getIContextSettings()) qFatal("Settings missing"); - - this->connect(this->getIContextSettings(), &IContextSettings::changedSettings, this, &CSettingsComponent::changedSettings); - this->connect(this->m_timerAudioTests, &QTimer::timeout, this, &CSettingsComponent::audioTestUpdate); - - // based on audio context - Q_ASSERT(this->getIContextAudio()); - if (this->getIContextAudio()) - { - this->initAudioDeviceLists(); - bool connected = this->connect(this->getIContextAudio(), &IContextAudio::audioTestCompleted, this, &CSettingsComponent::audioTestUpdate); - Q_ASSERT(connected); - connected = this->connect(this->ui->cb_SettingsAudioInputDevice, SIGNAL(currentIndexChanged(int)), this, SLOT(audioDeviceSelected(int))); - Q_ASSERT(connected); - connected = this->connect(this->ui->cb_SettingsAudioOutputDevice, SIGNAL(currentIndexChanged(int)), this, SLOT(audioDeviceSelected(int))); - Q_ASSERT(connected); - this->connect(this->ui->pb_SettingsAudioMicrophoneTest, &QPushButton::clicked, this, &CSettingsComponent::startAudioTest); - this->connect(this->ui->pb_SettingsAudioSquelchTest, &QPushButton::clicked, this, &CSettingsComponent::startAudioTest); - } - - // Opacity, intervals - this->connect(this->ui->hs_SettingsGuiOpacity, &QSlider::valueChanged, this, &CSettingsComponent::changedWindowsOpacity); - this->connect(this->ui->hs_SettingsGuiAircraftRefreshTime, &QSlider::valueChanged, this, &CSettingsComponent::changedAircraftsUpdateInterval); - this->connect(this->ui->hs_SettingsGuiAtcRefreshTime, &QSlider::valueChanged, this, &CSettingsComponent::changedAtcStationsUpdateInterval); - this->connect(this->ui->hs_SettingsGuiUserRefreshTime, &QSlider::valueChanged, this, &CSettingsComponent::changedUsersUpdateInterval); - - // Settings server - this->connect(this->ui->pb_SettingsTnCurrentServer, &QPushButton::released, this, &CSettingsComponent::alterTrafficServer); - this->connect(this->ui->pb_SettingsTnRemoveServer, &QPushButton::released, this, &CSettingsComponent::alterTrafficServer); - this->connect(this->ui->pb_SettingsTnSaveServer, &QPushButton::released, this, &CSettingsComponent::alterTrafficServer); - this->connect(this->ui->tvp_SettingsTnServers, &QTableView::clicked, this, &CSettingsComponent::networkServerSelected); - - // Settings hotkeys - this->connect(this->ui->pb_SettingsMiscCancel, &QPushButton::clicked, this, &CSettingsComponent::reloadSettings); - this->connect(this->ui->pb_SettingsMiscSave, &QPushButton::clicked, this, &CSettingsComponent::saveHotkeys); - this->connect(this->ui->pb_SettingsMiscRemove, &QPushButton::clicked, this, &CSettingsComponent::clearHotkey); - } - - /* - * Network has been selected - */ - void CSettingsComponent::networkServerSelected(QModelIndex index) - { - const CServer clickedServer = this->ui->tvp_SettingsTnServers->at(index); - this->updateGuiSelectedServerTextboxes(clickedServer); - } - - /* - * Alter server - */ - void CSettingsComponent::alterTrafficServer() - { - CServer server = this->selectedServerFromTextboxes(); - if (!server.isValidForLogin()) - { - const CStatusMessage validation = CStatusMessage::getValidationError("Wrong settings for server"); - this->sendStatusMessage(validation); - return; - } - - const QString path = CSettingUtilities::appendPaths(IContextSettings::PathNetworkSettings(), CSettingsNetwork::ValueTrafficServers()); - QObject *sender = QObject::sender(); - CStatusMessageList msgs; - if (sender == this->ui->pb_SettingsTnCurrentServer) - { - msgs = this->getIContextSettings()->value(path, CSettingsNetwork::CmdSetCurrentServer(), server.toQVariant()); - } - else if (sender == this->ui->pb_SettingsTnRemoveServer) - { - msgs = this->getIContextSettings()->value(path, CSettingUtilities::CmdRemove(), server.toQVariant()); - } - else if (sender == this->ui->pb_SettingsTnSaveServer) - { - msgs = this->getIContextSettings()->value(path, CSettingUtilities::CmdUpdate(), server.toQVariant()); - } - - // status messages - this->sendStatusMessages(msgs); - } - - /* - * Settings did changed - */ - void CSettingsComponent::changedSettings(uint typeValue) - { - IContextSettings::SettingsType type = static_cast(typeValue); - this->reloadSettings(); - Q_UNUSED(type); - } - - /* - * Textboxes from server - */ - void CSettingsComponent::updateGuiSelectedServerTextboxes(const CServer &server) - { - this->ui->le_SettingsTnCsName->setText(server.getName()); - this->ui->le_SettingsTnCsDescription->setText(server.getDescription()); - this->ui->le_SettingsTnCsAddress->setText(server.getAddress()); - this->ui->le_SettingsTnCsPort->setText(QString::number(server.getPort())); - this->ui->le_SettingsTnCsRealName->setText(server.getUser().getRealName()); - this->ui->le_SettingsTnCsNetworkId->setText(server.getUser().getId()); - this->ui->le_SettingsTnCsPassword->setText(server.getUser().getPassword()); - } - - /* - * Server settings from textboxes - */ - CServer CSettingsComponent::selectedServerFromTextboxes() const - { - CServer server; - bool portOk = false; - server.setName(this->ui->le_SettingsTnCsName->text()); - server.setDescription(this->ui->le_SettingsTnCsDescription->text()); - server.setAddress(this->ui->le_SettingsTnCsAddress->text()); - server.setPort(this->ui->le_SettingsTnCsPort->text().toInt(&portOk)); - if (!portOk) server.setPort(-1); - - CUser user; - user.setRealName(this->ui->le_SettingsTnCsRealName->text()); - user.setId(this->ui->le_SettingsTnCsNetworkId->text()); - user.setPassword(this->ui->le_SettingsTnCsPassword->text()); - server.setUser(user); - - return server; - } - - /* - * Save the hotkeys - */ - void CSettingsComponent::saveHotkeys() - { - const QString path = CSettingUtilities::appendPaths(IContextSettings::PathRoot(), IContextSettings::PathHotkeys()); - CStatusMessageList msgs = this->getIContextSettings()->value(path, CSettingUtilities::CmdUpdate(), this->ui->tvp_SettingsMiscHotkeys->derivedModel()->getContainer().toQVariant()); - - // status messages - this->sendStatusMessages(msgs); - } - - /* - * Clear particular hotkey - */ - void CSettingsComponent::clearHotkey() - { - QModelIndex i = this->ui->tvp_SettingsMiscHotkeys->currentIndex(); - if (i.row() < 0 || i.row() >= this->ui->tvp_SettingsMiscHotkeys->rowCount()) return; - BlackMisc::Hardware::CKeyboardKey key = this->ui->tvp_SettingsMiscHotkeys->at(i); - BlackMisc::Hardware::CKeyboardKey defaultKey; - defaultKey.setFunction(key.getFunction()); - this->ui->tvp_SettingsMiscHotkeys->derivedModel()->update(i, defaultKey); - } - - /* - * Set audio device lists - */ - void CSettingsComponent::initAudioDeviceLists() - { - if (!this->getIContextAudio()) return; - this->ui->cb_SettingsAudioOutputDevice->clear(); - this->ui->cb_SettingsAudioInputDevice->clear(); - - foreach(CAudioDevice device, this->getIContextAudio()->getAudioDevices()) - { - if (device.getType() == CAudioDevice::InputDevice) - { - this->ui->cb_SettingsAudioInputDevice->addItem(device.toQString(true)); - } - else if (device.getType() == CAudioDevice::OutputDevice) - { - this->ui->cb_SettingsAudioOutputDevice->addItem(device.toQString(true)); - } - } - - foreach(CAudioDevice device, this->getIContextAudio()->getCurrentAudioDevices()) - { - if (device.getType() == CAudioDevice::InputDevice) - { - this->ui->cb_SettingsAudioInputDevice->setCurrentText(device.toQString(true)); - } - else if (device.getType() == CAudioDevice::OutputDevice) - { - this->ui->cb_SettingsAudioOutputDevice->setCurrentText(device.toQString(true)); - } - } - } - - /* - * Start the voice tests - */ - void CSettingsComponent::startAudioTest() - { - if (!this->getIContextAudio()) - { - CStatusMessage m(CStatusMessage::TypeAudio, CStatusMessage::SeverityError, "voice context not available"); - this->sendStatusMessage(m); - return; - } - if (this->m_timerAudioTests->isActive()) - { - CStatusMessage m(CStatusMessage::TypeAudio, CStatusMessage::SeverityError, "test running, wait until completed"); - this->sendStatusMessage(m); - return; - } - - QObject *sender = QObject::sender(); - this->m_timerAudioTests->start(600); // I let this run for ms, so there is enough overhead to really complete it - this->ui->prb_SettingsAudioTestProgress->setValue(0); - this->ui->pte_SettingsAudioTestActionAndResult->clear(); - if (sender == this->ui->pb_SettingsAudioMicrophoneTest) - { - this->m_audioTestRunning = MicrophoneTest; - this->getIContextAudio()->runMicrophoneTest(); - this->ui->pte_SettingsAudioTestActionAndResult->appendPlainText("Speak normally for 5 seconds"); - } - else if (sender == this->ui->pb_SettingsAudioSquelchTest) - { - this->m_audioTestRunning = SquelchTest; - this->getIContextAudio()->runSquelchTest(); - this->ui->pte_SettingsAudioTestActionAndResult->appendPlainText("Silence for 5 seconds"); - } - this->ui->prb_SettingsAudioTestProgress->setVisible(true); - this->ui->pb_SettingsAudioMicrophoneTest->setEnabled(false); - this->ui->pb_SettingsAudioSquelchTest->setEnabled(false); - } - - /* - * Start the voice tests - */ - void CSettingsComponent::audioTestUpdate() - { - Q_ASSERT(this->getIContextAudio()); - if (!this->getIContextAudio()) return; - int v = this->ui->prb_SettingsAudioTestProgress->value(); - QObject *sender = this->sender(); - - if (v < 100 && (sender == m_timerAudioTests)) - { - // timer update, increasing progress - this->ui->prb_SettingsAudioTestProgress->setValue(v + 10); - } - else - { - this->m_timerAudioTests->stop(); - this->ui->prb_SettingsAudioTestProgress->setValue(100); - if (sender == m_timerAudioTests) return; // just timer update - - // getting here we assume the audio test finished signal - // fetch results - this->ui->pte_SettingsAudioTestActionAndResult->clear(); - if (this->m_audioTestRunning == SquelchTest) - { - double s = this->getIContextAudio()->getSquelchValue(); - this->ui->pte_SettingsAudioTestActionAndResult->appendPlainText(QString::number(s)); - } - else if (this->m_audioTestRunning == MicrophoneTest) - { - QString m = this->getIContextAudio()->getMicrophoneTestResult(); - this->ui->pte_SettingsAudioTestActionAndResult->appendPlainText(m); - } - this->m_audioTestRunning = NoAudioTest; - this->m_timerAudioTests->stop(); - this->ui->pb_SettingsAudioMicrophoneTest->setEnabled(true); - this->ui->pb_SettingsAudioSquelchTest->setEnabled(true); - this->ui->prb_SettingsAudioTestProgress->setVisible(false); - } - } - - /* - * Select audio device - */ - void CSettingsComponent::audioDeviceSelected(int index) - { - if (!this->getIContextAudio()) return; - if (index < 0)return; - - CAudioDeviceList devices = this->getIContextAudio()->getAudioDevices(); - if (devices.isEmpty()) return; - CAudioDevice selectedDevice; - QObject *sender = QObject::sender(); - if (sender == this->ui->cb_SettingsAudioInputDevice) - { - CAudioDeviceList inputDevices = devices.getInputDevices(); - if (index >= inputDevices.size()) return; - selectedDevice = inputDevices[index]; - this->getIContextAudio()->setCurrentAudioDevice(selectedDevice); - } - else if (sender == this->ui->cb_SettingsAudioOutputDevice) - { - CAudioDeviceList outputDevices = devices.getOutputDevices(); - if (index >= outputDevices.size()) return; - selectedDevice = outputDevices[index]; - this->getIContextAudio()->setCurrentAudioDevice(selectedDevice); - } - } - -} // namespace diff --git a/src/blackgui/settingscomponent.h b/src/blackgui/settingscomponent.h deleted file mode 100644 index 246d3cb61..000000000 --- a/src/blackgui/settingscomponent.h +++ /dev/null @@ -1,130 +0,0 @@ -#ifndef BLACKGUI_SETTINGSCOMPONENT_H -#define BLACKGUI_SETTINGSCOMPONENT_H - -#include "blackgui/runtimebasedcomponent.h" -#include -#include -#include - - -namespace Ui { class CSettingsComponent; } - -namespace BlackGui -{ - //! Settings component - class CSettingsComponent : public QTabWidget, public CRuntimeBasedComponent - { - Q_OBJECT - - public: - //! Constructor - explicit CSettingsComponent(QWidget *parent = nullptr); - - //! Destructor - ~CSettingsComponent(); - - //! ICAO data from GUI - void setOwnAircraftIcaoDataFromGui(BlackMisc::Aviation::CAircraftIcao &icao) const; - - //! GUI Opacity 0-100% - void setGuiOpacity(double value); - - //! Login as observer - bool loginAsObserver() const; - - //! Login as observer - bool loginStealth() const; - - //! Play notification sounds (at all) - bool playNotificationSounds() const; - - //! ATC refresh time - int getAtcUpdateIntervalSeconds() const; - - //! Aircraft refresh time - int getAircraftUpdateIntervalSeconds() const; - - //! Aircraft refresh time - int getUsersUpdateIntervalSeconds() const; - - //! Own callsign - QString getOwnCallsignFromGui() const; - - signals: - //! Change the windows opacity 0..100 - void changedWindowsOpacity(int opacity); - - //! Update interval changed (ATC) - void changedAtcStationsUpdateInterval(int seconds); - - //! Update interval changed (aircrafts) - void changedAircraftsUpdateInterval(int seconds); - - //! Update interval changed (users) - void changedUsersUpdateInterval(int seconds); - - public slots: - //! Reload settings - void reloadSettings(); - - protected: - //! \copydoc CRuntimeBasedComponent::runtimeHasBeenSet - virtual void runtimeHasBeenSet() override; - - private slots: - - //! Network server selected - void networkServerSelected(QModelIndex index); - - //! Alter traffic server - void alterTrafficServer(); - - /*! - * \brief Update the selected server textboxes - * \param server to be displayed - */ - void updateGuiSelectedServerTextboxes(const BlackMisc::Network::CServer &server); - - //! Selected server from textboxes - BlackMisc::Network::CServer selectedServerFromTextboxes() const; - - //! Settings have been changed - void changedSettings(uint typeValue); - - //! Save the Hotkeys - void saveHotkeys(); - - //! Clear single hotkey - void clearHotkey(); - - //! start the MIC tests (Squelch) - void startAudioTest(); - - //! Audio test updates (timer) for progressbar and fetching results - void audioTestUpdate(); - - /*! - * \brief Audio device selected - * \param index audio device index (COM1, COM2) - */ - void audioDeviceSelected(int index); - - private: - //! Audio test modes - enum AudioTest - { - NoAudioTest, - SquelchTest, - MicrophoneTest - }; - - Ui::CSettingsComponent *ui; - QTimer *m_timerAudioTests; //!< audio tests: progress bar, disable/enable buttons - AudioTest m_audioTestRunning; - - //! Audio device lists from settings - void initAudioDeviceLists(); - }; -} // namespace - -#endif // guard diff --git a/src/blackgui/settingsfsxcomponent.cpp b/src/blackgui/settingsfsxcomponent.cpp deleted file mode 100644 index 8451d27dd..000000000 --- a/src/blackgui/settingsfsxcomponent.cpp +++ /dev/null @@ -1,176 +0,0 @@ -#include "settingsfsxcomponent.h" -#include "ui_settingsfsxcomponent.h" -#include -#include -#include -#include - -#include "blackmisc/networkutils.h" -#include "blackmisc/statusmessage.h" -#include "blacksim/fsx/fsxsimulatorsetup.h" -#include "blacksim/fsx/simconnectutilities.h" - -using namespace BlackMisc; -using namespace BlackSim::Fsx; -using namespace BlackMisc::Network; - -namespace BlackGui -{ - - CSettingsFsxComponent::CSettingsFsxComponent(QWidget *parent) : - QFrame(parent), CRuntimeBasedComponent(nullptr, false), ui(new Ui::CSettingsFsxComponent) - { - ui->setupUi(this); - - this->connect(this->ui->pb_SettingsFsxTestConnection, &QPushButton::clicked, this, &CSettingsFsxComponent::testSimConnectConnection); - this->connect(this->ui->pb_SettingsFsxSaveSimconnectCfg, &QPushButton::clicked, this, &CSettingsFsxComponent::saveSimConnectCfg); - this->connect(this->ui->pb_SettingsFsxOpenSimconnectCfg, &QPushButton::clicked, this, &CSettingsFsxComponent::simConnectCfgFile); - this->connect(this->ui->pb_SettingsFsxDeleteSimconnectCfg, &QPushButton::clicked, this, &CSettingsFsxComponent::simConnectCfgFile); - this->connect(this->ui->pb_SettingsFsxExistsSimconncetCfg, &QPushButton::clicked, this, &CSettingsFsxComponent::simConnectCfgFile); - - } - - CSettingsFsxComponent::~CSettingsFsxComponent() - { - delete ui; - } - - /* - * SimConnect working? - */ - void CSettingsFsxComponent::testSimConnectConnection() - { - QString address = this->ui->le_SettingsFsxAddress->text().trimmed(); - QString port = this->ui->le_SettingsFsxPort->text().trimmed(); - - if (address.isEmpty() || port.isEmpty()) - { - this->sendStatusMessage(CStatusMessage(CStatusMessage::TypeTrafficNetwork, CStatusMessage::SeverityWarning, "no address or port")); - return; - } - if (!CNetworkUtils::isValidIPv4Address(address)) - { - this->sendStatusMessage(CStatusMessage(CStatusMessage::TypeTrafficNetwork, CStatusMessage::SeverityWarning, "IPv4 address invalid")); - return; - } - if (!CNetworkUtils::isValidPort(port)) - { - this->sendStatusMessage(CStatusMessage(CStatusMessage::TypeTrafficNetwork, CStatusMessage::SeverityWarning, "invalid port")); - return; - } - quint16 p = port.toUInt(); - QString msg; - if (!CNetworkUtils::canConnect(address, p, msg)) - { - this->sendStatusMessage(CStatusMessage(CStatusMessage::TypeTrafficNetwork, CStatusMessage::SeverityWarning, msg)); - return; - } - - msg = QString("Connected to %1:%2").arg(address).arg(port); - this->sendStatusMessage(CStatusMessage(CStatusMessage::TypeTrafficNetwork, CStatusMessage::SeverityInfo, msg)); - } - - /* - * Save simconnect.cfg - */ - void CSettingsFsxComponent::saveSimConnectCfg() - { - if (!this->getIContextSimulator() || !this->getIContextSimulator()->isSimulatorAvailable()) - { - this->sendStatusMessage(CStatusMessage::getErrorMessage("Simulator not available", CStatusMessage::TypeSimulator)); - return; - } - QString address = this->ui->le_SettingsFsxAddress->text().trimmed(); - QString port = this->ui->le_SettingsFsxPort->text().trimmed(); - - if (address.isEmpty() || port.isEmpty()) - { - this->sendStatusMessage(CStatusMessage(CStatusMessage::TypeTrafficNetwork, CStatusMessage::SeverityWarning, "no address or port")); - return; - } - if (!CNetworkUtils::isValidIPv4Address(address)) - { - this->sendStatusMessage(CStatusMessage(CStatusMessage::TypeTrafficNetwork, CStatusMessage::SeverityWarning, "IPv4 address invalid")); - return; - } - if (!CNetworkUtils::isValidPort(port)) - { - this->sendStatusMessage(CStatusMessage(CStatusMessage::TypeTrafficNetwork, CStatusMessage::SeverityWarning, "invalid port")); - return; - } - quint16 p = port.toUInt(); - QString fileName = this->getIContextSimulator()->getSimulatorInfo().getSimulatorSetupValueAsString(CFsxSimulatorSetup::SetupSimConnectCfgFile); - Q_ASSERT(!fileName.isEmpty()); - // write either local or remote file - bool local = this->getIContextSimulator()->usingLocalObjects(); - bool success = local ? - BlackSim::Fsx::CSimConnectUtilities::writeSimConnectCfg(fileName, address, p) : - this->getIContextApplication()->writeToFile(fileName, CSimConnectUtilities::simConnectCfg(address, p)); - if (success) - { - QString m = QString("Written ").append(local ? " local " : "remote ").append(fileName); - this->sendStatusMessage(CStatusMessage(CStatusMessage::TypeTrafficNetwork, CStatusMessage::SeverityInfo, m)); - } - else - { - QString m = QString("Cannot write ").append(fileName); - this->sendStatusMessage(CStatusMessage(CStatusMessage::TypeTrafficNetwork, CStatusMessage::SeverityError, m)); - } - this->ui->pb_SettingsFsxExistsSimconncetCfg->click(); // update status - } - - /* - * simconnect.cfg: open, delete, exists? - */ - void CSettingsFsxComponent::simConnectCfgFile() - { - if (!this->getIContextSimulator() || !this->getIContextSimulator()->isSimulatorAvailable()) - { - this->sendStatusMessage(CStatusMessage::getErrorMessage("Simulator not available", CStatusMessage::TypeSimulator)); - return; - } - - QObject *sender = QObject::sender(); - if (sender == this->ui->pb_SettingsFsxOpenSimconnectCfg) - { - QFileInfo fi(CSimConnectUtilities::getLocalSimConnectCfgFilename()); - QString path = QDir::toNativeSeparators(fi.absolutePath()); - QDesktopServices::openUrl(QUrl("file:///" + path)); - } - else if (sender == this->ui->pb_SettingsFsxDeleteSimconnectCfg) - { - if (!this->getIContextSimulator()) return; - QString fileName = BlackSim::Fsx::CSimConnectUtilities::getLocalSimConnectCfgFilename(); - QString m = QString("Deleted %1 ").append(fileName); - if (this->getIContextSimulator()->usingLocalObjects()) - { - QFile f(fileName); - f.remove(); - m = m.arg("locally"); - } - else - { - this->getIContextApplication()->removeFile(fileName); - m = m.arg("remotely"); - } - this->sendStatusMessage(CStatusMessage(CStatusMessage::TypeSimulator, CStatusMessage::SeverityInfo, m)); - this->ui->pb_SettingsFsxExistsSimconncetCfg->click(); // update status - } - else if (sender == this->ui->pb_SettingsFsxExistsSimconncetCfg) - { - if (!this->getIContextSimulator()) return; - QString fileName = BlackSim::Fsx::CSimConnectUtilities::getLocalSimConnectCfgFilename(); - bool exists = this->getIContextSimulator()->usingLocalObjects() ? - QFile::exists(fileName) : - this->getIContextApplication()->existsFile(fileName); - if (exists) - { - this->ui->le_SettingsFsxExistsSimconncetCfg->setText(fileName); - } - else - { - this->ui->le_SettingsFsxExistsSimconncetCfg->setText("no file"); - } - } - } -} diff --git a/src/blackgui/settingsfsxcomponent.h b/src/blackgui/settingsfsxcomponent.h deleted file mode 100644 index 939fd4742..000000000 --- a/src/blackgui/settingsfsxcomponent.h +++ /dev/null @@ -1,41 +0,0 @@ -#ifndef BLACKGUI_SETTINGSFSXCOMPONENT_H -#define BLACKGUI_SETTINGSFSXCOMPONENT_H - -#include "blackgui/runtimebasedcomponent.h" -#include - -namespace Ui { class CSettingsFsxComponent; } - -namespace BlackGui -{ - - /*! - * \brief Settings for FSX - */ - class CSettingsFsxComponent : public QFrame, public CRuntimeBasedComponent - { - Q_OBJECT - - public: - //! Constructor - explicit CSettingsFsxComponent(QWidget *parent = nullptr); - - //! Destructor - ~CSettingsFsxComponent(); - - private slots: - //! Test the SIM connect connectivity - void testSimConnectConnection(); - - //! Save a simconnect.cfg file for FSX - void saveSimConnectCfg(); - - //! simConnect.cfg: open, exists? delete - void simConnectCfgFile(); - - private: - Ui::CSettingsFsxComponent *ui; - }; -} - -#endif // guard diff --git a/src/blackgui/settingssimulatorcomponent.cpp b/src/blackgui/settingssimulatorcomponent.cpp deleted file mode 100644 index 9ca2b5101..000000000 --- a/src/blackgui/settingssimulatorcomponent.cpp +++ /dev/null @@ -1,161 +0,0 @@ -#include "settingssimulatorcomponent.h" -#include "ui_settingssimulatorcomponent.h" - -#include "blackcore/context_settings.h" -#include "blacksim/simulatorinfolist.h" -#include "blacksim/setsimulator.h" -#include "blackmisc/settingutilities.h" - -#include - -using namespace BlackMisc; -using namespace BlackMisc::Settings; -using namespace BlackMisc::PhysicalQuantities; -using namespace BlackSim; -using namespace BlackSim::Settings; -using namespace BlackCore; - -namespace BlackGui -{ - CSettingsSimulatorComponent::CSettingsSimulatorComponent(QWidget *parent) : - QFrame(parent), CRuntimeBasedComponent(nullptr, false), - ui(new Ui::CSettingsSimulatorComponent) - { - ui->setupUi(this); - } - - CSettingsSimulatorComponent::~CSettingsSimulatorComponent() - { - delete ui; - } - - void CSettingsSimulatorComponent::runtimeHasBeenSet() - { - Q_ASSERT(this->getIContextSimulator()); - Q_ASSERT(this->getIContextSettings()); - if (this->getIContextSimulator()) - { - QStringList plugins = this->getIContextSimulator()->getAvailableSimulatorPlugins().toStringList(true); - CSimulatorInfo currentPlugin = this->getIContextSimulator()->getSimulatorInfo(); - this->ui->cb_Plugins->addItems(plugins); - this->setCurrentPlugin(currentPlugin); - - // disable / enable driver specific GUI parts - bool fsxDriver = - this->getIContextSimulator()->getAvailableSimulatorPlugins().supportsSimulator(CSimulatorInfo::FSX()); - this->ui->comp_SettingsSimulatorFsx->setVisible(fsxDriver); - - // time sync - bool timeSynced = this->getIContextSimulator()->isTimeSynchronized(); - this->ui->cb_TimeSync->setChecked(timeSynced); - CTime timeOffset= this->getIContextSimulator()->getTimeSynchronizationOffset(); - this->ui->le_TimeSyncOffset->setText(timeOffset.formattedHrsMin()); - - // only with simulator context set GUI values - bool connected = this->connect(this->ui->cb_Plugins, SIGNAL(currentIndexChanged(int)), this, SLOT(ps_pluginHasChanged(int))); - Q_ASSERT(connected); - Q_UNUSED(connected); - } - - if (this->getIContextSettings()) - { - connect(this->getIContextSettings(), &IContextSettings::changedSettings, this, &CSettingsSimulatorComponent::ps_settingsHaveChanged); - } - - connect(this->ui->cb_TimeSync, &QCheckBox::released, this, &CSettingsSimulatorComponent::ps_guiValueHasChanged); - connect(this->ui->le_TimeSyncOffset, &QLineEdit::returnPressed, this, &CSettingsSimulatorComponent::ps_guiValueHasChanged); - } - - void CSettingsSimulatorComponent::setCurrentPlugin(const CSimulatorInfo &plugin) - { - if (plugin.isUnspecified()) return; - const QString searchFor = plugin.getShortName(); - for (int i = 0; i < this->ui->cb_Plugins->count(); ++i) - { - const QString t = ui->cb_Plugins->itemText(i); - if (t.indexOf(searchFor, 0, Qt::CaseInsensitive) >= 0) - { - if (i == this->ui->cb_Plugins->currentIndex()) return; - this->ui->cb_Plugins->setCurrentIndex(i); - break; - } - } - } - - void CSettingsSimulatorComponent::ps_pluginHasChanged(int index) - { - Q_ASSERT(this->getIContextSimulator()); - Q_ASSERT(this->getIContextSettings()); - if (!this->getIContextSimulator() || !this->getIContextSettings()) return; - - CSimulatorInfoList simDrivers = this->getIContextSimulator()->getAvailableSimulatorPlugins(); - if (simDrivers.isEmpty()) - { - this->sendStatusMessage(CStatusMessage::getErrorMessage("No drivers available", CStatusMessage::TypeSimulator)); - return; - } - if (simDrivers.size() <= index) - { - this->sendStatusMessage(CStatusMessage::getErrorMessage("Wrong driver index", CStatusMessage::TypeSimulator)); - return; - } - - // update - CSimulatorInfo currentDriver = simDrivers[index]; - const QString path = CSettingUtilities::appendPaths(IContextSettings::PathSimulatorSettings(), CSettingsSimulator::ValueSelectedDriver()); - this->sendStatusMessages( - this->getIContextSettings()->value(path, CSettingUtilities::CmdUpdate(), currentDriver.toCVariant()) - ); - } - - void CSettingsSimulatorComponent::ps_settingsHaveChanged(uint settingsType) - { - Q_ASSERT(this->getIContextSettings()); - IContextSettings::SettingsType type = static_cast(settingsType); - if (type != IContextSettings::SettingsSimulator || !this->getIContextSettings()) return; - CSettingsSimulator simSettings = this->getIContextSettings()->getSimulatorSettings(); - - this->setCurrentPlugin(simSettings.getSelectedPlugin()); - this->ui->le_TimeSyncOffset->setText(simSettings.getSyncTimeOffset().formattedHrsMin()); - this->ui->cb_TimeSync->setChecked(simSettings.isTimeSyncEnabled()); - } - - void CSettingsSimulatorComponent::ps_guiValueHasChanged() - { - Q_ASSERT(this->getIContextSettings()); - if (!this->getIContextSettings()) return; - - QObject *sender = QObject::sender(); - if (!sender) return; - - const QString ps = IContextSettings::PathSimulatorSettings(); - CStatusMessageList msgs; - if (sender == this->ui->cb_TimeSync) - { - bool timeSync = this->ui->cb_TimeSync->isChecked(); - msgs = this->getIContextSettings()->value(CSettingUtilities::appendPaths(ps, CSettingsSimulator::ValueSyncTime()), CSettingUtilities::CmdUpdate(), QVariant(timeSync)); - } - else if (sender == this->ui->le_TimeSyncOffset) - { - const QString os = this->ui->le_TimeSyncOffset->text(); - CTime ost(0, CTimeUnit::hrmin()); - if (!os.isEmpty()) - { - ost.parseFromString(os); - } - if (ost.isNull()) - { - msgs.push_back(CStatusMessage::getValidationError("Invalid offset time")); - } - else - { - msgs = this->getIContextSettings()->value(CSettingUtilities::appendPaths(ps, CSettingsSimulator::ValueSyncTimeOffset()), CSettingUtilities::CmdUpdate(), ost.toQVariant()); - } - } - if (!msgs.isEmpty()) - { - this->getIContextApplication()->sendStatusMessages(msgs); - } - } - -} // namespace diff --git a/src/blackgui/settingssimulatorcomponent.h b/src/blackgui/settingssimulatorcomponent.h deleted file mode 100644 index 5e544ce23..000000000 --- a/src/blackgui/settingssimulatorcomponent.h +++ /dev/null @@ -1,48 +0,0 @@ -#ifndef BLACKGUI_SETTINGSSIMULATORCOMPONENT_H -#define BLACKGUI_SETTINGSSIMULATORCOMPONENT_H - -#include "runtimebasedcomponent.h" -#include - -namespace Ui { class CSettingsSimulatorComponent; } - -namespace BlackGui -{ - /*! - * All simulator settings component (GUI) - */ - class CSettingsSimulatorComponent : public QFrame, public CRuntimeBasedComponent - { - Q_OBJECT - - public: - //! Constructor - explicit CSettingsSimulatorComponent(QWidget *parent = nullptr); - - //! Destructor - ~CSettingsSimulatorComponent(); - - protected: - //! \copydoc CRuntimeBasedComponent::runtimeHasBeenSet() - virtual void runtimeHasBeenSet() override; - - private slots: - //! Driver changed - void ps_pluginHasChanged(int index); - - //! Settings have been changed - void ps_settingsHaveChanged(uint settingsType); - - //! A GUI value has been changed - void ps_guiValueHasChanged(); - - private: - Ui::CSettingsSimulatorComponent *ui; //!< UI - - //! Smarter way to set current driver, avoids unnecessary signals and less formatting dependend - void setCurrentPlugin(const BlackSim::CSimulatorInfo &plugin); - - }; - -} // namespace -#endif // guard diff --git a/src/blackgui/textmessagecomponent.cpp b/src/blackgui/textmessagecomponent.cpp deleted file mode 100644 index 4eae4e7cb..000000000 --- a/src/blackgui/textmessagecomponent.cpp +++ /dev/null @@ -1,461 +0,0 @@ -#include "textmessagecomponent.h" -#include "blackmisc/nwuser.h" -#include "blackmisc/notificationsounds.h" -#include "ui_textmessagecomponent.h" - -#include -#include - -using namespace BlackCore; -using namespace BlackMisc; -using namespace BlackGui; -using namespace BlackMisc::Network; -using namespace BlackMisc::Aviation; -using namespace BlackMisc::PhysicalQuantities; -using namespace BlackMisc::Settings; - -namespace BlackGui -{ - - CTextMessageComponent::CTextMessageComponent(QWidget *parent) : - QTabWidget(parent), CRuntimeBasedComponent(nullptr, false), ui(new Ui::CTextMessageComponent), m_selcalCallback(nullptr), m_clearTextEditAction(nullptr), m_currentTextEdit(nullptr) - { - ui->setupUi(this); - this->m_clearTextEditAction = new QAction("Clear", this); - connect(this->m_clearTextEditAction, &QAction::triggered, this, &CTextMessageComponent::clearTextEdit); - - ui->te_TextMessagesAll->setContextMenuPolicy(Qt::CustomContextMenu); - connect(ui->te_TextMessagesAll, &QTextEdit::customContextMenuRequested, this, &CTextMessageComponent::showContextMenuForTextEdit); - - ui->te_TextMessagesUnicom->setContextMenuPolicy(Qt::CustomContextMenu); - connect(ui->te_TextMessagesUnicom, &QTextEdit::customContextMenuRequested, this, &CTextMessageComponent::showContextMenuForTextEdit); - - ui->te_TextMessagesCOM1->setContextMenuPolicy(Qt::CustomContextMenu); - connect(ui->te_TextMessagesCOM1, &QTextEdit::customContextMenuRequested, this, &CTextMessageComponent::showContextMenuForTextEdit); - - ui->te_TextMessagesCOM2->setContextMenuPolicy(Qt::CustomContextMenu); - connect(ui->te_TextMessagesCOM2, &QTextEdit::customContextMenuRequested, this, &CTextMessageComponent::showContextMenuForTextEdit); - } - - CTextMessageComponent::~CTextMessageComponent() - { - delete ui; - } - - QWidget *CTextMessageComponent::getTab(CTextMessageComponent::Tab tab) - { - switch (tab) - { - case TextMessagesAll: - return this->ui->tb_TextMessagesAll; - case TextMessagesCom1: - return this->ui->tb_TextMessagesCOM1; - case TextMessagesCom2: - return this->ui->tb_TextMessagesCOM2; - case TextMessagesUnicom: - return this->ui->tb_TextMessagesUnicom; - default: - qFatal("Wrong index"); - break; - } - return nullptr; - } - - /* - * Text messages received or send, append to GUI - */ - void CTextMessageComponent::appendTextMessagesToGui(const CTextMessageList &messages, bool sending) - { - if (messages.isEmpty()) return; - foreach(CTextMessage message, messages) - { - const QString currentSelcal = this->m_selcalCallback ? this->m_selcalCallback() : ""; - if (CSelcal::isValidCode(currentSelcal) && message.isSelcalMessageFor(currentSelcal)) - { - if (this->getOwnAircraft().isActiveFrequencyWithin25kHzChannel(message.getFrequency())) - { - // this is SELCAL for me - if (this->getIContextAudio()) - { - this->getIContextAudio()->playSelcalTone(currentSelcal); - } - else - { - emit this->displayInInfoWindow(CStatusMessage::getInfoMessage("SELCAL received", CStatusMessage::TypeGui).toCVariant(), 3 * 1000); - } - } - continue; // not displayed - } - - bool relevantForMe = false; - QString m = message.asString(true, false, "\t"); - - if (message.isSendToUnicom()) - { - this->ui->te_TextMessagesUnicom->append(m); - relevantForMe = true; - } - - // check message - if (message.isRadioMessage()) - { - // check for own COM frequencies - if (message.isSendToFrequency(this->getOwnAircraft().getCom1System().getFrequencyActive())) - { - this->ui->te_TextMessagesCOM1->append(m); - relevantForMe = true; - } - if (message.isSendToFrequency(this->getOwnAircraft().getCom2System().getFrequencyActive())) - { - this->ui->te_TextMessagesCOM2->append(m); - relevantForMe = true; - } - } - else if (message.isPrivateMessage() && !message.isServerMessage()) - { - // private message - this->addPrivateChannelTextMessage(message, sending); - relevantForMe = true; - } - - // message for me? right frequency? otherwise quit - if (relevantForMe || message.isServerMessage()) this->ui->te_TextMessagesAll->append(m); - if (!relevantForMe) return; - - // overlay message if this channel is not selected - if (!sending && !message.isSendToUnicom() && !message.isServerMessage()) - { - // if the channel is selected, do nothing - if (!this->isCorrespondingTextMessageTabSelected(message)) - emit this->displayInInfoWindow(message.toCVariant(), 5 * 1000); - } - } - } - - void CTextMessageComponent::changedAircraftCockpit() - { - this->showCurrentFrequenciesFromCockpit(); - } - - void CTextMessageComponent::runtimeHasBeenSet() - { - connect(this->getIContextOwnAircraft(), &IContextOwnAircraft::changedAircraftCockpit, this, &CTextMessageComponent::changedAircraftCockpit); - } - - /* - * Is the tab of the message's receiver selected? - */ - bool CTextMessageComponent::isCorrespondingTextMessageTabSelected(CTextMessage textMessage) const - { - if (!this->isVisible()) return false; - if (!textMessage.hasValidRecipient()) return false; - if (textMessage.isEmpty()) return false; // ignore empty message - if (textMessage.isPrivateMessage()) - { - // private message - CCallsign cs = textMessage.getSenderCallsign(); - if (cs.isEmpty()) return false; - QWidget *tab = this->findTextMessageTabByName(cs.getStringAsSet()); - if (!tab) return false; - return this->currentWidget() == tab; - } - else - { - // frequency message - const CAircraft ownAircraft = this->getOwnAircraft(); - if (this->currentWidget() == this->ui->tb_TextMessagesAll) return true; - if (textMessage.isSendToFrequency(ownAircraft.getCom1System().getFrequencyActive())) - return this->currentWidget() == this->ui->tb_TextMessagesCOM1; - if (textMessage.isSendToFrequency(ownAircraft.getCom2System().getFrequencyActive())) - return this->currentWidget() == this->ui->tb_TextMessagesCOM2; - return false; - } - } - - void CTextMessageComponent::showCurrentFrequenciesFromCockpit() - { - const CAircraft ownAircraft = this->getOwnAircraft(); - QString f1n, f2n; - f1n.sprintf("%03.3f", ownAircraft.getCom1System().getFrequencyActive().valueRounded(CFrequencyUnit::MHz(), 3)); - f2n.sprintf("%03.3f", ownAircraft.getCom2System().getFrequencyActive().valueRounded(CFrequencyUnit::MHz(), 3)); - const QString f1 = QString("COM1: %1").arg(f1n); - const QString f2 = QString("COM2: %1").arg(f2n); - this->ui->tb_TextMessagesCOM1->setToolTip(f1); - this->ui->tb_TextMessagesCOM1->setToolTip(f2); - this->setTabText(this->indexOf(this->ui->tb_TextMessagesCOM1), f1); - this->setTabText(this->indexOf(this->ui->tb_TextMessagesCOM2), f2); - } - - /* - * Add new text message tab - */ - QWidget *CTextMessageComponent::addNewTextMessageTab(const QString &tabName) - { - QWidget *newTab = new QWidget(this); - QPushButton *closeButton = new QPushButton("Close", newTab); - QVBoxLayout *layout = new QVBoxLayout(newTab); - QTextEdit *textEdit = new QTextEdit(newTab); - int marginLeft, marginRight, marginTop, marginBottom; - this->ui->tb_TextMessagesAll->layout()->getContentsMargins(&marginLeft, &marginTop, &marginRight, &marginBottom); - newTab->layout()->setContentsMargins(marginLeft, marginTop, marginRight, 2); - textEdit->setReadOnly(true); - textEdit->setWordWrapMode(QTextOption::NoWrap); - layout->addWidget(textEdit); - layout->addWidget(closeButton); - newTab->setLayout(layout); - textEdit->setContextMenuPolicy(Qt::CustomContextMenu); - connect(textEdit, &QTextEdit::customContextMenuRequested, this, &CTextMessageComponent::showContextMenuForTextEdit); - int index = this->addTab(newTab, tabName); - this->connect(closeButton, &QPushButton::released, this, &CTextMessageComponent::closeTextMessageTab); - this->setCurrentIndex(index); - - if (this->getIContextNetwork()) - { - QString realName = this->getIContextNetwork()->getUserForCallsign(CCallsign(tabName)).getRealName(); - if (!realName.isEmpty()) this->setTabToolTip(index, realName); - } - return newTab; - } - - /* - * Add a private channel text message - */ - void CTextMessageComponent::addPrivateChannelTextMessage(const CTextMessage &textMessage, bool sending) - { - if (!textMessage.isPrivateMessage()) return; - CCallsign cs = sending ? textMessage.getRecipientCallsign() : textMessage.getSenderCallsign(); - if (cs.isEmpty()) return; - QWidget *tab = this->findTextMessageTabByName(cs.getStringAsSet()); - if (tab == nullptr) tab = this->findTextMessageTabByName(cs.asString()); - if (tab == nullptr) tab = this->addNewTextMessageTab(cs.getStringAsSet()); - Q_ASSERT(tab != nullptr); - QTextEdit *textEdit = tab->findChild(); - Q_ASSERT(textEdit != nullptr); - if (textEdit == nullptr) return; // do not crash, though this situation could not happen - textEdit->append(textMessage.asString(true, false, "\t")); - - // sound - if (this->getIContextAudio()) - this->getIContextAudio()->playNotification(BlackSound::CNotificationSounds::NotificationTextMessagePrivate, true); - } - - /* - * Message tab by name - */ - QWidget *CTextMessageComponent::findTextMessageTabByName(const QString &name) const - { - if (name.isEmpty()) return nullptr; - QString n = name.trimmed(); - for (int index = 0; index < this->count(); index++) - { - QString tabName = this->tabText(index); - if (tabName.indexOf(n, 0, Qt::CaseInsensitive) < 0) continue; - QWidget *tab = this->widget(index); - return tab; - } - return nullptr; - } - - /* - * Text message stub (sender/receiver) for current channel - */ - CTextMessage CTextMessageComponent::getTextMessageStubForChannel() - { - CTextMessage tm; - int index = this->currentIndex(); - if (index < 0) return tm; - if (index == this->indexOf(this->ui->tb_TextMessagesAll)) return tm; - - // from - tm.setSenderCallsign(this->getOwnAircraft().getCallsign()); - - // frequency text message? - if (index == this->indexOf(this->ui->tb_TextMessagesCOM1)) - { - tm.setFrequency(this->getOwnAircraft().getCom1System().getFrequencyActive()); - } - else if (index == this->indexOf(this->ui->tb_TextMessagesCOM2)) - { - tm.setFrequency(this->getOwnAircraft().getCom2System().getFrequencyActive()); - } - else if (index == this->indexOf(this->ui->tb_TextMessagesUnicom)) - { - tm.setFrequency(CPhysicalQuantitiesConstants::FrequencyUnicom()); - } - else - { - // not a standard channel - QString selectedTabText = this->tabText(index); - bool isNumber; - double frequency = selectedTabText.toDouble(&isNumber); - if (isNumber) - { - CFrequency radioFrequency = CFrequency(frequency, CFrequencyUnit::MHz()); - if (CComSystem::isValidCivilAviationFrequency(radioFrequency)) - { - tm.setFrequency(radioFrequency); - } - else - { - CCallsign toCallsign(selectedTabText); - tm.setRecipientCallsign(toCallsign); - } - } - else - { - CCallsign toCallsign(selectedTabText); - tm.setRecipientCallsign(toCallsign); - } - } - return tm; // now valid message stub with receiver - } - - /* - * Close message tab - */ - void CTextMessageComponent::closeTextMessageTab() - { - QObject *sender = QObject::sender(); - QWidget *parentWidget = qobject_cast(sender->parent()); - Q_ASSERT(parentWidget); - int index = -1; - - while (index < 0 && parentWidget) - { - index = this->indexOf(parentWidget); - parentWidget = parentWidget->parentWidget(); - } - if (index >= 0) this->removeTab(index); - } - - void CTextMessageComponent::showContextMenuForTextEdit(const QPoint &pt) - { - QObject *sender = QObject::sender(); - this->m_currentTextEdit = qobject_cast(sender); - Q_ASSERT(this->m_currentTextEdit); - - QMenu *menu = this->m_currentTextEdit->createStandardContextMenu(); - menu->setParent(this->m_currentTextEdit); - menu->setObjectName(this->m_currentTextEdit->objectName().append("_contextMenu")); - menu->addSeparator(); - menu->addAction(this->m_clearTextEditAction); - menu->exec(this->m_currentTextEdit->mapToGlobal(pt)); - delete menu; - } - - void CTextMessageComponent::clearTextEdit() - { - if (!this->m_currentTextEdit) return; - this->m_currentTextEdit->clear(); - this->m_currentTextEdit = nullptr; - } - - /* - * Command entered - */ - void CTextMessageComponent::commandEntered() - { - // TODO: just a first draft of the command line parser - // needs to be refactored, as soon as a first version works - - QLineEdit *lineEdit = qobject_cast(QObject::sender()); - Q_ASSERT(lineEdit); - - QString cmdLine = lineEdit->text().simplified(); - if (cmdLine.isEmpty()) return; - QList parts = cmdLine.toLower().split(' '); - if (parts.length() < 1) return; - QString cmd = parts[0].startsWith('.') ? parts[0].toLower() : ""; - if (cmd == ".m" || cmd == ".msg") - { - if (!this->getIContextNetwork() || !this->getIContextNetwork()->isConnected()) - { - this->sendStatusMessage(CStatusMessage(CStatusMessage::TypeTrafficNetwork, CStatusMessage::SeverityError, "network needs to be connected")); - return; - } - if (parts.length() < 3) - { - this->sendStatusMessage(CStatusMessage(CStatusMessage::TypeValidation, CStatusMessage::SeverityError, "incorrect message")); - return; - } - QString p = parts[1].trimmed(); // receiver - - // select current tab by command - this->setVisible(true); - if (p == "c1" || p == "com1") - { - this->setCurrentWidget(this->ui->tb_TextMessagesCOM1); - } - else if (p == "c2" || p == "com2") - { - this->setCurrentWidget(this->ui->tb_TextMessagesCOM2); - } - else if (p == "u" || p == "unicom" || p == "uni") - { - this->setCurrentWidget(this->ui->tb_TextMessagesUnicom); - } - else - { - QWidget *tab = this->findTextMessageTabByName(p.trimmed()); - if (tab == nullptr) tab = this->addNewTextMessageTab(p.trimmed().toUpper()); - this->setCurrentWidget(tab); - } - CTextMessage tm = this->getTextMessageStubForChannel(); - int index = cmdLine.indexOf(tm.getRecipientCallsign().getStringAsSet(), 0, Qt::CaseInsensitive); - if (index < 0) - { - this->sendStatusMessage( - CStatusMessage(CStatusMessage::TypeValidation, CStatusMessage::SeverityError, - "incomplete message") - ); - return; - } - QString msg(cmdLine.mid(index + tm.getRecipientCallsign().asString().length() + 1)); - tm.setMessage(msg); - if (tm.isEmpty()) return; - if (!this->isNetworkConnected()) return; - CTextMessageList tml(tm); - this->getIContextNetwork()->sendTextMessages(tml); - this->appendTextMessagesToGui(tml, true); - lineEdit->setText(""); - } - else if (cmd.startsWith(".")) - { - // dump CMDs - } - else - { - // single line, no command - // line is considered to be a message to the selected channel, send - if (!this->isNetworkConnected()) - { - this->sendStatusMessage(CStatusMessage(CStatusMessage::TypeTrafficNetwork, CStatusMessage::SeverityError, "network needs to be connected")); - return; - } - - if (!this->isVisible()) - { - this->sendStatusMessage(CStatusMessage(CStatusMessage::TypeTrafficNetwork, CStatusMessage::SeverityError, "text messages can only be sent from corresponding page")); - return; - } - - int index = this->currentIndex(); - if (index < 0 || index == this->indexOf(this->ui->tb_TextMessagesAll)) - { - this->sendStatusMessage(CStatusMessage(CStatusMessage::TypeValidation, CStatusMessage::SeverityError, "incorrect channel")); - } - else - { - CTextMessage tm = this->getTextMessageStubForChannel(); - tm.setMessage(cmdLine); - if (tm.isEmpty()) return; - if (!this->getIContextNetwork()) return; - CTextMessageList textMessageList(tm); - this->getIContextNetwork()->sendTextMessages(textMessageList); - this->appendTextMessagesToGui(textMessageList, true); - lineEdit->setText(""); - } - } - } -} - diff --git a/src/blackgui/textmessagecomponent.h b/src/blackgui/textmessagecomponent.h deleted file mode 100644 index 43ae4ad10..000000000 --- a/src/blackgui/textmessagecomponent.h +++ /dev/null @@ -1,116 +0,0 @@ -#ifndef BLACKGUI_TEXTMESSAGECOMPONENT_H -#define BLACKGUI_TEXTMESSAGECOMPONENT_H - -#include "blackgui/runtimebasedcomponent.h" -#include "blackgui/timerbasedcomponent.h" -#include "blackmisc/nwtextmessage.h" -#include "blackmisc/avaircraft.h" - -#include -#include -#include - -namespace Ui { class CTextMessageComponent; } -namespace BlackGui -{ - //! Text message widget - class CTextMessageComponent : public QTabWidget, public CRuntimeBasedComponent - { - Q_OBJECT - - public: - //! Tabs - enum Tab - { - TextMessagesAll, - TextMessagesUnicom, - TextMessagesCom1, - TextMessagesCom2 - }; - - //! Constructor - explicit CTextMessageComponent(QWidget *parent = nullptr); - - //! Destructor - ~CTextMessageComponent(); - - //! SELCAL callback, SELCAL is obtained by that - void setSelcalCallback(const std::function &selcalCallback) { this->m_selcalCallback = selcalCallback; } - - signals: - //! Message to be displayed in info window - void displayInInfoWindow(const BlackMisc::CVariant &message, int displayDurationMs) const; - - public slots: - //! Command entered - void commandEntered(); - - /*! - * \brief Append text messages (received, to be sent) to GUI - * \param messages - * \param sending - */ - void appendTextMessagesToGui(const BlackMisc::Network::CTextMessageList &messages, bool sending = false); - - //! Cockpit values changed, used to updated some components - void changedAircraftCockpit(); - - protected: - //! \copydoc CRuntimeBasedComponent::runtimeHasBeenSet - void runtimeHasBeenSet() override; - - private: - Ui::CTextMessageComponent *ui; - QWidget *getTab(Tab tab); //!< enum to widget - std::function m_selcalCallback; //!< obtain SELCAL by that - QAction *m_clearTextEditAction; - QTextEdit *m_currentTextEdit; - - /*! - * \brief Add new text message tab - * \param tabName name of the new tab, usually the channel name - * \return - */ - QWidget *addNewTextMessageTab(const QString &tabName); - - //! Find text message tab by its name - QWidget *findTextMessageTabByName(const QString &name) const; - - /*! - * \brief Private channel text message - * \param textMessage - * \param sending sending or receiving - */ - void addPrivateChannelTextMessage(const BlackMisc::Network::CTextMessage &textMessage, bool sending = false); - - /*! - * Stub for sending a text message (eihter radio or private message). - * Sets sender / receiver depending on frequency / channel situation. - */ - BlackMisc::Network::CTextMessage getTextMessageStubForChannel(); - - //! own aircraft - const BlackMisc::Aviation::CAircraft getOwnAircraft() const { Q_ASSERT(this->getIContextOwnAircraft()); return this->getIContextOwnAircraft()->getOwnAircraft(); } - - //! For this text message's recepient, is the current tab selected? - bool isCorrespondingTextMessageTabSelected(BlackMisc::Network::CTextMessage textMessage) const; - - //! Network connected? - bool isNetworkConnected() const { return this->getIContextNetwork() && this->getIContextNetwork()->isConnected() ; } - - //! Show current frequencies - void showCurrentFrequenciesFromCockpit(); - - private slots: - //! Close text message tab - void closeTextMessageTab(); - - //! Context menu for text edit including clear - void showContextMenuForTextEdit(const QPoint &pt); - - //! Clear text edit - void clearTextEdit(); - }; -} - -#endif // guard diff --git a/src/blackgui/timerbasedcomponent.cpp b/src/blackgui/timerbasedcomponent.cpp deleted file mode 100644 index dd004b593..000000000 --- a/src/blackgui/timerbasedcomponent.cpp +++ /dev/null @@ -1,31 +0,0 @@ -#include "timerbasedcomponent.h" - -namespace BlackGui -{ - - CTimerBasedComponent::CTimerBasedComponent(const char *slot, QObject *parent) : - QObject(parent), m_timer(nullptr) - { - this->m_timer = new QTimer(this); - this->connect(this->m_timer, SIGNAL(timeout()), parent, slot); - } - - CTimerBasedComponent::~CTimerBasedComponent() - { - this->m_timer->stop(); - if (this->parent()) this->disconnect(this->parent()); - } - - void CTimerBasedComponent::setUpdateInterval(int milliSeconds) - { - if (milliSeconds < 100) - { - this->m_timer->stop(); - } - else - { - this->m_timer->setInterval(milliSeconds); - if (!this->m_timer->isActive()) this->m_timer->start(); - } - } -} // guard diff --git a/src/blackgui/timerbasedcomponent.h b/src/blackgui/timerbasedcomponent.h deleted file mode 100644 index 6eca257c2..000000000 --- a/src/blackgui/timerbasedcomponent.h +++ /dev/null @@ -1,34 +0,0 @@ -#ifndef BLACKGUI_TIMERBASEDCOMPONENT_H -#define BLACKGUI_TIMERBASEDCOMPONENT_H - -#include - -namespace BlackGui -{ - - //! Timer based componenet - class CTimerBasedComponent: public QObject - { - public: - //! Constructor - CTimerBasedComponent(const char *slot, QObject *parent); - - //! Destructor - ~CTimerBasedComponent(); - - public slots: - //! Update time, time < 100 stops updates - void setUpdateInterval(int milliSeconds); - - //! Update time - void setUpdateIntervalSeconds(int seconds) { this->setUpdateInterval(1000 * seconds); } - - //! Stop timer - void stopTimer() { this->setUpdateInterval(-1); } - - private: - QTimer *m_timer; - }; -} - -#endif // guard diff --git a/src/blackgui/usercomponent.cpp b/src/blackgui/usercomponent.cpp deleted file mode 100644 index c50383b8f..000000000 --- a/src/blackgui/usercomponent.cpp +++ /dev/null @@ -1,30 +0,0 @@ -#include "usercomponent.h" -#include "ui_usercomponent.h" - -namespace BlackGui -{ - CUserComponent::CUserComponent(QWidget *parent) : - QTabWidget(parent), CRuntimeBasedComponent(nullptr, false), ui(new Ui::CUserComponent), m_timerComponent(nullptr) - { - ui->setupUi(this); - this->m_timerComponent = new CTimerBasedComponent(SLOT(update()), this); - } - - CUserComponent::~CUserComponent() - { - delete ui; - } - - void CUserComponent::update() - { - Q_ASSERT(this->ui->tvp_AllUsers); - Q_ASSERT(this->ui->tvp_Clients); - Q_ASSERT(this->getIContextNetwork()); - - if (this->getIContextNetwork()->isConnected()) - { - this->ui->tvp_Clients->update(this->getIContextNetwork()->getOtherClients()); - this->ui->tvp_AllUsers->update(this->getIContextNetwork()->getUsers()); - } - } -} // guard diff --git a/src/blackgui/usercomponent.h b/src/blackgui/usercomponent.h deleted file mode 100644 index 28b0d03a5..000000000 --- a/src/blackgui/usercomponent.h +++ /dev/null @@ -1,50 +0,0 @@ -#ifndef BLACKGUI_USERCOMPONENT_H -#define BLACKGUI_USERCOMPONENT_H - -#include "blackgui/runtimebasedcomponent.h" -#include "blackgui/timerbasedcomponent.h" -#include "blackmisc/nwuserlist.h" - -#include -#include - -namespace Ui { class CUserComponent; } - -namespace BlackGui -{ - - //! User componenet (users, clients) - class CUserComponent : public QTabWidget, public CRuntimeBasedComponent - { - Q_OBJECT - - public: - //! Constructor - explicit CUserComponent(QWidget *parent = nullptr); - - //! Destructor - ~CUserComponent(); - - //! Timer for updating - CTimerBasedComponent *getTimerComponent() { return this->m_timerComponent; } - - public slots: - //! Update users - void update(); - - //! \copydoc CTimerBasedComponent::setUpdateIntervalSeconds - void setUpdateIntervalSeconds(int seconds) { Q_ASSERT(this->m_timerComponent); this->m_timerComponent->setUpdateIntervalSeconds(seconds); } - - //! \copydoc CTimerBasedComponent::setUpdateInterval - void setUpdateInterval(int milliSeconds) { Q_ASSERT(this->m_timerComponent); this->m_timerComponent->setUpdateInterval(milliSeconds); } - - //! \copydoc CTimerBasedComponent::stopTimer - void stopTimer() { Q_ASSERT(this->m_timerComponent); this->m_timerComponent->stopTimer(); } - - private: - Ui::CUserComponent *ui; - CTimerBasedComponent *m_timerComponent; - }; -} - -#endif // guard