Path: blob/main/src/netedit/frames/network/GNETLSEditorFrame.cpp
193867 views
/****************************************************************************/1// Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo2// Copyright (C) 2001-2026 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 GNETLSEditorFrame.cpp14/// @author Jakob Erdmann15/// @date May 201116///17// The Widget for modifying traffic lights18/****************************************************************************/1920#include <netbuild/NBLoadedSUMOTLDef.h>21#include <netbuild/NBOwnTLDef.h>22#include <netedit/GNEApplicationWindow.h>23#include <netedit/GNENet.h>24#include <netedit/GNETagProperties.h>25#include <netedit/GNEUndoList.h>26#include <netedit/GNEInternalTest.h>27#include <netedit/GNEViewParent.h>28#include <netedit/changes/GNEChange_TLS.h>29#include <netedit/dialogs/basic/GNEQuestionBasicDialog.h>30#include <netedit/dialogs/basic/GNEWarningBasicDialog.h>31#include <netedit/dialogs/GNEParametersDialog.h>32#include <netedit/elements/network/GNEConnection.h>33#include <netedit/elements/network/GNECrossing.h>34#include <netedit/elements/network/GNEInternalLane.h>35#include <netedit/frames/GNEOverlappedInspection.h>36#include <netedit/frames/GNETLSTable.h>37#include <netimport/NIXMLTrafficLightsHandler.h>38#include <netwrite/NWWriter_SUMO.h>39#include <utils/foxtools/MFXTextFieldIcon.h>40#include <utils/foxtools/MFXToggleButtonTooltip.h>41#include <utils/gui/div/GUIDesigns.h>42#include <utils/xml/XMLSubSys.h>4344#include "GNETLSEditorFrame.h"4546// ===========================================================================47// FOX callback mapping48// ===========================================================================4950FXDEFMAP(GNETLSEditorFrame::TLSJunction) TLSJunctionMap[] = {51FXMAPFUNC(SEL_COMMAND, MID_GNE_TLSFRAME_TLSJUNCTION_ID, GNETLSEditorFrame::TLSJunction::onCmdRenameTLS),52FXMAPFUNC(SEL_COMMAND, MID_GNE_TLSFRAME_TLSJUNCTION_TYPE, GNETLSEditorFrame::TLSJunction::onCmdChangeType),53FXMAPFUNC(SEL_COMMAND, MID_GNE_TLSFRAME_TLSJUNCTION_TOGGLEJOIN, GNETLSEditorFrame::TLSJunction::onCmdToggleJoinTLS),54FXMAPFUNC(SEL_COMMAND, MID_GNE_TLSFRAME_TLSJUNCTION_DISJOIN, GNETLSEditorFrame::TLSJunction::onCmdDisjoinTLS),55FXMAPFUNC(SEL_COMMAND, MID_GNE_BUTTON_ACCEPT, GNETLSEditorFrame::TLSJunction::onCmdAcceptJoin),56FXMAPFUNC(SEL_COMMAND, MID_GNE_BUTTON_CANCEL, GNETLSEditorFrame::TLSJunction::onCmdCancelJoin)57};5859FXDEFMAP(GNETLSEditorFrame::TLSPrograms) TLSProgramsMap[] = {60FXMAPFUNC(SEL_COMMAND, MID_GNE_TLSFRAME_DEFINITION_CREATE, GNETLSEditorFrame::TLSPrograms::onCmdCreate),61FXMAPFUNC(SEL_COMMAND, MID_GNE_TLSFRAME_DEFINITION_DELETE, GNETLSEditorFrame::TLSPrograms::onCmdDelete),62FXMAPFUNC(SEL_COMMAND, MID_GNE_TLSFRAME_DEFINITION_RESETCURRENT, GNETLSEditorFrame::TLSPrograms::onCmdResetCurrentProgram),63FXMAPFUNC(SEL_COMMAND, MID_GNE_TLSFRAME_DEFINITION_RESETALL, GNETLSEditorFrame::TLSPrograms::onCmdResetAll),64FXMAPFUNC(SEL_COMMAND, MID_GNE_TLSFRAME_DEFINITION_SWITCHPROGRAM, GNETLSEditorFrame::TLSPrograms::onCmdDefSwitchTLSProgram),65FXMAPFUNC(SEL_COMMAND, MID_GNE_TLSFRAME_DEFINITION_SAVE, GNETLSEditorFrame::TLSPrograms::onCmdSaveChanges),66FXMAPFUNC(SEL_COMMAND, MID_GNE_TLSFRAME_DEFINITION_DISCARD, GNETLSEditorFrame::TLSPrograms::onCmdDiscardChanges),67};6869FXDEFMAP(GNETLSEditorFrame::TLSAttributes) TLSAttributesMap[] = {70FXMAPFUNC(SEL_COMMAND, MID_GNE_TLSFRAME_ATTRIBUTES_OFFSET, GNETLSEditorFrame::TLSAttributes::onCmdSetOffset),71FXMAPFUNC(SEL_COMMAND, MID_GNE_TLSFRAME_ATTRIBUTES_PARAMETERS, GNETLSEditorFrame::TLSAttributes::onCmdSetParameters),72FXMAPFUNC(SEL_COMMAND, MID_GNE_TLSFRAME_ATTRIBUTES_PARAMETERSDIALOG, GNETLSEditorFrame::TLSAttributes::onCmdParametersDialog),73FXMAPFUNC(SEL_COMMAND, MID_GNE_TLSFRAME_ATTRIBUTES_TOGGLEDETECTOR, GNETLSEditorFrame::TLSAttributes::onCmdToggleDetectorMode),74};7576FXDEFMAP(GNETLSEditorFrame::TLSPhases) TLSPhasesMap[] = {77FXMAPFUNC(SEL_COMMAND, MID_GNE_TLSFRAME_PHASES_CLEANUP, GNETLSEditorFrame::TLSPhases::onCmdCleanStates),78FXMAPFUNC(SEL_COMMAND, MID_GNE_TLSFRAME_PHASES_ADDUNUSED, GNETLSEditorFrame::TLSPhases::onCmdAddUnusedStates),79FXMAPFUNC(SEL_COMMAND, MID_GNE_TLSFRAME_PHASES_GROUPSTATES, GNETLSEditorFrame::TLSPhases::onCmdGroupStates),80FXMAPFUNC(SEL_COMMAND, MID_GNE_TLSFRAME_PHASES_UNGROUPSTATES, GNETLSEditorFrame::TLSPhases::onCmdUngroupStates),81};8283FXDEFMAP(GNETLSEditorFrame::TLSFile) TLSFileMap[] = {84FXMAPFUNC(SEL_COMMAND, MID_GNE_TLSFRAME_FILE_LOADPROGRAM, GNETLSEditorFrame::TLSFile::onCmdLoadTLSProgram),85FXMAPFUNC(SEL_COMMAND, MID_GNE_TLSFRAME_FILE_SAVEPROGRAM, GNETLSEditorFrame::TLSFile::onCmdSaveTLSProgram),86};8788// Object implementation89FXIMPLEMENT(GNETLSEditorFrame::TLSJunction, GNEGroupBoxModule, TLSJunctionMap, ARRAYNUMBER(TLSJunctionMap))90FXIMPLEMENT(GNETLSEditorFrame::TLSPrograms, GNEGroupBoxModule, TLSProgramsMap, ARRAYNUMBER(TLSProgramsMap))91FXIMPLEMENT(GNETLSEditorFrame::TLSAttributes, GNEGroupBoxModule, TLSAttributesMap, ARRAYNUMBER(TLSAttributesMap))92FXIMPLEMENT(GNETLSEditorFrame::TLSPhases, GNEGroupBoxModule, TLSPhasesMap, ARRAYNUMBER(TLSPhasesMap))93FXIMPLEMENT(GNETLSEditorFrame::TLSFile, GNEGroupBoxModule, TLSFileMap, ARRAYNUMBER(TLSFileMap))949596// ===========================================================================97// method definitions98// ===========================================================================99100GNETLSEditorFrame::GNETLSEditorFrame(GNEViewParent* viewParent, GNEViewNet* viewNet):101GNEFrame(viewParent, viewNet, TL("Edit Traffic Light")),102myEditedDef(nullptr) {103104// Create Overlapped Inspection module only for junctions105myOverlappedInspection = new GNEOverlappedInspection(this, true);106107// create TLSJunction module108myTLSJunction = new GNETLSEditorFrame::TLSJunction(this);109110// create TLSPrograms module111myTLSPrograms = new GNETLSEditorFrame::TLSPrograms(this);112113// create TLSAttributes module114myTLSAttributes = new GNETLSEditorFrame::TLSAttributes(this);115116// create TLSPhases module117myTLSPhases = new GNETLSEditorFrame::TLSPhases(this);118119// create TLSFile module120myTLSFile = new GNETLSEditorFrame::TLSFile(this);121}122123124GNETLSEditorFrame::~GNETLSEditorFrame() {125myTLSPhases->clearPhaseTable();126}127128129void130GNETLSEditorFrame::show() {131myOverlappedInspection->clearOverlappedInspection();132// show133GNEFrame::show();134}135136137void138GNETLSEditorFrame::frameWidthUpdated() {139// recalc table width140myTLSPhases->getPhaseTable()->recalcTableWidth();141}142143144void145GNETLSEditorFrame::updateModules() {146if (myTLSJunction) {147myTLSJunction->updateTLSJunction();148}149if (myTLSPrograms) {150myTLSPrograms->updateTLSPrograms();151}152if (myTLSAttributes) {153myTLSAttributes->updateTLSAttributes();154}155if (myTLSPhases) {156myTLSPhases->updateTLSPhases();157}158if (myTLSFile) {159myTLSFile->updateTLSFile();160}161update();162}163164165void166GNETLSEditorFrame::editTLS(GNEViewNetHelper::ViewObjectsSelector& viewObjects, const Position& clickedPosition, const bool shiftKeyPressed) {167// first check if in viewObjects there is a junction168if (viewObjects.getJunctionFront()) {169// check if we're adding or removing joined TLSs170if (myTLSJunction->isJoiningJunctions()) {171myTLSJunction->toggleJunctionSelected(viewObjects.getJunctionFront());172} else {173// show objects under cursor174myOverlappedInspection->showOverlappedInspection(viewObjects, clickedPosition, shiftKeyPressed);175// hide if we inspect only one junction176if (myOverlappedInspection->getNumberOfOverlappedACs()) {177if (myOverlappedInspection->getNumberOfOverlappedACs() == 1) {178myOverlappedInspection->hiderOverlappedInspection();179}180for (const auto& junction : viewObjects.getJunctions()) {181if (junction == myOverlappedInspection->getCurrentAC()) {182editJunction(junction);183}184}185}186}187} else if (viewObjects.getAdditionalFront() && myTLSAttributes->isSetDetectorsToggleButtonEnabled() &&188(viewObjects.getAdditionalFront()->getTagProperty()->getTag() == SUMO_TAG_INDUCTION_LOOP)) {189myTLSAttributes->toggleE1DetectorSelection(viewObjects.getAdditionalFront());190}191myViewNet->update();192}193194195bool196GNETLSEditorFrame::isTLSSaved() {197if (myTLSPrograms->checkHaveModifications()) {198// show question dialog199const GNEQuestionBasicDialog questionDialog(myViewNet->getViewParent()->getGNEAppWindows(),200GNEDialog::Buttons::YES_NO_CANCEL,201TL("Save TLS Changes"),202TL("There are unsaved changes in the currently edited traffic light."),203TL("Do you want to save it before changing mode?"));204// continue depending of result205if (questionDialog.getResult() == GNEDialog::Result::ACCEPT) {206// save modifications207myTLSPrograms->onCmdSaveChanges(nullptr, 0, nullptr);208return true;209} else if (questionDialog.getResult() == GNEDialog::Result::CANCEL) {210// cancel modifications211myTLSPrograms->onCmdDiscardChanges(nullptr, 0, nullptr);212return true;213} else {214// abort changing mode215return false;216}217} else {218return true;219}220}221222223bool224GNETLSEditorFrame::parseTLSPrograms(const std::string& file) {225NBTrafficLightLogicCont& tllCont = myViewNet->getNet()->getTLLogicCont();226NBTrafficLightLogicCont tmpTLLCont;227NIXMLTrafficLightsHandler tllHandler(tmpTLLCont, myViewNet->getNet()->getEdgeCont());228// existing definitions must be available to update their programs229std::set<NBTrafficLightDefinition*> origDefs;230for (NBTrafficLightDefinition* def : tllCont.getDefinitions()) {231// make a duplicate of every program232NBTrafficLightLogic* logic = tllCont.getLogic(def->getID(), def->getProgramID());233if (logic != nullptr) {234NBTrafficLightDefinition* duplicate = new NBLoadedSUMOTLDef(*def, *logic);235std::vector<NBNode*> nodes = def->getNodes();236for (auto it_node : nodes) {237GNEJunction* junction = myViewNet->getNet()->getAttributeCarriers()->retrieveJunction(it_node->getID());238myViewNet->getUndoList()->add(new GNEChange_TLS(junction, def, false, false), true);239myViewNet->getUndoList()->add(new GNEChange_TLS(junction, duplicate, true), true);240}241tmpTLLCont.insert(duplicate);242origDefs.insert(duplicate);243} else {244WRITE_WARNINGF(TL("tlLogic '%', program '%' could not be built"), def->getID(), def->getProgramID());245}246}247//std::cout << " initialized tmpCont with " << origDefs.size() << " defs\n";248XMLSubSys::runParser(tllHandler, file);249250std::vector<NBLoadedSUMOTLDef*> loadedTLS;251for (NBTrafficLightDefinition* def : tmpTLLCont.getDefinitions()) {252NBLoadedSUMOTLDef* sdef = dynamic_cast<NBLoadedSUMOTLDef*>(def);253if (sdef != nullptr) {254loadedTLS.push_back(sdef);255}256}257myViewNet->setStatusBarText(TL("Loaded ") + toString(loadedTLS.size()) + TL(" programs"));258for (auto def : loadedTLS) {259if (origDefs.count(def) != 0) {260// already add to undolist before261//std::cout << " skip " << def->getDescription() << "\n";262continue;263}264std::vector<NBNode*> nodes = def->getNodes();265//std::cout << " add " << def->getDescription() << " for nodes=" << toString(nodes) << "\n";266for (auto it_node : nodes) {267GNEJunction* junction = myViewNet->getNet()->getAttributeCarriers()->retrieveJunction(it_node->getID());268//myViewNet->getUndoList()->add(new GNEChange_TLS(junction, myTLSEditorParent->myEditedDef, false), true);269myViewNet->getUndoList()->add(new GNEChange_TLS(junction, def, true), true);270}271}272// clean up temporary container to avoid deletion of defs when its destruct is called273for (NBTrafficLightDefinition* def : tmpTLLCont.getDefinitions()) {274tmpTLLCont.removeProgram(def->getID(), def->getProgramID(), false);275}276return true;277}278279280void281GNETLSEditorFrame::selectedOverlappedElement(GNEAttributeCarrier* AC) {282auto junction = dynamic_cast<GNEJunction*>(AC);283if (junction) {284editJunction(junction);285}286}287288289void290GNETLSEditorFrame::cleanup() {291if (myTLSJunction->getCurrentJunction()) {292myTLSJunction->getCurrentJunction()->selectTLS(false);293if (myTLSPrograms->getNumberOfPrograms() > 0) {294for (const auto& node : myTLSPrograms->getCurrentTLSPrograms()->getNodes()) {295myViewNet->getNet()->getAttributeCarriers()->retrieveJunction(node->getID())->selectTLS(false);296}297}298}299// clean data structures300myTLSJunction->setCurrentJunction(nullptr);301// check if delete myEditedDef302if (myEditedDef) {303delete myEditedDef;304myEditedDef = nullptr;305}306// clear internal lanes307buildInternalLanes(nullptr);308// clean up attributes309myTLSPrograms->clearTLSProgramss();310// clean up attributes311myTLSAttributes->clearTLSAttributes();312// only clears when there are no definitions313myTLSPhases->initPhaseTable();314}315316317GNETLSEditorFrame::TLSJunction*318GNETLSEditorFrame::getTLSJunction() const {319return myTLSJunction;320}321322323GNETLSEditorFrame::TLSPrograms*324GNETLSEditorFrame::getTLSPrograms() const {325return myTLSPrograms;326}327328329GNETLSEditorFrame::TLSAttributes*330GNETLSEditorFrame::getTLSAttributes() const {331return myTLSAttributes;332}333334335GNETLSEditorFrame::TLSPhases*336GNETLSEditorFrame::getTLSPhases() const {337return myTLSPhases;338}339340341void342GNETLSEditorFrame::buildInternalLanes(const NBTrafficLightDefinition* tlDef) {343// clean up previous internal lanes344for (const auto& internalLanes : myInternalLanes) {345for (const auto& internalLane : internalLanes.second) {346// remove internal lane from ACs347myViewNet->getNet()->getAttributeCarriers()->deleteInternalLane(internalLane);348// delete internal lane349delete internalLane;350}351}352// clear container353myInternalLanes.clear();354// create new internal lanes355if (tlDef != nullptr) {356const int NUM_POINTS = 10;357const NBNode* nbnCurrentJunction = myTLSJunction->getCurrentJunction()->getNBNode();358// get innerID NWWriter_SUMO::writeInternalEdges359const std::string innerID = ":" + nbnCurrentJunction->getID();360const NBConnectionVector& links = tlDef->getControlledLinks();361// iterate over links362for (const auto& link : links) {363int tlIndex = link.getTLIndex();364PositionVector shape;365try {366const NBEdge::Connection& con = link.getFrom()->getConnection(link.getFromLane(), link.getTo(), link.getToLane());367shape = con.shape;368shape.append(con.viaShape);369} catch (ProcessError&) {370shape = link.getFrom()->getToNode()->computeInternalLaneShape(link.getFrom(), NBEdge::Connection(link.getFromLane(),371link.getTo(), link.getToLane()), NUM_POINTS);372}373if (shape.length() < 2) {374// enlarge shape to ensure visibility375shape.clear();376const PositionVector laneShapeFrom = link.getFrom()->getLaneShape(link.getFromLane());377const PositionVector laneShapeTo = link.getTo()->getLaneShape(link.getToLane());378shape.push_back(laneShapeFrom.positionAtOffset(MAX2(0.0, laneShapeFrom.length() - 1)));379shape.push_back(laneShapeTo.positionAtOffset(MIN2(1.0, laneShapeFrom.length())));380}381GNEInternalLane* internalLane = new GNEInternalLane(this, myTLSJunction->getCurrentJunction(), innerID + '_' + toString(tlIndex), shape, tlIndex);382// add into atribute carriers383myViewNet->getNet()->getAttributeCarriers()->insertInternalLane(internalLane);384myInternalLanes[tlIndex].push_back(internalLane);385}386// iterate over crossings387for (const auto& nbn : tlDef->getNodes()) {388for (const auto& crossing : nbn->getCrossings()) {389if (crossing->tlLinkIndex2 > 0 && crossing->tlLinkIndex2 != crossing->tlLinkIndex) {390// draw both directions391PositionVector forward = crossing->shape;392forward.move2side(crossing->width / 4);393GNEInternalLane* internalLane = new GNEInternalLane(this, myTLSJunction->getCurrentJunction(), crossing->id, forward, crossing->tlLinkIndex);394// add into atribute carriers395myViewNet->getNet()->getAttributeCarriers()->insertInternalLane(internalLane);396myInternalLanes[crossing->tlLinkIndex].push_back(internalLane);397PositionVector backward = crossing->shape.reverse();398backward.move2side(crossing->width / 4);399GNEInternalLane* internalLaneReverse = new GNEInternalLane(this, myTLSJunction->getCurrentJunction(), crossing->id + "_r", backward, crossing->tlLinkIndex2);400// add into atribute carriers401myViewNet->getNet()->getAttributeCarriers()->insertInternalLane(internalLaneReverse);402myInternalLanes[crossing->tlLinkIndex2].push_back(internalLaneReverse);403} else {404// draw only one lane for both directions405GNEInternalLane* internalLane = new GNEInternalLane(this, myTLSJunction->getCurrentJunction(), crossing->id, crossing->shape, crossing->tlLinkIndex);406// add into atribute carriers407myViewNet->getNet()->getAttributeCarriers()->insertInternalLane(internalLane);408myInternalLanes[crossing->tlLinkIndex].push_back(internalLane);409}410}411}412}413}414415416std::string417GNETLSEditorFrame::varDurString(SUMOTime dur) {418return (dur == NBTrafficLightDefinition::UNSPECIFIED_DURATION) ? "" : getSteps2Time(dur);419}420421422const NBTrafficLightLogic::PhaseDefinition&423GNETLSEditorFrame::getPhase(const int index) {424if ((index >= 0) || (index < (int)myEditedDef->getLogic()->getPhases().size())) {425return myEditedDef->getLogic()->getPhases().at(index);426} else {427throw ProcessError(TL("Invalid phase index"));428}429}430431432void433GNETLSEditorFrame::handleChange(GNEInternalLane* lane) {434myTLSPrograms->markAsModified();435// get current selected row436const auto selectedRow = myTLSPhases->getPhaseTable()->getCurrentSelectedRow();437if (myViewNet->changeAllPhases()) {438for (int row = 0; row < (int)myEditedDef->getLogic()->getPhases().size(); row++) {439myEditedDef->getLogic()->setPhaseState(row, lane->getTLIndex(), lane->getLinkState());440}441} else {442myEditedDef->getLogic()->setPhaseState(myTLSPhases->getPhaseTable()->getCurrentSelectedRow(), lane->getTLIndex(), lane->getLinkState());443}444// init phaseTable445myTLSPhases->initPhaseTable();446// select row447myTLSPhases->getPhaseTable()->selectRow(selectedRow);448// focus table449myTLSPhases->getPhaseTable()->setFocus();450}451452453void454GNETLSEditorFrame::handleMultiChange(GNELane* lane, FXObject* obj, FXSelector sel, void* eventData) {455if (myEditedDef != nullptr) {456myTLSPrograms->markAsModified();457const NBConnectionVector& links = myEditedDef->getControlledLinks();458std::set<std::string> fromIDs;459fromIDs.insert(lane->getMicrosimID());460// if neither the lane nor its edge are selected, apply changes to the whole edge461if (!lane->getParentEdge()->isAttributeCarrierSelected() && !lane->isAttributeCarrierSelected()) {462for (auto it_lane : lane->getParentEdge()->getChildLanes()) {463fromIDs.insert(it_lane->getMicrosimID());464}465} else {466// if the edge is selected, apply changes to all lanes of all selected edges467if (lane->getParentEdge()->isAttributeCarrierSelected()) {468const auto selectedEdge = myViewNet->getNet()->getAttributeCarriers()->getSelectedEdges();469for (const auto& edge : selectedEdge) {470for (auto it_lane : edge->getChildLanes()) {471fromIDs.insert(it_lane->getMicrosimID());472}473}474}475// if the lane is selected, apply changes to all selected lanes476if (lane->isAttributeCarrierSelected()) {477const auto selectedLanes = myViewNet->getNet()->getAttributeCarriers()->getSelectedLanes();478for (auto it_lane : selectedLanes) {479fromIDs.insert(it_lane->getMicrosimID());480}481}482483}484// set new state for all connections from the chosen lane IDs485for (auto it : links) {486if (fromIDs.count(it.getFrom()->getLaneID(it.getFromLane())) > 0) {487std::vector<GNEInternalLane*> lanes = myInternalLanes[it.getTLIndex()];488for (auto it_lane : lanes) {489it_lane->onDefault(obj, sel, eventData);490}491}492}493}494}495496497bool498GNETLSEditorFrame::controlsEdge(GNEEdge* edge) const {499if (myEditedDef != nullptr) {500const NBConnectionVector& links = myEditedDef->getControlledLinks();501for (auto it : links) {502if (it.getFrom()->getID() == edge->getMicrosimID()) {503return true;504}505}506}507return false;508}509510511void512GNETLSEditorFrame::editJunction(GNEJunction* junction) {513if ((myTLSJunction->getCurrentJunction() == nullptr) || (!myTLSPrograms->checkHaveModifications() && (junction != myTLSJunction->getCurrentJunction()))) {514// discard previous changes515myTLSPrograms->discardChanges(false);516// set junction517myTLSJunction->setCurrentJunction(junction);518// init TLS definitions519if (myTLSPrograms->initTLSPrograms()) {520// init TLSAttributes521myTLSAttributes->initTLSAttributes();522// begin undo-list523myViewNet->getUndoList()->begin(GUIIcon::MODETLS, TL("modifying TLS definition"));524// only select TLS if getCurrentJunction exist525if (myTLSJunction->getCurrentJunction()) {526myTLSJunction->getCurrentJunction()->selectTLS(true);527}528if (myTLSPrograms->getNumberOfPrograms() > 0) {529for (NBNode* node : myTLSPrograms->getCurrentTLSPrograms()->getNodes()) {530myViewNet->getNet()->getAttributeCarriers()->retrieveJunction(node->getID())->selectTLS(true);531}532// update color533myTLSPhases->updateTLSColoring();534}535}536} else {537myViewNet->setStatusBarText(TL("Unsaved modifications. Abort or Save"));538}539updateModules();540}541542543SUMOTime544GNETLSEditorFrame::getSUMOTime(const std::string& string) {545return TIME2STEPS(GNEAttributeCarrier::parse<double>(string));546}547548const std::string549GNETLSEditorFrame::getSteps2Time(const SUMOTime value) {550return toString(STEPS2TIME(value));551}552553// ---------------------------------------------------------------------------554// GNETLSEditorFrame::TLSAttributes - methods555// ---------------------------------------------------------------------------556557GNETLSEditorFrame::TLSAttributes::TLSAttributes(GNETLSEditorFrame* TLSEditorParent) :558GNEGroupBoxModule(TLSEditorParent, TL("Traffic Light Attributes")),559myTLSEditorParent(TLSEditorParent) {560// create frame, label and TextField for Offset (By default disabled)561FXHorizontalFrame* horizontalFrame = new FXHorizontalFrame(getCollapsableFrame(), GUIDesignAuxiliarHorizontalFrame);562new FXLabel(horizontalFrame, toString(SUMO_ATTR_OFFSET).c_str(), nullptr, GUIDesignLabelThickedFixed(100));563myOffsetTextField = new FXTextField(horizontalFrame, GUIDesignTextFieldNCol, this, MID_GNE_TLSFRAME_ATTRIBUTES_OFFSET, GUIDesignTextField);564myOffsetTextField->disable();565// create frame, label and TextField for parameters (By default disabled)566horizontalFrame = new FXHorizontalFrame(getCollapsableFrame(), GUIDesignAuxiliarHorizontalFrame);567myButtonEditParameters = GUIDesigns::buildFXButton(horizontalFrame, TL("parameters"), "", "", nullptr, this, MID_GNE_TLSFRAME_ATTRIBUTES_PARAMETERSDIALOG, GUIDesignButtonAttribute);568myParametersTextField = new FXTextField(horizontalFrame, GUIDesignTextFieldNCol, this, MID_GNE_TLSFRAME_ATTRIBUTES_PARAMETERS, GUIDesignTextField);569myButtonEditParameters->disable();570myParametersTextField->disable();571// create set detectors button (By default disabled)572mySetDetectorsToggleButton = new MFXToggleButtonTooltip(getCollapsableFrame(),573TLSEditorParent->getViewNet()->getViewParent()->getGNEAppWindows()->getStaticTooltipMenu(),574TL("Assign E1 detectors") + std::string("\t") + TL("Enable assign E1 mode") + std::string("\t") + TL("Assign E1 detectors to the current TLS"),575TL("Assign E1 detectors") + std::string("\t") + TL("Disable assign E1 mode") + std::string("\t") + TL("Assign E1 detectors to the current TLS"),576GUIIconSubSys::getIcon(GUIIcon::E1), GUIIconSubSys::getIcon(GUIIcon::E1),577this, MID_GNE_TLSFRAME_ATTRIBUTES_TOGGLEDETECTOR, GUIDesignButton);578mySetDetectorsToggleButton->disable();579}580581582GNETLSEditorFrame::TLSAttributes::~TLSAttributes() {}583584585void586GNETLSEditorFrame::TLSAttributes::updateTLSAttributes() {587if (myTLSEditorParent->myTLSPrograms->getNumberOfPrograms() == 0) {588// no TLS programs, disable elements589myOffsetTextField->disable();590myButtonEditParameters->disable();591myParametersTextField->disable();592// disable E1 detector mode593disableE1DetectorMode();594mySetDetectorsToggleButton->disable();595// clear E1 detectors596if (myE1Detectors.size() > 0) {597myE1Detectors.clear();598myTLSEditorParent->getViewNet()->update();599}600} else if (myTLSEditorParent->myTLSJunction->isJoiningJunctions()) {601// joining TLSs, disable button602myOffsetTextField->disable();603myButtonEditParameters->disable();604myParametersTextField->disable();605// disable E1 detector mode606disableE1DetectorMode();607mySetDetectorsToggleButton->disable();608// clear E1 detectors609if (myE1Detectors.size() > 0) {610myE1Detectors.clear();611myTLSEditorParent->getViewNet()->update();612}613} else if (isSetDetectorsToggleButtonEnabled()) {614// set detectors toggle button is enabled, disable elements615myOffsetTextField->disable();616myButtonEditParameters->disable();617myParametersTextField->disable();618} else {619myOffsetTextField->enable();620myButtonEditParameters->enable();621myParametersTextField->enable();622// disable E1 detector mode in static623if (myTLSEditorParent->myTLSPrograms->getCurrentTLSPrograms()->getType() != TrafficLightType::ACTUATED) {624// disable E1 detector mode625disableE1DetectorMode();626mySetDetectorsToggleButton->disable();627// clear E1 detectors628if (myE1Detectors.size() > 0) {629myE1Detectors.clear();630myTLSEditorParent->getViewNet()->update();631}632} else {633mySetDetectorsToggleButton->enable();634}635}636}637638639void640GNETLSEditorFrame::TLSAttributes::showTLSAttributes() {641show();642}643644645void646GNETLSEditorFrame::TLSAttributes::hideTLSAttributes() {647hide();648}649650651void652GNETLSEditorFrame::TLSAttributes::initTLSAttributes() {653// get current edited junction654const auto junction = myTLSEditorParent->myTLSJunction->getCurrentJunction();655if (junction == nullptr) {656throw ProcessError("Junction cannot be NULL");657} else {658// enable Offset659myOffsetTextField->enable();660myOffsetTextField->setTextColor(MFXUtils::getFXColor(RGBColor::BLACK));661// enable parameters662myButtonEditParameters->enable();663myParametersTextField->enable();664myParametersTextField->setTextColor(MFXUtils::getFXColor(RGBColor::BLACK));665// reset mySetDetectorsToggleButton666disableE1DetectorMode();667}668}669670671void672GNETLSEditorFrame::TLSAttributes::clearTLSAttributes() {673// clear and disable Offset TextField674myOffsetTextField->setText("");675myOffsetTextField->disable();676myOffsetTextField->setTextColor(MFXUtils::getFXColor(RGBColor::BLACK));677// clear and disable parameters TextField678myButtonEditParameters->disable();679myParametersTextField->setText("");680myParametersTextField->disable();681myParametersTextField->setTextColor(MFXUtils::getFXColor(RGBColor::BLACK));682}683684685SUMOTime686GNETLSEditorFrame::TLSAttributes::getOffset() const {687return getSUMOTime(myOffsetTextField->getText().text());688}689690691void692GNETLSEditorFrame::TLSAttributes::setOffset(const SUMOTime& offset) {693myOffsetTextField->setText(getSteps2Time(offset).c_str());694myOffsetTextField->setTextColor(MFXUtils::getFXColor(RGBColor::BLACK));695}696697698bool699GNETLSEditorFrame::TLSAttributes::isValidOffset() {700if (GNEAttributeCarrier::canParse<SUMOTime>(myOffsetTextField->getText().text())) {701myOffsetTextField->setTextColor(MFXUtils::getFXColor(RGBColor::BLACK));702return true;703} else {704myOffsetTextField->setTextColor(MFXUtils::getFXColor(RGBColor::RED));705return false;706}707}708709710std::string711GNETLSEditorFrame::TLSAttributes::getParameters() const {712return myParametersTextField->getText().text();713}714715716void717GNETLSEditorFrame::TLSAttributes::setParameters(const std::string& parameters) {718myParametersTextField->setText(parameters.c_str());719myParametersTextField->setTextColor(MFXUtils::getFXColor(RGBColor::BLACK));720// update E1 detectors721if (myTLSEditorParent->myEditedDef->getType() != TrafficLightType::STATIC) {722updateE1Detectors();723}724}725726727bool728GNETLSEditorFrame::TLSAttributes::isValidParameters() {729if (Parameterised::areParametersValid(myParametersTextField->getText().text())) {730myParametersTextField->setTextColor(MFXUtils::getFXColor(RGBColor::BLACK));731return true;732} else {733myParametersTextField->setTextColor(MFXUtils::getFXColor(RGBColor::RED));734return false;735}736}737738739bool740GNETLSEditorFrame::TLSAttributes::isSetDetectorsToggleButtonEnabled() const {741return (mySetDetectorsToggleButton->getState() == TRUE);742}743744745bool746GNETLSEditorFrame::TLSAttributes::toggleE1DetectorSelection(const GNEAdditional* E1) {747// get E1 lane ID748const auto laneID = E1->getParentLanes().front()->getID();749// iterate over all E1 detectors750for (auto it = myE1Detectors.begin(); it != myE1Detectors.end(); it++) {751if (E1->getID() == it->second) {752// already selected, then remove it from detectors753myE1Detectors.erase(it);754// and remove it from parameters755myTLSEditorParent->myEditedDef->unsetParameter(laneID);756myParametersTextField->setText(myTLSEditorParent->myEditedDef->getParametersStr().c_str());757// mark TL as modified758myTLSEditorParent->myTLSPrograms->markAsModified();759return true;760} else if (laneID == it->first) {761// there is another E1 in the same lane, then swap762myE1Detectors.erase(it);763myE1Detectors[laneID] = E1->getID();764// also in parameters765myTLSEditorParent->myEditedDef->setParameter(laneID, E1->getID());766myParametersTextField->setText(myTLSEditorParent->myEditedDef->getParametersStr().c_str());767// mark TL as modified768myTLSEditorParent->myTLSPrograms->markAsModified();769return true;770}771}772// add it in parameters773myE1Detectors[laneID] = E1->getID();774myTLSEditorParent->myEditedDef->setParameter(laneID, E1->getID());775myParametersTextField->setText(myTLSEditorParent->myEditedDef->getParametersStr().c_str());776// mark TL as modified777myTLSEditorParent->myTLSPrograms->markAsModified();778return true;779}780781782const std::map<std::string, std::string>&783GNETLSEditorFrame::TLSAttributes::getE1Detectors() const {784return myE1Detectors;785}786787788void789GNETLSEditorFrame::TLSAttributes::disableE1DetectorMode() {790mySetDetectorsToggleButton->setState(FALSE, TRUE);791}792793794long795GNETLSEditorFrame::TLSAttributes::onCmdSetOffset(FXObject*, FXSelector, void*) {796if (isValidOffset()) {797myTLSEditorParent->myTLSPrograms->markAsModified();798myTLSEditorParent->myEditedDef->setOffset(getOffset());799myOffsetTextField->killFocus();800myTLSEditorParent->updateModules();801}802return 1;803}804805806long807GNETLSEditorFrame::TLSAttributes::onCmdSetParameters(FXObject*, FXSelector, void*) {808if (isValidParameters()) {809myTLSEditorParent->myTLSPrograms->markAsModified();810myTLSEditorParent->myEditedDef->setParametersStr(getParameters());811myParametersTextField->killFocus();812myTLSEditorParent->updateModules();813}814return 1;815}816817818long819GNETLSEditorFrame::TLSAttributes::onCmdParametersDialog(FXObject*, FXSelector, void*) {820auto GNEApp = myTLSEditorParent->getViewNet()->getViewParent()->getGNEAppWindows();821// continue depending of myEditedDef822if (myTLSEditorParent->myEditedDef) {823// get previous parameters824const auto previousParameters = getParameters();825// open parameters dialog826const GNEParametersDialog parametersDialog(GNEApp, myTLSEditorParent->myEditedDef->getParametersMap());827// continue depending of result828if (parametersDialog.getResult() == GNEDialog::Result::ACCEPT) {829// set parameters in myEditedDef830myTLSEditorParent->myEditedDef->setParameters(parametersDialog.getEditedParameters());831// set parameters in textfield832setParameters(myTLSEditorParent->myEditedDef->getParametersStr());833// only mark as modified if parameters are different834if (getParameters() != previousParameters) {835myTLSEditorParent->myTLSPrograms->markAsModified();836}837}838myTLSEditorParent->updateModules();839}840return 1;841}842843844long845GNETLSEditorFrame::TLSAttributes::onCmdToggleDetectorMode(FXObject*, FXSelector, void*) {846if (mySetDetectorsToggleButton->getState()) {847// set special color848mySetDetectorsToggleButton->setBackColor(FXRGBA(253, 255, 206, 255));849} else {850// restore default color851mySetDetectorsToggleButton->setBackColor(4293980400);852}853myTLSEditorParent->updateModules();854// update view855myTLSEditorParent->getViewNet()->update();856return 1;857}858859860void861GNETLSEditorFrame::TLSAttributes::updateE1Detectors() {862// first clear E1 detectors863myE1Detectors.clear();864// iterate over parameters865for (const auto& parameter : myTLSEditorParent->myEditedDef->getParametersMap()) {866// check if both lane and E1 exists867if (myTLSEditorParent->getViewNet()->getNet()->getAttributeCarriers()->retrieveLane(parameter.first, false) &&868myTLSEditorParent->getViewNet()->getNet()->getAttributeCarriers()->retrieveAdditional(SUMO_TAG_INDUCTION_LOOP, parameter.second, false)) {869// add it into list870myE1Detectors[parameter.first] = parameter.second;871}872}873myTLSEditorParent->updateModules();874// update view net875myTLSEditorParent->getViewNet()->update();876}877878// ---------------------------------------------------------------------------879// GNETLSEditorFrame::TLSJunction - methods880// ---------------------------------------------------------------------------881882GNETLSEditorFrame::TLSJunction::TLSJunction(GNETLSEditorFrame* TLSEditorParent) :883GNEGroupBoxModule(TLSEditorParent, TL("Traffic Light")),884myTLSEditorParent(TLSEditorParent),885myCurrentJunction(nullptr) {886const auto staticTooltip = TLSEditorParent->getViewNet()->getViewParent()->getGNEAppWindows()->getStaticTooltipMenu();887// Create frame for junction IDs888FXHorizontalFrame* junctionIDFrame = new FXHorizontalFrame(getCollapsableFrame(), GUIDesignAuxiliarHorizontalFrame);889myJunctionIDLabel = new FXLabel(junctionIDFrame, TL("Junction ID"), nullptr, GUIDesignLabelThickedFixed(100));890myJunctionIDTextField = new MFXTextFieldIcon(junctionIDFrame, staticTooltip, GUIIcon::EMPTY, nullptr, 0, GUIDesignTextField);891// junction ID remains always disabled892myJunctionIDTextField->disable();893// Create frame for TLS Program ID894FXHorizontalFrame* TLSIDFrame = new FXHorizontalFrame(getCollapsableFrame(), GUIDesignAuxiliarHorizontalFrame);895new FXLabel(TLSIDFrame, TL("TLS ID"), nullptr, GUIDesignLabelThickedFixed(100));896myTLSIDTextField = new MFXTextFieldIcon(TLSIDFrame, staticTooltip, GUIIcon::EMPTY, this, MID_GNE_TLSFRAME_TLSJUNCTION_ID, GUIDesignTextField);897// create frame, label and textfield for type898FXHorizontalFrame* typeFrame = new FXHorizontalFrame(getCollapsableFrame(), GUIDesignAuxiliarHorizontalFrame);899new FXLabel(typeFrame, toString(SUMO_ATTR_TYPE).c_str(), nullptr, GUIDesignLabelThickedFixed(100));900myTLSTypeComboBox = new MFXComboBoxIcon(typeFrame, staticTooltip, false, GUIDesignComboBoxVisibleItems,901this, MID_GNE_TLSFRAME_TLSJUNCTION_TYPE, GUIDesignComboBoxAttribute);902// fill comboBox (only certain TL types)903myTLSTypeComboBox->appendIconItem(toString(TrafficLightType::STATIC).c_str());904myTLSTypeComboBox->appendIconItem(toString(TrafficLightType::ACTUATED).c_str());905myTLSTypeComboBox->appendIconItem(toString(TrafficLightType::DELAYBASED).c_str());906myTLSTypeComboBox->appendIconItem(toString(TrafficLightType::NEMA).c_str());907// create frame for join buttons908FXHorizontalFrame* joinButtons = new FXHorizontalFrame(getCollapsableFrame(), GUIDesignAuxiliarHorizontalFrameUniform);909// create join states button910myJoinTLSToggleButton = new MFXToggleButtonTooltip(joinButtons, staticTooltip,911TL("Join") + std::string("\t") + TL("Enable join mode") + std::string("\t") + TL("Join TLS and junctions in the current junction."),912TL("Join") + std::string("\t") + TL("Disable join mode") + std::string("\t") + TL("Join TLS and junctions in the current junction."),913GUIIconSubSys::getIcon(GUIIcon::JOIN), GUIIconSubSys::getIcon(GUIIcon::JOIN),914this, MID_GNE_TLSFRAME_TLSJUNCTION_TOGGLEJOIN, GUIDesignButton);915myDisjoinTLSButton = new MFXButtonTooltip(joinButtons, staticTooltip,916TL("Disjoin") + std::string("\t") + TL("Disjoin current TLS") + std::string("\t") + TL("Disjoin current TLS."),917GUIIconSubSys::getIcon(GUIIcon::DISJOIN), this, MID_GNE_TLSFRAME_TLSJUNCTION_DISJOIN, GUIDesignButton);918// create frame for join control buttons919myJoinControlButtons = new FXHorizontalFrame(getCollapsableFrame(), GUIDesignAuxiliarHorizontalFrameUniform);920// create create tlDef button921GUIDesigns::buildFXButton(myJoinControlButtons, TL("Accept"), "", TL("Finish join."),922GUIIconSubSys::getIcon(GUIIcon::ACCEPT), this, MID_GNE_BUTTON_ACCEPT, GUIDesignButton);923GUIDesigns::buildFXButton(myJoinControlButtons, TL("Cancel"), "", TL("Cancel Join."),924GUIIconSubSys::getIcon(GUIIcon::CANCEL), this, MID_GNE_BUTTON_CANCEL, GUIDesignButton);925// update junction description after creation926refreshTLSJunction();927// show TLS Junction928show();929}930931932GNETLSEditorFrame::TLSJunction::~TLSJunction() {}933934935void936GNETLSEditorFrame::TLSJunction::updateTLSJunction() {937if ((myCurrentJunction == nullptr) ||938(myCurrentJunction->getNBNode()->getControllingTLS().size() == 0)) {939// no TLS940myJunctionIDTextField->setText(TL("No junction selected"));941myTLSIDTextField->setText("");942myTLSIDTextField->disable();943myTLSTypeComboBox->disable();944myJoinTLSToggleButton->disable();945myDisjoinTLSButton->disable();946myJoinControlButtons->hide();947} else {948// get first controled TLS949const auto TLS = (*myCurrentJunction->getNBNode()->getControllingTLS().begin());950// set TLS type in comboBox951const int index = myTLSTypeComboBox->findItem(myCurrentJunction->getAttribute(SUMO_ATTR_TLTYPE).c_str());952if (index != -1) {953myTLSTypeComboBox->setCurrentItem(index, FALSE);954}955// set text field IDs956myJunctionIDTextField->setText(myCurrentJunction->getID().c_str());957myTLSIDTextField->setText(TLS->getID().c_str());958// continue with more options959if (myTLSEditorParent->myTLSAttributes->isSetDetectorsToggleButtonEnabled() ||960myTLSEditorParent->myTLSPrograms->checkHaveModifications()) {961// disable if selecting selecting detectors or we modified the program962myTLSIDTextField->setText("");963myTLSIDTextField->disable();964myTLSTypeComboBox->disable();965myJoinTLSToggleButton->disable();966myDisjoinTLSButton->disable();967myJoinControlButtons->hide();968} else if (myTLSEditorParent->myTLSJunction->isJoiningJunctions()) {969// partial disable due joining970myTLSIDTextField->setText("");971myTLSIDTextField->disable();972myTLSTypeComboBox->disable();973myDisjoinTLSButton->disable();974// enable join TLS and show control buttons975myJoinTLSToggleButton->enable();976myJoinControlButtons->show();977} else {978// enable979myTLSIDTextField->enable();980myTLSTypeComboBox->enable();981myJoinTLSToggleButton->enable();982// disjoint button only if we have more than one TLS controlled983if (TLS->getNodes().size() == 1) {984myDisjoinTLSButton->disable();985} else {986myDisjoinTLSButton->enable();987}988}989}990}991992993GNEJunction*994GNETLSEditorFrame::TLSJunction::getCurrentJunction() const {995return myCurrentJunction;996}997998999void1000GNETLSEditorFrame::TLSJunction::setCurrentJunction(GNEJunction* junction) {1001myCurrentJunction = junction;1002// resfresh module1003refreshTLSJunction();1004}100510061007bool1008GNETLSEditorFrame::TLSJunction::isJoiningJunctions() const {1009return (myJoinTLSToggleButton->getState() == TRUE);1010}101110121013bool1014GNETLSEditorFrame::TLSJunction::isJunctionSelected(const GNEJunction* junction) const {1015return (std::find(mySelectedJunctionIDs.begin(), mySelectedJunctionIDs.end(), junction->getID()) != mySelectedJunctionIDs.end());1016}101710181019void1020GNETLSEditorFrame::TLSJunction::toggleJunctionSelected(const GNEJunction* junction) {1021// avoid current junction1022if (junction != myCurrentJunction) {1023// find ID in selected junctions1024auto it = std::find(mySelectedJunctionIDs.begin(), mySelectedJunctionIDs.end(), junction->getID());1025// check if add or remove1026if (it == mySelectedJunctionIDs.end()) {1027mySelectedJunctionIDs.push_back(junction->getID());1028} else {1029mySelectedJunctionIDs.erase(it);1030}1031}1032}103310341035const std::vector<std::string>&1036GNETLSEditorFrame::TLSJunction::getSelectedJunctionIDs() const {1037return mySelectedJunctionIDs;1038}103910401041long1042GNETLSEditorFrame::TLSJunction::onCmdRenameTLS(FXObject*, FXSelector, void*) {1043// get IDs1044const std::string currentTLID = (*myCurrentJunction->getNBNode()->getControllingTLS().begin())->getID();1045const std::string newTLID = myTLSIDTextField->getText().text();1046// check if ID is valid1047if (newTLID.empty() || (newTLID == currentTLID)) {1048// same ID or empty1049myTLSIDTextField->setTextColor(GUIDesignTextColorBlack);1050myTLSIDTextField->setText(currentTLID.c_str());1051myTLSIDTextField->killFocus();1052myTLSEditorParent->update();1053// show all moduls1054myTLSEditorParent->myTLSPrograms->showTLSPrograms();1055myTLSEditorParent->myTLSAttributes->showTLSAttributes();1056myTLSEditorParent->myTLSPhases->showTLSPhases();1057myTLSEditorParent->myTLSFile->showTLSFile();1058} else if (!SUMOXMLDefinitions::isValidNetID(newTLID) || myCurrentJunction->getNet()->getTLLogicCont().exist(newTLID)) {1059// set invalid color1060myTLSIDTextField->setTextColor(GUIDesignTextColorRed);1061// hide moduls1062myTLSEditorParent->myTLSPrograms->hideTLSPrograms();1063myTLSEditorParent->myTLSAttributes->hideTLSAttributes();1064myTLSEditorParent->myTLSPhases->hideTLSPhases();1065myTLSEditorParent->myTLSFile->hideTLSFile();1066} else {1067// make a copy of myCurrentJunction and current tlDef (because will be reset after calling discardChanges)1068auto junction = myCurrentJunction;1069const auto tlDef = myTLSEditorParent->myTLSPrograms->getCurrentTLSPrograms();1070// restore color1071myTLSIDTextField->setTextColor(GUIDesignTextColorBlack);1072myTLSIDTextField->killFocus();1073myTLSEditorParent->update();1074// discard previous changes1075myTLSEditorParent->myTLSPrograms->discardChanges(false);1076// change name using undo-List1077myTLSEditorParent->getViewNet()->getUndoList()->begin(GUIIcon::MODETLS, TL("rename TLS"));1078myTLSEditorParent->getViewNet()->getUndoList()->add(new GNEChange_TLS(junction, tlDef, newTLID), true);1079myTLSEditorParent->getViewNet()->getUndoList()->end();1080// show all moduls1081myTLSEditorParent->myTLSPrograms->showTLSPrograms();1082myTLSEditorParent->myTLSAttributes->showTLSAttributes();1083myTLSEditorParent->myTLSPhases->showTLSPhases();1084myTLSEditorParent->myTLSFile->showTLSFile();1085// edit junction again1086myTLSEditorParent->editJunction(junction);1087}1088myTLSEditorParent->updateModules();1089return 1;1090}109110921093long1094GNETLSEditorFrame::TLSJunction::onCmdChangeType(FXObject*, FXSelector, void*) {1095// get IDs1096const std::string currentTLType = toString((*myCurrentJunction->getNBNode()->getControllingTLS().begin())->getType());1097const std::string newTLType = myTLSTypeComboBox->getText().text();1098// check if ID is valid1099if (newTLType.empty() || (newTLType == currentTLType)) {1100// same ID or empty, don't change1101myTLSTypeComboBox->setTextColor(GUIDesignTextColorBlack);1102// set value1103const int index = myTLSTypeComboBox->findItem(currentTLType.c_str());1104if (index == -1) {1105myTLSTypeComboBox->disable();1106} else {1107myTLSTypeComboBox->setCurrentItem(index);1108myTLSTypeComboBox->enable();1109}1110myTLSTypeComboBox->killFocus();1111myTLSEditorParent->update();1112// show all moduls1113myTLSEditorParent->myTLSPrograms->showTLSPrograms();1114myTLSEditorParent->myTLSAttributes->showTLSAttributes();1115myTLSEditorParent->myTLSPhases->showTLSPhases();1116myTLSEditorParent->myTLSFile->showTLSFile();1117} else if (!SUMOXMLDefinitions::TrafficLightTypes.hasString(newTLType)) {1118// set invalid color1119myTLSTypeComboBox->setTextColor(GUIDesignTextColorRed);1120// hide moduls1121myTLSEditorParent->myTLSPrograms->hideTLSPrograms();1122myTLSEditorParent->myTLSAttributes->hideTLSAttributes();1123myTLSEditorParent->myTLSPhases->hideTLSPhases();1124myTLSEditorParent->myTLSFile->hideTLSFile();1125} else {1126// reset color1127myTLSTypeComboBox->setTextColor(GUIDesignTextColorBlack);1128myTLSTypeComboBox->killFocus();1129myTLSEditorParent->update();1130// make a copy of myCurrentJunction (because will be reset after calling discardChanges)1131auto junction = myCurrentJunction;1132// discard previous changes1133myTLSEditorParent->myTLSPrograms->discardChanges(false);1134// change name using undo-List1135myTLSEditorParent->getViewNet()->getUndoList()->begin(GUIIcon::MODETLS, TL("change TLS type"));1136junction->setAttribute(SUMO_ATTR_TLTYPE, newTLType, myTLSEditorParent->getViewNet()->getUndoList());1137myTLSEditorParent->getViewNet()->getUndoList()->end();1138// show all moduls1139myTLSEditorParent->myTLSPrograms->showTLSPrograms();1140myTLSEditorParent->myTLSAttributes->showTLSAttributes();1141myTLSEditorParent->myTLSPhases->showTLSPhases();1142myTLSEditorParent->myTLSFile->showTLSFile();1143// edit junction again1144myTLSEditorParent->editJunction(junction);1145}1146myTLSEditorParent->updateModules();1147return 1;11481149}115011511152long1153GNETLSEditorFrame::TLSJunction::onCmdToggleJoinTLS(FXObject*, FXSelector, void*) {1154if (myJoinTLSToggleButton->getState()) {1155// set special color1156myJoinTLSToggleButton->setBackColor(FXRGBA(253, 255, 206, 255));1157// clear and fill mySelectedJunctionIDs1158mySelectedJunctionIDs.clear();1159// get all nodes controlled by this TLS1160const auto TLNodes = (*myCurrentJunction->getNBNode()->getControllingTLS().begin())->getNodes();1161// fill mySelectedJunctionIDs with TLNodes1162mySelectedJunctionIDs.clear();1163for (const auto& TLNode : TLNodes) {1164mySelectedJunctionIDs.push_back(TLNode->getID());1165}1166// make a copy of selected junctions1167myOriginalSelectedJunctionIDs = mySelectedJunctionIDs;1168// show control buttons1169myJoinControlButtons->show();1170getCollapsableFrame()->recalc();1171} else {1172// hide control buttons1173myJoinControlButtons->hide();1174getCollapsableFrame()->recalc();1175// make a copy of current junction1176const auto currentJunction = myCurrentJunction;1177// declare vectors for junctions1178std::vector<GNEJunction*> selectedJunctions, resetTLJunctions;1179// get selected junctions (all except current1180for (const auto& selectedJunctionID : mySelectedJunctionIDs) {1181if (selectedJunctionID != currentJunction->getID()) {1182selectedJunctions.push_back(myTLSEditorParent->getViewNet()->getNet()->getAttributeCarriers()->retrieveJunction(selectedJunctionID));1183}1184}1185// get junctions to reset TL (all TL nodes except current)1186for (const auto& TLNBNode : (*currentJunction->getNBNode()->getControllingTLS().begin())->getNodes()) {1187if (TLNBNode != currentJunction->getNBNode()) {1188resetTLJunctions.push_back(myTLSEditorParent->getViewNet()->getNet()->getAttributeCarriers()->retrieveJunction(TLNBNode->getID()));1189}1190}1191// discard changes1192myTLSEditorParent->myTLSPrograms->discardChanges(false);1193// begin undo list1194myTLSEditorParent->getViewNet()->getUndoList()->begin(GUIIcon::MODETLS, TL("join TLS"));1195// remove tl from TLNBNode1196for (const auto& resetTLJunction : resetTLJunctions) {1197resetTLJunction->setAttribute(SUMO_ATTR_TYPE, "priority", myTLSEditorParent->getViewNet()->getUndoList());1198}1199// now update it in all joined junctions1200for (const auto& selectedJunction : selectedJunctions) {1201selectedJunction->setAttribute(SUMO_ATTR_TYPE, currentJunction->getAttribute(SUMO_ATTR_TYPE), myTLSEditorParent->getViewNet()->getUndoList());1202selectedJunction->setAttribute(SUMO_ATTR_TLID, currentJunction->getAttribute(SUMO_ATTR_TLID), myTLSEditorParent->getViewNet()->getUndoList());1203}1204// end undo list1205myTLSEditorParent->getViewNet()->getUndoList()->end();1206// restore default color1207myJoinTLSToggleButton->setBackColor(4293980400);1208// clear selected junction IDs1209mySelectedJunctionIDs.clear();1210// edit junction again1211myTLSEditorParent->editJunction(currentJunction);1212}1213myTLSEditorParent->updateModules();1214// update view1215myTLSEditorParent->getViewNet()->update();1216return 1;1217}121812191220long1221GNETLSEditorFrame::TLSJunction::onCmdDisjoinTLS(FXObject*, FXSelector, void*) {1222// make a copy of current junction1223const auto currentJunction = myCurrentJunction;1224// declare vectors for junctions1225std::vector<GNEJunction*> resetTLJunctions;1226// get junctions to reset TL1227for (const auto& TLNBNode : (*currentJunction->getNBNode()->getControllingTLS().begin())->getNodes()) {1228resetTLJunctions.push_back(myTLSEditorParent->getViewNet()->getNet()->getAttributeCarriers()->retrieveJunction(TLNBNode->getID()));1229}1230// save TL types1231const auto type = resetTLJunctions.front()->getAttribute(SUMO_ATTR_TYPE);1232const auto tlType = resetTLJunctions.front()->getAttribute(SUMO_ATTR_TLTYPE);1233// discard changes1234myTLSEditorParent->myTLSPrograms->discardChanges(false);1235// begin undo list1236myTLSEditorParent->getViewNet()->getUndoList()->begin(GUIIcon::MODETLS, TL("disjoin TLS"));1237// the disjoint tlIds will be the junction ids. Ensure that there is no name clash with the current tlId1238NBTrafficLightLogicCont& tllCont = myTLSEditorParent->getViewNet()->getNet()->getTLLogicCont();1239const std::string oldId = currentJunction->getAttribute(SUMO_ATTR_TLID);1240const std::string tmpIdBase = oldId + "_TMP";1241int tmpIndex = 0;1242std::string tmpId = tmpIdBase + toString(tmpIndex);1243while (tllCont.exist(tmpId)) {1244tmpId = tmpIdBase + toString(++tmpIndex);1245}1246for (NBTrafficLightDefinition* tlDef : currentJunction->getNBNode()->getControllingTLS()) {1247myTLSEditorParent->getViewNet()->getUndoList()->add(new GNEChange_TLS(currentJunction, tlDef, tmpId), true);1248}1249// remove tl from TLNBNode and the re-initialize as single traffic light1250for (const auto& resetTLJunction : resetTLJunctions) {1251resetTLJunction->setAttribute(SUMO_ATTR_TYPE, "priority", myTLSEditorParent->getViewNet()->getUndoList());1252resetTLJunction->setAttribute(SUMO_ATTR_TYPE, type, myTLSEditorParent->getViewNet()->getUndoList());1253resetTLJunction->setAttribute(SUMO_ATTR_TLTYPE, tlType, myTLSEditorParent->getViewNet()->getUndoList());1254}1255// end undo list1256myTLSEditorParent->getViewNet()->getUndoList()->end();1257// restore default color1258myJoinTLSToggleButton->setBackColor(4293980400);1259// clear selected junction IDs1260mySelectedJunctionIDs.clear();1261// edit junction again1262myTLSEditorParent->editJunction(currentJunction);1263myTLSEditorParent->updateModules();1264return 1;1265}126612671268long1269GNETLSEditorFrame::TLSJunction::onCmdAcceptJoin(FXObject*, FXSelector, void*) {1270myJoinTLSToggleButton->setState(FALSE, TRUE);1271myTLSEditorParent->updateModules();1272return 1;1273}127412751276long1277GNETLSEditorFrame::TLSJunction::onCmdCancelJoin(FXObject*, FXSelector, void*) {1278// restore selected junction1279mySelectedJunctionIDs = myOriginalSelectedJunctionIDs;1280myJoinTLSToggleButton->setState(FALSE, TRUE);1281myTLSEditorParent->updateModules();1282return 1;1283}128412851286void1287GNETLSEditorFrame::TLSJunction::refreshTLSJunction() {1288// first reset junction label1289myJunctionIDLabel->setText(TL("Junction ID"));1290// clear selected junctions1291mySelectedJunctionIDs.clear();1292// cancel joining junction mode1293onCmdCancelJoin(nullptr, 0, nullptr);1294// continue depending of current junction1295if (myCurrentJunction == nullptr) {1296myJunctionIDTextField->setText(TL("No junction selected"));1297} else {1298// get all TLS assigned to this node1299const auto& TLSs = myCurrentJunction->getNBNode()->getControllingTLS();1300// check if junction is controlled1301if (TLSs.size() > 0) {1302// get first TLS1303const auto TLS = (*TLSs.begin());1304// update junction ID text field1305if (TLS->getNodes().size() > 1) {1306// declare string1307std::string TLSNodesStr;1308for (auto it = TLS->getNodes().begin(); it != TLS->getNodes().end(); it++) {1309if (it == (TLS->getNodes().end() - 1)) {1310TLSNodesStr += (*it)->getID();1311} else {1312TLSNodesStr += (*it)->getID() + ", ";1313}1314}1315// updated junction fields1316myJunctionIDTextField->setText(TLSNodesStr.c_str());1317// update junction label if we have multiple nodes1318if (TLS->getNodes().size() > 1) {1319myJunctionIDLabel->setText(TL("Junction IDs"));1320}1321// set TLS type in comboBox1322const int index = myTLSTypeComboBox->findItem(myCurrentJunction->getAttribute(SUMO_ATTR_TLTYPE).c_str());1323if (index != -1) {1324myTLSTypeComboBox->setCurrentItem(index, FALSE);1325}1326}1327} else {1328// update junction ID text field1329myJunctionIDTextField->setText(myCurrentJunction->getID().c_str());1330myTLSTypeComboBox->setCurrentItem(0, FALSE);1331}1332}1333// update TLS junction1334updateTLSJunction();1335}13361337// ---------------------------------------------------------------------------1338// GNETLSEditorFrame::TLSPrograms - methods1339// ---------------------------------------------------------------------------13401341GNETLSEditorFrame::TLSPrograms::TLSPrograms(GNETLSEditorFrame* TLSEditorParent) :1342GNEGroupBoxModule(TLSEditorParent, TL("Traffic Light Programs")),1343myTLSEditorParent(TLSEditorParent) {1344// create frame, label and comboBox for programID1345FXHorizontalFrame* programFrame = new FXHorizontalFrame(getCollapsableFrame(), GUIDesignAuxiliarHorizontalFrame);1346new FXLabel(programFrame, toString(SUMO_ATTR_PROGRAMID).c_str(), nullptr, GUIDesignLabelThickedFixed(100));1347myProgramComboBox = new MFXComboBoxIcon(programFrame, TLSEditorParent->getViewNet()->getViewParent()->getGNEAppWindows()->getStaticTooltipMenu(),1348false, GUIDesignComboBoxVisibleItems, this, MID_GNE_TLSFRAME_DEFINITION_SWITCHPROGRAM, GUIDesignComboBoxAttribute);1349myProgramComboBox->disable();1350// create auxiliar frames1351FXHorizontalFrame* horizontalFrameAux = new FXHorizontalFrame(getCollapsableFrame(), GUIDesignAuxiliarHorizontalFrameUniform);1352FXVerticalFrame* verticalFrameAuxA = new FXVerticalFrame(horizontalFrameAux, GUIDesignAuxiliarHorizontalFrame);1353FXVerticalFrame* verticalFrameAuxB = new FXVerticalFrame(horizontalFrameAux, GUIDesignAuxiliarHorizontalFrame);1354// create create tlDef button1355myCreateButton = GUIDesigns::buildFXButton(verticalFrameAuxA, TL("Create TLS"), "", TL("Create a new traffic light program."),1356GUIIconSubSys::getIcon(GUIIcon::MODETLS), this, MID_GNE_TLSFRAME_DEFINITION_CREATE, GUIDesignButton);1357myCreateButton->disable();1358// create delete tlDef button1359myDeleteButton = GUIDesigns::buildFXButton(verticalFrameAuxA, TL("Delete"), "", TL("Delete a traffic light program. If all programs are deleted the junction turns into a priority junction."),1360GUIIconSubSys::getIcon(GUIIcon::REMOVE), this, MID_GNE_TLSFRAME_DEFINITION_DELETE, GUIDesignButton);1361myDeleteButton->disable();1362// create reset current tlDef button1363myResetSingleButton = GUIDesigns::buildFXButton(verticalFrameAuxB, TL("Reset single"), "", TL("Reset current TLS program."),1364GUIIconSubSys::getIcon(GUIIcon::RESET), this, MID_GNE_TLSFRAME_DEFINITION_RESETCURRENT, GUIDesignButton);1365myResetSingleButton->disable();1366// create reset all tlDefs button1367myResetAllButton = GUIDesigns::buildFXButton(verticalFrameAuxB, TL("Reset all"), "", TL("Reset all TLS programs."),1368GUIIconSubSys::getIcon(GUIIcon::RESET), this, MID_GNE_TLSFRAME_DEFINITION_RESETALL, GUIDesignButton);1369myResetAllButton->disable();1370// create save modifications button1371mySaveButon = GUIDesigns::buildFXButton(verticalFrameAuxA, TL("Save"), "", TL("Save program modifications. (Enter)"),1372GUIIconSubSys::getIcon(GUIIcon::OK), this, MID_GNE_TLSFRAME_DEFINITION_SAVE, GUIDesignButton);1373mySaveButon->disable();1374// create cancel modifications buttons1375myCancelButon = GUIDesigns::buildFXButton(verticalFrameAuxB, TL("Cancel"), "", TL("Discard program modifications. (Esc)"),1376GUIIconSubSys::getIcon(GUIIcon::CANCEL), this, MID_GNE_TLSFRAME_DEFINITION_DISCARD, GUIDesignButton);1377myCancelButon->disable();1378// show GroupBox1379show();1380}138113821383GNETLSEditorFrame::TLSPrograms::~TLSPrograms() {}138413851386void1387GNETLSEditorFrame::TLSPrograms::updateTLSPrograms() {1388if (getNumberOfPrograms() == 0) {1389// no TLS Programs, disable buttons except create (if we have a junction)1390if (myTLSEditorParent->getTLSJunction()->getCurrentJunction() != nullptr) {1391myCreateButton->enable();1392} else {1393myCreateButton->disable();1394}1395myDeleteButton->disable();1396myResetSingleButton->disable();1397myProgramComboBox->disable();1398myResetAllButton->disable();1399mySaveButon->disable();1400myCancelButon->disable();1401} else if (myTLSEditorParent->myTLSAttributes->isSetDetectorsToggleButtonEnabled()) {1402// selecting E1, disable buttons1403myCreateButton->disable();1404myDeleteButton->disable();1405myResetSingleButton->disable();1406myProgramComboBox->disable();1407myResetAllButton->disable();1408mySaveButon->disable();1409myCancelButon->disable();1410} else if (myTLSEditorParent->myTLSJunction->isJoiningJunctions()) {1411// joining TLSs, disable button1412myCreateButton->disable();1413myDeleteButton->disable();1414myResetSingleButton->disable();1415myProgramComboBox->disable();1416myResetAllButton->disable();1417mySaveButon->disable();1418myCancelButon->disable();1419} else if (myHaveModifications) {1420// modifications, disable button1421myCreateButton->disable();1422myDeleteButton->disable();1423myResetSingleButton->disable();1424myProgramComboBox->disable();1425myResetAllButton->disable();1426// enable save and cancel buttons1427mySaveButon->enable();1428myCancelButon->enable();1429} else {1430myCreateButton->enable();1431myDeleteButton->enable();1432myResetSingleButton->enable();1433myProgramComboBox->enable();1434// disable save and cancel buttons1435mySaveButon->disable();1436myCancelButon->disable();1437// check if enable reset all1438if (getNumberOfPrograms() > 1) {1439myResetAllButton->enable();1440} else {1441myResetAllButton->disable();1442}1443}1444// get current junction1445const auto currentJunction = myTLSEditorParent->myTLSJunction->getCurrentJunction();1446// update button text1447if (currentJunction == nullptr) {1448myCreateButton->setText(TL("Create"));1449} else if (currentJunction->getNBNode()->isTLControlled()) {1450myCreateButton->setText(TL("Duplicate"));1451} else {1452myCreateButton->setText(TL("Create"));1453}1454}145514561457void1458GNETLSEditorFrame::TLSPrograms::showTLSPrograms() {1459show();1460}146114621463void1464GNETLSEditorFrame::TLSPrograms::hideTLSPrograms() {1465hide();1466}146714681469bool1470GNETLSEditorFrame::TLSPrograms::initTLSPrograms() {1471// get current edited junction1472const auto junction = myTLSEditorParent->myTLSJunction->getCurrentJunction();1473if (junction == nullptr) {1474throw ProcessError("Junction cannot be NULL");1475} else {1476// clear definitions1477myTLSPrograms.clear();1478// obtain TLSs sorted by ID1479std::set<std::string> programIDs;1480for (const auto& TLS : junction->getNBNode()->getControllingTLS()) {1481myTLSPrograms.push_back(TLS);1482programIDs.insert(TLS->getProgramID());1483}1484for (const auto& programID : programIDs) {1485myProgramComboBox->appendIconItem(programID.c_str());1486}1487// check if enable TLS definitions1488if (myTLSPrograms.size() > 0) {1489myProgramComboBox->enable();1490myProgramComboBox->setCurrentItem(0);1491// switch TLS Program1492return switchProgram();1493}1494return false;1495}1496}149714981499void1500GNETLSEditorFrame::TLSPrograms::clearTLSProgramss() {1501// clear definitions1502myTLSPrograms.clear();1503// clear and disable myProgramComboBox1504myProgramComboBox->clearItems();1505myProgramComboBox->disable();1506}150715081509int1510GNETLSEditorFrame::TLSPrograms::getNumberOfPrograms() const {1511return myProgramComboBox->getNumItems();1512}151315141515bool1516GNETLSEditorFrame::TLSPrograms::checkHaveModifications() const {1517return myHaveModifications;1518}151915201521void1522GNETLSEditorFrame::TLSPrograms::markAsModified() {1523myHaveModifications = true;1524myTLSEditorParent->updateModules();1525}152615271528NBTrafficLightDefinition*1529GNETLSEditorFrame::TLSPrograms::getCurrentTLSPrograms() const {1530// find TLS definition1531for (const auto& TLSPrograms : myTLSPrograms) {1532if (TLSPrograms->getProgramID() == myProgramComboBox->getText().text()) {1533return TLSPrograms;1534}1535}1536throw ProcessError(TL("TLSPrograms cannot be found"));1537}153815391540const std::string1541GNETLSEditorFrame::TLSPrograms::getCurrentTLSProgramID() const {1542if (myProgramComboBox->getNumItems() == 0) {1543return "";1544} else {1545return myProgramComboBox->getText().text();1546}1547}154815491550void1551GNETLSEditorFrame::TLSPrograms::discardChanges(const bool editJunctionAgain) {1552// get junction copy1553auto currentJunction = myTLSEditorParent->myTLSJunction->getCurrentJunction();1554if (currentJunction != nullptr) {1555myTLSEditorParent->getViewNet()->getUndoList()->abortAllChangeGroups();1556myTLSEditorParent->cleanup();1557myTLSEditorParent->getViewNet()->updateViewNet();1558// edit junction again1559if (editJunctionAgain) {1560myTLSEditorParent->editJunction(currentJunction);1561}1562}1563myTLSEditorParent->updateModules();1564}156515661567long1568GNETLSEditorFrame::TLSPrograms::onCmdCreate(FXObject*, FXSelector, void*) {1569auto GNEApp = myTLSEditorParent->getViewNet()->getViewParent()->getGNEAppWindows();1570// get current edited junction (needed because onCmdDiscardChanges clear junction)1571GNEJunction* currentJunction = myTLSEditorParent->myTLSJunction->getCurrentJunction();1572// abort because we onCmdOk assumes we wish to save an edited definition1573discardChanges(false);1574// check number of edges1575if (currentJunction->getGNEIncomingEdges().empty() && currentJunction->getGNEOutgoingEdges().empty()) {1576// open warning dialog1577GNEWarningBasicDialog(GNEApp,1578TL("TLS cannot be created"),1579TL("Traffic Light cannot be created because junction must have"),1580TL("at least one incoming edge and one outgoing edge.")1581);1582return 1;1583}1584// check number of connections1585if (currentJunction->getGNEConnections().empty()) {1586// open warning dialog1587GNEWarningBasicDialog(GNEApp,1588TL("TLS cannot be created"),1589TL("Traffic Light cannot be created because junction"),1590TL("must have at least one connection.")1591);1592return 1;1593}1594// check uncontrolled connections1595bool connectionControlled = false;1596for (const auto& connection : currentJunction->getGNEConnections()) {1597if (!connection->getNBEdgeConnection().uncontrolled) {1598connectionControlled = true;1599}1600}1601if (!connectionControlled) {1602// open warning dialog1603GNEWarningBasicDialog(GNEApp,1604TL("TLS cannot be created"),1605TL("Traffic Light cannot be created because junction"),1606TL("must have at least one controlled connection.")1607);1608return 1;1609}1610// all checks ok, then create TLS in junction1611createTLS(currentJunction);1612// edit junction1613myTLSEditorParent->editJunction(currentJunction);1614// switch to the last program1615myProgramComboBox->setCurrentItem(myProgramComboBox->getNumItems() - 1, TRUE);1616myTLSEditorParent->updateModules();1617return 1;1618}161916201621long1622GNETLSEditorFrame::TLSPrograms::onCmdDelete(FXObject*, FXSelector, void*) {1623// get current junction1624GNEJunction* currentJunction = myTLSEditorParent->myTLSJunction->getCurrentJunction();1625// get current edited tlDef1626NBTrafficLightDefinition* tlDef = myTLSEditorParent->myTLSPrograms->getCurrentTLSPrograms();1627// check if remove entire TLS or only one program1628const bool changeJunctionType = (myTLSEditorParent->myTLSPrograms->getNumberOfPrograms() == 1);1629// abort because onCmdOk assumes we wish to save an edited definition1630discardChanges(false);1631// check if change junction type1632if (changeJunctionType) {1633currentJunction->setAttribute(SUMO_ATTR_TYPE, toString(SumoXMLNodeType::PRIORITY), myTLSEditorParent->getViewNet()->getUndoList());1634} else {1635// just remove TLDef1636myTLSEditorParent->getViewNet()->getUndoList()->add(new GNEChange_TLS(currentJunction, tlDef, false), true);1637// edit junction again1638myTLSEditorParent->editJunction(currentJunction);1639}1640myTLSEditorParent->updateModules();1641return 1;1642}164316441645long1646GNETLSEditorFrame::TLSPrograms::onCmdResetCurrentProgram(FXObject*, FXSelector, void*) {1647// obtain junction and old definitions1648GNEJunction* junction = myTLSEditorParent->myTLSJunction->getCurrentJunction();1649NBTrafficLightDefinition* oldDef = myTLSEditorParent->myTLSPrograms->getCurrentTLSPrograms();1650const std::string programID = oldDef->getProgramID();1651// discard changes1652discardChanges(false);1653// begin undo1654myTLSEditorParent->getViewNet()->getUndoList()->begin(GUIIcon::MODETLS, TL("reset current program"));1655// remove old definition1656myTLSEditorParent->getViewNet()->getUndoList()->add(new GNEChange_TLS(junction, oldDef, false), true);1657// create new definition, and add it1658NBOwnTLDef* newDef = new NBOwnTLDef(oldDef->getID(), oldDef->getNodes(), oldDef->getOffset(), oldDef->getType());1659newDef->setProgramID(programID);1660myTLSEditorParent->getViewNet()->getUndoList()->add(new GNEChange_TLS(junction, newDef, true, true), true);1661// set old index1662// end undo1663myTLSEditorParent->getViewNet()->getUndoList()->end();1664// inspect junction again1665myTLSEditorParent->editJunction(junction);1666// switch to programID1667int index = -1;1668for (int i = 0; i < myProgramComboBox->getNumItems(); i++) {1669if (myProgramComboBox->getItemText(i) == programID) {1670index = i;1671}1672}1673if (index != -1) {1674myProgramComboBox->setCurrentItem(index, TRUE);1675}1676myTLSEditorParent->updateModules();1677return 1;1678}167916801681long1682GNETLSEditorFrame::TLSPrograms::onCmdResetAll(FXObject*, FXSelector, void*) {1683// obtain junction and old definitions1684GNEJunction* junction = myTLSEditorParent->myTLSJunction->getCurrentJunction();1685NBTrafficLightDefinition* oldDef = myTLSEditorParent->myTLSPrograms->getCurrentTLSPrograms();1686// get a list of all affected nodes1687std::vector<GNEJunction*> TLSJunctions;1688for (const auto& TLSNode : oldDef->getNodes()) {1689TLSJunctions.push_back(myTLSEditorParent->getViewNet()->getNet()->getAttributeCarriers()->retrieveJunction(TLSNode->getID()));1690}1691// discard all previous changes1692discardChanges(false);1693// begin undo1694myTLSEditorParent->getViewNet()->getUndoList()->begin(GUIIcon::MODETLS, TL("reset TLS"));1695// set junction as priority (this will also remove all program, see GNEJunction::setJunctionType)1696for (const auto& TLSJunction : TLSJunctions) {1697TLSJunction->setAttribute(SUMO_ATTR_TYPE, toString(SumoXMLNodeType::PRIORITY), myTLSEditorParent->getViewNet()->getUndoList());1698}1699// create TLS in junction1700createTLS(junction);1701// set TLS in all other junctions1702for (const auto& TLSJunction : TLSJunctions) {1703if (TLSJunction != junction) {1704TLSJunction->setAttribute(SUMO_ATTR_TYPE, TLSJunction->getAttribute(SUMO_ATTR_TYPE), myTLSEditorParent->getViewNet()->getUndoList());1705TLSJunction->setAttribute(SUMO_ATTR_TLID, TLSJunction->getAttribute(SUMO_ATTR_TLID), myTLSEditorParent->getViewNet()->getUndoList());1706}1707}1708// end undo1709myTLSEditorParent->getViewNet()->getUndoList()->end();1710// edit junction1711myTLSEditorParent->editJunction(junction);1712return 1;1713}171417151716long1717GNETLSEditorFrame::TLSPrograms::onCmdDefSwitchTLSProgram(FXObject*, FXSelector, void*) {1718// check if program is valid (user may input arbitrary text)1719bool found = false;1720for (const auto& TLSPrograms : myTLSPrograms) {1721if (TLSPrograms->getProgramID() == myProgramComboBox->getText().text()) {1722found = true;1723break;1724}1725}1726if (!found) {1727// reset field to a valid program1728myProgramComboBox->setText(myTLSPrograms.front()->getProgramID().c_str());1729}1730switchProgram();1731return 1;1732}173317341735long1736GNETLSEditorFrame::TLSPrograms::onCmdSaveChanges(FXObject*, FXSelector, void*) {1737// get junction copy1738const auto currentJunction = myTLSEditorParent->myTLSJunction->getCurrentJunction();1739// get current program1740const auto currentProgram = myProgramComboBox->getCurrentItem();1741// check that junction is valid1742if (currentJunction != nullptr) {1743const auto oldDefinition = getCurrentTLSPrograms();1744std::vector<NBNode*> nodes = oldDefinition->getNodes();1745GNEUndoList* undoList = myTLSEditorParent->getViewNet()->getUndoList();1746for (const auto& node : nodes) {1747GNEJunction* junction = myTLSEditorParent->getViewNet()->getNet()->getAttributeCarriers()->retrieveJunction(node->getID());1748undoList->add(new GNEChange_TLS(junction, oldDefinition, false), true);1749undoList->add(new GNEChange_TLS(junction, myTLSEditorParent->myEditedDef, true), true);1750// synchronize crossing tl-indices in case they were changed (via onCmdCleanStates)1751for (const auto& gc : junction->getGNECrossings()) {1752NBNode::Crossing* c = gc->getNBCrossing();1753if (c) {1754gc->setAttribute(SUMO_ATTR_TLLINKINDEX, toString(c->tlLinkIndex), undoList);1755gc->setAttribute(SUMO_ATTR_TLLINKINDEX2, toString(c->tlLinkIndex2), undoList);1756}1757}175817591760}1761// end change1762myTLSEditorParent->getViewNet()->getUndoList()->end();1763// mark as saved1764myHaveModifications = false;1765// reset myEditedDef (because is already in eine undo-list)1766myTLSEditorParent->myEditedDef = nullptr;1767myTLSEditorParent->cleanup();1768myTLSEditorParent->getViewNet()->updateViewNet();1769// edit junction again1770myTLSEditorParent->editJunction(currentJunction);1771// change program1772myProgramComboBox->setCurrentItem(currentProgram, TRUE);1773} else {1774// discard changes inspecting junction again1775discardChanges(true);1776}1777myTLSEditorParent->updateModules();1778return 1;1779}178017811782long1783GNETLSEditorFrame::TLSPrograms::onCmdDiscardChanges(FXObject*, FXSelector, void*) {1784// discard changes inspecting junction again1785discardChanges(true);1786return 1;1787}178817891790void1791GNETLSEditorFrame::TLSPrograms::createTLS(GNEJunction* junction) {1792// get current TLS program id1793const auto currentTLS = getCurrentTLSProgramID();1794// check conditions1795if (junction == nullptr) {1796throw ProcessError("junction cannot be null");1797} else if (junction->getAttribute(SUMO_ATTR_TYPE) != toString(SumoXMLNodeType::TRAFFIC_LIGHT)) {1798// set junction as TLS1799junction->setAttribute(SUMO_ATTR_TYPE, toString(SumoXMLNodeType::TRAFFIC_LIGHT), myTLSEditorParent->getViewNet()->getUndoList());1800} else if (junction->getNBNode()->isTLControlled()) {1801// use existing traffic light as template for type, signal groups, controlled nodes etc1802NBTrafficLightDefinition* tpl = nullptr;1803for (const auto& TLS : junction->getNBNode()->getControllingTLS()) {1804if (TLS->getProgramID() == currentTLS) {1805tpl = TLS;1806}1807}1808// if template is empty, use first TLS1809if (tpl == nullptr) {1810tpl = *junction->getNBNode()->getControllingTLS().begin();1811}1812// create new logic1813NBTrafficLightLogic* newLogic = tpl->compute(OptionsCont::getOptions());1814// create new TLDef1815NBLoadedSUMOTLDef* newDef = new NBLoadedSUMOTLDef(*tpl, *newLogic);1816NBTrafficLightLogicCont& tllCont = myTLSEditorParent->getViewNet()->getNet()->getTLLogicCont();1817newDef->setProgramID(tllCont.getNextProgramID(newDef->getID()));1818// remove new logic1819delete newLogic;1820// add it using GNEChange_TLS1821myTLSEditorParent->getViewNet()->getUndoList()->begin(GUIIcon::MODETLS, TLF("duplicate program '%' of traffic light '%'", tpl->getProgramID(), tpl->getID()));1822for (NBNode* node : newDef->getNodes()) {1823GNEJunction* j = myTLSEditorParent->getViewNet()->getNet()->getAttributeCarriers()->retrieveJunction(node->getID());1824// not forcing insertion because we already ensured a new id and multiple junctions will attempt insertion1825myTLSEditorParent->getViewNet()->getUndoList()->add(new GNEChange_TLS(j, newDef, true, false), true);1826}1827myTLSEditorParent->getViewNet()->getUndoList()->end();1828} else {1829// for some reason the traffic light was not built, try again1830myTLSEditorParent->getViewNet()->getUndoList()->add(new GNEChange_TLS(junction, nullptr, true, true), true);1831}1832}183318341835bool1836GNETLSEditorFrame::TLSPrograms::switchProgram() {1837if (myTLSEditorParent->myTLSJunction->getCurrentJunction() == nullptr) {1838throw ProcessError("Junction cannot be NULL");1839} else {1840// reset save flag1841myHaveModifications = false;1842// get current definition1843NBTrafficLightDefinition* tlDef = getCurrentTLSPrograms();1844// logic may not have been recomputed yet. recompute to be sure1845NBTrafficLightLogicCont& tllCont = myTLSEditorParent->getViewNet()->getNet()->getTLLogicCont();1846// compute junction1847myTLSEditorParent->getViewNet()->getNet()->computeJunction(myTLSEditorParent->myTLSJunction->getCurrentJunction());1848// obtain TrafficLight logic vinculated with tlDef1849NBTrafficLightLogic* tllogic = tllCont.getLogic(tlDef->getID(), tlDef->getProgramID());1850// check that tllLogic exist1851if (tllogic != nullptr) {1852// now we can be sure that the tlDef is up to date (i.e. re-guessed)1853myTLSEditorParent->buildInternalLanes(tlDef);1854// create working duplicate from original def1855delete myTLSEditorParent->myEditedDef;1856myTLSEditorParent->myEditedDef = new NBLoadedSUMOTLDef(*tlDef, *tllogic);1857// set values1858myTLSEditorParent->myTLSAttributes->setOffset(myTLSEditorParent->myEditedDef->getLogic()->getOffset());1859myTLSEditorParent->myTLSAttributes->setParameters(myTLSEditorParent->myEditedDef->getLogic()->getParametersStr());1860// init phaseTable with the new TLS1861myTLSEditorParent->myTLSPhases->initPhaseTable();1862} else {1863// tlDef has no valid logic (probably because id does not control any links1864discardChanges(false);1865myTLSEditorParent->getViewNet()->setStatusBarText(TL("Traffic Light does not control any links"));1866return false;1867}1868}1869return true;1870}18711872// ---------------------------------------------------------------------------1873// GNETLSEditorFrame::TLSPhases - methods1874// ---------------------------------------------------------------------------18751876GNETLSEditorFrame::TLSPhases::TLSPhases(GNETLSEditorFrame* TLSEditorParent) :1877GNEGroupBoxModule(TLSEditorParent, TL("Phases"), GNEGroupBoxModule::Options::COLLAPSIBLE | GNEGroupBoxModule::Options::EXTENSIBLE),1878myTLSEditorParent(TLSEditorParent) {1879// create GNETLSTable1880myPhaseTable = new GNETLSTable(this);1881// hide phase table1882myPhaseTable->hide();1883FXHorizontalFrame* phaseButtons = new FXHorizontalFrame(getCollapsableFrame(), GUIDesignAuxiliarHorizontalFrameUniform);1884FXVerticalFrame* col1 = new FXVerticalFrame(phaseButtons, GUIDesignAuxiliarHorizontalFrame); // left button columm1885FXVerticalFrame* col2 = new FXVerticalFrame(phaseButtons, GUIDesignAuxiliarHorizontalFrame); // right button column1886// create cleanup states button1887myCleanStatesButton = new MFXButtonTooltip(col1, TLSEditorParent->getViewNet()->getViewParent()->getGNEAppWindows()->getStaticTooltipMenu(),1888TL("Clean States") + std::string("\t") +1889TL("Clean unused states from all phase") + std::string("\t") +1890TL("Clean unused states from all phase. (Not allowed for multiple programs)"),1891nullptr, this, MID_GNE_TLSFRAME_PHASES_CLEANUP, GUIDesignButton);1892myCleanStatesButton->disable();1893// add unused states button1894myAddStates = new MFXButtonTooltip(col2, TLSEditorParent->getViewNet()->getViewParent()->getGNEAppWindows()->getStaticTooltipMenu(),1895TL("Add States") + std::string("\t") +1896TL("Extend the state vector for all phases by one entry") + std::string("\t") +1897TL("Extend the state vector for all phases by one entry. (Unused until a connection or crossing is assigned to the new index)"),1898nullptr, this, MID_GNE_TLSFRAME_PHASES_ADDUNUSED, GUIDesignButton);1899myAddStates->disable();1900// group states button1901myGroupSignalsButton = new MFXButtonTooltip(col1, TLSEditorParent->getViewNet()->getViewParent()->getGNEAppWindows()->getStaticTooltipMenu(),1902TL("Group Sig.") + std::string("\t") +1903TL("Shorten state definition by letting connections with the same signal states use the same index") + std::string("\t") +1904TL("Shorten state definition by letting connections with the same signal states use the same index. (Not allowed for multiple programs)"),1905nullptr, this, MID_GNE_TLSFRAME_PHASES_GROUPSTATES, GUIDesignButton);1906myGroupSignalsButton->disable();1907// ungroup states button1908myUngroupSignalsButton = new MFXButtonTooltip(col2, TLSEditorParent->getViewNet()->getViewParent()->getGNEAppWindows()->getStaticTooltipMenu(),1909TL("Ungroup Sig.") + std::string("\t") +1910TL("Let every connection use a distinct index (reverse state grouping)") + std::string("\t") +1911TL("Let every connection use a distinct index (reverse state grouping). (Not allowed for multiple programs)"),1912nullptr, this, MID_GNE_TLSFRAME_PHASES_UNGROUPSTATES, GUIDesignButton);1913myUngroupSignalsButton->disable();1914// show TLSFile1915show();1916}191719181919GNETLSEditorFrame::TLSPhases::~TLSPhases() {1920}192119221923void1924GNETLSEditorFrame::TLSPhases::updateTLSPhases() {1925if (myTLSEditorParent->myTLSAttributes->isSetDetectorsToggleButtonEnabled()) {1926// selecting E1, disable buttons1927myPhaseTable->disable();1928myCleanStatesButton->disable();1929myAddStates->disable();1930myGroupSignalsButton->disable();1931myUngroupSignalsButton->disable();1932} else if (myTLSEditorParent->myTLSJunction->isJoiningJunctions()) {1933// joining TLSs, disable buttons1934myPhaseTable->disable();1935myCleanStatesButton->disable();1936myAddStates->disable();1937myGroupSignalsButton->disable();1938myUngroupSignalsButton->disable();1939myUngroupSignalsButton->disable();1940} else if (myTLSEditorParent->myTLSPrograms->getNumberOfPrograms() == 0) {1941// no TLSs, disable buttons1942myPhaseTable->disable();1943myCleanStatesButton->disable();1944myAddStates->disable();1945myGroupSignalsButton->disable();1946myUngroupSignalsButton->disable();1947} else if (myTLSEditorParent->myEditedDef == nullptr) {1948// no edited definition, disable buttons1949myPhaseTable->disable();1950myCleanStatesButton->disable();1951myAddStates->disable();1952myGroupSignalsButton->disable();1953myUngroupSignalsButton->disable();1954} else {1955myPhaseTable->enable();1956myCleanStatesButton->enable();1957myAddStates->enable();1958myGroupSignalsButton->enable();1959if (myTLSEditorParent->myEditedDef->usingSignalGroups()) {1960myUngroupSignalsButton->enable();1961} else {1962myUngroupSignalsButton->disable();1963}1964}1965}196619671968void1969GNETLSEditorFrame::TLSPhases::showTLSPhases() {1970show();1971}197219731974void1975GNETLSEditorFrame::TLSPhases::hideTLSPhases() {1976hide();1977}197819791980GNETLSEditorFrame*1981GNETLSEditorFrame::TLSPhases::getTLSEditorParent() const {1982return myTLSEditorParent;1983}198419851986GNETLSTable*1987GNETLSEditorFrame::TLSPhases::getPhaseTable() const {1988return myPhaseTable;1989}199019911992void1993GNETLSEditorFrame::TLSPhases::initPhaseTable() {1994// first clear table1995clearPhaseTable();1996if (myTLSEditorParent->myTLSPrograms->getNumberOfPrograms() > 0) {1997if (myTLSEditorParent->myEditedDef->getType() == TrafficLightType::STATIC) {1998initStaticPhaseTable();1999} else if (myTLSEditorParent->myEditedDef->getType() == TrafficLightType::ACTUATED) {2000initActuatedPhaseTable();2001} else if (myTLSEditorParent->myEditedDef->getType() == TrafficLightType::DELAYBASED) {2002initDelayBasePhaseTable();2003} else if (myTLSEditorParent->myEditedDef->getType() == TrafficLightType::NEMA) {2004initNEMAPhaseTable();2005}2006// select first element (by default)2007myPhaseTable->selectRow(0);2008// recalc width and show2009myPhaseTable->recalcTableWidth();2010myPhaseTable->show();2011} else {2012myPhaseTable->hide();2013}2014update();2015}201620172018void2019GNETLSEditorFrame::TLSPhases::clearPhaseTable() {2020myPhaseTable->clearTable();2021}202220232024bool2025GNETLSEditorFrame::TLSPhases::changePhaseValue(const int col, const int row, const std::string& value) {2026// Declare columns2027int colDuration = 1;2028int colState = -1;2029int colNext = -1;2030int colName = -1;2031int colMinDur = -1;2032int colMaxDur = -1;2033int colEarliestEnd = -1;2034int colLatestEnd = -1;2035int colVehExt = -1;2036int colYellow = -1;2037int colRed = -1;2038// set columns depending of traffic light type2039if (myTLSEditorParent->myEditedDef->getType() == TrafficLightType::STATIC) {2040colState = 2;2041colNext = 3;2042colName = 4;2043} else if (myTLSEditorParent->myEditedDef->getType() == TrafficLightType::ACTUATED) {2044colMinDur = 2;2045colMaxDur = 3;2046colState = 4;2047colEarliestEnd = 5;2048colLatestEnd = 6;2049colNext = 7;2050colName = 8;2051} else if (myTLSEditorParent->myEditedDef->getType() == TrafficLightType::DELAYBASED) {2052colMinDur = 2;2053colMaxDur = 3;2054colState = 4;2055colNext = 5;2056colName = 6;2057} else if (myTLSEditorParent->myEditedDef->getType() == TrafficLightType::NEMA) {2058colMinDur = 2;2059colMaxDur = 3;2060colState = 4;2061colVehExt = 5;2062colYellow = 6;2063colRed = 7;2064colNext = 8;2065colName = 9;2066}2067// check column2068if (col == colDuration) {2069return setDuration(col, row, value);2070} else if (col == colState) {2071return setState(col, row, value);2072} else if (col == colNext) {2073return setNext(row, value);2074} else if (col == colName) {2075return setName(row, value);2076} else if (col == colMinDur) {2077return setMinDur(row, value);2078} else if (col == colMaxDur) {2079return setMaxDur(row, value);2080} else if (col == colEarliestEnd) {2081return setEarliestEnd(row, value);2082} else if (col == colLatestEnd) {2083return setLatestEnd(row, value);2084} else if (col == colVehExt) {2085return setVehExt(row, value);2086} else if (col == colYellow) {2087return setYellow(row, value);2088} else if (col == colRed) {2089return setRed(row, value);2090} else {2091throw ProcessError(TL("invalid column"));2092}2093}209420952096void2097GNETLSEditorFrame::TLSPhases::addPhase(const int row, const char c) {2098// mark TLS as modified2099myTLSEditorParent->myTLSPrograms->markAsModified();2100// build default phase2101const int newIndex = buildDefaultPhase(row);2102// check if override state2103switch (c) {2104case 'r':2105case 'y':2106case 'g':2107case 'G':2108myTLSEditorParent->myEditedDef->getLogic()->overrideState(newIndex, c);2109break;2110default:2111break;2112}2113// int phase table again2114initPhaseTable();2115// mark new row as selected2116myPhaseTable->selectRow(newIndex);2117// set focus in table2118getPhaseTable()->setFocus();2119}212021212122void2123GNETLSEditorFrame::TLSPhases::duplicatePhase(const int row) {2124// mark TLS as modified2125myTLSEditorParent->myTLSPrograms->markAsModified();2126// build default phase2127const int newIndex = buildDefaultPhase(row);2128// coply old phase in the new phase2129myTLSEditorParent->myEditedDef->getLogic()->copyPhase(row, row + 1);2130// int phase table again2131initPhaseTable();2132// mark new row as selected2133myPhaseTable->selectRow(newIndex);2134// set focus in table2135getPhaseTable()->setFocus();2136}213721382139void2140GNETLSEditorFrame::TLSPhases::removePhase(const int row) {2141// mark TLS ad modified2142myTLSEditorParent->myTLSPrograms->markAsModified();2143// calculate new row2144const auto newRow = MAX2(0, (row - 1));2145// delete selected row2146myTLSEditorParent->myEditedDef->getLogic()->deletePhase(row);2147// int phase table again2148initPhaseTable();2149// mark new row as selected2150myPhaseTable->selectRow(newRow);2151// set focus in table2152getPhaseTable()->setFocus();2153}215421552156void2157GNETLSEditorFrame::TLSPhases::movePhaseUp(const int row) {2158// mark TLS ad modified2159myTLSEditorParent->myTLSPrograms->markAsModified();2160// delete selected row2161if (row == 0) {2162myTLSEditorParent->myEditedDef->getLogic()->swapfirstPhase();2163} else {2164myTLSEditorParent->myEditedDef->getLogic()->swapPhase(row, row - 1);2165}2166// int phase table again2167initPhaseTable();2168// mark new row as selected2169if (row == 0) {2170myPhaseTable->selectRow((int)myTLSEditorParent->myEditedDef->getLogic()->getPhases().size() - 1);2171} else {2172myPhaseTable->selectRow(row - 1);2173}2174// set focus in table2175getPhaseTable()->setFocus();2176}217721782179void2180GNETLSEditorFrame::TLSPhases::movePhaseDown(const int row) {2181// mark TLS ad modified2182myTLSEditorParent->myTLSPrograms->markAsModified();2183// delete selected row2184if (row == (int)myTLSEditorParent->myEditedDef->getLogic()->getPhases().size() - 1) {2185myTLSEditorParent->myEditedDef->getLogic()->swaplastPhase();2186} else {2187myTLSEditorParent->myEditedDef->getLogic()->swapPhase(row, row + 1);2188}2189// int phase table again2190initPhaseTable();2191// mark new row as selected2192if (row == (int)myTLSEditorParent->myEditedDef->getLogic()->getPhases().size() - 1) {2193myPhaseTable->selectRow(0);2194} else {2195myPhaseTable->selectRow(row + 1);2196}2197// set focus in table2198getPhaseTable()->setFocus();2199}220022012202void2203GNETLSEditorFrame::TLSPhases::updateTLSColoring() {2204// get phase2205const auto& phase = myTLSEditorParent->getPhase(myPhaseTable->getCurrentSelectedRow());2206// need not hold since links could have been deleted somewhere else and indices may be reused2207for (const auto& internalLane : myTLSEditorParent->myInternalLanes) {2208int tlIndex = internalLane.first;2209std::vector<GNEInternalLane*> lanes = internalLane.second;2210LinkState state = LINKSTATE_DEADEND;2211if (tlIndex >= 0 && tlIndex < (int)phase.state.size()) {2212state = (LinkState)phase.state[tlIndex];2213}2214for (const auto& lane : lanes) {2215lane->setLinkState(state);2216}2217}2218// update view net (for coloring)2219myTLSEditorParent->getViewNet()->updateViewNet();2220}222122222223long2224GNETLSEditorFrame::TLSPhases::onCmdCleanStates(FXObject*, FXSelector, void*) {2225if (myTLSEditorParent->myEditedDef->cleanupStates()) {2226myTLSEditorParent->myTLSPrograms->markAsModified();2227}2228myTLSEditorParent->buildInternalLanes(myTLSEditorParent->myEditedDef);2229initPhaseTable();2230myPhaseTable->setFocus();2231myTLSEditorParent->myTLSPrograms->markAsModified();2232myTLSEditorParent->updateModules();2233return 1;2234}223522362237long2238GNETLSEditorFrame::TLSPhases::onCmdAddUnusedStates(FXObject*, FXSelector, void*) {2239myTLSEditorParent->myEditedDef->getLogic()->setStateLength(myTLSEditorParent->myEditedDef->getLogic()->getNumLinks() + 1);2240myTLSEditorParent->myTLSPrograms->markAsModified();2241initPhaseTable();2242myPhaseTable->setFocus();2243myTLSEditorParent->updateModules();2244return 1;2245}224622472248long2249GNETLSEditorFrame::TLSPhases::onCmdGroupStates(FXObject*, FXSelector, void*) {2250myTLSEditorParent->myEditedDef->groupSignals();2251myTLSEditorParent->myTLSPrograms->markAsModified();2252myTLSEditorParent->buildInternalLanes(myTLSEditorParent->myEditedDef);2253initPhaseTable();2254myPhaseTable->setFocus();2255myTLSEditorParent->updateModules();2256return 1;2257}225822592260long2261GNETLSEditorFrame::TLSPhases::onCmdUngroupStates(FXObject*, FXSelector, void*) {2262myTLSEditorParent->myEditedDef->setParticipantsInformation();2263myTLSEditorParent->myEditedDef->ungroupSignals();2264myTLSEditorParent->myTLSPrograms->markAsModified();2265myTLSEditorParent->buildInternalLanes(myTLSEditorParent->myEditedDef);2266initPhaseTable();2267myPhaseTable->setFocus();2268myTLSEditorParent->updateModules();2269return 1;2270}227122722273void2274GNETLSEditorFrame::TLSPhases::initStaticPhaseTable() {2275// declare constants for columns2276const int colDuration = 1;2277const int colState = 2;2278const int colNext = 3;2279const int colName = 4;2280// get phases2281const auto& phases = myTLSEditorParent->myEditedDef->getLogic()->getPhases();2282// adjust table2283myPhaseTable->setTableSize("sup-midtb", (int)phases.size());2284// fill rows2285for (int row = 0; row < (int)phases.size(); row++) {2286myPhaseTable->setItemText(row, colDuration, getSteps2Time(phases.at(row).duration).c_str());2287myPhaseTable->setItemText(row, colState, phases.at(row).state.c_str());2288myPhaseTable->setItemText(row, colNext, phases.at(row).next.size() > 0 ? toString(phases.at(row).next).c_str() : "");2289myPhaseTable->setItemText(row, colName, phases.at(row).name.c_str());2290}2291// set columns2292myPhaseTable->setColumnLabelTop(colDuration, "dur");2293myPhaseTable->setColumnLabelTop(colState, "state");2294myPhaseTable->setColumnLabelTop(colNext, "next");2295myPhaseTable->setColumnLabelTop(colName, "name");2296// set bot labels2297updateCycleDuration(colDuration);2298updateStateSize(colState);2299// set focus2300myPhaseTable->setFocus();2301}230223032304void2305GNETLSEditorFrame::TLSPhases::initActuatedPhaseTable() {2306// declare constants for columns2307const int colDuration = 1;2308const int colMinDur = 2;2309const int colMaxDur = 3;2310const int colState = 4;2311const int colEarliestEnd = 5;2312const int colLatestEnd = 6;2313const int colNext = 7;2314const int colName = 8;2315// get phases2316const auto& phases = myTLSEditorParent->myEditedDef->getLogic()->getPhases();2317// adjust table2318myPhaseTable->setTableSize("suffpff-midtb", (int)phases.size());2319// fill rows2320for (int row = 0; row < (int)phases.size(); row++) {2321myPhaseTable->setItemText(row, colDuration, getSteps2Time(phases.at(row).duration).c_str());2322myPhaseTable->setItemText(row, colMinDur, varDurString(phases.at(row).minDur).c_str());2323myPhaseTable->setItemText(row, colMaxDur, varDurString(phases.at(row).maxDur).c_str());2324myPhaseTable->setItemText(row, colState, phases.at(row).state.c_str());2325myPhaseTable->setItemText(row, colEarliestEnd, varDurString(phases.at(row).earliestEnd).c_str());2326myPhaseTable->setItemText(row, colLatestEnd, varDurString(phases.at(row).latestEnd).c_str());2327myPhaseTable->setItemText(row, colNext, phases.at(row).next.size() > 0 ? toString(phases.at(row).next).c_str() : "");2328myPhaseTable->setItemText(row, colName, phases.at(row).name.c_str());2329}2330// set columns2331myPhaseTable->setColumnLabelTop(colDuration, "dur");2332myPhaseTable->setColumnLabelTop(colMinDur, "min");2333myPhaseTable->setColumnLabelTop(colMaxDur, "max");2334myPhaseTable->setColumnLabelTop(colEarliestEnd, "ear.end", "earlyEnd");2335myPhaseTable->setColumnLabelTop(colLatestEnd, "lat.end", "latestEnd");2336myPhaseTable->setColumnLabelTop(colState, "state");2337myPhaseTable->setColumnLabelTop(colNext, "next");2338myPhaseTable->setColumnLabelTop(colName, "name");2339// set bot labels2340updateCycleDuration(colDuration);2341updateStateSize(colState);2342// set focus2343myPhaseTable->setFocus();2344}234523462347void2348GNETLSEditorFrame::TLSPhases::initDelayBasePhaseTable() {2349// declare constants for columns2350const int colDuration = 1;2351const int colMinDur = 2;2352const int colMaxDur = 3;2353const int colState = 4;2354const int colNext = 5;2355const int colName = 6;2356// get phases2357const auto& phases = myTLSEditorParent->myEditedDef->getLogic()->getPhases();2358// adjust table2359myPhaseTable->setTableSize("suffp-midtb", (int)phases.size());2360// fill rows2361for (int row = 0; row < (int)phases.size(); row++) {2362myPhaseTable->setItemText(row, colDuration, getSteps2Time(phases.at(row).duration).c_str());2363myPhaseTable->setItemText(row, colMinDur, varDurString(phases.at(row).minDur).c_str());2364myPhaseTable->setItemText(row, colMaxDur, varDurString(phases.at(row).maxDur).c_str());2365myPhaseTable->setItemText(row, colState, phases.at(row).state.c_str());2366myPhaseTable->setItemText(row, colNext, phases.at(row).next.size() > 0 ? toString(phases.at(row).next).c_str() : "");2367myPhaseTable->setItemText(row, colName, phases.at(row).name.c_str());2368}2369// set columns2370myPhaseTable->setColumnLabelTop(colDuration, "dur");2371myPhaseTable->setColumnLabelTop(colMinDur, "min");2372myPhaseTable->setColumnLabelTop(colMaxDur, "max");2373myPhaseTable->setColumnLabelTop(colState, "state");2374myPhaseTable->setColumnLabelTop(colNext, "next");2375myPhaseTable->setColumnLabelTop(colName, "name");2376// set bot labels2377updateCycleDuration(colDuration);2378updateStateSize(colState);2379// set focus2380myPhaseTable->setFocus();2381}238223832384void2385GNETLSEditorFrame::TLSPhases::initNEMAPhaseTable() {2386// declare constants for columns2387const int colDuration = 1;2388const int colMinDur = 2;2389const int colMaxDur = 3;2390const int colState = 4;2391const int colVehExt = 5;2392const int colYellow = 6;2393const int colRed = 7;2394const int colNext = 8;2395const int colName = 9;2396// get phases2397const auto& phases = myTLSEditorParent->myEditedDef->getLogic()->getPhases();2398// adjust table2399myPhaseTable->setTableSize("suffpfff-midtb", (int)phases.size());2400// fill rows2401for (int row = 0; row < (int)phases.size(); row++) {2402myPhaseTable->setItemText(row, colDuration, getSteps2Time(phases.at(row).duration).c_str());2403myPhaseTable->setItemText(row, colMinDur, varDurString(phases.at(row).minDur).c_str());2404myPhaseTable->setItemText(row, colMaxDur, varDurString(phases.at(row).maxDur).c_str());2405myPhaseTable->setItemText(row, colState, phases.at(row).state.c_str());2406myPhaseTable->setItemText(row, colVehExt, varDurString(phases.at(row).vehExt).c_str());2407myPhaseTable->setItemText(row, colYellow, varDurString(phases.at(row).yellow).c_str());2408myPhaseTable->setItemText(row, colRed, varDurString(phases.at(row).red).c_str());2409myPhaseTable->setItemText(row, colNext, phases.at(row).next.size() > 0 ? toString(phases.at(row).next).c_str() : "");2410myPhaseTable->setItemText(row, colName, phases.at(row).name.c_str());2411}2412// set columns2413myPhaseTable->setColumnLabelTop(colDuration, "dur");2414myPhaseTable->setColumnLabelTop(colMinDur, "min");2415myPhaseTable->setColumnLabelTop(colMaxDur, "max");2416myPhaseTable->setColumnLabelTop(colState, "state");2417myPhaseTable->setColumnLabelTop(colVehExt, "vehExt", "vehicle extension");2418myPhaseTable->setColumnLabelTop(colYellow, "yellow");2419myPhaseTable->setColumnLabelTop(colRed, "red");2420myPhaseTable->setColumnLabelTop(colNext, "next");2421myPhaseTable->setColumnLabelTop(colName, "name");2422// set bot labels2423updateCycleDuration(colDuration);2424updateStateSize(colState);2425// set focus2426myPhaseTable->setFocus();2427}242824292430int2431GNETLSEditorFrame::TLSPhases::buildDefaultPhase(const int row) {2432// get option container2433const auto& neteditOptions = OptionsCont::getOptions();2434// check if TLS is static2435const bool TLSStatic = (myTLSEditorParent->myEditedDef->getType() == TrafficLightType::STATIC);2436const bool NEMA = (myTLSEditorParent->myEditedDef->getType() == TrafficLightType::NEMA);2437// calculate new index2438const int newIndex = row + 1;2439// duplicate current row2440auto duration = getSUMOTime(myPhaseTable->getItemText(row, 1));2441const auto oldState = myPhaseTable->getItemText(row, TLSStatic ? 2 : 4);2442auto state = oldState;2443// update crossingINdices2444std::set<int> crossingIndices;2445for (const auto& node : myTLSEditorParent->myEditedDef->getNodes()) {2446for (const auto& crossing : node->getCrossings()) {2447crossingIndices.insert(crossing->tlLinkIndex);2448crossingIndices.insert(crossing->tlLinkIndex2);2449}2450}2451// smart adapations for new state2452bool haveGreen = false;2453bool haveYellow = false;2454for (const auto& linkStateChar : state) {2455if ((linkStateChar == LINKSTATE_TL_GREEN_MAJOR) || (linkStateChar == LINKSTATE_TL_GREEN_MINOR)) {2456haveGreen = true;2457} else if ((linkStateChar == LINKSTATE_TL_YELLOW_MAJOR) || (linkStateChar == LINKSTATE_TL_YELLOW_MINOR)) {2458haveYellow = true;2459}2460}2461if (haveGreen && haveYellow) {2462// guess left-mover state2463duration = TIME2STEPS(neteditOptions.getInt("tls.left-green.time"));2464for (int i = 0; i < (int)state.size(); i++) {2465if ((state[i] == LINKSTATE_TL_YELLOW_MAJOR) || (state[i] == LINKSTATE_TL_YELLOW_MINOR)) {2466state[i] = LINKSTATE_TL_RED;2467} else if (state[i] == LINKSTATE_TL_GREEN_MINOR) {2468state[i] = LINKSTATE_TL_GREEN_MAJOR;2469}2470}2471} else if (haveGreen) {2472// guess yellow state2473myTLSEditorParent->myEditedDef->setParticipantsInformation();2474duration = TIME2STEPS(myTLSEditorParent->myEditedDef->computeBrakingTime(neteditOptions.getFloat("tls.yellow.min-decel")));2475for (int i = 0; i < (int)state.size(); i++) {2476if ((state[i] == LINKSTATE_TL_GREEN_MAJOR) || (state[i] == LINKSTATE_TL_GREEN_MINOR)) {2477if (crossingIndices.count(i) == 0) {2478state[i] = LINKSTATE_TL_YELLOW_MINOR;2479} else {2480state[i] = LINKSTATE_TL_RED;2481}2482}2483}2484} else if (haveYellow) {2485duration = TIME2STEPS(neteditOptions.isDefault("tls.allred.time") ? 2 : neteditOptions.getInt("tls.allred.time"));2486// guess all-red state2487for (int i = 0; i < (int)state.size(); i++) {2488if ((state[i] == LINKSTATE_TL_YELLOW_MAJOR) || (state[i] == LINKSTATE_TL_YELLOW_MINOR)) {2489state[i] = LINKSTATE_TL_RED;2490}2491}2492}2493// fix continuous green states2494const int nextIndex = (myPhaseTable->getNumRows() > newIndex) ? newIndex : 0;2495const std::string state2 = myPhaseTable->getItemText(nextIndex, (TLSStatic ? 2 : 4));2496for (int i = 0; i < (int)state.size(); i++) {2497if (((oldState[i] == LINKSTATE_TL_GREEN_MAJOR) || (oldState[i] == LINKSTATE_TL_GREEN_MINOR)) &&2498((state2[i] == LINKSTATE_TL_GREEN_MAJOR) || (state2[i] == LINKSTATE_TL_GREEN_MINOR))) {2499state[i] = oldState[i];2500}2501}2502// add new step2503if (NEMA) {2504myTLSEditorParent->myEditedDef->getLogic()->addStep(string2time("90"), state, string2time("5"), string2time("50"),2505NBTrafficLightDefinition::UNSPECIFIED_DURATION, NBTrafficLightDefinition::UNSPECIFIED_DURATION,2506string2time("2"), string2time("3"), string2time("2"), "1", std::vector<int>(), newIndex);2507} else {2508myTLSEditorParent->myEditedDef->getLogic()->addStep(duration, state, std::vector<int>(), "", newIndex);2509}2510// return new index2511return newIndex;2512}251325142515bool2516GNETLSEditorFrame::TLSPhases::setDuration(const int col, const int row, const std::string& value) {2517// check value2518if (value.empty()) {2519// input empty, reset2520getPhaseTable()->setItemText(row, col, getSteps2Time(myTLSEditorParent->getPhase(row).duration).c_str());2521return true;2522} else if (GNEAttributeCarrier::canParse<double>(value)) {2523const auto duration = getSUMOTime(value);2524// check that duration > 02525if (duration > 0) {2526myTLSEditorParent->myEditedDef->getLogic()->setPhaseDuration(row, duration);2527myTLSEditorParent->myTLSPrograms->markAsModified();2528// update Cycle duration2529updateCycleDuration(col);2530return true;2531} else {2532return false;2533}2534} else {2535return false;2536}2537}253825392540bool2541GNETLSEditorFrame::TLSPhases::setState(const int col, const int row, const std::string& value) {2542// get state2543const auto& phase = myTLSEditorParent->getPhase(row);2544// declare new state. If value is empty, use previous value (reset)2545const auto newState = value.empty() ? phase.state : value;2546// insert phase2547try {2548myTLSEditorParent->myEditedDef->getLogic()->addStep(phase.duration, newState, phase.next, phase.name, row);2549} catch (ProcessError&) {2550// invalid character in newState2551return false;2552}2553// delete next phase2554try {2555myTLSEditorParent->myEditedDef->getLogic()->deletePhase(row + 1);2556} catch (InvalidArgument&) {2557WRITE_ERROR(TL("Error deleting phase '") + toString(row + 1) + "'");2558return false;2559}2560// mark TLS as modified depending of value2561if (value.size() > 0) {2562myTLSEditorParent->myTLSPrograms->markAsModified();2563// select row2564myPhaseTable->selectRow(row);2565} else {2566// input empty, reset2567getPhaseTable()->setItemText(row, col, newState);2568}2569// update state size2570updateStateSize(col);2571return true;2572}257325742575bool2576GNETLSEditorFrame::TLSPhases::setNext(const int row, const std::string& value) {2577// check next2578if (GNEAttributeCarrier::canParse<std::vector<int> >(value)) {2579const auto nextEdited = GNEAttributeCarrier::parse<std::vector<int> >(value);2580for (const auto nextPhase : nextEdited) {2581if ((nextPhase < 0) || (nextPhase >= myPhaseTable->getNumRows())) {2582return false;2583}2584}2585// set new next2586myTLSEditorParent->myEditedDef->getLogic()->setPhaseNext(row, nextEdited);2587myTLSEditorParent->myTLSPrograms->markAsModified();2588return true;2589} else {2590return false;2591}2592}259325942595bool2596GNETLSEditorFrame::TLSPhases::setName(const int row, const std::string& value) {2597// update name (currently no check needed)2598myTLSEditorParent->myEditedDef->getLogic()->setPhaseName(row, value);2599myTLSEditorParent->myTLSPrograms->markAsModified();2600return true;2601}260226032604bool2605GNETLSEditorFrame::TLSPhases::setMinDur(const int row, const std::string& value) {2606// check value2607if (value.empty()) {2608// set empty value2609myTLSEditorParent->myEditedDef->getLogic()->setPhaseMinDuration(row, NBTrafficLightDefinition::UNSPECIFIED_DURATION);2610myTLSEditorParent->myTLSPrograms->markAsModified();2611return true;2612} else if (GNEAttributeCarrier::canParse<double>(value)) {2613const auto minDur = getSUMOTime(value);2614// check that minDur > 02615if (minDur > 0) {2616myTLSEditorParent->myEditedDef->getLogic()->setPhaseMinDuration(row, minDur);2617myTLSEditorParent->myTLSPrograms->markAsModified();2618return true;2619} else {2620return false;2621}2622} else if (StringUtils::prune(value).empty()) {2623myTLSEditorParent->myEditedDef->getLogic()->setPhaseMinDuration(row, NBTrafficLightDefinition::UNSPECIFIED_DURATION);2624myTLSEditorParent->myTLSPrograms->markAsModified();2625return true;2626} else {2627return false;2628}2629}263026312632bool2633GNETLSEditorFrame::TLSPhases::setMaxDur(const int row, const std::string& value) {2634// check value2635if (value.empty()) {2636// set empty value2637myTLSEditorParent->myEditedDef->getLogic()->setPhaseMaxDuration(row, NBTrafficLightDefinition::UNSPECIFIED_DURATION);2638myTLSEditorParent->myTLSPrograms->markAsModified();2639return true;2640} else if (GNEAttributeCarrier::canParse<double>(value)) {2641const auto maxDur = getSUMOTime(value);2642// check that minDur > 02643if (maxDur > 0) {2644myTLSEditorParent->myEditedDef->getLogic()->setPhaseMaxDuration(row, maxDur);2645myTLSEditorParent->myTLSPrograms->markAsModified();2646return true;2647} else {2648return false;2649}2650} else if (StringUtils::prune(value).empty()) {2651myTLSEditorParent->myEditedDef->getLogic()->setPhaseMaxDuration(row, NBTrafficLightDefinition::UNSPECIFIED_DURATION);2652myTLSEditorParent->myTLSPrograms->markAsModified();2653return true;2654} else {2655return false;2656}2657}265826592660bool2661GNETLSEditorFrame::TLSPhases::setEarliestEnd(const int row, const std::string& value) {2662// check value2663if (value.empty()) {2664// set empty value2665myTLSEditorParent->myEditedDef->getLogic()->setPhaseEarliestEnd(row, NBTrafficLightDefinition::UNSPECIFIED_DURATION);2666myTLSEditorParent->myTLSPrograms->markAsModified();2667return true;2668} else if (GNEAttributeCarrier::canParse<double>(value)) {2669const auto earliestEnd = getSUMOTime(value);2670// check that earliestEnd > 02671if (earliestEnd > 0) {2672myTLSEditorParent->myEditedDef->getLogic()->setPhaseEarliestEnd(row, earliestEnd);2673myTLSEditorParent->myTLSPrograms->markAsModified();2674return true;2675} else {2676return false;2677}2678} else if (StringUtils::prune(value).empty()) {2679myTLSEditorParent->myEditedDef->getLogic()->setPhaseEarliestEnd(row, NBTrafficLightDefinition::UNSPECIFIED_DURATION);2680myTLSEditorParent->myTLSPrograms->markAsModified();2681return true;2682} else {2683return false;2684}2685}268626872688bool2689GNETLSEditorFrame::TLSPhases::setLatestEnd(const int row, const std::string& value) {2690// check value2691if (value.empty()) {2692// set empty value2693myTLSEditorParent->myEditedDef->getLogic()->setPhaseLatestEnd(row, NBTrafficLightDefinition::UNSPECIFIED_DURATION);2694myTLSEditorParent->myTLSPrograms->markAsModified();2695return true;2696} else if (GNEAttributeCarrier::canParse<double>(value)) {2697const auto latestEnd = getSUMOTime(value);2698// check that latestEnd > 02699if (latestEnd > 0) {2700myTLSEditorParent->myEditedDef->getLogic()->setPhaseLatestEnd(row, latestEnd);2701myTLSEditorParent->myTLSPrograms->markAsModified();2702return true;2703} else {2704return false;2705}2706} else if (StringUtils::prune(value).empty()) {2707myTLSEditorParent->myEditedDef->getLogic()->setPhaseLatestEnd(row, NBTrafficLightDefinition::UNSPECIFIED_DURATION);2708myTLSEditorParent->myTLSPrograms->markAsModified();2709return true;2710} else {2711return false;2712}2713}271427152716bool2717GNETLSEditorFrame::TLSPhases::setVehExt(const int row, const std::string& value) {2718// check value2719if (value.empty()) {2720// set empty value2721myTLSEditorParent->myEditedDef->getLogic()->setPhaseVehExt(row, NBTrafficLightDefinition::UNSPECIFIED_DURATION);2722myTLSEditorParent->myTLSPrograms->markAsModified();2723return true;2724} else if (GNEAttributeCarrier::canParse<double>(value)) {2725const auto vehExt = getSUMOTime(value);2726// check that vehExt > 02727if (vehExt > 0) {2728myTLSEditorParent->myEditedDef->getLogic()->setPhaseVehExt(row, vehExt);2729myTLSEditorParent->myTLSPrograms->markAsModified();2730return true;2731} else {2732return false;2733}2734} else if (StringUtils::prune(value).empty()) {2735myTLSEditorParent->myEditedDef->getLogic()->setPhaseVehExt(row, NBTrafficLightDefinition::UNSPECIFIED_DURATION);2736myTLSEditorParent->myTLSPrograms->markAsModified();2737return true;2738} else {2739return false;2740}2741}274227432744bool2745GNETLSEditorFrame::TLSPhases::setYellow(const int row, const std::string& value) {2746// check value2747if (value.empty()) {2748// set empty value2749myTLSEditorParent->myEditedDef->getLogic()->setPhaseYellow(row, NBTrafficLightDefinition::UNSPECIFIED_DURATION);2750myTLSEditorParent->myTLSPrograms->markAsModified();2751return true;2752} else if (GNEAttributeCarrier::canParse<double>(value)) {2753const auto yellow = getSUMOTime(value);2754// check that yellow > 02755if (yellow > 0) {2756myTLSEditorParent->myEditedDef->getLogic()->setPhaseYellow(row, yellow);2757myTLSEditorParent->myTLSPrograms->markAsModified();2758return true;2759} else {2760return false;2761}2762} else if (StringUtils::prune(value).empty()) {2763myTLSEditorParent->myEditedDef->getLogic()->setPhaseYellow(row, NBTrafficLightDefinition::UNSPECIFIED_DURATION);2764myTLSEditorParent->myTLSPrograms->markAsModified();2765return true;2766} else {2767return false;2768}2769}277027712772bool2773GNETLSEditorFrame::TLSPhases::setRed(const int row, const std::string& value) {2774// check value2775if (value.empty()) {2776// set empty value2777myTLSEditorParent->myEditedDef->getLogic()->setPhaseRed(row, NBTrafficLightDefinition::UNSPECIFIED_DURATION);2778myTLSEditorParent->myTLSPrograms->markAsModified();2779return true;2780} else if (GNEAttributeCarrier::canParse<double>(value)) {2781const auto red = getSUMOTime(value);2782// check that red > 02783if (red > 0) {2784myTLSEditorParent->myEditedDef->getLogic()->setPhaseRed(row, red);2785myTLSEditorParent->myTLSPrograms->markAsModified();2786return true;2787} else {2788return false;2789}2790} else if (StringUtils::prune(value).empty()) {2791myTLSEditorParent->myEditedDef->getLogic()->setPhaseRed(row, NBTrafficLightDefinition::UNSPECIFIED_DURATION);2792myTLSEditorParent->myTLSPrograms->markAsModified();2793return true;2794} else {2795return false;2796}2797}279827992800void2801GNETLSEditorFrame::TLSPhases::updateCycleDuration(const int col) {2802SUMOTime cycleDuration = 0;2803for (const auto& phase : myTLSEditorParent->myEditedDef->getLogic()->getPhases()) {2804cycleDuration += phase.duration;2805}2806// update bot label with cycle duration2807myPhaseTable->setColumnLabelBot(col, getSteps2Time(cycleDuration));2808}280928102811void2812GNETLSEditorFrame::TLSPhases::updateStateSize(const int col) {2813// update bot label with number of links2814myPhaseTable->setColumnLabelBot(col, "Links: " + toString(myTLSEditorParent->myEditedDef->getLogic()->getNumLinks()));2815}28162817// ---------------------------------------------------------------------------2818// GNETLSEditorFrame::TLSFile - methods2819// ---------------------------------------------------------------------------28202821GNETLSEditorFrame::TLSFile::TLSFile(GNETLSEditorFrame* TLSEditorParent) :2822GNEGroupBoxModule(TLSEditorParent, TL("TLS Program File")),2823myTLSEditorParent(TLSEditorParent) {2824FXHorizontalFrame* buttonsFrame = new FXHorizontalFrame(getCollapsableFrame(), GUIDesignAuxiliarHorizontalFrame);2825// create create tlDef button2826myLoadButton = GUIDesigns::buildFXButton(buttonsFrame, TL("Load"), "", TL("Load TLS program from additional file"), GUIIconSubSys::getIcon(GUIIcon::OPEN), this, MID_GNE_TLSFRAME_FILE_LOADPROGRAM, GUIDesignButton);2827myLoadButton->disable();2828// create create tlDef button2829mySaveButton = GUIDesigns::buildFXButton(buttonsFrame, TL("Save"), "", TL("Save TLS program to additional file"), GUIIconSubSys::getIcon(GUIIcon::SAVE), this, MID_GNE_TLSFRAME_FILE_SAVEPROGRAM, GUIDesignButton);2830mySaveButton->disable();2831// show TLSFile2832show();2833}283428352836GNETLSEditorFrame::TLSFile::~TLSFile() {}283728382839void2840GNETLSEditorFrame::TLSFile::updateTLSFile() {2841if (myTLSEditorParent->myTLSPrograms->getNumberOfPrograms() == 0) {2842myLoadButton->disable();2843mySaveButton->disable();2844} else if (myTLSEditorParent->myTLSAttributes->isSetDetectorsToggleButtonEnabled()) {2845// selecting E1, disable buttons2846myLoadButton->disable();2847mySaveButton->disable();2848} else if (myTLSEditorParent->myTLSJunction->isJoiningJunctions()) {2849// joining TLSs, disable button2850myLoadButton->disable();2851mySaveButton->disable();2852} else {2853myLoadButton->enable();2854mySaveButton->enable();2855}2856}285728582859void2860GNETLSEditorFrame::TLSFile::showTLSFile() {2861show();2862}286328642865void2866GNETLSEditorFrame::TLSFile::hideTLSFile() {2867hide();2868}286928702871long2872GNETLSEditorFrame::TLSFile::onCmdLoadTLSProgram(FXObject*, FXSelector, void*) {2873FXFileDialog opendialog(getCollapsableFrame(), "Load TLS Program");2874opendialog.setIcon(GUIIconSubSys::getIcon(GUIIcon::MODETLS));2875opendialog.setSelectMode(SELECTFILE_EXISTING);2876opendialog.setPatternList(SUMOXMLDefinitions::XMLFileExtensions.getMultilineString().c_str());2877if (gCurrentFolder.length() != 0) {2878opendialog.setDirectory(gCurrentFolder);2879}2880if (opendialog.execute()) {2881// run parser2882NBTrafficLightLogicCont tmpTLLCont;2883NIXMLTrafficLightsHandler tllHandler(tmpTLLCont, myTLSEditorParent->getViewNet()->getNet()->getEdgeCont(), true);2884tmpTLLCont.insert(myTLSEditorParent->myEditedDef);2885XMLSubSys::runParser(tllHandler, opendialog.getFilename().text());28862887NBLoadedSUMOTLDef* newDefSameProgram = nullptr;2888std::set<NBLoadedSUMOTLDef*> newDefsOtherProgram;2889for (auto item : tmpTLLCont.getPrograms(myTLSEditorParent->myEditedDef->getID())) {2890if (item.second != myTLSEditorParent->myEditedDef) {2891NBLoadedSUMOTLDef* sdef = dynamic_cast<NBLoadedSUMOTLDef*>(item.second);2892if (item.first == myTLSEditorParent->myEditedDef->getProgramID()) {2893newDefSameProgram = sdef;2894} else {2895newDefsOtherProgram.insert(sdef);2896}2897}2898}2899const int newPrograms = (int)newDefsOtherProgram.size();2900if (newPrograms > 0 || newDefSameProgram != nullptr) {2901std::vector<NBNode*> nodes = myTLSEditorParent->myEditedDef->getNodes();2902for (auto newProg : newDefsOtherProgram) {2903for (auto it_node : nodes) {2904GNEJunction* junction = myTLSEditorParent->getViewNet()->getNet()->getAttributeCarriers()->retrieveJunction(it_node->getID());2905myTLSEditorParent->getViewNet()->getUndoList()->add(new GNEChange_TLS(junction, newProg, true), true);2906}2907}2908if (newPrograms > 0) {2909WRITE_MESSAGE(TL("Loaded ") + toString(newPrograms) + TL(" new programs for tlLogic '") + myTLSEditorParent->myEditedDef->getID() + "'");2910}2911if (newDefSameProgram != nullptr) {2912// replace old program when loading the same program ID2913myTLSEditorParent->myEditedDef = newDefSameProgram;2914WRITE_MESSAGE(TL("Updated program '") + newDefSameProgram->getProgramID() + TL("' for tlLogic '") + myTLSEditorParent->myEditedDef->getID() + "'");2915}2916} else {2917if (tllHandler.getSeenIDs().count(myTLSEditorParent->myEditedDef->getID()) == 0) {2918myTLSEditorParent->getViewNet()->setStatusBarText(TL("No programs found for traffic light '") + myTLSEditorParent->myEditedDef->getID() + "'");2919}2920}29212922// clean up temporary container to avoid deletion of defs when its destruct is called2923for (NBTrafficLightDefinition* def : tmpTLLCont.getDefinitions()) {2924tmpTLLCont.removeProgram(def->getID(), def->getProgramID(), false);2925}29262927myTLSEditorParent->myTLSPhases->initPhaseTable();2928myTLSEditorParent->myTLSPrograms->markAsModified();2929}2930myTLSEditorParent->updateModules();2931return 0;2932}293329342935long2936GNETLSEditorFrame::TLSFile::onCmdSaveTLSProgram(FXObject*, FXSelector, void*) {2937FXString file = MFXUtils::getFilename2Write(this, TL("Save TLS Program as"),2938SUMOXMLDefinitions::XMLFileExtensions.getMultilineString().c_str(),2939GUIIconSubSys::getIcon(GUIIcon::MODETLS), gCurrentFolder);2940// check file2941if (file != "") {2942// add xml extension2943file = FileHelpers::addExtension(file.text(), ".xml").c_str();2944OutputDevice& device = OutputDevice::getDevice(file.text());2945// save program2946device.writeXMLHeader("additional", "additional_file.xsd");2947NWWriter_SUMO::writeTrafficLight(device, myTLSEditorParent->myEditedDef->getLogic());2948device.close();2949}2950myTLSEditorParent->updateModules();2951return 1;2952}295329542955std::string2956GNETLSEditorFrame::TLSFile::writeSUMOTime(SUMOTime steps) {2957const double time = STEPS2TIME(steps);2958if (time == std::floor(time)) {2959return toString(int(time));2960} else {2961return toString(time);2962}2963}29642965/****************************************************************************/296629672968