1089 lines
35 KiB
C++
Executable File
1089 lines
35 KiB
C++
Executable File
/**
|
||
* @RDE_HEADER@
|
||
* (Base) Symbol Model for Esri, XML, ETS Symbols
|
||
* $Id$
|
||
* $HeadURL$
|
||
* $Author$
|
||
* Created by Norbert Thoden, NLE, 12.12.2019
|
||
*/
|
||
|
||
// Own
|
||
#include "base_symbol_model.h"
|
||
#include "symbol_dictionary_impl.h"
|
||
#include "sidc_codec.h"
|
||
#include "sidc_builder_base.h"
|
||
|
||
#include <LtsWidgets/lts_column_filter_proxy_model.h>
|
||
#include <ngltools/ngltools_dtg.h>
|
||
|
||
|
||
// arcgis
|
||
#include <arcgis/TaskWatcher.h>
|
||
#include <arcgis/DictionarySymbolStyle.h>
|
||
|
||
|
||
// Qt
|
||
#include <QGuiApplication>
|
||
#include <QString>
|
||
#include <QUuid>
|
||
#include <QByteArray>
|
||
#include <QBuffer>
|
||
#include <QMimeData>
|
||
#include <QTimer>
|
||
|
||
|
||
namespace AdvancedSymbology
|
||
{
|
||
static constexpr int SWATCH_SIZE = 64;
|
||
static constexpr int ICON_SIZE_CUSTOM = 50;
|
||
|
||
|
||
QString geometryTypeToDisplayString(GeometryType geomType)
|
||
{
|
||
switch (geomType)
|
||
{
|
||
case GeometryType::Point:
|
||
return QObject::tr("Point");
|
||
case GeometryType::Polyline:
|
||
return QObject::tr("Line");
|
||
case GeometryType::Polygon:
|
||
return QObject::tr("Area");
|
||
case GeometryType::Undefined:
|
||
return QObject::tr("Undefined");
|
||
}
|
||
return QObject::tr("Undefined");
|
||
}
|
||
|
||
//------------------------------------------------------------------------------
|
||
// ResultWatcherData
|
||
//------------------------------------------------------------------------------
|
||
void ResultWatcherData::onResultReady()
|
||
{
|
||
if (!m_symbolResultWatcher)
|
||
return;
|
||
QSharedPointer<AdvancedSymbology::SymbolResult> symResult = m_symbolResultWatcher->symbolResult();
|
||
if (!symResult)
|
||
return; // should NEVER happen! (Which object should have triggered the signal???)
|
||
|
||
m_orgImage = symResult->symbolImage().image();
|
||
m_scaledImage = m_orgImage.scaled(ICON_SIZE_CUSTOM, ICON_SIZE_CUSTOM, Qt::KeepAspectRatio, Qt::SmoothTransformation);
|
||
|
||
// update view:
|
||
if (m_baseSymbolItem)
|
||
m_baseSymbolItem->emit_dataChanged();
|
||
}
|
||
|
||
|
||
//------------------------------------------------------------------------------
|
||
// BaseSymbolItem
|
||
//------------------------------------------------------------------------------
|
||
BaseSymbolItem::BaseSymbolItem(int id, Esri::ArcGISRuntime::Symbol *esriSymbol_Search)
|
||
: QObject()
|
||
{
|
||
m_id = id;
|
||
m_esriSearch.m_esriSymbol = esriSymbol_Search;
|
||
|
||
m_findBaseSymbolRWD = new ResultWatcherData(this);
|
||
m_findPreviewRWD = new ResultWatcherData(this);
|
||
m_findImageRWD = new ResultWatcherData(this);
|
||
}
|
||
|
||
BaseSymbolItem::BaseSymbolItem(int id, const QString &baseSymbolCode, const QString &operatorName, qint64 lastModified, const SymbologyXML::Symbol &symbol)
|
||
: QObject()
|
||
, m_id(id)
|
||
, m_operatorName(operatorName)
|
||
, m_lastModified(lastModified)
|
||
{
|
||
setXmlSymbol(symbol);
|
||
|
||
m_baseSymbolCode = baseSymbolCode;
|
||
|
||
m_findBaseSymbolRWD = new ResultWatcherData(this);
|
||
m_findPreviewRWD = new ResultWatcherData(this);
|
||
m_findImageRWD = new ResultWatcherData(this);
|
||
}
|
||
|
||
BaseSymbolItem::BaseSymbolItem(int id, const QString &baseSymbolCode, const QImage &image)
|
||
: QObject()
|
||
, m_id(id)
|
||
, m_baseSymbolCode(baseSymbolCode)
|
||
|
||
{
|
||
m_findBaseSymbolRWD = new ResultWatcherData(this);
|
||
m_findBaseSymbolRWD->image() = image;
|
||
m_findBaseSymbolRWD->originalImage() = image;
|
||
}
|
||
|
||
BaseSymbolItem::~BaseSymbolItem()
|
||
{
|
||
delete m_findBaseSymbolRWD;
|
||
delete m_findPreviewRWD;
|
||
delete m_findImageRWD;
|
||
delete m_xmlSymbol;
|
||
}
|
||
|
||
void BaseSymbolItem::setSymbolDictionary(SymbolDictionary *symbolDictionary)
|
||
{
|
||
m_symbolDictionaryImpl = static_cast<SymbolDictionaryImpl *>(symbolDictionary);
|
||
m_esriDictionary = const_cast<Esri::ArcGISRuntime::DictionarySymbolStyle *>(m_symbolDictionaryImpl->getEsriSymbolDictionary());
|
||
}
|
||
|
||
void BaseSymbolItem::setEsriSearchSymbol(Esri::ArcGISRuntime::Symbol *esriSymbol_Search)
|
||
{
|
||
m_esriSearch.m_esriSymbol = esriSymbol_Search;
|
||
}
|
||
|
||
void BaseSymbolItem::setXmlSymbol(const SymbologyXML::Symbol &symbol)
|
||
{
|
||
delete m_xmlSymbol;
|
||
if (!m_xmlSymbol)
|
||
m_xmlSymbol = new XmlSymbolStruct;
|
||
m_xmlSymbol->m_symbol = symbol;
|
||
}
|
||
|
||
QString BaseSymbolItem::baseSymbolCode()
|
||
{
|
||
if (m_baseSymbolCode.isEmpty() && m_symbolDictionaryImpl)
|
||
m_baseSymbolCode = AdvancedSymbology::SidcCodec::encodeBaseSymbolCode(m_symbolDictionaryImpl->symbologyType(),
|
||
m_symbolProperties.originalKey().left(8));
|
||
return m_baseSymbolCode;
|
||
}
|
||
|
||
QString BaseSymbolItem::sidc()
|
||
{
|
||
return AdvancedSymbology::SidcBuilderBase::baseSymbolCodeToSidc(baseSymbolCode());
|
||
}
|
||
|
||
QString BaseSymbolItem::symbolSet()
|
||
{
|
||
if (m_symbolSet.isEmpty())
|
||
{
|
||
SidcDefinitions::SymbolSet symbolSet = SidcDefinitions::castToSymbolSet(m_symbolProperties.originalKey().leftRef(2).toUInt());
|
||
m_symbolSet = QString(QStringLiteral("%1 - ")).arg(static_cast<int>(symbolSet)) + AdvancedSymbology::SidcDefinitions::toString(symbolSet);
|
||
}
|
||
return m_symbolSet;
|
||
}
|
||
|
||
int BaseSymbolItem::symbolSetAsInt()
|
||
{
|
||
return static_cast<int>(SidcDefinitions::castToSymbolSet(m_symbolProperties.originalKey().leftRef(2).toUInt()));
|
||
}
|
||
|
||
|
||
QString BaseSymbolItem::getTooltip(const QImage &image)
|
||
{
|
||
QString tooltip;
|
||
const AdvancedSymbology::SymbolProperties &symProp = m_symbolProperties;
|
||
|
||
QByteArray data;
|
||
QBuffer buffer(&data);
|
||
image.save(&buffer, "PNG", 100);
|
||
|
||
const QString paragraphBegin = QStringLiteral("<center>");
|
||
const QString paragraphEnd = QStringLiteral("</center>");
|
||
const QString separator = QStringLiteral("<br/>");
|
||
tooltip = QStringLiteral("<html>");
|
||
|
||
tooltip += paragraphBegin;
|
||
tooltip += QStringLiteral("<img src='data:image/png;base64,%1'>").arg(QString::fromLatin1(data.toBase64()));
|
||
tooltip += paragraphEnd; // + QStringLiteral("<hr>");
|
||
|
||
tooltip += paragraphBegin;
|
||
tooltip += symProp.name();
|
||
tooltip += paragraphEnd;
|
||
|
||
tooltip += paragraphBegin;
|
||
tooltip += baseSymbolCode();
|
||
tooltip += paragraphEnd;
|
||
|
||
tooltip += QStringLiteral("<hr>");
|
||
|
||
// tooltip += separator;
|
||
|
||
tooltip += paragraphBegin + geometryTypeToDisplayString(symProp.geometryType()) + paragraphEnd;
|
||
|
||
tooltip += QStringLiteral("<hr>");
|
||
tooltip += paragraphBegin + symProp.tags().join(separator) + paragraphEnd;
|
||
tooltip += QStringLiteral("</html>");
|
||
|
||
return tooltip;
|
||
}
|
||
|
||
QImage BaseSymbolItem::getSearchSwatch()
|
||
{
|
||
// if (!m_esriSearch.m_esriSymbol)
|
||
// m_esriSearch.m_esriSymbol = m_esriSearch.m_sssResult.symbol(this);
|
||
|
||
if (m_esriSearch.m_esriSwatch.isNull() && m_esriSearch.m_esriSymbol && m_esriSearch.m_esriTaskUuid.isNull())
|
||
{
|
||
// ok, create swatch now:
|
||
|
||
// qCritical() << " SEARCH: id=" << m_id << " create swatch now";
|
||
// qCritical() << " SEARCH: id=" << m_esriSearch.m_esriSymbol->toJson();
|
||
|
||
connect(m_esriSearch.m_esriSymbol, &Esri::ArcGISRuntime::Symbol::createSwatchCompleted,
|
||
this, &BaseSymbolItem::onEsriSearchSymbolSwatchCompleted, Qt::UniqueConnection);
|
||
|
||
const Esri::ArcGISRuntime::TaskWatcher &tw = m_esriSearch.m_esriSymbol->createSwatch(SWATCH_SIZE, SWATCH_SIZE, 1);
|
||
if (tw.isValid())
|
||
m_esriSearch.m_esriTaskUuid = tw.taskId();
|
||
else
|
||
qCritical() << " SEARCH: id=" << m_id << " taskId invalid";
|
||
}
|
||
return m_esriSearch.m_esriSwatch;
|
||
}
|
||
|
||
void BaseSymbolItem::onEsriSearchSymbolSwatchCompleted(const QUuid &taskId, const QImage &image)
|
||
{
|
||
if (m_esriSearch.m_esriTaskUuid != taskId)
|
||
return;
|
||
|
||
m_esriSearch.m_esriSwatch = image;
|
||
|
||
emit dataChanged(m_id);
|
||
}
|
||
|
||
QImage BaseSymbolItem::getFetchSwatch() const
|
||
{
|
||
if (!m_symbolDictionaryImpl || !m_symbolDictionaryImpl->getEsriSymbolDictionary())
|
||
return m_esriFetch.m_esriSwatch;
|
||
|
||
if (m_esriFetch.m_esriSwatch.isNull() && m_esriFetch.m_esriFetchTaskIdUuid.isNull())
|
||
{
|
||
connect(m_esriDictionary, &Esri::ArcGISRuntime::DictionarySymbolStyle::fetchSymbolCompleted,
|
||
this, &BaseSymbolItem::onEsriFetchCompleted, Qt::UniqueConnection);
|
||
|
||
// from key8 to sidc (20 digits)
|
||
const QString &key8 = m_symbolProperties.key().left(8);
|
||
|
||
// "10011500002102000000"
|
||
// 0123456789
|
||
|
||
m_esriFetch.m_sidc = QString(QStringLiteral("10011500002102000000"));
|
||
m_esriFetch.m_sidc.replace(4, 2, key8.left(2)); // SymbolSet
|
||
m_esriFetch.m_sidc.replace(10, 6, key8.right(6)); // Entity
|
||
|
||
// static int s_counter = 0;
|
||
// qCritical() << " FETCH: id=" << m_id << " fetch now"
|
||
// << " sidc='" << m_esriFetch.m_sidc << "'"
|
||
// << " s_counter=" << s_counter++;
|
||
|
||
const QVariantMap keys({{QStringLiteral("sidc"), m_esriFetch.m_sidc}, // SidcCodec::decodeRawSidc ; set sidc of symbol in case of MIL2525
|
||
{QStringLiteral("sic"), m_esriFetch.m_sidc}}); // SidcCodec::decodeRawSidc , set sidc of symbol in case of APP6
|
||
|
||
const Esri::ArcGISRuntime::TaskWatcher &tw = m_esriDictionary->fetchSymbol(keys);
|
||
if (tw.isValid())
|
||
m_esriFetch.m_esriFetchTaskIdUuid = tw.taskId();
|
||
else
|
||
qCritical() << " FETCH: id=" << m_id << " m_esriFetchTaskIdUuid invalid";
|
||
}
|
||
return m_esriFetch.m_esriSwatch;
|
||
}
|
||
|
||
void BaseSymbolItem::onEsriFetchCompleted(const QUuid &taskId, Esri::ArcGISRuntime::Symbol *symbol)
|
||
{
|
||
if (m_esriFetch.m_esriFetchTaskIdUuid != taskId)
|
||
return;
|
||
|
||
// save intermediate result:
|
||
m_esriFetch.m_esriSymbol = symbol;
|
||
|
||
// start creating swatch of fetched symbol:
|
||
connect(m_esriFetch.m_esriSymbol, &Esri::ArcGISRuntime::Symbol::createSwatchCompleted,
|
||
this, &BaseSymbolItem::onEsriFetchSymbolSwatchCompleted, Qt::UniqueConnection);
|
||
|
||
const Esri::ArcGISRuntime::TaskWatcher &tw = m_esriFetch.m_esriSymbol->createSwatch(SWATCH_SIZE, SWATCH_SIZE, 1);
|
||
if (tw.isValid())
|
||
m_esriFetch.m_esriSwatchTaskUuid = tw.taskId();
|
||
else
|
||
qCritical() << " FETCH: id=" << m_id << " taskId invalid";
|
||
}
|
||
|
||
void BaseSymbolItem::onEsriFetchSymbolSwatchCompleted(const QUuid &taskId, const QImage &image)
|
||
{
|
||
if (m_esriFetch.m_esriSwatchTaskUuid != taskId)
|
||
return;
|
||
|
||
m_esriFetch.m_esriSwatch = image;
|
||
|
||
// qCritical() << " FETCH: id=" << m_id << " image " << image.size();
|
||
|
||
emit dataChanged(m_id);
|
||
}
|
||
|
||
|
||
|
||
//------------------------------------------------------------------------------
|
||
// BaseSymbolModel::Private
|
||
//------------------------------------------------------------------------------
|
||
struct BaseSymbolModel::Private
|
||
{
|
||
SymbolDictionaryImpl *m_symbolDictionaryImpl = nullptr;
|
||
Esri::ArcGISRuntime::DictionarySymbolStyle *m_esriDictionary = nullptr;
|
||
|
||
// findBaseSymbol-Uuid -> SymbolResult
|
||
mutable QMap<QUuid, QWeakPointer<SymbolResult>> m_findBaseSymbol2symbolResult;
|
||
|
||
QTimer *m_finishInitializationTimer = nullptr;
|
||
|
||
// For proxyModel
|
||
QSet<QString> m_usedOperator;
|
||
QMap<int, QString> m_usedSymbolSet;
|
||
QSet<QString> m_usedSymbolClass;
|
||
QSet<double> m_usedXmlSymbolScale;
|
||
QSet<AdvancedSymbology::GeometryType> m_usedGeometryTypes;
|
||
QSet<QString> m_usedCategory;
|
||
QSet<QString> m_usedGctStrings;
|
||
};
|
||
|
||
|
||
//------------------------------------------------------------------------------
|
||
// BaseSymbolModel
|
||
//------------------------------------------------------------------------------
|
||
BaseSymbolModel::BaseSymbolModel(SymbolDictionary *symbolDictionary)
|
||
: BaseClass(
|
||
{
|
||
tr("Id"),
|
||
|
||
tr("SearchIcon"), // de: so lassen
|
||
tr("FetchIcon"), // de: so lassen
|
||
|
||
tr("Icon"), // ((SD-findBaseSymbol))
|
||
tr("SD-findPreview"),
|
||
tr("SD-findImage"),
|
||
|
||
tr("Org_key"),
|
||
tr("Key"),
|
||
tr("BaseSymbolCode"), // de: so lassen
|
||
tr("Sidc"),
|
||
tr("SymbolSet"), // de: Symbolset
|
||
tr("Name"),
|
||
|
||
tr("Operator"), // de: Benutzer
|
||
tr("last modified"), // de: letzte Änderung (analog zu flm)
|
||
|
||
tr("Scale"), // ((XmlSymbolSize)) de: Skalierung (analog zum SymbolEditor)
|
||
tr("Category"), // de: so lassen
|
||
tr("SymbolClass"), // de: so lassen
|
||
tr("Tags"), // de: so lassen
|
||
tr("GCTString"), // de: so lassen
|
||
tr("GeometryType") // de: Geometrytyp
|
||
},
|
||
symbolDictionary) // parent
|
||
, m_logger(getLogger("BaseSymbolModel"))
|
||
, d(new Private())
|
||
{
|
||
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
|
||
|
||
d->m_symbolDictionaryImpl = static_cast<SymbolDictionaryImpl *>(symbolDictionary);
|
||
d->m_esriDictionary = const_cast<Esri::ArcGISRuntime::DictionarySymbolStyle *>(d->m_symbolDictionaryImpl->getEsriSymbolDictionary());
|
||
|
||
|
||
//// QString path = QStringLiteral("/usr/share/arcgis/resources/symbols/mil2525d/mil2525d.stylx");
|
||
// QString path = QStringLiteral("/usr/share/arcgis/resources/symbols_arcade/mil2525d/mil2525d.stylx");
|
||
|
||
// d->m_esri_dictionary = Esri::ArcGISRuntime::DictionarySymbolStyle::createFromFile(path, this);
|
||
|
||
// if (d->m_esri_dictionary)
|
||
// {
|
||
// connect(d->m_esri_dictionary, &Esri::ArcGISRuntime::DictionarySymbolStyle::loadStatusChanged,
|
||
// this, &BaseSymbolModel::onLoadStatusChanged);
|
||
// connect(d->m_esri_dictionary, &Esri::ArcGISRuntime::DictionarySymbolStyle::errorOccurred,
|
||
// this, &BaseSymbolModel::onErrorDictionary);
|
||
// }
|
||
// d->m_esri_dictionary->load();
|
||
|
||
|
||
d->m_finishInitializationTimer = new QTimer(this);
|
||
d->m_finishInitializationTimer->setSingleShot(true);
|
||
d->m_finishInitializationTimer->setInterval(500);
|
||
|
||
connect(d->m_finishInitializationTimer, &QTimer::timeout,
|
||
this, &BaseSymbolModel::onFinishInitalization);
|
||
|
||
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
|
||
}
|
||
|
||
BaseSymbolModel::~BaseSymbolModel()
|
||
{
|
||
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
|
||
delete d->m_finishInitializationTimer;
|
||
delete d;
|
||
d = nullptr;
|
||
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
|
||
}
|
||
|
||
void BaseSymbolModel::onLoadStatusChanged(Esri::ArcGISRuntime::LoadStatus loadStatus)
|
||
{
|
||
if (loadStatus == Esri::ArcGISRuntime::LoadStatus::Loaded)
|
||
{
|
||
INFO_LOG(m_logger) << LOGFUNCTION << " ***** m_esri_dictionary " << d->m_esriDictionary
|
||
<< " loading done ";
|
||
}
|
||
}
|
||
|
||
void BaseSymbolModel::onErrorDictionary(const Esri::ArcGISRuntime::Error &error)
|
||
{
|
||
FATAL_LOG(m_logger) << LOGFUNCTION << " ---EsriError--- occured: "
|
||
<< " code=" << error.code()
|
||
<< ", domain=" << static_cast<int>(error.domain())
|
||
<< ", extendedErrorType=" << static_cast<int>(error.extendedErrorType())
|
||
<< ", message='" << error.message() << "'"
|
||
<< ", additionalMessage='" << error.additionalMessage() << "'";
|
||
}
|
||
|
||
void BaseSymbolModel::initModel(SymbolDictionary *symbolDictionary,
|
||
const QList<Esri::ArcGISRuntime::SymbolStyleSearchResult> &searchResultList,
|
||
const SidcCodec::SidcHashTable<SymbolProperties> &baseSymbolCodeToSymbolPropertyTable)
|
||
{
|
||
clear();
|
||
|
||
int itemCounter = 0;
|
||
QVector<DATA_T> vecData;
|
||
vecData.reserve(searchResultList.size());
|
||
for (const Esri::ArcGISRuntime::SymbolStyleSearchResult &searchResult : qAsConst(searchResultList))
|
||
{
|
||
GeometryType gt = GeometryType::Undefined;
|
||
auto it = baseSymbolCodeToSymbolPropertyTable.find(searchResult.key().left(8));
|
||
if (it != baseSymbolCodeToSymbolPropertyTable.end())
|
||
gt = it->geometryType();
|
||
#ifndef LTS_DEBUG
|
||
else
|
||
continue; /// release mode -> skip entries with GeometryType::Undefined
|
||
#endif // LTS_DEBUG
|
||
|
||
|
||
// spend time to create (expensive) Esri::ArcGISRuntime::Symbol?
|
||
#ifdef LTS_DEBUG
|
||
Esri::ArcGISRuntime::Symbol *esriSymbol = nullptr;
|
||
const bool showAll = QGuiApplication::keyboardModifiers().testFlag(Qt::KeyboardModifier::ControlModifier);
|
||
if (showAll)
|
||
esriSymbol = searchResult.symbol(this); // symbol() has to be called from mainThread, is expensive / time consuming
|
||
#else
|
||
// release mode: save time, won´t be visible
|
||
Esri::ArcGISRuntime::Symbol *esriSymbol = nullptr;
|
||
#endif // LTS_DEBUG
|
||
|
||
|
||
BaseSymbolItem *bsi = new BaseSymbolItem(itemCounter++, esriSymbol);
|
||
|
||
bsi->setSymbolDictionary(symbolDictionary);
|
||
|
||
bsi->m_symbolProperties.setTags(searchResult.tags());
|
||
bsi->m_symbolProperties.setName(searchResult.name());
|
||
bsi->m_symbolProperties.setSymbolClass(searchResult.symbolClass());
|
||
bsi->m_symbolProperties.setCategory(searchResult.category());
|
||
bsi->m_symbolProperties.setKey(searchResult.key().left(8));
|
||
bsi->m_symbolProperties.setOriginalKey(searchResult.key()); // searchResult does not have orgKey
|
||
bsi->m_symbolProperties.setGeometryType(gt);
|
||
|
||
connect(bsi, &BaseSymbolItem::dataChanged,
|
||
this, &BaseSymbolModel::onDataChanged);
|
||
|
||
vecData.append(DATA_T(bsi));
|
||
} // for
|
||
this->setData(vecData);
|
||
|
||
triggerFinishInitalization();
|
||
}
|
||
|
||
bool BaseSymbolModel::insertXmlSymbol(int fileId, const QString &operatorName, qint64 lastModified, const SymbologyXML::Symbol &symbol, const SymbolProperties &properties)
|
||
{
|
||
INFO_LOG(m_logger) << LOGFUNCTION << " START"
|
||
<< ", fileId=" << fileId
|
||
<< ", operatorName='" << operatorName << "'"
|
||
<< ", lastModified=" << lastModified
|
||
<< ", symbol.id=" << symbol.id()
|
||
<< ", symbol.getName=" << symbol.getName();
|
||
if (fileId < 0)
|
||
{
|
||
FATAL_LOG(m_logger) << " fileId not valid. fileId=" << fileId;
|
||
return false;
|
||
}
|
||
if (!symbol.isValid())
|
||
{
|
||
FATAL_LOG(m_logger) << " symbol not valid. fileId=" << fileId;
|
||
return false;
|
||
}
|
||
|
||
BaseSymbolItem *bsi = new BaseSymbolItem(fileId, SidcCodec::encodeCivilXml(QString::number(fileId)),
|
||
operatorName, lastModified, symbol);
|
||
bsi->m_symbolProperties = properties;
|
||
connect(bsi, &BaseSymbolItem::dataChanged, this, &BaseSymbolModel::onDataChanged);
|
||
|
||
// insert or update?
|
||
const int row = findRowForId(fileId);
|
||
if (row >= 0)
|
||
setRowData(row, DATA_T(bsi));
|
||
else
|
||
insertRow(DATA_T(bsi));
|
||
|
||
triggerFinishInitalization();
|
||
|
||
return true;
|
||
}
|
||
|
||
bool BaseSymbolModel::removeXmlSymbol(int fileId)
|
||
{
|
||
if (fileId < 0)
|
||
{
|
||
FATAL_LOG(m_logger) << " fileId not valid. fileId=" << fileId;
|
||
return false;
|
||
}
|
||
|
||
const int row = findRowForId(fileId);
|
||
return this->removeRow(row);
|
||
}
|
||
|
||
bool BaseSymbolModel::insertEtsSymbol(int fileId, const QString &sidc, const SymbolProperties &properties, const QImage &image)
|
||
{
|
||
TRACE_LOG(m_logger) << LOGFUNCTION << " START" << ", sidc='" << sidc << "'";
|
||
if (sidc.isEmpty())
|
||
return false;
|
||
|
||
BaseSymbolItem *bsi = new BaseSymbolItem(fileId, sidc, image);
|
||
bsi->m_symbolProperties = properties;
|
||
|
||
// not required for ETS:
|
||
// connect(bsi, &BaseSymbolItem::dataChanged,
|
||
// this, &BaseSymbolModel::onDataChanged);
|
||
|
||
// insert or update?
|
||
const int row = findRowForId(fileId);
|
||
if (row >= 0)
|
||
setRowData(row, DATA_T(bsi));
|
||
else
|
||
insertRow(DATA_T(bsi));
|
||
|
||
triggerFinishInitalization();
|
||
|
||
return true;
|
||
}
|
||
|
||
bool BaseSymbolModel::removeEtsSymbol(int fileId)
|
||
{
|
||
return removeXmlSymbol(fileId);
|
||
}
|
||
|
||
void BaseSymbolModel::triggerFinishInitalization()
|
||
{
|
||
d->m_finishInitializationTimer->start();
|
||
}
|
||
|
||
void BaseSymbolModel::onFinishInitalization()
|
||
{
|
||
qDebug() << LOGFUNCTION << " START";
|
||
|
||
connect(this, &BaseSymbolModel::rowsInserted, this, &BaseSymbolModel::onUpdateUsedItemsForComboBox, Qt::QueuedConnection);
|
||
connect(this, &BaseSymbolModel::rowsRemoved, this, &BaseSymbolModel::onUpdateUsedItemsForComboBox, Qt::QueuedConnection);
|
||
connect(this, &BaseSymbolModel::modelReset, this, &BaseSymbolModel::onUpdateUsedItemsForComboBox, Qt::QueuedConnection);
|
||
|
||
onUpdateUsedItemsForComboBox();
|
||
}
|
||
|
||
|
||
QVariant BaseSymbolModel::headerData(int section, Qt::Orientation orientation, int role) const
|
||
{
|
||
if (role == LtsWidgets::LtsColumnFilterProxyModel::ComboboxFilterRole &&
|
||
orientation == Qt::Horizontal)
|
||
{
|
||
if (section == OPERATOR_NAME)
|
||
{
|
||
LtsWidgets::ComboboxFilterContent cfc;
|
||
cfc.sortItems = true;
|
||
cfc.data.reserve(d->m_usedOperator.size());
|
||
LtsWidgets::ComboboxFilterData cfd;
|
||
for (const QString &opName : qAsConst(d->m_usedOperator))
|
||
{
|
||
cfd.data = opName;
|
||
cfd.text = opName;
|
||
cfc.data.push_back(cfd);
|
||
}
|
||
return cfc.toVariant();
|
||
}
|
||
else if (section == SYMBOL_SET)
|
||
{
|
||
LtsWidgets::ComboboxFilterContent cfc;
|
||
cfc.data.reserve(d->m_usedSymbolSet.size());
|
||
LtsWidgets::ComboboxFilterData cfd;
|
||
for (const auto &symSet : qAsConst(d->m_usedSymbolSet))
|
||
{
|
||
cfd.data = symSet;
|
||
cfd.text = symSet;
|
||
cfc.data.push_back(cfd);
|
||
}
|
||
return cfc.toVariant();
|
||
}
|
||
else if (section == SYMBOLCLASS)
|
||
{
|
||
LtsWidgets::ComboboxFilterContent cfc;
|
||
cfc.data.reserve(d->m_usedSymbolClass.size());
|
||
LtsWidgets::ComboboxFilterData cfd;
|
||
for (const auto &sc : qAsConst(d->m_usedSymbolClass))
|
||
{
|
||
cfd.data = sc;
|
||
cfd.text = sc;
|
||
cfc.data.push_back(cfd);
|
||
}
|
||
return cfc.toVariant();
|
||
}
|
||
else if (section == XML_SYMBOL_SIZE)
|
||
{
|
||
LtsWidgets::ComboboxFilterContent cfc;
|
||
cfc.sortItems = true;
|
||
cfc.data.reserve(d->m_usedXmlSymbolScale.size());
|
||
LtsWidgets::ComboboxFilterData cfd;
|
||
for (const auto &symScale : qAsConst(d->m_usedXmlSymbolScale))
|
||
{
|
||
cfd.data = symScale;
|
||
cfd.text = QString::number(symScale);
|
||
cfc.data.push_back(cfd);
|
||
}
|
||
return cfc.toVariant();
|
||
}
|
||
else if (section == GEOMETRYTYPE)
|
||
{
|
||
LtsWidgets::ComboboxFilterContent cfc;
|
||
cfc.data.reserve(d->m_usedGeometryTypes.size());
|
||
LtsWidgets::ComboboxFilterData cfd;
|
||
for (const AdvancedSymbology::GeometryType > : qAsConst(d->m_usedGeometryTypes))
|
||
{
|
||
cfd.data = (int)gt;
|
||
cfd.text = geometryTypeToDisplayString(gt);
|
||
cfc.data.push_back(cfd);
|
||
}
|
||
return cfc.toVariant();
|
||
}
|
||
else if (section == CATEGORY)
|
||
{
|
||
LtsWidgets::ComboboxFilterContent cfc;
|
||
cfc.sortItems = true;
|
||
cfc.data.reserve(d->m_usedCategory.size());
|
||
LtsWidgets::ComboboxFilterData cfd;
|
||
for (const auto &cat : qAsConst(d->m_usedCategory))
|
||
{
|
||
cfd.data = cat;
|
||
cfd.text = cat;
|
||
cfc.data.push_back(cfd);
|
||
}
|
||
return cfc.toVariant();
|
||
}
|
||
else if (section == GCTSTRING)
|
||
{
|
||
LtsWidgets::ComboboxFilterContent cfc;
|
||
cfc.sortItems = true;
|
||
cfc.data.reserve(d->m_usedGctStrings.size());
|
||
LtsWidgets::ComboboxFilterData cfd;
|
||
for (const auto &gctStr : qAsConst(d->m_usedGctStrings))
|
||
{
|
||
cfd.data = gctStr;
|
||
cfd.text = gctStr;
|
||
cfc.data.push_back(cfd);
|
||
}
|
||
return cfc.toVariant();
|
||
}
|
||
}
|
||
|
||
return BaseClass::headerData(section, orientation, role);
|
||
}
|
||
|
||
QVariant BaseSymbolModel::data(const QModelIndex &index, int role) const
|
||
{
|
||
if ((role == Qt::SizeHintRole) &&
|
||
((index.column() == SEARCH_ICON) ||
|
||
(index.column() == FETCH_ICON) ||
|
||
(index.column() == FIND_BASE_SYMBOL) ||
|
||
(index.column() == FIND_PREVIEW) ||
|
||
(index.column() == FIND_IMAGE)
|
||
))
|
||
return QSize(SWATCH_SIZE, SWATCH_SIZE);
|
||
|
||
if ((role != Qt::DisplayRole) &&
|
||
(role != Qt::DecorationRole) &&
|
||
(role != Qt::ToolTipRole) &&
|
||
// role != Qt::EditRole // required by QDataWidgetMapper
|
||
(role != LtsWidgets::LtsColumnFilterProxyModel::ComboboxFilterRole)
|
||
)
|
||
return QVariant();
|
||
|
||
const DATA_T &item = m_vecData.at(index.row());
|
||
|
||
if (!item)
|
||
return QVariant();
|
||
|
||
const QString &baseSymbolCode = item->baseSymbolCode();
|
||
|
||
if (role == Qt::DecorationRole)
|
||
{
|
||
switch (index.column())
|
||
{
|
||
case SEARCH_ICON:
|
||
return item->getSearchSwatch();
|
||
case FETCH_ICON:
|
||
return item->getFetchSwatch();
|
||
|
||
case FIND_BASE_SYMBOL:
|
||
{
|
||
ResultWatcherData *rwd = item->m_findBaseSymbolRWD;
|
||
if (rwd)
|
||
{
|
||
if (rwd->image().isNull())
|
||
{
|
||
// setup temporaryImage until finished/resultReady:
|
||
// store that at rwd to avoid unwanted findImage/findBaseSymbol/...
|
||
rwd->image() = AdvancedSymbology::SymbolDictionary::temporaryImage();
|
||
|
||
rwd->getResultWatcher()->setSymbolResult(d->m_symbolDictionaryImpl->findBaseSymbol(baseSymbolCode));
|
||
}
|
||
return rwd->image();
|
||
}
|
||
}
|
||
break;
|
||
|
||
case FIND_PREVIEW:
|
||
{
|
||
ResultWatcherData *rwd = item->m_findPreviewRWD;
|
||
if (rwd)
|
||
{
|
||
if (rwd->image().isNull())
|
||
{
|
||
// setup temporaryImage until finished/resultReady:
|
||
// store that at rwd to avoid unwanted findImage/findBaseSymbol/...
|
||
rwd->image() = AdvancedSymbology::SymbolDictionary::temporaryImage();
|
||
|
||
rwd->getResultWatcher()->setSymbolResult(d->m_symbolDictionaryImpl->findPreview(SidcBuilderBase::baseSymbolCodeToSidc(baseSymbolCode)));
|
||
}
|
||
return rwd->image();
|
||
}
|
||
}
|
||
break;
|
||
|
||
case FIND_IMAGE:
|
||
{
|
||
ResultWatcherData *rwd = item->m_findImageRWD;
|
||
if (rwd)
|
||
{
|
||
if (rwd->image().isNull())
|
||
{
|
||
|
||
AdvancedSymbology::SymbolDataToRender symDataToRender;
|
||
// symDataToRender.sidc = SidcCodec::isCivil(sidc) ? sidc : SidcBuilderBase::baseSymbolCodeToSidc(sidc);
|
||
symDataToRender.sidc = SidcBuilderBase::baseSymbolCodeToSidc(baseSymbolCode);
|
||
symDataToRender.fillColor = Qt::red;
|
||
symDataToRender.fillColorReplace = true;
|
||
symDataToRender.injury = Injury::TotalKill;
|
||
symDataToRender.injuryColor = Qt::gray;
|
||
symDataToRender.injuryColor.setAlphaF(0.2);
|
||
|
||
symDataToRender.additionalSymbols.insert(AdditionalSymbolType::BiteError);
|
||
symDataToRender.additionalSymbols.insert(AdditionalSymbolType::Manipulation);
|
||
symDataToRender.additionalSymbols.insert(AdditionalSymbolType::NbcProtection);
|
||
symDataToRender.additionalSymbols.insert(AdditionalSymbolType::NoPosition);
|
||
|
||
// setup temporaryImage until finished/resultReady:
|
||
// store that at rwd to avoid unwanted findImage/findBaseSymbol/...
|
||
rwd->image() = AdvancedSymbology::SymbolDictionary::temporaryImage(symDataToRender.sizeL);
|
||
|
||
rwd->getResultWatcher()->setSymbolResult(d->m_symbolDictionaryImpl->findImage(symDataToRender));
|
||
|
||
}
|
||
return rwd->image();
|
||
}
|
||
}
|
||
break;
|
||
|
||
} // switch
|
||
|
||
return QVariant(); // otherwise we get into next if statement
|
||
|
||
} // if (role == Qt::DecorationRole)
|
||
|
||
if ((role == Qt::DisplayRole) || (role == Qt::EditRole) || (role != LtsWidgets::LtsColumnFilterProxyModel::ComboboxFilterRole))
|
||
{
|
||
const AdvancedSymbology::SymbolProperties &symbolProperties = item->m_symbolProperties;
|
||
|
||
switch (index.column())
|
||
{
|
||
case ID:
|
||
return item->m_id;
|
||
case ORIGINAL_KEY:
|
||
return symbolProperties.originalKey();
|
||
case KEY:
|
||
return symbolProperties.key();
|
||
case BASE_SYMBOL_CODE:
|
||
return item->baseSymbolCode();
|
||
case SIDC:
|
||
return item->sidc();
|
||
// return symbolProperties.sidc();
|
||
case SYMBOL_SET:
|
||
return item->symbolSet();
|
||
case NAME:
|
||
return symbolProperties.name();
|
||
|
||
case OPERATOR_NAME:
|
||
return item->m_operatorName;
|
||
case LAST_MODIFIED:
|
||
return DTG::toStringMSec(item->m_lastModified);
|
||
|
||
case XML_SYMBOL_SIZE:
|
||
if (item->m_xmlSymbol)
|
||
return item->m_xmlSymbol->m_symbol.getScale();
|
||
return QVariant();
|
||
|
||
case CATEGORY:
|
||
return symbolProperties.category();
|
||
case SYMBOLCLASS:
|
||
return symbolProperties.symbolClass();
|
||
case TAGS:
|
||
return symbolProperties.tags().join(QLatin1Char(';'));
|
||
case GCTSTRING:
|
||
return symbolProperties.gctString();
|
||
case GEOMETRYTYPE:
|
||
return AdvancedSymbology::toString(symbolProperties.geometryType());
|
||
|
||
} // switch
|
||
} // if (role == Qt::DisplayRole)
|
||
|
||
|
||
if (role == Qt::ToolTipRole)
|
||
{
|
||
switch (index.column())
|
||
{
|
||
case SEARCH_ICON:
|
||
return item->getTooltip(item->getSearchSwatch());
|
||
case FETCH_ICON:
|
||
return item->getTooltip(item->getFetchSwatch());
|
||
case FIND_BASE_SYMBOL:
|
||
return item->getTooltip(item->m_findBaseSymbolRWD->originalImage());
|
||
case FIND_PREVIEW:
|
||
return item->getTooltip(item->m_findPreviewRWD->originalImage());
|
||
case FIND_IMAGE:
|
||
return item->getTooltip(item->m_findImageRWD->originalImage());
|
||
default:
|
||
break;
|
||
} //switch
|
||
return item->getTooltip(item->m_findImageRWD->originalImage());
|
||
}
|
||
else if (role == LtsWidgets::LtsColumnFilterProxyModel::ComboboxFilterRole)
|
||
{
|
||
if (index.column() == OPERATOR_NAME)
|
||
return item->m_operatorName;
|
||
if (index.column() == SYMBOL_SET)
|
||
return item->symbolSet();
|
||
if (index.column() == CATEGORY)
|
||
return item->m_symbolProperties.category();
|
||
if (index.column() == SYMBOLCLASS)
|
||
return item->m_symbolProperties.symbolClass();
|
||
if (index.column() == GCTSTRING)
|
||
return item->m_symbolProperties.gctString();
|
||
if (index.column() == GEOMETRYTYPE)
|
||
return (int)item->m_symbolProperties.geometryType();
|
||
if (index.column() == XML_SYMBOL_SIZE)
|
||
if (item->m_xmlSymbol)
|
||
return item->m_xmlSymbol->m_symbol.getScale();
|
||
}
|
||
|
||
return QVariant();
|
||
}
|
||
|
||
|
||
int BaseSymbolModel::findRowForBaseSymbolCode(const QString &baseSymbolCode)
|
||
{
|
||
int row = -1;
|
||
for (int i = 0; i < m_vecData.size(); ++i)
|
||
{
|
||
const DATA_T &item = m_vecData.at(i);
|
||
if (!item)
|
||
continue;
|
||
if (item->baseSymbolCode() == baseSymbolCode)
|
||
row = i;
|
||
} // for
|
||
return row;
|
||
}
|
||
|
||
|
||
void BaseSymbolModel::onDataChanged(int id)
|
||
{
|
||
// FATAL_LOG(m_logger) << LOGFUNCTION << " START, id=" << id;
|
||
|
||
// new image -> update view:
|
||
|
||
int row = findRowForId(id);
|
||
emit dataChanged(index(row, 0), index(row, LtsAbstractTableModel::columnCount(QModelIndex()) - 1));
|
||
}
|
||
|
||
void BaseSymbolModel::onUpdateUsedItemsForComboBox()
|
||
{
|
||
d->m_usedOperator.clear();
|
||
d->m_usedSymbolSet.clear();
|
||
d->m_usedSymbolClass.clear();
|
||
d->m_usedXmlSymbolScale.clear();
|
||
d->m_usedGeometryTypes.clear();
|
||
d->m_usedCategory.clear();
|
||
d->m_usedGctStrings.clear();
|
||
|
||
for (const QSharedPointer<BaseSymbolItem> &item : qAsConst(m_vecData))
|
||
{
|
||
if (!item)
|
||
continue;
|
||
d->m_usedOperator.insert(item->m_operatorName);
|
||
d->m_usedSymbolSet.insert(item->symbolSetAsInt(), item->symbolSet());
|
||
d->m_usedSymbolClass.insert(item->m_symbolProperties.symbolClass());
|
||
if (item->m_xmlSymbol)
|
||
d->m_usedXmlSymbolScale.insert(item->m_xmlSymbol->m_symbol.getScale());
|
||
d->m_usedGeometryTypes.insert(item->m_symbolProperties.geometryType());
|
||
d->m_usedCategory.insert(item->m_symbolProperties.category());
|
||
d->m_usedGctStrings.insert(item->m_symbolProperties.gctString());
|
||
}
|
||
d->m_usedGctStrings.remove(QString());
|
||
}
|
||
|
||
|
||
SymbolProperties BaseSymbolModel::symbolProperties(const QString &baseSymbolCode)
|
||
{
|
||
// bisher aus m_baseSymbolCodeToSymbolPropertyTable beantwortet:
|
||
|
||
SymbolProperties symbolProperties;
|
||
for (const auto &item : qAsConst(m_vecData))
|
||
{
|
||
if (item->baseSymbolCode() != baseSymbolCode)
|
||
continue;
|
||
|
||
symbolProperties = item->m_symbolProperties;
|
||
}
|
||
return symbolProperties;
|
||
}
|
||
|
||
|
||
//------------------------------------------------------------------------------
|
||
// BaseSymbolProxyModel
|
||
//------------------------------------------------------------------------------
|
||
BaseSymbolProxyModel::BaseSymbolProxyModel(QObject *parent)
|
||
: BaseClass(parent)
|
||
{
|
||
}
|
||
|
||
void BaseSymbolProxyModel::setSourceModel(QAbstractItemModel *sourceModel)
|
||
{
|
||
m_sourceModel = qobject_cast<BaseSymbolModel *>(sourceModel);
|
||
BaseClass::setSourceModel(sourceModel);
|
||
}
|
||
|
||
bool BaseSymbolProxyModel::filterPoints() const
|
||
{
|
||
return m_geometrySet.contains(AdvancedSymbology::GeometryType::Point);
|
||
}
|
||
bool BaseSymbolProxyModel::filterLines() const
|
||
{
|
||
return m_geometrySet.contains(AdvancedSymbology::GeometryType::Polyline);
|
||
}
|
||
bool BaseSymbolProxyModel::filterAreas() const
|
||
{
|
||
return m_geometrySet.contains(AdvancedSymbology::GeometryType::Polygon);
|
||
}
|
||
|
||
QSet<QString> BaseSymbolProxyModel::validBaseSymbolCodes() const
|
||
{
|
||
return m_validBaseSymbolCodes;
|
||
}
|
||
|
||
void BaseSymbolProxyModel::setValidBaseSymbolCodes(const QSet<QString> &validBaseSymbolCodes)
|
||
{
|
||
m_validBaseSymbolCodes = validBaseSymbolCodes;
|
||
invalidateFilter();
|
||
}
|
||
|
||
void BaseSymbolProxyModel::onFilterPoints(bool on)
|
||
{
|
||
if (on)
|
||
m_geometrySet.insert(AdvancedSymbology::GeometryType::Point);
|
||
else
|
||
m_geometrySet.remove(AdvancedSymbology::GeometryType::Point);
|
||
invalidateFilter();
|
||
}
|
||
void BaseSymbolProxyModel::onFilterLines(bool on)
|
||
{
|
||
if (on)
|
||
m_geometrySet.insert(AdvancedSymbology::GeometryType::Polyline);
|
||
else
|
||
m_geometrySet.remove(AdvancedSymbology::GeometryType::Polyline);
|
||
invalidateFilter();
|
||
}
|
||
void BaseSymbolProxyModel::onFilterAreas(bool on)
|
||
{
|
||
if (on)
|
||
m_geometrySet.insert(AdvancedSymbology::GeometryType::Polygon);
|
||
else
|
||
m_geometrySet.remove(AdvancedSymbology::GeometryType::Polygon);
|
||
invalidateFilter();
|
||
}
|
||
|
||
bool BaseSymbolProxyModel::filterAcceptsRow(int source_row, const QModelIndex &source_parent) const
|
||
{
|
||
if (!m_sourceModel || source_parent.isValid() || source_row < 0 || source_row >= m_sourceModel->rowCount())
|
||
return LtsWidgets::LtsColumnFilterProxyModel::filterAcceptsRow(source_row, source_parent);
|
||
|
||
const QSharedPointer<BaseSymbolItem> &item = m_sourceModel->getRowData(source_row);
|
||
|
||
if (item)
|
||
{
|
||
// check geometryType
|
||
GeometryType symbolGeometry = item->m_symbolProperties.geometryType();
|
||
if (!m_geometrySet.contains(symbolGeometry))
|
||
return false;
|
||
|
||
// check m_validBaseSymbolCodes
|
||
if (!m_validBaseSymbolCodes.isEmpty() && !m_validBaseSymbolCodes.contains(item->baseSymbolCode()))
|
||
return false;
|
||
}
|
||
|
||
return LtsWidgets::LtsColumnFilterProxyModel::filterAcceptsRow(source_row, source_parent);
|
||
}
|
||
|
||
bool BaseSymbolProxyModel::lessThan(const QModelIndex &source_left, const QModelIndex &source_right) const
|
||
{
|
||
if (!m_sourceModel ||
|
||
source_left.column() != source_right.column() ||
|
||
source_left.row() < 0 || source_left.row() >= m_sourceModel->m_vecData.size() ||
|
||
source_right.row() < 0 || source_right.row() >= m_sourceModel->m_vecData.size()
|
||
)
|
||
return BaseClass::lessThan(source_left, source_right);
|
||
|
||
|
||
const QSharedPointer<BaseSymbolItem> &left = m_sourceModel->m_vecData.at(source_left.row());
|
||
const QSharedPointer<BaseSymbolItem> &right = m_sourceModel->m_vecData.at(source_right.row());
|
||
switch (source_left.column())
|
||
{
|
||
case BaseSymbolModel::Columns::ID:
|
||
return left->m_id < right->m_id;
|
||
|
||
case BaseSymbolModel::Columns::OPERATOR_NAME:
|
||
return left->m_operatorName < right->m_operatorName;
|
||
case BaseSymbolModel::Columns::LAST_MODIFIED:
|
||
return left->m_lastModified < right->m_lastModified;
|
||
|
||
case BaseSymbolModel::Columns::BASE_SYMBOL_CODE:
|
||
return left->baseSymbolCode() < right->baseSymbolCode();
|
||
|
||
// case BaseSymbolModel::Columns::ORIGINAL_KEY:
|
||
// return left->m_symbolProperties.originalKey() < right->m_symbolProperties.originalKey();
|
||
// case BaseSymbolModel::Columns::KEY:
|
||
// return left->m_symbolProperties.key() < right->m_symbolProperties.key();
|
||
// case BaseSymbolModel::Columns::NAME:
|
||
// return left->m_symbolProperties.name() < right->m_symbolProperties.name();
|
||
// case BaseSymbolModel::Columns::CATEGORY:
|
||
// return left->m_symbolProperties.category() < right->m_symbolProperties.category();
|
||
// case BaseSymbolModel::Columns::SYMBOLCLASS:
|
||
// return left->m_symbolProperties.symbolClass() < right->m_symbolProperties.symbolClass();
|
||
|
||
case BaseSymbolModel::Columns::XML_SYMBOL_SIZE:
|
||
if (left->m_xmlSymbol && right->m_xmlSymbol)
|
||
return left->m_xmlSymbol->m_symbol.getScale() > right->m_xmlSymbol->m_symbol.getScale();
|
||
} // switch
|
||
|
||
return BaseClass::lessThan(source_left, source_right);
|
||
}
|
||
|
||
|
||
} // namespace AdvancedSymbology
|