Path: blob/main/src/netedit/frames/common/GNEInspectorFrame.cpp
169685 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 GNEInspectorFrame.cpp14/// @author Jakob Erdmann15/// @author Pablo Alvarez Lopez16/// @date Mar 201117///18// The Widget for modifying network-element attributes (i.e. lane speed)19/****************************************************************************/2021#include <netedit/GNEApplicationWindow.h>22#include <netedit/GNENet.h>23#include <netedit/GNETagProperties.h>24#include <netedit/GNEUndoList.h>25#include <netedit/GNEViewParent.h>26#include <netedit/elements/network/GNEEdgeTemplate.h>27#include <netedit/frames/GNEAttributesEditor.h>28#include <netedit/frames/GNEElementTree.h>29#include <netedit/frames/GNEOverlappedInspection.h>30#include <netedit/frames/network/GNECreateEdgeFrame.h>31#include <utils/gui/div/GUIDesigns.h>3233#include "GNEInspectorFrame.h"3435// ===========================================================================36// FOX callback mapping37// ===========================================================================3839FXDEFMAP(GNEInspectorFrame) GNEInspectorFrameMap[] = {40FXMAPFUNC(SEL_COMMAND, MID_GNE_INSPECTORFRAME_INSPECTPREVIOUSELEMENT, GNEInspectorFrame::onCmdInspectPreviousElement)41};4243FXDEFMAP(GNEInspectorFrame::TemplateEditor) TemplateEditorMap[] = {44FXMAPFUNC(SEL_COMMAND, MID_HOTKEY_SHIFT_F1_TEMPLATE_SET, GNEInspectorFrame::TemplateEditor::onCmdSetTemplate),45FXMAPFUNC(SEL_COMMAND, MID_HOTKEY_SHIFT_F2_TEMPLATE_COPY, GNEInspectorFrame::TemplateEditor::onCmdCopyTemplate),46FXMAPFUNC(SEL_COMMAND, MID_HOTKEY_SHIFT_F3_TEMPLATE_CLEAR, GNEInspectorFrame::TemplateEditor::onCmdClearTemplate),47};4849// Object implementation50FXIMPLEMENT(GNEInspectorFrame, FXVerticalFrame, GNEInspectorFrameMap, ARRAYNUMBER(GNEInspectorFrameMap))51FXIMPLEMENT(GNEInspectorFrame::TemplateEditor, MFXGroupBoxModule, TemplateEditorMap, ARRAYNUMBER(TemplateEditorMap))525354// ===========================================================================55// method definitions56// ===========================================================================5758// ---------------------------------------------------------------------------59// GNEInspectorFrame::TemplateEditor - methods60// ---------------------------------------------------------------------------6162GNEInspectorFrame::TemplateEditor::TemplateEditor(GNEInspectorFrame* inspectorFrameParent) :63MFXGroupBoxModule(inspectorFrameParent, TL("Templates")),64myInspectorFrameParent(inspectorFrameParent),65myEdgeTemplate(nullptr) {66// Create set template button67mySetTemplateButton = GUIDesigns::buildFXButton(getCollapsableFrame(), TL("Set as Template"), "", "", nullptr, this, MID_HOTKEY_SHIFT_F1_TEMPLATE_SET, GUIDesignButton);68// Create copy template button69myCopyTemplateButton = GUIDesigns::buildFXButton(getCollapsableFrame(), "", "", "", nullptr, this, MID_HOTKEY_SHIFT_F2_TEMPLATE_COPY, GUIDesignButton);70// Create copy template button71myClearTemplateButton = GUIDesigns::buildFXButton(getCollapsableFrame(), TL("clear Edge Template"), "", "", nullptr, this, MID_HOTKEY_SHIFT_F3_TEMPLATE_CLEAR, GUIDesignButton);72}737475GNEInspectorFrame::TemplateEditor::~TemplateEditor() {76}777879bool80GNEInspectorFrame::TemplateEditor::showTemplateEditor() {81// show template editor only if we're editing an edge in Network mode AND we have at least one inspected edge82if (myInspectorFrameParent->myViewNet->getEditModes().isCurrentSupermodeNetwork()) {83for (const auto& AC : myInspectorFrameParent->getViewNet()->getInspectedElements().getACs()) {84if (AC->getTagProperty()->getTag() == SUMO_TAG_EDGE) {85// update buttons and show module86updateButtons();87show();88return true;89}90}91}92return false;93}949596void97GNEInspectorFrame::TemplateEditor::hideTemplateEditor() {98// hide template editor99hide();100}101102103GNEEdgeTemplate*104GNEInspectorFrame::TemplateEditor::getEdgeTemplate() const {105return myEdgeTemplate;106}107108109void110GNEInspectorFrame::TemplateEditor::setEdgeTemplate(const GNEEdge* edge) {111// delete previous template edge112if (myEdgeTemplate) {113delete myEdgeTemplate;114myEdgeTemplate = nullptr;115}116// update edge template117if (edge) {118myEdgeTemplate = new GNEEdgeTemplate(edge);119// use template by default120myInspectorFrameParent->myViewNet->getViewParent()->getCreateEdgeFrame()->setUseEdgeTemplate();121}122}123124125void126GNEInspectorFrame::TemplateEditor::updateEdgeTemplate() {127if (myEdgeTemplate) {128myEdgeTemplate->updateLaneTemplates();129// use template by default130myInspectorFrameParent->myViewNet->getViewParent()->getCreateEdgeFrame()->setUseEdgeTemplate();131}132}133134void135GNEInspectorFrame::TemplateEditor::setTemplate() {136// check if template editor AND mySetTemplateButton is enabled137if (shown() && mySetTemplateButton->isEnabled()) {138onCmdSetTemplate(nullptr, 0, nullptr);139}140}141142143void144GNEInspectorFrame::TemplateEditor::copyTemplate() {145// check if template editor AND myCopyTemplateButton is enabled146if (shown() && myCopyTemplateButton->isEnabled()) {147onCmdCopyTemplate(nullptr, 0, nullptr);148}149}150151152void153GNEInspectorFrame::TemplateEditor::clearTemplate() {154// check if template editor AND myClearTemplateButton is enabled155if (shown() && myClearTemplateButton->isEnabled()) {156onCmdClearTemplate(nullptr, 0, nullptr);157}158}159160161long162GNEInspectorFrame::TemplateEditor::onCmdSetTemplate(FXObject*, FXSelector, void*) {163// apply to all selected edges164for (const auto& AC : myInspectorFrameParent->myViewNet->getInspectedElements().getACs()) {165if (AC->getTagProperty()->getTag() == SUMO_TAG_EDGE) {166// set template167setEdgeTemplate(myInspectorFrameParent->myViewNet->getNet()->getAttributeCarriers()->retrieveEdge(AC->getID()));168// update buttons169updateButtons();170}171}172return 1;173}174175176long177GNEInspectorFrame::TemplateEditor::onCmdCopyTemplate(FXObject*, FXSelector, void*) {178// first check179if (myEdgeTemplate) {180// begin copy template181myInspectorFrameParent->myViewNet->getUndoList()->begin(myEdgeTemplate, "copy edge template");182// iterate over inspected ACs183for (const auto& AC : myInspectorFrameParent->myViewNet->getInspectedElements().getACs()) {184// avoid copy template in the same edge185if (AC->getID() != myEdgeTemplate->getID()) {186// retrieve edge ID (and throw exception if edge doesn't exist)187myInspectorFrameParent->myViewNet->getNet()->getAttributeCarriers()->retrieveEdge(AC->getID())->copyTemplate(myEdgeTemplate, myInspectorFrameParent->myViewNet->getUndoList());188}189}190// end copy template191myInspectorFrameParent->myViewNet->getUndoList()->end();192// refresh inspector parent193myInspectorFrameParent->myAttributesEditor->refreshAttributesEditor();194}195return 1;196}197198199long200GNEInspectorFrame::TemplateEditor::onCmdClearTemplate(FXObject*, FXSelector, void*) {201// set null edge202setEdgeTemplate(nullptr);203// update buttons204updateButtons();205return 1;206}207208209void210GNEInspectorFrame::TemplateEditor::updateButtons() {211const auto& inspectedElements = myInspectorFrameParent->getViewNet()->getInspectedElements();212// only show set template button if we have exactly one inspected edge213if (inspectedElements.isInspectingSingleElement() && (inspectedElements.getFirstAC()->getTagProperty()->getTag() == SUMO_TAG_EDGE)) {214mySetTemplateButton->setText((TLF("Set edge '%' as Template", inspectedElements.getFirstAC()->getID())).c_str());215mySetTemplateButton->show();216} else {217mySetTemplateButton->hide();218}219// enable or disable clear buttons depending of myEdgeTemplate220if (myEdgeTemplate) {221// update caption of copy button222if (inspectedElements.isInspectingSingleElement()) {223myCopyTemplateButton->setText(("Copy '" + myEdgeTemplate->getID() + "' into edge '" + inspectedElements.getFirstAC()->getID() + "'").c_str());224} else {225myCopyTemplateButton->setText(("Copy '" + myEdgeTemplate->getID() + "' into " + toString(inspectedElements.getACs().size()) + " selected edges").c_str());226}227// enable set and clear buttons228myCopyTemplateButton->enable();229myClearTemplateButton->enable();230} else {231// update caption of copy button232myCopyTemplateButton->setText(TL("No edge Template Set"));233// disable set and clear buttons234myCopyTemplateButton->disable();235myClearTemplateButton->disable();236}237}238239// ---------------------------------------------------------------------------240// GNEInspectorFrame - methods241// ---------------------------------------------------------------------------242243GNEInspectorFrame::GNEInspectorFrame(GNEViewParent* viewParent, GNEViewNet* viewNet) :244GNEFrame(viewParent, viewNet, "Inspector") {245246// Create back button247myBackButton = GUIDesigns::buildFXButton(myHeaderLeftFrame, "", "", "", GUIIconSubSys::getIcon(GUIIcon::BIGARROWLEFT),248this, MID_GNE_INSPECTORFRAME_INSPECTPREVIOUSELEMENT, GUIDesignButtonRectangular);249myHeaderLeftFrame->hide();250myBackButton->hide();251252// Create Overlapped Inspection module253myOverlappedInspection = new GNEOverlappedInspection(this, false);254255// Create Attributes Editor module256myAttributesEditor = new GNEAttributesEditor(this, GNEAttributesEditorType::EditorType::EDITOR);257258// Create Template editor module259myTemplateEditor = new TemplateEditor(this);260261// Create GNEElementTree module262myHierarchicalElementTree = new GNEElementTree(this);263}264265266GNEInspectorFrame::~GNEInspectorFrame() {}267268269void270GNEInspectorFrame::show() {271refreshInspection();272// stop reparenting273myAttributesEditor->abortReparenting();274// show275GNEFrame::show();276}277278279void280GNEInspectorFrame::hide() {281myViewNet->getInspectedElements().inspectACs({});282GNEFrame::hide();283}284285286bool287GNEInspectorFrame::inspectClickedElements(GNEViewNetHelper::ViewObjectsSelector& viewObjects,288const Position& clickedPosition, const bool shiftKeyPressed) {289// get unlocked attribute carrier front290auto AC = viewObjects.getAttributeCarrierFront();291// first check if we have clicked over an Attribute Carrier292if (AC) {293// if Control key is Pressed, select instead inspect element294if (myViewNet->getMouseButtonKeyPressed().controlKeyPressed()) {295// toggle networkElement selection296if (AC->isAttributeCarrierSelected()) {297AC->unselectAttributeCarrier();298} else {299AC->selectAttributeCarrier();300}301} else {302// show Overlapped Inspection module303myOverlappedInspection->showOverlappedInspection(viewObjects, clickedPosition, shiftKeyPressed);304// focus upper element of inspector frame305focusUpperElement();306}307return true;308} else {309return false;310}311}312313314void315GNEInspectorFrame::inspectElement(GNEAttributeCarrier* AC, GNEAttributeCarrier* previousInspectedAC) {316std::vector<GNEAttributeCarrier*> itemsToInspect;317// Use the implementation of inspect for multiple AttributeCarriers to avoid repetition of code318if (AC) {319if (AC->isAttributeCarrierSelected() && !myViewNet->getMouseButtonKeyPressed().altKeyPressed()) {320// obtain selected ACs depending of current supermode321const auto selectedACs = myViewNet->getNet()->getAttributeCarriers()->getSelectedAttributeCarriers(false);322// reserve space323itemsToInspect.reserve(selectedACs.size());324// iterate over selected ACs325for (const auto& selectedAC : selectedACs) {326// filter ACs to inspect using Tag as criterion327if (selectedAC->getTagProperty()->getTag() == AC->getTagProperty()->getTag()) {328itemsToInspect.push_back(selectedAC);329}330}331} else {332itemsToInspect.push_back(AC);333}334}335inspectElements(itemsToInspect, previousInspectedAC);336}337338void339GNEInspectorFrame::inspectElements(const std::vector<GNEAttributeCarrier*>& ACs, GNEAttributeCarrier* previousInspectedAC) {340myViewNet->getInspectedElements().inspectACs(ACs);341myPreviousInspectedAC = previousInspectedAC;342refreshInspection();343}344345346void347GNEInspectorFrame::clearInspection() {348// simply clear overlapped inspection (it refresh inspector frame)349myOverlappedInspection->clearOverlappedInspection();350}351352353void354GNEInspectorFrame::refreshInspection() {355const auto& inspectedElements = myViewNet->getInspectedElements();356// check if show back button357if (myPreviousInspectedAC) {358myHeaderLeftFrame->show();359myBackButton->show();360} else {361myHeaderLeftFrame->hide();362myBackButton->hide();363}364// Show all attribute editors (will be automatically hidden if there are no elements to inspect)365myAttributesEditor->showAttributesEditor(inspectedElements.getACs(), true);366// Hide other moduls367myTemplateEditor->hideTemplateEditor();368myHierarchicalElementTree->hideHierarchicalElementTree();369// If vector of attribute Carriers contain data370if (inspectedElements.isInspectingElements()) {371// Set header372std::string headerString;373if (inspectedElements.getFirstAC()->getTagProperty()->isNetworkElement()) {374headerString = "Net: ";375} else if (inspectedElements.getFirstAC()->getTagProperty()->isAdditionalElement()) {376headerString = "Additional: ";377} else if (inspectedElements.getFirstAC()->getTagProperty()->isShapeElement()) {378headerString = "Shape: ";379} else if (inspectedElements.getFirstAC()->getTagProperty()->isTAZElement()) {380headerString = "TAZ: ";381} else if (inspectedElements.getFirstAC()->getTagProperty()->isWireElement()) {382headerString = "WIRE: ";383} else if (inspectedElements.getFirstAC()->getTagProperty()->isVehicle()) {384headerString = "Vehicle: ";385} else if (inspectedElements.getFirstAC()->getTagProperty()->isRoute()) {386headerString = "Route: ";387} else if (inspectedElements.getFirstAC()->getTagProperty()->isPerson()) {388headerString = "Person: ";389} else if (inspectedElements.getFirstAC()->getTagProperty()->isPlanPerson()) {390headerString = "PersonPlan: ";391} else if (inspectedElements.getFirstAC()->getTagProperty()->isContainer()) {392headerString = "Container: ";393} else if (inspectedElements.getFirstAC()->getTagProperty()->isPlanContainer()) {394headerString = "ContainerPlan: ";395} else if (inspectedElements.getFirstAC()->getTagProperty()->isVehicleStop()) {396headerString = "Stop: ";397} else if (inspectedElements.getFirstAC()->getTagProperty()->isDataElement()) {398headerString = "Data: ";399}400if (myViewNet->getInspectedElements().isInspectingMultipleElements()) {401headerString += toString(inspectedElements.getACs().size()) + " ";402}403headerString += inspectedElements.getFirstAC()->getTagStr();404if (myViewNet->getInspectedElements().isInspectingMultipleElements()) {405headerString += "s";406}407// Set headerString into header label408getFrameHeaderLabel()->setText(headerString.c_str());409410// If attributes correspond to an Edge and we aren't in demand mode, show template editor411myTemplateEditor->showTemplateEditor();412413// if we inspect a single Attribute carrier vector, show their children414if (inspectedElements.isInspectingSingleElement()) {415myHierarchicalElementTree->showHierarchicalElementTree(inspectedElements.getFirstAC());416}417} else {418getFrameHeaderLabel()->setText(TL("Inspect"));419myOverlappedInspection->hiderOverlappedInspection();420}421// update frame width422setFrameWidth(myViewNet->getViewParent()->getFrameAreaWidth());423// update viewNet424myViewNet->update();425}426427428GNEAttributesEditor*429GNEInspectorFrame::getAttributesEditor() const {430return myAttributesEditor;431}432433434GNEInspectorFrame::TemplateEditor*435GNEInspectorFrame::getTemplateEditor() const {436return myTemplateEditor;437}438439440GNEOverlappedInspection*441GNEInspectorFrame::getOverlappedInspection() const {442return myOverlappedInspection;443}444445446GNEElementTree*447GNEInspectorFrame::getHierarchicalElementTree() const {448return myHierarchicalElementTree;449}450451452long453GNEInspectorFrame::onCmdInspectPreviousElement(FXObject*, FXSelector, void*) {454inspectElement(myPreviousInspectedAC, nullptr);455return 1;456}457458459void460GNEInspectorFrame::updateFrameAfterUndoRedo() {461refreshInspection();462}463464465void466GNEInspectorFrame::selectedOverlappedElement(GNEAttributeCarrier* AC) {467inspectElement(AC);468// update view (due dotted contour)469myViewNet->updateViewNet();470}471472/****************************************************************************/473474475