From 74d608b5df5f915162ba0cc806d56e7981ffe122 Mon Sep 17 00:00:00 2001 From: Klaus Basan Date: Fri, 3 Feb 2017 20:43:33 +0100 Subject: [PATCH] refs #617, allow to use CGuiActionBindHandler with buttons * used for weather enable/disable * use actionBindWasDestroyed when corresponding BlackCore::CActionBind is destroyed --- src/blackcore/actionbind.h | 5 +- src/blackgui/components/weathercomponent.cpp | 18 +++-- src/blackgui/components/weathercomponent.h | 4 +- src/blackgui/guiactionbind.cpp | 75 +++++++++++++++----- src/blackgui/guiactionbind.h | 30 ++++++-- 5 files changed, 101 insertions(+), 31 deletions(-) diff --git a/src/blackcore/actionbind.h b/src/blackcore/actionbind.h index 845951bf3..a9f14b044 100644 --- a/src/blackcore/actionbind.h +++ b/src/blackcore/actionbind.h @@ -58,8 +58,11 @@ namespace BlackCore std::function m_deleteCallback; //!< called when deleted }; + //! Single binding + using CActionBinding = QSharedPointer; + //! List of bindings - using CActionBindings = QList>; + using CActionBindings = QList; } #endif diff --git a/src/blackgui/components/weathercomponent.cpp b/src/blackgui/components/weathercomponent.cpp index 93c61fab1..2a05bf926 100644 --- a/src/blackgui/components/weathercomponent.cpp +++ b/src/blackgui/components/weathercomponent.cpp @@ -11,6 +11,7 @@ #include "blackgui/infoarea.h" #include "blackgui/views/viewbase.h" #include "blackgui/guiapplication.h" +#include "blackgui/guiactionbind.h" #include "blackcore/context/contextapplication.h" #include "blackcore/context/contextsimulator.h" #include "blackcore/context/contextownaircraft.h" @@ -43,21 +44,24 @@ namespace BlackGui ui(new Ui::CWeatherComponent) { ui->setupUi(this); - m_weatherScenarios = CWeatherGrid::getAllScenarios(); - for (const auto &scenario : m_weatherScenarios) + m_weatherScenarios = CWeatherGrid::getAllScenarios(); + for (const auto &scenario : as_const(m_weatherScenarios)) { ui->cb_weatherScenario->addItem(scenario.getName(), QVariant::fromValue(scenario)); } - auto scenario = m_weatherScenarioSetting.get(); - ui->cb_weatherScenario->setCurrentIndex(scenario.getIndex()); + const auto scenario = m_weatherScenarioSetting.get(); + ui->cb_weatherScenario->setCurrentIndex(scenario.getIndex()); ui->pb_ActivateWeather->setIcon(CIcons::metar()); setupConnections(); setupInputValidators(); setupCompleter(); + // hotkeys + m_hotkeyBindings.append(CGuiActionBindHandler::bindButton(ui->pb_ActivateWeather, "Weather/Toggle weather", true)); + // Set interval to 5 min m_weatherUpdateTimer.setInterval(1000 * 60 * 5); @@ -146,7 +150,7 @@ namespace BlackGui { Q_ASSERT(sGui->getIContextOwnAircraft()); position = sGui->getIContextOwnAircraft()->getOwnAircraft().getPosition(); - if(position == CCoordinateGeodetic()) + if (position == CCoordinateGeodetic()) { ui->le_LatOrIcao->setText("N/A"); ui->le_Lon->setText("N/A"); @@ -187,7 +191,7 @@ namespace BlackGui if (CWeatherScenario::isRealWeatherScenario(scenario)) { if (!useOwnAcftPosition || - calculateGreatCircleDistance(position, m_lastOwnAircraftPosition).value(CLengthUnit::km()) > 20 ) + calculateGreatCircleDistance(position, m_lastOwnAircraftPosition).value(CLengthUnit::km()) > 20) { requestWeatherGrid(position); m_lastOwnAircraftPosition = position; @@ -201,7 +205,7 @@ namespace BlackGui void CWeatherComponent::weatherGridReceived(const CWeatherGrid &weatherGrid, const CIdentifier &identifier) { - if(!isMyIdentifier(identifier)) { return; } + if (!isMyIdentifier(identifier)) { return; } ui->lb_Status->setText({}); setWeatherGrid(weatherGrid); } diff --git a/src/blackgui/components/weathercomponent.h b/src/blackgui/components/weathercomponent.h index 4ae7a2739..c39423fd0 100644 --- a/src/blackgui/components/weathercomponent.h +++ b/src/blackgui/components/weathercomponent.h @@ -12,8 +12,9 @@ #ifndef BLACKGUI_WEATHERCOMPONENT_H #define BLACKGUI_WEATHERCOMPONENT_H -#include "blackgui/blackguiexport.h" #include "blackgui/components/enablefordockwidgetinfoarea.h" +#include "blackgui/blackguiexport.h" +#include "blackcore/actionbind.h" #include "blackmisc/geo/coordinategeodetic.h" #include "blackmisc/simulation/simulatorsettings.h" #include "blackmisc/weather/weatherscenario.h" @@ -77,6 +78,7 @@ namespace BlackGui QTimer m_weatherUpdateTimer { this }; BlackMisc::Geo::CCoordinateGeodetic m_lastOwnAircraftPosition; BlackMisc::CSetting m_weatherScenarioSetting { this }; + BlackCore::CActionBindings m_hotkeyBindings; bool m_isWeatherActivated = false; }; } // namespace diff --git a/src/blackgui/guiactionbind.cpp b/src/blackgui/guiactionbind.cpp index 5fad2a1a9..0f373a7e9 100644 --- a/src/blackgui/guiactionbind.cpp +++ b/src/blackgui/guiactionbind.cpp @@ -15,9 +15,14 @@ using namespace BlackCore; namespace BlackGui { - CGuiActionBindHandler::CGuiActionBindHandler(QAction *action) : QObject(action) + CGuiActionBindHandler::CGuiActionBindHandler(QAction *action) : QObject(action), m_action(action) { - this->setAction(action); + this->connectDestroy(action); + } + + CGuiActionBindHandler::CGuiActionBindHandler(QAbstractButton *button) : QObject(button), m_button(button) + { + this->connectDestroy(button); } CGuiActionBindHandler::~CGuiActionBindHandler() @@ -27,6 +32,7 @@ namespace BlackGui CActionBindings CGuiActionBindHandler::bindMenu(QMenu *menu, const QString &path) { + Q_ASSERT(menu); CActionBindings boundActions; if (!menu || menu->isEmpty()) { return boundActions; } for (QAction *action : menu->actions()) @@ -41,19 +47,36 @@ namespace BlackGui } CGuiActionBindHandler *bindHandler = new CGuiActionBindHandler(action); - QSharedPointer actionBind(new CActionBind(pathNew, bindHandler, &CGuiActionBindHandler::boundFunction, [bindHandler]() { bindHandler->deleteLater(); })); - bindHandler->m_index = actionBind->getIndex(); - boundActions.append(actionBind); // takes ownership + CActionBinding actionBinding(new CActionBind(pathNew, bindHandler, &CGuiActionBindHandler::boundFunction, [bindHandler]() { CGuiActionBindHandler::actionBindWasDestroyed(bindHandler); })); + bindHandler->m_index = actionBinding->getIndex(); + boundActions.append(actionBinding); // takes ownership } return boundActions; } - void CGuiActionBindHandler::setAction(QAction *action) + CActionBinding CGuiActionBindHandler::bindButton(QAbstractButton *button, const QString &path, bool absoluteName) { - this->m_action = action; + Q_ASSERT(button); + const QString pathNew = absoluteName ? + path : + CGuiActionBindHandler::appendPath(path, button->text()).remove('&'); // remove E&xit key codes + CGuiActionBindHandler *bindHandler = new CGuiActionBindHandler(button); + CActionBinding actionBinding(new CActionBind(pathNew, bindHandler, &CGuiActionBindHandler::boundFunction, [bindHandler]() { CGuiActionBindHandler::actionBindWasDestroyed(bindHandler); })); + bindHandler->m_index = actionBinding->getIndex(); + return actionBinding; + } + void CGuiActionBindHandler::actionBindWasDestroyed(CGuiActionBindHandler *bindHandler) + { + if (!bindHandler) { return; } + bindHandler->reset(); + // do not delete, as it might be still referenced somewhere + } + + void CGuiActionBindHandler::connectDestroy(QObject *object) + { // if the action is destroyed from somewhere else I unbind myself - QObject::connect(action, &QAction::destroyed, [ = ] + QObject::connect(object, &QObject::destroyed, [ = ] { this->unbind(); }); @@ -61,21 +84,39 @@ namespace BlackGui void CGuiActionBindHandler::unbind() { - if (!this->m_action) { return; } - this->m_action = nullptr; - if (CInputManager::instance()) + if (this->hasTarget()) { - CInputManager::instance()->unbind(this->m_index); - m_index = -1; + if (CInputManager::instance()) + { + CInputManager::instance()->unbind(this->m_index); + } } + this->reset(); + } + + void CGuiActionBindHandler::reset() + { + m_index = -1; + m_button = nullptr; + m_action = nullptr; + } + + bool CGuiActionBindHandler::hasTarget() const + { + return (m_button || m_action) && m_index >= 0; } void CGuiActionBindHandler::boundFunction(bool enabled) { - if (!enabled) { return; } - if (!m_action) { return; } - if (m_index < 0) { return; } - m_action->trigger(); + if (!enabled || !this->hasTarget()) { return; } + if (m_action) + { + m_action->trigger(); + } + else if (m_button) + { + m_button->click(); + } } QString CGuiActionBindHandler::appendPath(const QString &path, const QString &name) diff --git a/src/blackgui/guiactionbind.h b/src/blackgui/guiactionbind.h index 26ecc24e3..e7ae2a6a5 100644 --- a/src/blackgui/guiactionbind.h +++ b/src/blackgui/guiactionbind.h @@ -17,6 +17,8 @@ #include #include +#include +#include #include namespace BlackGui @@ -27,9 +29,6 @@ namespace BlackGui Q_OBJECT public: - //! Constructor - CGuiActionBindHandler(QAction *action); - //! Destructor virtual ~CGuiActionBindHandler(); @@ -37,23 +36,44 @@ namespace BlackGui void boundFunction(bool enabled); //! Bind whole menu + //! \remark keep BlackCore::CActionBindings as long you want to keep this binding alive static BlackCore::CActionBindings bindMenu(QMenu *menu, const QString &path = {}); + //! Bind button, with relative name + //! \remark keep BlackCore::CActionBinding as long you want to keep this binding alive + static BlackCore::CActionBinding bindButton(QAbstractButton *button, const QString &path, bool absoluteName); + + //! Corresponding BlackCore::CActionBind died, so delete CGuiActionBindHandler + static void actionBindWasDestroyed(CGuiActionBindHandler *bindHandler); + private: + //! Constructor for QAction + CGuiActionBindHandler(QAction *action); + + //! Constructor for QPushButton + CGuiActionBindHandler(QAbstractButton *button); + //! Corresponding action destroyed void destroyed(); //! Set the action - void setAction(QAction *action); + void connectDestroy(QObject *action); //! Unbind this action void unbind(); + //! Reset + void reset(); + + //! Target available? + bool hasTarget() const; + //! Append path for action static QString appendPath(const QString &path, const QString &name); int m_index = -1; - QAction *m_action = nullptr; + QAction *m_action = nullptr; + QAbstractButton *m_button = nullptr; }; } // namespace