344 lines
9.3 KiB
C++
Executable File
344 lines
9.3 KiB
C++
Executable File
/**
|
||
* @RDE_HEADER@
|
||
* Class SymbolResult
|
||
* $Id$
|
||
* $HeadURL$
|
||
* $Author$
|
||
*/
|
||
#pragma once
|
||
|
||
// Own
|
||
#include "advanced_symbology_export.h"
|
||
#include "symbol_dictionary_types.h"
|
||
#include <SymbologyImpl/advanced_symbology_logging.h>
|
||
#include "result_watcher.h"
|
||
|
||
|
||
// Qt
|
||
#include <QObject>
|
||
#include <QImage>
|
||
#include <QLabel>
|
||
#include <QFuture>
|
||
#include <QSize>
|
||
#include <QBuffer>
|
||
#include <QElapsedTimer>
|
||
|
||
|
||
// forward
|
||
class QUuid;
|
||
class QComboBox;
|
||
|
||
//----------------------------------------------------------------------------
|
||
namespace AdvancedSymbology
|
||
{
|
||
|
||
/**
|
||
* @brief The SymbolResult class mainly contains a GeometryType and a SymbolImage.
|
||
* It´s based on the future pattern. So the real result can only be retrieved if
|
||
* the asynchron operation has finished (and the result is ready).
|
||
* To standardize this you should use a propper watcher: SymbolResultWatcher.
|
||
*
|
||
* \sa \ref secResultWatcherExample
|
||
*/
|
||
class ADVANCED_SYMBOLOGY_EXPORT SymbolResult : public QObject
|
||
{
|
||
Q_OBJECT
|
||
|
||
/*! \name Construction, Destruction */
|
||
//@{
|
||
public:
|
||
/**
|
||
* @brief Constructor / Destructor.
|
||
*/
|
||
explicit SymbolResult();
|
||
virtual ~SymbolResult();
|
||
//@}
|
||
|
||
|
||
/*! \name Data regarding requested */
|
||
//@{
|
||
|
||
/**
|
||
* @brief symbolDataToRender What was requested?
|
||
* @return Requested data
|
||
*/
|
||
const SymbolDataToRender &symbolDataToRender() const;
|
||
//@}
|
||
|
||
/*! \name Data regarding processing*/
|
||
//@{
|
||
/**
|
||
* @brief taskId internal taskId
|
||
* @return internal taskId
|
||
*/
|
||
const QUuid &taskId() const;
|
||
|
||
/*! \name Data regarding result*/
|
||
//@{
|
||
/**
|
||
* @brief Get geometryType of request
|
||
* @return Geometry type
|
||
*/
|
||
GeometryType geometryType() const;
|
||
|
||
/**
|
||
* @brief Get symbol image
|
||
* @return symbol image
|
||
*/
|
||
SymbolImage symbolImage() const;
|
||
//@}
|
||
|
||
|
||
bool isResultReady() const;
|
||
|
||
Q_SIGNALS:
|
||
/// This signal is for internal usage only. Use SymbolResultWatcher!
|
||
void resultReadyInternal();
|
||
|
||
protected:
|
||
friend class SymbolDictionaryImpl;
|
||
friend class EsriDictionaryProcessor;
|
||
friend class BaseSymbolModel;
|
||
void fireResultReady();
|
||
|
||
friend class ResultWatcher<SymbolResult>;
|
||
friend class SymbolResultWatcher;
|
||
|
||
void setSymbolDataToRender(const SymbolDataToRender &symDataToRender);
|
||
void setTaskId(const QUuid &uuid);
|
||
void setFuture(const QFuture<QImage> &future);
|
||
void setGeometryType(GeometryType geometryType);
|
||
void setSymbolImage(const SymbolImage &symbolImage);
|
||
|
||
protected Q_SLOTS:
|
||
void onFinished();
|
||
|
||
private:
|
||
class Private;
|
||
/**
|
||
* The private d->pointer to not break BC when changing internals of this class
|
||
*/
|
||
Private *d = nullptr;
|
||
|
||
LOGGER_T m_logger; ///< Interface of the Logging-Facility
|
||
};
|
||
|
||
|
||
//------------------------------------------------------------------------------
|
||
|
||
/**
|
||
* @brief The SymbolResultWatcher class can watch one SymbolResult using setSymbolResult.
|
||
* If the background operation has finished, the signal resultReady is emitted exactly one time.
|
||
*
|
||
* \sa \ref secResultWatcherExample
|
||
*/
|
||
class ADVANCED_SYMBOLOGY_EXPORT SymbolResultWatcher : public ResultWatcher<SymbolResult>
|
||
{
|
||
Q_OBJECT
|
||
|
||
using BaseClass = ResultWatcher<SymbolResult>;
|
||
|
||
public:
|
||
explicit SymbolResultWatcher(QObject *parent = nullptr);
|
||
~SymbolResultWatcher() = default;
|
||
|
||
QSharedPointer<SymbolResult> symbolResult() const;
|
||
void setSymbolResult(const QSharedPointer<SymbolResult> &symbolResult);
|
||
|
||
QElapsedTimer *m_et { nullptr };
|
||
|
||
protected:
|
||
LOGGER_T m_logger; ///< Interface of the Logging-Facility
|
||
};
|
||
|
||
|
||
//------------------------------------------------------------------------------
|
||
// for convenience (ComboxBox)
|
||
//------------------------------------------------------------------------------
|
||
/**
|
||
* @brief The SymbolResultWatcherComboxBox class can be used to combine a comboBox
|
||
* and an infinite number of item containing an icon.
|
||
*
|
||
* Here is an example:
|
||
*
|
||
* \code
|
||
* AdvancedSymbology::SymbolResultWatcherComboxBox *srwCb;
|
||
foreach(auto sidc, sidcs)
|
||
{
|
||
// SymbolResultWatcherComboxBox is stored as userData at every item.
|
||
// The lifetime is limited to the lifetime of the comboBox since it`s the parent.
|
||
|
||
d->m_cbRubSidc->addItem(sidc, QVariant::fromValue(srwCb = new AdvancedSymbology::SymbolResultWatcherComboxBox(d->m_cbRubSidc)) );
|
||
srwCb->setSymbolResult(dict.fetchSymbol(sidc));
|
||
}
|
||
* \endcode
|
||
*/
|
||
class ADVANCED_SYMBOLOGY_EXPORT SymbolResultWatcherComboxBox : public QObject
|
||
{
|
||
Q_OBJECT
|
||
|
||
public:
|
||
explicit SymbolResultWatcherComboxBox(QComboBox *comboBox, int role = Qt::UserRole);
|
||
|
||
void setSymbolResult(const QSharedPointer<SymbolResult> &symbolResult);
|
||
|
||
/**
|
||
* @brief enableToolTip of each entry
|
||
* @param on
|
||
*/
|
||
void enableToolTip(bool on = true) { m_enableToolTip = on; }
|
||
bool isToolTipEnabled() { return m_enableToolTip; }
|
||
|
||
|
||
private slots:
|
||
void onResultReady();
|
||
|
||
private:
|
||
QComboBox *m_comboBox{nullptr};
|
||
AdvancedSymbology::SymbolResultWatcher m_watcher;
|
||
int m_role{Qt::UserRole};
|
||
bool m_enableToolTip{true};
|
||
};
|
||
|
||
|
||
//------------------------------------------------------------------------------
|
||
// for convenience (QWidget)
|
||
//------------------------------------------------------------------------------
|
||
/**
|
||
* @brief The SymbolResultWatcherQWidgetBase class can be used with a QWidget,
|
||
* most of the time a LtsWidgets::LtsDragIcon.
|
||
* Required is a method 'setIcon(const QPixmap &pixmap)'
|
||
*
|
||
* Here is an example:
|
||
*
|
||
* \code
|
||
LtsWidgets::LtsDragIcon *dummyIcon = new LtsWidgets::LtsDragIcon(this);
|
||
|
||
AdvancedSymbology::SymbolResultWatcherQWidgetBase *dummyIconSibling =
|
||
new AdvancedSymbology::SymbolResultWatcherQWidget<LtsWidgets::LtsDragIcon>(dummyIcon);
|
||
|
||
AdvancedSymbology::SymbolDictionary &dict = d->m_mapImpl->symbolDictionary();
|
||
dummyIconSibling->setSymbolResult(dict.fetchSymbol(SidcCodec::encodeComplete(SymbologyType::MIL2525D,"10042500001401040000")));
|
||
* \endcode
|
||
* This sibling define the lifetime.
|
||
*/
|
||
class ADVANCED_SYMBOLOGY_EXPORT SymbolResultWatcherQWidgetBase : public QObject
|
||
{
|
||
Q_OBJECT
|
||
using BaseClass = QObject;
|
||
|
||
public:
|
||
explicit SymbolResultWatcherQWidgetBase(QObject *widget);
|
||
|
||
void setSymbolResult(const QSharedPointer<SymbolResult> &symbolResult);
|
||
QSharedPointer<AdvancedSymbology::SymbolResult> symbolResult() const;
|
||
|
||
private slots:
|
||
void onResultReady();
|
||
|
||
signals:
|
||
void resultReady();
|
||
|
||
protected:
|
||
virtual void onResultReadyImpl() = 0;
|
||
AdvancedSymbology::SymbolResultWatcher m_watcher;
|
||
};
|
||
|
||
template <typename PARENT_TYPE>
|
||
class SymbolResultWatcherQWidget : public SymbolResultWatcherQWidgetBase
|
||
{
|
||
using BaseClass = SymbolResultWatcherQWidgetBase;
|
||
public:
|
||
explicit SymbolResultWatcherQWidget(PARENT_TYPE *parentWidget, const QSize &size = QSize())
|
||
: BaseClass(parentWidget)
|
||
, m_size(size)
|
||
, m_parentWidget(parentWidget)
|
||
{}
|
||
|
||
private:
|
||
void onResultReadyImpl() override
|
||
{
|
||
if (!m_parentWidget)
|
||
return;
|
||
|
||
QSharedPointer<AdvancedSymbology::SymbolResult> symResult = m_watcher.symbolResult();
|
||
if (!symResult)
|
||
return; // should NEVER happen! (Which object should have triggered the signal???)
|
||
|
||
const SymbolImage &symImage = symResult->symbolImage();
|
||
const auto dpr = m_parentWidget->devicePixelRatioF();
|
||
QImage imgCopy;
|
||
if (m_size.isValid())
|
||
imgCopy = symImage.image().scaled(m_size * dpr, Qt::KeepAspectRatio, Qt::SmoothTransformation);
|
||
else
|
||
imgCopy = symImage.image();
|
||
imgCopy.setDevicePixelRatio(dpr);
|
||
|
||
m_parentWidget->setIcon(QPixmap::fromImage(std::move(imgCopy)));
|
||
|
||
{
|
||
QString tooltip;
|
||
|
||
QByteArray data;
|
||
QBuffer buffer(&data);
|
||
// XML-Symbol with scale = 4 will produce huge images. Limit the size:
|
||
symImage.image().scaled(QSize(300, 300), Qt::KeepAspectRatio, Qt::SmoothTransformation).save(&buffer, "PNG", 100);
|
||
|
||
tooltip = QStringLiteral("<html>");
|
||
|
||
tooltip += QStringLiteral("<center>");
|
||
tooltip += QStringLiteral("<img src='data:image/png;base64,%1'>").arg(QString::fromLatin1(data.toBase64()));
|
||
tooltip += QStringLiteral("</center>");
|
||
|
||
tooltip += QStringLiteral("<center>");
|
||
tooltip += symResult->symbolDataToRender().sidc;
|
||
tooltip += QStringLiteral("</center>");
|
||
|
||
tooltip += QStringLiteral("<hr>");
|
||
tooltip += QStringLiteral("</html>");
|
||
m_parentWidget->setToolTip(tooltip);
|
||
}
|
||
}
|
||
|
||
QSize m_size;
|
||
PARENT_TYPE *m_parentWidget;
|
||
};
|
||
|
||
//------------------------------------------------------------------------------
|
||
// for convenience (QLabel)
|
||
//------------------------------------------------------------------------------
|
||
/**
|
||
* @brief The SymbolResultWatcherLabel class can be used to combine a QLabel
|
||
* Here is an example:
|
||
*
|
||
* \code
|
||
* QLabel *label = new QLabel(this);
|
||
* AdvancedSymbology::SymbolResultWatcherLabel *symbolLabelWatcher(label);
|
||
*
|
||
*
|
||
*
|
||
* \endcode
|
||
*/
|
||
class ADVANCED_SYMBOLOGY_EXPORT SymbolResultWatcherLabel : public QObject
|
||
{
|
||
Q_OBJECT
|
||
|
||
public:
|
||
explicit SymbolResultWatcherLabel(QLabel *label, const QSize &size = QSize(45, 45));
|
||
|
||
void setSymbolResult(const QSharedPointer<AdvancedSymbology::SymbolResult> &symbolResult);
|
||
|
||
private slots:
|
||
void onResultReady();
|
||
|
||
private:
|
||
QSize m_size;
|
||
QLabel *m_label{nullptr};
|
||
AdvancedSymbology::SymbolResultWatcher m_watcher;
|
||
};
|
||
|
||
|
||
} // namespace AdvancedSymbology
|
||
|
||
Q_DECLARE_METATYPE_TEMPLATE_1ARG(AdvancedSymbology::ResultWatcher)
|