Path: blob/main/src/utils/gui/windows/GUIDialog_ChooserAbstract.cpp
169684 views
/****************************************************************************/1// Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo2// Copyright (C) 2001-2025 German Aerospace Center (DLR) and others.3// This program and the accompanying materials are made available under the4// terms of the Eclipse Public License 2.0 which is available at5// https://www.eclipse.org/legal/epl-2.0/6// This Source Code may also be made available under the following Secondary7// Licenses when the conditions for such availability set forth in the Eclipse8// Public License 2.0 are satisfied: GNU General Public License, version 29// or later which is available at10// https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html11// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later12/****************************************************************************/13/// @file GUIDialog_ChooserAbstract.cpp14/// @author Daniel Krajzewicz15/// @author Jakob Erdmann16/// @author Michael Behrisch17/// @date Sept 200218///19// Class for the window that allows to choose a street, junction or vehicle20/****************************************************************************/21#include <config.h>2223#include <string>24#include <vector>25#include <fxkeys.h>26#include <utils/common/MsgHandler.h>27#include <utils/gui/windows/GUIAppEnum.h>28#include <utils/gui/windows/GUIGlChildWindow.h>29#include <utils/gui/windows/GUIMainWindow.h>30#include <utils/gui/globjects/GUIGlObject.h>31#include <utils/gui/globjects/GUIGlObjectStorage.h>32#include <utils/gui/images/GUIIconSubSys.h>33#include <utils/gui/div/GUIGlobalSelection.h>34#include <utils/gui/div/GUIDesigns.h>35#include <utils/gui/globjects/GUIGlObject_AbstractAdd.h>3637#include "GUIDialog_ChooserAbstract.h"383940// ===========================================================================41// FOX callback mapping42// ===========================================================================43FXDEFMAP(GUIDialog_ChooserAbstract) GUIDialog_ChooserAbstractMap[] = {44FXMAPFUNC(SEL_COMMAND, MID_CHOOSER_CENTER, GUIDialog_ChooserAbstract::onCmdCenter),45FXMAPFUNC(SEL_COMMAND, MID_CHOOSER_TRACK, GUIDialog_ChooserAbstract::onCmdTrack),46FXMAPFUNC(SEL_COMMAND, MID_CANCEL, GUIDialog_ChooserAbstract::onCmdClose),47FXMAPFUNC(SEL_CHANGED, MID_CHOOSER_TEXT, GUIDialog_ChooserAbstract::onChgText),48FXMAPFUNC(SEL_COMMAND, MID_CHOOSER_TEXT, GUIDialog_ChooserAbstract::onCmdText),49FXMAPFUNC(SEL_KEYPRESS, 0, GUIDialog_ChooserAbstract::onKeyPress),50FXMAPFUNC(SEL_CHANGED, MID_CHOOSER_LIST, GUIDialog_ChooserAbstract::onChgList),51FXMAPFUNC(SEL_DESELECTED, MID_CHOOSER_LIST, GUIDialog_ChooserAbstract::onChgListSel),52FXMAPFUNC(SEL_COMMAND, MID_CHOOSER_FILTER, GUIDialog_ChooserAbstract::onCmdFilter),53FXMAPFUNC(SEL_COMMAND, MID_CHOOSER_FILTER_SUBSTR, GUIDialog_ChooserAbstract::onCmdFilterSubstr),54FXMAPFUNC(SEL_COMMAND, MID_CHOOSEN_INVERT, GUIDialog_ChooserAbstract::onCmdToggleSelection),55FXMAPFUNC(SEL_COMMAND, MID_CHOOSEN_SELECT, GUIDialog_ChooserAbstract::onCmdAddListSelection),56FXMAPFUNC(SEL_COMMAND, MID_CHOOSEN_CLEAR, GUIDialog_ChooserAbstract::onCmdClearListSelection),57FXMAPFUNC(SEL_COMMAND, MID_CHOOSEN_NAME, GUIDialog_ChooserAbstract::onCmdLocateByName),58FXMAPFUNC(SEL_COMMAND, MID_UPDATE, GUIDialog_ChooserAbstract::onCmdUpdate),59};6061FXIMPLEMENT(GUIDialog_ChooserAbstract, FXMainWindow, GUIDialog_ChooserAbstractMap, ARRAYNUMBER(GUIDialog_ChooserAbstractMap))626364// ===========================================================================65// method definitions66// ===========================================================================67#ifdef _MSC_VER68#pragma warning(push)69#pragma warning(disable: 4355) // mask warning about "this" in initializers70#endif71GUIDialog_ChooserAbstract::GUIDialog_ChooserAbstract(GUIGlChildWindow* windowsParent, int messageId,72FXIcon* icon, const FXString& title, const std::vector<GUIGlID>& ids, GUIGlObjectStorage& /*glStorage*/) :73FXMainWindow(windowsParent->getApp(), title, icon, nullptr, GUIDesignChooserDialog),74GUIPersistentWindowPos(this, "LOCATOR", true, 20, 40, 300, 350),75myWindowsParent(windowsParent),76myMessageId(messageId),77myLocateByName(false),78myHaveFilteredSubstring(false) {79FXHorizontalFrame* hbox = new FXHorizontalFrame(this, GUIDesignAuxiliarFrame);80// build the list81FXVerticalFrame* layoutLeft = new FXVerticalFrame(hbox, GUIDesignChooserLayoutLeft);82myTextEntry = new FXTextField(layoutLeft, 0, this, MID_CHOOSER_TEXT, TEXTFIELD_ENTER_ONLY | GUIDesignChooserTextField);83FXVerticalFrame* layoutList = new FXVerticalFrame(layoutLeft, GUIDesignChooserLayoutList);84myList = new FXList(layoutList, this, MID_CHOOSER_LIST, GUIDesignChooserListSingle);85// build the buttons86FXVerticalFrame* layoutRight = new FXVerticalFrame(hbox, GUIDesignChooserLayoutRight);87myCenterButton = GUIDesigns::buildFXButton(layoutRight, TL("Center"), "", "", GUIIconSubSys::getIcon(GUIIcon::RECENTERVIEW), this, MID_CHOOSER_CENTER, GUIDesignChooserButtons);88myTrackButton = GUIDesigns::buildFXButton(layoutRight, TL("Track"), "", "", GUIIconSubSys::getIcon(GUIIcon::RECENTERVIEW), this, MID_CHOOSER_TRACK, GUIDesignChooserButtons);89// only enable Track Button if we're locating vehicles90if (title.text() != std::string(TL("Vehicle Chooser"))) {91myTrackButton->disable();92myTrackButton->hide();93}94new FXHorizontalSeparator(layoutRight, GUIDesignHorizontalSeparator);95GUIDesigns::buildFXButton(layoutRight, TL("&Hide Unselected"), "", "", GUIIconSubSys::getIcon(GUIIcon::FLAG), this, MID_CHOOSER_FILTER, GUIDesignChooserButtons);96GUIDesigns::buildFXButton(layoutRight, TL("By &Name"), TL("Locate item by name"), "", nullptr, this, MID_CHOOSEN_NAME, GUIDesignChooserButtons);97GUIDesigns::buildFXButton(layoutRight, TL("&Select/deselect"), "", TL("Select/deselect current object"), GUIIconSubSys::getIcon(GUIIcon::FLAG), this, MID_CHOOSEN_INVERT, GUIDesignChooserButtons);98GUIDesigns::buildFXButton(layoutRight, TL("&Filter substring"), "", "", nullptr, this, MID_CHOOSER_FILTER_SUBSTR, GUIDesignChooserButtons);99GUIDesigns::buildFXButton(layoutRight, TL("Select &all"), "", TL("Select all items in list"), GUIIconSubSys::getIcon(GUIIcon::FLAG), this, MID_CHOOSEN_SELECT, GUIDesignChooserButtons);100GUIDesigns::buildFXButton(layoutRight, TL("&Deselect all"), "", TL("Deselect all items in list"), GUIIconSubSys::getIcon(GUIIcon::FLAG), this, MID_CHOOSEN_CLEAR, GUIDesignChooserButtons);101GUIDesigns::buildFXButton(layoutRight, TL("&Update"), "", TL("Reload all ids"), GUIIconSubSys::getIcon(GUIIcon::RELOAD), this, MID_UPDATE, GUIDesignChooserButtons);102new FXHorizontalSeparator(layoutRight, GUIDesignHorizontalSeparator);103GUIDesigns::buildFXButton(layoutRight, TL("&Close"), "", "", GUIIconSubSys::getIcon(GUIIcon::NO), this, MID_CANCEL, GUIDesignChooserButtons);104myCountLabel = new FXLabel(layoutRight, "placeholder", nullptr, LAYOUT_BOTTOM | LAYOUT_FILL_X | JUSTIFY_LEFT);105myCaseSensitive = new FXCheckButton(layoutRight, TL("case-sensitive search"));106myCaseSensitive->setCheck(getApp()->reg().readIntEntry("LOCATOR", "caseSensitive", 0) == 1);107myInstantCenter = new FXCheckButton(layoutRight, TL("auto-center"));108myInstantCenter->setCheck(getApp()->reg().readIntEntry("LOCATOR", "autoCenter", 0) == 1);109refreshList(ids);110// add child in windowsParent111myWindowsParent->getGUIMainWindowParent()->addChild(this);112loadWindowPos();113// create and show dialog114create();115show();116}117#ifdef _MSC_VER118#pragma warning(pop)119#endif120121122GUIDialog_ChooserAbstract::~GUIDialog_ChooserAbstract() {123// remove child from windowsParent124myWindowsParent->getGUIMainWindowParent()->removeChild(this);125getApp()->reg().writeIntEntry("LOCATOR", "autoCenter", myInstantCenter->getCheck());126getApp()->reg().writeIntEntry("LOCATOR", "caseSensitive", myCaseSensitive->getCheck());127}128129130GUIGlObject*131GUIDialog_ChooserAbstract::getObject() const {132return static_cast<GUIGlObject*>(mySelected);133}134135136void137GUIDialog_ChooserAbstract::show() {138FXMainWindow::show();139myTextEntry->setFocus();140}141142143long144GUIDialog_ChooserAbstract::onCmdCenter(FXObject*, FXSelector, void*) {145int selected = myList->getCurrentItem();146if (selected >= 0) {147myWindowsParent->getView()->stopTrack();148myWindowsParent->setView(*static_cast<GUIGlID*>(myList->getItemData(selected)));149}150return 1;151}152153154long155GUIDialog_ChooserAbstract::onCmdTrack(FXObject*, FXSelector, void*) {156int selected = myList->getCurrentItem();157if (selected >= 0) {158myWindowsParent->setView(*static_cast<GUIGlID*>(myList->getItemData(selected)));159GUIGlID id = *static_cast<GUIGlID*>(myList->getItemData(selected));160GUIGlObject* o = GUIGlObjectStorage::gIDStorage.getObjectBlocking(id);161if (o->getType() == GLO_VEHICLE) {162myWindowsParent->getView()->startTrack(o->getGlID());163}164GUIGlObjectStorage::gIDStorage.unblockObject(id);165}166return 1;167}168169170long171GUIDialog_ChooserAbstract::onCmdClose(FXObject*, FXSelector, void*) {172close(true);173return 1;174}175176long177GUIDialog_ChooserAbstract::onChgList(FXObject*, FXSelector, void*) {178// mouse-click toggles item selection but changked current item with179// keyboard does not affect select180// Enabling the line blow toggles the behavior (which must be fixed via onChgListSel)181myList->selectItem(myList->getCurrentItem());182if (myInstantCenter->getCheck()) {183onCmdCenter(nullptr, 0, nullptr);184}185return 1;186}187188long189GUIDialog_ChooserAbstract::onChgListSel(FXObject*, FXSelector, void*) {190myList->selectItem(myList->getCurrentItem());191return 1;192}193194long195GUIDialog_ChooserAbstract::onChgText(FXObject*, FXSelector, void*) {196const bool caseSensitive = myCaseSensitive->getCheck() == TRUE;197int id = -1;198if (myLocateByName || myHaveFilteredSubstring) {199// findItem does not support substring search200const int numItems = myList->getNumItems();201FXString t = myTextEntry->getText();202if (!caseSensitive) {203t = t.lower();204}205for (int i = 0; i < numItems; i++) {206FXString t2 = myList->getItemText(i);207if (!caseSensitive) {208t2 = t2.lower();209}210if (t2.find(t) >= 0) {211id = i;212break;213}214}215} else {216const int caseOpt = caseSensitive ? 0 : SEARCH_IGNORECASE;217id = myList->findItem(myTextEntry->getText(), -1, SEARCH_PREFIX | caseOpt);218}219if (id < 0) {220if (myList->getNumItems() > 0) {221myList->deselectItem(myList->getCurrentItem());222}223myCenterButton->disable();224myTrackButton->disable();225return 1;226}227myList->deselectItem(myList->getCurrentItem());228myList->makeItemVisible(id);229myList->selectItem(id);230myList->setCurrentItem(id, true);231myCenterButton->enable();232myTrackButton->enable();233return 1;234}235236237long238GUIDialog_ChooserAbstract::onCmdText(FXObject*, FXSelector, void*) {239int current = myList->getCurrentItem();240if (current >= 0 && myList->isItemSelected(current)) {241myWindowsParent->setView(*static_cast<GUIGlID*>(myList->getItemData(current)));242}243return 1;244}245246247248long249GUIDialog_ChooserAbstract::onKeyPress(FXObject* o, FXSelector sel, void* ptr) {250FXEvent* event = (FXEvent*)ptr;251if (event->code == KEY_Return) {252onCmdText(nullptr, 0, nullptr);253if ((event->state & CONTROLMASK) != 0) {254close(true);255}256return 1;257} else if (event->code == KEY_Left || (event->code == KEY_Up && myList->getCurrentItem() == 0)) {258myTextEntry->setFocus();259return 1;260} else if (event->code == KEY_Escape) {261close(true);262return 1;263}264return FXMainWindow::onKeyPress(o, sel, ptr);265}266267268long269GUIDialog_ChooserAbstract::onCmdFilter(FXObject*, FXSelector, void*) {270FXIcon* flag = GUIIconSubSys::getIcon(GUIIcon::FLAG);271std::vector<GUIGlID> selectedGlIDs;272const int numItems = myList->getNumItems();273for (int i = 0; i < numItems; i++) {274const GUIGlID glID = *static_cast<GUIGlID*>(myList->getItemData(i));275if (myList->getItemIcon(i) == flag) {276selectedGlIDs.push_back(glID);277}278}279refreshList(selectedGlIDs);280return 1;281}282283284long285GUIDialog_ChooserAbstract::onCmdFilterSubstr(FXObject*, FXSelector, void*) {286const bool caseSensitive = myCaseSensitive->getCheck() == TRUE;287std::vector<GUIGlID> selectedGlIDs;288const int numItems = myList->getNumItems();289FXString t = myTextEntry->getText();290if (!caseSensitive) {291t = t.lower();292}293for (int i = 0; i < numItems; i++) {294FXString t2 = myList->getItemText(i);295if (!caseSensitive) {296t2 = t2.lower();297}298if (t2.find(t) >= 0) {299const GUIGlID glID = *static_cast<GUIGlID*>(myList->getItemData(i));300selectedGlIDs.push_back(glID);301}302}303refreshList(selectedGlIDs);304// filter ACs in netedit305filterACs(selectedGlIDs);306myHaveFilteredSubstring = true;307onChgText(nullptr, 0, nullptr);308return 1;309}310311312std::string313GUIDialog_ChooserAbstract::getObjectName(GUIGlObject* o) const {314if (myLocateByName) {315return o->getOptionalName();316} else {317return o->getMicrosimID();318}319}320321void322GUIDialog_ChooserAbstract::refreshList(const std::vector<GUIGlID>& ids) {323myList->clearItems();324for (auto i : ids) {325GUIGlObject* o = GUIGlObjectStorage::gIDStorage.getObjectBlocking(i);326if (o == nullptr) {327continue;328}329const std::string& name = getObjectName(o);330const bool selected = myWindowsParent->isSelected(o);331FXIcon* const ico = selected ? GUIIconSubSys::getIcon(GUIIcon::FLAG) : nullptr;332myIDs.insert(o->getGlID());333myList->appendItem(name.c_str(), ico, (void*) & (*myIDs.find(o->getGlID())));334GUIGlObjectStorage::gIDStorage.unblockObject(i);335}336myList->update();337myCountLabel->setText(TLF("% objects", toString(ids.size())).c_str());338}339340341long342GUIDialog_ChooserAbstract::onCmdToggleSelection(FXObject*, FXSelector, void*) {343FXIcon* flag = GUIIconSubSys::getIcon(GUIIcon::FLAG);344int i = myList->getCurrentItem();345if (i >= 0) {346toggleSelection(i);347if (myList->getItemIcon(i) == flag) {348myList->setItemIcon(i, nullptr);349} else {350myList->setItemIcon(i, flag);351}352}353myList->update();354myWindowsParent->getView()->update();355return 1;356}357358359long360GUIDialog_ChooserAbstract::onCmdAddListSelection(FXObject*, FXSelector, void*) {361FXIcon* flag = GUIIconSubSys::getIcon(GUIIcon::FLAG);362const int numItems = myList->getNumItems();363for (int i = 0; i < numItems; i++) {364select(i);365myList->setItemIcon(i, flag);366}367myList->update();368myWindowsParent->getView()->update();369return 1;370}371372373long374GUIDialog_ChooserAbstract::onCmdClearListSelection(FXObject*, FXSelector, void*) {375const int numItems = myList->getNumItems();376for (int i = 0; i < numItems; i++) {377deselect(i);378myList->setItemIcon(i, nullptr);379}380myList->update();381myWindowsParent->getView()->update();382return 1;383}384385386long387GUIDialog_ChooserAbstract::onCmdLocateByName(FXObject*, FXSelector, void*) {388std::vector<std::pair<std::string, GUIGlID> > namesAndIDs;389myLocateByName = true;390const int numItems = myList->getNumItems();391for (int i = 0; i < numItems; i++) {392GUIGlID glID = *static_cast<GUIGlID*>(myList->getItemData(i));393GUIGlObject* o = GUIGlObjectStorage::gIDStorage.getObjectBlocking(glID);394if (o != 0) {395const std::string& name = getObjectName(o);396if (name != "") {397namesAndIDs.push_back(std::make_pair(name, glID));398}399}400GUIGlObjectStorage::gIDStorage.unblockObject(glID);401}402std::sort(namesAndIDs.begin(), namesAndIDs.end());403std::vector<GUIGlID> selectedGlIDs;404for (const auto& item : namesAndIDs) {405selectedGlIDs.push_back(item.second);406}407refreshList(selectedGlIDs);408myTextEntry->setFocus();409return 1;410}411412long413GUIDialog_ChooserAbstract::onCmdUpdate(FXObject*, FXSelector, void*) {414refreshList(myWindowsParent->getObjectIDs(myMessageId));415return 1;416}417418void419GUIDialog_ChooserAbstract::toggleSelection(int listIndex) {420GUIGlID* glID = static_cast<GUIGlID*>(myList->getItemData(listIndex));421gSelected.toggleSelection(*glID);422}423424void425GUIDialog_ChooserAbstract::select(int listIndex) {426GUIGlID* glID = static_cast<GUIGlID*>(myList->getItemData(listIndex));427gSelected.select(*glID);428}429430void431GUIDialog_ChooserAbstract::deselect(int listIndex) {432GUIGlID* glID = static_cast<GUIGlID*>(myList->getItemData(listIndex));433gSelected.deselect(*glID);434}435436437void438GUIDialog_ChooserAbstract::filterACs(const std::vector<GUIGlID>& /*GLIDs*/) {439// overrided in GNEACChooserDialog440}441442/****************************************************************************/443444445