Path: blob/main/src/netedit/frames/common/GNEDeleteFrame.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 GNEDeleteFrame.cpp14/// @author Pablo Alvarez Lopez15/// @date Dec 201616///17// The Widget for remove network-elements18/****************************************************************************/1920#include <netedit/GNEApplicationWindow.h>21#include <netedit/GNENet.h>22#include <netedit/GNEInternalTest.h>23#include <netedit/GNEViewParent.h>24#include <netedit/GNETagProperties.h>25#include <netedit/GNEUndoList.h>26#include <netedit/dialogs/basic/GNEWarningBasicDialog.h>27#include <netedit/elements/additional/GNEPoly.h>28#include <netedit/elements/additional/GNETAZ.h>29#include <netedit/elements/network/GNEConnection.h>30#include <netedit/elements/network/GNECrossing.h>31#include <utils/gui/div/GUIDesigns.h>3233#include "GNEDeleteFrame.h"3435// ===========================================================================36// FOX callback mapping37// ===========================================================================3839FXDEFMAP(GNEDeleteFrame::DeleteOptions) DeleteOptionsMap[] = {40FXMAPFUNC(SEL_COMMAND, MID_GNE_SET_ATTRIBUTE, GNEDeleteFrame::DeleteOptions::onCmdSetOption),41};4243FXDEFMAP(GNEDeleteFrame::ProtectElements) ProtectElementsMap[] = {44FXMAPFUNC(SEL_COMMAND, MID_GNE_PROTECT_ALL, GNEDeleteFrame::ProtectElements::onCmdProtectAll),45FXMAPFUNC(SEL_UPDATE, MID_GNE_PROTECT_ALL, GNEDeleteFrame::ProtectElements::onUpdProtectAll),46FXMAPFUNC(SEL_COMMAND, MID_GNE_UNPROTECT_ALL, GNEDeleteFrame::ProtectElements::onCmdUnprotectAll),47FXMAPFUNC(SEL_UPDATE, MID_GNE_UNPROTECT_ALL, GNEDeleteFrame::ProtectElements::onUpdUnprotectAll),48};4950// Object implementation51FXIMPLEMENT(GNEDeleteFrame::DeleteOptions, MFXGroupBoxModule, DeleteOptionsMap, ARRAYNUMBER(DeleteOptionsMap))52FXIMPLEMENT(GNEDeleteFrame::ProtectElements, MFXGroupBoxModule, ProtectElementsMap, ARRAYNUMBER(ProtectElementsMap))5354// ---------------------------------------------------------------------------55// GNEDeleteFrame::DeleteOptions - methods56// ---------------------------------------------------------------------------5758GNEDeleteFrame::DeleteOptions::DeleteOptions(GNEDeleteFrame* deleteFrameParent) :59MFXGroupBoxModule(deleteFrameParent, TL("Options")),60myDeleteFrameParent(deleteFrameParent) {61// Create checkbox for enable/disable delete only geomtery point(by default, disabled)62myDeleteOnlyGeometryPoints = new FXCheckButton(getCollapsableFrame(), TL("Delete geometry points"), this, MID_GNE_SET_ATTRIBUTE, GUIDesignCheckButton);63myDeleteOnlyGeometryPoints->setCheck(FALSE);64}656667GNEDeleteFrame::DeleteOptions::~DeleteOptions() {}686970bool71GNEDeleteFrame::DeleteOptions::deleteOnlyGeometryPoints() const {72return (myDeleteOnlyGeometryPoints->getCheck() == TRUE);73}747576long77GNEDeleteFrame::DeleteOptions::onCmdSetOption(FXObject*, FXSelector, void*) {78myDeleteFrameParent->getViewNet()->update();79return 1;80}8182// ---------------------------------------------------------------------------83// GNEDeleteFrame::SubordinatedElements - methods84// ---------------------------------------------------------------------------8586GNEDeleteFrame::SubordinatedElements::SubordinatedElements(const GNEJunction* junction) :87SubordinatedElements(junction, junction->getNet()->getViewNet(), junction) {88// add the number of subodinated elements of child edges89for (const auto& edge : junction->getChildEdges()) {90addValuesFromSubordinatedElements(this, edge);91}92}939495GNEDeleteFrame::SubordinatedElements::SubordinatedElements(const GNEEdge* edge) :96SubordinatedElements(edge, edge->getNet()->getViewNet(), edge) {97// add the number of subodinated elements of child lanes98for (const auto& lane : edge->getChildLanes()) {99addValuesFromSubordinatedElements(this, lane);100}101}102103104GNEDeleteFrame::SubordinatedElements::SubordinatedElements(const GNELane* lane) :105SubordinatedElements(lane, lane->getNet()->getViewNet(), lane) {106}107108109GNEDeleteFrame::SubordinatedElements::SubordinatedElements(const GNEAdditional* additional) :110SubordinatedElements(additional, additional->getNet()->getViewNet()) {111}112113114GNEDeleteFrame::SubordinatedElements::SubordinatedElements(const GNEDemandElement* demandElement) :115SubordinatedElements(demandElement, demandElement->getNet()->getViewNet()) {116}117118119GNEDeleteFrame::SubordinatedElements::SubordinatedElements(const GNEGenericData* genericData) :120SubordinatedElements(genericData, genericData->getNet()->getViewNet()) {121}122123124GNEDeleteFrame::SubordinatedElements::~SubordinatedElements() {}125126127bool128GNEDeleteFrame::SubordinatedElements::checkElements(const ProtectElements* protectElements) {129// check if running internal tests130const auto internalTest = protectElements->getDeleteFrameParent()->getViewNet()->getViewParent()->getGNEAppWindows()->getInternalTest();131const bool runningInternalTests = internalTest ? internalTest->isRunning() : false;132// check every parent/child133if ((myAdditionalParents > 0) && protectElements->protectAdditionals()) {134openWarningDialog("additional", myAdditionalParents, false, runningInternalTests);135} else if ((myAdditionalChilds > 0) && protectElements->protectAdditionals()) {136openWarningDialog("additional", myAdditionalChilds, true, runningInternalTests);137} else if ((myDemandElementParents > 0) && protectElements->protectDemandElements()) {138openWarningDialog("demand", myDemandElementParents, false, runningInternalTests);139} else if ((myDemandElementChilds > 0) && protectElements->protectDemandElements()) {140openWarningDialog("demand", myDemandElementChilds, true, runningInternalTests);141} else if ((myGenericDataParents > 0) && protectElements->protectGenericDatas()) {142openWarningDialog("data", myGenericDataParents, false, runningInternalTests);143} else if ((myGenericDataChilds > 0) && protectElements->protectGenericDatas()) {144openWarningDialog("data", myGenericDataChilds, true, runningInternalTests);145} else {146// all checks ok, then return true, to remove element147return true;148}149return false;150}151152153GNEDeleteFrame::SubordinatedElements::SubordinatedElements(const GNEAttributeCarrier* attributeCarrier, GNEViewNet* viewNet) :154myAttributeCarrier(attributeCarrier),155myViewNet(viewNet),156myAdditionalParents(0),157myAdditionalChilds(0),158myDemandElementParents(0),159myDemandElementChilds(0),160myGenericDataParents(0),161myGenericDataChilds(0) {162}163164165GNEDeleteFrame::SubordinatedElements::SubordinatedElements(const GNEAttributeCarrier* attributeCarrier, GNEViewNet* viewNet,166const GNEHierarchicalElement* hierarchicalElement) :167myAttributeCarrier(attributeCarrier),168myViewNet(viewNet),169myAdditionalParents(hierarchicalElement->getParentAdditionals().size()),170myAdditionalChilds(hierarchicalElement->getChildAdditionals().size()),171myDemandElementParents(hierarchicalElement->getParentDemandElements().size()),172myDemandElementChilds(hierarchicalElement->getChildDemandElements().size()),173myGenericDataParents(hierarchicalElement->getParentGenericDatas().size()),174myGenericDataChilds(hierarchicalElement->getChildGenericDatas().size()) {175// add the number of subodinated elements of additionals, demand elements and generic datas176for (const auto& additionalParent : hierarchicalElement->getParentAdditionals()) {177addValuesFromSubordinatedElements(this, additionalParent);178}179for (const auto& demandParent : hierarchicalElement->getParentDemandElements()) {180addValuesFromSubordinatedElements(this, demandParent);181}182for (const auto& genericDataParent : hierarchicalElement->getParentGenericDatas()) {183addValuesFromSubordinatedElements(this, genericDataParent);184}185for (const auto& additionalChild : hierarchicalElement->getChildAdditionals()) {186addValuesFromSubordinatedElements(this, additionalChild);187}188for (const auto& demandChild : hierarchicalElement->getChildDemandElements()) {189addValuesFromSubordinatedElements(this, demandChild);190}191for (const auto& genericDataChild : hierarchicalElement->getChildGenericDatas()) {192addValuesFromSubordinatedElements(this, genericDataChild);193}194}195196197void198GNEDeleteFrame::SubordinatedElements::addValuesFromSubordinatedElements(SubordinatedElements* originalSE, const SubordinatedElements& newSE) {199originalSE->myAdditionalParents += newSE.myAdditionalParents;200originalSE->myAdditionalChilds += newSE.myAdditionalChilds;201originalSE->myDemandElementParents += newSE.myDemandElementParents;202originalSE->myDemandElementChilds += newSE.myDemandElementChilds;203originalSE->myGenericDataParents += newSE.myGenericDataParents;204originalSE->myGenericDataChilds += newSE.myGenericDataChilds;205}206207208void209GNEDeleteFrame::SubordinatedElements::openWarningDialog(const std::string& type, const size_t number, const bool isChild, const bool runningInternalTests) {210// declare plural depending of "number"211const std::string plural = (number > 1) ? "s" : "";212// declare header213const std::string header = "Problem deleting " + myAttributeCarrier->getTagProperty()->getTagStr() + " '" + myAttributeCarrier->getID() + "'";214// declare message215std::string msg;216// set message depending of isChild217if (isChild) {218msg = myAttributeCarrier->getTagProperty()->getTagStr() + " '" + myAttributeCarrier->getID() +219"' cannot be deleted because it has " + toString(number) + " " + type + " element" + plural + ".\n" +220"To delete it, uncheck 'protect " + type + " elements'.";221} else {222msg = myAttributeCarrier->getTagProperty()->getTagStr() + " '" + myAttributeCarrier->getID() +223"' cannot be deleted because it is part of " + toString(number) + " " + type + " element" + plural + ".\n" +224"To delete it, uncheck 'protect " + type + " elements'.";225}226// open message box only if we're not running internal tests227if (!runningInternalTests) {228GNEWarningBasicDialog(myViewNet->getViewParent()->getGNEAppWindows(), header, msg);229}230}231232// ---------------------------------------------------------------------------233// GNEDeleteFrame::ProtectElements - methods234// ---------------------------------------------------------------------------235236GNEDeleteFrame::ProtectElements::ProtectElements(GNEDeleteFrame* deleteFrameParent) :237MFXGroupBoxModule(deleteFrameParent, TL("Protect Elements")),238myDeleteFrameParent(deleteFrameParent) {239// Create "Protect all" Button240myProtectAllButton = GUIDesigns::buildFXButton(getCollapsableFrame(), TL("Protect all"), "", TL("Protect all elements"), nullptr, this, MID_GNE_PROTECT_ALL, GUIDesignButton);241// start disabled (because allelements are protected)242myProtectAllButton->disable();243// Create "Unprotect all" Button244myUnprotectAllButton = GUIDesigns::buildFXButton(getCollapsableFrame(), TL("Unprotect all"), "", TL("Unprotect all elements"), nullptr, this, MID_GNE_UNPROTECT_ALL, GUIDesignButton);245// Create checkbox for enable/disable delete only geomtery point(by default, disabled)246myProtectAdditionals = new FXCheckButton(getCollapsableFrame(), TL("Protect additional elements"), deleteFrameParent, MID_GNE_SET_ATTRIBUTE, GUIDesignCheckButton);247myProtectAdditionals->setCheck(TRUE);248// Create checkbox for enable/disable delete only geomtery point(by default, disabled)249myProtectTAZs = new FXCheckButton(getCollapsableFrame(), TL("Protect TAZ elements"), deleteFrameParent, MID_GNE_SET_ATTRIBUTE, GUIDesignCheckButton);250myProtectTAZs->setCheck(TRUE);251// Create checkbox for enable/disable delete only geomtery point(by default, disabled)252myProtectDemandElements = new FXCheckButton(getCollapsableFrame(), TL("Protect demand elements"), deleteFrameParent, MID_GNE_SET_ATTRIBUTE, GUIDesignCheckButton);253myProtectDemandElements->setCheck(TRUE);254// Create checkbox for enable/disable delete only geomtery point(by default, disabled)255myProtectGenericDatas = new FXCheckButton(getCollapsableFrame(), TL("Protect data elements"), deleteFrameParent, MID_GNE_SET_ATTRIBUTE, GUIDesignCheckButton);256myProtectGenericDatas->setCheck(TRUE);257}258259260GNEDeleteFrame::ProtectElements::~ProtectElements() {}261262263GNEDeleteFrame*264GNEDeleteFrame::ProtectElements::getDeleteFrameParent() const {265return myDeleteFrameParent;266}267268269bool270GNEDeleteFrame::ProtectElements::protectAdditionals() const {271return (myProtectAdditionals->getCheck() == TRUE);272}273274275bool276GNEDeleteFrame::ProtectElements::protectTAZs() const {277return (myProtectTAZs->getCheck() == TRUE);278}279280281bool282GNEDeleteFrame::ProtectElements::protectDemandElements() const {283return (myProtectDemandElements->getCheck() == TRUE);284}285286287bool288GNEDeleteFrame::ProtectElements::protectGenericDatas() const {289return (myProtectGenericDatas->getCheck() == TRUE);290}291292293long294GNEDeleteFrame::ProtectElements::onCmdProtectAll(FXObject*, FXSelector, void*) {295myProtectAdditionals->setCheck(TRUE);296myProtectTAZs->setCheck(TRUE);297myProtectDemandElements->setCheck(TRUE);298myProtectGenericDatas->setCheck(TRUE);299myUnprotectAllButton->enable();300return 1;301}302303304long305GNEDeleteFrame::ProtectElements::onCmdUnprotectAll(FXObject*, FXSelector, void*) {306myProtectAdditionals->setCheck(FALSE);307myProtectTAZs->setCheck(FALSE);308myProtectDemandElements->setCheck(FALSE);309myProtectGenericDatas->setCheck(FALSE);310myProtectAllButton->enable();311return 1;312}313314315long316GNEDeleteFrame::ProtectElements::onUpdProtectAll(FXObject* sender, FXSelector, void*) {317if (myProtectAdditionals->getCheck() && myProtectTAZs->getCheck() &&318myProtectDemandElements->getCheck() && myProtectGenericDatas->getCheck()) {319return sender->handle(this, FXSEL(SEL_COMMAND, ID_DISABLE), nullptr);320} else {321return sender->handle(this, FXSEL(SEL_COMMAND, ID_ENABLE), nullptr);322}323}324325326long327GNEDeleteFrame::ProtectElements::onUpdUnprotectAll(FXObject* sender, FXSelector, void*) {328if (!myProtectAdditionals->getCheck() && !myProtectTAZs->getCheck() &&329!myProtectDemandElements->getCheck() && !myProtectGenericDatas->getCheck()) {330return sender->handle(this, FXSEL(SEL_COMMAND, ID_DISABLE), nullptr);331} else {332return sender->handle(this, FXSEL(SEL_COMMAND, ID_ENABLE), nullptr);333}334}335336// ===========================================================================337// method definitions338// ===========================================================================339340GNEDeleteFrame::GNEDeleteFrame(GNEViewParent* viewParent, GNEViewNet* viewNet) :341GNEFrame(viewParent, viewNet, TL("Delete")) {342// create delete options module343myDeleteOptions = new DeleteOptions(this);344// create protect elements module345myProtectElements = new ProtectElements(this);346}347348349GNEDeleteFrame::~GNEDeleteFrame() {350}351352353void354GNEDeleteFrame::show() {355GNEFrame::show();356}357358359void360GNEDeleteFrame::hide() {361GNEFrame::hide();362}363364365void366GNEDeleteFrame::removeSelectedAttributeCarriers() {367// get attribute carriers368const auto& attributeCarriers = myViewNet->getNet()->getAttributeCarriers();369// first check if there is additional to remove370if (selectedACsToDelete()) {371// remove all selected attribute carriers using the following parent-child sequence372myViewNet->getUndoList()->begin(GUIIcon::MODEDELETE, TL("remove selected items"));373// disable update geometry374myViewNet->getNet()->disableUpdateGeometry();375// delete selected attribute carriers depending of current supermode376if (myViewNet->getEditModes().isCurrentSupermodeNetwork()) {377//junctions378const auto selectedJunctions = attributeCarriers->getSelectedJunctions();379for (const auto& selectedJunction : selectedJunctions) {380myViewNet->getNet()->deleteJunction(selectedJunction, myViewNet->getUndoList());381}382// edges383const auto selectedEdges = attributeCarriers->getSelectedEdges();384for (const auto& selectedEdge : selectedEdges) {385myViewNet->getNet()->deleteEdge(selectedEdge, myViewNet->getUndoList(), false);386}387// lanes388const auto selectedLanes = attributeCarriers->getSelectedLanes();389for (const auto& selectedLane : selectedLanes) {390myViewNet->getNet()->deleteLane(selectedLane, myViewNet->getUndoList(), false);391}392// connections393const auto selectedConnections = attributeCarriers->getSelectedConnections();394for (const auto& selectedConnection : selectedConnections) {395myViewNet->getNet()->deleteConnection(selectedConnection, myViewNet->getUndoList());396}397// crossings398const auto selectedCrossings = attributeCarriers->getSelectedCrossings();399for (const auto& selectedCrossing : selectedCrossings) {400myViewNet->getNet()->deleteCrossing(selectedCrossing, myViewNet->getUndoList());401}402// additionals (including Polygons, POIs, TAZs and Wires)403while (attributeCarriers->getNumberOfSelectedAdditionals() > 0) {404myViewNet->getNet()->deleteAdditional(attributeCarriers->getSelectedAdditionals().front(), myViewNet->getUndoList());405}406} else if (myViewNet->getEditModes().isCurrentSupermodeDemand()) {407// demand elements408while (attributeCarriers->getNumberOfSelectedDemandElements() > 0) {409myViewNet->getNet()->deleteDemandElement(attributeCarriers->getSelectedDemandElements().front(), myViewNet->getUndoList());410}411} else if (myViewNet->getEditModes().isCurrentSupermodeData()) {412// generic datas413auto selectedGenericDatas = attributeCarriers->getSelectedGenericDatas();414for (const auto& selectedGenericData : selectedGenericDatas) {415myViewNet->getNet()->deleteGenericData(selectedGenericData, myViewNet->getUndoList());416}417}418// enable update geometry419myViewNet->getNet()->enableUpdateGeometry();420// finish deletion421myViewNet->getUndoList()->end();422}423}424425426void427GNEDeleteFrame::removeAttributeCarrier(const GNEViewNetHelper::ViewObjectsSelector& viewObjects) {428// disable update geometry429myViewNet->getNet()->disableUpdateGeometry();430// first check if there more than one clicked GL object under cursor431if (viewObjects.getGLObjects().size() > 1) {432std::vector<GUIGlObject*> filteredGLObjects;433// filter objects434for (const auto& glObject : viewObjects.getGLObjects()) {435if (glObject->isGLObjectLocked()) {436continue;437}438filteredGLObjects.push_back(glObject);439}440// now filter elements based on the first element441filteredGLObjects = GNEViewNetHelper::filterElementsByLayer(filteredGLObjects);442// after filter, check if there is more than one element443if (filteredGLObjects.size() > 1) {444// use Cursor dialog445myViewNet->openDeleteDialogAtCursor(filteredGLObjects);446} else if (filteredGLObjects.size() > 0) {447filteredGLObjects.front()->deleteGLObject();448}449} else if ((viewObjects.getGLObjects().size() > 0) &&450!viewObjects.getGLObjects().front()->isGLObjectLocked()) {451viewObjects.getGLObjects().front()->deleteGLObject();452}453// enable update geometry454myViewNet->getNet()->enableUpdateGeometry();455}456457458bool459GNEDeleteFrame::removeGeometryPoint(const GNEViewNetHelper::ViewObjectsSelector& viewObjects) {460// get clicked position461const Position clickedPosition = myViewNet->getPositionInformation();462// filter elements with geometry points463for (const auto& AC : viewObjects.getAttributeCarriers()) {464if (AC->getTagProperty()->getTag() == SUMO_TAG_EDGE) {465viewObjects.getEdgeFront()->removeGeometryPoint(clickedPosition, myViewNet->getUndoList());466return true;467} else if (AC->getTagProperty()->getTag() == SUMO_TAG_POLY) {468viewObjects.getPolyFront()->removeGeometryPoint(clickedPosition, myViewNet->getUndoList());469return true;470} else if (AC->getTagProperty()->getTag() == SUMO_TAG_TAZ) {471viewObjects.getTAZFront()->removeGeometryPoint(clickedPosition, myViewNet->getUndoList());472return true;473}474}475return false;476}477478479GNEDeleteFrame::DeleteOptions*480GNEDeleteFrame::getDeleteOptions() const {481return myDeleteOptions;482}483484485GNEDeleteFrame::ProtectElements*486GNEDeleteFrame::getProtectElements() const {487return myProtectElements;488}489490// ---------------------------------------------------------------------------491// GNEAdditionalFrame - protected methods492// ---------------------------------------------------------------------------493494bool495GNEDeleteFrame::selectedACsToDelete() const {496// invert selection of elements depending of current supermode497if (myViewNet->getEditModes().isCurrentSupermodeNetwork()) {498// iterate over junctions499for (const auto& junction : myViewNet->getNet()->getAttributeCarriers()->getJunctions()) {500if (junction.second->isAttributeCarrierSelected()) {501return true;502}503// since we iterate over all junctions, it's only necessary to iterate over incoming edges504for (const auto& edge : junction.second->getGNEIncomingEdges()) {505if (edge->isAttributeCarrierSelected()) {506return true;507}508// check lanes509for (const auto& lane : edge->getChildLanes()) {510if (lane->isAttributeCarrierSelected()) {511return true;512}513}514// check connections515for (const auto& connection : edge->getGNEConnections()) {516if (connection->isAttributeCarrierSelected()) {517return true;518}519}520}521// check crossings522for (const auto& crossing : junction.second->getGNECrossings()) {523if (crossing->isAttributeCarrierSelected()) {524return true;525}526}527}528// check additionals529for (const auto& additionalTag : myViewNet->getNet()->getAttributeCarriers()->getAdditionals()) {530for (const auto& additional : additionalTag.second) {531if (additional.second->isAttributeCarrierSelected()) {532return true;533}534}535}536} else if (myViewNet->getEditModes().isCurrentSupermodeDemand()) {537// check demand elements538for (const auto& demandElementTag : myViewNet->getNet()->getAttributeCarriers()->getDemandElements()) {539for (const auto& demandElement : demandElementTag.second) {540if (demandElement.second->isAttributeCarrierSelected()) {541return true;542}543}544}545} else if (myViewNet->getEditModes().isCurrentSupermodeData()) {546// iterate over all generic datas547for (const auto& genericDataTag : myViewNet->getNet()->getAttributeCarriers()->getGenericDatas()) {548for (const auto& genericData : genericDataTag.second) {549if (genericData.second->isAttributeCarrierSelected()) {550return true;551}552}553}554}555return false;556}557558/****************************************************************************/559560561