Skip to content
Merged
71 changes: 39 additions & 32 deletions src/gui/map/map_find_feature.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2017-2024 Kai Pastor
* Copyright 2017-2020, 2024, 2025 Kai Pastor
*
* This file is part of OpenOrienteering.
*
Expand Down Expand Up @@ -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"
Expand All @@ -44,7 +46,17 @@

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}
Expand Down Expand Up @@ -172,46 +184,41 @@ 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)
{
if (auto window = controller.getWindow())
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 = [&](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) && query(object))
{
if (first_object)
{
if (object == first_object)
first_object = nullptr;
}
else if (query(object))
{
next_object = object;
}
if (after_pivot)
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->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);

Expand All @@ -231,9 +238,9 @@ void MapFindFeature::findAll()
controller.getWindow()->showStatusBarMessage(OpenOrienteering::TagSelectWidget::tr("Invalid query"), 2000);
return;
}

map->getCurrentPart()->applyOnMatchingObjects([map](Object* object) {
map->addObjectToSelection(object, false);
if (isSelectable(object))
map->addObjectToSelection(object, false);
}, std::cref(query));
map->emitSelectionChanged();
map->ensureVisibilityOfSelectedObjects(Map::FullVisibility);
Expand Down