Port SymbologyImpl Esri processors to the ArcGIS 300 QFuture async API

TaskWatcher (searchSymbols/fetchSymbol/createSwatch + completion signals) -> QFuture (searchSymbolsAsync/fetchSymbolAsync/createSwatchAsync + QFutureWatcher finished/result getter); flat arcgis/ includes; arcgisversion.h shim (external SDK). advancedSymbology now builds+links vs 300 (0 errors); SymbologyXML CTest 6/6, 0 assertion failures. Migration-only vs legacy; one documented forced delta: 300 has no spec-only DictionarySymbolStyle. Summary: MIGRATION_SUMMARY_ARCGIS300_SYMBOLOGY.md.
This commit is contained in:
berrux-dev committed 2026-10-07 06:24:35 +02:00
1 parent 78253c60f4
commit 2b957d1edb
13 files changed
+512 -157

No files matched your search

@@ -18,8 +18,9 @@
// arcgis
#include <TaskWatcher.h>
#include <DictionarySymbolStyle.h>
#include <MapTypes.h> // Esri::ArcGISRuntime::LoadStatus (300: enum class; Loadable.h only forward-declares it)
#include <Error.h> // Esri::ArcGISRuntime::Error (complete type; 300 dropped Error::code())
// Qt
@@ -31,6 +32,9 @@
#include <utility>
#include <QMimeData>
#include <QtCore/QTimer>
#include <QtCore/QFuture>
#include <QtCore/QFutureWatcher>
#include <QtGui/QImage>
namespace AdvancedSymbology
@@ -159,7 +163,7 @@ QString BaseSymbolItem::symbolSet()
{
if (m_symbolSet.isEmpty())
{
SidcDefinitions::SymbolSet symbolSet = SidcDefinitions::castToSymbolSet(m_symbolProperties.originalKey().left(2).toUInt() // Qt6: leftRef removed);
SidcDefinitions::SymbolSet symbolSet = SidcDefinitions::castToSymbolSet(m_symbolProperties.originalKey().left(2).toUInt()); // Qt6: leftRef(2) removed
m_symbolSet = QString(QStringLiteral("%1 - ")).arg(static_cast<int>(symbolSet)) + AdvancedSymbology::SidcDefinitions::toString(symbolSet);
}
return m_symbolSet;
@@ -167,7 +171,7 @@ QString BaseSymbolItem::symbolSet()
int BaseSymbolItem::symbolSetAsInt()
{
return static_cast<int>(SidcDefinitions::castToSymbolSet(m_symbolProperties.originalKey().left(2).toUInt() // Qt6: leftRef removed));
return static_cast<int>(SidcDefinitions::castToSymbolSet(m_symbolProperties.originalKey().left(2).toUInt())); // Qt6: leftRef(2) removed
}
@@ -222,23 +226,32 @@ QImage BaseSymbolItem::getSearchSwatch()
// 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();
// ArcGIS 300: no TaskWatcher / createSwatchCompleted — createSwatchAsync() returns a
// QFuture<QImage>; a per-request QFutureWatcher delivers the QImage on the main thread.
const QFuture<QImage> fut = m_esriSearch.m_esriSymbol->createSwatchAsync(SWATCH_SIZE, SWATCH_SIZE, 1);
if (fut.isValid())
{
m_esriSearch.m_esriTaskUuid = QUuid::createUuid(); // in-flight guard (was the 100.x task id)
QFutureWatcher<QImage> *watcher = new QFutureWatcher<QImage>(this);
watcher->setFuture(fut);
// 300/Qt6: the 'result' signal is name-collision-ambiguous with the result() getter (QOverload
// can't disambiguate); connect to the unambiguous finished() signal and read the value via the
// result() getter (the future is finished when finished() fires).
connect(watcher, &QFutureWatcher<QImage>::finished, watcher,
[this, watcher] {
onEsriSearchSymbolSwatchCompleted(watcher->result());
watcher->deleteLater();
});
}
else
qCritical() << " SEARCH: id=" << m_id << " taskId invalid";
qCritical() << " SEARCH: id=" << m_id << " createSwatchAsync future invalid";
}
return m_esriSearch.m_esriSwatch;
}
void BaseSymbolItem::onEsriSearchSymbolSwatchCompleted(const QUuid &taskId, const QImage &image)
void BaseSymbolItem::onEsriSearchSymbolSwatchCompleted(const QImage &image)
{
if (m_esriSearch.m_esriTaskUuid != taskId)
return;
// ArcGIS 300: the dedicated QFutureWatcher makes the (removed) taskId stale-check unnecessary.
m_esriSearch.m_esriSwatch = image;
emit dataChanged(m_id);
@@ -251,9 +264,6 @@ QImage BaseSymbolItem::getFetchSwatch() const
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);
@@ -272,39 +282,57 @@ QImage BaseSymbolItem::getFetchSwatch() const
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();
// ArcGIS 300: no TaskWatcher / fetchSymbolCompleted — fetchSymbolAsync() returns a
// QFuture<Symbol*>; a per-request QFutureWatcher delivers the Symbol* on the main thread.
const QFuture<Esri::ArcGISRuntime::Symbol *> fut = m_esriDictionary->fetchSymbolAsync(keys);
if (fut.isValid())
{
m_esriFetch.m_esriFetchTaskIdUuid = QUuid::createUuid(); // in-flight guard (was the 100.x task id)
BaseSymbolItem *const self = const_cast<BaseSymbolItem *>(this); // this method is const
QFutureWatcher<Esri::ArcGISRuntime::Symbol *> *watcher = new QFutureWatcher<Esri::ArcGISRuntime::Symbol *>(self);
watcher->setFuture(fut);
// 300/Qt6: connect to finished() and read the Symbol* via the result() getter (see above).
connect(watcher, &QFutureWatcher<Esri::ArcGISRuntime::Symbol *>::finished, watcher,
[self, watcher] {
self->onEsriFetchCompleted(watcher->result());
watcher->deleteLater();
});
}
else
qCritical() << " FETCH: id=" << m_id << " m_esriFetchTaskIdUuid invalid";
qCritical() << " FETCH: id=" << m_id << " fetchSymbolAsync future invalid";
}
return m_esriFetch.m_esriSwatch;
}
void BaseSymbolItem::onEsriFetchCompleted(const QUuid &taskId, Esri::ArcGISRuntime::Symbol *symbol)
void BaseSymbolItem::onEsriFetchCompleted(Esri::ArcGISRuntime::Symbol *symbol)
{
if (m_esriFetch.m_esriFetchTaskIdUuid != taskId)
return;
// ArcGIS 300: the dedicated QFutureWatcher makes the (removed) taskId stale-check unnecessary.
// 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();
// start creating swatch of fetched symbol (createSwatchAsync -> QFuture<QImage>):
const QFuture<QImage> fut = m_esriFetch.m_esriSymbol->createSwatchAsync(SWATCH_SIZE, SWATCH_SIZE, 1);
if (fut.isValid())
{
m_esriFetch.m_esriSwatchTaskUuid = QUuid::createUuid(); // in-flight guard (was the 100.x task id)
QFutureWatcher<QImage> *watcher = new QFutureWatcher<QImage>(this);
watcher->setFuture(fut);
// 300/Qt6: connect to finished() and read the QImage via the result() getter (see above).
connect(watcher, &QFutureWatcher<QImage>::finished, watcher,
[this, watcher] {
onEsriFetchSymbolSwatchCompleted(watcher->result());
watcher->deleteLater();
});
}
else
qCritical() << " FETCH: id=" << m_id << " taskId invalid";
qCritical() << " FETCH: id=" << m_id << " createSwatchAsync future invalid";
}
void BaseSymbolItem::onEsriFetchSymbolSwatchCompleted(const QUuid &taskId, const QImage &image)
void BaseSymbolItem::onEsriFetchSymbolSwatchCompleted(const QImage &image)
{
if (m_esriFetch.m_esriSwatchTaskUuid != taskId)
return;
// ArcGIS 300: the dedicated QFutureWatcher makes the (removed) taskId stale-check unnecessary.
m_esriFetch.m_esriSwatch = image;
// qCritical() << " FETCH: id=" << m_id << " image " << image.size();
@@ -426,7 +454,7 @@ void BaseSymbolModel::onLoadStatusChanged(Esri::ArcGISRuntime::LoadStatus loadSt
void BaseSymbolModel::onErrorDictionary(const Esri::ArcGISRuntime::Error &error)
{
FATAL_LOG(m_logger) << LOGFUNCTION << " ---EsriError--- occured: "
<< " code=" << error.code()
<< " code=" << error.arcGISServerErrorCode().value_or(-1) // 300: Error::code() removed
<< ", domain=" << static_cast<int>(error.domain())
<< ", extendedErrorType=" << static_cast<int>(error.extendedErrorType())
<< ", message='" << error.message() << "'"
@@ -456,13 +484,15 @@ void BaseSymbolModel::initModel(SymbolDictionary *symbolDictionary,
// spend time to create (expensive) Esri::ArcGISRuntime::Symbol?
#ifdef LTS_DEBUG
Esri::ArcGISRuntime::Symbol *esriSymbol = nullptr;
Esri::ArcGISRuntime::Symbol *esriSymbol = nullptr; // 300: filled asynchronously (see below)
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
// 300: symbol() (const, sync, mainThread) is gone; fetchSymbolAsync() is non-const + async.
// When showAll, the Symbol is fetched after the item exists and attached via
// setEsriSearchSymbol() when the future completes.
#else
// release mode: save time, won´t be visible
Esri::ArcGISRuntime::Symbol *esriSymbol = nullptr;
const bool showAll = false;
#endif // LTS_DEBUG
@@ -470,6 +500,29 @@ void BaseSymbolModel::initModel(SymbolDictionary *symbolDictionary,
bsi->setSymbolDictionary(symbolDictionary);
#ifdef LTS_DEBUG
// 300: fetch the Symbol asynchronously and attach it to the item when the future completes.
// fetchSymbolAsync() is non-const; copy the (const) search result to call it.
if (showAll)
{
Esri::ArcGISRuntime::SymbolStyleSearchResult sr(searchResult);
QFuture<Esri::ArcGISRuntime::Symbol *> fut = sr.fetchSymbolAsync(this);
if (fut.isValid())
{
QFutureWatcher<Esri::ArcGISRuntime::Symbol *> *watcher = new QFutureWatcher<Esri::ArcGISRuntime::Symbol *>(this);
watcher->setFuture(fut);
// 300/Qt6: connect to finished() and read the Symbol* via the result() getter (see above).
connect(watcher, &QFutureWatcher<Esri::ArcGISRuntime::Symbol *>::finished, watcher,
[bsi, watcher] {
Esri::ArcGISRuntime::Symbol *symbol = watcher->result();
if (symbol)
bsi->setEsriSearchSymbol(symbol);
watcher->deleteLater();
});
}
}
#endif // LTS_DEBUG
bsi->m_symbolProperties.setTags(searchResult.tags());
bsi->m_symbolProperties.setName(searchResult.name());
bsi->m_symbolProperties.setSymbolClass(searchResult.symbolClass());