/** * @RDE_HEADER@ * Class ResultWatcherBase, ResultWatcher * $Id$ * $HeadURL$ * $Author$ */ #pragma once // Own #include "advanced_symbology_export.h" #include "symbol_dictionary_types.h" #include // Qt #include //---------------------------------------------------------------------------- namespace AdvancedSymbology { //---------------------------------------------------------------------------- // - ResultWatcherBase (containing the Q_OBJECT for signal/slot) // - ResultWatcher (containing template) //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- // ResultWatcherBase (containing the Q_OBJECT for signal/slot) //---------------------------------------------------------------------------- /** * @brief The ResultWatcherBase class is a simple base class of ResultWatcher * and contain the signal resultReady, since a template class can`t. */ class ADVANCED_SYMBOLOGY_EXPORT ResultWatcherBase : public QObject { Q_OBJECT public: ///< Constructor explicit ResultWatcherBase(QObject *parent = nullptr) : QObject(parent) {} ///< Destructor ~ResultWatcherBase() = default; Q_SIGNALS: /// Signal emits when result is ready void resultReady(); protected Q_SLOTS: void onResultReadyInternal() { // to avoid emitting signal twice: if (! m_alreadyEmitted) emit resultReady(); m_alreadyEmitted = true; } protected: bool m_alreadyEmitted = false; }; //---------------------------------------------------------------------------- // ResultWatcher (containing template) //---------------------------------------------------------------------------- /** * @brief The ResultWatcher class takes a result and will emit resultReady exactly one time. * * \section secResultWatcherExample Using the ResultWatcher * Here is an example of using the ResultWatcher * * \code * AdvancedSymbology::SymbolDictionary &dict = AdvancedSymbology::SymbolDictionary::dictionary(AdvancedSymbology::MIL2525D); * * AdvancedSymbology::SymbolResultWatcher symbolResultWatcher; * * // FIRST connect: * connect(&symbolResultWatcher, &AdvancedSymbology::SymbolResultWatcher::resultReady, this, [](){ * * QSharedPointer symResult = symbolResultWatcher.symbolResult(); * if (! symResult) * return; // should NEVER happen! (Which object should have triggered the signal???) * * if (this->m_targetObject) * { * this->m_targetObject->setImage(symResult->symbolImage().image()); * } * }); * * // SECOND setResult (starting the asynchronous operation) * symbolResultWatcher.setSymbolResult( dict.findSymbol("mySidc") ); * \endcode * * There is an convenience class: SymbolResultWatcherComboxBox * * @note * Template classes can not contain signals why this is moved to the base class ResultWatcherBase. * */ template class ResultWatcher : public ResultWatcherBase { public: ///< Constructor explicit ResultWatcher(QObject *parent = nullptr) : ResultWatcherBase(parent) {} ///< Destructor virtual ~ResultWatcher() = default; bool resultIsValid() const { return ! m_result.isNull(); } void cancel() { m_result.clear(); } protected: QSharedPointer result() const { return m_result; } void setResult(const QSharedPointer &result) { // 2017-11-13, N.Thoden : // With rev 36928 the SymbolResult of two identical request (identical SymbolDataToRender) // will shared ONE SymbolResult! // This szenario happens while showing a snapshot. // So we have to disconnect explicitly: // make sure, that we won`t be called by the 'old' object: // so disconnect: if (m_result) m_result->disconnect(this); // : 2017-11-13, N.Thoden m_result = result; m_alreadyEmitted = false; if (m_result) { // Handle race condition: // 1. connect connect(m_result.data(), &RESULT_TYPE::resultReadyInternal, this, &ResultWatcher::onResultReadyInternal); // 2. maybe result was ready before? if (m_result->isResultReady()) onResultReadyInternal(); } } QSharedPointer m_result; }; } // namespace AdvancedSymbology