From a8195c6e2c1c6c69a1d0446245319ca5737c8e5e Mon Sep 17 00:00:00 2001 From: Matthias Kuehlewein Date: Sun, 27 Apr 2025 14:02:52 +0200 Subject: [PATCH 01/16] MapFindFeature: Exclude hidden and protected objects The 'Find next' search failed if the object query returned an object with either a hidden or protected symbol since these kind of objects can't be added to an object selection. Exclude all hidden and protected objects from the 'Find next' and 'Find all' search. --- src/gui/map/map_find_feature.cpp | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/src/gui/map/map_find_feature.cpp b/src/gui/map/map_find_feature.cpp index 39425efaa..4a888209c 100644 --- a/src/gui/map/map_find_feature.cpp +++ b/src/gui/map/map_find_feature.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2017-2024 Kai Pastor + * Copyright 2017-2020, 2024, 2025 Kai Pastor * * This file is part of OpenOrienteering. * @@ -35,7 +35,9 @@ #include "core/map.h" #include "core/map_part.h" +#include "core/objects/object.h" #include "core/objects/object_query.h" +#include "core/symbols/symbol.h" #include "gui/main_window.h" #include "gui/util_gui.h" #include "gui/map/map_editor.h" @@ -193,9 +195,11 @@ void MapFindFeature::findNext() if (object == first_object) first_object = nullptr; } - else if (query(object)) + else { - next_object = object; + const auto* object_symbol = object->getSymbol(); + if (!object_symbol->isProtected() && !object_symbol->isHidden() && query(object)) + next_object = object; } } }; @@ -231,10 +235,13 @@ void MapFindFeature::findAll() controller.getWindow()->showStatusBarMessage(OpenOrienteering::TagSelectWidget::tr("Invalid query"), 2000); return; } - + auto search = [&query](const Object* object) { + const auto* object_symbol = object->getSymbol(); + return !object_symbol->isProtected() && !object_symbol->isHidden() && query(object); + }; map->getCurrentPart()->applyOnMatchingObjects([map](Object* object) { map->addObjectToSelection(object, false); - }, std::cref(query)); + }, search); map->emitSelectionChanged(); map->ensureVisibilityOfSelectedObjects(Map::FullVisibility); controller.getWindow()->showStatusBarMessage(OpenOrienteering::TagSelectWidget::tr("%n object(s) selected", nullptr, map->getNumSelectedObjects()), 2000); From 8c6c8f059fe5b5d7892a90924585a7fab734e515 Mon Sep 17 00:00:00 2001 From: Kai Pastor Date: Mon, 12 May 2025 06:50:01 +0200 Subject: [PATCH 02/16] Factor out isSelectable() --- src/gui/map/map_find_feature.cpp | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/src/gui/map/map_find_feature.cpp b/src/gui/map/map_find_feature.cpp index 4a888209c..bc2236ab4 100644 --- a/src/gui/map/map_find_feature.cpp +++ b/src/gui/map/map_find_feature.cpp @@ -48,6 +48,18 @@ namespace OpenOrienteering { class Object; +namespace { + +// Returns true if an object can be added to the selection. +bool isSelectable(const Object* object) +{ + const auto* symbol = object ? object->getSymbol() : nullptr; + return symbol && !symbol->isHidden() && !symbol->isProtected(); +} + +} // namespace + + MapFindFeature::MapFindFeature(MapEditorController& controller) : QObject{nullptr} , controller{controller} @@ -195,11 +207,9 @@ void MapFindFeature::findNext() if (object == first_object) first_object = nullptr; } - else + else if (isSelectable(object) && query(object)) { - const auto* object_symbol = object->getSymbol(); - if (!object_symbol->isProtected() && !object_symbol->isHidden() && query(object)) - next_object = object; + next_object = object; } } }; @@ -236,8 +246,7 @@ void MapFindFeature::findAll() return; } auto search = [&query](const Object* object) { - const auto* object_symbol = object->getSymbol(); - return !object_symbol->isProtected() && !object_symbol->isHidden() && query(object); + return isSelectable(object) && query(object); }; map->getCurrentPart()->applyOnMatchingObjects([map](Object* object) { map->addObjectToSelection(object, false); From 1e1ca1cca8f13c86fc785098c17e610b8d5982e0 Mon Sep 17 00:00:00 2001 From: Kai Pastor Date: Mon, 12 May 2025 06:53:36 +0200 Subject: [PATCH 03/16] Revert new search functor --- src/gui/map/map_find_feature.cpp | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/gui/map/map_find_feature.cpp b/src/gui/map/map_find_feature.cpp index bc2236ab4..f986025c5 100644 --- a/src/gui/map/map_find_feature.cpp +++ b/src/gui/map/map_find_feature.cpp @@ -245,12 +245,10 @@ void MapFindFeature::findAll() controller.getWindow()->showStatusBarMessage(OpenOrienteering::TagSelectWidget::tr("Invalid query"), 2000); return; } - auto search = [&query](const Object* object) { - return isSelectable(object) && query(object); - }; map->getCurrentPart()->applyOnMatchingObjects([map](Object* object) { - map->addObjectToSelection(object, false); - }, search); + if (isSelectable(object)) + map->addObjectToSelection(object, false); + }, query); map->emitSelectionChanged(); map->ensureVisibilityOfSelectedObjects(Map::FullVisibility); controller.getWindow()->showStatusBarMessage(OpenOrienteering::TagSelectWidget::tr("%n object(s) selected", nullptr, map->getNumSelectedObjects()), 2000); From 116b343d31d90208f2196757119634b74cc66686 Mon Sep 17 00:00:00 2001 From: Kai Pastor Date: Mon, 12 May 2025 08:29:00 +0200 Subject: [PATCH 04/16] Use single walk for "Find next" --- src/gui/map/map_find_feature.cpp | 51 +++++++++++++++----------------- 1 file changed, 24 insertions(+), 27 deletions(-) diff --git a/src/gui/map/map_find_feature.cpp b/src/gui/map/map_find_feature.cpp index f986025c5..2f4d46781 100644 --- a/src/gui/map/map_find_feature.cpp +++ b/src/gui/map/map_find_feature.cpp @@ -186,11 +186,6 @@ ObjectQuery MapFindFeature::makeQuery() const void MapFindFeature::findNext() { - auto map = controller.getMap(); - auto first_object = map->getFirstSelectedObject(); - map->clearObjectSelection(false); - - Object* next_object = nullptr; auto query = makeQuery(); if (!query) { @@ -198,34 +193,36 @@ void MapFindFeature::findNext() window->showStatusBarMessage(OpenOrienteering::TagSelectWidget::tr("Invalid query"), 2000); return; } + + auto* map = controller.getMap(); + Object* first_match = nullptr; // the first match in all objects + Object* pivot_object = map->getFirstSelectedObject(); + Object* next_match = nullptr; // the next match after pivot_object + map->clearObjectSelection(false); + + auto search = [&first_match, &pivot_object, &next_match](Object* object) { + if (next_match) + return; - auto search = [&first_object, &next_object, &query](Object* object) { - if (!next_object) + bool after_pivot = (pivot_object == nullptr); + if (object == pivot_object) + pivot_object = nullptr; + + if (isSelectable(object)) { - if (first_object) - { - if (object == first_object) - first_object = nullptr; - } - else if (isSelectable(object) && query(object)) - { - next_object = object; - } + if (after_pivot && !next_match) + next_match = object; + else if (!first_match) + first_match = object; } }; - - // Start from selected object - map->getCurrentPart()->applyOnAllObjects(search); - if (!next_object) - { - // Start from first object - first_object = nullptr; - map->getCurrentPart()->applyOnAllObjects(search); - } + map->getCurrentPart()->applyOnMatchingObjects(search, query); map->clearObjectSelection(false); - if (next_object) - map->addObjectToSelection(next_object, false); + if (!next_match) + next_match = first_match; + if (next_match) + map->addObjectToSelection(next_match, false); map->emitSelectionChanged(); map->ensureVisibilityOfSelectedObjects(Map::FullVisibility); From 34a1c2def437a44ed26c2bd72c182bb7402c9595 Mon Sep 17 00:00:00 2001 From: Kai Pastor Date: Mon, 12 May 2025 08:29:12 +0200 Subject: [PATCH 05/16] Cleanup --- src/gui/map/map_find_feature.cpp | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/gui/map/map_find_feature.cpp b/src/gui/map/map_find_feature.cpp index 2f4d46781..f5dda248a 100644 --- a/src/gui/map/map_find_feature.cpp +++ b/src/gui/map/map_find_feature.cpp @@ -20,8 +20,6 @@ #include "map_find_feature.h" -#include - #include #include #include @@ -46,8 +44,6 @@ namespace OpenOrienteering { -class Object; - namespace { // Returns true if an object can be added to the selection. @@ -217,8 +213,6 @@ void MapFindFeature::findNext() } }; map->getCurrentPart()->applyOnMatchingObjects(search, query); - - map->clearObjectSelection(false); if (!next_match) next_match = first_match; if (next_match) From 71d742cecfd3a171dd4786bacef26cbc27044b8d Mon Sep 17 00:00:00 2001 From: Kai Pastor Date: Mon, 12 May 2025 08:51:44 +0200 Subject: [PATCH 06/16] Fixup --- src/gui/map/map_find_feature.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/map/map_find_feature.cpp b/src/gui/map/map_find_feature.cpp index f5dda248a..cc5c2dfa4 100644 --- a/src/gui/map/map_find_feature.cpp +++ b/src/gui/map/map_find_feature.cpp @@ -206,7 +206,7 @@ void MapFindFeature::findNext() if (isSelectable(object)) { - if (after_pivot && !next_match) + if (after_pivot) next_match = object; else if (!first_match) first_match = object; From 1122a736040c4035676f03f283b22195845b3001 Mon Sep 17 00:00:00 2001 From: Matthias Kuehlewein Date: Mon, 12 May 2025 14:15:18 +0200 Subject: [PATCH 07/16] Fix passing of query --- src/gui/map/map_find_feature.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/gui/map/map_find_feature.cpp b/src/gui/map/map_find_feature.cpp index cc5c2dfa4..4004398d2 100644 --- a/src/gui/map/map_find_feature.cpp +++ b/src/gui/map/map_find_feature.cpp @@ -20,6 +20,8 @@ #include "map_find_feature.h" +#include + #include #include #include @@ -212,7 +214,7 @@ void MapFindFeature::findNext() first_match = object; } }; - map->getCurrentPart()->applyOnMatchingObjects(search, query); + map->getCurrentPart()->applyOnMatchingObjects(search, std::cref(query)); if (!next_match) next_match = first_match; if (next_match) @@ -239,7 +241,7 @@ void MapFindFeature::findAll() map->getCurrentPart()->applyOnMatchingObjects([map](Object* object) { if (isSelectable(object)) map->addObjectToSelection(object, false); - }, query); + }, std::cref(query)); map->emitSelectionChanged(); map->ensureVisibilityOfSelectedObjects(Map::FullVisibility); controller.getWindow()->showStatusBarMessage(OpenOrienteering::TagSelectWidget::tr("%n object(s) selected", nullptr, map->getNumSelectedObjects()), 2000); From fb09aa0b66f9a4cef254c1a2fe1bc83b40168294 Mon Sep 17 00:00:00 2001 From: Kai Pastor Date: Tue, 13 May 2025 06:00:20 +0200 Subject: [PATCH 08/16] Search pivot object in all objects --- src/gui/map/map_find_feature.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/gui/map/map_find_feature.cpp b/src/gui/map/map_find_feature.cpp index 4004398d2..41a2ed7c8 100644 --- a/src/gui/map/map_find_feature.cpp +++ b/src/gui/map/map_find_feature.cpp @@ -198,7 +198,7 @@ void MapFindFeature::findNext() Object* next_match = nullptr; // the next match after pivot_object map->clearObjectSelection(false); - auto search = [&first_match, &pivot_object, &next_match](Object* object) { + auto search = [&](Object* object) { if (next_match) return; @@ -206,7 +206,7 @@ void MapFindFeature::findNext() if (object == pivot_object) pivot_object = nullptr; - if (isSelectable(object)) + if (isSelectable(object) && query(object)) { if (after_pivot) next_match = object; @@ -214,7 +214,7 @@ void MapFindFeature::findNext() first_match = object; } }; - map->getCurrentPart()->applyOnMatchingObjects(search, std::cref(query)); + map->getCurrentPart()->applyOnAllObjects(search); if (!next_match) next_match = first_match; if (next_match) From b0dcb5a2e30df769c919816d019376a708e341c4 Mon Sep 17 00:00:00 2001 From: Matthias Kuehlewein Date: Tue, 13 May 2025 13:00:35 +0200 Subject: [PATCH 09/16] Code polishing --- src/gui/map/map_find_feature.cpp | 9 +++++---- src/gui/map/map_find_feature.h | 20 +++++++++++--------- 2 files changed, 16 insertions(+), 13 deletions(-) diff --git a/src/gui/map/map_find_feature.cpp b/src/gui/map/map_find_feature.cpp index 41a2ed7c8..e3aeca3ab 100644 --- a/src/gui/map/map_find_feature.cpp +++ b/src/gui/map/map_find_feature.cpp @@ -22,8 +22,8 @@ #include -#include #include +#include #include #include #include @@ -129,7 +129,7 @@ void MapFindFeature::showDialog() auto button_box = new QDialogButtonBox(QDialogButtonBox::Close | QDialogButtonBox::Help); connect(button_box, &QDialogButtonBox::rejected, &*find_dialog, &QDialog::hide); - connect(button_box->button(QDialogButtonBox::Help), &QPushButton::clicked, this, &MapFindFeature::showHelp); + connect(button_box, &QDialogButtonBox::helpRequested, this, &MapFindFeature::showHelp); editor_stack = new QStackedLayout(); editor_stack->addWidget(text_edit); @@ -182,6 +182,7 @@ ObjectQuery MapFindFeature::makeQuery() const } +// slot void MapFindFeature::findNext() { auto query = makeQuery(); @@ -227,6 +228,7 @@ void MapFindFeature::findNext() } +// slot void MapFindFeature::findAll() { auto map = controller.getMap(); @@ -251,14 +253,13 @@ void MapFindFeature::findAll() } - +// slot void MapFindFeature::showHelp() const { Util::showHelp(controller.getWindow(), "find_objects.html"); } - // slot void MapFindFeature::tagSelectorToggled(bool active) { diff --git a/src/gui/map/map_find_feature.h b/src/gui/map/map_find_feature.h index 7568372fb..242c17a36 100644 --- a/src/gui/map/map_find_feature.h +++ b/src/gui/map/map_find_feature.h @@ -1,5 +1,5 @@ /* - * Copyright 2017 Kai Pastor + * Copyright 2017-2019, 2025 Kai Pastor * * This file is part of OpenOrienteering. * @@ -56,15 +56,11 @@ class MapFindFeature : public QObject void setEnabled(bool enabled); - QAction* showDialogAction() { return show_action; } + QAction* showDialogAction() const { return show_action; } - QAction* findNextAction() { return find_next_action; } - -private: - void showDialog(); - - ObjectQuery makeQuery() const; + QAction* findNextAction() const { return find_next_action; } +private slots: void findNext(); void findAll(); @@ -73,6 +69,12 @@ class MapFindFeature : public QObject void tagSelectorToggled(bool active); +private: + void showDialog(); + + ObjectQuery makeQuery() const; + + MapEditorController& controller; QPointer find_dialog; // child of controller's window QStackedLayout* editor_stack = nullptr; // child of find_dialog @@ -88,4 +90,4 @@ class MapFindFeature : public QObject } // namespace OpenOrienteering -#endif +#endif // OPENORIENTEERING_MAP_FIND_FEATURE_H From 1bf23daf9abaeec936ccabdda8676c46d39d92e9 Mon Sep 17 00:00:00 2001 From: Matthias Kuehlewein Date: Tue, 13 May 2025 20:47:18 +0200 Subject: [PATCH 10/16] Add test --- src/gui/map/map_find_feature.cpp | 32 +++++++---- src/gui/map/map_find_feature.h | 6 ++- test/object_query_t.cpp | 91 ++++++++++++++++++++++++++++++-- test/object_query_t.h | 3 +- 4 files changed, 116 insertions(+), 16 deletions(-) diff --git a/src/gui/map/map_find_feature.cpp b/src/gui/map/map_find_feature.cpp index e3aeca3ab..b12b1003d 100644 --- a/src/gui/map/map_find_feature.cpp +++ b/src/gui/map/map_find_feature.cpp @@ -193,6 +193,17 @@ void MapFindFeature::findNext() return; } + auto* map = controller.getMap(); + findNextMatchingObject(query); + map->emitSelectionChanged(); + map->ensureVisibilityOfSelectedObjects(Map::FullVisibility); + + if (!map->selectedObjects().empty()) + controller.setEditTool(); +} + +void MapFindFeature::findNextMatchingObject(ObjectQuery& query) +{ auto* map = controller.getMap(); Object* first_match = nullptr; // the first match in all objects Object* pivot_object = map->getFirstSelectedObject(); @@ -215,16 +226,12 @@ void MapFindFeature::findNext() first_match = object; } }; + map->getCurrentPart()->applyOnAllObjects(search); if (!next_match) next_match = first_match; if (next_match) map->addObjectToSelection(next_match, false); - map->emitSelectionChanged(); - map->ensureVisibilityOfSelectedObjects(Map::FullVisibility); - - if (!map->selectedObjects().empty()) - controller.setEditTool(); } @@ -240,10 +247,8 @@ void MapFindFeature::findAll() controller.getWindow()->showStatusBarMessage(OpenOrienteering::TagSelectWidget::tr("Invalid query"), 2000); return; } - map->getCurrentPart()->applyOnMatchingObjects([map](Object* object) { - if (isSelectable(object)) - map->addObjectToSelection(object, false); - }, std::cref(query)); + + findAllMatchingObjects(query); map->emitSelectionChanged(); map->ensureVisibilityOfSelectedObjects(Map::FullVisibility); controller.getWindow()->showStatusBarMessage(OpenOrienteering::TagSelectWidget::tr("%n object(s) selected", nullptr, map->getNumSelectedObjects()), 2000); @@ -252,6 +257,15 @@ void MapFindFeature::findAll() controller.setEditTool(); } +void MapFindFeature::findAllMatchingObjects(ObjectQuery& query) +{ + auto map = controller.getMap(); + map->getCurrentPart()->applyOnMatchingObjects([map](Object* object) { + if (isSelectable(object)) + map->addObjectToSelection(object, false); + }, std::cref(query)); +} + // slot void MapFindFeature::showHelp() const diff --git a/src/gui/map/map_find_feature.h b/src/gui/map/map_find_feature.h index 242c17a36..56ed72bdd 100644 --- a/src/gui/map/map_find_feature.h +++ b/src/gui/map/map_find_feature.h @@ -37,7 +37,6 @@ class MapEditorController; class ObjectQuery; class TagSelectWidget; - /** * Provides an interactive feature for finding objects in the map. * @@ -48,7 +47,6 @@ class TagSelectWidget; class MapFindFeature : public QObject { Q_OBJECT - public: MapFindFeature(MapEditorController& controller); @@ -60,6 +58,10 @@ class MapFindFeature : public QObject QAction* findNextAction() const { return find_next_action; } + void findNextMatchingObject(ObjectQuery& query); + + void findAllMatchingObjects(ObjectQuery& query); + private slots: void findNext(); diff --git a/test/object_query_t.cpp b/test/object_query_t.cpp index d724011bf..c7e7b4022 100644 --- a/test/object_query_t.cpp +++ b/test/object_query_t.cpp @@ -1,6 +1,6 @@ /* * Copyright 2016 Mitchell Krome - * Copyright 2017-2022 Kai Pastor + * Copyright 2017-2022, 2025 Kai Pastor * * This file is part of OpenOrienteering. * @@ -20,8 +20,8 @@ #include "object_query_t.h" -#include #include +#include #include #include @@ -29,11 +29,16 @@ #include #include +#include "global.h" #include "core/map.h" +#include "core/map_part.h" #include "core/objects/object.h" -#include "core/objects/text_object.h" #include "core/objects/object_query.h" +#include "core/objects/text_object.h" #include "core/symbols/point_symbol.h" +#include "gui/main_window.h" +#include "gui/map/map_editor.h" +#include "gui/map/map_find_feature.h" using namespace OpenOrienteering; @@ -53,6 +58,7 @@ ObjectQueryTest::ObjectQueryTest(QObject* parent) // nothing } + const Object* ObjectQueryTest::testObject() { static TextObject obj; @@ -509,11 +515,88 @@ void ObjectQueryTest::testParser() } +void ObjectQueryTest::testFindObjects() +{ + Q_INIT_RESOURCE(resources); + doStaticInitializations(); + + Map map; + auto* window = new MainWindow(); + auto* editor = new MapEditorController(MapEditorController::MapEditor, &map); + window->setController(editor); + const auto* part = map.getCurrentPart(); + + auto* point_symbol_1 = new PointSymbol(); + point_symbol_1->setNumberComponent(0, 123); + map.addSymbol(point_symbol_1, 0); + auto* point_object_1 = new PointObject(point_symbol_1); + point_object_1->setTag(QLatin1String("match"), QLatin1String("yes")); + QVERIFY(map.addObject(point_object_1) == 0); // object pos 0 + + auto* point_object_2 = new PointObject(point_symbol_1); + point_object_2->setTag(QLatin1String("match"), QLatin1String("no")); + QVERIFY(map.addObject(point_object_2) == 1); // object pos 1 + + point_object_2 = new PointObject(point_symbol_1); + point_object_2->setTag(QLatin1String("match"), QLatin1String("yes")); + QVERIFY(map.addObject(point_object_2) == 2); // object pos 2 + + auto* point_symbol_2 = new PointSymbol(); + point_symbol_2->setNumberComponent(0, 124); + point_symbol_2->setHidden(true); + map.addSymbol(point_symbol_2, 1); + point_object_2 = new PointObject(point_symbol_2); + point_object_2->setTag(QLatin1String("match"), QLatin1String("yes")); + QVERIFY(map.addObject(point_object_2) == 3); // object pos 3 + + point_object_2 = new PointObject(point_symbol_1); + point_object_2->setTag(QLatin1String("match"), QLatin1String("yes")); + QVERIFY(map.addObject(point_object_2) == 4); // object pos 4 + + auto* point_symbol_3 = new PointSymbol(); + point_symbol_3->setNumberComponent(0, 125); + point_symbol_3->setProtected(true); + map.addSymbol(point_symbol_3, 2); + point_object_2 = new PointObject(point_symbol_3); + point_object_2->setTag(QLatin1String("match"), QLatin1String("yes")); + QVERIFY(map.addObject(point_object_2) == 5); // object pos 5 + + std::unique_ptr find_feature = std::make_unique(*editor); + ObjectQuery single_query_is_true{QLatin1String("match"), ObjectQuery::OperatorIs, QLatin1String("yes")}; + + map.clearObjectSelection(false); + auto symbol_query = ObjectQuery(single_query_is_true); + find_feature->findAllMatchingObjects(symbol_query); + QVERIFY(map.getNumSelectedObjects() == 3); // matching objects at pos 0, 2, 4 while ignoring objects at pos 1, 3, 5 + + map.clearObjectSelection(false); + find_feature->findNextMatchingObject(symbol_query); + QVERIFY(map.getNumSelectedObjects() == 1); + auto* selected_object = map.getFirstSelectedObject(); + QCOMPARE(part->findObjectIndex(selected_object), 4); // search first returns the last matching object + + find_feature->findNextMatchingObject(symbol_query); + QVERIFY(map.getNumSelectedObjects() == 1); + selected_object = map.getFirstSelectedObject(); + QCOMPARE(part->findObjectIndex(selected_object), 2); + + find_feature->findNextMatchingObject(symbol_query); + QVERIFY(map.getNumSelectedObjects() == 1); + selected_object = map.getFirstSelectedObject(); + QCOMPARE(part->findObjectIndex(selected_object), 0); + + find_feature->findNextMatchingObject(symbol_query); + QVERIFY(map.getNumSelectedObjects() == 1); + selected_object = map.getFirstSelectedObject(); + QCOMPARE(part->findObjectIndex(selected_object), 4); +} + + /* * We don't need a real GUI window. */ namespace { - auto Q_DECL_UNUSED qpa_selected = qputenv("QT_QPA_PLATFORM", "minimal"); // clazy:exclude=non-pod-global-static + auto const Q_DECL_UNUSED qpa_selected = qputenv("QT_QPA_PLATFORM", "minimal"); // clazy:exclude=non-pod-global-static } diff --git a/test/object_query_t.h b/test/object_query_t.h index f688ff99e..9d077d40a 100644 --- a/test/object_query_t.h +++ b/test/object_query_t.h @@ -1,6 +1,6 @@ /* * Copyright 2016 Mitchell Krome - * Copyright 2017-2020 Kai Pastor + * Copyright 2017-2020, 2025 Kai Pastor * * This file is part of OpenOrienteering. * @@ -48,6 +48,7 @@ private slots: void testNegation(); void testToString(); void testParser(); + void testFindObjects(); private: const Object* testObject(); From b401a035de0b5ce7841c8f1b8ff5266833d89ccc Mon Sep 17 00:00:00 2001 From: Kai Pastor Date: Wed, 14 May 2025 14:11:53 +0200 Subject: [PATCH 11/16] Move and revise testFindFeatures --- test/object_query_t.cpp | 91 ++--------------------------------------- test/object_query_t.h | 3 +- test/tools_t.cpp | 65 +++++++++++++++++++++++++++-- test/tools_t.h | 4 +- 4 files changed, 70 insertions(+), 93 deletions(-) diff --git a/test/object_query_t.cpp b/test/object_query_t.cpp index c7e7b4022..d724011bf 100644 --- a/test/object_query_t.cpp +++ b/test/object_query_t.cpp @@ -1,6 +1,6 @@ /* * Copyright 2016 Mitchell Krome - * Copyright 2017-2022, 2025 Kai Pastor + * Copyright 2017-2022 Kai Pastor * * This file is part of OpenOrienteering. * @@ -20,8 +20,8 @@ #include "object_query_t.h" -#include #include +#include #include #include @@ -29,16 +29,11 @@ #include #include -#include "global.h" #include "core/map.h" -#include "core/map_part.h" #include "core/objects/object.h" -#include "core/objects/object_query.h" #include "core/objects/text_object.h" +#include "core/objects/object_query.h" #include "core/symbols/point_symbol.h" -#include "gui/main_window.h" -#include "gui/map/map_editor.h" -#include "gui/map/map_find_feature.h" using namespace OpenOrienteering; @@ -58,7 +53,6 @@ ObjectQueryTest::ObjectQueryTest(QObject* parent) // nothing } - const Object* ObjectQueryTest::testObject() { static TextObject obj; @@ -515,88 +509,11 @@ void ObjectQueryTest::testParser() } -void ObjectQueryTest::testFindObjects() -{ - Q_INIT_RESOURCE(resources); - doStaticInitializations(); - - Map map; - auto* window = new MainWindow(); - auto* editor = new MapEditorController(MapEditorController::MapEditor, &map); - window->setController(editor); - const auto* part = map.getCurrentPart(); - - auto* point_symbol_1 = new PointSymbol(); - point_symbol_1->setNumberComponent(0, 123); - map.addSymbol(point_symbol_1, 0); - auto* point_object_1 = new PointObject(point_symbol_1); - point_object_1->setTag(QLatin1String("match"), QLatin1String("yes")); - QVERIFY(map.addObject(point_object_1) == 0); // object pos 0 - - auto* point_object_2 = new PointObject(point_symbol_1); - point_object_2->setTag(QLatin1String("match"), QLatin1String("no")); - QVERIFY(map.addObject(point_object_2) == 1); // object pos 1 - - point_object_2 = new PointObject(point_symbol_1); - point_object_2->setTag(QLatin1String("match"), QLatin1String("yes")); - QVERIFY(map.addObject(point_object_2) == 2); // object pos 2 - - auto* point_symbol_2 = new PointSymbol(); - point_symbol_2->setNumberComponent(0, 124); - point_symbol_2->setHidden(true); - map.addSymbol(point_symbol_2, 1); - point_object_2 = new PointObject(point_symbol_2); - point_object_2->setTag(QLatin1String("match"), QLatin1String("yes")); - QVERIFY(map.addObject(point_object_2) == 3); // object pos 3 - - point_object_2 = new PointObject(point_symbol_1); - point_object_2->setTag(QLatin1String("match"), QLatin1String("yes")); - QVERIFY(map.addObject(point_object_2) == 4); // object pos 4 - - auto* point_symbol_3 = new PointSymbol(); - point_symbol_3->setNumberComponent(0, 125); - point_symbol_3->setProtected(true); - map.addSymbol(point_symbol_3, 2); - point_object_2 = new PointObject(point_symbol_3); - point_object_2->setTag(QLatin1String("match"), QLatin1String("yes")); - QVERIFY(map.addObject(point_object_2) == 5); // object pos 5 - - std::unique_ptr find_feature = std::make_unique(*editor); - ObjectQuery single_query_is_true{QLatin1String("match"), ObjectQuery::OperatorIs, QLatin1String("yes")}; - - map.clearObjectSelection(false); - auto symbol_query = ObjectQuery(single_query_is_true); - find_feature->findAllMatchingObjects(symbol_query); - QVERIFY(map.getNumSelectedObjects() == 3); // matching objects at pos 0, 2, 4 while ignoring objects at pos 1, 3, 5 - - map.clearObjectSelection(false); - find_feature->findNextMatchingObject(symbol_query); - QVERIFY(map.getNumSelectedObjects() == 1); - auto* selected_object = map.getFirstSelectedObject(); - QCOMPARE(part->findObjectIndex(selected_object), 4); // search first returns the last matching object - - find_feature->findNextMatchingObject(symbol_query); - QVERIFY(map.getNumSelectedObjects() == 1); - selected_object = map.getFirstSelectedObject(); - QCOMPARE(part->findObjectIndex(selected_object), 2); - - find_feature->findNextMatchingObject(symbol_query); - QVERIFY(map.getNumSelectedObjects() == 1); - selected_object = map.getFirstSelectedObject(); - QCOMPARE(part->findObjectIndex(selected_object), 0); - - find_feature->findNextMatchingObject(symbol_query); - QVERIFY(map.getNumSelectedObjects() == 1); - selected_object = map.getFirstSelectedObject(); - QCOMPARE(part->findObjectIndex(selected_object), 4); -} - - /* * We don't need a real GUI window. */ namespace { - auto const Q_DECL_UNUSED qpa_selected = qputenv("QT_QPA_PLATFORM", "minimal"); // clazy:exclude=non-pod-global-static + auto Q_DECL_UNUSED qpa_selected = qputenv("QT_QPA_PLATFORM", "minimal"); // clazy:exclude=non-pod-global-static } diff --git a/test/object_query_t.h b/test/object_query_t.h index 9d077d40a..f688ff99e 100644 --- a/test/object_query_t.h +++ b/test/object_query_t.h @@ -1,6 +1,6 @@ /* * Copyright 2016 Mitchell Krome - * Copyright 2017-2020, 2025 Kai Pastor + * Copyright 2017-2020 Kai Pastor * * This file is part of OpenOrienteering. * @@ -48,7 +48,6 @@ private slots: void testNegation(); void testToString(); void testParser(); - void testFindObjects(); private: const Object* testObject(); diff --git a/test/tools_t.cpp b/test/tools_t.cpp index 2b83ad31e..4ab93dfe6 100644 --- a/test/tools_t.cpp +++ b/test/tools_t.cpp @@ -1,6 +1,7 @@ /* * Copyright 2012, 2013 Thomas Schöps - * Copyright 2015-2020 Kai Pastor + * Copyright 2015-2020, 2025 Kai Pastor + * Copyright 2025 Matthias Kühlewein * * This file is part of OpenOrienteering. * @@ -35,10 +36,13 @@ #include "core/map_color.h" #include "core/map_coord.h" #include "core/objects/object.h" +#include "core/objects/object_query.h" #include "core/symbols/line_symbol.h" +#include "core/symbols/point_symbol.h" #include "global.h" #include "gui/main_window.h" #include "gui/map/map_editor.h" +#include "gui/map/map_find_feature.h" #include "gui/map/map_widget.h" #include "templates/paint_on_template_feature.h" #include "tools/edit_point_tool.h" @@ -161,7 +165,7 @@ void TestMapEditor::simulateDrag(const QPointF& start_pos, const QPointF& end_po } -// ### TestTools ### +// ### ToolsTest ### void ToolsTest::initTestCase() { @@ -229,6 +233,61 @@ void ToolsTest::paintOnTemplateFeature() } +void ToolsTest::testFindObjects() +{ + auto* map = new Map; + { + auto* normal_point_symbol = new PointSymbol(); + map->addSymbol(normal_point_symbol, 0); + + auto* hidden_point_symbol = new PointSymbol(); + hidden_point_symbol->setHidden(true); + map->addSymbol(hidden_point_symbol, 1); + + auto* protected_point_symbol = new PointSymbol(); + protected_point_symbol->setProtected(true); + map->addSymbol(protected_point_symbol, 2); + + auto add_object = [map](Symbol* symbol, const char* label) { + auto* object = new PointObject(symbol); + object->setTag(QLatin1String("match"), QLatin1String(label)); + map->addObject(object); + }; + add_object(normal_point_symbol, "yes"); // expected match + add_object(normal_point_symbol, "no"); + add_object(normal_point_symbol, "yes"); // expected match + add_object(hidden_point_symbol, "yes"); + add_object(normal_point_symbol, "yes"); // expected match + add_object(protected_point_symbol, "yes"); + } + + TestMapEditor editor(map); // taking ownership + MapFindFeature find_feature {*editor.editor}; + ObjectQuery query {QLatin1String("match"), ObjectQuery::OperatorIs, QLatin1String("yes")}; + + map->clearObjectSelection(false); + find_feature.findAllMatchingObjects(query); + QCOMPARE(map->getNumSelectedObjects(), 3); + + map->clearObjectSelection(false); + find_feature.findNextMatchingObject(query); + QCOMPARE(map->getNumSelectedObjects(), 1); + auto* first_match = map->getFirstSelectedObject(); + + find_feature.findNextMatchingObject(query); + QCOMPARE(map->getNumSelectedObjects(), 1); + QVERIFY(map->getFirstSelectedObject() != first_match); + + find_feature.findNextMatchingObject(query); + QCOMPARE(map->getNumSelectedObjects(), 1); + QVERIFY(map->getFirstSelectedObject() != first_match); + + find_feature.findNextMatchingObject(query); + QCOMPARE(map->getNumSelectedObjects(), 1); + QVERIFY(map->getFirstSelectedObject() == first_match); +} + + /* * We select a non-standard QPA because we don't need a real GUI window. * @@ -236,7 +295,7 @@ void ToolsTest::paintOnTemplateFeature() * However, it bails out with a QFontDatabase error (cf. QTBUG-33674) */ namespace { - auto Q_DECL_UNUSED qpa_selected = qputenv("QT_QPA_PLATFORM", "minimal"); // clazy:exclude=non-pod-global-static + auto const Q_DECL_UNUSED qpa_selected = qputenv("QT_QPA_PLATFORM", "minimal"); // clazy:exclude=non-pod-global-static } diff --git a/test/tools_t.h b/test/tools_t.h index 8e8bf6a22..21832b333 100644 --- a/test/tools_t.h +++ b/test/tools_t.h @@ -1,6 +1,6 @@ /* * Copyright 2012, 2013 Thomas Schöps - * Copyright 2017 Kai Pastor + * Copyright 2017, 2020, 2025 Kai Pastor * * This file is part of OpenOrienteering. * @@ -36,6 +36,8 @@ private slots: void editTool(); void paintOnTemplateFeature(); + + void testFindObjects(); }; #endif From b223b89035f7cd706ac5c7b7e18d142bec7666b5 Mon Sep 17 00:00:00 2001 From: Kai Pastor Date: Wed, 14 May 2025 14:20:24 +0200 Subject: [PATCH 12/16] Partially revert polishing No slot markup, member functions are good enough. No const on functions which hand out non-const member. Restore original order in header which matched order in source. Move the new functions for testing purpose from public to protected. The test can access them via light-weight derived type. --- src/gui/map/map_find_feature.cpp | 4 ---- src/gui/map/map_find_feature.h | 16 ++++++++-------- test/tools_t.cpp | 9 ++++++++- 3 files changed, 16 insertions(+), 13 deletions(-) diff --git a/src/gui/map/map_find_feature.cpp b/src/gui/map/map_find_feature.cpp index b12b1003d..ab7bbcc90 100644 --- a/src/gui/map/map_find_feature.cpp +++ b/src/gui/map/map_find_feature.cpp @@ -182,7 +182,6 @@ ObjectQuery MapFindFeature::makeQuery() const } -// slot void MapFindFeature::findNext() { auto query = makeQuery(); @@ -235,7 +234,6 @@ void MapFindFeature::findNextMatchingObject(ObjectQuery& query) } -// slot void MapFindFeature::findAll() { auto map = controller.getMap(); @@ -267,14 +265,12 @@ void MapFindFeature::findAllMatchingObjects(ObjectQuery& query) } -// slot void MapFindFeature::showHelp() const { Util::showHelp(controller.getWindow(), "find_objects.html"); } -// slot void MapFindFeature::tagSelectorToggled(bool active) { editor_stack->setCurrentIndex(active ? 1 : 0); diff --git a/src/gui/map/map_find_feature.h b/src/gui/map/map_find_feature.h index 56ed72bdd..9f4d67efa 100644 --- a/src/gui/map/map_find_feature.h +++ b/src/gui/map/map_find_feature.h @@ -54,15 +54,20 @@ class MapFindFeature : public QObject void setEnabled(bool enabled); - QAction* showDialogAction() const { return show_action; } + QAction* showDialogAction() { return show_action; } - QAction* findNextAction() const { return find_next_action; } + QAction* findNextAction() { return find_next_action; } +protected: void findNextMatchingObject(ObjectQuery& query); void findAllMatchingObjects(ObjectQuery& query); -private slots: +private: + void showDialog(); + + ObjectQuery makeQuery() const; + void findNext(); void findAll(); @@ -71,11 +76,6 @@ private slots: void tagSelectorToggled(bool active); -private: - void showDialog(); - - ObjectQuery makeQuery() const; - MapEditorController& controller; QPointer find_dialog; // child of controller's window diff --git a/test/tools_t.cpp b/test/tools_t.cpp index 4ab93dfe6..7ab8b56ea 100644 --- a/test/tools_t.cpp +++ b/test/tools_t.cpp @@ -262,7 +262,14 @@ void ToolsTest::testFindObjects() } TestMapEditor editor(map); // taking ownership - MapFindFeature find_feature {*editor.editor}; + + struct TestMapFindFeature : public MapFindFeature + { + TestMapFindFeature(MapEditorController &controller) : MapFindFeature(controller) {} + using MapFindFeature::findNextMatchingObject; + using MapFindFeature::findAllMatchingObjects; + } find_feature {*editor.editor}; + ObjectQuery query {QLatin1String("match"), ObjectQuery::OperatorIs, QLatin1String("yes")}; map->clearObjectSelection(false); From 5b110779d5af93cd62681cebd9213fe854ec4022 Mon Sep 17 00:00:00 2001 From: Kai Pastor Date: Wed, 14 May 2025 14:55:18 +0200 Subject: [PATCH 13/16] Refactoring, cont. --- src/gui/map/map_find_feature.cpp | 37 +++++++++++++++++--------------- src/gui/map/map_find_feature.h | 5 ++--- test/tools_t.cpp | 17 +++++---------- 3 files changed, 27 insertions(+), 32 deletions(-) diff --git a/src/gui/map/map_find_feature.cpp b/src/gui/map/map_find_feature.cpp index ab7bbcc90..447953d70 100644 --- a/src/gui/map/map_find_feature.cpp +++ b/src/gui/map/map_find_feature.cpp @@ -191,19 +191,14 @@ void MapFindFeature::findNext() window->showStatusBarMessage(OpenOrienteering::TagSelectWidget::tr("Invalid query"), 2000); return; } - - auto* map = controller.getMap(); - findNextMatchingObject(query); - map->emitSelectionChanged(); - map->ensureVisibilityOfSelectedObjects(Map::FullVisibility); - - if (!map->selectedObjects().empty()) - controller.setEditTool(); + findNextMatchingObject(controller, query); } -void MapFindFeature::findNextMatchingObject(ObjectQuery& query) +// static +void MapFindFeature::findNextMatchingObject(MapEditorController& controller, const ObjectQuery& query) { auto* map = controller.getMap(); + Object* first_match = nullptr; // the first match in all objects Object* pivot_object = map->getFirstSelectedObject(); Object* next_match = nullptr; // the next match after pivot_object @@ -231,6 +226,12 @@ void MapFindFeature::findNextMatchingObject(ObjectQuery& query) next_match = first_match; if (next_match) map->addObjectToSelection(next_match, false); + + map->emitSelectionChanged(); + map->ensureVisibilityOfSelectedObjects(Map::FullVisibility); + + if (!map->selectedObjects().empty()) + controller.setEditTool(); } @@ -246,22 +247,24 @@ void MapFindFeature::findAll() return; } - findAllMatchingObjects(query); - map->emitSelectionChanged(); - map->ensureVisibilityOfSelectedObjects(Map::FullVisibility); - controller.getWindow()->showStatusBarMessage(OpenOrienteering::TagSelectWidget::tr("%n object(s) selected", nullptr, map->getNumSelectedObjects()), 2000); - - if (!map->selectedObjects().empty()) - controller.setEditTool(); + findAllMatchingObjects(controller, query); } -void MapFindFeature::findAllMatchingObjects(ObjectQuery& query) +// static +void MapFindFeature::findAllMatchingObjects(MapEditorController& controller, const ObjectQuery& query) { auto map = controller.getMap(); map->getCurrentPart()->applyOnMatchingObjects([map](Object* object) { if (isSelectable(object)) map->addObjectToSelection(object, false); }, std::cref(query)); + + map->emitSelectionChanged(); + map->ensureVisibilityOfSelectedObjects(Map::FullVisibility); + controller.getWindow()->showStatusBarMessage(OpenOrienteering::TagSelectWidget::tr("%n object(s) selected", nullptr, map->getNumSelectedObjects()), 2000); + + if (!map->selectedObjects().empty()) + controller.setEditTool(); } diff --git a/src/gui/map/map_find_feature.h b/src/gui/map/map_find_feature.h index 9f4d67efa..f4af33672 100644 --- a/src/gui/map/map_find_feature.h +++ b/src/gui/map/map_find_feature.h @@ -58,10 +58,9 @@ class MapFindFeature : public QObject QAction* findNextAction() { return find_next_action; } -protected: - void findNextMatchingObject(ObjectQuery& query); + static void findNextMatchingObject(MapEditorController& controller, const ObjectQuery& query); - void findAllMatchingObjects(ObjectQuery& query); + static void findAllMatchingObjects(MapEditorController& controller, const ObjectQuery& query); private: void showDialog(); diff --git a/test/tools_t.cpp b/test/tools_t.cpp index 7ab8b56ea..c19889c99 100644 --- a/test/tools_t.cpp +++ b/test/tools_t.cpp @@ -263,33 +263,26 @@ void ToolsTest::testFindObjects() TestMapEditor editor(map); // taking ownership - struct TestMapFindFeature : public MapFindFeature - { - TestMapFindFeature(MapEditorController &controller) : MapFindFeature(controller) {} - using MapFindFeature::findNextMatchingObject; - using MapFindFeature::findAllMatchingObjects; - } find_feature {*editor.editor}; - ObjectQuery query {QLatin1String("match"), ObjectQuery::OperatorIs, QLatin1String("yes")}; map->clearObjectSelection(false); - find_feature.findAllMatchingObjects(query); + MapFindFeature::findAllMatchingObjects(*editor.editor, query); QCOMPARE(map->getNumSelectedObjects(), 3); map->clearObjectSelection(false); - find_feature.findNextMatchingObject(query); + MapFindFeature::findNextMatchingObject(*editor.editor, query); QCOMPARE(map->getNumSelectedObjects(), 1); auto* first_match = map->getFirstSelectedObject(); - find_feature.findNextMatchingObject(query); + MapFindFeature::findNextMatchingObject(*editor.editor, query); QCOMPARE(map->getNumSelectedObjects(), 1); QVERIFY(map->getFirstSelectedObject() != first_match); - find_feature.findNextMatchingObject(query); + MapFindFeature::findNextMatchingObject(*editor.editor, query); QCOMPARE(map->getNumSelectedObjects(), 1); QVERIFY(map->getFirstSelectedObject() != first_match); - find_feature.findNextMatchingObject(query); + MapFindFeature::findNextMatchingObject(*editor.editor, query); QCOMPARE(map->getNumSelectedObjects(), 1); QVERIFY(map->getFirstSelectedObject() == first_match); } From e6b874c04be1df507a0b89f83189db5ecfcfdd95 Mon Sep 17 00:00:00 2001 From: Kai Pastor Date: Wed, 14 May 2025 19:13:38 +0200 Subject: [PATCH 14/16] Refactoring, oversight and cont. --- src/gui/map/map_find_feature.cpp | 6 ++---- test/tools_t.cpp | 3 +-- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/src/gui/map/map_find_feature.cpp b/src/gui/map/map_find_feature.cpp index 447953d70..cbed406fd 100644 --- a/src/gui/map/map_find_feature.cpp +++ b/src/gui/map/map_find_feature.cpp @@ -237,16 +237,12 @@ void MapFindFeature::findNextMatchingObject(MapEditorController& controller, con void MapFindFeature::findAll() { - auto map = controller.getMap(); - map->clearObjectSelection(false); - auto query = makeQuery(); if (!query) { controller.getWindow()->showStatusBarMessage(OpenOrienteering::TagSelectWidget::tr("Invalid query"), 2000); return; } - findAllMatchingObjects(controller, query); } @@ -254,6 +250,8 @@ void MapFindFeature::findAll() void MapFindFeature::findAllMatchingObjects(MapEditorController& controller, const ObjectQuery& query) { auto map = controller.getMap(); + map->clearObjectSelection(false); + map->getCurrentPart()->applyOnMatchingObjects([map](Object* object) { if (isSelectable(object)) map->addObjectToSelection(object, false); diff --git a/test/tools_t.cpp b/test/tools_t.cpp index c19889c99..30da6c2ce 100644 --- a/test/tools_t.cpp +++ b/test/tools_t.cpp @@ -264,12 +264,11 @@ void ToolsTest::testFindObjects() TestMapEditor editor(map); // taking ownership ObjectQuery query {QLatin1String("match"), ObjectQuery::OperatorIs, QLatin1String("yes")}; + QVERIFY(query); - map->clearObjectSelection(false); MapFindFeature::findAllMatchingObjects(*editor.editor, query); QCOMPARE(map->getNumSelectedObjects(), 3); - map->clearObjectSelection(false); MapFindFeature::findNextMatchingObject(*editor.editor, query); QCOMPARE(map->getNumSelectedObjects(), 1); auto* first_match = map->getFirstSelectedObject(); From 332f4ad7c29b575274888de93731fab84602b0aa Mon Sep 17 00:00:00 2001 From: Kai Pastor Date: Wed, 14 May 2025 19:17:12 +0200 Subject: [PATCH 15/16] Move error message to makeQuery() --- src/gui/map/map_find_feature.cpp | 21 ++++++--------------- 1 file changed, 6 insertions(+), 15 deletions(-) diff --git a/src/gui/map/map_find_feature.cpp b/src/gui/map/map_find_feature.cpp index cbed406fd..56cde15cb 100644 --- a/src/gui/map/map_find_feature.cpp +++ b/src/gui/map/map_find_feature.cpp @@ -178,20 +178,16 @@ ObjectQuery MapFindFeature::makeQuery() const query = tag_selector->makeQuery(); } } + if (!query) + controller.getWindow()->showStatusBarMessage(OpenOrienteering::TagSelectWidget::tr("Invalid query"), 2000); return query; } void MapFindFeature::findNext() { - auto query = makeQuery(); - if (!query) - { - if (auto window = controller.getWindow()) - window->showStatusBarMessage(OpenOrienteering::TagSelectWidget::tr("Invalid query"), 2000); - return; - } - findNextMatchingObject(controller, query); + if (auto query = makeQuery()) + findNextMatchingObject(controller, query); } // static @@ -237,13 +233,8 @@ void MapFindFeature::findNextMatchingObject(MapEditorController& controller, con void MapFindFeature::findAll() { - auto query = makeQuery(); - if (!query) - { - controller.getWindow()->showStatusBarMessage(OpenOrienteering::TagSelectWidget::tr("Invalid query"), 2000); - return; - } - findAllMatchingObjects(controller, query); + if (auto query = makeQuery()) + findAllMatchingObjects(controller, query); } // static From b9cf6b35b9ba77d729b024ba7fcf06625bd51ba1 Mon Sep 17 00:00:00 2001 From: Kai Pastor Date: Wed, 14 May 2025 21:27:15 +0200 Subject: [PATCH 16/16] Restore clearing the selection on error There is a status message, but it hardly visible at the moment. --- src/gui/map/map_find_feature.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/gui/map/map_find_feature.cpp b/src/gui/map/map_find_feature.cpp index 56cde15cb..023bb10a9 100644 --- a/src/gui/map/map_find_feature.cpp +++ b/src/gui/map/map_find_feature.cpp @@ -179,7 +179,10 @@ ObjectQuery MapFindFeature::makeQuery() const } } if (!query) + { + controller.getMap()->clearObjectSelection(true); controller.getWindow()->showStatusBarMessage(OpenOrienteering::TagSelectWidget::tr("Invalid query"), 2000); + } return query; }