Line data Source code
1 : /****************************************************************************/
2 : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3 : // Copyright (C) 2001-2025 German Aerospace Center (DLR) and others.
4 : // This program and the accompanying materials are made available under the
5 : // terms of the Eclipse Public License 2.0 which is available at
6 : // https://www.eclipse.org/legal/epl-2.0/
7 : // This Source Code may also be made available under the following Secondary
8 : // Licenses when the conditions for such availability set forth in the Eclipse
9 : // Public License 2.0 are satisfied: GNU General Public License, version 2
10 : // or later which is available at
11 : // https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
12 : // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
13 : /****************************************************************************/
14 : /// @file GUIDialog_Breakpoints.cpp
15 : /// @author Daniel Krajzewicz
16 : /// @author Jakob Erdmann
17 : /// @author Michael Behrisch
18 : /// @date Thu, 17 Jun 2004
19 : ///
20 : // Editor for simulation breakpoints
21 : /****************************************************************************/
22 : #include <config.h>
23 :
24 : #include <string>
25 : #include <vector>
26 : #include <iostream>
27 : #include <fstream>
28 : #include <set>
29 : #include <fxkeys.h>
30 : #include <gui/GUIApplicationWindow.h>
31 : #include <utils/gui/windows/GUIAppEnum.h>
32 : #include <gui/GUIGlobals.h>
33 : #include <utils/gui/globjects/GUIGlObject.h>
34 : #include <utils/foxtools/MFXUtils.h>
35 : #include <utils/common/ToString.h>
36 : #include <utils/common/StringUtils.h>
37 : #include <utils/gui/windows/GUISUMOAbstractView.h>
38 : #include <utils/gui/settings/GUISettingsHandler.h>
39 : #include <utils/common/FileHelpers.h>
40 : #include <utils/common/MsgHandler.h>
41 : #include <utils/options/OptionsCont.h>
42 : #include <utils/gui/div/GUIIOGlobals.h>
43 : #include <utils/gui/div/GUIDesigns.h>
44 : #include <utils/gui/images/GUIIconSubSys.h>
45 : #include <utils/iodevices/OutputDevice.h>
46 : #include "GUIDialog_Breakpoints.h"
47 :
48 :
49 : // ===========================================================================
50 : // FOX callback mapping
51 : // ===========================================================================
52 :
53 : FXDEFMAP(GUIDialog_Breakpoints) GUIDialog_BreakpointsMap[] = {
54 : FXMAPFUNC(SEL_COMMAND, MID_CHOOSEN_LOAD, GUIDialog_Breakpoints::onCmdLoad),
55 : FXMAPFUNC(SEL_COMMAND, MID_CHOOSEN_SAVE, GUIDialog_Breakpoints::onCmdSave),
56 : FXMAPFUNC(SEL_COMMAND, MID_CHOOSEN_CLEAR, GUIDialog_Breakpoints::onCmdClear),
57 : FXMAPFUNC(SEL_COMMAND, MID_CANCEL, GUIDialog_Breakpoints::onCmdClose),
58 : FXMAPFUNC(SEL_COMMAND, MID_TIMELINK_BREAKPOINT, GUIDialog_Breakpoints::onCmdUpdateBreakpoints),
59 : FXMAPFUNC(SEL_REPLACED, MID_TABLE, GUIDialog_Breakpoints::onCmdEditTable),
60 : FXMAPFUNC(SEL_KEYPRESS, 0, GUIDialog_Breakpoints::onKeyPress),
61 : };
62 :
63 :
64 0 : FXIMPLEMENT(GUIDialog_Breakpoints, FXMainWindow, GUIDialog_BreakpointsMap, ARRAYNUMBER(GUIDialog_BreakpointsMap))
65 :
66 :
67 : // ===========================================================================
68 : // method definitions
69 : // ===========================================================================
70 0 : GUIDialog_Breakpoints::GUIDialog_Breakpoints(GUIApplicationWindow* parent, std::vector<SUMOTime>& breakpoints, FXMutex& breakpointLock, const SUMOTime simBegin) :
71 0 : FXMainWindow(parent->getApp(), TL("Breakpoints Editor"), GUIIconSubSys::getIcon(GUIIcon::APP_BREAKPOINTS), nullptr, GUIDesignChooserDialog),
72 0 : myParent(parent),
73 0 : myBreakpoints(&breakpoints),
74 0 : myBreakpointLock(&breakpointLock),
75 0 : mySimBegin(simBegin) {
76 : // build main Frame
77 0 : FXHorizontalFrame* hbox = new FXHorizontalFrame(this, GUIDesignAuxiliarFrame);
78 : // build the table
79 0 : FXVerticalFrame* layoutLeft = new FXVerticalFrame(hbox, GUIDesignChooserLayoutLeft);
80 0 : myTable = new FXTable(layoutLeft, this, MID_TABLE, GUIDesignBreakpointTable);
81 0 : myTable->setVisibleRows(20);
82 0 : myTable->setVisibleColumns(1);
83 0 : myTable->setTableSize(20, 1);
84 0 : myTable->setBackColor(GUIDesignBackgroundColorWhite);
85 0 : myTable->getRowHeader()->setWidth(0);
86 0 : myBreakpointLock->lock();
87 0 : rebuildList();
88 0 : myBreakpointLock->unlock();
89 : // build the layout
90 0 : FXVerticalFrame* layoutRight = new FXVerticalFrame(hbox, GUIDesignChooserLayoutRight);
91 : // create buttons ('&' in the label creates a hot key)
92 : // "Load"
93 0 : GUIDesigns::buildFXButton(layoutRight, TL("&Load"), "", "", GUIIconSubSys::getIcon(GUIIcon::OPEN), this, MID_CHOOSEN_LOAD, GUIDesignChooserButtons);
94 : // "Save"
95 0 : GUIDesigns::buildFXButton(layoutRight, TL("&Save"), "", "", GUIIconSubSys::getIcon(GUIIcon::SAVE), this, MID_CHOOSEN_SAVE, GUIDesignChooserButtons);
96 0 : new FXHorizontalSeparator(layoutRight, GUIDesignHorizontalSeparator);
97 : // "Clear List"
98 0 : GUIDesigns::buildFXButton(layoutRight, TL("Clea&r"), "", "", GUIIconSubSys::getIcon(GUIIcon::CLEANJUNCTIONS), this, MID_CHOOSEN_CLEAR, GUIDesignChooserButtons);
99 0 : new FXHorizontalSeparator(layoutRight, GUIDesignHorizontalSeparator);
100 : // "Close"
101 0 : GUIDesigns::buildFXButton(layoutRight, TL("&Close"), "", "", GUIIconSubSys::getIcon(GUIIcon::NO), this, MID_CANCEL, GUIDesignChooserButtons);
102 : // add this dialog as child of GUIMainWindow parent
103 0 : myParent->addChild(this);
104 0 : myPersistentPos = std::unique_ptr<GUIPersistentWindowPos>(new GUIPersistentWindowPos(this, "DIALOG_BREAKPOINTS", true, 20, 40, 300, 350));
105 0 : myPersistentPos->loadWindowPos();
106 0 : create();
107 0 : show();
108 0 : }
109 :
110 :
111 0 : GUIDialog_Breakpoints::~GUIDialog_Breakpoints() {
112 : // remove this dialog as child of GUIMainWindow parent
113 0 : myParent->removeChild(this);
114 0 : myParent->eraseBreakpointDialog();
115 0 : }
116 :
117 :
118 : void
119 0 : GUIDialog_Breakpoints::show() {
120 0 : FXMainWindow::show();
121 0 : myTable->startInput((int)myBreakpoints->size(), 0);
122 0 : }
123 :
124 :
125 : void
126 0 : GUIDialog_Breakpoints::rebuildList() {
127 0 : myTable->clearItems();
128 0 : sort(myBreakpoints->begin(), myBreakpoints->end());
129 : // set table attributes
130 0 : myTable->setTableSize((FXint)myBreakpoints->size() + 1, 1);
131 0 : myTable->setColumnText(0, TL("Time"));
132 0 : FXHeader* header = myTable->getColumnHeader();
133 0 : header->setHeight(GUIDesignHeight);
134 0 : header->setItemJustify(0, JUSTIFY_CENTER_X);
135 : // insert into table
136 0 : for (int row = 0; row < (int)myBreakpoints->size(); row++) {
137 0 : myTable->setItemText(row, 0, time2string((*myBreakpoints)[row]).c_str());
138 : }
139 : // insert dummy last field
140 0 : myTable->setItemText((int)myBreakpoints->size(), 0, " ");
141 0 : }
142 :
143 :
144 : long
145 0 : GUIDialog_Breakpoints::onKeyPress(FXObject* o, FXSelector sel, void* ptr) {
146 : const FXEvent* e = (FXEvent*) ptr;
147 0 : if(e->code==KEY_Escape){
148 0 : onCmdClose(nullptr, 0, nullptr);
149 0 : return 1;
150 : }
151 0 : return FXMainWindow::onKeyPress(o, sel, ptr);
152 : }
153 :
154 :
155 : long
156 0 : GUIDialog_Breakpoints::onCmdLoad(FXObject*, FXSelector, void*) {
157 0 : FXFileDialog opendialog(this, TL("Load Breakpoints"));
158 0 : opendialog.setIcon(GUIIconSubSys::getIcon(GUIIcon::EMPTY));
159 0 : opendialog.setSelectMode(SELECTFILE_ANY);
160 0 : opendialog.setPatternList(SUMOXMLDefinitions::TXTFileExtensions.getMultilineString().c_str());
161 0 : if (gCurrentFolder.length() != 0) {
162 0 : opendialog.setDirectory(gCurrentFolder);
163 : }
164 0 : if (opendialog.execute()) {
165 0 : gCurrentFolder = opendialog.getDirectory();
166 0 : std::string file = opendialog.getFilename().text();
167 0 : std::vector<SUMOTime> newBreakpoints = GUISettingsHandler::loadBreakpoints(file);
168 0 : FXMutexLock lock(*myBreakpointLock);
169 0 : myBreakpoints->assign(newBreakpoints.begin(), newBreakpoints.end());
170 0 : rebuildList();
171 0 : }
172 0 : return 1;
173 0 : }
174 :
175 :
176 : long
177 0 : GUIDialog_Breakpoints::onCmdSave(FXObject*, FXSelector, void*) {
178 0 : FXString file = MFXUtils::getFilename2Write(this, TL("Save Breakpoints"),
179 0 : SUMOXMLDefinitions::TXTFileExtensions.getMultilineString().c_str(),
180 0 : GUIIconSubSys::getIcon(GUIIcon::EMPTY), gCurrentFolder);
181 0 : if (file == "") {
182 : return 1;
183 : }
184 0 : std::string content = encode2TXT();
185 : try {
186 0 : OutputDevice& dev = OutputDevice::getDevice(file.text());
187 0 : dev << content;
188 0 : dev.close();
189 0 : } catch (IOError& e) {
190 0 : FXMessageBox::error(this, MBOX_OK, TL("Storing failed!"), "%s", e.what());
191 0 : }
192 : return 1;
193 0 : }
194 :
195 :
196 : std::string
197 0 : GUIDialog_Breakpoints::encode2TXT() {
198 0 : FXMutexLock lock(*myBreakpointLock);
199 0 : std::ostringstream strm;
200 0 : std::sort(myBreakpoints->begin(), myBreakpoints->end());
201 0 : for (std::vector<SUMOTime>::iterator j = myBreakpoints->begin(); j != myBreakpoints->end(); ++j) {
202 0 : strm << time2string(*j) << std::endl;
203 : }
204 0 : return strm.str();
205 0 : }
206 :
207 :
208 : long
209 0 : GUIDialog_Breakpoints::onCmdClear(FXObject*, FXSelector, void*) {
210 0 : FXMutexLock lock(*myBreakpointLock);
211 0 : myBreakpoints->clear();
212 0 : rebuildList();
213 0 : return 1;
214 : }
215 :
216 :
217 : long
218 0 : GUIDialog_Breakpoints::onCmdUpdateBreakpoints(FXObject*, FXSelector, void*) {
219 0 : FXMutexLock lock(*myBreakpointLock);
220 0 : rebuildList();
221 0 : return 1;
222 : }
223 :
224 :
225 : long
226 0 : GUIDialog_Breakpoints::onCmdClose(FXObject*, FXSelector, void*) {
227 0 : close(true);
228 0 : return 1;
229 : }
230 :
231 :
232 : long
233 0 : GUIDialog_Breakpoints::onCmdEditTable(FXObject*, FXSelector, void* ptr) {
234 0 : FXMutexLock lock(*myBreakpointLock);
235 : const FXTablePos* const i = (FXTablePos*) ptr;
236 0 : const std::string value = StringUtils::prune(myTable->getItemText(i->row, i->col).text());
237 : // check whether the inserted value is empty
238 : const bool empty = value.find_first_not_of(" ") == std::string::npos;
239 : try {
240 0 : SUMOTime t = -1;
241 0 : if (!empty) {
242 0 : t = string2time(value);
243 : // round down to nearest reachable time step
244 0 : t -= (t - mySimBegin) % DELTA_T;
245 : }
246 0 : if (i->row == (int)myBreakpoints->size()) {
247 0 : if (!empty) {
248 0 : myBreakpoints->push_back(t);
249 : }
250 : } else {
251 0 : if (empty) {
252 : myBreakpoints->erase(myBreakpoints->begin() + i->row);
253 : } else {
254 0 : (*myBreakpoints)[i->row] = t;
255 : }
256 : }
257 0 : } catch (NumberFormatException&) {
258 0 : std::string msg = "The value must be a number, is:" + value;
259 0 : FXMessageBox::error(this, MBOX_OK, TL("Time format error"), "%s", msg.c_str());
260 0 : } catch (ProcessError&) {
261 0 : std::string msg = "The value must be a number or a string of the form hh:mm:ss, is:" + value;
262 0 : FXMessageBox::error(this, MBOX_OK, TL("Time format error"), "%s", msg.c_str());
263 0 : }
264 0 : rebuildList();
265 0 : return 1;
266 : }
267 :
268 :
269 : void
270 0 : GUIDialog_Breakpoints::layout() {
271 0 : FXMainWindow::layout();
272 0 : myTable->setColumnWidth(0, myTable->getWidth() - 1);
273 0 : }
274 :
275 :
276 : /****************************************************************************/
|