Line data Source code
1 : /****************************************************************************/
2 : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3 : // Copyright (C) 2001-2024 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 <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"
46 :
47 :
48 : // ===========================================================================
49 : // FOX callback mapping
50 : // ===========================================================================
51 :
52 : FXDEFMAP(GUIDialog_Breakpoints) GUIDialog_BreakpointsMap[] = {
53 : FXMAPFUNC(SEL_COMMAND, MID_CHOOSEN_LOAD, GUIDialog_Breakpoints::onCmdLoad),
54 : FXMAPFUNC(SEL_COMMAND, MID_CHOOSEN_SAVE, GUIDialog_Breakpoints::onCmdSave),
55 : FXMAPFUNC(SEL_COMMAND, MID_CHOOSEN_CLEAR, GUIDialog_Breakpoints::onCmdClear),
56 : FXMAPFUNC(SEL_COMMAND, MID_CANCEL, GUIDialog_Breakpoints::onCmdClose),
57 : FXMAPFUNC(SEL_COMMAND, MID_TIMELINK_BREAKPOINT, GUIDialog_Breakpoints::onCmdUpdateBreakpoints),
58 : FXMAPFUNC(SEL_REPLACED, MID_TABLE, GUIDialog_Breakpoints::onCmdEditTable),
59 : };
60 :
61 :
62 0 : FXIMPLEMENT(GUIDialog_Breakpoints, FXMainWindow, GUIDialog_BreakpointsMap, ARRAYNUMBER(GUIDialog_BreakpointsMap))
63 :
64 : // ===========================================================================
65 : // method definitions
66 : // ===========================================================================
67 :
68 0 : GUIDialog_Breakpoints::GUIDialog_Breakpoints(GUIApplicationWindow* parent, std::vector<SUMOTime>& breakpoints, FXMutex& breakpointLock, const SUMOTime simBegin) :
69 0 : FXMainWindow(parent->getApp(), TL("Breakpoints Editor"), GUIIconSubSys::getIcon(GUIIcon::APP_BREAKPOINTS), nullptr, GUIDesignChooserDialog),
70 : GUIPersistentWindowPos(this, "DIALOG_BREAKPOINTS", true, 20, 40, 300, 350),
71 0 : myParent(parent),
72 0 : myBreakpoints(&breakpoints),
73 0 : myBreakpointLock(&breakpointLock),
74 0 : mySimBegin(simBegin) {
75 : // build main Frame
76 0 : FXHorizontalFrame* hbox = new FXHorizontalFrame(this, GUIDesignAuxiliarFrame);
77 : // build the table
78 0 : FXVerticalFrame* layoutLeft = new FXVerticalFrame(hbox, GUIDesignChooserLayoutLeft);
79 0 : myTable = new FXTable(layoutLeft, this, MID_TABLE, GUIDesignBreakpointTable);
80 0 : myTable->setVisibleRows(20);
81 0 : myTable->setVisibleColumns(1);
82 0 : myTable->setTableSize(20, 1);
83 0 : myTable->setBackColor(FXRGB(255, 255, 255));
84 0 : myTable->getRowHeader()->setWidth(0);
85 0 : myBreakpointLock->lock();
86 0 : rebuildList();
87 0 : myBreakpointLock->unlock();
88 : // build the layout
89 0 : FXVerticalFrame* layoutRight = new FXVerticalFrame(hbox, GUIDesignChooserLayoutRight);
90 : // create buttons ('&' in the label creates a hot key)
91 : // "Load"
92 0 : GUIDesigns::buildFXButton(layoutRight, TL("&Load"), "", "", GUIIconSubSys::getIcon(GUIIcon::OPEN), this, MID_CHOOSEN_LOAD, GUIDesignChooserButtons);
93 : // "Save"
94 0 : GUIDesigns::buildFXButton(layoutRight, TL("&Save"), "", "", GUIIconSubSys::getIcon(GUIIcon::SAVE), this, MID_CHOOSEN_SAVE, GUIDesignChooserButtons);
95 0 : new FXHorizontalSeparator(layoutRight, GUIDesignHorizontalSeparator);
96 : // "Clear List"
97 0 : GUIDesigns::buildFXButton(layoutRight, TL("Clea&r"), "", "", GUIIconSubSys::getIcon(GUIIcon::CLEANJUNCTIONS), this, MID_CHOOSEN_CLEAR, GUIDesignChooserButtons);
98 0 : new FXHorizontalSeparator(layoutRight, GUIDesignHorizontalSeparator);
99 : // "Close"
100 0 : GUIDesigns::buildFXButton(layoutRight, TL("&Close"), "", "", GUIIconSubSys::getIcon(GUIIcon::NO), this, MID_CANCEL, GUIDesignChooserButtons);
101 : // add this dialog as child of GUIMainWindow parent
102 0 : myParent->addChild(this);
103 0 : loadWindowPos();
104 0 : create();
105 0 : show();
106 0 : }
107 :
108 :
109 0 : GUIDialog_Breakpoints::~GUIDialog_Breakpoints() {
110 : // remove this dialog as child of GUIMainWindow parent
111 0 : myParent->removeChild(this);
112 0 : myParent->eraseBreakpointDialog();
113 0 : }
114 :
115 :
116 : void
117 0 : GUIDialog_Breakpoints::show() {
118 0 : FXMainWindow::show();
119 0 : myTable->startInput((int)myBreakpoints->size(), 0);
120 0 : }
121 :
122 :
123 : void
124 0 : GUIDialog_Breakpoints::rebuildList() {
125 0 : myTable->clearItems();
126 0 : sort(myBreakpoints->begin(), myBreakpoints->end());
127 : // set table attributes
128 0 : myTable->setTableSize((FXint)myBreakpoints->size() + 1, 1);
129 0 : myTable->setColumnText(0, TL("Time"));
130 0 : FXHeader* header = myTable->getColumnHeader();
131 0 : header->setHeight(GUIDesignHeight);
132 0 : header->setItemJustify(0, JUSTIFY_CENTER_X);
133 : // insert into table
134 0 : for (int row = 0; row < (int)myBreakpoints->size(); row++) {
135 0 : myTable->setItemText(row, 0, time2string((*myBreakpoints)[row]).c_str());
136 : }
137 : // insert dummy last field
138 0 : myTable->setItemText((int)myBreakpoints->size(), 0, " ");
139 0 : }
140 :
141 :
142 : long
143 0 : GUIDialog_Breakpoints::onCmdLoad(FXObject*, FXSelector, void*) {
144 0 : FXFileDialog opendialog(this, TL("Load Breakpoints"));
145 0 : opendialog.setIcon(GUIIconSubSys::getIcon(GUIIcon::EMPTY));
146 0 : opendialog.setSelectMode(SELECTFILE_ANY);
147 0 : opendialog.setPatternList("*.txt");
148 0 : if (gCurrentFolder.length() != 0) {
149 0 : opendialog.setDirectory(gCurrentFolder);
150 : }
151 0 : if (opendialog.execute()) {
152 0 : gCurrentFolder = opendialog.getDirectory();
153 0 : std::string file = opendialog.getFilename().text();
154 0 : std::vector<SUMOTime> newBreakpoints = GUISettingsHandler::loadBreakpoints(file);
155 0 : FXMutexLock lock(*myBreakpointLock);
156 0 : myBreakpoints->assign(newBreakpoints.begin(), newBreakpoints.end());
157 0 : rebuildList();
158 0 : }
159 0 : return 1;
160 0 : }
161 :
162 :
163 : long
164 0 : GUIDialog_Breakpoints::onCmdSave(FXObject*, FXSelector, void*) {
165 0 : FXString file = MFXUtils::getFilename2Write(this, TL("Save Breakpoints"), ".txt", GUIIconSubSys::getIcon(GUIIcon::EMPTY), gCurrentFolder);
166 0 : if (file == "") {
167 : return 1;
168 : }
169 0 : std::string content = encode2TXT();
170 : try {
171 0 : OutputDevice& dev = OutputDevice::getDevice(file.text());
172 0 : dev << content;
173 0 : dev.close();
174 0 : } catch (IOError& e) {
175 0 : FXMessageBox::error(this, MBOX_OK, TL("Storing failed!"), "%s", e.what());
176 0 : }
177 : return 1;
178 0 : }
179 :
180 :
181 : std::string
182 0 : GUIDialog_Breakpoints::encode2TXT() {
183 0 : FXMutexLock lock(*myBreakpointLock);
184 0 : std::ostringstream strm;
185 0 : std::sort(myBreakpoints->begin(), myBreakpoints->end());
186 0 : for (std::vector<SUMOTime>::iterator j = myBreakpoints->begin(); j != myBreakpoints->end(); ++j) {
187 0 : strm << time2string(*j) << std::endl;
188 : }
189 0 : return strm.str();
190 0 : }
191 :
192 :
193 : long
194 0 : GUIDialog_Breakpoints::onCmdClear(FXObject*, FXSelector, void*) {
195 0 : FXMutexLock lock(*myBreakpointLock);
196 0 : myBreakpoints->clear();
197 0 : rebuildList();
198 0 : return 1;
199 : }
200 :
201 :
202 : long
203 0 : GUIDialog_Breakpoints::onCmdUpdateBreakpoints(FXObject*, FXSelector, void*) {
204 0 : FXMutexLock lock(*myBreakpointLock);
205 0 : rebuildList();
206 0 : return 1;
207 : }
208 :
209 :
210 : long
211 0 : GUIDialog_Breakpoints::onCmdClose(FXObject*, FXSelector, void*) {
212 0 : close(true);
213 0 : return 1;
214 : }
215 :
216 :
217 : long
218 0 : GUIDialog_Breakpoints::onCmdEditTable(FXObject*, FXSelector, void* ptr) {
219 0 : FXMutexLock lock(*myBreakpointLock);
220 : const FXTablePos* const i = (FXTablePos*) ptr;
221 0 : const std::string value = StringUtils::prune(myTable->getItemText(i->row, i->col).text());
222 : // check whether the inserted value is empty
223 : const bool empty = value.find_first_not_of(" ") == std::string::npos;
224 : try {
225 0 : SUMOTime t = -1;
226 0 : if (!empty) {
227 0 : t = string2time(value);
228 : // round down to nearest reachable time step
229 0 : t -= (t - mySimBegin) % DELTA_T;
230 : }
231 0 : if (i->row == (int)myBreakpoints->size()) {
232 0 : if (!empty) {
233 0 : myBreakpoints->push_back(t);
234 : }
235 : } else {
236 0 : if (empty) {
237 : myBreakpoints->erase(myBreakpoints->begin() + i->row);
238 : } else {
239 0 : (*myBreakpoints)[i->row] = t;
240 : }
241 : }
242 0 : } catch (NumberFormatException&) {
243 0 : std::string msg = "The value must be a number, is:" + value;
244 0 : FXMessageBox::error(this, MBOX_OK, TL("Time format error"), "%s", msg.c_str());
245 0 : } catch (ProcessError&) {
246 0 : std::string msg = "The value must be a number or a string of the form hh:mm:ss, is:" + value;
247 0 : FXMessageBox::error(this, MBOX_OK, TL("Time format error"), "%s", msg.c_str());
248 0 : }
249 0 : rebuildList();
250 0 : return 1;
251 : }
252 :
253 :
254 : void
255 0 : GUIDialog_Breakpoints::layout() {
256 0 : FXMainWindow::layout();
257 0 : myTable->setColumnWidth(0, myTable->getWidth() - 1);
258 0 : }
259 :
260 :
261 : /****************************************************************************/
|