Skip to content

Commit cb105d6

Browse files
committed
Sorted out issues with ownership between ContextMenuController and IdentifyController. Added a method to cleanup popup elements whenever the UI is closed instead of waiting until the next Identify is performed.
1 parent 8df444d commit cb105d6

5 files changed

Lines changed: 76 additions & 38 deletions

File tree

Handheld/qml/main.qml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -450,6 +450,7 @@ Handheld {
450450

451451
closeCallback: () => {
452452
identifyResultsContainer.visible = false;
453+
identifyController.clearPopups();
453454
}
454455
}
455456

Shared/ContextMenuController.cpp

Lines changed: 37 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -275,21 +275,24 @@ void ContextMenuController::clearOptions()
275275
{
276276
m_options->setStringList(QStringList{});
277277

278-
for (const auto& geoElements : std::as_const(m_contextGeoElements))
278+
for (const QList<GeoElement*>& geoElements : std::as_const(m_contextGeoElements))
279279
{
280280
if (geoElements.empty())
281281
continue;
282282

283-
// DynamicEntity and DynamicEntityObservation objects should not be deleted
284-
// They are owned by their MessageFeed
285-
const GeoElement* ge = geoElements.first();
286-
if (const auto* de = dynamic_cast<const DynamicEntity*>(ge); de)
287-
continue;
288-
289-
if (const auto* deo = dynamic_cast<const DynamicEntityObservation*>(ge); deo)
290-
continue;
283+
for (GeoElement* ge : geoElements)
284+
{
285+
if (!ge)
286+
continue;
291287

292-
qDeleteAll(geoElements);
288+
// anything that was previously identified from the view
289+
// that is owned by the controller should be deleted
290+
if (QObject* o = GeoElementUtils::toQObject(ge); o)
291+
{
292+
if (o->parent() == this)
293+
o->deleteLater();
294+
}
295+
}
293296
}
294297
m_contextGeoElements.clear();
295298
}
@@ -363,14 +366,14 @@ void ContextMenuController::invokeIdentifyOnGeoView()
363366
auto idenfityLayers = geoView->identifyLayersAsync(m_contextScreenPosition, 5.0, false, -1, this);
364367
auto identifyGraphicsOverlays = geoView->identifyGraphicsOverlaysAsync(m_contextScreenPosition, 5.0, false, -1, this);
365368

