Path: blob/main/src/netedit/frames/network/GNETLSEditorFrame.cpp
169685 views
/****************************************************************************/1// Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo2// Copyright (C) 2001-2025 German Aerospace Center (DLR) and others.3// This program and the accompanying materials are made available under the4// terms of the Eclipse Public License 2.0 which is available at5// https://www.eclipse.org/legal/epl-2.0/6// This Source Code may also be made available under the following Secondary7// Licenses when the conditions for such availability set forth in the Eclipse8// Public License 2.0 are satisfied: GNU General Public License, version 29// or later which is available at10// https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html11// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later12/****************************************************************************/13/// @file 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, MFXGroupBoxModule, TLSJunctionMap, ARRAYNUMBER(TLSJunctionMap))90FXIMPLEMENT(GNETLSEditorFrame::TLSPrograms, MFXGroupBoxModule, TLSProgramsMap, ARRAYNUMBER(TLSProgramsMap))91FXIMPLEMENT(GNETLSEditorFrame::TLSAttributes, MFXGroupBoxModule, TLSAttributesMap, ARRAYNUMBER(TLSAttributesMap))92FXIMPLEMENT(GNETLSEditorFrame::TLSPhases, MFXGroupBoxModule, TLSPhasesMap, ARRAYNUMBER(TLSPhasesMap))93FXIMPLEMENT(GNETLSEditorFrame::TLSFile, MFXGroupBoxModule, 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}158update();159}160161162void163GNETLSEditorFrame::editTLS(GNEViewNetHelper::ViewObjectsSelector& viewObjects, const Position& clickedPosition, const bool shiftKeyPressed) {164// first check if in viewObjects there is a junction165if (viewObjects.getJunctionFront()) {166// check if we're adding or removing joined TLSs167if (myTLSJunction->isJoiningJunctions()) {168myTLSJunction->toggleJunctionSelected(viewObjects.getJunctionFront());169} else {170// show objects under cursor171myOverlappedInspection->showOverlappedInspection(viewObjects, clickedPosition, shiftKeyPressed);172// hide if we inspect only one junction173if (myOverlappedInspection->getNumberOfOverlappedACs()) {174if (myOverlappedInspection->getNumberOfOverlappedACs() == 1) {175myOverlappedInspection->hiderOverlappedInspection();176}177for (const auto& junction : viewObjects.getJunctions()) {178if (junction == myOverlappedInspection->getCurrentAC()) {179editJunction(junction);180}181}182}183}184} else if (viewObjects.getAdditionalFront() && myTLSAttributes->isSetDetectorsToggleButtonEnabled() &&185(viewObjects.getAdditionalFront()->getTagProperty()->getTag() == SUMO_TAG_INDUCTION_LOOP)) {186myTLSAttributes->toggleE1DetectorSelection(viewObjects.getAdditionalFront());187}188myViewNet->update();189}190191192bool193GNETLSEditorFrame::isTLSSaved() {194if (myTLSPrograms->checkHaveModifications()) {195// show question dialog196const auto questionDialog = GNEQuestionBasicDialog(myViewNet->getViewParent()->getGNEAppWindows(), GNEDialog::Buttons::YES_NO_CANCEL,197TL("Save TLS Changes"),198TL("There are unsaved changes in the currently edited traffic light."),199TL("Do you want to save it before changing mode?"));200// continue depending of result201if (questionDialog.getResult() == GNEDialog::Result::ACCEPT) {202// save modifications203myTLSPrograms->onCmdSaveChanges(nullptr, 0, nullptr);204return true;205} else if (questionDialog.getResult() == GNEDialog::Result::CANCEL) {206// cancel modifications207myTLSPrograms->onCmdDiscardChanges(nullptr, 0, nullptr);208return true;209} else {210// abort changing mode211return false;212}213} else {214return true;215}216}217218219bool220GNETLSEditorFrame::parseTLSPrograms(const std::string& file) {221NBTrafficLightLogicCont& tllCont = myViewNet->getNet()->getTLLogicCont();222NBTrafficLightLogicCont tmpTLLCont;223NIXMLTrafficLightsHandler tllHandler(tmpTLLCont, myViewNet->getNet()->getEdgeCont());224// existing definitions must be available to update their programs225std::set<NBTrafficLightDefinition*> origDefs;226for (NBTrafficLightDefinition* def : tllCont.getDefinitions()) {227// make a duplicate of every program228NBTrafficLightLogic* logic = tllCont.getLogic(def->getID(), def->getProgramID());229if (logic != nullptr) {230NBTrafficLightDefinition* duplicate = new NBLoadedSUMOTLDef(*def, *logic);231std::vector<NBNode*> nodes = def->getNodes();232for (auto it_node : nodes) {233GNEJunction* junction = myViewNet->getNet()->getAttributeCarriers()->retrieveJunction(it_node->getID());234myViewNet->getUndoList()->add(new GNEChange_TLS(junction, def, false, false), true);235myViewNet->getUndoList()->add(new GNEChange_TLS(junction, duplicate, true), true);236}237tmpTLLCont.insert(duplicate);238origDefs.insert(duplicate);239} else {240WRITE_WARNINGF(TL("tlLogic '%', program '%' could not be built"), def->getID(), def->getProgramID());241}242}243//std::cout << " initialized tmpCont with " << origDefs.size() << " defs\n";244XMLSubSys::runParser(tllHandler, file);245246std::vector<NBLoadedSUMOTLDef*> loadedTLS;247for (NBTrafficLightDefinition* def : tmpTLLCont.getDefinitions()) {248NBLoadedSUMOTLDef* sdef = dynamic_cast<NBLoadedSUMOTLDef*>(def);249if (sdef != nullptr) {250loadedTLS.push_back(sdef);251}252}253myViewNet->setStatusBarText(TL("Loaded ") + toString(loadedTLS.size()) + TL(" programs"));254for (auto def : loadedTLS) {255if (origDefs.count(def) != 0) {256// already add to undolist before257//std::cout << " skip " << def->getDescription() << "\n";258continue;259}260std::vector<NBNode*> nodes = def->getNodes();261//std::cout << " add " << def->getDescription() << " for nodes=" << toString(nodes) << "\n";262for (auto it_node : nodes) {263GNEJunction* junction = myViewNet->getNet()->getAttributeCarriers()->retrieveJunction(it_node->getID());264//myViewNet->getUndoList()->add(new GNEChange_TLS(junction, myTLSEditorParent->myEditedDef, false), true);265myViewNet->getUndoList()->add(new GNEChange_TLS(junction, def, true), true);266}267}268// clean up temporary container to avoid deletion of defs when its destruct is called269for (NBTrafficLightDefinition* def : tmpTLLCont.getDefinitions()) {270tmpTLLCont.removeProgram(def->getID(), def->getProgramID(), false);271}272return true;273}274275276void277GNETLSEditorFrame::selectedOverlappedElement(GNEAttributeCarrier* AC) {278auto junction = dynamic_cast<GNEJunction*>(AC);279if (junction) {280editJunction(junction);281}282}283284285void286GNETLSEditorFrame::cleanup() {287if (myTLSJunction->getCurrentJunction()) {288myTLSJunction->getCurrentJunction()->selectTLS(false);289if (myTLSPrograms->getNumberOfPrograms() > 0) {290for (const auto& node : myTLSPrograms->getCurrentTLSPrograms()->getNodes()) {291myViewNet->getNet()->getAttributeCarriers()->retrieveJunction(node->getID())->selectTLS(false);292}293}294}295// clean data structures296myTLSJunction->setCurrentJunction(nullptr);297// check if delete myEditedDef298if (myEditedDef) {299delete myEditedDef;300myEditedDef = nullptr;301}302// clear internal lanes303buildInternalLanes(nullptr);304// clean up attributes305myTLSPrograms->clearTLSProgramss();306// clean up attributes307myTLSAttributes->clearTLSAttributes();308// only clears when there are no definitions309myTLSPhases->initPhaseTable();310}311312313GNETLSEditorFrame::TLSJunction*314GNETLSEditorFrame::getTLSJunction() const {315return myTLSJunction;316}317318319GNETLSEditorFrame::TLSPrograms*320GNETLSEditorFrame::getTLSPrograms() const {321return myTLSPrograms;322}323324325GNETLSEditorFrame::TLSAttributes*326GNETLSEditorFrame::getTLSAttributes() const {327return myTLSAttributes;328}329330331GNETLSEditorFrame::TLSPhases*332GNETLSEditorFrame::getTLSPhases() const {333return myTLSPhases;334}335336337void338GNETLSEditorFrame::buildInternalLanes(const NBTrafficLightDefinition* tlDef) {339// clean up previous internal lanes340for (const auto& internalLanes : myInternalLanes) {341for (const auto& internalLane : internalLanes.second) {342// remove internal lane from ACs343myViewNet->getNet()->getAttributeCarriers()->deleteInternalLane(internalLane);344// delete internal lane345delete internalLane;346}347}348// clear container349myInternalLanes.clear();350// create new internal lanes351if (tlDef != nullptr) {352const int NUM_POINTS = 10;353const NBNode* nbnCurrentJunction = myTLSJunction->getCurrentJunction()->getNBNode();354// get innerID NWWriter_SUMO::writeInternalEdges355const std::string innerID = ":" + nbnCurrentJunction->getID();356const NBConnectionVector& links = tlDef->getControlledLinks();357// iterate over links358for (const auto& link : links) {359int tlIndex = link.getTLIndex();360PositionVector shape;361try {362const NBEdge::Connection& con = link.getFrom()->getConnection(link.getFromLane(), link.getTo(), link.getToLane());363shape = con.shape;364shape.append(con.viaShape);365} catch (ProcessError&) {366shape = link.getFrom()->getToNode()->computeInternalLaneShape(link.getFrom(), NBEdge::Connection(link.getFromLane(),367link.getTo(), link.getToLane()), NUM_POINTS);368}369if (shape.length() < 2) {370// enlarge shape to ensure visibility371shape.clear();372const PositionVector laneShapeFrom = link.getFrom()->getLaneShape(link.getFromLane());373const PositionVector laneShapeTo = link.getTo()->getLaneShape(link.getToLane());374shape.push_back(laneShapeFrom.positionAtOffset(MAX2(0.0, laneShapeFrom.length() - 1)));375shape.push_back(laneShapeTo.positionAtOffset(MIN2(1.0, laneShapeFrom.length())));376}377GNEInternalLane* internalLane = new GNEInternalLane(this, myTLSJunction->getCurrentJunction(), innerID + '_' + toString(tlIndex), shape, tlIndex);378// add into atribute carriers379myViewNet->getNet()->getAttributeCarriers()->insertInternalLane(internalLane);380myInternalLanes[tlIndex].push_back(internalLane);381}382// iterate over crossings383for (const auto& nbn : tlDef->getNodes()) {384for (const auto& crossing : nbn->getCrossings()) {385if (crossing->tlLinkIndex2 > 0 && crossing->tlLinkIndex2 != crossing->tlLinkIndex) {386// draw both directions387PositionVector forward = crossing->shape;388forward.move2side(crossing->width / 4);389GNEInternalLane* internalLane = new GNEInternalLane(this, myTLSJunction->getCurrentJunction(), crossing->id, forward, crossing->tlLinkIndex);390// add into atribute carriers391myViewNet->getNet()->getAttributeCarriers()->insertInternalLane(internalLane);392myInternalLanes[crossing->tlLinkIndex].push_back(internalLane);393PositionVector backward = crossing->shape.reverse();394backward.move2side(crossing->width / 4);395GNEInternalLane* internalLaneReverse = new GNEInternalLane(this, myTLSJunction->getCurrentJunction(), crossing->id + "_r", backward, crossing->tlLinkIndex2);396// add into atribute carriers397myViewNet->getNet()->getAttributeCarriers()->insertInternalLane(internalLaneReverse);398myInternalLanes[crossing->tlLinkIndex2].push_back(internalLaneReverse);399} else {400// draw only one lane for both directions401GNEInternalLane* internalLane = new GNEInternalLane(this, myTLSJunction->getCurrentJunction(), crossing->id, crossing->shape, crossing->tlLinkIndex);402// add into atribute carriers403myViewNet->getNet()->getAttributeCarriers()->insertInternalLane(internalLane);404myInternalLanes[crossing->tlLinkIndex].push_back(internalLane);405}406}407}408}409}410411412std::string413GNETLSEditorFrame::varDurString(SUMOTime dur) {414return (dur == NBTrafficLightDefinition::UNSPECIFIED_DURATION) ? "" : getSteps2Time(dur);415}416417418const NBTrafficLightLogic::PhaseDefinition&419GNETLSEditorFrame::getPhase(const int index) {420if ((index >= 0) || (index < (int)myEditedDef->getLogic()->getPhases().size())) {421return myEditedDef->getLogic()->getPhases().at(index);422} else {423throw ProcessError(TL("Invalid phase index"));424}425}426427428void429GNETLSEditorFrame::handleChange(GNEInternalLane* lane) {430myTLSPrograms->markAsModified();431// get current selected row432const auto selectedRow = myTLSPhases->getPhaseTable()->getCurrentSelectedRow();433if (myViewNet->changeAllPhases()) {434for (int row = 0; row < (int)myEditedDef->getLogic()->getPhases().size(); row++) {435myEditedDef->getLogic()->setPhaseState(row, lane->getTLIndex(), lane->getLinkState());436}437} else {438myEditedDef->getLogic()->setPhaseState(myTLSPhases->getPhaseTable()->getCurrentSelectedRow(), lane->getTLIndex(), lane->getLinkState());439}440// init phaseTable441myTLSPhases->initPhaseTable();442// select row443myTLSPhases->getPhaseTable()->selectRow(selectedRow);444// focus table445myTLSPhases->getPhaseTable()->setFocus();446}447448449void450GNETLSEditorFrame::handleMultiChange(GNELane* lane, FXObject* obj, FXSelector sel, void* eventData) {451if (myEditedDef != nullptr) {452myTLSPrograms->markAsModified();453const NBConnectionVector& links = myEditedDef->getControlledLinks();454std::set<std::string> fromIDs;455fromIDs.insert(lane->getMicrosimID());456// if neither the lane nor its edge are selected, apply changes to the whole edge457if (!lane->getParentEdge()->isAttributeCarrierSelected() && !lane->isAttributeCarrierSelected()) {458for (auto it_lane : lane->getParentEdge()->getChildLanes()) {459fromIDs.insert(it_lane->getMicrosimID());460}461} else {462// if the edge is selected, apply changes to all lanes of all selected edges463if (lane->getParentEdge()->isAttributeCarrierSelected()) {464const auto selectedEdge = myViewNet->getNet()->getAttributeCarriers()->getSelectedEdges();465for (const auto& edge : selectedEdge) {466for (auto it_lane : edge->getChildLanes()) {467fromIDs.insert(it_lane->getMicrosimID());468}469}470}471// if the lane is selected, apply changes to all selected lanes472if (lane->isAttributeCarrierSelected()) {473const auto selectedLanes = myViewNet->getNet()->getAttributeCarriers()->getSelectedLanes();474for (auto it_lane : selectedLanes) {475fromIDs.insert(it_lane->getMicrosimID());476}477}478479}480// set new state for all connections from the chosen lane IDs481for (auto it : links) {482if (fromIDs.count(it.getFrom()->getLaneID(it.getFromLane())) > 0) {483std::vector<GNEInternalLane*> lanes = myInternalLanes[it.getTLIndex()];484for (auto it_lane : lanes) {485it_lane->onDefault(obj, sel, eventData);486}487}488}489}490}491492493bool494GNETLSEditorFrame::controlsEdge(GNEEdge* edge) const {495if (myEditedDef != nullptr) {496const NBConnectionVector& links = myEditedDef->getControlledLinks();497for (auto it : links) {498if (it.getFrom()->getID() == edge->getMicrosimID()) {499return true;500}501}502}503return false;504}505506507void508GNETLSEditorFrame::editJunction(GNEJunction* junction) {509if ((myTLSJunction->getCurrentJunction() == nullptr) || (!myTLSPrograms->checkHaveModifications() && (junction != myTLSJunction->getCurrentJunction()))) {510// discard previous changes511myTLSPrograms->discardChanges(false);512// set junction513myTLSJunction->setCurrentJunction(junction);514// init TLS definitions515if (myTLSPrograms->initTLSPrograms()) {516// init TLSAttributes517myTLSAttributes->initTLSAttributes();518// begin undo-list519myViewNet->getUndoList()->begin(GUIIcon::MODETLS, TL("modifying TLS definition"));520// only select TLS if getCurrentJunction exist521if (myTLSJunction->getCurrentJunction()) {522myTLSJunction->getCurrentJunction()->selectTLS(true);523}524if (myTLSPrograms->getNumberOfPrograms() > 0) {525for (NBNode* node : myTLSPrograms->getCurrentTLSPrograms()->getNodes()) {526myViewNet->getNet()->getAttributeCarriers()->retrieveJunction(node->getID())->selectTLS(true);527}528// update color529myTLSPhases->updateTLSColoring();530}531}532} else {533myViewNet->setStatusBarText(TL("Unsaved modifications. Abort or Save"));534}535updateModules();536}537538539SUMOTime540GNETLSEditorFrame::getSUMOTime(const std::string& string) {541return TIME2STEPS(GNEAttributeCarrier::parse<double>(string));542}543544const std::string545GNETLSEditorFrame::getSteps2Time(const SUMOTime value) {546return toString(STEPS2TIME(value));547}548549// ---------------------------------------------------------------------------550// GNETLSEditorFrame::TLSAttributes - methods551// ---------------------------------------------------------------------------552553GNETLSEditorFrame::TLSAttributes::TLSAttributes(GNETLSEditorFrame* TLSEditorParent) :554MFXGroupBoxModule(TLSEditorParent, TL("Traffic Light Attributes")),555myTLSEditorParent(TLSEditorParent) {556// create frame, label and TextField for Offset (By default disabled)557FXHorizontalFrame* horizontalFrame = new FXHorizontalFrame(getCollapsableFrame(), GUIDesignAuxiliarHorizontalFrame);558new FXLabel(horizontalFrame, toString(SUMO_ATTR_OFFSET).c_str(), nullptr, GUIDesignLabelThickedFixed(100));559myOffsetTextField = new FXTextField(horizontalFrame, GUIDesignTextFieldNCol, this, MID_GNE_TLSFRAME_ATTRIBUTES_OFFSET, GUIDesignTextField);560myOffsetTextField->disable();561// create frame, label and TextField for parameters (By default disabled)562horizontalFrame = new FXHorizontalFrame(getCollapsableFrame(), GUIDesignAuxiliarHorizontalFrame);563myButtonEditParameters = GUIDesigns::buildFXButton(horizontalFrame, TL("parameters"), "", "", nullptr, this, MID_GNE_TLSFRAME_ATTRIBUTES_PARAMETERSDIALOG, GUIDesignButtonAttribute);564myParametersTextField = new FXTextField(horizontalFrame, GUIDesignTextFieldNCol, this, MID_GNE_TLSFRAME_ATTRIBUTES_PARAMETERS, GUIDesignTextField);565myButtonEditParameters->disable();566myParametersTextField->disable();567// create set detectors button (By default disabled)568mySetDetectorsToggleButton = new MFXToggleButtonTooltip(getCollapsableFrame(),569TLSEditorParent->getViewNet()->getViewParent()->getGNEAppWindows()->getStaticTooltipMenu(),570TL("Assign E1 detectors") + std::string("\t") + TL("Enable assign E1 mode") + std::string("\t") + TL("Assign E1 detectors to the current TLS"),571TL("Assign E1 detectors") + std::string("\t") + TL("Disable assign E1 mode") + std::string("\t") + TL("Assign E1 detectors to the current TLS"),572GUIIconSubSys::getIcon(GUIIcon::E1), GUIIconSubSys::getIcon(GUIIcon::E1),573this, MID_GNE_TLSFRAME_ATTRIBUTES_TOGGLEDETECTOR, GUIDesignButton);574mySetDetectorsToggleButton->disable();575}576577578GNETLSEditorFrame::TLSAttributes::~TLSAttributes() {}579580581void582GNETLSEditorFrame::TLSAttributes::updateTLSAttributes() {583if (myTLSEditorParent->myTLSPrograms->getNumberOfPrograms() == 0) {584// no TLS programs, disable elements585myOffsetTextField->disable();586myButtonEditParameters->disable();587myParametersTextField->disable();588// disable E1 detector mode589disableE1DetectorMode();590mySetDetectorsToggleButton->disable();591// clear E1 detectors592if (myE1Detectors.size() > 0) {593myE1Detectors.clear();594myTLSEditorParent->getViewNet()->update();595}596} else if (myTLSEditorParent->myTLSJunction->isJoiningJunctions()) {597// joining TLSs, disable button598myOffsetTextField->disable();599myButtonEditParameters->disable();600myParametersTextField->disable();601// disable E1 detector mode602disableE1DetectorMode();603mySetDetectorsToggleButton->disable();604// clear E1 detectors605if (myE1Detectors.size() > 0) {606myE1Detectors.clear();607myTLSEditorParent->getViewNet()->update();608}609} else if (isSetDetectorsToggleButtonEnabled()) {610// set detectors toggle button is enabled, disable elements611myOffsetTextField->disable();612myButtonEditParameters->disable();613myParametersTextField->disable();614} else {615myOffsetTextField->enable();616myButtonEditParameters->enable();617myParametersTextField->enable();618// disable E1 detector mode in static619if (myTLSEditorParent->myTLSPrograms->getCurrentTLSPrograms()->getType() != TrafficLightType::ACTUATED) {620// disable E1 detector mode621disableE1DetectorMode();622mySetDetectorsToggleButton->disable();623// clear E1 detectors624if (myE1Detectors.size() > 0) {625myE1Detectors.clear();626myTLSEditorParent->getViewNet()->update();627}628} else {629mySetDetectorsToggleButton->enable();630}631}632}633634635void636GNETLSEditorFrame::TLSAttributes::showTLSAttributes() {637show();638}639640641void642GNETLSEditorFrame::TLSAttributes::hideTLSAttributes() {643hide();644}645646647void648GNETLSEditorFrame::TLSAttributes::initTLSAttributes() {649// get current edited junction650const auto junction = myTLSEditorParent->myTLSJunction->getCurrentJunction();651if (junction == nullptr) {652throw ProcessError("Junction cannot be NULL");653} else {654// enable Offset655myOffsetTextField->enable();656myOffsetTextField->setTextColor(MFXUtils::getFXColor(RGBColor::BLACK));657// enable parameters658myButtonEditParameters->enable();659myParametersTextField->enable();660myParametersTextField->setTextColor(MFXUtils::getFXColor(RGBColor::BLACK));661// reset mySetDetectorsToggleButton662disableE1DetectorMode();663}664}665666667void668GNETLSEditorFrame::TLSAttributes::clearTLSAttributes() {669// clear and disable Offset TextField670myOffsetTextField->setText("");671myOffsetTextField->disable();672myOffsetTextField->setTextColor(MFXUtils::getFXColor(RGBColor::BLACK));673// clear and disable parameters TextField674myButtonEditParameters->disable();675myParametersTextField->setText("");676myParametersTextField->disable();677myParametersTextField->setTextColor(MFXUtils::getFXColor(RGBColor::BLACK));678}679680681SUMOTime682GNETLSEditorFrame::TLSAttributes::getOffset() const {683return getSUMOTime(myOffsetTextField->getText().text());684}685686687void688GNETLSEditorFrame::TLSAttributes::setOffset(const SUMOTime& offset) {689myOffsetTextField->setText(getSteps2Time(offset).c_str());690myOffsetTextField->setTextColor(MFXUtils::getFXColor(RGBColor::BLACK));691}692693694bool695GNETLSEditorFrame::TLSAttributes::isValidOffset() {696if (GNEAttributeCarrier::canParse<SUMOTime>(myOffsetTextField->getText().text())) {697myOffsetTextField->setTextColor(MFXUtils::getFXColor(RGBColor::BLACK));698return true;699} else {700myOffsetTextField->setTextColor(MFXUtils::getFXColor(RGBColor::RED));701return false;702}703}704705706std::string707GNETLSEditorFrame::TLSAttributes::getParameters() const {708return myParametersTextField->getText().text();709}710711712void713GNETLSEditorFrame::TLSAttributes::setParameters(const std::string& parameters) {714myParametersTextField->setText(parameters.c_str());715myParametersTextField->setTextColor(MFXUtils::getFXColor(RGBColor::BLACK));716// update E1 detectors717if (myTLSEditorParent->myEditedDef->getType() != TrafficLightType::STATIC) {718updateE1Detectors();719}720}721722723bool724GNETLSEditorFrame::TLSAttributes::isValidParameters() {725if (Parameterised::areParametersValid(myParametersTextField->getText().text())) {726myParametersTextField->setTextColor(MFXUtils::getFXColor(RGBColor::BLACK));727return true;728} else {729myParametersTextField->setTextColor(MFXUtils::getFXColor(RGBColor::RED));730return false;731}732}733734735bool736GNETLSEditorFrame::TLSAttributes::isSetDetectorsToggleButtonEnabled() const {737return (mySetDetectorsToggleButton->getState() == TRUE);738}739740741bool742GNETLSEditorFrame::TLSAttributes::toggleE1DetectorSelection(const GNEAdditional* E1) {743// get E1 lane ID744const auto laneID = E1->getParentLanes().front()->getID();745// iterate over all E1 detectors746for (auto it = myE1Detectors.begin(); it != myE1Detectors.end(); it++) {747if (E1->getID() == it->second) {748// already selected, then remove it from detectors749myE1Detectors.erase(it);750// and remove it from parameters751myTLSEditorParent->myEditedDef->unsetParameter(laneID);752myParametersTextField->setText(myTLSEditorParent->myEditedDef->getParametersStr().c_str());753// mark TL as modified754myTLSEditorParent->myTLSPrograms->markAsModified();755return true;756} else if (laneID == it->first) {757// there is another E1 in the same lane, then swap758myE1Detectors.erase(it);759myE1Detectors[laneID] = E1->getID();760// also in parameters761myTLSEditorParent->myEditedDef->setParameter(laneID, E1->getID());762myParametersTextField->setText(myTLSEditorParent->myEditedDef->getParametersStr().c_str());763// mark TL as modified764myTLSEditorParent->myTLSPrograms->markAsModified();765return true;766}767}768// add it in parameters769myE1Detectors[laneID] = E1->getID();770myTLSEditorParent->myEditedDef->setParameter(laneID, E1->getID());771myParametersTextField->setText(myTLSEditorParent->myEditedDef->getParametersStr().c_str());772// mark TL as modified773myTLSEditorParent->myTLSPrograms->markAsModified();774return true;775}776777778const std::map<std::string, std::string>&779GNETLSEditorFrame::TLSAttributes::getE1Detectors() const {780return myE1Detectors;781}782783784void785GNETLSEditorFrame::TLSAttributes::disableE1DetectorMode() {786mySetDetectorsToggleButton->setState(FALSE, TRUE);787}788789790long791GNETLSEditorFrame::TLSAttributes::onCmdSetOffset(FXObject*, FXSelector, void*) {792if (isValidOffset()) {793myTLSEditorParent->myTLSPrograms->markAsModified();794myTLSEditorParent->myEditedDef->setOffset(getOffset());795myOffsetTextField->killFocus();796myTLSEditorParent->updateModules();797}798return 1;799}800801802long803GNETLSEditorFrame::TLSAttributes::onCmdSetParameters(FXObject*, FXSelector, void*) {804if (isValidParameters()) {805myTLSEditorParent->myTLSPrograms->markAsModified();806myTLSEditorParent->myEditedDef->setParametersStr(getParameters());807myParametersTextField->killFocus();808myTLSEditorParent->updateModules();809}810return 1;811}812813814long815GNETLSEditorFrame::TLSAttributes::onCmdParametersDialog(FXObject*, FXSelector, void*) {816// continue depending of myEditedDef817if (myTLSEditorParent->myEditedDef) {818// get previous parameters819const auto previousParameters = getParameters();820// open parameters dialog821const auto parametersDialog = GNEParametersDialog(myTLSEditorParent->getViewNet()->getViewParent()->getGNEAppWindows(),822myTLSEditorParent->myEditedDef->getParametersMap());823// continue depending of result824if (parametersDialog.getResult() == GNEDialog::Result::ACCEPT) {825// set parameters in myEditedDef826myTLSEditorParent->myEditedDef->setParameters(parametersDialog.getEditedParameters());827// set parameters in textfield828setParameters(myTLSEditorParent->myEditedDef->getParametersStr());829// only mark as modified if parameters are different830if (getParameters() != previousParameters) {831myTLSEditorParent->myTLSPrograms->markAsModified();832}833}834myTLSEditorParent->updateModules();835}836return 1;837}838839840long841GNETLSEditorFrame::TLSAttributes::onCmdToggleDetectorMode(FXObject*, FXSelector, void*) {842if (mySetDetectorsToggleButton->getState()) {843// set special color844mySetDetectorsToggleButton->setBackColor(FXRGBA(253, 255, 206, 255));845} else {846// restore default color847mySetDetectorsToggleButton->setBackColor(4293980400);848}849myTLSEditorParent->updateModules();850// update view851myTLSEditorParent->getViewNet()->update();852return 1;853}854855856void857GNETLSEditorFrame::TLSAttributes::updateE1Detectors() {858// first clear E1 detectors859myE1Detectors.clear();860// iterate over parameters861for (const auto& parameter : myTLSEditorParent->myEditedDef->getParametersMap()) {862// check if both lane and E1 exists863if (myTLSEditorParent->getViewNet()->getNet()->getAttributeCarriers()->retrieveLane(parameter.first, false) &&864myTLSEditorParent->getViewNet()->getNet()->getAttributeCarriers()->retrieveAdditional(SUMO_TAG_INDUCTION_LOOP, parameter.second, false)) {865// add it into list866myE1Detectors[parameter.first] = parameter.second;867}868}869myTLSEditorParent->updateModules();870// update view net871myTLSEditorParent->getViewNet()->update();872}873874// ---------------------------------------------------------------------------875// GNETLSEditorFrame::TLSJunction - methods876// ---------------------------------------------------------------------------877878GNETLSEditorFrame::TLSJunction::TLSJunction(GNETLSEditorFrame* TLSEditorParent) :879MFXGroupBoxModule(TLSEditorParent, TL("Traffic Light")),880myTLSEditorParent(TLSEditorParent),881myCurrentJunction(nullptr) {882const auto staticTooltip = TLSEditorParent->getViewNet()->getViewParent()->getGNEAppWindows()->getStaticTooltipMenu();883// Create frame for junction IDs884FXHorizontalFrame* junctionIDFrame = new FXHorizontalFrame(getCollapsableFrame(), GUIDesignAuxiliarHorizontalFrame);885myJunctionIDLabel = new FXLabel(junctionIDFrame, TL("Junction ID"), nullptr, GUIDesignLabelThickedFixed(100));886myJunctionIDTextField = new MFXTextFieldIcon(junctionIDFrame, staticTooltip, GUIIcon::EMPTY, nullptr, 0, GUIDesignTextField);887// junction ID remains always disabled888myJunctionIDTextField->disable();889// Create frame for TLS Program ID890FXHorizontalFrame* TLSIDFrame = new FXHorizontalFrame(getCollapsableFrame(), GUIDesignAuxiliarHorizontalFrame);891new FXLabel(TLSIDFrame, TL("TLS ID"), nullptr, GUIDesignLabelThickedFixed(100));892myTLSIDTextField = new MFXTextFieldIcon(TLSIDFrame, staticTooltip, GUIIcon::EMPTY, this, MID_GNE_TLSFRAME_TLSJUNCTION_ID, GUIDesignTextField);893// create frame, label and textfield for type894FXHorizontalFrame* typeFrame = new FXHorizontalFrame(getCollapsableFrame(), GUIDesignAuxiliarHorizontalFrame);895new FXLabel(typeFrame, toString(SUMO_ATTR_TYPE).c_str(), nullptr, GUIDesignLabelThickedFixed(100));896myTLSTypeComboBox = new MFXComboBoxIcon(typeFrame, staticTooltip, false, GUIDesignComboBoxVisibleItems,897this, MID_GNE_TLSFRAME_TLSJUNCTION_TYPE, GUIDesignComboBoxAttribute);898// fill comboBox (only certain TL types)899myTLSTypeComboBox->appendIconItem(toString(TrafficLightType::STATIC).c_str());900myTLSTypeComboBox->appendIconItem(toString(TrafficLightType::ACTUATED).c_str());901myTLSTypeComboBox->appendIconItem(toString(TrafficLightType::DELAYBASED).c_str());902myTLSTypeComboBox->appendIconItem(toString(TrafficLightType::NEMA).c_str());903// create frame for join buttons904FXHorizontalFrame* joinButtons = new FXHorizontalFrame(getCollapsableFrame(), GUIDesignAuxiliarHorizontalFrameUniform);905// create join states button906myJoinTLSToggleButton = new MFXToggleButtonTooltip(joinButtons, staticTooltip,907TL("Join") + std::string("\t") + TL("Enable join mode") + std::string("\t") + TL("Join TLS and junctions in the current junction."),908TL("Join") + std::string("\t") + TL("Disable join mode") + std::string("\t") + TL("Join TLS and junctions in the current junction."),909GUIIconSubSys::getIcon(GUIIcon::JOIN), GUIIconSubSys::getIcon(GUIIcon::JOIN),910this, MID_GNE_TLSFRAME_TLSJUNCTION_TOGGLEJOIN, GUIDesignButton);911myDisjoinTLSButton = new MFXButtonTooltip(joinButtons, staticTooltip,912TL("Disjoin") + std::string("\t") + TL("Disjoin current TLS") + std::string("\t") + TL("Disjoin current TLS."),913GUIIconSubSys::getIcon(GUIIcon::DISJOIN), this, MID_GNE_TLSFRAME_TLSJUNCTION_DISJOIN, GUIDesignButton);914// create frame for join control buttons915myJoinControlButtons = new FXHorizontalFrame(getCollapsableFrame(), GUIDesignAuxiliarHorizontalFrameUniform);916// create create tlDef button917GUIDesigns::buildFXButton(myJoinControlButtons, TL("Accept"), "", TL("Finish join."),918GUIIconSubSys::getIcon(GUIIcon::ACCEPT), this, MID_GNE_BUTTON_ACCEPT, GUIDesignButton);919GUIDesigns::buildFXButton(myJoinControlButtons, TL("Cancel"), "", TL("Cancel Join."),920GUIIconSubSys::getIcon(GUIIcon::CANCEL), this, MID_GNE_BUTTON_CANCEL, GUIDesignButton);921// update junction description after creation922refreshTLSJunction();923// show TLS Junction924show();925}926927928GNETLSEditorFrame::TLSJunction::~TLSJunction() {}929930931void932GNETLSEditorFrame::TLSJunction::updateTLSJunction() {933if ((myCurrentJunction == nullptr) ||934(myCurrentJunction->getNBNode()->getControllingTLS().size() == 0)) {935// no TLS936myTLSIDTextField->setText("");937myTLSIDTextField->disable();938myTLSTypeComboBox->disable();939myJoinTLSToggleButton->disable();940myDisjoinTLSButton->disable();941myJoinControlButtons->hide();942} else {943// get first controled TLS944const auto TLS = (*myCurrentJunction->getNBNode()->getControllingTLS().begin());945// set text field ID946myTLSIDTextField->setText(TLS->getID().c_str());947// continue with more options948if (myTLSEditorParent->myTLSAttributes->isSetDetectorsToggleButtonEnabled() ||949myTLSEditorParent->myTLSPrograms->checkHaveModifications()) {950// disable if selecting selecting detectors or we modified the program951myTLSIDTextField->setText("");952myTLSIDTextField->disable();953myTLSTypeComboBox->disable();954myJoinTLSToggleButton->disable();955myDisjoinTLSButton->disable();956myJoinControlButtons->hide();957} else if (myTLSEditorParent->myTLSJunction->isJoiningJunctions()) {958// partial disable due joining959myTLSIDTextField->setText("");960myTLSIDTextField->disable();961myTLSTypeComboBox->disable();962myDisjoinTLSButton->disable();963// enable join TLS and show control buttons964myJoinTLSToggleButton->enable();965myJoinControlButtons->show();966} else {967// enable968myTLSIDTextField->enable();969myTLSTypeComboBox->enable();970myJoinTLSToggleButton->enable();971// disjoint button only if we have more than one TLS controlled972if (TLS->getNodes().size() == 1) {973myDisjoinTLSButton->disable();974} else {975myDisjoinTLSButton->enable();976}977}978}979}980981982GNEJunction*983GNETLSEditorFrame::TLSJunction::getCurrentJunction() const {984return myCurrentJunction;985}986987988void989GNETLSEditorFrame::TLSJunction::setCurrentJunction(GNEJunction* junction) {990myCurrentJunction = junction;991// resfresh module992refreshTLSJunction();993}994995996bool997GNETLSEditorFrame::TLSJunction::isJoiningJunctions() const {998return (myJoinTLSToggleButton->getState() == TRUE);999}100010011002bool1003GNETLSEditorFrame::TLSJunction::isJunctionSelected(const GNEJunction* junction) const {1004return (std::find(mySelectedJunctionIDs.begin(), mySelectedJunctionIDs.end(), junction->getID()) != mySelectedJunctionIDs.end());1005}100610071008void1009GNETLSEditorFrame::TLSJunction::toggleJunctionSelected(const GNEJunction* junction) {1010// avoid current junction1011if (junction != myCurrentJunction) {1012// find ID in selected junctions1013auto it = std::find(mySelectedJunctionIDs.begin(), mySelectedJunctionIDs.end(), junction->getID());1014// check if add or remove1015if (it == mySelectedJunctionIDs.end()) {1016mySelectedJunctionIDs.push_back(junction->getID());1017} else {1018mySelectedJunctionIDs.erase(it);1019}1020}1021}102210231024const std::vector<std::string>&1025GNETLSEditorFrame::TLSJunction::getSelectedJunctionIDs() const {1026return mySelectedJunctionIDs;1027}102810291030long1031GNETLSEditorFrame::TLSJunction::onCmdRenameTLS(FXObject*, FXSelector, void*) {1032// get IDs1033const std::string currentTLID = (*myCurrentJunction->getNBNode()->getControllingTLS().begin())->getID();1034const std::string newTLID = myTLSIDTextField->getText().text();1035// check if ID is valid1036if (newTLID.empty() || (newTLID == currentTLID)) {1037// same ID or empty1038myTLSIDTextField->setTextColor(GUIDesignTextColorBlack);1039myTLSIDTextField->setText(currentTLID.c_str());1040myTLSIDTextField->killFocus();1041myTLSEditorParent->update();1042// show all moduls1043myTLSEditorParent->myTLSPrograms->showTLSPrograms();1044myTLSEditorParent->myTLSAttributes->showTLSAttributes();1045myTLSEditorParent->myTLSPhases->showTLSPhases();1046myTLSEditorParent->myTLSFile->showTLSFile();1047} else if (!SUMOXMLDefinitions::isValidNetID(newTLID) || myCurrentJunction->getNet()->getTLLogicCont().exist(newTLID)) {1048// set invalid color1049myTLSIDTextField->setTextColor(GUIDesignTextColorRed);1050// hide moduls1051myTLSEditorParent->myTLSPrograms->hideTLSPrograms();1052myTLSEditorParent->myTLSAttributes->hideTLSAttributes();1053myTLSEditorParent->myTLSPhases->hideTLSPhases();1054myTLSEditorParent->myTLSFile->hideTLSFile();1055} else {1056// make a copy of myCurrentJunction and current tlDef (because will be reset after calling discardChanges)1057auto junction = myCurrentJunction;1058const auto tlDef = myTLSEditorParent->myTLSPrograms->getCurrentTLSPrograms();1059// restore color1060myTLSIDTextField->setTextColor(GUIDesignTextColorBlack);1061myTLSIDTextField->killFocus();1062myTLSEditorParent->update();1063// discard previous changes1064myTLSEditorParent->myTLSPrograms->discardChanges(false);1065// change name using undo-List1066myTLSEditorParent->getViewNet()->getUndoList()->begin(GUIIcon::MODETLS, TL("rename TLS"));1067myTLSEditorParent->getViewNet()->getUndoList()->add(new GNEChange_TLS(junction, tlDef, newTLID), true);1068myTLSEditorParent->getViewNet()->getUndoList()->end();1069// show all moduls1070myTLSEditorParent->myTLSPrograms->showTLSPrograms();1071myTLSEditorParent->myTLSAttributes->showTLSAttributes();1072myTLSEditorParent->myTLSPhases->showTLSPhases();1073myTLSEditorParent->myTLSFile->showTLSFile();1074// edit junction again1075myTLSEditorParent->editJunction(junction);1076}1077myTLSEditorParent->updateModules();1078return 1;1079}108010811082long1083GNETLSEditorFrame::TLSJunction::onCmdChangeType(FXObject*, FXSelector, void*) {1084// get IDs1085const std::string currentTLType = toString((*myCurrentJunction->getNBNode()->getControllingTLS().begin())->getType());1086const std::string newTLType = myTLSTypeComboBox->getText().text();1087// check if ID is valid1088if (newTLType.empty() || (newTLType == currentTLType)) {1089// same ID or empty, don't change1090myTLSTypeComboBox->setTextColor(GUIDesignTextColorBlack);1091// set value1092const int index = myTLSTypeComboBox->findItem(currentTLType.c_str());1093if (index == -1) {1094myTLSTypeComboBox->disable();1095} else {1096myTLSTypeComboBox->setCurrentItem(index);1097myTLSTypeComboBox->enable();1098}1099myTLSTypeComboBox->killFocus();1100myTLSEditorParent->update();1101// show all moduls1102myTLSEditorParent->myTLSPrograms->showTLSPrograms();1103myTLSEditorParent->myTLSAttributes->showTLSAttributes();1104myTLSEditorParent->myTLSPhases->showTLSPhases();1105myTLSEditorParent->myTLSFile->showTLSFile();1106} else if (!SUMOXMLDefinitions::TrafficLightTypes.hasString(newTLType)) {1107// set invalid color1108myTLSTypeComboBox->setTextColor(GUIDesignTextColorRed);1109// hide moduls1110myTLSEditorParent->myTLSPrograms->hideTLSPrograms();1111myTLSEditorParent->myTLSAttributes->hideTLSAttributes();1112myTLSEditorParent->myTLSPhases->hideTLSPhases();1113myTLSEditorParent->myTLSFile->hideTLSFile();1114} else {1115// reset color1116myTLSTypeComboBox->setTextColor(GUIDesignTextColorBlack);1117myTLSTypeComboBox->killFocus();1118myTLSEditorParent->update();1119// make a copy of myCurrentJunction (because will be reset after calling discardChanges)1120auto junction = myCurrentJunction;1121// discard previous changes1122myTLSEditorParent->myTLSPrograms->discardChanges(false);1123// change name using undo-List1124myTLSEditorParent->getViewNet()->getUndoList()->begin(GUIIcon::MODETLS, TL("change TLS type"));1125junction->setAttribute(SUMO_ATTR_TLTYPE, newTLType, myTLSEditorParent->getViewNet()->getUndoList());1126myTLSEditorParent->getViewNet()->getUndoList()->end();1127// show all moduls1128myTLSEditorParent->myTLSPrograms->showTLSPrograms();1129myTLSEditorParent->myTLSAttributes->showTLSAttributes();1130myTLSEditorParent->myTLSPhases->showTLSPhases();1131myTLSEditorParent->myTLSFile->showTLSFile();1132// edit junction again1133myTLSEditorParent->editJunction(junction);1134}1135myTLSEditorParent->updateModules();1136return 1;11371138}113911401141long1142GNETLSEditorFrame::TLSJunction::onCmdToggleJoinTLS(FXObject*, FXSelector, void*) {1143if (myJoinTLSToggleButton->getState()) {1144// set special color1145myJoinTLSToggleButton->setBackColor(FXRGBA(253, 255, 206, 255));1146// clear and fill mySelectedJunctionIDs1147mySelectedJunctionIDs.clear();1148// get all nodes controlled by this TLS1149const auto TLNodes = (*myCurrentJunction->getNBNode()->getControllingTLS().begin())->getNodes();1150// fill mySelectedJunctionIDs with TLNodes1151mySelectedJunctionIDs.clear();1152for (const auto& TLNode : TLNodes) {1153mySelectedJunctionIDs.push_back(TLNode->getID());1154}1155// make a copy of selected junctions1156myOriginalSelectedJunctionIDs = mySelectedJunctionIDs;1157// show control buttons1158myJoinControlButtons->show();1159getCollapsableFrame()->recalc();1160} else {1161// hide control buttons1162myJoinControlButtons->hide();1163getCollapsableFrame()->recalc();1164// make a copy of current junction1165const auto currentJunction = myCurrentJunction;1166// declare vectors for junctions1167std::vector<GNEJunction*> selectedJunctions, resetTLJunctions;1168// get selected junctions (all except current1169for (const auto& selectedJunctionID : mySelectedJunctionIDs) {1170if (selectedJunctionID != currentJunction->getID()) {1171selectedJunctions.push_back(myTLSEditorParent->getViewNet()->getNet()->getAttributeCarriers()->retrieveJunction(selectedJunctionID));1172}1173}1174// get junctions to reset TL (all TL nodes except current)1175for (const auto& TLNBNode : (*currentJunction->getNBNode()->getControllingTLS().begin())->getNodes()) {1176if (TLNBNode != currentJunction->getNBNode()) {1177resetTLJunctions.push_back(myTLSEditorParent->getViewNet()->getNet()->getAttributeCarriers()->retrieveJunction(TLNBNode->getID()));1178}1179}1180// discard changes1181myTLSEditorParent->myTLSPrograms->discardChanges(false);1182// begin undo list1183myTLSEditorParent->getViewNet()->getUndoList()->begin(GUIIcon::MODETLS, TL("join TLS"));1184// remove tl from TLNBNode1185for (const auto& resetTLJunction : resetTLJunctions) {1186resetTLJunction->setAttribute(SUMO_ATTR_TYPE, "priority", myTLSEditorParent->getViewNet()->getUndoList());1187}1188// now update it in all joined junctions1189for (const auto& selectedJunction : selectedJunctions) {1190selectedJunction->setAttribute(SUMO_ATTR_TYPE, currentJunction->getAttribute(SUMO_ATTR_TYPE), myTLSEditorParent->getViewNet()->getUndoList());1191selectedJunction->setAttribute(SUMO_ATTR_TLID, currentJunction->getAttribute(SUMO_ATTR_TLID), myTLSEditorParent->getViewNet()->getUndoList());1192}1193// end undo list1194myTLSEditorParent->getViewNet()->getUndoList()->end();1195// restore default color1196myJoinTLSToggleButton->setBackColor(4293980400);1197// clear selected junction IDs1198mySelectedJunctionIDs.clear();1199// edit junction again1200myTLSEditorParent->editJunction(currentJunction);1201}1202myTLSEditorParent->updateModules();1203// update view1204myTLSEditorParent->getViewNet()->update();1205return 1;1206}120712081209long1210GNETLSEditorFrame::TLSJunction::onCmdDisjoinTLS(FXObject*, FXSelector, void*) {1211// make a copy of current junction1212const auto currentJunction = myCurrentJunction;1213// declare vectors for junctions1214std::vector<GNEJunction*> resetTLJunctions;1215// get junctions to reset TL1216for (const auto& TLNBNode : (*currentJunction->getNBNode()->getControllingTLS().begin())->getNodes()) {1217resetTLJunctions.push_back(myTLSEditorParent->getViewNet()->getNet()->getAttributeCarriers()->retrieveJunction(TLNBNode->getID()));1218}1219// save TL types1220const auto type = resetTLJunctions.front()->getAttribute(SUMO_ATTR_TYPE);1221const auto tlType = resetTLJunctions.front()->getAttribute(SUMO_ATTR_TLTYPE);1222// discard changes1223myTLSEditorParent->myTLSPrograms->discardChanges(false);1224// begin undo list1225myTLSEditorParent->getViewNet()->getUndoList()->begin(GUIIcon::MODETLS, TL("disjoin TLS"));1226// the disjoint tlIds will be the junction ids. Ensure that there is no name clash with the current tlId1227NBTrafficLightLogicCont& tllCont = myTLSEditorParent->getViewNet()->getNet()->getTLLogicCont();1228const std::string oldId = currentJunction->getAttribute(SUMO_ATTR_TLID);1229const std::string tmpIdBase = oldId + "_TMP";1230int tmpIndex = 0;1231std::string tmpId = tmpIdBase + toString(tmpIndex);1232while (tllCont.exist(tmpId)) {1233tmpId = tmpIdBase + toString(++tmpIndex);1234}1235for (NBTrafficLightDefinition* tlDef : currentJunction->getNBNode()->getControllingTLS()) {1236myTLSEditorParent->getViewNet()->getUndoList()->add(new GNEChange_TLS(currentJunction, tlDef, tmpId), true);1237}1238// remove tl from TLNBNode and the re-initialize as single traffic light1239for (const auto& resetTLJunction : resetTLJunctions) {1240resetTLJunction->setAttribute(SUMO_ATTR_TYPE, "priority", myTLSEditorParent->getViewNet()->getUndoList());1241resetTLJunction->setAttribute(SUMO_ATTR_TYPE, type, myTLSEditorParent->getViewNet()->getUndoList());1242resetTLJunction->setAttribute(SUMO_ATTR_TLTYPE, tlType, myTLSEditorParent->getViewNet()->getUndoList());1243}1244// end undo list1245myTLSEditorParent->getViewNet()->getUndoList()->end();1246// restore default color1247myJoinTLSToggleButton->setBackColor(4293980400);1248// clear selected junction IDs1249mySelectedJunctionIDs.clear();1250// edit junction again1251myTLSEditorParent->editJunction(currentJunction);1252myTLSEditorParent->updateModules();1253return 1;1254}125512561257long1258GNETLSEditorFrame::TLSJunction::onCmdAcceptJoin(FXObject*, FXSelector, void*) {1259myJoinTLSToggleButton->setState(FALSE, TRUE);1260myTLSEditorParent->updateModules();1261return 1;1262}126312641265long1266GNETLSEditorFrame::TLSJunction::onCmdCancelJoin(FXObject*, FXSelector, void*) {1267// restore selected junction1268mySelectedJunctionIDs = myOriginalSelectedJunctionIDs;1269myJoinTLSToggleButton->setState(FALSE, TRUE);1270myTLSEditorParent->updateModules();1271return 1;1272}127312741275void1276GNETLSEditorFrame::TLSJunction::refreshTLSJunction() {1277// first reset junction label1278myJunctionIDLabel->setText(TL("Junction ID"));1279// clear selected junctions1280mySelectedJunctionIDs.clear();1281// cancel joining junction mode1282onCmdCancelJoin(nullptr, 0, nullptr);1283// continue depending of current junction1284if (myCurrentJunction == nullptr) {1285myJunctionIDTextField->setText(TL("No junction selected"));1286} else {1287// get all TLS assigned to this node1288const auto& TLSs = myCurrentJunction->getNBNode()->getControllingTLS();1289// check if junction is controlled1290if (TLSs.size() > 0) {1291// get first TLS1292const auto TLS = (*TLSs.begin());1293// update junction ID text field1294if (TLS->getNodes().size() > 1) {1295// declare string1296std::string TLSNodesStr;1297for (auto it = TLS->getNodes().begin(); it != TLS->getNodes().end(); it++) {1298if (it == (TLS->getNodes().end() - 1)) {1299TLSNodesStr += (*it)->getID();1300} else {1301TLSNodesStr += (*it)->getID() + ", ";1302}1303}1304// updated junction fields1305myJunctionIDTextField->setText(TLSNodesStr.c_str());1306// update junction label if we have multiple nodes1307if (TLS->getNodes().size() > 1) {1308myJunctionIDLabel->setText(TL("Junction IDs"));1309}1310// set TLS type in comboBox1311const int index = myTLSTypeComboBox->findItem(myCurrentJunction->getAttribute(SUMO_ATTR_TLTYPE).c_str());1312if (index != -1) {1313myTLSTypeComboBox->setCurrentItem(index, FALSE);1314}1315}1316} else {1317// update junction ID text field1318myJunctionIDTextField->setText(myCurrentJunction->getID().c_str());1319myTLSTypeComboBox->setCurrentItem(0, FALSE);1320}1321}1322// update TLS junction1323updateTLSJunction();1324}13251326// ---------------------------------------------------------------------------1327// GNETLSEditorFrame::TLSPrograms - methods1328// ---------------------------------------------------------------------------13291330GNETLSEditorFrame::TLSPrograms::TLSPrograms(GNETLSEditorFrame* TLSEditorParent) :1331MFXGroupBoxModule(TLSEditorParent, TL("Traffic Light Programs")),1332myTLSEditorParent(TLSEditorParent) {1333// create frame, label and comboBox for programID1334FXHorizontalFrame* programFrame = new FXHorizontalFrame(getCollapsableFrame(), GUIDesignAuxiliarHorizontalFrame);1335new FXLabel(programFrame, toString(SUMO_ATTR_PROGRAMID).c_str(), nullptr, GUIDesignLabelThickedFixed(100));1336myProgramComboBox = new MFXComboBoxIcon(programFrame, TLSEditorParent->getViewNet()->getViewParent()->getGNEAppWindows()->getStaticTooltipMenu(),1337false, GUIDesignComboBoxVisibleItems, this, MID_GNE_TLSFRAME_DEFINITION_SWITCHPROGRAM, GUIDesignComboBoxAttribute);1338myProgramComboBox->disable();1339// create auxiliar frames1340FXHorizontalFrame* horizontalFrameAux = new FXHorizontalFrame(getCollapsableFrame(), GUIDesignAuxiliarHorizontalFrameUniform);1341FXVerticalFrame* verticalFrameAuxA = new FXVerticalFrame(horizontalFrameAux, GUIDesignAuxiliarHorizontalFrame);1342FXVerticalFrame* verticalFrameAuxB = new FXVerticalFrame(horizontalFrameAux, GUIDesignAuxiliarHorizontalFrame);1343// create create tlDef button1344myCreateButton = GUIDesigns::buildFXButton(verticalFrameAuxA, TL("Create TLS"), "", TL("Create a new traffic light program."),1345GUIIconSubSys::getIcon(GUIIcon::MODETLS), this, MID_GNE_TLSFRAME_DEFINITION_CREATE, GUIDesignButton);1346myCreateButton->disable();1347// create delete tlDef button1348myDeleteButton = GUIDesigns::buildFXButton(verticalFrameAuxA, TL("Delete"), "", TL("Delete a traffic light program. If all programs are deleted the junction turns into a priority junction."),1349GUIIconSubSys::getIcon(GUIIcon::REMOVE), this, MID_GNE_TLSFRAME_DEFINITION_DELETE, GUIDesignButton);1350myDeleteButton->disable();1351// create reset current tlDef button1352myResetSingleButton = GUIDesigns::buildFXButton(verticalFrameAuxB, TL("Reset single"), "", TL("Reset current TLS program."),1353GUIIconSubSys::getIcon(GUIIcon::RESET), this, MID_GNE_TLSFRAME_DEFINITION_RESETCURRENT, GUIDesignButton);1354myResetSingleButton->disable();1355// create reset all tlDefs button1356myResetAllButton = GUIDesigns::buildFXButton(verticalFrameAuxB, TL("Reset all"), "", TL("Reset all TLS programs."),1357GUIIconSubSys::getIcon(GUIIcon::RESET), this, MID_GNE_TLSFRAME_DEFINITION_RESETALL, GUIDesignButton);1358myResetAllButton->disable();1359// create save modifications button1360mySaveButon = GUIDesigns::buildFXButton(verticalFrameAuxA, TL("Save"), "", TL("Save program modifications. (Enter)"),1361GUIIconSubSys::getIcon(GUIIcon::OK), this, MID_GNE_TLSFRAME_DEFINITION_SAVE, GUIDesignButton);1362mySaveButon->disable();1363// create cancel modifications buttons1364myCancelButon = GUIDesigns::buildFXButton(verticalFrameAuxB, TL("Cancel"), "", TL("Discard program modifications. (Esc)"),1365GUIIconSubSys::getIcon(GUIIcon::CANCEL), this, MID_GNE_TLSFRAME_DEFINITION_DISCARD, GUIDesignButton);1366myCancelButon->disable();1367// show GroupBox1368show();1369}137013711372GNETLSEditorFrame::TLSPrograms::~TLSPrograms() {}137313741375void1376GNETLSEditorFrame::TLSPrograms::updateTLSPrograms() {1377if (getNumberOfPrograms() == 0) {1378// no TLS Programs, disable buttons except create (if we have a junction)1379if (myTLSEditorParent->getTLSJunction()->getCurrentJunction() != nullptr) {1380myCreateButton->enable();1381} else {1382myCreateButton->disable();1383}1384myDeleteButton->disable();1385myResetSingleButton->disable();1386myProgramComboBox->disable();1387myResetAllButton->disable();1388mySaveButon->disable();1389myCancelButon->disable();1390} else if (myTLSEditorParent->myTLSAttributes->isSetDetectorsToggleButtonEnabled()) {1391// selecting E1, disable buttons1392myCreateButton->disable();1393myDeleteButton->disable();1394myResetSingleButton->disable();1395myProgramComboBox->disable();1396myResetAllButton->disable();1397mySaveButon->disable();1398myCancelButon->disable();1399} else if (myTLSEditorParent->myTLSJunction->isJoiningJunctions()) {1400// joining TLSs, disable button1401myCreateButton->disable();1402myDeleteButton->disable();1403myResetSingleButton->disable();1404myProgramComboBox->disable();1405myResetAllButton->disable();1406mySaveButon->disable();1407myCancelButon->disable();1408} else if (myHaveModifications) {1409// modifications, disable button1410myCreateButton->disable();1411myDeleteButton->disable();1412myResetSingleButton->disable();1413myProgramComboBox->disable();1414myResetAllButton->disable();1415// enable save and cancel buttons1416mySaveButon->enable();1417myCancelButon->enable();1418} else {1419myCreateButton->enable();1420myDeleteButton->enable();1421myResetSingleButton->enable();1422myProgramComboBox->enable();1423// disable save and cancel buttons1424mySaveButon->disable();1425myCancelButon->disable();1426// check if enable reset all1427if (getNumberOfPrograms() > 1) {1428myResetAllButton->enable();1429} else {1430myResetAllButton->disable();1431}1432}1433// get current junction1434const auto currentJunction = myTLSEditorParent->myTLSJunction->getCurrentJunction();1435// update button text1436if (currentJunction == nullptr) {1437myCreateButton->setText(TL("Create"));1438} else if (currentJunction->getNBNode()->isTLControlled()) {1439myCreateButton->setText(TL("Duplicate"));1440} else {1441myCreateButton->setText(TL("Create"));1442}1443}144414451446void1447GNETLSEditorFrame::TLSPrograms::showTLSPrograms() {1448show();1449}145014511452void1453GNETLSEditorFrame::TLSPrograms::hideTLSPrograms() {1454hide();1455}145614571458bool1459GNETLSEditorFrame::TLSPrograms::initTLSPrograms() {1460// get current edited junction1461const auto junction = myTLSEditorParent->myTLSJunction->getCurrentJunction();1462if (junction == nullptr) {1463throw ProcessError("Junction cannot be NULL");1464} else {1465// clear definitions1466myTLSPrograms.clear();1467// obtain TLSs sorted by ID1468std::set<std::string> programIDs;1469for (const auto& TLS : junction->getNBNode()->getControllingTLS()) {1470myTLSPrograms.push_back(TLS);1471programIDs.insert(TLS->getProgramID());1472}1473for (const auto& programID : programIDs) {1474myProgramComboBox->appendIconItem(programID.c_str());1475}1476// check if enable TLS definitions1477if (myTLSPrograms.size() > 0) {1478myProgramComboBox->enable();1479myProgramComboBox->setCurrentItem(0);1480// switch TLS Program1481return switchProgram();1482}1483return false;1484}1485}148614871488void1489GNETLSEditorFrame::TLSPrograms::clearTLSProgramss() {1490// clear definitions1491myTLSPrograms.clear();1492// clear and disable myProgramComboBox1493myProgramComboBox->clearItems();1494myProgramComboBox->disable();1495}149614971498int1499GNETLSEditorFrame::TLSPrograms::getNumberOfPrograms() const {1500return myProgramComboBox->getNumItems();1501}150215031504bool1505GNETLSEditorFrame::TLSPrograms::checkHaveModifications() const {1506return myHaveModifications;1507}150815091510void1511GNETLSEditorFrame::TLSPrograms::markAsModified() {1512myHaveModifications = true;1513myTLSEditorParent->updateModules();1514}151515161517NBTrafficLightDefinition*1518GNETLSEditorFrame::TLSPrograms::getCurrentTLSPrograms() const {1519// find TLS definition1520for (const auto& TLSPrograms : myTLSPrograms) {1521if (TLSPrograms->getProgramID() == myProgramComboBox->getText().text()) {1522return TLSPrograms;1523}1524}1525throw ProcessError(TL("TLSPrograms cannot be found"));1526}152715281529const std::string1530GNETLSEditorFrame::TLSPrograms::getCurrentTLSProgramID() const {1531if (myProgramComboBox->getNumItems() == 0) {1532return "";1533} else {1534return myProgramComboBox->getText().text();1535}1536}153715381539void1540GNETLSEditorFrame::TLSPrograms::discardChanges(const bool editJunctionAgain) {1541// get junction copy1542auto currentJunction = myTLSEditorParent->myTLSJunction->getCurrentJunction();1543if (currentJunction != nullptr) {1544myTLSEditorParent->getViewNet()->getUndoList()->abortAllChangeGroups();1545myTLSEditorParent->cleanup();1546myTLSEditorParent->getViewNet()->updateViewNet();1547// edit junction again1548if (editJunctionAgain) {1549myTLSEditorParent->editJunction(currentJunction);1550}1551}1552myTLSEditorParent->updateModules();1553}155415551556long1557GNETLSEditorFrame::TLSPrograms::onCmdCreate(FXObject*, FXSelector, void*) {1558// get current edited junction (needed because onCmdDiscardChanges clear junction)1559GNEJunction* currentJunction = myTLSEditorParent->myTLSJunction->getCurrentJunction();1560// abort because we onCmdOk assumes we wish to save an edited definition1561discardChanges(false);1562// check number of edges1563if (currentJunction->getGNEIncomingEdges().empty() && currentJunction->getGNEOutgoingEdges().empty()) {1564// open warning dialog1565GNEWarningBasicDialog(myTLSEditorParent->getViewNet()->getViewParent()->getGNEAppWindows(),1566TL("TLS cannot be created"),1567TL("Traffic Light cannot be created because junction must have"),1568TL("at least one incoming edge and one outgoing edge.")1569);1570return 1;1571}1572// check number of connections1573if (currentJunction->getGNEConnections().empty()) {1574// open warning dialog1575GNEWarningBasicDialog(myTLSEditorParent->getViewNet()->getViewParent()->getGNEAppWindows(),1576TL("TLS cannot be created"),1577TL("Traffic Light cannot be created because junction"),1578TL("must have at least one connection.")1579);1580return 1;1581}1582// check uncontrolled connections1583bool connectionControlled = false;1584for (const auto& connection : currentJunction->getGNEConnections()) {1585if (!connection->getNBEdgeConnection().uncontrolled) {1586connectionControlled = true;1587}1588}1589if (!connectionControlled) {1590// open warning dialog1591GNEWarningBasicDialog(myTLSEditorParent->getViewNet()->getViewParent()->getGNEAppWindows(),1592TL("TLS cannot be created"),1593TL("Traffic Light cannot be created because junction"),1594TL("must have at least one controlled connection.")1595);1596return 1;1597}1598// all checks ok, then create TLS in junction1599createTLS(currentJunction);1600// edit junction1601myTLSEditorParent->editJunction(currentJunction);1602// switch to the last program1603myProgramComboBox->setCurrentItem(myProgramComboBox->getNumItems() - 1, TRUE);1604myTLSEditorParent->updateModules();1605return 1;1606}160716081609long1610GNETLSEditorFrame::TLSPrograms::onCmdDelete(FXObject*, FXSelector, void*) {1611// get current junction1612GNEJunction* currentJunction = myTLSEditorParent->myTLSJunction->getCurrentJunction();1613// get current edited tlDef1614NBTrafficLightDefinition* tlDef = myTLSEditorParent->myTLSPrograms->getCurrentTLSPrograms();1615// check if remove entire TLS or only one program1616const bool changeJunctionType = (myTLSEditorParent->myTLSPrograms->getNumberOfPrograms() == 1);1617// abort because onCmdOk assumes we wish to save an edited definition1618discardChanges(false);1619// check if change junction type1620if (changeJunctionType) {1621currentJunction->setAttribute(SUMO_ATTR_TYPE, toString(SumoXMLNodeType::PRIORITY), myTLSEditorParent->getViewNet()->getUndoList());1622} else {1623// just remove TLDef1624myTLSEditorParent->getViewNet()->getUndoList()->add(new GNEChange_TLS(currentJunction, tlDef, false), true);1625// edit junction again1626myTLSEditorParent->editJunction(currentJunction);1627}1628myTLSEditorParent->updateModules();1629return 1;1630}163116321633long1634GNETLSEditorFrame::TLSPrograms::onCmdResetCurrentProgram(FXObject*, FXSelector, void*) {1635// obtain junction and old definitions1636GNEJunction* junction = myTLSEditorParent->myTLSJunction->getCurrentJunction();1637NBTrafficLightDefinition* oldDef = myTLSEditorParent->myTLSPrograms->getCurrentTLSPrograms();1638const std::string programID = oldDef->getProgramID();1639// discard changes1640discardChanges(false);1641// begin undo1642myTLSEditorParent->getViewNet()->getUndoList()->begin(GUIIcon::MODETLS, TL("reset current program"));1643// remove old definition1644myTLSEditorParent->getViewNet()->getUndoList()->add(new GNEChange_TLS(junction, oldDef, false), true);1645// create new definition, and add it1646NBOwnTLDef* newDef = new NBOwnTLDef(oldDef->getID(), oldDef->getNodes(), oldDef->getOffset(), oldDef->getType());1647newDef->setProgramID(programID);1648myTLSEditorParent->getViewNet()->getUndoList()->add(new GNEChange_TLS(junction, newDef, true, true), true);1649// set old index1650// end undo1651myTLSEditorParent->getViewNet()->getUndoList()->end();1652// inspect junction again1653myTLSEditorParent->editJunction(junction);1654// switch to programID1655int index = -1;1656for (int i = 0; i < myProgramComboBox->getNumItems(); i++) {1657if (myProgramComboBox->getItemText(i) == programID) {1658index = i;1659}1660}1661if (index != -1) {1662myProgramComboBox->setCurrentItem(index, TRUE);1663}1664myTLSEditorParent->updateModules();1665return 1;1666}166716681669long1670GNETLSEditorFrame::TLSPrograms::onCmdResetAll(FXObject*, FXSelector, void*) {1671// obtain junction and old definitions1672GNEJunction* junction = myTLSEditorParent->myTLSJunction->getCurrentJunction();1673NBTrafficLightDefinition* oldDef = myTLSEditorParent->myTLSPrograms->getCurrentTLSPrograms();1674// get a list of all affected nodes1675std::vector<GNEJunction*> TLSJunctions;1676for (const auto& TLSNode : oldDef->getNodes()) {1677TLSJunctions.push_back(myTLSEditorParent->getViewNet()->getNet()->getAttributeCarriers()->retrieveJunction(TLSNode->getID()));1678}1679// discard all previous changes1680discardChanges(false);1681// begin undo1682myTLSEditorParent->getViewNet()->getUndoList()->begin(GUIIcon::MODETLS, TL("reset TLS"));1683// set junction as priority (this will also remove all program, see GNEJunction::setJunctionType)1684for (const auto& TLSJunction : TLSJunctions) {1685TLSJunction->setAttribute(SUMO_ATTR_TYPE, toString(SumoXMLNodeType::PRIORITY), myTLSEditorParent->getViewNet()->getUndoList());1686}1687// create TLS in junction1688createTLS(junction);1689// set TLS in all other junctions1690for (const auto& TLSJunction : TLSJunctions) {1691if (TLSJunction != junction) {1692TLSJunction->setAttribute(SUMO_ATTR_TYPE, TLSJunction->getAttribute(SUMO_ATTR_TYPE), myTLSEditorParent->getViewNet()->getUndoList());1693TLSJunction->setAttribute(SUMO_ATTR_TLID, TLSJunction->getAttribute(SUMO_ATTR_TLID), myTLSEditorParent->getViewNet()->getUndoList());1694}1695}1696// end undo1697myTLSEditorParent->getViewNet()->getUndoList()->end();1698// edit junction1699myTLSEditorParent->editJunction(junction);1700return 1;1701}170217031704long1705GNETLSEditorFrame::TLSPrograms::onCmdDefSwitchTLSProgram(FXObject*, FXSelector, void*) {1706// check if program is valid (user may input arbitrary text)1707bool found = false;1708for (const auto& TLSPrograms : myTLSPrograms) {1709if (TLSPrograms->getProgramID() == myProgramComboBox->getText().text()) {1710found = true;1711break;1712}1713}1714if (!found) {1715// reset field to a valid program1716myProgramComboBox->setText(myTLSPrograms.front()->getProgramID().c_str());1717}1718switchProgram();1719return 1;1720}172117221723long1724GNETLSEditorFrame::TLSPrograms::onCmdSaveChanges(FXObject*, FXSelector, void*) {1725// get junction copy1726const auto currentJunction = myTLSEditorParent->myTLSJunction->getCurrentJunction();1727// get current program1728const auto currentProgram = myProgramComboBox->getCurrentItem();1729// check that junction is valid1730if (currentJunction != nullptr) {1731const auto oldDefinition = getCurrentTLSPrograms();1732std::vector<NBNode*> nodes = oldDefinition->getNodes();1733GNEUndoList* undoList = myTLSEditorParent->getViewNet()->getUndoList();1734for (const auto& node : nodes) {1735GNEJunction* junction = myTLSEditorParent->getViewNet()->getNet()->getAttributeCarriers()->retrieveJunction(node->getID());1736undoList->add(new GNEChange_TLS(junction, oldDefinition, false), true);1737undoList->add(new GNEChange_TLS(junction, myTLSEditorParent->myEditedDef, true), true);1738// synchronize crossing tl-indices in case they were changed (via onCmdCleanStates)1739for (const auto& gc : junction->getGNECrossings()) {1740NBNode::Crossing* c = gc->getNBCrossing();1741if (c) {1742gc->setAttribute(SUMO_ATTR_TLLINKINDEX, toString(c->tlLinkIndex), undoList);1743gc->setAttribute(SUMO_ATTR_TLLINKINDEX2, toString(c->tlLinkIndex2), undoList);1744}1745}174617471748}1749// end change1750myTLSEditorParent->getViewNet()->getUndoList()->end();1751// mark as saved1752myHaveModifications = false;1753// reset myEditedDef (because is already in eine undo-list)1754myTLSEditorParent->myEditedDef = nullptr;1755myTLSEditorParent->cleanup();1756myTLSEditorParent->getViewNet()->updateViewNet();1757// edit junction again1758myTLSEditorParent->editJunction(currentJunction);1759// change program1760myProgramComboBox->setCurrentItem(currentProgram, TRUE);1761} else {1762// discard changes inspecting junction again1763discardChanges(true);1764}1765myTLSEditorParent->updateModules();1766return 1;1767}176817691770long1771GNETLSEditorFrame::TLSPrograms::onCmdDiscardChanges(FXObject*, FXSelector, void*) {1772// discard changes inspecting junction again1773discardChanges(true);1774return 1;1775}177617771778void1779GNETLSEditorFrame::TLSPrograms::createTLS(GNEJunction* junction) {1780// get current TLS program id1781const auto currentTLS = getCurrentTLSProgramID();1782// check conditions1783if (junction == nullptr) {1784throw ProcessError("junction cannot be null");1785} else if (junction->getAttribute(SUMO_ATTR_TYPE) != toString(SumoXMLNodeType::TRAFFIC_LIGHT)) {1786// set junction as TLS1787junction->setAttribute(SUMO_ATTR_TYPE, toString(SumoXMLNodeType::TRAFFIC_LIGHT), myTLSEditorParent->getViewNet()->getUndoList());1788} else if (junction->getNBNode()->isTLControlled()) {1789// use existing traffic light as template for type, signal groups, controlled nodes etc1790NBTrafficLightDefinition* tpl = nullptr;1791for (const auto& TLS : junction->getNBNode()->getControllingTLS()) {1792if (TLS->getProgramID() == currentTLS) {1793tpl = TLS;1794}1795}1796// if template is empty, use first TLS1797if (tpl == nullptr) {1798tpl = *junction->getNBNode()->getControllingTLS().begin();1799}1800// create new logic1801NBTrafficLightLogic* newLogic = tpl->compute(OptionsCont::getOptions());1802// create new TLDef1803NBLoadedSUMOTLDef* newDef = new NBLoadedSUMOTLDef(*tpl, *newLogic);1804NBTrafficLightLogicCont& tllCont = myTLSEditorParent->getViewNet()->getNet()->getTLLogicCont();1805newDef->setProgramID(tllCont.getNextProgramID(newDef->getID()));1806// remove new logic1807delete newLogic;1808// add it using GNEChange_TLS1809myTLSEditorParent->getViewNet()->getUndoList()->begin(GUIIcon::MODETLS, TLF("duplicate program '%' of traffic light '%'", tpl->getProgramID(), tpl->getID()));1810for (NBNode* node : newDef->getNodes()) {1811GNEJunction* j = myTLSEditorParent->getViewNet()->getNet()->getAttributeCarriers()->retrieveJunction(node->getID());1812// not forcing insertion because we already ensured a new id and multiple junctions will attempt insertion1813myTLSEditorParent->getViewNet()->getUndoList()->add(new GNEChange_TLS(j, newDef, true, false), true);1814}1815myTLSEditorParent->getViewNet()->getUndoList()->end();1816} else {1817// for some reason the traffic light was not built, try again1818myTLSEditorParent->getViewNet()->getUndoList()->add(new GNEChange_TLS(junction, nullptr, true, true), true);1819}1820}182118221823bool1824GNETLSEditorFrame::TLSPrograms::switchProgram() {1825if (myTLSEditorParent->myTLSJunction->getCurrentJunction() == nullptr) {1826throw ProcessError("Junction cannot be NULL");1827} else {1828// reset save flag1829myHaveModifications = false;1830// get current definition1831NBTrafficLightDefinition* tlDef = getCurrentTLSPrograms();1832// logic may not have been recomputed yet. recompute to be sure1833NBTrafficLightLogicCont& tllCont = myTLSEditorParent->getViewNet()->getNet()->getTLLogicCont();1834// compute junction1835myTLSEditorParent->getViewNet()->getNet()->computeJunction(myTLSEditorParent->myTLSJunction->getCurrentJunction());1836// obtain TrafficLight logic vinculated with tlDef1837NBTrafficLightLogic* tllogic = tllCont.getLogic(tlDef->getID(), tlDef->getProgramID());1838// check that tllLogic exist1839if (tllogic != nullptr) {1840// now we can be sure that the tlDef is up to date (i.e. re-guessed)1841myTLSEditorParent->buildInternalLanes(tlDef);1842// create working duplicate from original def1843delete myTLSEditorParent->myEditedDef;1844myTLSEditorParent->myEditedDef = new NBLoadedSUMOTLDef(*tlDef, *tllogic);1845// set values1846myTLSEditorParent->myTLSAttributes->setOffset(myTLSEditorParent->myEditedDef->getLogic()->getOffset());1847myTLSEditorParent->myTLSAttributes->setParameters(myTLSEditorParent->myEditedDef->getLogic()->getParametersStr());1848// init phaseTable with the new TLS1849myTLSEditorParent->myTLSPhases->initPhaseTable();1850} else {1851// tlDef has no valid logic (probably because id does not control any links1852discardChanges(false);1853myTLSEditorParent->getViewNet()->setStatusBarText(TL("Traffic Light does not control any links"));1854return false;1855}1856}1857return true;1858}18591860// ---------------------------------------------------------------------------1861// GNETLSEditorFrame::TLSPhases - methods1862// ---------------------------------------------------------------------------18631864GNETLSEditorFrame::TLSPhases::TLSPhases(GNETLSEditorFrame* TLSEditorParent) :1865MFXGroupBoxModule(TLSEditorParent, TL("Phases"), MFXGroupBoxModule::Options::COLLAPSIBLE | MFXGroupBoxModule::Options::EXTENSIBLE),1866myTLSEditorParent(TLSEditorParent) {1867// create GNETLSTable1868myPhaseTable = new GNETLSTable(this);1869// hide phase table1870myPhaseTable->hide();1871FXHorizontalFrame* phaseButtons = new FXHorizontalFrame(getCollapsableFrame(), GUIDesignAuxiliarHorizontalFrameUniform);1872FXVerticalFrame* col1 = new FXVerticalFrame(phaseButtons, GUIDesignAuxiliarHorizontalFrame); // left button columm1873FXVerticalFrame* col2 = new FXVerticalFrame(phaseButtons, GUIDesignAuxiliarHorizontalFrame); // right button column1874// create cleanup states button1875myCleanStatesButton = new MFXButtonTooltip(col1, TLSEditorParent->getViewNet()->getViewParent()->getGNEAppWindows()->getStaticTooltipMenu(),1876TL("Clean States") + std::string("\t") +1877TL("Clean unused states from all phase") + std::string("\t") +1878TL("Clean unused states from all phase. (Not allowed for multiple programs)"),1879nullptr, this, MID_GNE_TLSFRAME_PHASES_CLEANUP, GUIDesignButton);1880myCleanStatesButton->disable();1881// add unused states button1882myAddStates = new MFXButtonTooltip(col2, TLSEditorParent->getViewNet()->getViewParent()->getGNEAppWindows()->getStaticTooltipMenu(),1883TL("Add States") + std::string("\t") +1884TL("Extend the state vector for all phases by one entry") + std::string("\t") +1885TL("Extend the state vector for all phases by one entry. (Unused until a connection or crossing is assigned to the new index)"),1886nullptr, this, MID_GNE_TLSFRAME_PHASES_ADDUNUSED, GUIDesignButton);1887myAddStates->disable();1888// group states button1889myGroupSignalsButton = new MFXButtonTooltip(col1, TLSEditorParent->getViewNet()->getViewParent()->getGNEAppWindows()->getStaticTooltipMenu(),1890TL("Group Sig.") + std::string("\t") +1891TL("Shorten state definition by letting connections with the same signal states use the same index") + std::string("\t") +1892TL("Shorten state definition by letting connections with the same signal states use the same index. (Not allowed for multiple programs)"),1893nullptr, this, MID_GNE_TLSFRAME_PHASES_GROUPSTATES, GUIDesignButton);1894myGroupSignalsButton->disable();1895// ungroup states button1896myUngroupSignalsButton = new MFXButtonTooltip(col2, TLSEditorParent->getViewNet()->getViewParent()->getGNEAppWindows()->getStaticTooltipMenu(),1897TL("Ungroup Sig.") + std::string("\t") +1898TL("Let every connection use a distinct index (reverse state grouping)") + std::string("\t") +1899TL("Let every connection use a distinct index (reverse state grouping). (Not allowed for multiple programs)"),1900nullptr, this, MID_GNE_TLSFRAME_PHASES_UNGROUPSTATES, GUIDesignButton);1901myUngroupSignalsButton->disable();1902// show TLSFile1903show();1904}190519061907GNETLSEditorFrame::TLSPhases::~TLSPhases() {1908}190919101911void1912GNETLSEditorFrame::TLSPhases::updateTLSPhases() {1913if (myTLSEditorParent->myTLSAttributes->isSetDetectorsToggleButtonEnabled()) {1914// selecting E1, disable buttons1915myPhaseTable->disable();1916myCleanStatesButton->disable();1917myAddStates->disable();1918myGroupSignalsButton->disable();1919myUngroupSignalsButton->disable();1920} else if (myTLSEditorParent->myTLSJunction->isJoiningJunctions()) {1921// joining TLSs, disable buttons1922myPhaseTable->disable();1923myCleanStatesButton->disable();1924myAddStates->disable();1925myGroupSignalsButton->disable();1926myUngroupSignalsButton->disable();1927myUngroupSignalsButton->disable();1928} else if (myTLSEditorParent->myTLSPrograms->getNumberOfPrograms() == 0) {1929// no TLSs, disable buttons1930myPhaseTable->disable();1931myCleanStatesButton->disable();1932myAddStates->disable();1933myGroupSignalsButton->disable();1934myUngroupSignalsButton->disable();1935} else if (myTLSEditorParent->myEditedDef == nullptr) {1936// no edited definition, disable buttons1937myPhaseTable->disable();1938myCleanStatesButton->disable();1939myAddStates->disable();1940myGroupSignalsButton->disable();1941myUngroupSignalsButton->disable();1942} else {1943myPhaseTable->enable();1944myCleanStatesButton->enable();1945myAddStates->enable();1946myGroupSignalsButton->enable();1947if (myTLSEditorParent->myEditedDef->usingSignalGroups()) {1948myUngroupSignalsButton->enable();1949} else {1950myUngroupSignalsButton->disable();1951}1952}1953}195419551956void1957GNETLSEditorFrame::TLSPhases::showTLSPhases() {1958show();1959}196019611962void1963GNETLSEditorFrame::TLSPhases::hideTLSPhases() {1964hide();1965}196619671968GNETLSEditorFrame*1969GNETLSEditorFrame::TLSPhases::getTLSEditorParent() const {1970return myTLSEditorParent;1971}197219731974GNETLSTable*1975GNETLSEditorFrame::TLSPhases::getPhaseTable() const {1976return myPhaseTable;1977}197819791980void1981GNETLSEditorFrame::TLSPhases::initPhaseTable() {1982// first clear table1983clearPhaseTable();1984if (myTLSEditorParent->myTLSPrograms->getNumberOfPrograms() > 0) {1985if (myTLSEditorParent->myEditedDef->getType() == TrafficLightType::STATIC) {1986initStaticPhaseTable();1987} else if (myTLSEditorParent->myEditedDef->getType() == TrafficLightType::ACTUATED) {1988initActuatedPhaseTable();1989} else if (myTLSEditorParent->myEditedDef->getType() == TrafficLightType::DELAYBASED) {1990initDelayBasePhaseTable();1991} else if (myTLSEditorParent->myEditedDef->getType() == TrafficLightType::NEMA) {1992initNEMAPhaseTable();1993}1994// select first element (by default)1995myPhaseTable->selectRow(0);1996// recalc width and show1997myPhaseTable->recalcTableWidth();1998myPhaseTable->show();1999} else {2000myPhaseTable->hide();2001}2002update();2003}200420052006void2007GNETLSEditorFrame::TLSPhases::clearPhaseTable() {2008myPhaseTable->clearTable();2009}201020112012bool2013GNETLSEditorFrame::TLSPhases::changePhaseValue(const int col, const int row, const std::string& value) {2014// Declare columns2015int colDuration = 1;2016int colState = -1;2017int colNext = -1;2018int colName = -1;2019int colMinDur = -1;2020int colMaxDur = -1;2021int colEarliestEnd = -1;2022int colLatestEnd = -1;2023int colVehExt = -1;2024int colYellow = -1;2025int colRed = -1;2026// set columns depending of traffic light type2027if (myTLSEditorParent->myEditedDef->getType() == TrafficLightType::STATIC) {2028colState = 2;2029colNext = 3;2030colName = 4;2031} else if (myTLSEditorParent->myEditedDef->getType() == TrafficLightType::ACTUATED) {2032colMinDur = 2;2033colMaxDur = 3;2034colState = 4;2035colEarliestEnd = 5;2036colLatestEnd = 6;2037colNext = 7;2038colName = 8;2039} else if (myTLSEditorParent->myEditedDef->getType() == TrafficLightType::DELAYBASED) {2040colMinDur = 2;2041colMaxDur = 3;2042colState = 4;2043colNext = 5;2044colName = 6;2045} else if (myTLSEditorParent->myEditedDef->getType() == TrafficLightType::NEMA) {2046colMinDur = 2;2047colMaxDur = 3;2048colState = 4;2049colVehExt = 5;2050colYellow = 6;2051colRed = 7;2052colNext = 8;2053colName = 9;2054}2055// check column2056if (col == colDuration) {2057return setDuration(col, row, value);2058} else if (col == colState) {2059return setState(col, row, value);2060} else if (col == colNext) {2061return setNext(row, value);2062} else if (col == colName) {2063return setName(row, value);2064} else if (col == colMinDur) {2065return setMinDur(row, value);2066} else if (col == colMaxDur) {2067return setMaxDur(row, value);2068} else if (col == colEarliestEnd) {2069return setEarliestEnd(row, value);2070} else if (col == colLatestEnd) {2071return setLatestEnd(row, value);2072} else if (col == colVehExt) {2073return setVehExt(row, value);2074} else if (col == colYellow) {2075return setYellow(row, value);2076} else if (col == colRed) {2077return setRed(row, value);2078} else {2079throw ProcessError(TL("invalid column"));2080}2081}208220832084void2085GNETLSEditorFrame::TLSPhases::addPhase(const int row, const char c) {2086// mark TLS as modified2087myTLSEditorParent->myTLSPrograms->markAsModified();2088// build default phase2089const int newIndex = buildDefaultPhase(row);2090// check if override state2091switch (c) {2092case 'r':2093case 'y':2094case 'g':2095case 'G':2096myTLSEditorParent->myEditedDef->getLogic()->overrideState(newIndex, c);2097break;2098default:2099break;2100}2101// int phase table again2102initPhaseTable();2103// mark new row as selected2104myPhaseTable->selectRow(newIndex);2105// set focus in table2106getPhaseTable()->setFocus();2107}210821092110void2111GNETLSEditorFrame::TLSPhases::duplicatePhase(const int row) {2112// mark TLS as modified2113myTLSEditorParent->myTLSPrograms->markAsModified();2114// build default phase2115const int newIndex = buildDefaultPhase(row);2116// coply old phase in the new phase2117myTLSEditorParent->myEditedDef->getLogic()->copyPhase(row, row + 1);2118// int phase table again2119initPhaseTable();2120// mark new row as selected2121myPhaseTable->selectRow(newIndex);2122// set focus in table2123getPhaseTable()->setFocus();2124}212521262127void2128GNETLSEditorFrame::TLSPhases::removePhase(const int row) {2129// mark TLS ad modified2130myTLSEditorParent->myTLSPrograms->markAsModified();2131// calculate new row2132const auto newRow = MAX2(0, (row - 1));2133// delete selected row2134myTLSEditorParent->myEditedDef->getLogic()->deletePhase(row);2135// int phase table again2136initPhaseTable();2137// mark new row as selected2138myPhaseTable->selectRow(newRow);2139// set focus in table2140getPhaseTable()->setFocus();2141}214221432144void2145GNETLSEditorFrame::TLSPhases::movePhaseUp(const int row) {2146// mark TLS ad modified2147myTLSEditorParent->myTLSPrograms->markAsModified();2148// delete selected row2149if (row == 0) {2150myTLSEditorParent->myEditedDef->getLogic()->swapfirstPhase();2151} else {2152myTLSEditorParent->myEditedDef->getLogic()->swapPhase(row, row - 1);2153}2154// int phase table again2155initPhaseTable();2156// mark new row as selected2157if (row == 0) {2158myPhaseTable->selectRow((int)myTLSEditorParent->myEditedDef->getLogic()->getPhases().size() - 1);2159} else {2160myPhaseTable->selectRow(row - 1);2161}2162// set focus in table2163getPhaseTable()->setFocus();2164}216521662167void2168GNETLSEditorFrame::TLSPhases::movePhaseDown(const int row) {2169// mark TLS ad modified2170myTLSEditorParent->myTLSPrograms->markAsModified();2171// delete selected row2172if (row == (int)myTLSEditorParent->myEditedDef->getLogic()->getPhases().size() - 1) {2173myTLSEditorParent->myEditedDef->getLogic()->swaplastPhase();2174} else {2175myTLSEditorParent->myEditedDef->getLogic()->swapPhase(row, row + 1);2176}2177// int phase table again2178initPhaseTable();2179// mark new row as selected2180if (row == (int)myTLSEditorParent->myEditedDef->getLogic()->getPhases().size() - 1) {2181myPhaseTable->selectRow(0);2182} else {2183myPhaseTable->selectRow(row + 1);2184}2185// set focus in table2186getPhaseTable()->setFocus();2187}218821892190void2191GNETLSEditorFrame::TLSPhases::updateTLSColoring() {2192// get phase2193const auto& phase = myTLSEditorParent->getPhase(myPhaseTable->getCurrentSelectedRow());2194// need not hold since links could have been deleted somewhere else and indices may be reused2195for (const auto& internalLane : myTLSEditorParent->myInternalLanes) {2196int tlIndex = internalLane.first;2197std::vector<GNEInternalLane*> lanes = internalLane.second;2198LinkState state = LINKSTATE_DEADEND;2199if (tlIndex >= 0 && tlIndex < (int)phase.state.size()) {2200state = (LinkState)phase.state[tlIndex];2201}2202for (const auto& lane : lanes) {2203lane->setLinkState(state);2204}2205}2206// update view net (for coloring)2207myTLSEditorParent->getViewNet()->updateViewNet();2208}220922102211long2212GNETLSEditorFrame::TLSPhases::onCmdCleanStates(FXObject*, FXSelector, void*) {2213if (myTLSEditorParent->myEditedDef->cleanupStates()) {2214myTLSEditorParent->myTLSPrograms->markAsModified();2215}2216myTLSEditorParent->buildInternalLanes(myTLSEditorParent->myEditedDef);2217initPhaseTable();2218myPhaseTable->setFocus();2219myTLSEditorParent->myTLSPrograms->markAsModified();2220myTLSEditorParent->updateModules();2221return 1;2222}222322242225long2226GNETLSEditorFrame::TLSPhases::onCmdAddUnusedStates(FXObject*, FXSelector, void*) {2227myTLSEditorParent->myEditedDef->getLogic()->setStateLength(myTLSEditorParent->myEditedDef->getLogic()->getNumLinks() + 1);2228myTLSEditorParent->myTLSPrograms->markAsModified();2229initPhaseTable();2230myPhaseTable->setFocus();2231myTLSEditorParent->updateModules();2232return 1;2233}223422352236long2237GNETLSEditorFrame::TLSPhases::onCmdGroupStates(FXObject*, FXSelector, void*) {2238myTLSEditorParent->myEditedDef->groupSignals();2239myTLSEditorParent->myTLSPrograms->markAsModified();2240myTLSEditorParent->buildInternalLanes(myTLSEditorParent->myEditedDef);2241initPhaseTable();2242myPhaseTable->setFocus();2243myTLSEditorParent->updateModules();2244return 1;2245}224622472248long2249GNETLSEditorFrame::TLSPhases::onCmdUngroupStates(FXObject*, FXSelector, void*) {2250myTLSEditorParent->myEditedDef->setParticipantsInformation();2251myTLSEditorParent->myEditedDef->ungroupSignals();2252myTLSEditorParent->myTLSPrograms->markAsModified();2253myTLSEditorParent->buildInternalLanes(myTLSEditorParent->myEditedDef);2254initPhaseTable();2255myPhaseTable->setFocus();2256myTLSEditorParent->updateModules();2257return 1;2258}225922602261void2262GNETLSEditorFrame::TLSPhases::initStaticPhaseTable() {2263// declare constants for columns2264const int colDuration = 1;2265const int colState = 2;2266const int colNext = 3;2267const int colName = 4;2268// get phases2269const auto& phases = myTLSEditorParent->myEditedDef->getLogic()->getPhases();2270// adjust table2271myPhaseTable->setTableSize("sup-midtb", (int)phases.size());2272// fill rows2273for (int row = 0; row < (int)phases.size(); row++) {2274myPhaseTable->setItemText(row, colDuration, getSteps2Time(phases.at(row).duration).c_str());2275myPhaseTable->setItemText(row, colState, phases.at(row).state.c_str());2276myPhaseTable->setItemText(row, colNext, phases.at(row).next.size() > 0 ? toString(phases.at(row).next).c_str() : "");2277myPhaseTable->setItemText(row, colName, phases.at(row).name.c_str());2278}2279// set columns2280myPhaseTable->setColumnLabelTop(colDuration, "dur");2281myPhaseTable->setColumnLabelTop(colState, "state");2282myPhaseTable->setColumnLabelTop(colNext, "next");2283myPhaseTable->setColumnLabelTop(colName, "name");2284// set bot labels2285updateCycleDuration(colDuration);2286updateStateSize(colState);2287// set focus2288myPhaseTable->setFocus();2289}229022912292void2293GNETLSEditorFrame::TLSPhases::initActuatedPhaseTable() {2294// declare constants for columns2295const int colDuration = 1;2296const int colMinDur = 2;2297const int colMaxDur = 3;2298const int colState = 4;2299const int colEarliestEnd = 5;2300const int colLatestEnd = 6;2301const int colNext = 7;2302const int colName = 8;2303// get phases2304const auto& phases = myTLSEditorParent->myEditedDef->getLogic()->getPhases();2305// adjust table2306myPhaseTable->setTableSize("suffpff-midtb", (int)phases.size());2307// fill rows2308for (int row = 0; row < (int)phases.size(); row++) {2309myPhaseTable->setItemText(row, colDuration, getSteps2Time(phases.at(row).duration).c_str());2310myPhaseTable->setItemText(row, colMinDur, varDurString(phases.at(row).minDur).c_str());2311myPhaseTable->setItemText(row, colMaxDur, varDurString(phases.at(row).maxDur).c_str());2312myPhaseTable->setItemText(row, colState, phases.at(row).state.c_str());2313myPhaseTable->setItemText(row, colEarliestEnd, varDurString(phases.at(row).earliestEnd).c_str());2314myPhaseTable->setItemText(row, colLatestEnd, varDurString(phases.at(row).latestEnd).c_str());2315myPhaseTable->setItemText(row, colNext, phases.at(row).next.size() > 0 ? toString(phases.at(row).next).c_str() : "");2316myPhaseTable->setItemText(row, colName, phases.at(row).name.c_str());2317}2318// set columns2319myPhaseTable->setColumnLabelTop(colDuration, "dur");2320myPhaseTable->setColumnLabelTop(colMinDur, "min");2321myPhaseTable->setColumnLabelTop(colMaxDur, "max");2322myPhaseTable->setColumnLabelTop(colEarliestEnd, "ear.end", "earlyEnd");2323myPhaseTable->setColumnLabelTop(colLatestEnd, "lat.end", "latestEnd");2324myPhaseTable->setColumnLabelTop(colState, "state");2325myPhaseTable->setColumnLabelTop(colNext, "next");2326myPhaseTable->setColumnLabelTop(colName, "name");2327// set bot labels2328updateCycleDuration(colDuration);2329updateStateSize(colState);2330// set focus2331myPhaseTable->setFocus();2332}233323342335void2336GNETLSEditorFrame::TLSPhases::initDelayBasePhaseTable() {2337// declare constants for columns2338const int colDuration = 1;2339const int colMinDur = 2;2340const int colMaxDur = 3;2341const int colState = 4;2342const int colNext = 5;2343const int colName = 6;2344// get phases2345const auto& phases = myTLSEditorParent->myEditedDef->getLogic()->getPhases();2346// adjust table2347myPhaseTable->setTableSize("suffp-midtb", (int)phases.size());2348// fill rows2349for (int row = 0; row < (int)phases.size(); row++) {2350myPhaseTable->setItemText(row, colDuration, getSteps2Time(phases.at(row).duration).c_str());2351myPhaseTable->setItemText(row, colMinDur, varDurString(phases.at(row).minDur).c_str());2352myPhaseTable->setItemText(row, colMaxDur, varDurString(phases.at(row).maxDur).c_str());2353myPhaseTable->setItemText(row, colState, phases.at(row).state.c_str());2354myPhaseTable->setItemText(row, colNext, phases.at(row).next.size() > 0 ? toString(phases.at(row).next).c_str() : "");2355myPhaseTable->setItemText(row, colName, phases.at(row).name.c_str());2356}2357// set columns2358myPhaseTable->setColumnLabelTop(colDuration, "dur");2359myPhaseTable->setColumnLabelTop(colMinDur, "min");2360myPhaseTable->setColumnLabelTop(colMaxDur, "max");2361myPhaseTable->setColumnLabelTop(colState, "state");2362myPhaseTable->setColumnLabelTop(colNext, "next");2363myPhaseTable->setColumnLabelTop(colName, "name");2364// set bot labels2365updateCycleDuration(colDuration);2366updateStateSize(colState);2367// set focus2368myPhaseTable->setFocus();2369}237023712372void2373GNETLSEditorFrame::TLSPhases::initNEMAPhaseTable() {2374// declare constants for columns2375const int colDuration = 1;2376const int colMinDur = 2;2377const int colMaxDur = 3;2378const int colState = 4;2379const int colVehExt = 5;2380const int colYellow = 6;2381const int colRed = 7;2382const int colNext = 8;2383const int colName = 9;2384// get phases2385const auto& phases = myTLSEditorParent->myEditedDef->getLogic()->getPhases();2386// adjust table2387myPhaseTable->setTableSize("suffpfff-midtb", (int)phases.size());2388// fill rows2389for (int row = 0; row < (int)phases.size(); row++) {2390myPhaseTable->setItemText(row, colDuration, getSteps2Time(phases.at(row).duration).c_str());2391myPhaseTable->setItemText(row, colMinDur, varDurString(phases.at(row).minDur).c_str());2392myPhaseTable->setItemText(row, colMaxDur, varDurString(phases.at(row).maxDur).c_str());2393myPhaseTable->setItemText(row, colState, phases.at(row).state.c_str());2394myPhaseTable->setItemText(row, colVehExt, varDurString(phases.at(row).vehExt).c_str());2395myPhaseTable->setItemText(row, colYellow, varDurString(phases.at(row).yellow).c_str());2396myPhaseTable->setItemText(row, colRed, varDurString(phases.at(row).red).c_str());2397myPhaseTable->setItemText(row, colNext, phases.at(row).next.size() > 0 ? toString(phases.at(row).next).c_str() : "");2398myPhaseTable->setItemText(row, colName, phases.at(row).name.c_str());2399}2400// set columns2401myPhaseTable->setColumnLabelTop(colDuration, "dur");2402myPhaseTable->setColumnLabelTop(colMinDur, "min");2403myPhaseTable->setColumnLabelTop(colMaxDur, "max");2404myPhaseTable->setColumnLabelTop(colState, "state");2405myPhaseTable->setColumnLabelTop(colVehExt, "vehExt", "vehicle extension");2406myPhaseTable->setColumnLabelTop(colYellow, "yellow");2407myPhaseTable->setColumnLabelTop(colRed, "red");2408myPhaseTable->setColumnLabelTop(colNext, "next");2409myPhaseTable->setColumnLabelTop(colName, "name");2410// set bot labels2411updateCycleDuration(colDuration);2412updateStateSize(colState);2413// set focus2414myPhaseTable->setFocus();2415}241624172418int2419GNETLSEditorFrame::TLSPhases::buildDefaultPhase(const int row) {2420// get option container2421const auto& neteditOptions = OptionsCont::getOptions();2422// check if TLS is static2423const bool TLSStatic = (myTLSEditorParent->myEditedDef->getType() == TrafficLightType::STATIC);2424const bool NEMA = (myTLSEditorParent->myEditedDef->getType() == TrafficLightType::NEMA);2425// calculate new index2426const int newIndex = row + 1;2427// duplicate current row2428auto duration = getSUMOTime(myPhaseTable->getItemText(row, 1));2429const auto oldState = myPhaseTable->getItemText(row, TLSStatic ? 2 : 4);2430auto state = oldState;2431// update crossingINdices2432std::set<int> crossingIndices;2433for (const auto& node : myTLSEditorParent->myEditedDef->getNodes()) {2434for (const auto& crossing : node->getCrossings()) {2435crossingIndices.insert(crossing->tlLinkIndex);2436crossingIndices.insert(crossing->tlLinkIndex2);2437}2438}2439// smart adapations for new state2440bool haveGreen = false;2441bool haveYellow = false;2442for (const auto& linkStateChar : state) {2443if ((linkStateChar == LINKSTATE_TL_GREEN_MAJOR) || (linkStateChar == LINKSTATE_TL_GREEN_MINOR)) {2444haveGreen = true;2445} else if ((linkStateChar == LINKSTATE_TL_YELLOW_MAJOR) || (linkStateChar == LINKSTATE_TL_YELLOW_MINOR)) {2446haveYellow = true;2447}2448}2449if (haveGreen && haveYellow) {2450// guess left-mover state2451duration = TIME2STEPS(neteditOptions.getInt("tls.left-green.time"));2452for (int i = 0; i < (int)state.size(); i++) {2453if ((state[i] == LINKSTATE_TL_YELLOW_MAJOR) || (state[i] == LINKSTATE_TL_YELLOW_MINOR)) {2454state[i] = LINKSTATE_TL_RED;2455} else if (state[i] == LINKSTATE_TL_GREEN_MINOR) {2456state[i] = LINKSTATE_TL_GREEN_MAJOR;2457}2458}2459} else if (haveGreen) {2460// guess yellow state2461myTLSEditorParent->myEditedDef->setParticipantsInformation();2462duration = TIME2STEPS(myTLSEditorParent->myEditedDef->computeBrakingTime(neteditOptions.getFloat("tls.yellow.min-decel")));2463for (int i = 0; i < (int)state.size(); i++) {2464if ((state[i] == LINKSTATE_TL_GREEN_MAJOR) || (state[i] == LINKSTATE_TL_GREEN_MINOR)) {2465if (crossingIndices.count(i) == 0) {2466state[i] = LINKSTATE_TL_YELLOW_MINOR;2467} else {2468state[i] = LINKSTATE_TL_RED;2469}2470}2471}2472} else if (haveYellow) {2473duration = TIME2STEPS(neteditOptions.isDefault("tls.allred.time") ? 2 : neteditOptions.getInt("tls.allred.time"));2474// guess all-red state2475for (int i = 0; i < (int)state.size(); i++) {2476if ((state[i] == LINKSTATE_TL_YELLOW_MAJOR) || (state[i] == LINKSTATE_TL_YELLOW_MINOR)) {2477state[i] = LINKSTATE_TL_RED;2478}2479}2480}2481// fix continuous green states2482const int nextIndex = (myPhaseTable->getNumRows() > newIndex) ? newIndex : 0;2483const std::string state2 = myPhaseTable->getItemText(nextIndex, (TLSStatic ? 2 : 4));2484for (int i = 0; i < (int)state.size(); i++) {2485if (((oldState[i] == LINKSTATE_TL_GREEN_MAJOR) || (oldState[i] == LINKSTATE_TL_GREEN_MINOR)) &&2486((state2[i] == LINKSTATE_TL_GREEN_MAJOR) || (state2[i] == LINKSTATE_TL_GREEN_MINOR))) {2487state[i] = oldState[i];2488}2489}2490// add new step2491if (NEMA) {2492myTLSEditorParent->myEditedDef->getLogic()->addStep(string2time("90"), state, string2time("5"), string2time("50"),2493NBTrafficLightDefinition::UNSPECIFIED_DURATION, NBTrafficLightDefinition::UNSPECIFIED_DURATION,2494string2time("2"), string2time("3"), string2time("2"), "1", std::vector<int>(), newIndex);2495} else {2496myTLSEditorParent->myEditedDef->getLogic()->addStep(duration, state, std::vector<int>(), "", newIndex);2497}2498// return new index2499return newIndex;2500}250125022503bool2504GNETLSEditorFrame::TLSPhases::setDuration(const int col, const int row, const std::string& value) {2505// check value2506if (value.empty()) {2507// input empty, reset2508getPhaseTable()->setItemText(row, col, getSteps2Time(myTLSEditorParent->getPhase(row).duration).c_str());2509return true;2510} else if (GNEAttributeCarrier::canParse<double>(value)) {2511const auto duration = getSUMOTime(value);2512// check that duration > 02513if (duration > 0) {2514myTLSEditorParent->myEditedDef->getLogic()->setPhaseDuration(row, duration);2515myTLSEditorParent->myTLSPrograms->markAsModified();2516// update Cycle duration2517updateCycleDuration(col);2518return true;2519} else {2520return false;2521}2522} else {2523return false;2524}2525}252625272528bool2529GNETLSEditorFrame::TLSPhases::setState(const int col, const int row, const std::string& value) {2530// get state2531const auto& phase = myTLSEditorParent->getPhase(row);2532// declare new state. If value is empty, use previous value (reset)2533const auto newState = value.empty() ? phase.state : value;2534// insert phase2535try {2536myTLSEditorParent->myEditedDef->getLogic()->addStep(phase.duration, newState, phase.next, phase.name, row);2537} catch (ProcessError&) {2538// invalid character in newState2539return false;2540}2541// delete next phase2542try {2543myTLSEditorParent->myEditedDef->getLogic()->deletePhase(row + 1);2544} catch (InvalidArgument&) {2545WRITE_ERROR(TL("Error deleting phase '") + toString(row + 1) + "'");2546return false;2547}2548// mark TLS as modified depending of value2549if (value.size() > 0) {2550myTLSEditorParent->myTLSPrograms->markAsModified();2551// select row2552myPhaseTable->selectRow(row);2553} else {2554// input empty, reset2555getPhaseTable()->setItemText(row, col, newState);2556}2557// update state size2558updateStateSize(col);2559return true;2560}256125622563bool2564GNETLSEditorFrame::TLSPhases::setNext(const int row, const std::string& value) {2565// check next2566if (GNEAttributeCarrier::canParse<std::vector<int> >(value)) {2567const auto nextEdited = GNEAttributeCarrier::parse<std::vector<int> >(value);2568for (const auto nextPhase : nextEdited) {2569if ((nextPhase < 0) || (nextPhase >= myPhaseTable->getNumRows())) {2570return false;2571}2572}2573// set new next2574myTLSEditorParent->myEditedDef->getLogic()->setPhaseNext(row, nextEdited);2575myTLSEditorParent->myTLSPrograms->markAsModified();2576return true;2577} else {2578return false;2579}2580}258125822583bool2584GNETLSEditorFrame::TLSPhases::setName(const int row, const std::string& value) {2585// update name (currently no check needed)2586myTLSEditorParent->myEditedDef->getLogic()->setPhaseName(row, value);2587myTLSEditorParent->myTLSPrograms->markAsModified();2588return true;2589}259025912592bool2593GNETLSEditorFrame::TLSPhases::setMinDur(const int row, const std::string& value) {2594// check value2595if (value.empty()) {2596// set empty value2597myTLSEditorParent->myEditedDef->getLogic()->setPhaseMinDuration(row, NBTrafficLightDefinition::UNSPECIFIED_DURATION);2598myTLSEditorParent->myTLSPrograms->markAsModified();2599return true;2600} else if (GNEAttributeCarrier::canParse<double>(value)) {2601const auto minDur = getSUMOTime(value);2602// check that minDur > 02603if (minDur > 0) {2604myTLSEditorParent->myEditedDef->getLogic()->setPhaseMinDuration(row, minDur);2605myTLSEditorParent->myTLSPrograms->markAsModified();2606return true;2607} else {2608return false;2609}2610} else if (StringUtils::prune(value).empty()) {2611myTLSEditorParent->myEditedDef->getLogic()->setPhaseMinDuration(row, NBTrafficLightDefinition::UNSPECIFIED_DURATION);2612myTLSEditorParent->myTLSPrograms->markAsModified();2613return true;2614} else {2615return false;2616}2617}261826192620bool2621GNETLSEditorFrame::TLSPhases::setMaxDur(const int row, const std::string& value) {2622// check value2623if (value.empty()) {2624// set empty value2625myTLSEditorParent->myEditedDef->getLogic()->setPhaseMaxDuration(row, NBTrafficLightDefinition::UNSPECIFIED_DURATION);2626myTLSEditorParent->myTLSPrograms->markAsModified();2627return true;2628} else if (GNEAttributeCarrier::canParse<double>(value)) {2629const auto maxDur = getSUMOTime(value);2630// check that minDur > 02631if (maxDur > 0) {2632myTLSEditorParent->myEditedDef->getLogic()->setPhaseMaxDuration(row, maxDur);2633myTLSEditorParent->myTLSPrograms->markAsModified();2634return true;2635} else {2636return false;2637}2638} else if (StringUtils::prune(value).empty()) {2639myTLSEditorParent->myEditedDef->getLogic()->setPhaseMaxDuration(row, NBTrafficLightDefinition::UNSPECIFIED_DURATION);2640myTLSEditorParent->myTLSPrograms->markAsModified();2641return true;2642} else {2643return false;2644}2645}264626472648bool2649GNETLSEditorFrame::TLSPhases::setEarliestEnd(const int row, const std::string& value) {2650// check value2651if (value.empty()) {2652// set empty value2653myTLSEditorParent->myEditedDef->getLogic()->setPhaseEarliestEnd(row, NBTrafficLightDefinition::UNSPECIFIED_DURATION);2654myTLSEditorParent->myTLSPrograms->markAsModified();2655return true;2656} else if (GNEAttributeCarrier::canParse<double>(value)) {2657const auto earliestEnd = getSUMOTime(value);2658// check that earliestEnd > 02659if (earliestEnd > 0) {2660myTLSEditorParent->myEditedDef->getLogic()->setPhaseEarliestEnd(row, earliestEnd);2661myTLSEditorParent->myTLSPrograms->markAsModified();2662return true;2663} else {2664return false;2665}2666} else if (StringUtils::prune(value).empty()) {2667myTLSEditorParent->myEditedDef->getLogic()->setPhaseEarliestEnd(row, NBTrafficLightDefinition::UNSPECIFIED_DURATION);2668myTLSEditorParent->myTLSPrograms->markAsModified();2669return true;2670} else {2671return false;2672}2673}267426752676bool2677GNETLSEditorFrame::TLSPhases::setLatestEnd(const int row, const std::string& value) {2678// check value2679if (value.empty()) {2680// set empty value2681myTLSEditorParent->myEditedDef->getLogic()->setPhaseLatestEnd(row, NBTrafficLightDefinition::UNSPECIFIED_DURATION);2682myTLSEditorParent->myTLSPrograms->markAsModified();2683return true;2684} else if (GNEAttributeCarrier::canParse<double>(value)) {2685const auto latestEnd = getSUMOTime(value);2686// check that latestEnd > 02687if (latestEnd > 0) {2688myTLSEditorParent->myEditedDef->getLogic()->setPhaseLatestEnd(row, latestEnd);2689myTLSEditorParent->myTLSPrograms->markAsModified();2690return true;2691} else {2692return false;2693}2694} else if (StringUtils::prune(value).empty()) {2695myTLSEditorParent->myEditedDef->getLogic()->setPhaseLatestEnd(row, NBTrafficLightDefinition::UNSPECIFIED_DURATION);2696myTLSEditorParent->myTLSPrograms->markAsModified();2697return true;2698} else {2699return false;2700}2701}270227032704bool2705GNETLSEditorFrame::TLSPhases::setVehExt(const int row, const std::string& value) {2706// check value2707if (value.empty()) {2708// set empty value2709myTLSEditorParent->myEditedDef->getLogic()->setPhaseVehExt(row, NBTrafficLightDefinition::UNSPECIFIED_DURATION);2710myTLSEditorParent->myTLSPrograms->markAsModified();2711return true;2712} else if (GNEAttributeCarrier::canParse<double>(value)) {2713const auto vehExt = getSUMOTime(value);2714// check that vehExt > 02715if (vehExt > 0) {2716myTLSEditorParent->myEditedDef->getLogic()->setPhaseVehExt(row, vehExt);2717myTLSEditorParent->myTLSPrograms->markAsModified();2718return true;2719} else {2720return false;2721}2722} else if (StringUtils::prune(value).empty()) {2723myTLSEditorParent->myEditedDef->getLogic()->setPhaseVehExt(row, NBTrafficLightDefinition::UNSPECIFIED_DURATION);2724myTLSEditorParent->myTLSPrograms->markAsModified();2725return true;2726} else {2727return false;2728}2729}273027312732bool2733GNETLSEditorFrame::TLSPhases::setYellow(const int row, const std::string& value) {2734// check value2735if (value.empty()) {2736// set empty value2737myTLSEditorParent->myEditedDef->getLogic()->setPhaseYellow(row, NBTrafficLightDefinition::UNSPECIFIED_DURATION);2738myTLSEditorParent->myTLSPrograms->markAsModified();2739return true;2740} else if (GNEAttributeCarrier::canParse<double>(value)) {2741const auto yellow = getSUMOTime(value);2742// check that yellow > 02743if (yellow > 0) {2744myTLSEditorParent->myEditedDef->getLogic()->setPhaseYellow(row, yellow);2745myTLSEditorParent->myTLSPrograms->markAsModified();2746return true;2747} else {2748return false;2749}2750} else if (StringUtils::prune(value).empty()) {2751myTLSEditorParent->myEditedDef->getLogic()->setPhaseYellow(row, NBTrafficLightDefinition::UNSPECIFIED_DURATION);2752myTLSEditorParent->myTLSPrograms->markAsModified();2753return true;2754} else {2755return false;2756}2757}275827592760bool2761GNETLSEditorFrame::TLSPhases::setRed(const int row, const std::string& value) {2762// check value2763if (value.empty()) {2764// set empty value2765myTLSEditorParent->myEditedDef->getLogic()->setPhaseRed(row, NBTrafficLightDefinition::UNSPECIFIED_DURATION);2766myTLSEditorParent->myTLSPrograms->markAsModified();2767return true;2768} else if (GNEAttributeCarrier::canParse<double>(value)) {2769const auto red = getSUMOTime(value);2770// check that red > 02771if (red > 0) {2772myTLSEditorParent->myEditedDef->getLogic()->setPhaseRed(row, red);2773myTLSEditorParent->myTLSPrograms->markAsModified();2774return true;2775} else {2776return false;2777}2778} else if (StringUtils::prune(value).empty()) {2779myTLSEditorParent->myEditedDef->getLogic()->setPhaseRed(row, NBTrafficLightDefinition::UNSPECIFIED_DURATION);2780myTLSEditorParent->myTLSPrograms->markAsModified();2781return true;2782} else {2783return false;2784}2785}278627872788void2789GNETLSEditorFrame::TLSPhases::updateCycleDuration(const int col) {2790SUMOTime cycleDuration = 0;2791for (const auto& phase : myTLSEditorParent->myEditedDef->getLogic()->getPhases()) {2792cycleDuration += phase.duration;2793}2794// update bot label with cycle duration2795myPhaseTable->setColumnLabelBot(col, getSteps2Time(cycleDuration));2796}279727982799void2800GNETLSEditorFrame::TLSPhases::updateStateSize(const int col) {2801// update bot label with number of links2802myPhaseTable->setColumnLabelBot(col, "Links: " + toString(myTLSEditorParent->myEditedDef->getLogic()->getNumLinks()));2803}28042805// ---------------------------------------------------------------------------2806// GNETLSEditorFrame::TLSFile - methods2807// ---------------------------------------------------------------------------28082809GNETLSEditorFrame::TLSFile::TLSFile(GNETLSEditorFrame* TLSEditorParent) :2810MFXGroupBoxModule(TLSEditorParent, TL("TLS Program File")),2811myTLSEditorParent(TLSEditorParent) {2812FXHorizontalFrame* buttonsFrame = new FXHorizontalFrame(getCollapsableFrame(), GUIDesignAuxiliarHorizontalFrame);2813// create create tlDef button2814myLoadButton = GUIDesigns::buildFXButton(buttonsFrame, TL("Load"), "", TL("Load TLS program from additional file"), GUIIconSubSys::getIcon(GUIIcon::OPEN), this, MID_GNE_TLSFRAME_FILE_LOADPROGRAM, GUIDesignButton);2815myLoadButton->disable();2816// create create tlDef button2817mySaveButton = GUIDesigns::buildFXButton(buttonsFrame, TL("Save"), "", TL("Save TLS program to additional file"), GUIIconSubSys::getIcon(GUIIcon::SAVE), this, MID_GNE_TLSFRAME_FILE_SAVEPROGRAM, GUIDesignButton);2818mySaveButton->disable();2819// show TLSFile2820show();2821}282228232824GNETLSEditorFrame::TLSFile::~TLSFile() {}282528262827void2828GNETLSEditorFrame::TLSFile::updateTLSFile() {2829if (myTLSEditorParent->myTLSPrograms->getNumberOfPrograms() == 0) {2830myLoadButton->disable();2831mySaveButton->disable();2832} else if (myTLSEditorParent->myTLSAttributes->isSetDetectorsToggleButtonEnabled()) {2833// selecting E1, disable buttons2834myLoadButton->disable();2835mySaveButton->disable();2836} else if (myTLSEditorParent->myTLSJunction->isJoiningJunctions()) {2837// joining TLSs, disable button2838myLoadButton->disable();2839mySaveButton->disable();2840} else {2841myLoadButton->enable();2842mySaveButton->enable();2843}2844}284528462847void2848GNETLSEditorFrame::TLSFile::showTLSFile() {2849show();2850}285128522853void2854GNETLSEditorFrame::TLSFile::hideTLSFile() {2855hide();2856}285728582859long2860GNETLSEditorFrame::TLSFile::onCmdLoadTLSProgram(FXObject*, FXSelector, void*) {2861FXFileDialog opendialog(getCollapsableFrame(), "Load TLS Program");2862opendialog.setIcon(GUIIconSubSys::getIcon(GUIIcon::MODETLS));2863opendialog.setSelectMode(SELECTFILE_EXISTING);2864opendialog.setPatternList(SUMOXMLDefinitions::XMLFileExtensions.getMultilineString().c_str());2865if (gCurrentFolder.length() != 0) {2866opendialog.setDirectory(gCurrentFolder);2867}2868if (opendialog.execute()) {2869// run parser2870NBTrafficLightLogicCont tmpTLLCont;2871NIXMLTrafficLightsHandler tllHandler(tmpTLLCont, myTLSEditorParent->getViewNet()->getNet()->getEdgeCont(), true);2872tmpTLLCont.insert(myTLSEditorParent->myEditedDef);2873XMLSubSys::runParser(tllHandler, opendialog.getFilename().text());28742875NBLoadedSUMOTLDef* newDefSameProgram = nullptr;2876std::set<NBLoadedSUMOTLDef*> newDefsOtherProgram;2877for (auto item : tmpTLLCont.getPrograms(myTLSEditorParent->myEditedDef->getID())) {2878if (item.second != myTLSEditorParent->myEditedDef) {2879NBLoadedSUMOTLDef* sdef = dynamic_cast<NBLoadedSUMOTLDef*>(item.second);2880if (item.first == myTLSEditorParent->myEditedDef->getProgramID()) {2881newDefSameProgram = sdef;2882} else {2883newDefsOtherProgram.insert(sdef);2884}2885}2886}2887const int newPrograms = (int)newDefsOtherProgram.size();2888if (newPrograms > 0 || newDefSameProgram != nullptr) {2889std::vector<NBNode*> nodes = myTLSEditorParent->myEditedDef->getNodes();2890for (auto newProg : newDefsOtherProgram) {2891for (auto it_node : nodes) {2892GNEJunction* junction = myTLSEditorParent->getViewNet()->getNet()->getAttributeCarriers()->retrieveJunction(it_node->getID());2893myTLSEditorParent->getViewNet()->getUndoList()->add(new GNEChange_TLS(junction, newProg, true), true);2894}2895}2896if (newPrograms > 0) {2897WRITE_MESSAGE(TL("Loaded ") + toString(newPrograms) + TL(" new programs for tlLogic '") + myTLSEditorParent->myEditedDef->getID() + "'");2898}2899if (newDefSameProgram != nullptr) {2900// replace old program when loading the same program ID2901myTLSEditorParent->myEditedDef = newDefSameProgram;2902WRITE_MESSAGE(TL("Updated program '") + newDefSameProgram->getProgramID() + TL("' for tlLogic '") + myTLSEditorParent->myEditedDef->getID() + "'");2903}2904} else {2905if (tllHandler.getSeenIDs().count(myTLSEditorParent->myEditedDef->getID()) == 0) {2906myTLSEditorParent->getViewNet()->setStatusBarText(TL("No programs found for traffic light '") + myTLSEditorParent->myEditedDef->getID() + "'");2907}2908}29092910// clean up temporary container to avoid deletion of defs when its destruct is called2911for (NBTrafficLightDefinition* def : tmpTLLCont.getDefinitions()) {2912tmpTLLCont.removeProgram(def->getID(), def->getProgramID(), false);2913}29142915myTLSEditorParent->myTLSPhases->initPhaseTable();2916myTLSEditorParent->myTLSPrograms->markAsModified();2917}2918myTLSEditorParent->updateModules();2919return 0;2920}292129222923long2924GNETLSEditorFrame::TLSFile::onCmdSaveTLSProgram(FXObject*, FXSelector, void*) {2925FXString file = MFXUtils::getFilename2Write(this, TL("Save TLS Program as"),2926SUMOXMLDefinitions::XMLFileExtensions.getMultilineString().c_str(),2927GUIIconSubSys::getIcon(GUIIcon::MODETLS), gCurrentFolder);2928// check file2929if (file != "") {2930// add xml extension2931file = FileHelpers::addExtension(file.text(), ".xml").c_str();2932OutputDevice& device = OutputDevice::getDevice(file.text());2933// save program2934device.writeXMLHeader("additional", "additional_file.xsd");2935NWWriter_SUMO::writeTrafficLight(device, myTLSEditorParent->myEditedDef->getLogic());2936device.close();2937}2938myTLSEditorParent->updateModules();2939return 1;2940}294129422943std::string2944GNETLSEditorFrame::TLSFile::writeSUMOTime(SUMOTime steps) {2945const double time = STEPS2TIME(steps);2946if (time == std::floor(time)) {2947return toString(int(time));2948} else {2949return toString(time);2950}2951}29522953/****************************************************************************/295429552956