Path: blob/main/src/gui/dialogs/GUIDialog_Breakpoints.cpp
193728 views
/****************************************************************************/1// Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo2// Copyright (C) 2001-2026 German Aerospace Center (DLR) and others.3// This program and the accompanying materials are made available under the4// terms of the Eclipse Public License 2.0 which is available at5// https://www.eclipse.org/legal/epl-2.0/6// This Source Code may also be made available under the following Secondary7// Licenses when the conditions for such availability set forth in the Eclipse8// Public License 2.0 are satisfied: GNU General Public License, version 29// or later which is available at10// https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html11// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later12/****************************************************************************/13/// @file GUIDialog_Breakpoints.cpp14/// @author Daniel Krajzewicz15/// @author Jakob Erdmann16/// @author Michael Behrisch17/// @date Thu, 17 Jun 200418///19// Editor for simulation breakpoints20/****************************************************************************/21#include <config.h>2223#include <string>24#include <vector>25#include <iostream>26#include <fstream>27#include <set>28#include <fxkeys.h>29#include <gui/GUIApplicationWindow.h>30#include <utils/gui/windows/GUIAppEnum.h>31#include <gui/GUIGlobals.h>32#include <utils/gui/globjects/GUIGlObject.h>33#include <utils/foxtools/MFXUtils.h>34#include <utils/common/ToString.h>35#include <utils/common/StringUtils.h>36#include <utils/gui/windows/GUISUMOAbstractView.h>37#include <utils/gui/settings/GUISettingsHandler.h>38#include <utils/common/FileHelpers.h>39#include <utils/common/MsgHandler.h>40#include <utils/options/OptionsCont.h>41#include <utils/gui/div/GUIIOGlobals.h>42#include <utils/gui/div/GUIDesigns.h>43#include <utils/gui/images/GUIIconSubSys.h>44#include <utils/iodevices/OutputDevice.h>45#include "GUIDialog_Breakpoints.h"464748// ===========================================================================49// FOX callback mapping50// ===========================================================================5152FXDEFMAP(GUIDialog_Breakpoints) GUIDialog_BreakpointsMap[] = {53FXMAPFUNC(SEL_COMMAND, MID_CHOOSEN_LOAD, GUIDialog_Breakpoints::onCmdLoad),54FXMAPFUNC(SEL_COMMAND, MID_CHOOSEN_SAVE, GUIDialog_Breakpoints::onCmdSave),55FXMAPFUNC(SEL_COMMAND, MID_CHOOSEN_CLEAR, GUIDialog_Breakpoints::onCmdClear),56FXMAPFUNC(SEL_COMMAND, MID_CANCEL, GUIDialog_Breakpoints::onCmdClose),57FXMAPFUNC(SEL_COMMAND, MID_TIMELINK_BREAKPOINT, GUIDialog_Breakpoints::onCmdUpdateBreakpoints),58FXMAPFUNC(SEL_REPLACED, MID_TABLE, GUIDialog_Breakpoints::onCmdEditTable),59FXMAPFUNC(SEL_KEYPRESS, 0, GUIDialog_Breakpoints::onKeyPress),60};616263FXIMPLEMENT(GUIDialog_Breakpoints, FXMainWindow, GUIDialog_BreakpointsMap, ARRAYNUMBER(GUIDialog_BreakpointsMap))646566// ===========================================================================67// method definitions68// ===========================================================================69GUIDialog_Breakpoints::GUIDialog_Breakpoints(GUIApplicationWindow* parent, std::vector<SUMOTime>& breakpoints, FXMutex& breakpointLock, const SUMOTime simBegin) :70FXMainWindow(parent->getApp(), TL("Breakpoints Editor"), GUIIconSubSys::getIcon(GUIIcon::APP_BREAKPOINTS), nullptr, GUIDesignChooserDialog),71myParent(parent),72myBreakpoints(&breakpoints),73myBreakpointLock(&breakpointLock),74mySimBegin(simBegin) {75// build main Frame76FXHorizontalFrame* hbox = new FXHorizontalFrame(this, GUIDesignAuxiliarFrame);77// build the table78FXVerticalFrame* layoutLeft = new FXVerticalFrame(hbox, GUIDesignChooserLayoutLeft);79myTable = new FXTable(layoutLeft, this, MID_TABLE, GUIDesignBreakpointTable);80myTable->setVisibleRows(20);81myTable->setVisibleColumns(1);82myTable->setTableSize(20, 1);83myTable->setBackColor(GUIDesignBackgroundColorWhite);84myTable->getRowHeader()->setWidth(0);85myBreakpointLock->lock();86rebuildList();87myBreakpointLock->unlock();88// build the layout89FXVerticalFrame* layoutRight = new FXVerticalFrame(hbox, GUIDesignChooserLayoutRight);90// create buttons ('&' in the label creates a hot key)91// "Load"92GUIDesigns::buildFXButton(layoutRight, TL("&Load"), "", "", GUIIconSubSys::getIcon(GUIIcon::OPEN), this, MID_CHOOSEN_LOAD, GUIDesignChooserButtons);93// "Save"94GUIDesigns::buildFXButton(layoutRight, TL("&Save"), "", "", GUIIconSubSys::getIcon(GUIIcon::SAVE), this, MID_CHOOSEN_SAVE, GUIDesignChooserButtons);95new FXHorizontalSeparator(layoutRight, GUIDesignHorizontalSeparator);96// "Clear List"97GUIDesigns::buildFXButton(layoutRight, TL("Clea&r"), "", "", GUIIconSubSys::getIcon(GUIIcon::CLEANJUNCTIONS), this, MID_CHOOSEN_CLEAR, GUIDesignChooserButtons);98new FXHorizontalSeparator(layoutRight, GUIDesignHorizontalSeparator);99// "Close"100GUIDesigns::buildFXButton(layoutRight, TL("&Close"), "", "", GUIIconSubSys::getIcon(GUIIcon::NO), this, MID_CANCEL, GUIDesignChooserButtons);101// add this dialog as child of GUIMainWindow parent102myParent->addChild(this);103myPersistentPos = std::unique_ptr<GUIPersistentWindowPos>(new GUIPersistentWindowPos(this, "DIALOG_BREAKPOINTS", true, 20, 40, 300, 350));104myPersistentPos->loadWindowPos();105create();106show();107}108109110GUIDialog_Breakpoints::~GUIDialog_Breakpoints() {111// remove this dialog as child of GUIMainWindow parent112myParent->removeChild(this);113myParent->eraseBreakpointDialog();114}115116117void118GUIDialog_Breakpoints::show() {119FXMainWindow::show();120myTable->startInput((int)myBreakpoints->size(), 0);121}122123124void125GUIDialog_Breakpoints::rebuildList() {126myTable->clearItems();127sort(myBreakpoints->begin(), myBreakpoints->end());128// set table attributes129myTable->setTableSize((FXint)myBreakpoints->size() + 1, 1);130myTable->setColumnText(0, TL("Time"));131FXHeader* header = myTable->getColumnHeader();132header->setHeight(GUIDesignHeight);133header->setItemJustify(0, JUSTIFY_CENTER_X);134// insert into table135for (int row = 0; row < (int)myBreakpoints->size(); row++) {136myTable->setItemText(row, 0, time2string((*myBreakpoints)[row]).c_str());137}138// insert dummy last field139myTable->setItemText((int)myBreakpoints->size(), 0, " ");140}141142143long144GUIDialog_Breakpoints::onKeyPress(FXObject* o, FXSelector sel, void* ptr) {145const FXEvent* e = (FXEvent*) ptr;146if (e->code == KEY_Escape) {147onCmdClose(nullptr, 0, nullptr);148return 1;149}150return FXMainWindow::onKeyPress(o, sel, ptr);151}152153154long155GUIDialog_Breakpoints::onCmdLoad(FXObject*, FXSelector, void*) {156FXFileDialog opendialog(this, TL("Load Breakpoints"));157opendialog.setIcon(GUIIconSubSys::getIcon(GUIIcon::EMPTY));158opendialog.setSelectMode(SELECTFILE_ANY);159opendialog.setPatternList(SUMOXMLDefinitions::TXTFileExtensions.getMultilineString().c_str());160if (gCurrentFolder.length() != 0) {161opendialog.setDirectory(gCurrentFolder);162}163if (opendialog.execute()) {164gCurrentFolder = opendialog.getDirectory();165std::string file = opendialog.getFilename().text();166std::vector<SUMOTime> newBreakpoints = GUISettingsHandler::loadBreakpoints(file);167FXMutexLock lock(*myBreakpointLock);168myBreakpoints->assign(newBreakpoints.begin(), newBreakpoints.end());169rebuildList();170}171return 1;172}173174175long176GUIDialog_Breakpoints::onCmdSave(FXObject*, FXSelector, void*) {177FXString file = MFXUtils::getFilename2Write(this, TL("Save Breakpoints"),178SUMOXMLDefinitions::TXTFileExtensions.getMultilineString().c_str(),179GUIIconSubSys::getIcon(GUIIcon::EMPTY), gCurrentFolder);180if (file == "") {181return 1;182}183std::string content = encode2TXT();184try {185OutputDevice& dev = OutputDevice::getDevice(file.text());186dev << content;187dev.close();188} catch (IOError& e) {189FXMessageBox::error(this, MBOX_OK, TL("Storing failed!"), "%s", e.what());190}191return 1;192}193194195std::string196GUIDialog_Breakpoints::encode2TXT() {197FXMutexLock lock(*myBreakpointLock);198std::ostringstream strm;199std::sort(myBreakpoints->begin(), myBreakpoints->end());200for (std::vector<SUMOTime>::iterator j = myBreakpoints->begin(); j != myBreakpoints->end(); ++j) {201strm << time2string(*j) << std::endl;202}203return strm.str();204}205206207long208GUIDialog_Breakpoints::onCmdClear(FXObject*, FXSelector, void*) {209FXMutexLock lock(*myBreakpointLock);210myBreakpoints->clear();211rebuildList();212return 1;213}214215216long217GUIDialog_Breakpoints::onCmdUpdateBreakpoints(FXObject*, FXSelector, void*) {218FXMutexLock lock(*myBreakpointLock);219rebuildList();220return 1;221}222223224long225GUIDialog_Breakpoints::onCmdClose(FXObject*, FXSelector, void*) {226close(true);227return 1;228}229230231long232GUIDialog_Breakpoints::onCmdEditTable(FXObject*, FXSelector, void* ptr) {233FXMutexLock lock(*myBreakpointLock);234const FXTablePos* const i = (FXTablePos*) ptr;235const std::string value = StringUtils::prune(myTable->getItemText(i->row, i->col).text());236// check whether the inserted value is empty237const bool empty = value.find_first_not_of(" ") == std::string::npos;238try {239SUMOTime t = -1;240if (!empty) {241t = string2time(value);242// round down to nearest reachable time step243t -= (t - mySimBegin) % DELTA_T;244}245if (i->row == (int)myBreakpoints->size()) {246if (!empty) {247myBreakpoints->push_back(t);248}249} else {250if (empty) {251myBreakpoints->erase(myBreakpoints->begin() + i->row);252} else {253(*myBreakpoints)[i->row] = t;254}255}256} catch (NumberFormatException&) {257std::string msg = "The value must be a number, is:" + value;258FXMessageBox::error(this, MBOX_OK, TL("Time format error"), "%s", msg.c_str());259} catch (ProcessError&) {260std::string msg = "The value must be a number or a string of the form hh:mm:ss, is:" + value;261FXMessageBox::error(this, MBOX_OK, TL("Time format error"), "%s", msg.c_str());262}263rebuildList();264return 1;265}266267268void269GUIDialog_Breakpoints::layout() {270FXMainWindow::layout();271myTable->setColumnWidth(0, myTable->getWidth() - 1);272}273274275/****************************************************************************/276277278