366-
QtFuture::whenAll(idenfityLayers, identifyGraphicsOverlays).then(this, [this](const QList<IdentifyResultsVariant::FutureType> &identifyResults)
369+
QtFuture::whenAll(idenfityLayers, identifyGraphicsOverlays).then(this, [this](const QList<IdentifyResultsVariant::FutureType>& identifyResults)
367370
{
368371
for (const IdentifyResultsVariant::FutureType& identifyResult : identifyResults)
369372
{
370373
if (identifyResult.index() == IdentifyResultsVariant::Types::LAYERS)
371374
{
372-
LayerResultsManager resultsManager(std::get<IdentifyResultsVariant::Types::LAYERS>(identifyResult).result());
373-
for (IdentifyLayerResult* result : std::as_const(resultsManager.m_results))
375+
const QList<Esri::ArcGISRuntime::IdentifyLayerResult*> results = std::get<IdentifyResultsVariant::Types::LAYERS>(identifyResult).result();
376+
for (IdentifyLayerResult* result : results)
374377
{
375378
if (!result)
376379
continue;
@@ -379,34 +382,42 @@ void ContextMenuController::invokeIdentifyOnGeoView()
379382
if (geoElementsAll.isEmpty())
380383
continue;
381384

385+
QList<GeoElement*> geoElementsToOwn{};
382386
QList<GeoElement*> geoElements{};
383-
std::for_each(std::begin(geoElementsAll), std::end(geoElementsAll), [&](GeoElement* ge)
387+
for (GeoElement* ge : geoElementsAll)
384388
{
389+
// any non-observations (Feature, etc) should be owned
385390
DynamicEntityObservation* deo = dynamic_cast<DynamicEntityObservation*>(ge);
386391
if (!deo)
387392
{
393+
geoElementsToOwn.append(ge);
388394
geoElements.append(ge);
389-
return;
395+
continue;
390396
}
391397

392-
// add any observations that are not the latest to the list to be preserved
398+
// observations other than the latest at the time of the click
399+
// should also be owned
393400
DynamicEntity* de = deo->dynamicEntity();
394401
if (de->latestObservation()->observationId() != deo->observationId())
395402
{
403+
geoElementsToOwn.append(deo);
396404
geoElements.append(deo);
397-
return;
405+
continue;
398406
}
399407

400-
// for latest observations, add the entity itself and mark the observation as deleted
408+
// the remaining case is that the observation was itself the latest
409+
// so we add the dynamic entity instead of the observation element
410+
// and mark the observation as no longer needed
401411
geoElements.append(de);
402412
deo->deleteLater();
403-
});
413+
}
404414

405-
// set the GeoElements to be managed by the tool
406-
GeoElementUtils::setParent(geoElements, this);
415+
// set the observations and any other non-DynamicEntity GeoElements to be owned by the tool
416+
GeoElementUtils::setParent(geoElementsToOwn, this);
407417

408418
// add the geoElements to the context hash using the layer name as the key
409419
m_contextGeoElements.insert(result->layerContent()->name(), geoElements);
420+
result->deleteLater();
410421
}
411422
}
412423
else if (identifyResult.index() == IdentifyResultsVariant::Types::GRAPHICS)
@@ -492,7 +503,12 @@ void ContextMenuController::selectOption(const QString& option)
492503
if (!identifyTool)
493504
return;
494505

506+
// transfer the geoelements to the identify controller which takes ownership of them
495507
identifyTool->showPopups(m_contextGeoElements);
508+
509+
// clear the list so that the elements will not be cleaned up by subsequent
510+
// long presses on the geoview
511+
m_contextGeoElements.clear();
496512
}
497513
else if (option == OPTION_VIEWSHED)
498514
{

Shared/IdentifyController.cpp

Lines changed: 35 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
#include "PopupTypes.h"
3535

3636
// DSA headers
37+
#include "GeoElementUtils.h"
3738
#include "ToolManager.h"
3839

3940

@@ -54,11 +55,12 @@ QString IdentifyController::toolName() const
5455
return QStringLiteral("identify");
5556
}
5657

58+
/*!
59+
* \brief Creates popups for the GeoElements and takes ownership of any non-DynamicEntities.
60+
*/
5761
void IdentifyController::showPopups(const QHash<QString, QList<GeoElement*>>& geoElementsByTitle)
5862
{
59-
// reset the popups container properties
60-
m_popups.clear();
61-
m_currentPopupIndex = -1;
63+
clearPopups();
6264

6365
if (geoElementsByTitle.isEmpty())
6466
{
@@ -97,6 +99,16 @@ void IdentifyController::prevPopup()
9799
emit popupChanged();
98100
}
99101

102+
void IdentifyController::clearPopups()
103+
{
104+
for (Popup* popup : m_popups)
105+
popup->deleteLater();
106+
107+
m_popups.clear();
108+
109+
m_currentPopupIndex = -1;
110+
}
111+
100112
bool isObjectIdFieldName(QStringView fieldName)
101113
{
102114
static constexpr std::array<std::string_view, 3> oidFieldNames{
@@ -118,35 +130,42 @@ bool IdentifyController::addGeoElementPopup(GeoElement* geoElement, const QStrin
118130
if (!geoElement->attributes() || geoElement->attributes()->isEmpty())
119131
return false;
120132

121-
bool isDynamicEntity = false;
122-
if (const auto* de = dynamic_cast<DynamicEntity*>(geoElement); de)
123-
isDynamicEntity = true;
133+
// default popup title to the layer name
134+
auto* newPopup = new Popup(geoElement, this);
135+
newPopup->popupDefinition()->setTitle(popupTitle);
136+
if (const auto* de = dynamic_cast<DynamicEntity*>(geoElement); !de)
137+
{
138+
// set any non-dynamic entity geoelements to be owned by their popup which are cleaned up
139+
GeoElementUtils::toQObject(geoElement)->setParent(newPopup);
140+
}
141+
else
142+
{
143+
// don't change the parent but set unique label indicating the latest observation
144+
newPopup->popupDefinition()->setTitle(QString{"%1<br>(Live Updates)"}.arg(popupTitle));
145+
}
124146

125-
// create a new Popup from the geoElement
126-
auto newPopup = std::make_unique<Popup>(geoElement);
127-
newPopup->popupDefinition()->setTitle(isDynamicEntity ? QString{"%1<br>(Live Updates)"}.arg(popupTitle) : popupTitle);
128-
const auto popupElements = newPopup->popupDefinition()->elements();
129-
for (const auto popupElement : popupElements)
147+
const QList<PopupElement*> popupElements = newPopup->popupDefinition()->elements();
148+
for (const PopupElement* popupElement : popupElements)
130149
{
131150
if (popupElement->popupElementType() != PopupElementType::FieldsPopupElement)
132151
continue;
133152

134-
const auto* fieldsPE = static_cast<FieldsPopupElement*>(popupElement);
135-
const auto* fields = fieldsPE->fields();
153+
const auto* fieldsPE = static_cast<const FieldsPopupElement*>(popupElement);
154+
const PopupFieldListModel* fields = fieldsPE->fields();
136155
for (PopupField* field : *fields)
137156
{
138157
// check any fields that are not editable for common ObjectID field names
139158
if (!field->isEditable() && isObjectIdFieldName(field->fieldName()))
140159
continue;
141160

142161
// set parent to Popup
143-
auto popupFF = new PopupFieldFormat(dynamic_cast<QObject*>(newPopup.get()));
162+
auto popupFF = new PopupFieldFormat(static_cast<QObject*>(newPopup));
144163
popupFF->setDecimalPlaces(2);
145164
popupFF->setUseThousandsSeparator(true);
146165
field->setFormat(popupFF);
147166
}
148167
}
149-
m_popups.emplace_back(std::move(newPopup));
168+
m_popups.push_back(newPopup);
150169

151170
return true;
152171
}
@@ -166,7 +185,7 @@ Popup* IdentifyController::popup() const
166185
if (m_currentPopupIndex < 0 || m_currentPopupIndex >= static_cast<int>(m_popups.size()))
167186
return nullptr;
168187

169-
return m_popups.at(m_currentPopupIndex).get();
188+
return m_popups.at(m_currentPopupIndex);
170189
}
171190

172191
} // Dsa

Shared/IdentifyController.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ class IdentifyController : public AbstractTool
6060
void showPopups(const QHash<QString, QList<Esri::ArcGISRuntime::GeoElement*>>& geoElementsByTitle);
6161
Q_INVOKABLE void nextPopup();
6262
Q_INVOKABLE void prevPopup();
63+
Q_INVOKABLE void clearPopups();
6364

6465
signals:
6566
void popupChanged();
@@ -72,7 +73,7 @@ class IdentifyController : public AbstractTool
7273

7374
double m_tolerance = 5.0;
7475
int m_currentPopupIndex = -1;
75-
std::vector<std::unique_ptr<Esri::ArcGISRuntime::Popup>> m_popups;
76+
std::vector<Esri::ArcGISRuntime::Popup*> m_popups;
7677
};
7778

7879
// some shortcuts for working with multiple identify operation futures in a single 'QtFuture::whenAll' handler

Vehicle/qml/main.qml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -443,6 +443,7 @@ Vehicle {
443443

444444
closeCallback: () => {
445445
identifyResultsContainer.visible = false;
446+
identifyController.clearPopups();
446447
}
447448
}
448449

0 commit comments

Comments
 (0)